/* Definitions of target machine for GNU compiler, for MMIX.
- Copyright (C) 2000, 2001, 2002, 2003, 2004 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.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
rtx mmix_compare_op0;
rtx mmix_compare_op1;
-/* We ignore some options with arguments. They are passed to the linker,
- but also ends up here because they start with "-m". We tell the driver
- to store them in a variable we don't inspect. */
-const char *mmix_cc1_ignored_option;
-
/* Declarations of locals. */
/* Intermediate for insn output. */
static void mmix_file_end (void);
static bool mmix_rtx_costs (rtx, int, int, int *);
static rtx mmix_struct_value_rtx (tree, int);
-static tree mmix_gimplify_va_arg_expr (tree, tree, tree *, tree *);
-
+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_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_GIMPLIFY_VA_ARG_EXPR
-#define TARGET_GIMPLIFY_VA_ARG_EXPR mmix_gimplify_va_arg_expr
+#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
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
struct gcc_target targetm = TARGET_INITIALIZER;
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;
}
}
: 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
internal_error ("MMIX Internal: Last named vararg would not fit in a register");
}
-/* Gimplify VA_ARG_EXPR. All we need to do is figure out if TYPE is
- pass-by-reference and hand off to standard routines. */
-
-static tree
-mmix_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
-{
- CUMULATIVE_ARGS cum;
- cum.lib = 0;
-
- if (mmix_function_arg_pass_by_reference (&cum, TYPE_MODE (type), type, 0))
- return ind_gimplify_va_arg_expr (valist, type, pre_p, post_p);
- else
- return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
-}
-
/* TRAMPOLINE_SIZE. */
/* Four 4-byte insns plus two 8-byte values. */
int mmix_trampoline_size = 32;
fputs ("! mmixal:= 8H LOC Data_Section\n", asm_out_file);
/* Make sure each file starts with the text section. */
- text_section ();
+ switch_to_section (text_section);
}
/* TARGET_ASM_FILE_END. */
mmix_file_end (void)
{
/* Make sure each file ends with the data section. */
- data_section ();
+ switch_to_section (data_section);
}
/* ASM_OUTPUT_SOURCE_FILENAME. */
}
}
-/* 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;
}
int size,
int align)
{
- data_section ();
+ switch_to_section (data_section);
ASM_OUTPUT_ALIGN (stream, exact_log2 (align/BITS_PER_UNIT));
assemble_name (stream, name);
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))
/* Make sure we don't get an unaligned stack. */
if ((stack_space_to_allocate % 8) != 0)
- internal_error ("stack frame not a multiple of 8 bytes: %d",
+ internal_error ("stack frame not a multiple of 8 bytes: %wd",
stack_space_to_allocate);
if (current_function_pretend_args_size)
+ 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
/* Make sure we don't get an unaligned stack. */
if ((stack_space_to_deallocate % 8) != 0)
- internal_error ("stack frame not a multiple of octabyte: %d",
+ internal_error ("stack frame not a multiple of octabyte: %wd",
stack_space_to_deallocate);
/* We will add back small offsets to the stack pointer as we go.
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. */
return 1;
}
-/* True if this is an address_operand or a symbolic operand. */
-
-int
-mmix_symbolic_or_address_operand (rtx op, enum machine_mode mode)
-{
- switch (GET_CODE (op))
- {
- case SYMBOL_REF:
- case LABEL_REF:
- return 1;
- case CONST:
- op = XEXP (op, 0);
- if ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
- || GET_CODE (XEXP (op, 0)) == LABEL_REF)
- && (GET_CODE (XEXP (op, 1)) == CONST_INT
- || (GET_CODE (XEXP (op, 1)) == CONST_DOUBLE
- && GET_MODE (XEXP (op, 1)) == VOIDmode)))
- return 1;
- /* Fall through. */
- default:
- return address_operand (op, mode);
- }
-}
-
-/* True if this is a register or CONST_INT (or CONST_DOUBLE for DImode).
- We could narrow the value down with a couple of predicated, but that
- doesn't seem to be worth it at the moment. */
-
-int
-mmix_reg_or_constant_operand (rtx op, enum machine_mode mode)
-{
- return register_operand (op, mode)
- || (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
- || GET_CODE (op) == CONST_INT;
-}
-
-/* True if this is a register with a condition-code mode. */
-
-int
-mmix_reg_cc_operand (rtx op, enum machine_mode mode)
-{
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- return register_operand (op, mode)
- && (mode == CCmode || mode == CC_UNSmode || mode == CC_FPmode
- || mode == CC_FPEQmode || mode == CC_FUNmode);
-}
-
-/* True if this is a foldable comparison operator
- - one where a the result of (compare:CC (reg) (const_int 0)) can be
- replaced by (reg). */
-
-int
-mmix_foldable_comparison_operator (rtx op, enum machine_mode mode)
-{
- RTX_CODE code = GET_CODE (op);
-
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- if (mode == VOIDmode && COMPARISON_P (op))
- mode = GET_MODE (XEXP (op, 0));
-
- return ((mode == CCmode || mode == DImode)
- && (code == NE || code == EQ || code == GE || code == GT
- || code == LE))
- /* FIXME: This may be a stupid trick. What happens when GCC wants to
- reverse the condition? Can it do that by itself? Maybe it can
- even reverse the condition to fit a foldable one in the first
- place? */
- || (mode == CC_UNSmode && (code == GTU || code == LEU));
-}
-
-/* Like comparison_operator, but only true if this comparison operator is
- applied to a valid mode. Needed to avoid jump.c generating invalid
- code with -ffast-math (gcc.dg/20001228-1.c). */
-
-int
-mmix_comparison_operator (rtx op, enum machine_mode mode)
-{
- RTX_CODE code = GET_CODE (op);
-
- /* Comparison operators usually don't have a mode, but let's try and get
- one anyway for the day that changes. */
- if (mode == VOIDmode)
- mode = GET_MODE (op);
-
- /* Get the mode from the first operand if we don't have one. */
- 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 && COMPARISON_P (op))
- || (mode == CC_FUNmode
- && (code == ORDERED || code == UNORDERED))
- || (mode == CC_FPmode
- && (code == GT || code == LT))
- || (mode == CC_FPEQmode
- && (code == NE || code == EQ))
- || (mode == CC_UNSmode
- && (code == GEU || code == GTU || code == LEU || code == LTU))
- || (mode == CCmode
- && (code == NE || code == EQ || code == GE || code == GT
- || code == LE || code == LT))
- || (mode == DImode
- && (code == NE || code == EQ || code == GE || code == GT
- || code == LE || code == LT || code == LEU || code == GTU));
-}
-
-/* True if this is a register or 0 (int or float). */
-
-int
-mmix_reg_or_0_operand (rtx op, enum machine_mode mode)
-{
- /* FIXME: Is mode calculation necessary and correct? */
- return
- op == CONST0_RTX (mode == VOIDmode ? GET_MODE (op) : mode)
- || register_operand (op, mode);
-}
-
-/* True if this is a register or an int 0..255. */
-
-int
-mmix_reg_or_8bit_operand (rtx op, enum machine_mode mode)
-{
- return register_operand (op, mode)
- || (GET_CODE (op) == CONST_INT
- && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'));
-}
-
/* Returns zero if code and mode is not a valid condition from a
compare-type insn. Nonzero if it is. The parameter op, if non-NULL,
is the comparison of mode is CC-somethingmode. */
{
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
REAL_VALUE_TO_TARGET_DOUBLE (value, bits);
- if (sizeof (long) < sizeof (HOST_WIDEST_INT))
- {
- retval = (unsigned long) bits[1] / 2;
- retval *= 2;
- retval |= (unsigned long) bits[1] & 1;
- retval
- |= (unsigned HOST_WIDEST_INT) bits[0]
- << (sizeof (bits[0]) * 8);
- }
- else
- retval = (unsigned long) bits[1];
-
- return retval;
+ /* The double cast is necessary to avoid getting the long
+ sign-extended to unsigned long long(!) when they're of
+ different size (usually 32-bit hosts). */
+ return
+ ((unsigned HOST_WIDEST_INT) (unsigned long) bits[0]
+ << (unsigned HOST_WIDEST_INT) 32U)
+ | (unsigned HOST_WIDEST_INT) (unsigned long) bits[1];
}
else if (GET_MODE (x) == SFmode)
{