#include <setjmp.h>
#include "config.h"
#include "system.h"
#include "rtl.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "insn-config.h"
#include "conditions.h"
#include "insn-flags.h"
#include "output.h"
#include "insn-attr.h"
#include "tree.h"
#include "flags.h"
#include "except.h"
#include "function.h"
#include "recog.h"
#include "expr.h"
#include "toplev.h"
#ifdef MACHO_PIC
#include "insn-codes.h"
#include "apple/machopic.h"
#endif
#ifdef EXTRA_CONSTRAINT
error EXTRA_CONSTRAINT conflicts with S constraint letter
#endif
#ifndef CHECK_STACK_LIMIT
#define CHECK_STACK_LIMIT -1
#endif
enum reg_mem
{
reg_p,
mem_p,
imm_p
};
struct processor_costs i386_cost = {
1,
1,
3,
2,
6,
1,
23
};
struct processor_costs i486_cost = {
1,
1,
3,
2,
12,
1,
40
};
struct processor_costs pentium_cost = {
1,
1,
4,
1,
11,
0,
25
};
struct processor_costs pentiumpro_cost = {
1,
1,
3,
1,
4,
0,
17
};
struct processor_costs k6_cost = {
1,
1,
1,
1,
3,
0,
20
};
struct processor_costs *ix86_cost = &pentium_cost;
#define m_386 (1<<PROCESSOR_I386)
#define m_486 (1<<PROCESSOR_I486)
#define m_PENT (1<<PROCESSOR_PENTIUM)
#define m_PPRO (1<<PROCESSOR_PENTIUMPRO)
#define m_K6 (1<<PROCESSOR_K6)
const int x86_use_leave = m_386 | m_K6;
const int x86_push_memory = m_386 | m_K6;
const int x86_zero_extend_with_and = m_486 | m_PENT;
const int x86_movx = m_386 | m_PPRO | m_K6;
const int x86_double_with_add = ~(m_386 | m_PENT | m_PPRO);
const int x86_use_bit_test = m_386;
const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO;
const int x86_use_q_reg = m_PENT | m_PPRO | m_K6;
const int x86_use_any_reg = m_486;
const int x86_cmove = m_PPRO;
const int x86_deep_branch = m_PPRO| m_K6;
#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))
extern FILE *asm_out_file;
extern char *strcat ();
static void ix86_epilogue PROTO((int));
static void ix86_prologue PROTO((int));
char *singlemove_string ();
char *output_move_const_single ();
char *output_fp_cc0_set ();
char *hi_reg_name[] = HI_REGISTER_NAMES;
char *qi_reg_name[] = QI_REGISTER_NAMES;
char *qi_high_reg_name[] = QI_HIGH_REGISTER_NAMES;
#ifdef NEXT_SEMANTICS
static rtx lookup_i386_stack_local ();
#endif
enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
{
AREG, DREG, CREG, BREG,
SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
INDEX_REGS
};
struct rtx_def *i386_compare_op0 = NULL_RTX;
struct rtx_def *i386_compare_op1 = NULL_RTX;
struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
enum processor_type ix86_cpu;
int ix86_arch;
char *ix86_cpu_string;
char *ix86_arch_string;
char *i386_reg_alloc_order;
static char regs_allocated[FIRST_PSEUDO_REGISTER];
char *i386_regparm_string;
int i386_regparm;
char *i386_align_loops_string;
char *i386_align_jumps_string;
char *i386_preferred_stack_boundary_string;
int i386_preferred_stack_boundary;
int i386_branch_cost;
char *i386_branch_cost_string;
int i386_align_funcs;
char *i386_align_funcs_string;
int i386_align_loops;
int i386_align_jumps;
void
override_options ()
{
int ch, i, j;
int def_align;
static struct ptt
{
char *name;
enum processor_type processor;
struct processor_costs *cost;
int target_enable;
int target_disable;
} processor_target_table[] = {
{PROCESSOR_I386_STRING, PROCESSOR_I386, &i386_cost, 0, 0},
{PROCESSOR_I486_STRING, PROCESSOR_I486, &i486_cost, 0, 0},
{PROCESSOR_I586_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
{PROCESSOR_PENTIUM_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
{PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentiumpro_cost, 0, 0},
{PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO,
&pentiumpro_cost, 0, 0},
{PROCESSOR_K6_STRING, PROCESSOR_K6, &k6_cost, 0, 0}
};
int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
#ifdef SUBTARGET_OVERRIDE_OPTIONS
SUBTARGET_OVERRIDE_OPTIONS;
#endif
if (i386_reg_alloc_order)
{
for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
{
int regno = 0;
switch (ch)
{
case 'a': regno = 0; break;
case 'd': regno = 1; break;
case 'c': regno = 2; break;
case 'b': regno = 3; break;
case 'S': regno = 4; break;
case 'D': regno = 5; break;
case 'B': regno = 6; break;
default: fatal ("Register '%c' is unknown", ch);
}
if (regs_allocated[regno])
fatal ("Register '%c' already specified in allocation order", ch);
regs_allocated[regno] = 1;
}
}
if (ix86_arch_string == 0)
{
ix86_arch_string = PROCESSOR_PENTIUM_STRING;
if (ix86_cpu_string == 0)
ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
}
for (i = 0; i < ptt_size; i++)
if (! strcmp (ix86_arch_string, processor_target_table[i].name))
{
ix86_arch = processor_target_table[i].processor;
if (ix86_cpu_string == 0)
ix86_cpu_string = processor_target_table[i].name;
break;
}
if (i == ptt_size)
{
error ("bad value (%s) for -march= switch", ix86_arch_string);
ix86_arch_string = PROCESSOR_PENTIUM_STRING;
ix86_arch = PROCESSOR_DEFAULT;
}
if (ix86_cpu_string == 0)
ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
for (j = 0; j < ptt_size; j++)
if (! strcmp (ix86_cpu_string, processor_target_table[j].name))
{
ix86_cpu = processor_target_table[j].processor;
ix86_cost = processor_target_table[j].cost;
if (i > j && (int) ix86_arch >= (int) PROCESSOR_K6)
error ("-mcpu=%s does not support -march=%s",
ix86_cpu_string, ix86_arch_string);
target_flags |= processor_target_table[j].target_enable;
target_flags &= ~processor_target_table[j].target_disable;
break;
}
if (j == ptt_size)
{
error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);
ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
ix86_cpu = PROCESSOR_DEFAULT;
}
if (i386_regparm_string)
{
i386_regparm = atoi (i386_regparm_string);
if (i386_regparm < 0 || i386_regparm > REGPARM_MAX)
fatal ("-mregparm=%d is not between 0 and %d",
i386_regparm, REGPARM_MAX);
}
def_align = (TARGET_486) ? 4 : 2;
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
i386_align_loops = 4;
#else
i386_align_loops = 2;
#endif
#ifdef NEXT_SEMANTICS
i386_align_loops = 0;
#endif
if (i386_align_loops_string)
{
i386_align_loops = atoi (i386_align_loops_string);
if (i386_align_loops < 0 || i386_align_loops > MAX_CODE_ALIGN)
fatal ("-malign-loops=%d is not between 0 and %d",
i386_align_loops, MAX_CODE_ALIGN);
}
#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
i386_align_jumps = 4;
#else
i386_align_jumps = def_align;
#endif
#ifdef NEXT_SEMANTICS
i386_align_jumps = 0;
#endif
if (i386_align_jumps_string)
{
i386_align_jumps = atoi (i386_align_jumps_string);
if (i386_align_jumps < 0 || i386_align_jumps > MAX_CODE_ALIGN)
fatal ("-malign-jumps=%d is not between 0 and %d",
i386_align_jumps, MAX_CODE_ALIGN);
}
i386_align_funcs = def_align;
if (i386_align_funcs_string)
{
i386_align_funcs = atoi (i386_align_funcs_string);
if (i386_align_funcs < 0 || i386_align_funcs > MAX_CODE_ALIGN)
fatal ("-malign-functions=%d is not between 0 and %d",
i386_align_funcs, MAX_CODE_ALIGN);
}
i386_preferred_stack_boundary = 128;
if (i386_preferred_stack_boundary_string)
{
i = atoi (i386_preferred_stack_boundary_string);
if (i < 2 || i > 31)
fatal ("-mpreferred_stack_boundary=%d is not between 2 and 31", i);
i386_preferred_stack_boundary = (1 << i) * BITS_PER_UNIT;
}
i386_branch_cost = 1;
if (i386_branch_cost_string)
{
i386_branch_cost = atoi (i386_branch_cost_string);
if (i386_branch_cost < 0 || i386_branch_cost > 5)
fatal ("-mbranch-cost=%d is not between 0 and 5", i386_branch_cost);
}
if (TARGET_OMIT_LEAF_FRAME_POINTER)
flag_omit_frame_pointer = 1;
}
void
order_regs_for_local_alloc ()
{
int i, ch, order;
if (i386_reg_alloc_order)
{
for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
{
int regno = 0;
switch (ch)
{
case 'a': regno = 0; break;
case 'd': regno = 1; break;
case 'c': regno = 2; break;
case 'b': regno = 3; break;
case 'S': regno = 4; break;
case 'D': regno = 5; break;
case 'B': regno = 6; break;
}
reg_alloc_order[order++] = regno;
}
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
{
if (! regs_allocated[i])
reg_alloc_order[order++] = i;
}
}
else
{
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
reg_alloc_order[i] = i;
}
}
void
optimization_options (level, size)
int level;
int size ATTRIBUTE_UNUSED;
{
#ifdef INSN_SCHEDULING
if (level > 1)
flag_schedule_insns = 0;
#endif
}
struct rtx_def *
i386_sext16_if_const (op)
struct rtx_def *op;
{
if (GET_CODE (op) == CONST_INT)
{
HOST_WIDE_INT val = INTVAL (op);
HOST_WIDE_INT sext_val;
if (val & 0x8000)
sext_val = val | ~0xffff;
else
sext_val = val & 0xffff;
if (sext_val != val)
op = GEN_INT (sext_val);
}
return op;
}
static int
i386_aligned_reg_p (regno)
int regno;
{
return (regno == STACK_POINTER_REGNUM
|| (! flag_omit_frame_pointer && regno == FRAME_POINTER_REGNUM));
}
int
i386_aligned_p (op)
rtx op;
{
if (GET_CODE (op) != MEM)
return 1;
if (MEM_VOLATILE_P (op))
return 0;
op = XEXP (op, 0);
switch (GET_CODE (op))
{
case CONST_INT:
if (INTVAL (op) & 3)
break;
return 1;
case PLUS:
if (GET_CODE (XEXP (op, 1)) != CONST_INT)
break;
if (INTVAL (XEXP (op, 1)) & 3)
break;
op = XEXP (op, 0);
if (GET_CODE (op) != REG)
break;
case REG:
return i386_aligned_reg_p (REGNO (op));
default:
break;
}
return 0;
}
int
i386_cc_probably_useless_p (insn)
rtx insn;
{
return ! next_cc0_user (insn);
}
int
i386_valid_decl_attribute_p (decl, attributes, identifier, args)
tree decl ATTRIBUTE_UNUSED;
tree attributes ATTRIBUTE_UNUSED;
tree identifier ATTRIBUTE_UNUSED;
tree args ATTRIBUTE_UNUSED;
{
return 0;
}
int
i386_valid_type_attribute_p (type, attributes, identifier, args)
tree type;
tree attributes ATTRIBUTE_UNUSED;
tree identifier;
tree args;
{
if (TREE_CODE (type) != FUNCTION_TYPE
&& TREE_CODE (type) != METHOD_TYPE
&& TREE_CODE (type) != FIELD_DECL
&& TREE_CODE (type) != TYPE_DECL)
return 0;
if (is_attribute_p ("stdcall", identifier))
return (args == NULL_TREE);
if (is_attribute_p ("cdecl", identifier))
return (args == NULL_TREE);
if (is_attribute_p ("regparm", identifier))
{
tree cst;
if (! args || TREE_CODE (args) != TREE_LIST
|| TREE_CHAIN (args) != NULL_TREE
|| TREE_VALUE (args) == NULL_TREE)
return 0;
cst = TREE_VALUE (args);
if (TREE_CODE (cst) != INTEGER_CST)
return 0;
if (TREE_INT_CST_HIGH (cst) != 0
|| TREE_INT_CST_LOW (cst) < 0
|| TREE_INT_CST_LOW (cst) > REGPARM_MAX)
return 0;
return 1;
}
return 0;
}
int
i386_comp_type_attributes (type1, type2)
tree type1;
tree type2;
{
char *rtdstr = TARGET_RTD ? "cdecl" : "stdcall";
if (TREE_CODE (type1) != FUNCTION_TYPE)
return 1;
if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1))
!= !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2)))
return 0;
return 1;
}
int
i386_return_pops_args (fundecl, funtype, size)
tree fundecl;
tree funtype;
int size;
{
int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) {
#if defined (_WIN32) && defined (NEXT_PDO)
if (fundecl && TYPE_STDCALL (fundecl) || TYPE_STDCALL (funtype))
return size;
#endif
if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
rtd = 1;
if (rtd
&& (TYPE_ARG_TYPES (funtype) == NULL_TREE
|| (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype)))
== void_type_node)))
return size;
}
if (aggregate_value_p (TREE_TYPE (funtype)))
return GET_MODE_SIZE (Pmode);
return 0;
}
void
init_cumulative_args (cum, fntype, libname)
CUMULATIVE_ARGS *cum;
tree fntype;
rtx libname;
{
static CUMULATIVE_ARGS zero_cum;
tree param, next_param;
if (TARGET_DEBUG_ARG)
{
fprintf (stderr, "\ninit_cumulative_args (");
if (fntype)
fprintf (stderr, "fntype code = %s, ret code = %s",
tree_code_name[(int) TREE_CODE (fntype)],
tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]);
else
fprintf (stderr, "no fntype");
if (libname)
fprintf (stderr, ", libname = %s", XSTR (libname, 0));
}
*cum = zero_cum;
cum->nregs = i386_regparm;
if (fntype)
{
tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
if (attr)
cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
}
if (cum->nregs)
{
for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
param != 0; param = next_param)
{
next_param = TREE_CHAIN (param);
if (next_param == 0 && TREE_VALUE (param) != void_type_node)
cum->nregs = 0;
}
}
if (TARGET_DEBUG_ARG)
fprintf (stderr, ", nregs=%d )\n", cum->nregs);
return;
}
void
function_arg_advance (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
int bytes
= (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
if (TARGET_DEBUG_ARG)
fprintf (stderr,
"function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n",
words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
cum->words += words;
cum->nregs -= words;
cum->regno += words;
if (cum->nregs <= 0)
{
cum->nregs = 0;
cum->regno = 0;
}
return;
}
struct rtx_def *
function_arg (cum, mode, type, named)
CUMULATIVE_ARGS *cum;
enum machine_mode mode;
tree type;
int named;
{
rtx ret = NULL_RTX;
int bytes
= (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
switch (mode)
{
default:
break;
case BLKmode:
case DImode:
case SImode:
case HImode:
case QImode:
if (words <= cum->nregs)
ret = gen_rtx_REG (mode, cum->regno);
break;
}
if (TARGET_DEBUG_ARG)
{
fprintf (stderr,
"function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d",
words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
if (ret)
fprintf (stderr, ", reg=%%e%s", reg_names[ REGNO(ret) ]);
else
fprintf (stderr, ", stack");
fprintf (stderr, " )\n");
}
return ret;
}
int
function_arg_partial_nregs (cum, mode, type, named)
CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
tree type ATTRIBUTE_UNUSED;
int named ATTRIBUTE_UNUSED;
{
return 0;
}
char *
singlemove_string (operands)
rtx *operands;
{
rtx x;
if (GET_CODE (operands[0]) == MEM
&& GET_CODE (x = XEXP (operands[0], 0)) == PRE_DEC)
{
if (XEXP (x, 0) != stack_pointer_rtx)
abort ();
return "push%L1 %1";
}
else if (GET_CODE (operands[1]) == CONST_DOUBLE)
return output_move_const_single (operands);
else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
return AS2 (mov%L0,%1,%0);
else if (CONSTANT_P (operands[1]))
return AS2 (mov%L0,%1,%0);
else
{
output_asm_insn ("push%L1 %1", operands);
return "pop%L0 %0";
}
}
static void
asm_add (n, x)
int n;
rtx x;
{
rtx xops[2];
xops[0] = x;
if (n == -1)
output_asm_insn (AS1 (dec%L0,%0), xops);
else if (n == 1)
output_asm_insn (AS1 (inc%L0,%0), xops);
else if (n < 0 || n == 128)
{
xops[1] = GEN_INT (-n);
output_asm_insn (AS2 (sub%L0,%1,%0), xops);
}
else if (n > 0)
{
xops[1] = GEN_INT (n);
output_asm_insn (AS2 (add%L0,%1,%0), xops);
}
}
char *
output_move_double (operands)
rtx *operands;
{
enum {REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
rtx latehalf[2];
rtx middlehalf[2];
rtx xops[2];
int dest_overlapped_low = 0;
int size = GET_MODE_SIZE (GET_MODE (operands[0]));
middlehalf[0] = 0;
middlehalf[1] = 0;
if (REG_P (operands[0]))
optype0 = REGOP;
else if (offsettable_memref_p (operands[0]))
optype0 = OFFSOP;
else if (GET_CODE (XEXP (operands[0], 0)) == POST_INC)
optype0 = POPOP;
else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
optype0 = PUSHOP;
else if (GET_CODE (operands[0]) == MEM)
optype0 = MEMOP;
else
optype0 = RNDOP;
if (REG_P (operands[1]))
optype1 = REGOP;
else if (CONSTANT_P (operands[1]))
optype1 = CNSTOP;
else if (offsettable_memref_p (operands[1]))
optype1 = OFFSOP;
else if (GET_CODE (XEXP (operands[1], 0)) == POST_INC)
optype1 = POPOP;
else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
optype1 = PUSHOP;
else if (GET_CODE (operands[1]) == MEM)
optype1 = MEMOP;
else
optype1 = RNDOP;
if (optype0 == RNDOP || optype1 == RNDOP
|| optype0 == MEMOP || optype1 == MEMOP)
abort ();
if (optype0 == PUSHOP && optype1 == POPOP)
{
operands[0] = XEXP (XEXP (operands[0], 0), 0);
asm_add (-size, operands[0]);
if (GET_MODE (operands[1]) == XFmode)
operands[0] = gen_rtx_MEM (XFmode, operands[0]);
else if (GET_MODE (operands[0]) == DFmode)
operands[0] = gen_rtx_MEM (DFmode, operands[0]);
else
operands[0] = gen_rtx_MEM (DImode, operands[0]);
optype0 = OFFSOP;
}
if (optype0 == POPOP && optype1 == PUSHOP)
{
operands[1] = XEXP (XEXP (operands[1], 0), 0);
asm_add (-size, operands[1]);
if (GET_MODE (operands[1]) == XFmode)
operands[1] = gen_rtx_MEM (XFmode, operands[1]);
else if (GET_MODE (operands[1]) == DFmode)
operands[1] = gen_rtx_MEM (DFmode, operands[1]);
else
operands[1] = gen_rtx_MEM (DImode, operands[1]);
optype1 = OFFSOP;
}
if (size == 12)
{
if (optype0 == REGOP)
{
middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
}
else if (optype0 == OFFSOP)
{
middlehalf[0] = adj_offsettable_operand (operands[0], 4);
latehalf[0] = adj_offsettable_operand (operands[0], 8);
}
else
{
middlehalf[0] = operands[0];
latehalf[0] = operands[0];
}
if (optype1 == REGOP)
{
middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
}
else if (optype1 == OFFSOP)
{
middlehalf[1] = adj_offsettable_operand (operands[1], 4);
latehalf[1] = adj_offsettable_operand (operands[1], 8);
}
else if (optype1 == CNSTOP)
{
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r; long l[3];
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_LONG_DOUBLE (r, l);
operands[1] = GEN_INT (l[0]);
middlehalf[1] = GEN_INT (l[1]);
latehalf[1] = GEN_INT (l[2]);
}
else if (CONSTANT_P (operands[1]))
abort ();
}
else
{
middlehalf[1] = operands[1];
latehalf[1] = operands[1];
}
}
else
{
if (optype0 == REGOP)
latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
else if (optype0 == OFFSOP)
latehalf[0] = adj_offsettable_operand (operands[0], 4);
else
latehalf[0] = operands[0];
if (optype1 == REGOP)
latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
else if (optype1 == OFFSOP)
latehalf[1] = adj_offsettable_operand (operands[1], 4);
else if (optype1 == CNSTOP)
split_double (operands[1], &operands[1], &latehalf[1]);
else
latehalf[1] = operands[1];
}
if (optype0 == PUSHOP
&& REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM
&& reg_overlap_mentioned_p (stack_pointer_rtx, operands[1]))
middlehalf[1] = operands[1] = latehalf[1];
if (optype0 == REGOP && optype1 == OFFSOP)
{
if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
&& reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
{
compadr:
xops[0] = latehalf[0];
xops[1] = XEXP (operands[1], 0);
output_asm_insn (AS2 (lea%L0,%a1,%0), xops);
if (GET_MODE (operands[1]) == XFmode)
{
operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);
middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
latehalf[1] = adj_offsettable_operand (operands[1], size-4);
}
else
{
operands[1] = gen_rtx_MEM (DImode, latehalf[0]);
latehalf[1] = adj_offsettable_operand (operands[1], size-4);
}
}
else if (size == 12
&& reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
{
if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
|| reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
goto compadr;
output_asm_insn (singlemove_string (operands), operands);
output_asm_insn (singlemove_string (latehalf), latehalf);
output_asm_insn (singlemove_string (middlehalf), middlehalf);
return "";
}
else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
dest_overlapped_low = 1;
}
#if 0
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& REGNO (operands[0]) == REGNO (latehalf[1]))
|| dest_overlapped_low)
#endif
if (optype0 == PUSHOP || optype1 == PUSHOP
|| (optype0 == REGOP && optype1 == REGOP
&& ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
|| REGNO (operands[0]) == REGNO (latehalf[1])))
|| dest_overlapped_low)
{
output_asm_insn (singlemove_string (latehalf), latehalf);
if (size == 12)
output_asm_insn (singlemove_string (middlehalf), middlehalf);
return singlemove_string (operands);
}
output_asm_insn (singlemove_string (operands), operands);
if (size == 12)
output_asm_insn (singlemove_string (middlehalf), middlehalf);
output_asm_insn (singlemove_string (latehalf), latehalf);
return "";
}
#define MAX_TMPS 2
char *
output_move_pushmem (operands, insn, length, tmp_start, n_operands)
rtx operands[];
rtx insn;
int length;
int tmp_start;
int n_operands;
{
struct
{
char *load;
char *push;
rtx xops[2];
} tmp_info[MAX_TMPS];
rtx src = operands[1];
int max_tmps = 0;
int offset = 0;
int stack_p = reg_overlap_mentioned_p (stack_pointer_rtx, src);
int stack_offset = 0;
int i, num_tmps;
rtx xops[1];
if (! offsettable_memref_p (src))
fatal_insn ("Source is not offsettable", insn);
if ((length & 3) != 0)
fatal_insn ("Pushing non-word aligned size", insn);
for (i = tmp_start; i < n_operands; i++)
{
if (GET_CODE (operands[i]) == REG)
{
if (reg_overlap_mentioned_p (operands[i], src))
continue;
tmp_info[ max_tmps++ ].xops[1] = operands[i];
if (max_tmps == MAX_TMPS)
break;
}
}
if (max_tmps == 0)
for (offset = length - 4; offset >= 0; offset -= 4)
{
xops[0] = adj_offsettable_operand (src, offset + stack_offset);
output_asm_insn (AS1(push%L0,%0), xops);
if (stack_p)
stack_offset += 4;
}
else
for (offset = length - 4; offset >= 0; )
{
for (num_tmps = 0; num_tmps < max_tmps && offset >= 0; num_tmps++)
{
tmp_info[num_tmps].load = AS2(mov%L0,%0,%1);
tmp_info[num_tmps].push = AS1(push%L0,%1);
tmp_info[num_tmps].xops[0]
= adj_offsettable_operand (src, offset + stack_offset);
offset -= 4;
}
for (i = 0; i < num_tmps; i++)
output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
for (i = 0; i < num_tmps; i++)
output_asm_insn (tmp_info[i].push, tmp_info[i].xops);
if (stack_p)
stack_offset += 4*num_tmps;
}
return "";
}
int
standard_80387_constant_p (x)
rtx x;
{
#if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
REAL_VALUE_TYPE d;
jmp_buf handler;
int is0, is1;
if (setjmp (handler))
return 0;
set_float_handler (handler);
REAL_VALUE_FROM_CONST_DOUBLE (d, x);
is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d);
is1 = REAL_VALUES_EQUAL (d, dconst1);
set_float_handler (NULL_PTR);
if (is0)
return 1;
if (is1)
return 2;
#endif
return 0;
}
char *
output_move_const_single (operands)
rtx *operands;
{
if (FP_REG_P (operands[0]))
{
int conval = standard_80387_constant_p (operands[1]);
if (conval == 1)
return "fldz";
if (conval == 2)
return "fld1";
}
if (GET_CODE (operands[1]) == CONST_DOUBLE)
{
REAL_VALUE_TYPE r; long l;
if (GET_MODE (operands[1]) == XFmode)
abort ();
REAL_VALUE_FROM_CONST_DOUBLE (r, operands[1]);
REAL_VALUE_TO_TARGET_SINGLE (r, l);
operands[1] = GEN_INT (l);
}
return singlemove_string (operands);
}
int
symbolic_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
switch (GET_CODE (op))
{
case SYMBOL_REF:
case LABEL_REF:
return 1;
case CONST:
op = XEXP (op, 0);
return (
#if defined(NEXT_SEMANTICS)
GET_CODE (op) == SYMBOL_REF ||
#endif
(GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
&& GET_CODE (XEXP (op, 1)) == CONST_INT);
default:
return 0;
}
}
int
small_shift_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == CONST_INT && INTVAL (op) > 0 && INTVAL (op) < 4);
}
int
call_insn_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == MEM
&& ((CONSTANT_ADDRESS_P (XEXP (op, 0))
&& general_operand (XEXP (op, 0), Pmode))
|| (GET_CODE (XEXP (op, 0)) == REG
&& XEXP (op, 0) != arg_pointer_rtx
&& ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
&& REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
return 1;
return 0;
}
int
expander_call_insn_operand (op, mode)
rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == MEM
&& (CONSTANT_ADDRESS_P (XEXP (op, 0))
|| (GET_CODE (XEXP (op, 0)) == REG
&& XEXP (op, 0) != arg_pointer_rtx
&& ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
&& REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
return 1;
return 0;
}
int
arithmetic_comparison_operator (op, mode)
register rtx op;
enum machine_mode mode;
{
enum rtx_code code;
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
code = GET_CODE (op);
if (GET_RTX_CLASS (code) != '<')
return 0;
return (code != GT && code != LE);
}
int
ix86_logical_operator (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
}
int
symbolic_reference_mentioned_p (op)
rtx op;
{
register char *fmt;
register int i;
if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
return 1;
fmt = GET_RTX_FORMAT (GET_CODE (op));
for (i = GET_RTX_LENGTH (GET_CODE (op)) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (op, i) - 1; j >= 0; j--)
if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
return 1;
}
else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
return 1;
}
return 0;
}
int
ix86_expand_binary_operator (code, mode, operands)
enum rtx_code code;
enum machine_mode mode;
rtx operands[];
{
int modified;
if (GET_RTX_CLASS (code) == 'c'
&& (rtx_equal_p (operands[0], operands[2])
|| immediate_operand (operands[1], mode)))
{
rtx temp = operands[1];
operands[1] = operands[2];
operands[2] = temp;
}
if (TARGET_PSEUDO && optimize
&& ((reload_in_progress | reload_completed) == 0))
{
if (GET_CODE (operands[1]) == MEM
&& ! rtx_equal_p (operands[0], operands[1]))
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
if (GET_CODE (operands[2]) == MEM)
operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
{
rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
emit_move_insn (temp, operands[1]);
operands[1] = temp;
return TRUE;
}
}
if (!ix86_binary_operator_ok (code, mode, operands))
{
if ((! TARGET_PSEUDO || !optimize)
&& ((reload_in_progress | reload_completed) == 0)
&& (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM))
{
modified = FALSE;
if (GET_CODE (operands[1]) == MEM
&& ! rtx_equal_p (operands[0], operands[1]))
{
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
modified = TRUE;
}
if (GET_CODE (operands[2]) == MEM)
{
operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
modified = TRUE;
}
if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
{
rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
emit_move_insn (temp, operands[1]);
operands[1] = temp;
return TRUE;
}
if (modified && ! ix86_binary_operator_ok (code, mode, operands))
return FALSE;
}
else
return FALSE;
}
return TRUE;
}
int
ix86_binary_operator_ok (code, mode, operands)
enum rtx_code code;
enum machine_mode mode ATTRIBUTE_UNUSED;
rtx operands[3];
{
return (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)
&& (GET_CODE (operands[1]) != CONST_INT || GET_RTX_CLASS (code) == 'c');
}
int
ix86_expand_unary_operator (code, mode, operands)
enum rtx_code code;
enum machine_mode mode;
rtx operands[];
{
if (TARGET_PSEUDO
&& optimize
&& ((reload_in_progress | reload_completed) == 0)
&& GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
if (! ix86_unary_operator_ok (code, mode, operands))
{
if ((! TARGET_PSEUDO || optimize == 0)
&& ((reload_in_progress | reload_completed) == 0)
&& GET_CODE (operands[1]) == MEM)
{
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
if (! ix86_unary_operator_ok (code, mode, operands))
return FALSE;
}
else
return FALSE;
}
return TRUE;
}
int
ix86_unary_operator_ok (code, mode, operands)
enum rtx_code code ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
rtx operands[2] ATTRIBUTE_UNUSED;
{
return TRUE;
}
static rtx pic_label_rtx;
static char pic_label_name [256];
static int pic_label_no = 0;
void
asm_output_function_prefix (file, name)
FILE *file;
char *name ATTRIBUTE_UNUSED;
{
rtx xops[2];
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
xops[0] = pic_offset_table_rtx;
xops[1] = stack_pointer_rtx;
if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
{
tree prologue_node;
if (pic_label_rtx == 0)
{
pic_label_rtx = gen_label_rtx ();
ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
LABEL_NAME (pic_label_rtx) = pic_label_name;
}
prologue_node = make_node (FUNCTION_DECL);
DECL_RESULT (prologue_node) = 0;
ASM_OUTPUT_LABEL (file, pic_label_name);
output_asm_insn ("movl (%1),%0", xops);
output_asm_insn ("ret", xops);
}
}
void
function_prologue (file, size)
FILE *file ATTRIBUTE_UNUSED;
int size ATTRIBUTE_UNUSED;
{
if (TARGET_SCHEDULE_PROLOGUE)
{
pic_label_rtx = 0;
return;
}
ix86_prologue (0);
}
void
ix86_expand_prologue ()
{
if (! TARGET_SCHEDULE_PROLOGUE)
return;
ix86_prologue (1);
}
void
load_pic_register (int do_rtl, int is_picreg_reload)
{
rtx xops[4];
if (TARGET_DEEP_BRANCH_PREDICTION)
{
xops[0] = pic_offset_table_rtx;
if (pic_label_rtx == 0)
{
pic_label_rtx = gen_label_rtx ();
ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
LABEL_NAME (pic_label_rtx) = pic_label_name;
}
xops[1] = gen_rtx_MEM (QImode,
gen_rtx (SYMBOL_REF, Pmode,
LABEL_NAME (pic_label_rtx)));
if (do_rtl)
{
emit_insn (gen_prologue_get_pc (xops[0], xops[1]));
emit_insn (gen_prologue_set_got (xops[0],
#ifdef YES_UNDERSCORES
gen_rtx_SYMBOL_REF (Pmode,
"$__GLOBAL_OFFSET_TABLE_"),
#else
gen_rtx_SYMBOL_REF (Pmode,
"$_GLOBAL_OFFSET_TABLE_"),
#endif
xops[1]));
}
else
{
output_asm_insn (AS1 (call,%X1), xops);
output_asm_insn ("addl $%__GLOBAL_OFFSET_TABLE_,%0", xops);
pic_label_rtx = 0;
}
}
else
{
#if defined(MACHO_PIC) && !defined(FIXED_PIC_REG)
const int pic_reg = pic86_reg_num;
xops[0] = 0;
if (pic_offset_table_rtx == 0)
abort();
if ((pic_reg >= 0 && pic_reg < FIRST_PSEUDO_REGISTER)
|| (GET_CODE (pic_offset_table_rtx) == REG
&& REGNO (pic_offset_table_rtx) < FIRST_PSEUDO_REGISTER))
#endif
xops[0] = pic_offset_table_rtx;
#if defined(MACHO_PIC) && !defined(FIXED_PIC_REG)
else if (reg_renumber && pic_reg >= 0 && reg_renumber[pic_reg] >= 0)
xops[0] = gen_rtx_REG (SImode, reg_renumber[pic_reg]);
if (! xops[0])
{
if (pic_offset_table_rtx && GET_CODE (pic_offset_table_rtx) == MEM)
xops[0] = pic_offset_table_rtx;
}
if (xops[0])
{
#endif
if (do_rtl)
{
emit_insn (gen_prologue_get_pc_and_set_got
(xops[0], is_picreg_reload ? const1_rtx : const0_rtx));
}
else
{
#ifdef MACHO_PIC
const char *pic_label = machopic_function_base_name ();
if (*pic_label == '*')
++pic_label;
if (! is_picreg_reload)
{
fprintf (asm_out_file, "\tcall %s\n%s:\n", pic_label, pic_label);
}
else
#endif
{
xops[1] = gen_label_rtx ();
output_asm_insn (AS1 (call,%P1), xops);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xops[1]));
}
output_asm_insn (AS1 (pop%L0,%0), xops);
#ifdef MACHO_PIC
if (is_picreg_reload)
{
char buf[256];
sprintf (buf, "subl %%P1-%s,%%0", pic_label);
output_asm_insn (buf, xops);
}
#if !defined(FIXED_PIC_REG)
{
xops[1] = lookup_i386_stack_local (SImode, 2);
if (xops[1] != NULL_RTX && xops[0] != xops[1])
if (GET_CODE(xops[0]) == REG)
output_asm_insn ("movl %0,%1", xops);
else
{
output_asm_insn ("pushl %0", xops);
output_asm_insn ("popl %1", xops);
}
}
#endif
#else
output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
#endif
}
}
if (do_rtl)
emit_insn (gen_blockage ());
}
HOST_WIDE_INT
ix86_compute_frame_size (size, nregs_on_stack)
HOST_WIDE_INT size;
int *nregs_on_stack;
{
int limit;
int nregs;
int regno;
int padding;
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
HOST_WIDE_INT total_size;
limit = frame_pointer_needed
? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;
nregs = 0;
for (regno = limit - 1; regno >= 0; regno--)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
nregs++;
padding = 0;
total_size = size + (nregs * UNITS_PER_WORD);
#ifdef PREFERRED_STACK_BOUNDARY
{
int offset;
int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
offset = 4;
if (frame_pointer_needed)
offset += UNITS_PER_WORD;
total_size += offset;
padding = ((total_size + preferred_alignment - 1)
& -preferred_alignment) - total_size;
if (padding < (((offset + preferred_alignment - 1)
& -preferred_alignment) - offset))
padding += preferred_alignment;
if (size == 0 && current_function_is_leaf)
padding = 0;
}
#endif
if (nregs_on_stack)
*nregs_on_stack = nregs;
return size + padding;
}
static void
ix86_prologue (do_rtl)
int do_rtl;
{
register int regno;
int limit;
rtx xops[4];
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0);
rtx insn;
int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
xops[0] = stack_pointer_rtx;
xops[1] = frame_pointer_rtx;
xops[2] = GEN_INT (tsize);
if (frame_pointer_needed)
{
if (do_rtl)
{
insn = emit_insn (gen_rtx (SET, VOIDmode,
gen_rtx_MEM (SImode,
gen_rtx (PRE_DEC, SImode,
stack_pointer_rtx)),
frame_pointer_rtx));
RTX_FRAME_RELATED_P (insn) = 1;
insn = emit_move_insn (xops[1], xops[0]);
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
output_asm_insn ("push%L1 %1", xops);
#ifdef INCOMING_RETURN_ADDR_RTX
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
cfa_store_offset += 4;
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, - cfa_store_offset);
}
#endif
output_asm_insn (AS2 (mov%L0,%0,%1), xops);
#ifdef INCOMING_RETURN_ADDR_RTX
if (dwarf2out_do_frame ())
dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset);
#endif
}
}
#ifdef _WIN32
if (tsize >= 4096)
{
rtx yops[4];
yops[0] = gen_rtx( REG, SImode, 0 ); yops[1] = GEN_INT( tsize );
output_asm_insn( AS2( mov%L1, %1, %0 ), yops ); output_asm_insn( "call __chkstk", yops ); }
else
#endif
if (tsize == 0)
;
else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
{
if (do_rtl)
{
insn = emit_insn (gen_prologue_set_stack_ptr (xops[2]));
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
output_asm_insn (AS2 (sub%L0,%2,%0), xops);
#ifdef INCOMING_RETURN_ADDR_RTX
if (dwarf2out_do_frame ())
{
cfa_store_offset += tsize;
if (! frame_pointer_needed)
{
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
}
}
#endif
}
}
else
{
xops[3] = gen_rtx_REG (SImode, 0);
if (do_rtl)
emit_move_insn (xops[3], xops[2]);
else
output_asm_insn (AS2 (mov%L0,%2,%3), xops);
xops[3] = gen_rtx_MEM (FUNCTION_MODE,
gen_rtx (SYMBOL_REF, Pmode, "_alloca"));
if (do_rtl)
emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx));
else
output_asm_insn (AS1 (call,%P3), xops);
}
limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
for (regno = limit - 1; regno >= 0; regno--)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
#if !defined(MACHO_PIC) || defined(FIXED_PIC_REG)
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
#else
)
#endif
{
xops[0] = gen_rtx_REG (SImode, regno);
if (do_rtl)
{
insn = emit_insn (gen_rtx (SET, VOIDmode,
gen_rtx_MEM (SImode,
gen_rtx (PRE_DEC, SImode,
stack_pointer_rtx)),
xops[0]));
RTX_FRAME_RELATED_P (insn) = 1;
}
else
{
output_asm_insn ("push%L0 %0", xops);
#ifdef INCOMING_RETURN_ADDR_RTX
if (dwarf2out_do_frame ())
{
char *l = dwarf2out_cfi_label ();
cfa_store_offset += 4;
if (! frame_pointer_needed)
{
cfa_offset = cfa_store_offset;
dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
}
dwarf2out_reg_save (l, regno, - cfa_store_offset);
}
#endif
}
}
#ifdef NEXT_SEMANTICS
if (profile_flag)
#ifdef MACHO_PIC
if (flag_pic)
{
output_asm_insn ("call Lmcount$stub", NULL);
mcount_called = 1;
}
else
#endif
output_asm_insn ("call mcount", NULL);
#endif
#ifdef SUBTARGET_PROLOGUE
SUBTARGET_PROLOGUE;
#endif
if (pic_reg_used)
load_pic_register (do_rtl, 0);
#ifdef NEXT_SEMANTICS
if (tsize)
{
extern int flag_check_mem;
xops[2] = GEN_INT (tsize);
if (flag_check_mem)
output_asm_insn ("push%L0 %2\n\tcall _check_mem_enter", xops);
}
#endif
if ((profile_flag || profile_block_flag)
&& ! pic_reg_used && do_rtl)
emit_insn (gen_blockage ());
}
int
ix86_can_use_return_insn_p ()
{
int regno;
int nregs = 0;
int reglimit = (frame_pointer_needed
? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
#ifdef NON_SAVING_SETJMP
if (NON_SAVING_SETJMP && current_function_calls_setjmp)
return 0;
#endif
if (! reload_completed)
return 0;
for (regno = reglimit - 1; regno >= 0; regno--)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
#if !defined(MACHO_PIC) || defined(FIXED_PIC_REG)
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
#else
)
#endif
nregs++;
return nregs == 0 || ! frame_pointer_needed;
}
void
function_epilogue (file, size)
FILE *file ATTRIBUTE_UNUSED;
int size ATTRIBUTE_UNUSED;
{
return;
}
void
ix86_expand_epilogue ()
{
ix86_epilogue (1);
}
static void
ix86_epilogue (do_rtl)
int do_rtl;
{
register int regno;
register int limit;
int nregs;
rtx xops[3];
int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
|| current_function_uses_const_pool);
int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
HOST_WIDE_INT offset;
HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs);
offset = -(tsize + nregs * UNITS_PER_WORD);
xops[2] = stack_pointer_rtx;
if (flag_pic || profile_flag || profile_block_flag)
emit_insn (gen_blockage ());
limit = frame_pointer_needed
? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;
if (nregs > 1 || sp_valid)
{
if ( !sp_valid )
{
xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
if (do_rtl)
emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0)));
else
output_asm_insn (AS2 (lea%L2,%0,%2), xops);
}
for (regno = 0; regno < limit; regno++)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
#if !defined(MACHO_PIC) || defined(FIXED_PIC_REG)
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
#else
)
#endif
{
xops[0] = gen_rtx_REG (SImode, regno);
if (do_rtl)
emit_insn (gen_pop (xops[0]));
else
output_asm_insn ("pop%L0 %0", xops);
}
}
else
for (regno = 0; regno < limit; regno++)
if ((regs_ever_live[regno] && ! call_used_regs[regno])
#if !defined(MACHO_PIC) || defined(FIXED_PIC_REG)
|| (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
#else
)
#endif
{
xops[0] = gen_rtx_REG (SImode, regno);
xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
if (do_rtl)
emit_move_insn (xops[0], xops[1]);
else
output_asm_insn (AS2 (mov%L0,%1,%0), xops);
offset += 4;
}
if (frame_pointer_needed)
{
if (TARGET_USE_LEAVE)
{
if (do_rtl)
emit_insn (gen_leave());
else
output_asm_insn ("leave", xops);
}
else
{
xops[0] = frame_pointer_rtx;
xops[1] = stack_pointer_rtx;
if (do_rtl)
{
emit_insn (gen_epilogue_set_stack_ptr());
emit_insn (gen_pop (xops[0]));
}
else
{
output_asm_insn (AS2 (mov%L2,%0,%2), xops);
output_asm_insn ("pop%L0 %0", xops);
}
}
}
else if (tsize)
{
int use_pop = tsize == 4;
if (tsize == 8 && !TARGET_386 && !TARGET_486)
{
rtx retval = current_function_return_rtx;
xops[1] = gen_rtx_REG (SImode, 1);
use_pop = (retval == NULL
|| ! reg_overlap_mentioned_p (xops[1], retval));
}
if (use_pop)
{
xops[0] = gen_rtx_REG (SImode, 2);
if (do_rtl)
{
emit_insn (gen_blockage ());
emit_insn (gen_pop (xops[0]));
if (tsize == 8)
emit_insn (gen_pop (xops[1]));
}
else
{
output_asm_insn ("pop%L0 %0", xops);
if (tsize == 8)
output_asm_insn ("pop%L1 %1", xops);
}
}
else
{
xops[0] = GEN_INT (tsize);
if (do_rtl)
emit_insn (gen_rtx (SET, VOIDmode, xops[2],
gen_rtx (PLUS, SImode, xops[2], xops[0])));
else
output_asm_insn (AS2 (add%L2,%0,%2), xops);
}
}
#ifdef FUNCTION_BLOCK_PROFILER_EXIT
if (profile_block_flag == 2)
{
FUNCTION_BLOCK_PROFILER_EXIT(file);
}
#endif
#ifdef NEXT_SEMANTICS
if (flag_check_mem)
{
xops[0] = GEN_INT (tsize);
output_asm_insn ("push%L0 %0\n\tcall _check_mem_exit", xops);
}
#endif
if (current_function_pops_args && current_function_args_size)
{
xops[1] = GEN_INT (current_function_pops_args);
if (current_function_pops_args >= 32768)
{
xops[0] = gen_rtx_REG (SImode, 2);
if (do_rtl)
{
emit_insn (gen_pop (xops[0]));
emit_insn (gen_rtx (SET, VOIDmode, xops[2],
gen_rtx (PLUS, SImode, xops[1], xops[2])));
emit_jump_insn (xops[0]);
}
else
{
output_asm_insn ("pop%L0 %0", xops);
output_asm_insn (AS2 (add%L2,%1,%2), xops);
output_asm_insn ("jmp %*%0", xops);
}
}
else
{
if (do_rtl)
emit_jump_insn (gen_return_pop_internal (xops[1]));
else
output_asm_insn ("ret %1", xops);
}
}
else
{
if (do_rtl)
emit_jump_insn (gen_return_internal ());
else
output_asm_insn ("ret", xops);
}
}
#define ADDR_INVALID(msg,insn) \
do { \
if (TARGET_DEBUG_ADDR) \
{ \
fprintf (stderr, msg); \
debug_rtx (insn); \
} \
} while (0)
int
legitimate_pic_address_disp_p (disp)
register rtx disp;
{
if (GET_CODE (disp) != CONST)
return 0;
disp = XEXP (disp, 0);
if (GET_CODE (disp) == PLUS)
{
if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
return 0;
disp = XEXP (disp, 0);
}
if (GET_CODE (disp) != UNSPEC
|| XVECLEN (disp, 0) != 1)
return 0;
if (XINT (disp, 1) != 6
&& XINT (disp, 1) != 7)
return 0;
if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF
&& GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)
return 0;
return 1;
}
int
legitimate_address_p (mode, addr, strict)
enum machine_mode mode;
register rtx addr;
int strict;
{
rtx base = NULL_RTX;
rtx indx = NULL_RTX;
rtx scale = NULL_RTX;
rtx disp = NULL_RTX;
if (TARGET_DEBUG_ADDR)
{
fprintf (stderr,
"\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
GET_MODE_NAME (mode), strict);
debug_rtx (addr);
}
if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
base = addr;
else if (GET_CODE (addr) == PLUS)
{
rtx op0 = XEXP (addr, 0);
rtx op1 = XEXP (addr, 1);
enum rtx_code code0 = GET_CODE (op0);
enum rtx_code code1 = GET_CODE (op1);
if (code0 == REG || code0 == SUBREG)
{
if (code1 == REG || code1 == SUBREG)
{
indx = op0;
base = op1;
}
else
{
base = op0;
disp = op1;
}
}
else if (code0 == MULT)
{
indx = XEXP (op0, 0);
scale = XEXP (op0, 1);
if (code1 == REG || code1 == SUBREG)
base = op1;
else
disp = op1;
}
else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
{
indx = XEXP (XEXP (op0, 0), 0);
scale = XEXP (XEXP (op0, 0), 1);
base = XEXP (op0, 1);
disp = op1;
}
else if (code0 == PLUS)
{
indx = XEXP (op0, 0);
base = XEXP (op0, 1);
disp = op1;
}
else
{
ADDR_INVALID ("PLUS subcode is not valid.\n", op0);
return FALSE;
}
}
else if (GET_CODE (addr) == MULT)
{
indx = XEXP (addr, 0);
scale = XEXP (addr, 1);
}
else
disp = addr;
if (base && indx && !scale
&& (indx == arg_pointer_rtx || indx == stack_pointer_rtx))
{
rtx tmp = base;
base = indx;
indx = tmp;
}
if (base)
{
if (GET_CODE (base) != REG)
{
ADDR_INVALID ("Base is not a register.\n", base);
return FALSE;
}
if (GET_MODE (base) != Pmode)
{
ADDR_INVALID ("Base is not in Pmode.\n", base);
return FALSE;
}
if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
|| (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
{
ADDR_INVALID ("Base is not valid.\n", base);
return FALSE;
}
}
if (indx)
{
if (GET_CODE (indx) != REG)
{
ADDR_INVALID ("Index is not a register.\n", indx);
return FALSE;
}
if (GET_MODE (indx) != Pmode)
{
ADDR_INVALID ("Index is not in Pmode.\n", indx);
return FALSE;
}
if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (indx))
|| (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
{
ADDR_INVALID ("Index is not valid.\n", indx);
return FALSE;
}
}
else if (scale)
abort ();
if (scale)
{
HOST_WIDE_INT value;
if (GET_CODE (scale) != CONST_INT)
{
ADDR_INVALID ("Scale is not valid.\n", scale);
return FALSE;
}
value = INTVAL (scale);
if (value != 1 && value != 2 && value != 4 && value != 8)
{
ADDR_INVALID ("Scale is not a good multiplier.\n", scale);
return FALSE;
}
}
if (disp)
{
if (!CONSTANT_ADDRESS_P (disp))
{
ADDR_INVALID ("Displacement is not valid.\n", disp);
return FALSE;
}
else if (GET_CODE (disp) == CONST_DOUBLE)
{
ADDR_INVALID ("Displacement is a const_double.\n", disp);
return FALSE;
}
if (flag_pic && SYMBOLIC_CONST (disp))
{
if (! legitimate_pic_address_disp_p (disp))
{
ADDR_INVALID ("Displacement is an invalid PIC construct.\n",
disp);
return FALSE;
}
if (base != pic_offset_table_rtx
&& (indx != pic_offset_table_rtx || scale != NULL_RTX))
{
ADDR_INVALID ("PIC displacement against invalid base.\n", disp);
return FALSE;
}
}
else if (HALF_PIC_P ())
{
if (! HALF_PIC_ADDRESS_P (disp)
|| (base != NULL_RTX || indx != NULL_RTX))
{
ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
disp);
return FALSE;
}
}
}
if (TARGET_DEBUG_ADDR)
fprintf (stderr, "Address is valid.\n");
return TRUE;
}
rtx
legitimize_pic_address (orig, reg)
rtx orig;
rtx reg;
{
rtx addr = orig;
rtx new = orig;
rtx base;
#if defined(MACHO_PIC)
if (reg == 0)
reg = gen_reg_rtx (Pmode);
return machopic_legitimize_pic_address (orig, GET_MODE (orig), reg);
#endif
if (GET_CODE (addr) == LABEL_REF
|| (GET_CODE (addr) == SYMBOL_REF
&& (CONSTANT_POOL_ADDRESS_P (addr)
|| SYMBOL_REF_FLAG (addr))))
{
current_function_uses_pic_offset_table = 1;
new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 7);
new = gen_rtx_CONST (VOIDmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
if (reg != 0)
{
emit_move_insn (reg, new);
new = reg;
}
}
else if (GET_CODE (addr) == SYMBOL_REF)
{
current_function_uses_pic_offset_table = 1;
new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 6);
new = gen_rtx_CONST (VOIDmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
new = gen_rtx_MEM (Pmode, new);
RTX_UNCHANGING_P (new) = 1;
if (reg == 0)
reg = gen_reg_rtx (Pmode);
emit_move_insn (reg, new);
new = reg;
}
else
{
if (GET_CODE (addr) == CONST)
{
addr = XEXP (addr, 0);
if (GET_CODE (addr) == UNSPEC)
{
}
else if (GET_CODE (addr) != PLUS)
abort();
}
if (GET_CODE (addr) == PLUS)
{
rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
if ((GET_CODE (op0) == LABEL_REF
|| (GET_CODE (op0) == SYMBOL_REF
&& (CONSTANT_POOL_ADDRESS_P (op0)
|| SYMBOL_REF_FLAG (op0))))
&& GET_CODE (op1) == CONST_INT)
{
current_function_uses_pic_offset_table = 1;
new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, op0), 7);
new = gen_rtx_PLUS (VOIDmode, new, op1);
new = gen_rtx_CONST (VOIDmode, new);
new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
if (reg != 0)
{
emit_move_insn (reg, new);
new = reg;
}
}
else
{
base = legitimize_pic_address (XEXP (addr, 0), reg);
new = legitimize_pic_address (XEXP (addr, 1),
base == reg ? NULL_RTX : reg);
if (GET_CODE (new) == CONST_INT)
new = plus_constant (base, INTVAL (new));
else
{
if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1)))
{
base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0));
new = XEXP (new, 1);
}
new = gen_rtx_PLUS (Pmode, base, new);
}
}
}
}
return new;
}
void
emit_pic_move (operands, mode)
rtx *operands;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
#ifdef MACHO_PIC
if (MACHOPIC_PURE)
{
operands[1] = machopic_indirect_data_reference (operands[1], temp);
operands[1] = machopic_legitimize_pic_address (operands[1], mode,
temp == operands[1] ? 0 : temp);
}
else
{
if (MACHOPIC_INDIRECT)
operands[1] = machopic_indirect_data_reference (operands[1], 0);
}
#else
if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
operands[1] = force_reg (Pmode, operands[1]);
else
operands[1] = legitimize_pic_address (operands[1], temp);
#endif
}
rtx
legitimize_address (x, oldx, mode)
register rtx x;
register rtx oldx ATTRIBUTE_UNUSED;
enum machine_mode mode;
{
int changed = 0;
unsigned log;
if (TARGET_DEBUG_ADDR)
{
fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n",
GET_MODE_NAME (mode));
debug_rtx (x);
}
if (flag_pic && SYMBOLIC_CONST (x))
return legitimize_pic_address (x, 0);
if (GET_CODE (x) == ASHIFT
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4)
{
changed = 1;
x = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (x, 0)),
GEN_INT (1 << log));
}
if (GET_CODE (x) == PLUS)
{
if (GET_CODE (XEXP (x, 0)) == ASHIFT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
&& (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4)
{
changed = 1;
XEXP (x, 0) = gen_rtx (MULT, Pmode,
force_reg (Pmode, XEXP (XEXP (x, 0), 0)),
GEN_INT (1 << log));
}
if (GET_CODE (XEXP (x, 1)) == ASHIFT
&& GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
&& (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 1), 1)))) < 4)
{
changed = 1;
XEXP (x, 1) = gen_rtx (MULT, Pmode,
force_reg (Pmode, XEXP (XEXP (x, 1), 0)),
GEN_INT (1 << log));
}
if (GET_CODE (XEXP (x, 1)) == MULT)
{
rtx tmp = XEXP (x, 0);
XEXP (x, 0) = XEXP (x, 1);
XEXP (x, 1) = tmp;
changed = 1;
}
if (GET_CODE (XEXP (x, 0)) == MULT && GET_CODE (XEXP (x, 1)) == PLUS)
{
changed = 1;
x = gen_rtx (PLUS, Pmode,
gen_rtx (PLUS, Pmode, XEXP (x, 0),
XEXP (XEXP (x, 1), 0)),
XEXP (XEXP (x, 1), 1));
}
else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS
&& CONSTANT_P (XEXP (x, 1)))
{
rtx constant;
rtx other = NULL_RTX;
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
constant = XEXP (x, 1);
other = XEXP (XEXP (XEXP (x, 0), 1), 1);
}
else if (GET_CODE (XEXP (XEXP (XEXP (x, 0), 1), 1)) == CONST_INT)
{
constant = XEXP (XEXP (XEXP (x, 0), 1), 1);
other = XEXP (x, 1);
}
else
constant = 0;
if (constant)
{
changed = 1;
x = gen_rtx (PLUS, Pmode,
gen_rtx (PLUS, Pmode, XEXP (XEXP (x, 0), 0),
XEXP (XEXP (XEXP (x, 0), 1), 0)),
plus_constant (other, INTVAL (constant)));
}
}
if (changed && legitimate_address_p (mode, x, FALSE))
return x;
if (GET_CODE (XEXP (x, 0)) == MULT)
{
changed = 1;
XEXP (x, 0) = force_operand (XEXP (x, 0), 0);
}
if (GET_CODE (XEXP (x, 1)) == MULT)
{
changed = 1;
XEXP (x, 1) = force_operand (XEXP (x, 1), 0);
}
if (changed
&& GET_CODE (XEXP (x, 1)) == REG
&& GET_CODE (XEXP (x, 0)) == REG)
return x;
if (flag_pic && SYMBOLIC_CONST (XEXP (x, 1)))
{
changed = 1;
x = legitimize_pic_address (x, 0);
}
if (changed && legitimate_address_p (mode, x, FALSE))
return x;
if (GET_CODE (XEXP (x, 0)) == REG)
{
register rtx temp = gen_reg_rtx (Pmode);
register rtx val = force_operand (XEXP (x, 1), temp);
if (val != temp)
emit_move_insn (temp, val);
XEXP (x, 1) = temp;
return x;
}
else if (GET_CODE (XEXP (x, 1)) == REG)
{
register rtx temp = gen_reg_rtx (Pmode);
register rtx val = force_operand (XEXP (x, 0), temp);
if (val != temp)
emit_move_insn (temp, val);
XEXP (x, 0) = temp;
return x;
}
}
return x;
}
static void
output_pic_addr_const (file, x, code)
FILE *file;
rtx x;
int code;
{
char buf[256];
switch (GET_CODE (x))
{
case PC:
if (flag_pic)
putc ('.', file);
else
abort ();
break;
case SYMBOL_REF:
assemble_name (file, XSTR (x, 0));
#if !defined(MACHO_PIC)
if (code == 'P' && ! SYMBOL_REF_FLAG (x))
fputs ("@PLT", file);
#endif
break;
case LABEL_REF:
x = XEXP (x, 0);
case CODE_LABEL:
ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
assemble_name (asm_out_file, buf);
break;
case CONST_INT:
fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
break;
case CONST:
output_pic_addr_const (file, XEXP (x, 0), code);
break;
case CONST_DOUBLE:
if (GET_MODE (x) == VOIDmode)
{
if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
fprintf (file, "0x%lx%08lx",
(unsigned long) CONST_DOUBLE_HIGH (x),
(unsigned long) CONST_DOUBLE_LOW (x));
else
fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
}
else
output_operand_lossage ("floating constant misused");
break;
case PLUS:
if (GET_CODE (XEXP (x, 0)) == CONST_INT)
{
output_pic_addr_const (file, XEXP (x, 0), code);
fprintf (file, "+");
output_pic_addr_const (file, XEXP (x, 1), code);
}
else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
{
output_pic_addr_const (file, XEXP (x, 1), code);
fprintf (file, "+");
output_pic_addr_const (file, XEXP (x, 0), code);
}
else
abort ();
break;
case MINUS:
output_pic_addr_const (file, XEXP (x, 0), code);
fprintf (file, "-");
output_pic_addr_const (file, XEXP (x, 1), code);
break;
#if !defined(MACHO_PIC)
case UNSPEC:
if (XVECLEN (x, 0) != 1)
abort ();
output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
switch (XINT (x, 1))
{
case 6:
fputs ("@GOT", file);
break;
case 7:
fputs ("@GOTOFF", file);
break;
case 8:
fputs ("@PLT", file);
break;
default:
output_operand_lossage ("invalid UNSPEC as operand");
break;
}
break;
#endif
default:
output_operand_lossage ("invalid expression as operand");
}
}
static void
put_jump_code (code, reverse, file)
enum rtx_code code;
int reverse;
FILE *file;
{
int flags = cc_prev_status.flags;
int ieee = (TARGET_IEEE_FP && (flags & CC_IN_80387)
&& !(cc_prev_status.flags & CC_FCOMI));
const char *suffix;
if (flags & CC_Z_IN_NOT_C)
switch (code)
{
case EQ:
fputs (reverse ? "c" : "nc", file);
return;
case NE:
fputs (reverse ? "nc" : "c", file);
return;
default:
abort ();
}
if (ieee)
{
switch (code)
{
case LE:
suffix = reverse ? "ae" : "b";
break;
case GT:
case LT:
case GE:
suffix = reverse ? "ne" : "e";
break;
case EQ:
suffix = reverse ? "ne" : "e";
break;
case NE:
suffix = reverse ? "e" : "ne";
break;
default:
abort ();
}
fputs (suffix, file);
return;
}
if (flags & CC_TEST_AX)
abort();
if ((flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
abort ();
if (reverse)
code = reverse_condition (code);
switch (code)
{
case EQ:
suffix = "e";
break;
case NE:
suffix = "ne";
break;
case GT:
suffix = flags & CC_IN_80387 ? "a" : "g";
break;
case GTU:
suffix = "a";
break;
case LT:
if (flags & CC_NO_OVERFLOW)
suffix = "s";
else
suffix = flags & CC_IN_80387 ? "b" : "l";
break;
case LTU:
suffix = "b";
break;
case GE:
if (flags & CC_NO_OVERFLOW)
suffix = "ns";
else
suffix = flags & CC_IN_80387 ? "ae" : "ge";
break;
case GEU:
suffix = "ae";
break;
case LE:
suffix = flags & CC_IN_80387 ? "be" : "le";
break;
case LEU:
suffix = "be";
break;
default:
abort ();
}
fputs (suffix, file);
}
static void
put_condition_code (code, reverse_cc, mode, file)
enum rtx_code code;
int reverse_cc;
enum mode_class mode;
FILE * file;
{
int ieee = (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
&& ! (cc_prev_status.flags & CC_FCOMI));
if (reverse_cc && ! ieee)
code = reverse_condition (code);
if (mode == MODE_INT)
switch (code)
{
case NE:
if (cc_prev_status.flags & CC_Z_IN_NOT_C)
fputs ("b", file);
else
fputs ("ne", file);
return;
case EQ:
if (cc_prev_status.flags & CC_Z_IN_NOT_C)
fputs ("ae", file);
else
fputs ("e", file);
return;
case GE:
if (cc_prev_status.flags & CC_NO_OVERFLOW)
fputs ("ns", file);
else
fputs ("ge", file);
return;
case GT:
fputs ("g", file);
return;
case LE:
fputs ("le", file);
return;
case LT:
if (cc_prev_status.flags & CC_NO_OVERFLOW)
fputs ("s", file);
else
fputs ("l", file);
return;
case GEU:
fputs ("ae", file);
return;
case GTU:
fputs ("a", file);
return;
case LEU:
fputs ("be", file);
return;
case LTU:
fputs ("b", file);
return;
default:
output_operand_lossage ("Invalid %%C operand");
}
else if (mode == MODE_FLOAT)
switch (code)
{
case NE:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "ne", file);
return;
case EQ:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "e", file);
return;
case GE:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
return;
case GT:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
return;
case LE:
fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
return;
case LT:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
return;
case GEU:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
return;
case GTU:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
return;
case LEU:
fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
return;
case LTU:
fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
return;
default:
output_operand_lossage ("Invalid %%C operand");
}
}
void
print_operand (file, x, code)
FILE *file;
rtx x;
int code;
{
if (code)
{
switch (code)
{
case '*':
if (USE_STAR)
putc ('*', file);
return;
case '_':
#ifdef YES_UNDERSCORES
putc ('_', file);
#endif
return;
case 'L':
PUT_OP_SIZE (code, 'l', file);
return;
case 'W':
PUT_OP_SIZE (code, 'w', file);
return;
case 'B':
PUT_OP_SIZE (code, 'b', file);
return;
case 'Q':
PUT_OP_SIZE (code, 'l', file);
return;
case 'S':
PUT_OP_SIZE (code, 's', file);
return;
case 'T':
PUT_OP_SIZE (code, 't', file);
return;
case 'z':
if (STACK_REG_P (x))
return;
switch (GET_MODE_SIZE (GET_MODE (x)))
{
case 2:
#ifdef HAVE_GAS_FILDS_FISTS
PUT_OP_SIZE ('W', 's', file);
#endif
return;
case 4:
if (GET_MODE (x) == SFmode)
{
PUT_OP_SIZE ('S', 's', file);
return;
}
else
PUT_OP_SIZE ('L', 'l', file);
return;
case 12:
PUT_OP_SIZE ('T', 't', file);
return;
case 8:
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_INT)
{
#ifdef GAS_MNEMONICS
PUT_OP_SIZE ('Q', 'q', file);
return;
#else
PUT_OP_SIZE ('Q', 'l', file);
#endif
}
PUT_OP_SIZE ('Q', 'l', file);
return;
default:
abort ();
}
case 'b':
case 'w':
case 'k':
case 'h':
case 'y':
case 'P':
case 'X':
break;
case 'J':
switch (GET_CODE (x))
{
case NE: fputs ("jne", file); return;
case EQ: fputs ("je", file); return;
case GE: fputs ("jns", file); return;
case LT: fputs ("js", file); return;
case GEU: fputs ("jmp", file); return;
case GTU: fputs ("jne", file); return;
case LEU: fputs ("je", file); return;
case LTU: fputs ("#branch never", file); return;
default:
abort ();
}
case 's':
if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT)
{
PRINT_OPERAND (file, x, 0);
fputs (AS2C (,) + 1, file);
}
return;
case 'D':
put_jump_code (GET_CODE (x), 0, file);
return;
case 'd':
put_jump_code (GET_CODE (x), 1, file);
return;
case 'C':
put_condition_code (GET_CODE (x), 0, MODE_INT, file);
return;
case 'c':
put_condition_code (GET_CODE (x), 1, MODE_INT, file); return;
case 'F':
put_condition_code (GET_CODE (x), 0, MODE_FLOAT, file);
return;
case 'f':
put_condition_code (GET_CODE (x), 1, MODE_FLOAT, file);
return;
default:
{
char str[50];
sprintf (str, "invalid operand code `%c'", code);
output_operand_lossage (str);
}
}
}
if (GET_CODE (x) == REG)
{
PRINT_REG (x, code, file);
}
else if (GET_CODE (x) == MEM)
{
PRINT_PTR (x, file);
if (CONSTANT_ADDRESS_P (XEXP (x, 0)))
{
if (flag_pic)
output_pic_addr_const (file, XEXP (x, 0), code);
else
output_addr_const (file, XEXP (x, 0));
}
else
output_address (XEXP (x, 0));
}
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
{
REAL_VALUE_TYPE r;
long l;
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_TARGET_SINGLE (r, l);
PRINT_IMMED_PREFIX (file);
fprintf (file, "0x%lx", l);
}
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
{
REAL_VALUE_TYPE r;
char dstr[30];
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
fprintf (file, "%s", dstr);
}
else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode)
{
REAL_VALUE_TYPE r;
char dstr[30];
REAL_VALUE_FROM_CONST_DOUBLE (r, x);
REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
fprintf (file, "%s", dstr);
}
else
{
if (code != 'P')
{
if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
PRINT_IMMED_PREFIX (file);
else if (GET_CODE (x) == CONST || GET_CODE (x) == SYMBOL_REF
|| GET_CODE (x) == LABEL_REF)
PRINT_OFFSET_PREFIX (file);
}
if (flag_pic)
output_pic_addr_const (file, x, code);
else
output_addr_const (file, x);
}
}
void
print_operand_address (file, addr)
FILE *file;
register rtx addr;
{
register rtx reg1, reg2, breg, ireg;
rtx offset;
switch (GET_CODE (addr))
{
case REG:
if (REGNO_REG_CLASS (REGNO (addr)) == SIREG
&& ix86_cpu == PROCESSOR_K6 && !optimize_size)
output_addr_const (file, const0_rtx);
ADDR_BEG (file);
fprintf (file, "%se", RP);
fputs (hi_reg_name[REGNO (addr)], file);
ADDR_END (file);
break;
case PLUS:
reg1 = 0;
reg2 = 0;
ireg = 0;
breg = 0;
offset = 0;
if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
{
offset = XEXP (addr, 0);
addr = XEXP (addr, 1);
}
else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
{
offset = XEXP (addr, 1);
addr = XEXP (addr, 0);
}
if (GET_CODE (addr) != PLUS)
;
else if (GET_CODE (XEXP (addr, 0)) == MULT)
reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
else if (GET_CODE (XEXP (addr, 1)) == MULT)
reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
else if (GET_CODE (XEXP (addr, 0)) == REG)
reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
else if (GET_CODE (XEXP (addr, 1)) == REG)
reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
{
if (reg1 == 0)
reg1 = addr;
else
reg2 = addr;
addr = 0;
}
if (offset != 0)
{
if (addr != 0)
abort ();
addr = offset;
}
if ((reg1 && GET_CODE (reg1) == MULT)
|| (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
{
breg = reg2;
ireg = reg1;
}
else if (reg1 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg1)))
{
breg = reg1;
ireg = reg2;
}
if (ireg != 0 || breg != 0)
{
int scale = 1;
if (addr != 0)
{
if (flag_pic)
output_pic_addr_const (file, addr, 0);
else if (GET_CODE (addr) == LABEL_REF)
output_asm_label (addr);
else
output_addr_const (file, addr);
}
if (ireg != 0 && GET_CODE (ireg) == MULT)
{
scale = INTVAL (XEXP (ireg, 1));
ireg = XEXP (ireg, 0);
}
if (scale == 1 && ireg && REGNO (ireg) == STACK_POINTER_REGNUM)
{
rtx tmp;
tmp = breg;
breg = ireg;
ireg = tmp;
}
PRINT_B_I_S (breg, ireg, scale, file);
break;
}
case MULT:
{
int scale;
if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
{
scale = INTVAL (XEXP (addr, 0));
ireg = XEXP (addr, 1);
}
else
{
scale = INTVAL (XEXP (addr, 1));
ireg = XEXP (addr, 0);
}
if (scale == 2)
{
PRINT_B_I_S (ireg, ireg, 1, file);
}
else
{
output_addr_const (file, const0_rtx);
PRINT_B_I_S (NULL_RTX, ireg, scale, file);
}
}
break;
default:
if (GET_CODE (addr) == CONST_INT
&& INTVAL (addr) < 0x8000
&& INTVAL (addr) >= -0x8000)
fprintf (file, "%d", (int) INTVAL (addr));
else
{
if (flag_pic)
output_pic_addr_const (file, addr, 0);
else
output_addr_const (file, addr);
}
}
}
void
notice_update_cc (exp)
rtx exp;
{
if (GET_CODE (exp) == SET)
{
if (SET_DEST (exp) == pc_rtx)
return;
if (REG_P (SET_DEST (exp))
&& (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
|| GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'
|| GET_CODE (SET_SRC (exp)) == IF_THEN_ELSE))
{
if (cc_status.value1
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
cc_status.value1 = 0;
if (cc_status.value2
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
cc_status.value2 = 0;
return;
}
if (GET_CODE (SET_DEST (exp)) == MEM
&& (REG_P (SET_SRC (exp))
|| GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
{
if (cc_status.value1
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
cc_status.value1 = 0;
if (cc_status.value2
&& reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
cc_status.value2 = 0;
return;
}
else if (GET_CODE (SET_SRC (exp)) == CALL)
{
CC_STATUS_INIT;
return;
}
else if (SET_DEST (exp) == cc0_rtx)
{
CC_STATUS_INIT;
cc_status.value1 = SET_SRC (exp);
return;
}
else if (GET_MODE (SET_SRC (exp)) == SImode
|| GET_MODE (SET_SRC (exp)) == HImode
|| GET_MODE (SET_SRC (exp)) == QImode)
switch (GET_CODE (SET_SRC (exp)))
{
case ASHIFTRT: case LSHIFTRT: case ASHIFT:
if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
{
CC_STATUS_INIT;
break;
}
case PLUS: case MINUS: case NEG:
case AND: case IOR: case XOR:
cc_status.flags = CC_NO_OVERFLOW;
cc_status.value1 = SET_SRC (exp);
cc_status.value2 = SET_DEST (exp);
break;
case UNSPEC:
if (XINT (SET_SRC (exp), 1) == 5)
{
cc_status.flags
= CC_NOT_POSITIVE | CC_NOT_NEGATIVE | CC_NO_OVERFLOW;
cc_status.value1 = XVECEXP (SET_SRC (exp), 0, 0);
cc_status.value2 = 0;
break;
}
default:
CC_STATUS_INIT;
}
else
{
CC_STATUS_INIT;
}
}
else if (GET_CODE (exp) == PARALLEL
&& GET_CODE (XVECEXP (exp, 0, 0)) == SET)
{
if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
return;
if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
{
CC_STATUS_INIT;
if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
{
cc_status.flags |= CC_IN_80387;
if (TARGET_CMOVE && stack_regs_mentioned_p
(XEXP (SET_SRC (XVECEXP (exp, 0, 0)), 1)))
cc_status.flags |= CC_FCOMI;
}
else
cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
return;
}
CC_STATUS_INIT;
}
else
{
CC_STATUS_INIT;
}
}
void
split_di (operands, num, lo_half, hi_half)
rtx operands[];
int num;
rtx lo_half[], hi_half[];
{
while (num--)
{
rtx op = operands[num];
if (! reload_completed)
{
lo_half[num] = gen_lowpart (SImode, op);
hi_half[num] = gen_highpart (SImode, op);
}
else if (GET_CODE (op) == REG)
{
lo_half[num] = gen_rtx_REG (SImode, REGNO (op));
hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1);
}
else if (CONSTANT_P (op))
split_double (op, &lo_half[num], &hi_half[num]);
else if (offsettable_memref_p (op))
{
rtx lo_addr = XEXP (op, 0);
rtx hi_addr = XEXP (adj_offsettable_operand (op, 4), 0);
lo_half[num] = change_address (op, SImode, lo_addr);
hi_half[num] = change_address (op, SImode, hi_addr);
}
else
abort();
}
}
int
binary_387_op (op, mode)
register rtx op;
enum machine_mode mode;
{
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
switch (GET_CODE (op))
{
case PLUS:
case MINUS:
case MULT:
case DIV:
return GET_MODE_CLASS (GET_MODE (op)) == MODE_FLOAT;
default:
return 0;
}
}
int
shift_op (op, mode)
register rtx op;
enum machine_mode mode;
{
rtx operand = XEXP (op, 0);
if (mode != VOIDmode && mode != GET_MODE (op))
return 0;
if (GET_MODE (operand) != GET_MODE (op)
|| GET_MODE_CLASS (GET_MODE (op)) != MODE_INT)
return 0;
return (GET_CODE (op) == ASHIFT
|| GET_CODE (op) == ASHIFTRT
|| GET_CODE (op) == LSHIFTRT
|| GET_CODE (op) == ROTATE
|| GET_CODE (op) == ROTATERT);
}
int
VOIDmode_compare_op (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode;
}
char *
output_387_binary_op (insn, operands)
rtx insn;
rtx *operands;
{
rtx temp;
char *base_op;
static char buf[100];
switch (GET_CODE (operands[3]))
{
case PLUS:
base_op = "fadd";
break;
case MINUS:
base_op = "fsub";
break;
case MULT:
base_op = "fmul";
break;
case DIV:
base_op = "fdiv";
break;
default:
abort ();
}
strcpy (buf, base_op);
switch (GET_CODE (operands[3]))
{
case MULT:
case PLUS:
if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
{
temp = operands[2];
operands[2] = operands[1];
operands[1] = temp;
}
if (GET_CODE (operands[2]) == MEM)
return strcat (buf, AS1 (%z2,%2));
if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
abort ();
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
{
if (STACK_TOP_P (operands[0]))
return strcat (buf, AS2 (p,%0,%2));
else
return strcat (buf, AS2 (p,%2,%0));
}
if (STACK_TOP_P (operands[0]))
return strcat (buf, AS2C (%y2,%0));
else
return strcat (buf, AS2C (%2,%0));
case MINUS:
case DIV:
if (GET_CODE (operands[1]) == MEM)
return strcat (buf, AS1 (r%z1,%1));
if (GET_CODE (operands[2]) == MEM)
return strcat (buf, AS1 (%z2,%2));
if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
abort ();
if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
{
if (STACK_TOP_P (operands[0]))
return strcat (buf, AS2 (p,%0,%2));
else
return strcat (buf, AS2 (rp,%2,%0));
}
if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
{
if (STACK_TOP_P (operands[0]))
return strcat (buf, AS2 (rp,%0,%1));
else
return strcat (buf, AS2 (p,%1,%0));
}
if (STACK_TOP_P (operands[0]))
{
if (STACK_TOP_P (operands[1]))
return strcat (buf, AS2C (%y2,%0));
else
return strcat (buf, AS2 (r,%y1,%0));
}
else if (STACK_TOP_P (operands[1]))
return strcat (buf, AS2C (%1,%0));
else
return strcat (buf, AS2 (r,%2,%0));
default:
abort ();
}
}
char *
output_fix_trunc (insn, operands)
rtx insn;
rtx *operands;
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
rtx xops[2];
if (! STACK_TOP_P (operands[1]))
abort ();
if (GET_MODE (operands[0]) == DImode && ! stack_top_dies)
abort ();
xops[0] = GEN_INT (0x0c00);
xops[1] = operands[5];
output_asm_insn (AS1 (fnstc%W2,%2), operands);
output_asm_insn (AS2 (mov%W5,%2,%w5), operands);
output_asm_insn (AS2 (or%W1,%0,%w1), xops);
output_asm_insn (AS2 (mov%W3,%w5,%3), operands);
output_asm_insn (AS1 (fldc%W3,%3), operands);
xops[0] = NON_STACK_REG_P (operands[0]) ? operands[4] : operands[0];
if (stack_top_dies)
output_asm_insn (AS1 (fistp%z0,%y0), xops);
else
output_asm_insn (AS1 (fist%z0,%y0), xops);
if (NON_STACK_REG_P (operands[0]))
{
if (GET_MODE (operands[0]) == SImode)
output_asm_insn (AS2 (mov%L0,%4,%0), operands);
else
{
xops[0] = operands[0];
xops[1] = operands[4];
output_asm_insn (output_move_double (xops), xops);
}
}
return AS1 (fldc%W2,%2);
}
void
output_float_extend (insn, operands)
rtx insn;
rtx *operands;
{
int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
rtx xops[2];
if (! STACK_TOP_P (operands[0]) && ! STACK_TOP_P (operands[1]))
abort ();
if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]) && stack_top_dies)
return;
if (STACK_TOP_P (operands[0]) )
{
if (NON_STACK_REG_P (operands[1]))
{
if (GET_MODE (operands[1]) == SFmode)
output_asm_insn (AS2 (mov%L0,%1,%2), operands);
else
{
xops[0] = operands[2];
xops[1] = operands[1];
output_asm_insn (output_move_double (xops), xops);
}
}
xops[0] = NON_STACK_REG_P (operands[1]) ? operands[2] : operands[1];
output_asm_insn (AS1 (fld%z0,%y0), xops);
}
else
{
xops[0] = NON_STACK_REG_P (operands[0]) ? operands[3] : operands[0];
if (stack_top_dies
|| (GET_CODE (xops[0]) == MEM && GET_MODE (xops[0]) == XFmode))
{
output_asm_insn (AS1 (fstp%z0,%y0), xops);
if (! stack_top_dies)
output_asm_insn (AS1 (fld%z0,%y0), xops);
}
else
output_asm_insn (AS1 (fst%z0,%y0), xops);
if (NON_STACK_REG_P (operands[0]))
{
xops[0] = operands[0];
xops[1] = operands[3];
output_asm_insn (output_move_double (xops), xops);
}
}
}
char *
output_float_compare (insn, operands)
rtx insn;
rtx *operands;
{
int stack_top_dies;
rtx body = XVECEXP (PATTERN (insn), 0, 0);
int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
rtx tmp;
int cc0_set = 1;
int i;
if (TARGET_CMOVE && STACK_REG_P (operands[1])
&& STACK_REG_P (operands[0]))
{
cc_status.flags |= CC_FCOMI;
cc_prev_status.flags &= ~CC_TEST_AX;
}
if (! STACK_TOP_P (operands[0]))
{
tmp = operands[0];
operands[0] = operands[1];
operands[1] = tmp;
cc_status.flags |= CC_REVERSED;
}
if (! STACK_TOP_P (operands[0]))
abort ();
stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
if (STACK_REG_P (operands[1])
&& stack_top_dies
&& find_regno_note (insn, REG_DEAD, REGNO (operands[1]))
&& REGNO (operands[1]) == FIRST_STACK_REG + 1)
{
if (unordered_compare)
{
if (cc_status.flags & CC_FCOMI)
{
output_asm_insn (AS2 (fucomip,%y1,%0), operands);
output_asm_insn (AS1 (fstp, %y0), operands);
if (!TARGET_IEEE_FP)
cc0_set = 0;
}
else
output_asm_insn ("fucompp", operands);
}
else
{
if (cc_status.flags & CC_FCOMI)
{
output_asm_insn (AS2 (fcomip, %y1,%0), operands);
output_asm_insn (AS1 (fstp, %y0), operands);
if (!TARGET_IEEE_FP)
cc0_set = 0;
}
else
output_asm_insn ("fcompp", operands);
}
}
else
{
static char buf[100];
if (unordered_compare)
strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom");
else
strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom");
if (stack_top_dies)
strcat (buf, "p");
if (cc_status.flags & CC_FCOMI)
{
output_asm_insn (strcat (buf, AS2 (%z1,%y1,%0)), operands);
if (!TARGET_IEEE_FP)
cc0_set = 0;
}
else
output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
}
if (cc0_set)
{
char *r = output_fp_cc0_set (insn);
if (r[0]) output_asm_insn (r, operands);
}
for (i = 0; i < 2 ; i++)
{
if (STACK_REG_P (operands[i])
&& find_regno_note (insn, REG_DEAD, REGNO (operands[i]))
&& REGNO (operands[i]) != FIRST_STACK_REG
&& (!stack_top_dies || REGNO (operands[i]) != FIRST_STACK_REG + 1))
{
rtx xexp[2];
xexp[0] = gen_rtx_REG (DFmode,
REGNO (operands[i]) - (stack_top_dies != 0));
output_asm_insn (AS1 (fstp, %y0), xexp);
}
}
return "";
}
char *
output_fp_cc0_set (insn)
rtx insn;
{
rtx xops[3];
rtx next;
enum rtx_code code;
#ifdef NEXT_SEMANTICS
next = next_cc0_user (insn);
if (next == NULL_RTX && flag_fppc)
{
next = next_nonnote_insn (insn);
if (next && GET_CODE (next) == INSN
&& INSN_CODE (next) == CODE_FOR_fppc_switch)
{
next = next_cc0_user (next);
}
}
#endif
if (!(cc_status.flags & CC_FCOMI))
{
xops[0] = gen_rtx_REG (HImode, 0);
output_asm_insn (AS1 (fnsts%W0,%0), xops);
}
xops[0] = gen_rtx_REG (HImode, 0);
output_asm_insn (AS1 (fnsts%W0,%0), xops);
if (! TARGET_IEEE_FP)
{
if (!(cc_status.flags & CC_REVERSED))
{
next = next_cc0_user (insn);
if (GET_CODE (PATTERN (next)) == SET
&& SET_DEST (PATTERN (next)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
else if (GET_CODE (PATTERN (next)) == SET)
code = GET_CODE (SET_SRC (PATTERN (next)));
else
return "sahf";
if (code == GT || code == LT || code == EQ || code == NE
|| code == LE || code == GE)
{
cc_status.flags |= CC_TEST_AX;
return "";
}
}
return "sahf";
}
#ifndef NEXT_SEMANTICS
next = next_cc0_user (insn);
#endif
if (next == NULL_RTX)
abort ();
if (GET_CODE (PATTERN (next)) == SET
&& SET_DEST (PATTERN (next)) == pc_rtx
&& GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
else if (GET_CODE (PATTERN (next)) == SET)
{
if (GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
else
code = GET_CODE (SET_SRC (PATTERN (next)));
}
else if (GET_CODE (PATTERN (next)) == PARALLEL
&& GET_CODE (XVECEXP (PATTERN (next), 0, 0)) == SET)
{
if (GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0))) == IF_THEN_ELSE)
code = GET_CODE (XEXP (SET_SRC (XVECEXP (PATTERN (next), 0, 0)), 0));
else
code = GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0)));
}
else
abort ();
if (cc_status.flags & CC_FCOMI)
{
xops [0] = gen_rtx_REG (QImode, 0);
switch (code)
{
case GT:
case GE:
break;
case LT:
output_asm_insn (AS1 (setb,%b0), xops);
output_asm_insn (AS1 (setp,%h0), xops);
output_asm_insn (AS2 (cmp%B0,%b0,%h0), xops);
break;
case LE:
output_asm_insn (AS1 (setbe,%b0), xops);
output_asm_insn (AS1 (setnp,%h0), xops);
output_asm_insn (AS2 (xor%B0,%b0,%h0), xops);
break;
case EQ:
case NE:
output_asm_insn (AS1 (setne,%b0), xops);
output_asm_insn (AS1 (setp,%h0), xops);
output_asm_insn (AS2 (or%B0,%b0,%h0), xops);
break;
case GTU:
case LTU:
case GEU:
case LEU:
default:
abort ();
}
}
else
{
xops[0] = gen_rtx_REG (QImode, 0);
switch (code)
{
case GT:
xops[1] = GEN_INT (0x45);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
break;
case LT:
xops[1] = GEN_INT (0x45);
xops[2] = GEN_INT (0x01);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
break;
case GE:
xops[1] = GEN_INT (0x05);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
break;
case LE:
xops[1] = GEN_INT (0x45);
xops[2] = GEN_INT (0x40);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS1 (dec%B0,%h0), xops);
output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
break;
case EQ:
xops[1] = GEN_INT (0x45);
xops[2] = GEN_INT (0x40);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS2 (cmp%B0,%2,%h0), xops);
break;
case NE:
xops[1] = GEN_INT (0x44);
xops[2] = GEN_INT (0x40);
output_asm_insn (AS2 (and%B0,%1,%h0), xops);
output_asm_insn (AS2 (xor%B0,%2,%h0), xops);
break;
case GTU:
case LTU:
case GEU:
case LEU:
default:
abort ();
}
}
return "";
}
#ifndef MAX_386_STACK_LOCALS
#define MAX_386_STACK_LOCALS 2
#endif
static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
struct machine_function
{
rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
rtx pic_label_rtx;
char pic_label_name[256];
};
void
save_386_machine_status (p)
struct function *p;
{
p->machine
= (struct machine_function *) xmalloc (sizeof (struct machine_function));
bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals,
sizeof i386_stack_locals);
p->machine->pic_label_rtx = pic_label_rtx;
bcopy (pic_label_name, p->machine->pic_label_name, 256);
}
void
restore_386_machine_status (p)
struct function *p;
{
bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals,
sizeof i386_stack_locals);
pic_label_rtx = p->machine->pic_label_rtx;
bcopy (p->machine->pic_label_name, pic_label_name, 256);
free (p->machine);
p->machine = NULL;
}
void
clear_386_stack_locals ()
{
enum machine_mode mode;
int n;
for (mode = VOIDmode; (int) mode < (int) MAX_MACHINE_MODE;
mode = (enum machine_mode) ((int) mode + 1))
for (n = 0; n < MAX_386_STACK_LOCALS; n++)
i386_stack_locals[(int) mode][n] = NULL_RTX;
pic_label_rtx = NULL_RTX;
bzero (pic_label_name, 256);
save_machine_status = save_386_machine_status;
restore_machine_status = restore_386_machine_status;
}
rtx
assign_386_stack_local (mode, n)
enum machine_mode mode;
int n;
{
if (n < 0 || n >= MAX_386_STACK_LOCALS)
abort ();
if (i386_stack_locals[(int) mode][n] == NULL_RTX)
i386_stack_locals[(int) mode][n]
= assign_stack_local (mode, GET_MODE_SIZE (mode), 0);
return i386_stack_locals[(int) mode][n];
}
int is_mul(op,mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == MULT);
}
int is_div(op,mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
return (GET_CODE (op) == DIV);
}
#ifdef NOTYET
rtx
copy_all_rtx (orig)
register rtx orig;
{
register rtx copy;
register int i, j;
register RTX_CODE code;
register char *format_ptr;
code = GET_CODE (orig);
switch (code)
{
case REG:
case QUEUED:
case CONST_INT:
case CONST_DOUBLE:
case SYMBOL_REF:
case CODE_LABEL:
case PC:
case CC0:
case SCRATCH:
return orig;
#if 0
case CONST:
if (GET_CODE (XEXP (orig, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
&& GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
return orig;
break;
#endif
}
copy = rtx_alloc (code);
PUT_MODE (copy, GET_MODE (orig));
copy->in_struct = orig->in_struct;
copy->volatil = orig->volatil;
copy->unchanging = orig->unchanging;
copy->integrated = orig->integrated;
copy->is_spill_rtx = orig->is_spill_rtx;
format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
{
switch (*format_ptr++)
{
case 'e':
XEXP (copy, i) = XEXP (orig, i);
if (XEXP (orig, i) != NULL)
XEXP (copy, i) = copy_rtx (XEXP (orig, i));
break;
case '0':
case 'u':
XEXP (copy, i) = XEXP (orig, i);
break;
case 'E':
case 'V':
XVEC (copy, i) = XVEC (orig, i);
if (XVEC (orig, i) != NULL)
{
XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
for (j = 0; j < XVECLEN (copy, i); j++)
XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
}
break;
case 'w':
XWINT (copy, i) = XWINT (orig, i);
break;
case 'i':
XINT (copy, i) = XINT (orig, i);
break;
case 's':
case 'S':
XSTR (copy, i) = XSTR (orig, i);
break;
default:
abort ();
}
}
return copy;
}
void
rewrite_address (mem_rtx)
rtx mem_rtx;
{
rtx index_rtx, base_rtx, offset_rtx, scale_rtx, ret_rtx;
int scale = 1;
int offset_adjust = 0;
int was_only_offset = 0;
rtx mem_addr = XEXP (mem_rtx, 0);
char *storage = oballoc (0);
int in_struct = 0;
int is_spill_rtx = 0;
in_struct = MEM_IN_STRUCT_P (mem_rtx);
is_spill_rtx = RTX_IS_SPILL_P (mem_rtx);
if (GET_CODE (mem_addr) == PLUS
&& GET_CODE (XEXP (mem_addr, 1)) == PLUS
&& GET_CODE (XEXP (XEXP (mem_addr, 1), 0)) == REG)
{
ret_rtx
= gen_rtx (PLUS, GET_MODE (mem_addr),
gen_rtx (PLUS, GET_MODE (XEXP (mem_addr, 1)),
XEXP (mem_addr, 0), XEXP (XEXP (mem_addr, 1), 0)),
XEXP (XEXP (mem_addr, 1), 1));
if (memory_address_p (GET_MODE (mem_rtx), ret_rtx))
{
XEXP (mem_rtx, 0) = ret_rtx;
RTX_IS_SPILL_P (ret_rtx) = is_spill_rtx;
return;
}
obfree (storage);
}
storage = oballoc (0);
index_rtx = base_rtx = offset_rtx = NULL;
if (GET_CODE (mem_addr) == PLUS)
{
if (GET_CODE (XEXP (mem_addr, 0)) == REG)
{
if (GET_CODE (XEXP (mem_addr, 1)) == REG)
base_rtx = XEXP (mem_addr, 1), index_rtx = XEXP (mem_addr, 0);
else
base_rtx = XEXP (mem_addr, 0), offset_rtx = XEXP (mem_addr, 1);
}
else if (GET_CODE (XEXP (mem_addr, 0)) == MULT)
{
index_rtx = XEXP (mem_addr, 0);
if (GET_CODE (XEXP (mem_addr, 1)) == REG)
base_rtx = XEXP (mem_addr, 1);
else
offset_rtx = XEXP (mem_addr, 1);
}
else if (GET_CODE (XEXP (mem_addr, 0)) == PLUS)
{
if (GET_CODE (XEXP (XEXP (mem_addr, 0), 0)) == PLUS
&& GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0)) == MULT
&& (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 0))
== REG)
&& (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 1))
== CONST_INT)
&& (GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1))
== CONST_INT)
&& GET_CODE (XEXP (XEXP (mem_addr, 0), 1)) == REG
&& GET_CODE (XEXP (mem_addr, 1)) == SYMBOL_REF)
{
index_rtx = XEXP (XEXP (XEXP (mem_addr, 0), 0), 0);
offset_rtx = XEXP (mem_addr, 1);
base_rtx = XEXP (XEXP (mem_addr, 0), 1);
offset_adjust = INTVAL (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1));
}
else
{
offset_rtx = XEXP (mem_addr, 1);
index_rtx = XEXP (XEXP (mem_addr, 0), 0);
base_rtx = XEXP (XEXP (mem_addr, 0), 1);
}
}
else if (GET_CODE (XEXP (mem_addr, 0)) == CONST_INT)
{
was_only_offset = 1;
index_rtx = NULL;
base_rtx = NULL;
offset_rtx = XEXP (mem_addr, 1);
offset_adjust = INTVAL (XEXP (mem_addr, 0));
if (offset_adjust == 0)
{
XEXP (mem_rtx, 0) = offset_rtx;
RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
return;
}
}
else
{
obfree (storage);
return;
}
}
else if (GET_CODE (mem_addr) == MULT)
index_rtx = mem_addr;
else
{
obfree (storage);
return;
}
if (index_rtx != 0 && GET_CODE (index_rtx) == MULT)
{
if (GET_CODE (XEXP (index_rtx, 1)) != CONST_INT)
{
obfree (storage);
return;
}
scale_rtx = XEXP (index_rtx, 1);
scale = INTVAL (scale_rtx);
index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
}
if (index_rtx && GET_CODE (index_rtx) == CONST_INT && base_rtx == NULL)
{
offset_adjust = INTVAL (index_rtx) * scale;
if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
offset_rtx = plus_constant (offset_rtx, offset_adjust);
else if (offset_rtx == 0)
offset_rtx = const0_rtx;
RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
XEXP (mem_rtx, 0) = offset_rtx;
return;
}
if (base_rtx && GET_CODE (base_rtx) == PLUS
&& GET_CODE (XEXP (base_rtx, 0)) == REG
&& GET_CODE (XEXP (base_rtx, 1)) == CONST_INT)
{
offset_adjust += INTVAL (XEXP (base_rtx, 1));
base_rtx = copy_all_rtx (XEXP (base_rtx, 0));
}
else if (base_rtx && GET_CODE (base_rtx) == CONST_INT)
{
offset_adjust += INTVAL (base_rtx);
base_rtx = NULL;
}
if (index_rtx && GET_CODE (index_rtx) == PLUS
&& GET_CODE (XEXP (index_rtx, 0)) == REG
&& GET_CODE (XEXP (index_rtx, 1)) == CONST_INT)
{
offset_adjust += INTVAL (XEXP (index_rtx, 1)) * scale;
index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
}
if (index_rtx)
{
if (! LEGITIMATE_INDEX_P (index_rtx)
&& ! (index_rtx == stack_pointer_rtx && scale == 1
&& base_rtx == NULL))
{
obfree (storage);
return;
}
}
if (base_rtx)
{
if (! LEGITIMATE_INDEX_P (base_rtx) && GET_CODE (base_rtx) != REG)
{
obfree (storage);
return;
}
}
if (offset_adjust != 0)
{
if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
offset_rtx = plus_constant (offset_rtx, offset_adjust);
else
offset_rtx = const0_rtx;
if (index_rtx)
{
if (base_rtx)
{
if (scale != 1)
{
ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx),
gen_rtx (MULT, GET_MODE (index_rtx),
index_rtx, scale_rtx),
base_rtx);
if (GET_CODE (offset_rtx) != CONST_INT
|| INTVAL (offset_rtx) != 0)
ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
ret_rtx, offset_rtx);
}
else
{
ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
index_rtx, base_rtx);
if (GET_CODE (offset_rtx) != CONST_INT
|| INTVAL (offset_rtx) != 0)
ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
ret_rtx, offset_rtx);
}
}
else
{
if (scale != 1)
{
ret_rtx = gen_rtx (MULT, GET_MODE (index_rtx),
index_rtx, scale_rtx);
if (GET_CODE (offset_rtx) != CONST_INT
|| INTVAL (offset_rtx) != 0)
ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
ret_rtx, offset_rtx);
}
else
{
if (GET_CODE (offset_rtx) == CONST_INT
&& INTVAL (offset_rtx) == 0)
ret_rtx = index_rtx;
else
ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
index_rtx, offset_rtx);
}
}
}
else
{
if (base_rtx)
{
if (GET_CODE (offset_rtx) == CONST_INT
&& INTVAL (offset_rtx) == 0)
ret_rtx = base_rtx;
else
ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx), base_rtx,
offset_rtx);
}
else if (was_only_offset)
ret_rtx = offset_rtx;
else
{
obfree (storage);
return;
}
}
XEXP (mem_rtx, 0) = ret_rtx;
RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
return;
}
else
{
obfree (storage);
return;
}
}
#endif
int
last_to_set_cc (reg_rtx, insn)
rtx reg_rtx, insn;
{
rtx prev_insn = PREV_INSN (insn);
while (prev_insn)
{
if (GET_CODE (prev_insn) == NOTE)
;
else if (GET_CODE (prev_insn) == INSN)
{
if (GET_CODE (PATTERN (prev_insn)) != SET)
return (0);
if (rtx_equal_p (SET_DEST (PATTERN (prev_insn)), reg_rtx))
{
if (sets_condition_code (SET_SRC (PATTERN (prev_insn))))
return (1);
return (0);
}
else if (! doesnt_set_condition_code (SET_SRC (PATTERN (prev_insn))))
return (0);
}
else
return (0);
prev_insn = PREV_INSN (prev_insn);
}
return (0);
}
int
doesnt_set_condition_code (pat)
rtx pat;
{
switch (GET_CODE (pat))
{
case MEM:
case REG:
return 1;
default:
return 0;
}
}
int
sets_condition_code (pat)
rtx pat;
{
switch (GET_CODE (pat))
{
case PLUS:
case MINUS:
case AND:
case IOR:
case XOR:
case NOT:
case NEG:
case MULT:
case DIV:
case MOD:
case UDIV:
case UMOD:
return 1;
default:
return (0);
}
}
int
str_immediate_operand (op, mode)
register rtx op;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
if (GET_CODE (op) == CONST_INT && INTVAL (op) <= 32 && INTVAL (op) >= 0)
return 1;
return 0;
}
int
is_fp_insn (insn)
rtx insn;
{
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
&& (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
|| GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
|| GET_MODE (SET_DEST (PATTERN (insn))) == XFmode))
return 1;
return 0;
}
int
is_fp_dest (insn)
rtx insn;
{
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
&& (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
|| GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
|| GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
&& GET_CODE (SET_DEST (PATTERN (insn))) == REG
&& REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FLOAT_REG
&& GET_CODE (SET_SRC (PATTERN (insn))) != MEM)
return 1;
return 0;
}
int
is_fp_store (insn)
rtx insn;
{
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
&& (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
|| GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
|| GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
&& GET_CODE (SET_DEST (PATTERN (insn))) == MEM
&& GET_CODE (SET_SRC (PATTERN (insn))) == REG)
return 1;
return 0;
}
int
agi_dependent (insn, dep_insn)
rtx insn, dep_insn;
{
int push = 0, push_dep = 0;
if (GET_CODE (dep_insn) == INSN
&& GET_CODE (PATTERN (dep_insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG
&& reg_mentioned_in_mem (SET_DEST (PATTERN (dep_insn)), insn))
return 1;
if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (insn))) == MEM
&& push_operand (SET_DEST (PATTERN (insn)),
GET_MODE (SET_DEST (PATTERN (insn)))))
push = 1;
if (GET_CODE (dep_insn) == INSN && GET_CODE (PATTERN (dep_insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (dep_insn))) == MEM
&& push_operand (SET_DEST (PATTERN (dep_insn)),
GET_MODE (SET_DEST (PATTERN (dep_insn)))))
push_dep = 1;
if (push && push_dep)
return 0;
if (push_dep && reg_mentioned_in_mem (stack_pointer_rtx, insn))
return 1;
if (push && modified_in_p (stack_pointer_rtx, dep_insn))
return 1;
return 0;
}
int
reg_mentioned_in_mem (reg, rtl)
rtx reg, rtl;
{
register char *fmt;
register int i, j;
register enum rtx_code code;
if (rtl == NULL)
return 0;
code = GET_CODE (rtl);
switch (code)
{
case HIGH:
case CONST_INT:
case CONST:
case CONST_DOUBLE:
case SYMBOL_REF:
case LABEL_REF:
case PC:
case CC0:
case SUBREG:
return 0;
default:
break;
}
if (code == MEM && reg_mentioned_p (reg, rtl))
return 1;
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
for (j = XVECLEN (rtl, i) - 1; j >= 0; j--)
if (reg_mentioned_in_mem (reg, XVECEXP (rtl, i, j)))
return 1;
}
else if (fmt[i] == 'e' && reg_mentioned_in_mem (reg, XEXP (rtl, i)))
return 1;
}
return 0;
}
char *
output_strlen_unroll (operands)
rtx operands[];
{
rtx xops[18];
xops[0] = operands[0];
xops[1] = operands[2];
xops[2] = GEN_INT (0);
xops[3] = GEN_INT (2);
xops[4] = GEN_INT (3);
xops[5] = GEN_INT (4);
xops[8] = gen_label_rtx ();
if (TARGET_USE_Q_REG && QI_REG_P (xops[1]))
xops[9] = gen_label_rtx ();
xops[10] = gen_label_rtx ();
xops[11] = gen_label_rtx ();
xops[12] = gen_label_rtx ();
xops[14] = GEN_INT (0xff);
xops[15] = GEN_INT (0xff00);
xops[16] = GEN_INT (0xff0000);
xops[17] = GEN_INT (0xff000000);
if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) < 4)
{
if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
{
xops[6] = gen_label_rtx ();
xops[7] = gen_label_rtx ();
output_asm_insn (AS2 (and%L1,%4,%1), xops);
output_asm_insn (AS1 (je,%l8), xops);
output_asm_insn (AS1 (jp,%6), xops);
if (QI_REG_P (xops[1]))
output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
else
output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
output_asm_insn (AS1 (je,%7), xops);
}
else
{
output_asm_insn (AS2 (and%L1,%3,%1), xops);
output_asm_insn (AS1 (je,%l8), xops);
}
xops[13] = gen_rtx_MEM (QImode, xops[0]);
if (QI_REG_P (xops[1]))
{
output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
output_asm_insn (AS1 (je,%l12), xops);
output_asm_insn (AS1 (inc%L0,%0), xops);
if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
{
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xops[7]));
output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
output_asm_insn (AS1 (je,%l12), xops);
output_asm_insn (AS1 (inc%L0,%0), xops);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xops[6]));
}
output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
}
else
{
output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
output_asm_insn (AS1 (je,%l12), xops);
output_asm_insn (AS1 (inc%L0,%0), xops);
if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
{
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xops[7]));
output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
output_asm_insn (AS1 (je,%l12), xops);
output_asm_insn (AS1 (inc%L0,%0), xops);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xops[6]));
}
output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
}
output_asm_insn (AS1 (je,%l12), xops);
output_asm_insn (AS1 (inc%L0,%0), xops);
}
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8]));
xops[13] = gen_rtx_MEM (SImode, xops[0]);
output_asm_insn (AS2 (mov%L1,%13,%1), xops);
if (QI_REG_P (xops[1]))
{
if (TARGET_PENTIUM)
{
output_asm_insn (AS2 (test%B1,%h1,%b1), xops);
output_asm_insn (AS1 (jne,%l9), xops);
}
output_asm_insn (AS2 (test%B1,%b1,%b1), xops);
output_asm_insn (AS1 (je,%l12), xops);
output_asm_insn (AS2 (test%B1,%h1,%h1), xops);
output_asm_insn (AS1 (je,%l11), xops);
if (TARGET_PENTIUM)
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
CODE_LABEL_NUMBER (xops[9]));
}
else
{
output_asm_insn (AS2 (test%L1,%14,%1), xops);
output_asm_insn (AS1 (je,%l12), xops);
output_asm_insn (AS2 (test%L1,%15,%1), xops);
output_asm_insn (AS1 (je,%l11), xops);
}
output_asm_insn (AS2 (test%L1,%16,%1), xops);
output_asm_insn (AS1 (je,%l10), xops);
output_asm_insn (AS2 (add%L0,%5,%0), xops);
output_asm_insn (AS2 (test%L1,%17,%1), xops);
output_asm_insn (AS1 (jne,%l8), xops);
output_asm_insn (AS2 (sub%L0,%4,%0), xops);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10]));
output_asm_insn (AS1 (inc%L0,%0), xops);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11]));
output_asm_insn (AS1 (inc%L0,%0), xops);
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12]));
return "";
}
char *
output_fp_conditional_move (which_alternative, operands)
int which_alternative;
rtx operands[];
{
enum rtx_code code = GET_CODE (operands[1]);
if (!(cc_prev_status.flags & CC_IN_80387)
&& (code == GT || code == LE || code == GE || code == LT))
abort ();
switch (which_alternative)
{
case 0:
output_asm_insn (AS2 (fcmov%F1,%2,%0), operands);
break;
case 1:
output_asm_insn (AS2 (fcmov%f1,%3,%0), operands);
break;
default:
abort ();
}
return "";
}
char *
output_int_conditional_move (which_alternative, operands)
int which_alternative;
rtx operands[];
{
enum rtx_code code = GET_CODE (operands[1]);
if ((code == GT || code == LE)
&& (cc_prev_status.flags & CC_NO_OVERFLOW))
return NULL_PTR;
switch (which_alternative)
{
case 0:
output_asm_insn (AS2 (cmov%C1,%2,%0), operands);
break;
case 1:
output_asm_insn (AS2 (cmov%c1,%3,%0), operands);
break;
default:
abort ();
}
return "";
}
int
x86_adjust_cost (insn, link, dep_insn, cost)
rtx insn, link, dep_insn;
int cost;
{
rtx next_inst;
if (GET_CODE (dep_insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
return 0;
if (GET_CODE (dep_insn) == INSN
&& GET_CODE (PATTERN (dep_insn)) == SET
&& GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG
&& GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SET
&& !reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)),
SET_SRC (PATTERN (insn))))
return 0;
switch (ix86_cpu)
{
case PROCESSOR_PENTIUM:
if (cost != 0 && is_fp_insn (insn) && is_fp_insn (dep_insn)
&& !is_fp_dest (dep_insn))
return 0;
if (agi_dependent (insn, dep_insn))
return cost ? cost + 1 : 2;
if (GET_CODE (insn) == INSN
&& GET_CODE (PATTERN (insn)) == SET
&& SET_DEST (PATTERN (insn)) == cc0_rtx
&& (next_inst = next_nonnote_insn (insn))
&& GET_CODE (next_inst) == JUMP_INSN)
return 0;
if (is_fp_insn (insn) && cost && is_fp_store (dep_insn))
cost++;
break;
case PROCESSOR_K6:
default:
if (!is_fp_dest (dep_insn))
{
if(!agi_dependent (insn, dep_insn))
return 0;
if (TARGET_486)
return 2;
}
else
if (is_fp_store (insn) && is_fp_insn (dep_insn)
&& NEXT_INSN (insn) && NEXT_INSN (NEXT_INSN (insn))
&& NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))
&& (GET_CODE (NEXT_INSN (insn)) == INSN)
&& (GET_CODE (NEXT_INSN (NEXT_INSN (insn))) == JUMP_INSN)
&& (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) == NOTE)
&& (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn))))
== NOTE_INSN_LOOP_END))
return 3;
break;
}
return cost;
}
char *
output_ashl (insn, operands)
rtx insn, *operands;
{
if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
{
if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1)
switch (GET_MODE (operands[0]))
{
case SImode:
output_asm_insn (AS2 (mov%L0,%1,%0), operands);
return AS2 (add%L0,%1,%0);
case HImode:
output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
if (i386_cc_probably_useless_p (insn))
{
CC_STATUS_INIT;
return AS2 (add%L0,%k1,%k0);
}
return AS2 (add%W0,%k1,%k0);
case QImode:
output_asm_insn (AS2 (mov%B0,%1,%0), operands);
return AS2 (add%B0,%1,%0);
default:
abort ();
}
else
{
CC_STATUS_INIT;
if (operands[1] == stack_pointer_rtx)
{
output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
operands[1] = operands[0];
}
operands[1] = gen_rtx_MULT (SImode,
gen_rtx_REG (SImode, REGNO (operands[1])),
GEN_INT (1 << INTVAL (operands[2])));
return AS2 (lea%L0,%a1,%k0);
}
}
if (REG_P (operands[2]))
switch (GET_MODE (operands[0]))
{
case SImode:
return AS2 (sal%L0,%b2,%0);
case HImode:
if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
{
CC_STATUS_INIT;
return AS2 (sal%L0,%b2,%k0);
}
else
return AS2 (sal%W0,%b2,%0);
case QImode:
return AS2 (sal%B0,%b2,%0);
default:
abort ();
}
if (REG_P (operands[0]) && operands[2] == const1_rtx)
switch (GET_MODE (operands[0]))
{
case SImode:
return AS2 (add%L0,%0,%0);
case HImode:
if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
{
CC_STATUS_INIT;
return AS2 (add%L0,%k0,%k0);
}
else
return AS2 (add%W0,%0,%0);
case QImode:
return AS2 (add%B0,%0,%0);
default:
abort ();
}
#if 0
if (! optimize_size
&& REG_P (operands[0])
&& GET_CODE (operands[2]) == CONST_INT
&& INTVAL (operands[2]) <= 3
&& (int)ix86_cpu == (int)PROCESSOR_PENTIUM
&& GET_MODE (insn) != TImode)
{
CC_STATUS_INIT;
operands[1] = gen_rtx_MULT (SImode, gen_rtx_REG (SImode, REGNO (operands[1])),
GEN_INT (1 << INTVAL (operands[2])));
return AS2 (lea%L0,%a1,%0);
}
#endif
switch (GET_MODE (operands[0]))
{
case SImode:
return AS2 (sal%L0,%2,%0);
case HImode:
if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
{
CC_STATUS_INIT;
return AS2 (sal%L0,%2,%k0);
}
else
return AS2 (sal%W0,%2,%0);
case QImode:
return AS2 (sal%B0,%2,%0);
default:
abort ();
}
}
int
memory_address_info (addr, disp_length)
rtx addr;
int disp_length;
{
rtx base, index, disp, scale;
rtx op0, op1;
int len;
if (GET_CODE (addr) == PRE_DEC
|| GET_CODE (addr) == POST_INC)
return 0;
if (register_operand (addr, Pmode))
{
if (addr == stack_pointer_rtx
|| addr == arg_pointer_rtx
|| addr == frame_pointer_rtx
|| (REGNO_REG_CLASS (REGNO (addr)) == SIREG
&& ix86_cpu == PROCESSOR_K6 && !optimize_size))
return 1;
else
return 0;
}
if (CONSTANT_P (addr))
return 4;
index = base = disp = scale = NULL_RTX;
op0 = XEXP (addr, 0);
op1 = XEXP (addr, 1);
if (GET_CODE (addr) == PLUS)
{
if (register_operand (op0, Pmode))
{
if (register_operand (op1, Pmode))
index = op0, base = op1;
else
base = op0, disp = op1;
}
else if (GET_CODE (op0) == MULT)
{
index = XEXP (op0, 0);
scale = XEXP (op0, 1);
if (register_operand (op1, Pmode))
base = op1;
else
disp = op1;
}
else if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
{
index = XEXP (XEXP (op0, 0), 0);
scale = XEXP (XEXP (op0, 0), 1);
base = XEXP (op0, 1);
disp = op1;
}
else if (GET_CODE (op0) == PLUS)
{
index = XEXP (op0, 0);
base = XEXP (op0, 1);
disp = op1;
}
else
abort ();
}
else if (GET_CODE (addr) == MULT
|| GET_CODE (addr) == ASHIFT)
{
index = XEXP (addr, 0);
scale = XEXP (addr, 1);
}
else
abort ();
if (base && index && !scale
&& (index == stack_pointer_rtx
|| index == arg_pointer_rtx
|| index == frame_pointer_rtx))
{
rtx tmp = base;
base = index;
index = tmp;
}
if (base == frame_pointer_rtx && !disp)
disp = const0_rtx;
if (!base && index
&& (!scale || GET_CODE (scale) != CONST_INT || (INTVAL (scale) != 1)))
disp = const0_rtx;
len = 0;
if (disp)
{
if (GET_CODE (disp) == CONST_INT
&& CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K'))
len = 1;
else
len = 4;
}
if (index && ! disp_length)
len += 1;
return len;
}