/* Subroutines for insn-output.c for Intel 860
- Copyright (C) 1989, 1991, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1989, 91, 97, 98, 1999 Free Software Foundation, Inc.
Derived from sparc.c.
Written by Richard Stallman (rms@ai.mit.edu).
#include "config.h"
-#include <stdio.h>
+#include "system.h"
#include "flags.h"
#include "rtl.h"
+#include "tree.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "real.h"
#include "output.h"
#include "recog.h"
#include "insn-attr.h"
+#include "function.h"
+#include "expr.h"
static rtx find_addr_reg ();
if (CONSTANT_P (arg)
&& !(GET_CODE (arg) == CONST_INT
&& (SMALL_INT (arg)
- || INTVAL (arg) & 0xffff == 0)))
+ || (INTVAL (arg) & 0xffff) == 0)))
return 0;
}
case IOR:
if (CONSTANT_P (XEXP (op, 1))
&& !(GET_CODE (XEXP (op, 1)) == CONST_INT
&& (SMALL_INT (XEXP (op, 1))
- || INTVAL (XEXP (op, 1)) & 0xffff == 0)))
+ || (INTVAL (XEXP (op, 1)) & 0xffff) == 0)))
return 0;
case ASHIFT:
rtx xoperands[2];
cc_status.flags &= ~CC_F0_IS_0;
- xoperands[0] = gen_rtx (REG, SFmode, 32);
+ xoperands[0] = gen_rtx_REG (SFmode, 32);
xoperands[1] = operands[1];
output_asm_insn (singlemove_string (xoperands), xoperands);
xoperands[1] = xoperands[0];
operands in OPERANDS to be suitable for the low-numbered word. */
if (optype0 == REGOP)
- latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+ 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);
+ 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)
xops[0] = latehalf[0];
xops[1] = operands[0];
output_asm_insn ("adds %1,%0,%1", xops);
- operands[1] = gen_rtx (MEM, DImode, operands[0]);
+ operands[1] = gen_rtx_MEM (DImode, operands[0]);
latehalf[1] = adj_offsettable_operand (operands[1], 4);
addreg1 = 0;
highest_first = 1;
/* If the source operand is any sort of zero, use f0 instead. */
if (operands[1] == CONST0_RTX (GET_MODE (operands[1])))
- operands[1] = gen_rtx (REG, DFmode, F0_REGNUM);
+ operands[1] = gen_rtx_REG (DFmode, F0_REGNUM);
if (FP_REG_P (operands[0]))
{
if (GET_CODE (operands[1]) == REG)
{
output_asm_insn ("ixfr %1,%0", operands);
- operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
- operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
+ operands[0] = gen_rtx_REG (VOIDmode, REGNO (operands[0]) + 1);
+ operands[1] = gen_rtx_REG (VOIDmode, REGNO (operands[1]) + 1);
return "ixfr %1,%0";
}
if (operands[1] == CONST0_RTX (DFmode))
if (GET_CODE (operands[0]) == REG)
{
output_asm_insn ("fxfr %1,%0", operands);
- operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
- operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
+ operands[0] = gen_rtx_REG (VOIDmode, REGNO (operands[0]) + 1);
+ operands[1] = gen_rtx_REG (VOIDmode, REGNO (operands[1]) + 1);
return "fxfr %1,%0";
}
if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
output_asm_insn ("sub %2,%1,%0", xoperands);
else
{
- xoperands[1]
- = GEN_INT (INTVAL (size) - INTVAL (align));
+ xoperands[1] = GEN_INT (INTVAL (size) - INTVAL (align));
cc_status.flags &= ~ CC_KNOW_HI_R31;
output_asm_insn ("mov %1,%0", xoperands);
}
return "";
}
\f
+#if 0
/* Output a delayed branch insn with the delay insn in its
branch slot. The delayed branch insn template is in TEMPLATE,
with operands OPERANDS. The insn in its delay slot is INSN.
or l%x,%0,%1
*/
+/* ??? Disabled because this re-recognition is incomplete and causes
+ constrain_operands to segfault. Anyone who cares should fix up
+ the code to use the DBR pass. */
char *
output_delayed_branch (template, operands, insn)
else
{
int insn_code_number;
- rtx pat = gen_rtx (SET, VOIDmode, dest, src);
- rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
+ rtx pat = gen_rtx_SET (VOIDmode, dest, src);
+ rtx delay_insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, pat, -1, 0, 0);
int i;
/* Output the branch instruction first. */
}
insn_extract (delay_insn);
- if (! constrain_operands (insn_code_number, 1))
+ if (! constrain_operands (1))
fatal_insn_not_found (delay_insn);
template = insn_template[insn_code_number];
}
#ifdef REGISTER_CONSTRAINTS
- if (! constrain_operands (insn_code_number, 1))
+ if (! constrain_operands (1))
abort ();
#endif
output_asm_insn (template, recog_operand);
return "";
}
+#endif
\f
/* Special routine to convert an SFmode value represented as a
CONST_DOUBLE into its equivalent unsigned long bit pattern.
text_section();
#endif
}
+\f
+
+/* Expand a library call to __builtin_saveregs. */
+rtx
+i860_saveregs ()
+{
+ rtx fn = gen_rtx_SYMBOL_REF (Pmode, "__builtin_saveregs");
+ rtx save = gen_reg_rtx (Pmode);
+ rtx valreg = LIBCALL_VALUE (Pmode);
+ rtx ret;
+
+ /* The return value register overlaps the first argument register.
+ Save and restore it around the call. */
+ emit_move_insn (save, valreg);
+ ret = emit_library_call_value (fn, NULL_RTX, 1, Pmode, 0);
+ if (GET_CODE (ret) != REG || REGNO (ret) < FIRST_PSEUDO_REGISTER)
+ ret = copy_to_reg (ret);
+ emit_move_insn (valreg, save);
+
+ return ret;
+}
+
+tree
+i860_build_va_list ()
+{
+ tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr;
+ tree record;
+
+ record = make_node (RECORD_TYPE);
+
+ field_ireg_used = build_decl (FIELD_DECL, get_identifier ("__ireg_used"),
+ unsigned_type_node);
+ field_freg_used = build_decl (FIELD_DECL, get_identifier ("__freg_used"),
+ unsigned_type_node);
+ field_reg_base = build_decl (FIELD_DECL, get_identifier ("__reg_base"),
+ ptr_type_node);
+ field_mem_ptr = build_decl (FIELD_DECL, get_identifier ("__mem_ptr"),
+ ptr_type_node);
+
+ DECL_FIELD_CONTEXT (field_ireg_used) = record;
+ DECL_FIELD_CONTEXT (field_freg_used) = record;
+ DECL_FIELD_CONTEXT (field_reg_base) = record;
+ DECL_FIELD_CONTEXT (field_mem_ptr) = record;
+
+#ifdef I860_SVR4_VA_LIST
+ TYPE_FIELDS (record) = field_ireg_used;
+ TREE_CHAIN (field_ireg_used) = field_freg_used;
+ TREE_CHAIN (field_freg_used) = field_reg_base;
+ TREE_CHAIN (field_reg_base) = field_mem_ptr;
+#else
+ TYPE_FIELDS (record) = field_reg_base;
+ TREE_CHAIN (field_reg_base) = field_mem_ptr;
+ TREE_CHAIN (field_mem_ptr) = field_ireg_used;
+ TREE_CHAIN (field_ireg_used) = field_freg_used;
+#endif
+
+ layout_type (record);
+ return record;
+}
+
+void
+i860_va_start (stdarg_p, valist, nextarg)
+ int stdarg_p;
+ tree valist;
+ rtx nextarg;
+{
+ tree saveregs, t;
+
+ saveregs = make_tree (build_pointer_type (va_list_type_node),
+ expand_builtin_saveregs ());
+ saveregs = build1 (INDIRECT_REF, va_list_type_node, saveregs);
+
+ if (stdarg_p)
+ {
+ tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr;
+ tree ireg_used, freg_used, reg_base, mem_ptr;
+
+#ifdef I860_SVR4_VA_LIST
+ field_ireg_used = TYPE_FIELDS (va_list_type_node);
+ field_freg_used = TREE_CHAIN (field_ireg_used);
+ field_reg_base = TREE_CHAIN (field_freg_used);
+ field_mem_ptr = TREE_CHAIN (field_reg_base);
+#else
+ field_reg_base = TYPE_FIELDS (va_list_type_node);
+ field_mem_ptr = TREE_CHAIN (field_reg_base);
+ field_ireg_used = TREE_CHAIN (field_mem_ptr);
+ field_freg_used = TREE_CHAIN (field_ireg_used);
+#endif
+
+ ireg_used = build (COMPONENT_REF, TREE_TYPE (field_ireg_used),
+ valist, field_ireg_used);
+ freg_used = build (COMPONENT_REF, TREE_TYPE (field_freg_used),
+ valist, field_freg_used);
+ reg_base = build (COMPONENT_REF, TREE_TYPE (field_reg_base),
+ valist, field_reg_base);
+ mem_ptr = build (COMPONENT_REF, TREE_TYPE (field_mem_ptr),
+ valist, field_mem_ptr);
+
+ t = build_int_2 (current_function_args_info.ints, 0);
+ t = build (MODIFY_EXPR, TREE_TYPE (ireg_used), ireg_used, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ t = build_int_2 (ROUNDUP (current_function_args_info.floats, 8), 0);
+ t = build (MODIFY_EXPR, TREE_TYPE (freg_used), freg_used, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ t = build (COMPONENT_REF, TREE_TYPE (field_reg_base),
+ saveregs, field_reg_base);
+ t = build (MODIFY_EXPR, TREE_TYPE (reg_base), reg_base, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ t = make_tree (ptr_type_node, nextarg);
+ t = build (MODIFY_EXPR, TREE_TYPE (mem_ptr), mem_ptr, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+ else
+ {
+ t = build (MODIFY_EXPR, va_list_type_node, valist, saveregs);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+}
+
+#define NUM_PARM_FREGS 8
+#define NUM_PARM_IREGS 12
+#ifdef I860_SVR4_VARARGS
+#define FREG_OFFSET 0
+#define IREG_OFFSET (NUM_PARM_FREGS * UNITS_PER_WORD)
+#else
+#define FREG_OFFSET (NUM_PARM_IREGS * UNITS_PER_WORD)
+#define IREG_OFFSET 0
+#endif
+
+rtx
+i860_va_arg (valist, type)
+ tree valist, type;
+{
+ tree field_ireg_used, field_freg_used, field_reg_base, field_mem_ptr;
+ tree type_ptr_node, t;
+ rtx lab_over = NULL_RTX;
+ rtx ret, val;
+ HOST_WIDE_INT align;
+
+#ifdef I860_SVR4_VA_LIST
+ field_ireg_used = TYPE_FIELDS (va_list_type_node);
+ field_freg_used = TREE_CHAIN (field_ireg_used);
+ field_reg_base = TREE_CHAIN (field_freg_used);
+ field_mem_ptr = TREE_CHAIN (field_reg_base);
+#else
+ field_reg_base = TYPE_FIELDS (va_list_type_node);
+ field_mem_ptr = TREE_CHAIN (field_reg_base);
+ field_ireg_used = TREE_CHAIN (field_mem_ptr);
+ field_freg_used = TREE_CHAIN (field_ireg_used);
+#endif
+
+ field_ireg_used = build (COMPONENT_REF, TREE_TYPE (field_ireg_used),
+ valist, field_ireg_used);
+ field_freg_used = build (COMPONENT_REF, TREE_TYPE (field_freg_used),
+ valist, field_freg_used);
+ field_reg_base = build (COMPONENT_REF, TREE_TYPE (field_reg_base),
+ valist, field_reg_base);
+ field_mem_ptr = build (COMPONENT_REF, TREE_TYPE (field_mem_ptr),
+ valist, field_mem_ptr);
+
+ ret = gen_reg_rtx (Pmode);
+ type_ptr_node = build_pointer_type (type);
+
+ if (! AGGREGATE_TYPE_P (type))
+ {
+ int nparm, incr, ofs;
+ tree field;
+ rtx lab_false;
+
+ if (FLOAT_TYPE_P (type))
+ {
+ field = field_freg_used;
+ nparm = NUM_PARM_FREGS;
+ incr = 2;
+ ofs = FREG_OFFSET;
+ }
+ else
+ {
+ field = field_ireg_used;
+ nparm = NUM_PARM_IREGS;
+ incr = int_size_in_bytes (type) / UNITS_PER_WORD;
+ ofs = IREG_OFFSET;
+ }
+
+ lab_false = gen_label_rtx ();
+ lab_over = gen_label_rtx ();
+
+ emit_cmp_and_jump_insns (expand_expr (field, NULL_RTX, 0, 0),
+ GEN_INT (nparm - incr), GT, const0_rtx,
+ TYPE_MODE (TREE_TYPE (field)),
+ TREE_UNSIGNED (field), 0, lab_false);
+
+ t = fold (build (POSTINCREMENT_EXPR, TREE_TYPE (field), field,
+ build_int_2 (incr, 0)));
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ t = fold (build (MULT_EXPR, TREE_TYPE (field), field,
+ build_int_2 (UNITS_PER_WORD, 0)));
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ t = fold (build (PLUS_EXPR, ptr_type_node, field_reg_base,
+ fold (build (PLUS_EXPR, TREE_TYPE (field), t,
+ build_int_2 (ofs, 0)))));
+ TREE_SIDE_EFFECTS (t) = 1;
+
+ val = expand_expr (t, ret, VOIDmode, EXPAND_NORMAL);
+ if (val != ret)
+ emit_move_insn (ret, val);
+
+ emit_jump_insn (gen_jump (lab_over));
+ emit_barrier ();
+ emit_label (lab_false);
+ }
+
+ align = TYPE_ALIGN (type);
+ if (align < BITS_PER_WORD)
+ align = BITS_PER_WORD;
+ align /= BITS_PER_UNIT;
+
+ t = build (PLUS_EXPR, ptr_type_node, field_mem_ptr,
+ build_int_2 (align - 1, 0));
+ t = build (BIT_AND_EXPR, ptr_type_node, t, build_int_2 (-align, -1));
+
+ val = expand_expr (t, ret, VOIDmode, EXPAND_NORMAL);
+ if (val != ret)
+ emit_move_insn (ret, val);
+
+ t = fold (build (PLUS_EXPR, ptr_type_node,
+ make_tree (ptr_type_node, ret),
+ build_int_2 (int_size_in_bytes (type), 0)));
+ t = build (MODIFY_EXPR, ptr_type_node, field_mem_ptr, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ if (lab_over)
+ emit_label (lab_over);
+
+ return ret;
+}