/* Definitions of target machine for GNU compiler, for MMIX.
- Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005
+ Free Software Foundation, Inc.
Contributed by Hans-Peter Nilsson (hp@bitrange.com)
This file is part of GCC.
static void mmix_reorg (void);
static void mmix_asm_output_mi_thunk
(FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
+static void mmix_setup_incoming_varargs
+ (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);
static void mmix_file_start (void);
static void mmix_file_end (void);
static bool mmix_rtx_costs (rtx, int, int, int *);
-
+static rtx mmix_struct_value_rtx (tree, int);
+static bool mmix_pass_by_reference (const CUMULATIVE_ARGS *,
+ enum machine_mode, tree, bool);
/* Target structure macros. Listed by node. See `Using and Porting GCC'
for a general description. */
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG mmix_reorg
+#undef TARGET_PROMOTE_FUNCTION_ARGS
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#if 0
+/* Apparently not doing TRT if int < register-size. FIXME: Perhaps
+ FUNCTION_VALUE and LIBCALL_VALUE needs tweaking as some ports say. */
+#undef TARGET_PROMOTE_FUNCTION_RETURN
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#endif
+
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX mmix_struct_value_rtx
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS mmix_setup_incoming_varargs
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE mmix_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Functions that are expansions for target macros.
labels. */
if (flag_pic)
{
- warning ("-f%s not supported: ignored", (flag_pic > 1) ? "PIC" : "pic");
+ warning (0, "-f%s not supported: ignored", (flag_pic > 1) ? "PIC" : "pic");
flag_pic = 0;
}
}
/* DATA_ALIGNMENT.
We have trouble getting the address of stuff that is located at other
than 32-bit alignments (GETA requirements), so try to give everything
- at least 32-bit alignment. */
+ at least 32-bit alignment. */
int
mmix_data_alignment (tree type ATTRIBUTE_UNUSED, int basic_align)
: NULL_RTX;
return (argsp->regs < MMIX_MAX_ARGS_IN_REGS
- && !MUST_PASS_IN_STACK (mode, type)
+ && !targetm.calls.must_pass_in_stack (mode, type)
&& (GET_MODE_BITSIZE (mode) <= 64
|| argsp->lib
|| TARGET_LIBFUNC))
/* Returns nonzero for everything that goes by reference, 0 for
everything that goes by value. */
-int
-mmix_function_arg_pass_by_reference (const CUMULATIVE_ARGS *argsp,
- enum machine_mode mode,
- tree type,
- int named ATTRIBUTE_UNUSED)
+static bool
+mmix_pass_by_reference (const CUMULATIVE_ARGS *argsp, enum machine_mode mode,
+ tree type, bool named ATTRIBUTE_UNUSED)
{
- /* FIXME: Check: I'm not sure the MUST_PASS_IN_STACK check is
+ /* FIXME: Check: I'm not sure the must_pass_in_stack check is
necessary. */
- return
- MUST_PASS_IN_STACK (mode, type)
- || (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8
- && !TARGET_LIBFUNC
- && !argsp->lib);
+ if (targetm.calls.must_pass_in_stack (mode, type))
+ return true;
+
+ if (MMIX_FUNCTION_ARG_SIZE (mode, type) > 8
+ && !TARGET_LIBFUNC
+ && (!argsp || !argsp->lib))
+ return true;
+
+ return false;
}
/* Return nonzero if regno is a register number where a parameter is
return
gen_rtx_REG (mode, MMIX_OUTGOING_RETURN_VALUE_REGNUM);
- /* A complex type, made up of components. */
- cmode = TYPE_MODE (TREE_TYPE (valtype));
+ if (COMPLEX_MODE_P (mode))
+ /* A complex type, made up of components. */
+ cmode = TYPE_MODE (TREE_TYPE (valtype));
+ else
+ {
+ /* Of the other larger-than-register modes, we only support
+ scalar mode TImode. (At least, that's the only one that's
+ been rudimentally tested.) Make sure we're alerted for
+ unexpected cases. */
+ if (mode != TImode)
+ sorry ("support for mode %qs", GET_MODE_NAME (mode));
+
+ /* In any case, we will fill registers to the natural size. */
+ cmode = DImode;
+ }
+
nregs = ((GET_MODE_BITSIZE (mode) + BITS_PER_WORD - 1) / BITS_PER_WORD);
/* We need to take care of the effect of the register hole on return
vec[nregs - 1]
= gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (cmode, first_val_regnum + nregs - 1),
- GEN_INT (0));
+ const0_rtx);
return gen_rtx_PARALLEL (VOIDmode, gen_rtvec_v (nregs, vec));
}
HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
tree func)
{
- /* If you define STRUCT_VALUE to 0, rather than use STRUCT_VALUE_REGNUM,
- (i.e. pass location of structure to return as invisible first
- argument) you need to tweak this code too. */
+ /* If you define TARGET_STRUCT_VALUE_RTX that returns 0 (i.e. pass
+ location of structure to return as invisible first argument), you
+ need to tweak this code too. */
const char *regname = reg_names[MMIX_FIRST_INCOMING_ARG_REGNUM];
if (delta >= 0 && delta < 65536)
sorry ("function_profiler support for MMIX");
}
-/* SETUP_INCOMING_VARARGS. */
+/* Worker function for TARGET_SETUP_INCOMING_VARARGS. For the moment,
+ let's stick to pushing argument registers on the stack. Later, we
+ can parse all arguments in registers, to improve performance. */
-void
+static void
mmix_setup_incoming_varargs (CUMULATIVE_ARGS *args_so_farp,
enum machine_mode mode,
tree vartype,
*pretend_sizep = (MMIX_MAX_ARGS_IN_REGS - (args_so_farp->regs + 1)) * 8;
/* We assume that one argument takes up one register here. That should
- be true until we start messing with multi-reg parameters. */
+ be true until we start messing with multi-reg parameters. */
if ((7 + (MMIX_FUNCTION_ARG_SIZE (mode, vartype))) / 8 != 1)
internal_error ("MMIX Internal: Last named vararg would not fit in a register");
}
-/* EXPAND_BUILTIN_VA_ARG. */
-
-/* This is modified from the "standard" implementation of va_arg: read the
- value from the current (padded) address and increment by the (padded)
- size. The difference for MMIX is that if the type is
- pass-by-reference, then perform an indirection. */
-
-rtx
-mmix_expand_builtin_va_arg (tree valist, tree type)
-{
- tree ptr_size = size_int (BITS_PER_WORD / BITS_PER_UNIT);
- tree addr_tree, type_size = NULL;
- tree align, alignm1;
- tree rounded_size;
- rtx addr;
-
- /* Compute the rounded size of the type. */
-
- /* Get AP. */
- addr_tree = valist;
- align = size_int (PARM_BOUNDARY / BITS_PER_UNIT);
- alignm1 = size_int (PARM_BOUNDARY / BITS_PER_UNIT - 1);
- if (type == error_mark_node
- || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
- || TREE_OVERFLOW (type_size))
- /* Presumably an error; the size isn't computable. A message has
- supposedly been emitted elsewhere. */
- rounded_size = size_zero_node;
- else
- rounded_size = fold (build (MULT_EXPR, sizetype,
- fold (build (TRUNC_DIV_EXPR, sizetype,
- fold (build (PLUS_EXPR, sizetype,
- type_size, alignm1)),
- align)),
- align));
-
- if (AGGREGATE_TYPE_P (type)
- && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) < 8
- && GET_MODE_UNIT_SIZE (TYPE_MODE (type)) != 0)
- {
- /* Adjust for big-endian the location of aggregates passed in a
- register, but where the aggregate is accessed in a shorter mode
- than the natural register mode (i.e. it is accessed as SFmode(?),
- SImode, HImode or QImode rather than DImode or DFmode(?)). FIXME:
- Or should we adjust the mode in which the aggregate is read, to be
- a register size mode? (Hum, nah, a small offset is generally
- cheaper than a wider memory access on MMIX.) */
- addr_tree
- = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
- size_int ((BITS_PER_WORD / BITS_PER_UNIT)
- - GET_MODE_UNIT_SIZE (TYPE_MODE (type))));
- }
- else if (!integer_zerop (rounded_size))
- {
- if (!really_constant_p (type_size))
- /* Varying-size types come in by reference. */
- addr_tree
- = build1 (INDIRECT_REF, build_pointer_type (type), addr_tree);
- else
- {
- /* If the size is less than a register, then we need to pad the
- address by adding the difference. */
- tree addend
- = fold (build (COND_EXPR, sizetype,
- fold (build (GT_EXPR, sizetype,
- rounded_size,
- align)),
- size_zero_node,
- fold (build (MINUS_EXPR, sizetype,
- rounded_size,
- type_size))));
- tree addr_tree1
- = fold (build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
- addend));
-
- /* If this type is larger than what fits in a register, then it
- is passed by reference. */
- addr_tree
- = fold (build (COND_EXPR, TREE_TYPE (addr_tree1),
- fold (build (GT_EXPR, sizetype,
- rounded_size,
- ptr_size)),
- build1 (INDIRECT_REF, build_pointer_type (type),
- addr_tree1),
- addr_tree1));
- }
- }
-
- addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
- addr = copy_to_reg (addr);
-
- if (!integer_zerop (rounded_size))
- {
- /* Compute new value for AP. For MMIX, it is always advanced by the
- size of a register. */
- tree t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
- build (PLUS_EXPR, TREE_TYPE (valist), valist,
- ptr_size));
- TREE_SIDE_EFFECTS (t) = 1;
- expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- }
-
- return addr;
-}
-
/* TRAMPOLINE_SIZE. */
/* Four 4-byte insns plus two 8-byte values. */
int mmix_trampoline_size = 32;
case SYMBOL_REF:
return 1;
- case CONSTANT_P_RTX:
case HIGH:
/* FIXME: Don't know how to dissect these. Avoid them for now,
except we know they're constants. */
fputs ("! mmixal:= 8H LOC Data_Section\n", asm_out_file);
- /* Make sure each file starts with the text section. */
+ /* Make sure each file starts with the text section. */
text_section ();
}
static void
mmix_file_end (void)
{
- /* Make sure each file ends with the data section. */
+ /* Make sure each file ends with the data section. */
data_section ();
}
}
}
-/* ASM_OUTPUT_SOURCE_LINE. */
-
-void
-mmix_asm_output_source_line (FILE *stream, int lineno)
-{
- fprintf (stream, "# %d ", lineno);
- OUTPUT_QUOTED_STRING (stream, main_input_filename);
- fprintf (stream, "\n");
-}
-
/* Target hook for assembling integer objects. Use mmix_print_operand
for WYDE and TETRA. Use mmix_output_octa to output 8-byte
CONST_DOUBLEs. */
return true;
case 8:
- if (GET_CODE (x) == CONST_DOUBLE)
- /* We don't get here anymore for CONST_DOUBLE, because DImode
- isn't expressed as CONST_DOUBLE, and DFmode is handled
- elsewhere. */
- abort ();
+ /* We don't get here anymore for CONST_DOUBLE, because DImode
+ isn't expressed as CONST_DOUBLE, and DFmode is handled
+ elsewhere. */
+ gcc_assert (GET_CODE (x) != CONST_DOUBLE);
assemble_integer_with_op ("\tOCTA\t", x);
return true;
}
fprintf (stream, "\tIS @\n");
}
+/* ASM_OUTPUT_INTERNAL_LABEL. */
+
+void
+mmix_asm_output_internal_label (FILE *stream, const char *name)
+{
+ assemble_name_raw (stream, name);
+ fprintf (stream, "\tIS @\n");
+}
+
/* ASM_DECLARE_REGISTER_GLOBAL. */
void
default:
/* Presumably there's a missing case above if we get here. */
- internal_error ("MMIX Internal: Missing `%c' case in mmix_print_operand", code);
+ internal_error ("MMIX Internal: Missing %qc case in mmix_print_operand", code);
}
switch (GET_CODE (modified_x))
+ current_function_pretend_args_size
+ locals_size + 7) & ~7;
- /* The assumption that locals_size fits in an int is asserted in
- mmix_expand_prologue. */
-
/* The first address to access is beyond the outgoing_args area. */
- int offset = current_function_outgoing_args_size;
+ HOST_WIDE_INT offset = current_function_outgoing_args_size;
/* Add the space for global non-register-stack registers.
It is assumed that the frame-pointer register can be one of these
might be of an unaligned size. */
offset += (locals_size + 7) & ~7;
-
/* The saved register stack pointer is just below the frame-pointer
register. We don't need to restore it "manually"; the POP
instruction does that. */
|| (GET_CODE (XEXP (op, 1)) == CONST_DOUBLE
&& GET_MODE (XEXP (op, 1)) == VOIDmode)))
return 1;
- /* FALLTHROUGH */
+ /* Fall through. */
default:
return address_operand (op, mode);
}
if (mode == VOIDmode)
mode = GET_MODE (op);
- if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
+ if (mode == VOIDmode && COMPARISON_P (op))
mode = GET_MODE (XEXP (op, 0));
return ((mode == CCmode || mode == DImode)
mode = GET_MODE (op);
/* Get the mode from the first operand if we don't have one. */
- if (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
+ if (mode == VOIDmode && COMPARISON_P (op))
mode = GET_MODE (XEXP (op, 0));
/* FIXME: This needs to be kept in sync with the tables in
mmix_output_condition. */
return
- (mode == VOIDmode && GET_RTX_CLASS (GET_CODE (op)) == '<')
+ (mode == VOIDmode && COMPARISON_P (op))
|| (mode == CC_FUNmode
&& (code == ORDERED || code == UNORDERED))
|| (mode == CC_FPmode
{
enum machine_mode cc_mode;
- /* Terminated with {NIL, NULL, NULL} */
+ /* Terminated with {UNKNOWN, NULL, NULL} */
const struct cc_conv *const convs;
};
#undef CCEND
-#define CCEND {NIL, NULL, NULL}
+#define CCEND {UNKNOWN, NULL, NULL}
static const struct cc_conv cc_fun_convs[]
= {{ORDERED, "Z", "P"},
{
if (mode == cc_convs[i].cc_mode)
{
- for (j = 0; cc_convs[i].convs[j].cc != NIL; j++)
+ for (j = 0; cc_convs[i].convs[j].cc != UNKNOWN; j++)
if (cc == cc_convs[i].convs[j].cc)
{
const char *mmix_cc
fatal_insn ("MMIX Internal: This is not a constant:", x);
}
+/* Worker function for TARGET_STRUCT_VALUE_RTX. */
+
+static rtx
+mmix_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
+ int incoming ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (Pmode, MMIX_STRUCT_VALUE_REGNUM);
+}
+
/*
* Local variables:
* eval: (c-set-style "gnu")