+2000-01-23 Richard Henderson <rth@cygnus.com>
+
+ * alpha/osf.h (TARGET_HAS_XFLOATING_LIBS): Define.
+ * alpha/osf5.h: New file.
+ * configure.in (alpha-*-osf5): Add it to tm_file.
+
+ * emit-rtl.c (operand_subword): Support TFmode on a 64-bit target.
+
+ * alpha-protos.h (alpha_emit_xfloating_arith): Declare.
+ (alpha_emit_xfloating_cvt, function_arg): Declare.
+ * alpha.c (alpha_emit_conditional_branch): Call
+ alpha_emit_xfloating_compare for TFmode compares.
+ (alpha_lookup_xfloating_lib_func): New.
+ (alpha_compute_xfloating_mode_arg): New.
+ (alpha_emit_xfloating_libcall): New.
+ (alpha_emit_xfloating_arith): New.
+ (alpha_emit_xfloating_compare): New.
+ (alpha_emit_xfloating_cvt): New.
+ (print_operand): Add default abort case.
+ (function_arg): Mind FUNCTION_ARG_PASS_BY_REFERENCE.
+ * alpha.h (TARGET_HAS_XFLOATING_LIBS): New.
+ (BIGGEST_ALIGNMENT): Increase to 128 bits.
+ (RETURN_IN_MEMORY): True for TF/TCmode.
+ (ALPHA_ARG_SIZE): TF/TCmode is passed indirect.
+ (FUNCTION_ARG): Move to function_arg.
+ (FUNCTION_ARG_PASS_BY_REFERENCE): New.
+ (ASM_OUTPUT_LONG_DOUBLE): New.
+ (ASM_OUTPUT_DOUBLE): Always output bits.
+ * alpha.md (addtf3, divtf3, multf3, subtf3, cmptf): New.
+ (fix_trunctfdi2, floatditf2, floatunsditf2): New.
+ (extenddftf2, trunctfdf2): New.
+
2000-01-23 Alexandre Oliva <oliva@lsd.ic.unicamp.br>
* config/sparc/sol2-sld-64.h (TRANSFER_FROM_TRAMPOLINE): Moved...
HOST_WIDE_INT));
extern rtx alpha_emit_conditional_branch PARAMS ((enum rtx_code));
extern rtx alpha_emit_conditional_move PARAMS ((rtx, enum machine_mode));
+extern void alpha_emit_xfloating_arith PARAMS ((enum rtx_code, rtx[]));
+extern void alpha_emit_xfloating_cvt PARAMS ((enum rtx_code, rtx[]));
extern void alpha_expand_unaligned_load PARAMS ((rtx, rtx, HOST_WIDE_INT,
HOST_WIDE_INT, int));
extern void alpha_expand_unaligned_store PARAMS ((rtx, rtx, HOST_WIDE_INT,
#ifdef RTX_CODE
extern void alpha_va_start PARAMS ((int, tree, rtx));
extern rtx alpha_va_arg PARAMS ((tree, tree));
+extern rtx function_arg PARAMS ((CUMULATIVE_ARGS, enum machine_mode,
+ tree, int));
#endif
extern int vms_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree));
extern void alpha_start_function PARAMS ((FILE *, const char *, tree));
PARAMS ((struct function *p));
static void alpha_mark_machine_status
PARAMS ((struct function *p));
-static int alpha_ra_ever_killed PARAMS ((void));
-static rtx set_frame_related_p PARAMS ((void));
-
+static int alpha_ra_ever_killed
+ PARAMS ((void));
+static rtx set_frame_related_p
+ PARAMS ((void));
+static const char *alpha_lookup_xfloating_lib_func
+ PARAMS ((enum rtx_code));
+static int alpha_compute_xfloating_mode_arg
+ PARAMS ((enum rtx_code, enum alpha_fp_rounding_mode));
+static void alpha_emit_xfloating_libcall
+ PARAMS ((const char *, rtx, rtx[], int, rtx));
+static rtx alpha_emit_xfloating_compare
+ PARAMS ((enum rtx_code, rtx, rtx));
/* Get the number of args of a function in one of two ways. */
#ifdef OPEN_VMS
rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1;
rtx tem;
+ if (alpha_compare.fp_p && GET_MODE (op0) == TFmode)
+ {
+ if (! TARGET_HAS_XFLOATING_LIBS)
+ abort ();
+
+ /* X_floating library comparison functions return
+ -1 unordered
+ 0 false
+ 1 true
+ Convert the compare against the raw return value. */
+
+ op0 = alpha_emit_xfloating_compare (code, op0, op1);
+ op1 = const0_rtx;
+ alpha_compare.fp_p = 0;
+ code = GT;
+ }
+
/* The general case: fold the comparison code to the types of compares
that we have, choosing the branch as necessary. */
switch (code)
return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_op_mode));
}
\f
+/* Look up the function X_floating library function name for the
+ given operation. */
+
+static const char *
+alpha_lookup_xfloating_lib_func (code)
+ enum rtx_code code;
+{
+ struct xfloating_op
+ {
+ enum rtx_code code;
+ const char *func;
+ };
+
+ static const struct xfloating_op vms_xfloating_ops[] =
+ {
+ { PLUS, "OTS$ADD_X" },
+ { MINUS, "OTS$SUB_X" },
+ { MULT, "OTS$MUL_X" },
+ { DIV, "OTS$DIV_X" },
+ { EQ, "OTS$EQL_X" },
+ { NE, "OTS$NEQ_X" },
+ { LT, "OTS$LSS_X" },
+ { LE, "OTS$LEQ_X" },
+ { GT, "OTS$GTR_X" },
+ { GE, "OTS$GEQ_X" },
+ { FIX, "OTS$CVTXQ" },
+ { FLOAT, "OTS$CVTQX" },
+ { UNSIGNED_FLOAT, "OTS$CVTQUX" },
+ { FLOAT_EXTEND, "OTS$CVT_FLOAT_T_X" },
+ { FLOAT_TRUNCATE, "OTS$CVT_FLOAT_X_T" },
+ };
+
+ static const struct xfloating_op osf_xfloating_ops[] =
+ {
+ { PLUS, "_OtsAddX" },
+ { MINUS, "_OtsSubX" },
+ { MULT, "_OtsMulX" },
+ { DIV, "_OtsDivX" },
+ { EQ, "_OtsEqlX" },
+ { NE, "_OtsNeqX" },
+ { LT, "_OtsLssX" },
+ { LE, "_OtsLeqX" },
+ { GT, "_OtsGtrX" },
+ { GE, "_OtsGeqX" },
+ { FIX, "_OtsCvtXQ" },
+ { FLOAT, "_OtsCvtQX" },
+ { UNSIGNED_FLOAT, "_OtsCvtQUX" },
+ { FLOAT_EXTEND, "_OtsConvertFloatTX" },
+ { FLOAT_TRUNCATE, "_OtsConvertFloatXT" },
+ };
+
+ const struct xfloating_op *ops;
+ const long n = sizeof(osf_xfloating_ops) / sizeof(osf_xfloating_ops[0]);
+ long i;
+
+ /* How irritating. Nothing to key off for the table. Hardcode
+ knowledge of the G_floating routines. */
+ if (TARGET_FLOAT_VAX)
+ {
+ if (TARGET_OPEN_VMS)
+ {
+ if (code == FLOAT_EXTEND)
+ return "OTS$CVT_FLOAT_G_X";
+ if (code == FLOAT_TRUNCATE)
+ return "OTS$CVT_FLOAT_X_G";
+ }
+ else
+ {
+ if (code == FLOAT_EXTEND)
+ return "_OtsConvertFloatGX";
+ if (code == FLOAT_TRUNCATE)
+ return "_OtsConvertFloatXG";
+ }
+ }
+
+ if (TARGET_OPEN_VMS)
+ ops = vms_xfloating_ops;
+ else
+ ops = osf_xfloating_ops;
+
+ for (i = 0; i < n; ++i)
+ if (ops[i].code == code)
+ return ops[i].func;
+
+ abort();
+}
+
+/* Most X_floating operations take the rounding mode as an argument.
+ Compute that here. */
+
+static int
+alpha_compute_xfloating_mode_arg (code, round)
+ enum rtx_code code;
+ enum alpha_fp_rounding_mode round;
+{
+ int mode;
+
+ switch (round)
+ {
+ case ALPHA_FPRM_NORM:
+ mode = 2;
+ break;
+ case ALPHA_FPRM_MINF:
+ mode = 1;
+ break;
+ case ALPHA_FPRM_CHOP:
+ mode = 0;
+ break;
+ case ALPHA_FPRM_DYN:
+ mode = 4;
+ break;
+ default:
+ abort ();
+
+ /* XXX For reference, round to +inf is mode = 3. */
+ }
+
+ if (code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N)
+ mode |= 0x10000;
+
+ return mode;
+}
+
+/* Emit an X_floating library function call.
+
+ Note that these functions do not follow normal calling conventions:
+ TFmode arguments are passed in two integer registers (as opposed to
+ indirect); TFmode return values appear in R16+R17.
+
+ FUNC is the function name to call.
+ TARGET is where the output belongs.
+ OPERANDS are the inputs.
+ NOPERANDS is the count of inputs.
+ EQUIV is the expression equivalent for the function.
+*/
+
+static void
+alpha_emit_xfloating_libcall (func, target, operands, noperands, equiv)
+ const char *func;
+ rtx target;
+ rtx operands[];
+ int noperands;
+ rtx equiv;
+{
+ rtx usage = NULL_RTX, tmp, reg;
+ int regno = 16, i;
+
+ start_sequence ();
+
+ for (i = 0; i < noperands; ++i)
+ {
+ switch (GET_MODE (operands[i]))
+ {
+ case TFmode:
+ reg = gen_rtx_REG (TFmode, regno);
+ regno += 2;
+ break;
+
+ case DFmode:
+ reg = gen_rtx_REG (DFmode, regno + 32);
+ regno += 1;
+ break;
+
+ case VOIDmode:
+ if (GET_CODE (operands[i]) != CONST_INT)
+ abort ();
+ /* FALLTHRU */
+ case DImode:
+ reg = gen_rtx_REG (DImode, regno);
+ regno += 1;
+ break;
+
+ default:
+ abort ();
+ }
+
+ emit_move_insn (reg, operands[i]);
+ usage = alloc_EXPR_LIST (0, gen_rtx_USE (VOIDmode, reg), usage);
+ }
+
+ switch (GET_MODE (target))
+ {
+ case TFmode:
+ reg = gen_rtx_REG (TFmode, 16);
+ break;
+ case DFmode:
+ reg = gen_rtx_REG (DFmode, 32);
+ break;
+ case DImode:
+ reg = gen_rtx_REG (DImode, 0);
+ break;
+ default:
+ abort ();
+ }
+
+ tmp = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, func));
+ tmp = emit_call_insn (gen_call_value (reg, tmp, const0_rtx,
+ const0_rtx, const0_rtx));
+ CALL_INSN_FUNCTION_USAGE (tmp) = usage;
+
+ tmp = get_insns ();
+ end_sequence ();
+
+ emit_libcall_block (tmp, target, reg, equiv);
+}
+
+/* Emit an X_floating library function call for arithmetic (+,-,*,/). */
+
+void
+alpha_emit_xfloating_arith (code, operands)
+ enum rtx_code code;
+ rtx operands[];
+{
+ const char *func;
+ int mode;
+
+ func = alpha_lookup_xfloating_lib_func (code);
+ mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
+
+ operands[3] = GEN_INT (mode);
+ alpha_emit_xfloating_libcall (func, operands[0], operands+1, 3,
+ gen_rtx_fmt_ee (code, TFmode, operands[1],
+ operands[2]));
+}
+
+/* Emit an X_floating library function call for a comparison. */
+
+static rtx
+alpha_emit_xfloating_compare (code, op0, op1)
+ enum rtx_code code;
+ rtx op0, op1;
+{
+ const char *func;
+ rtx out, operands[2];
+
+ func = alpha_lookup_xfloating_lib_func (code);
+
+ operands[0] = op0;
+ operands[1] = op1;
+ out = gen_reg_rtx (DImode);
+
+ /* ??? Strange equiv cause what's actually returned is -1,0,1, not a
+ proper boolean value. */
+ alpha_emit_xfloating_libcall (func, out, operands, 2,
+ gen_rtx_COMPARE (TFmode, op0, op1));
+
+ return out;
+}
+
+/* Emit an X_floating library function call for a conversion. */
+
+void
+alpha_emit_xfloating_cvt (code, operands)
+ enum rtx_code code;
+ rtx operands[];
+{
+ int noperands = 1, mode;
+ const char *func;
+
+ func = alpha_lookup_xfloating_lib_func (code);
+
+ switch (code)
+ {
+ case FIX:
+ mode = alpha_compute_xfloating_mode_arg (code, ALPHA_FPRM_CHOP);
+ operands[noperands++] = GEN_INT (mode);
+ break;
+ case FLOAT_TRUNCATE:
+ mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
+ operands[noperands++] = GEN_INT (mode);
+ break;
+ default:
+ break;
+ }
+
+ alpha_emit_xfloating_libcall (func, operands[0], operands+1, noperands,
+ gen_rtx_fmt_e (code, GET_MODE (operands[0]),
+ operands[1]));
+}
+\f
/* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
unaligned data:
emit_insn (gen_extqh (exth, memh, addr));
mode = DImode;
break;
+
default:
abort();
}
case ALPHA_FPRM_DYN:
fputc ('d', file);
break;
+ default:
+ abort ();
}
break;
emit_insn (gen_imb ());
}
\f
+/* Determine where to put an argument 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 Alpha the first 6 words of args are normally in registers
+ and the rest are pushed. */
+
+rtx
+function_arg(cum, mode, type, named)
+ CUMULATIVE_ARGS cum;
+ enum machine_mode mode;
+ tree type;
+ int named ATTRIBUTE_UNUSED;
+{
+ int basereg;
+
+ if (cum >= 6 || MUST_PASS_IN_STACK (mode, type))
+ return NULL_RTX;
+
+ if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named))
+ basereg = 16;
+ else if (TARGET_FPREGS
+ && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+ || GET_MODE_CLASS (mode) == MODE_FLOAT))
+ basereg = 32 + 16;
+ else
+ basereg = 16;
+
+ return gen_rtx_REG (mode, cum + basereg);
+}
+
tree
alpha_build_va_list ()
{
#ifndef TARGET_CAN_FAULT_IN_PROLOGUE
#define TARGET_CAN_FAULT_IN_PROLOGUE 0
#endif
+#ifndef TARGET_HAS_XFLOATING_LIBS
+#define TARGET_HAS_XFLOATING_LIBS 0
+#endif
/* Macro to define tables used to set the flags.
This is a list in braces of pairs in braces,
(optimize > 0 && write_symbols != SDB_DEBUG ? 4 : 0)
/* No data type wants to be aligned rounder than this. */
-#define BIGGEST_ALIGNMENT 64
+#define BIGGEST_ALIGNMENT 128
/* For atomic access to objects, must have at least 32-bit alignment
unless the machine has byte operations. */
#define RETURN_IN_MEMORY(TYPE) \
(TYPE_MODE (TYPE) == BLKmode \
+ || TYPE_MODE (TYPE) == TFmode \
+ || TYPE_MODE (TYPE) == TCmode \
|| (TREE_CODE (TYPE) == INTEGER_TYPE && TYPE_PRECISION (TYPE) > 64))
/* 1 if N is a possible register number for a function value
for the Alpha. */
#define ALPHA_ARG_SIZE(MODE, TYPE, NAMED) \
-((MODE) != BLKmode \
- ? (GET_MODE_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD \
- : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
+ ((MODE) == TFmode || (MODE) == TCmode ? 1 \
+ : (((MODE) == BLKmode ? int_size_in_bytes (TYPE) : GET_MODE_SIZE (MODE)) \
+ + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD)
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
and the rest are pushed. */
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
-((CUM) < 6 && ! MUST_PASS_IN_STACK (MODE, TYPE) \
- ? gen_rtx_REG ((MODE), \
- (CUM) + 16 \
- + ((TARGET_FPREGS \
- && (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \
- || GET_MODE_CLASS (MODE) == MODE_FLOAT)) \
- * 32)) \
- : 0)
+ function_arg((CUM), (MODE), (TYPE), (NAMED))
+
+/* A C expression that indicates when an argument must be passed by
+ reference. If nonzero for an argument, a copy of that argument is
+ made in memory and a pointer to the argument is passed instead of
+ the argument itself. The pointer is passed in whatever way is
+ appropriate for passing a pointer to that type. */
+
+#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
+ ((MODE) == TFmode || (MODE) == TCmode)
/* Specify the padding direction of arguments.
class, but it isn't worth doing anything more efficient in this rare
case. */
-
#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \
{ if ((CUM) < 6) \
{ \
#define CHECK_FLOAT_VALUE(MODE, D, OVERFLOW) \
((OVERFLOW) = check_float_value (MODE, &D, OVERFLOW))
+/* This is how to output an assembler line defining a `long double'
+ constant. */
+
+#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE) \
+ do { \
+ long t[4]; \
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE ((VALUE), t); \
+ fprintf (FILE, "\t.quad 0x%lx%08lx,0x%lx%08lx\n", \
+ t[1] & 0xffffffff, t[0] & 0xffffffff, \
+ t[3] & 0xffffffff, t[2] & 0xffffffff); \
+ } while (0)
+
/* This is how to output an assembler line defining a `double' constant. */
#define ASM_OUTPUT_DOUBLE(FILE,VALUE) \
- { \
- if (REAL_VALUE_ISINF (VALUE) \
- || REAL_VALUE_ISNAN (VALUE) \
- || REAL_VALUE_MINUS_ZERO (VALUE)) \
- { \
- long t[2]; \
- REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
- fprintf (FILE, "\t.quad 0x%lx%08lx\n", \
- t[1] & 0xffffffff, t[0] & 0xffffffff); \
- } \
- else \
- { \
- char str[30]; \
- REAL_VALUE_TO_DECIMAL (VALUE, "%.20e", str); \
- fprintf (FILE, "\t.%c_floating %s\n", (TARGET_FLOAT_VAX)?'g':'t', str); \
- } \
- }
+ do { \
+ long t[2]; \
+ REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t); \
+ fprintf (FILE, "\t.quad 0x%lx%08lx\n", \
+ t[1] & 0xffffffff, t[0] & 0xffffffff); \
+ } while (0)
/* This is how to output an assembler line defining a `float' constant. */
long t; \
REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t); \
fprintf (FILE, "\t.long 0x%lx\n", t & 0xffffffff); \
-} while (0)
+ } while (0)
/* This is how to output an assembler line defining an `int' constant. */
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
+(define_expand "addtf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (PLUS, operands); DONE;")
+
;; Define conversion operators between DFmode and SImode, using the cvtql
;; instruction. To allow combine et al to do useful things, we keep the
;; operation as a unit until after reload, at which point we split the
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
+(define_expand "fix_trunctfdi2"
+ [(use (match_operand:DI 0 "register_operand" ""))
+ (use (match_operand:TF 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FIX, operands); DONE;")
+
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=&f")
(float:SF (match_operand:DI 1 "reg_no_subreg_operand" "f")))]
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
+(define_expand "floatditf2"
+ [(use (match_operand:TF 0 "register_operand" ""))
+ (use (match_operand:DI 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FLOAT, operands); DONE;")
+
+(define_expand "floatunsditf2"
+ [(use (match_operand:TF 0 "register_operand" ""))
+ (use (match_operand:DI 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (UNSIGNED_FLOAT, operands); DONE;")
+
(define_expand "extendsfdf2"
[(use (match_operand:DF 0 "register_operand" ""))
(use (match_operand:SF 1 "nonimmediate_operand" ""))]
[(set_attr "type" "fcpys,fld,fst")
(set_attr "trap" "yes")])
+(define_expand "extenddftf2"
+ [(use (match_operand:TF 0 "register_operand" ""))
+ (use (match_operand:DF 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FLOAT_EXTEND, operands); DONE;")
+
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=&f")
(float_truncate:SF (match_operand:DF 1 "reg_or_fp0_operand" "fG")))]
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
+(define_expand "trunctfdf2"
+ [(use (match_operand:DF 0 "register_operand" ""))
+ (use (match_operand:TF 1 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_cvt (FLOAT_TRUNCATE, operands); DONE;")
+
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=&f")
(div:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
[(set_attr "type" "fdiv")
(set_attr "trap" "yes")])
+(define_expand "divtf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (DIV, operands); DONE;")
+
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=&f")
(mult:SF (match_operand:SF 1 "reg_or_fp0_operand" "%fG")
[(set_attr "type" "fmul")
(set_attr "trap" "yes")])
+(define_expand "multf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (MULT, operands); DONE;")
+
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=&f")
(minus:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")
[(set_attr "type" "fadd")
(set_attr "trap" "yes")])
+(define_expand "subtf3"
+ [(use (match_operand 0 "register_operand" ""))
+ (use (match_operand 1 "general_operand" ""))
+ (use (match_operand 2 "general_operand" ""))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "alpha_emit_xfloating_arith (MINUS, operands); DONE;")
+
(define_insn ""
[(set (match_operand:SF 0 "register_operand" "=&f")
(sqrt:SF (match_operand:SF 1 "reg_or_fp0_operand" "fG")))]
DONE;
}")
+(define_expand "cmptf"
+ [(set (cc0) (compare (match_operand:TF 0 "general_operand" "")
+ (match_operand:TF 1 "general_operand" "")))]
+ "TARGET_HAS_XFLOATING_LIBS"
+ "
+{
+ alpha_compare.op0 = operands[0];
+ alpha_compare.op1 = operands[1];
+ alpha_compare.fp_p = 1;
+ DONE;
+}")
+
(define_expand "cmpdi"
[(set (cc0) (compare (match_operand:DI 0 "reg_or_0_operand" "")
(match_operand:DI 1 "reg_or_8bit_operand" "")))]
#undef TARGET_AS_CAN_SUBTRACT_LABELS
#define TARGET_AS_CAN_SUBTRACT_LABELS 1
+/* The GEM libraries for X_float are present, though not used by C. */
+
+#undef TARGET_HAS_XFLOATING_LIBS
+#define TARGET_HAS_XFLOATING_LIBS 1
+
/* Names to predefine in the preprocessor for this target machine. */
#define CPP_PREDEFINES "\
--- /dev/null
+/* Definitions of target machine for GNU compiler, for DEC Alpha on Tru64 5.
+ Copyright (C) 2000 Free Software Foundation, Inc.
+
+ This file is part of GNU CC.
+
+ GNU CC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU CC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU CC; see the file COPYING. If not, write to
+ the Free Software Foundation, 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#undef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE 128
install_headers_dir=install-headers-cpio
;;
*-*-osf5*)
- tm_file="${tm_file} alpha/osf.h"
+ tm_file="${tm_file} alpha/osf.h alpha/osf5.h"
;;
esac
case $machine in
install_headers_dir=install-headers-cpio
;;
*-*-osf5*)
- tm_file="${tm_file} alpha/osf.h"
+ tm_file="${tm_file} alpha/osf.h alpha/osf5.h"
;;
esac
case $machine in
are defined as returning one or two 32 bit values, respectively,
and not values of BITS_PER_WORD bits. */
#ifdef REAL_ARITHMETIC
-/* The output is some bits, the width of the target machine's word.
- A wider-word host can surely hold them in a CONST_INT. A narrower-word
- host can't. */
+ /* The output is some bits, the width of the target machine's word.
+ A wider-word host can surely hold them in a CONST_INT. A narrower-word
+ host can't. */
if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) == 64
&& GET_MODE_CLASS (mode) == MODE_FLOAT
&& GET_MODE_BITSIZE (mode) > 64
&& GET_CODE (op) == CONST_DOUBLE)
- {
- long k[4];
- REAL_VALUE_TYPE rv;
+ {
+ long k[4];
+ REAL_VALUE_TYPE rv;
- REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
- REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
- if (BITS_PER_WORD == 32)
- {
- val = k[i];
- val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
- return GEN_INT (val);
- }
- else
- abort ();
- }
+ if (BITS_PER_WORD == 32)
+ {
+ val = k[i];
+ val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+ return GEN_INT (val);
+ }
+#if HOST_BITS_PER_WIDE_INT >= 64
+ else if (BITS_PER_WORD >= 64 && i <= 1)
+ {
+ val = k[i*2 + ! WORDS_BIG_ENDIAN];
+ val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
+ val |= (HOST_WIDE_INT) k[i*2 + WORDS_BIG_ENDIAN] & 0xffffffff;
+ return GEN_INT (val);
+ }
+#endif
+ else
+ abort ();
+ }
#else /* no REAL_ARITHMETIC */
if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
&& HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)