/* Subroutines for insn-output.c for VAX.
- Copyright (C) 1987, 1994, 1995, 1997, 1998, 1999, 2000, 2001, 2002,
- 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 1987-2013 Free Software Foundation, Inc.
This file is part of GCC.
#include "rtl.h"
#include "df.h"
#include "tree.h"
+#include "calls.h"
+#include "varasm.h"
#include "regs.h"
#include "hard-reg-set.h"
#include "insn-config.h"
#include "flags.h"
#include "debug.h"
#include "diagnostic-core.h"
-#include "toplev.h"
+#include "reload.h"
#include "tm-preds.h"
#include "tm-constrs.h"
#include "tm_p.h"
#include "target.h"
#include "target-def.h"
+#include "wide-int.h"
static void vax_option_override (void);
static bool vax_legitimate_address_p (enum machine_mode, rtx, bool);
-static void vax_output_function_prologue (FILE *, HOST_WIDE_INT);
static void vax_file_start (void);
static void vax_init_libfuncs (void);
static void vax_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
static int vax_address_cost_1 (rtx);
-static int vax_address_cost (rtx, bool);
-static bool vax_rtx_costs (rtx, int, int, int *, bool);
+static int vax_address_cost (rtx, enum machine_mode, addr_space_t, bool);
+static bool vax_rtx_costs (rtx, int, int, int, int *, bool);
+static rtx vax_function_arg (cumulative_args_t, enum machine_mode,
+ const_tree, bool);
+static void vax_function_arg_advance (cumulative_args_t, enum machine_mode,
+ const_tree, bool);
static rtx vax_struct_value_rtx (tree, int);
static rtx vax_builtin_setjmp_frame_value (void);
static void vax_asm_trampoline_template (FILE *);
static void vax_trampoline_init (rtx, tree, rtx);
static int vax_return_pops_args (tree, tree, int);
+static bool vax_mode_dependent_address_p (const_rtx, addr_space_t);
\f
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
-#undef TARGET_ASM_FUNCTION_PROLOGUE
-#define TARGET_ASM_FUNCTION_PROLOGUE vax_output_function_prologue
-
#undef TARGET_ASM_FILE_START
#define TARGET_ASM_FILE_START vax_file_start
#undef TARGET_ASM_FILE_START_APP_OFF
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
-#undef TARGET_DEFAULT_TARGET_FLAGS
-#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
-
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS vax_rtx_costs
#undef TARGET_ADDRESS_COST
#undef TARGET_PROMOTE_PROTOTYPES
#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG vax_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE vax_function_arg_advance
+
#undef TARGET_STRUCT_VALUE_RTX
#define TARGET_STRUCT_VALUE_RTX vax_struct_value_rtx
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P vax_legitimate_address_p
+#undef TARGET_MODE_DEPENDENT_ADDRESS_P
+#define TARGET_MODE_DEPENDENT_ADDRESS_P vax_mode_dependent_address_p
#undef TARGET_FRAME_POINTER_REQUIRED
#define TARGET_FRAME_POINTER_REQUIRED hook_bool_void_true
#endif
}
+static void
+vax_add_reg_cfa_offset (rtx insn, int offset, rtx src)
+{
+ rtx x;
+
+ x = plus_constant (Pmode, frame_pointer_rtx, offset);
+ x = gen_rtx_MEM (SImode, x);
+ x = gen_rtx_SET (VOIDmode, x, src);
+ add_reg_note (insn, REG_CFA_OFFSET, x);
+}
+
/* Generate the assembly code for function entry. FILE is a stdio
stream to output the code to. SIZE is an int: how many units of
temporary storage to allocate.
used in the function. This function is responsible for knowing
which registers should not be saved even if used. */
-static void
-vax_output_function_prologue (FILE * file, HOST_WIDE_INT size)
+void
+vax_expand_prologue (void)
{
- int regno;
+ int regno, offset;
int mask = 0;
+ HOST_WIDE_INT size;
+ rtx insn;
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
mask |= 1 << regno;
- fprintf (file, "\t.word 0x%x\n", mask);
+ insn = emit_insn (gen_procedure_entry_mask (GEN_INT (mask)));
+ RTX_FRAME_RELATED_P (insn) = 1;
- if (dwarf2out_do_frame ())
- {
- const char *label = dwarf2out_cfi_label (false);
- int offset = 0;
+ /* The layout of the CALLG/S stack frame is follows:
- for (regno = FIRST_PSEUDO_REGISTER-1; regno >= 0; --regno)
- if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
- dwarf2out_reg_save (label, regno, offset -= 4);
+ <- CFA, AP
+ r11
+ r10
+ ... Registers saved as specified by MASK
+ r3
+ r2
+ return-addr
+ old fp
+ old ap
+ old psw
+ zero
+ <- FP, SP
- dwarf2out_reg_save (label, PC_REGNUM, offset -= 4);
- dwarf2out_reg_save (label, FRAME_POINTER_REGNUM, offset -= 4);
- dwarf2out_reg_save (label, ARG_POINTER_REGNUM, offset -= 4);
- dwarf2out_def_cfa (label, FRAME_POINTER_REGNUM, -(offset - 4));
- }
+ The rest of the prologue will adjust the SP for the local frame. */
+
+ vax_add_reg_cfa_offset (insn, 4, arg_pointer_rtx);
+ vax_add_reg_cfa_offset (insn, 8, frame_pointer_rtx);
+ vax_add_reg_cfa_offset (insn, 12, pc_rtx);
+
+ offset = 16;
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (mask & (1 << regno))
+ {
+ vax_add_reg_cfa_offset (insn, offset, gen_rtx_REG (SImode, regno));
+ offset += 4;
+ }
+
+ /* Because add_reg_note pushes the notes, adding this last means that
+ it will be processed first. This is required to allow the other
+ notes be interpreted properly. */
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (Pmode, frame_pointer_rtx, offset));
+ /* Allocate the local stack frame. */
+ size = get_frame_size ();
size -= STARTING_FRAME_OFFSET;
- if (size >= 64)
- asm_fprintf (file, "\tmovab %wd(%Rsp),%Rsp\n", -size);
- else if (size)
- asm_fprintf (file, "\tsubl2 $%wd,%Rsp\n", size);
+ emit_insn (gen_addsi3 (stack_pointer_rtx,
+ stack_pointer_rtx, GEN_INT (-size)));
+
+ /* Do not allow instructions referencing local stack memory to be
+ scheduled before the frame is allocated. This is more pedantic
+ than anything else, given that VAX does not currently have a
+ scheduling description. */
+ emit_insn (gen_blockage ());
}
/* When debugging with stabs, we want to output an extra dummy label
if (offset)
{
if (CONST_INT_P (offset))
- offset = plus_constant (XEXP (addr, 0), INTVAL (offset));
+ offset = plus_constant (Pmode, XEXP (addr, 0),
+ INTVAL (offset));
else
{
gcc_assert (CONST_INT_P (XEXP (addr, 0)));
- offset = plus_constant (offset, INTVAL (XEXP (addr, 0)));
+ offset = plus_constant (Pmode, offset,
+ INTVAL (XEXP (addr, 0)));
}
}
offset = XEXP (addr, 0);
if (offset)
{
if (CONST_INT_P (offset))
- offset = plus_constant (XEXP (addr, 1), INTVAL (offset));
+ offset = plus_constant (Pmode, XEXP (addr, 1),
+ INTVAL (offset));
else
{
gcc_assert (CONST_INT_P (XEXP (addr, 1)));
- offset = plus_constant (offset, INTVAL (XEXP (addr, 1)));
+ offset = plus_constant (Pmode, offset,
+ INTVAL (XEXP (addr, 1)));
}
}
offset = XEXP (addr, 1);
fprintf (file, "$%d", (int) (0xff & - INTVAL (x)));
else if (code == 'M' && CONST_INT_P (x))
fprintf (file, "$%d", ~((1 << INTVAL (x)) - 1));
+ else if (code == 'x' && CONST_INT_P (x))
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
else if (REG_P (x))
fprintf (file, "%s", reg_names[REGNO (x)]);
else if (MEM_P (x))
{
int x = 1 << i;
bool ok;
- REAL_VALUE_FROM_INT (s, x, 0, mode);
+ real_from_integer (&s, mode, x, SIGNED);
if (REAL_VALUES_EQUAL (r, s))
return true;
}
static int
-vax_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
+vax_address_cost (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED,
+ addr_space_t as ATTRIBUTE_UNUSED,
+ bool speed ATTRIBUTE_UNUSED)
{
return (1 + (REG_P (x) ? 0 : vax_address_cost_1 (x)));
}
costs on a per cpu basis. */
static bool
-vax_rtx_costs (rtx x, int code, int outer_code, int *total,
- bool speed ATTRIBUTE_UNUSED)
+vax_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
+ int *total, bool speed ATTRIBUTE_UNUSED)
{
enum machine_mode mode = GET_MODE (x);
int i = 0; /* may be modified in switch */
{
lval >>= n;
-#if HOST_BITS_PER_WIDE_INT == 32
/* On 32bit platforms, if the 6bits didn't overflow into the
upper 32bit value that value better be 0. If we have
overflowed, make sure it wasn't too much. */
- if (hval != 0)
+ if (HOST_BITS_PER_WIDE_INT == 32 && hval != 0)
{
if (n <= 26 || hval >= ((unsigned)1 << (n - 26)))
n = 0; /* failure */
else
lval |= hval << (32 - n);
}
-#endif
/* If n is 0, then ashq is not the best way to emit this. */
if (n > 0)
{
operands[1] = GEN_INT (lval);
operands[2] = GEN_INT (n);
- return "ashq %2,%1,%0";
+ return "ashq %2,%D1,%0";
}
#if HOST_BITS_PER_WIDE_INT == 32
}
{
operands[1] = GEN_INT (hval >> n);
operands[2] = GEN_INT (n + 32);
- return "ashq %2,%1,%0";
+ return "ashq %2,%D1,%0";
#endif
}
}
return true;
}
-/* True if the constant value X is a legitimate general operand.
- It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
-
-bool
-legitimate_constant_p (rtx x ATTRIBUTE_UNUSED)
-{
- return true;
-}
-
/* The other macros defined here are used only in legitimate_address_p (). */
/* Nonzero if X is a hard reg that can be used as an index
rtx xfoo0;
if (REG_P (x))
{
- extern rtx *reg_equiv_mem;
if (! reload_in_progress
- || reg_equiv_mem[REGNO (x)] == 0
- || indirectable_address_p (reg_equiv_mem[REGNO (x)], strict, false))
+ || reg_equiv_mem (REGNO (x)) == 0
+ || indirectable_address_p (reg_equiv_mem (REGNO (x)), strict, false))
return true;
}
if (indirectable_constant_address_p (x, false))
increment being the length of the operand) and all indexed address depend
thus (because the index scale factor is the length of the operand). */
-bool
-vax_mode_dependent_address_p (rtx x)
+static bool
+vax_mode_dependent_address_p (const_rtx x, addr_space_t as ATTRIBUTE_UNUSED)
{
rtx xfoo0, xfoo1;
mem = adjust_address (m_tramp, SImode, 4);
emit_move_insn (mem, cxt);
mem = adjust_address (m_tramp, SImode, 11);
- emit_move_insn (mem, plus_constant (fnaddr, 2));
+ emit_move_insn (mem, plus_constant (Pmode, fnaddr, 2));
emit_insn (gen_sync_istream ());
}
{
return size > 255 * 4 ? 0 : size;
}
+
+/* Define where to put the arguments to a function.
+ Value is zero to push the argument on the stack,
+ or a hard register in which to store the argument.
+
+ MODE is the argument's machine mode.
+ TYPE is the data type of the argument (as a tree).
+ This is null for libcalls where that information may
+ not be available.
+ CUM is a variable of type CUMULATIVE_ARGS which gives info about
+ the preceding args and about the function being called.
+ NAMED is nonzero if this argument is a named parameter
+ (otherwise it is an extra parameter matching an ellipsis). */
+
+/* On the VAX all args are pushed. */
+
+static rtx
+vax_function_arg (cumulative_args_t cum ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ const_tree type ATTRIBUTE_UNUSED,
+ bool named ATTRIBUTE_UNUSED)
+{
+ return NULL_RTX;
+}
+
+/* Update the data in CUM to advance over an argument of mode MODE and
+ data type TYPE. (TYPE is null for libcalls where that information
+ may not be available.) */
+
+static void
+vax_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+
+ *cum += (mode != BLKmode
+ ? (GET_MODE_SIZE (mode) + 3) & ~3
+ : (int_size_in_bytes (type) + 3) & ~3);
+}