Commit 3f622353 by Richard Henderson Committed by Richard Henderson

configure.in (ia64-*): Set float_format for i386 long double.

	* configure.in (ia64-*): Set float_format for i386 long double.

	* real.c (GET_REAL): Treat 128-bit INTEL_EXTENDED_IEEE_FORMAT
	as we would for i386 XFmode.
	(PUT_REAL): Likewise.
	(endian, ereal_atof, real_value_truncate): Likewise.
	(ereal_isneg, toe64, etens, make_nan): Likewise.
	* real.h (REAL_VALUE_TO_TARGET_LONG_DOUBLE): Likewise.

	* config/ia64/ia64-protos.h: Update.
	* config/ia64/ia64.c (general_tfmode_operand): New.
	(destination_tfmode_operand): New.
	(tfreg_or_fp01_operand): New.
	(ia64_split_timode): New.
	(spill_tfmode_operand): New.
	(ia64_expand_prologue): Use TFmode not XFmode.
	(ia64_expand_epilogue): Likewise.
	(ia64_function_arg): Likewise.
	(ia64_function_arg_advance): Likewise.
	(ia64_return_in_memory): Likewise.
	(ia64_function_value): Likewise.
	(ia64_print_operand): Likewise.
	(ia64_register_move_cost): Set GR<->FR to 5.
	(ia64_secondary_reload_class): Get GR for TImode memory op.
	* config/ia64/ia64.h (ROUND_TYPE_SIZE): Remove.
	(ROUND_TYPE_ALIGN): Remove.
	(LONG_DOUBLE_TYPE_SIZE): Set to 128.
	(INTEL_EXTENDED_IEEE_FORMAT): Define.
	(HARD_REGNO_NREGS): Use TFmode, not XFmode.
	(HARD_REGNO_MODE_OK): Likewise.  Disallow TImode in FRs.
	(MODES_TIEABLE_P): Use TFmode, not XFmode.
	(CLASS_MAX_NREGS): Likewise.
	(ASM_OUTPUT_LONG_DOUBLE): Output by 4 byte hunks.
	(PREDICATE_CODES): Update.
	* config/ia64/ia64.md (movti): New.
	(movti_internal): Use a clobber for memory alternatives.
	(reload_inti, reload_outti): New.
	(movsfcc_astep): Predicate properly.
	(movdfcc_astep): Likewise.
	(movxf): Remove.
	(movtf): New.
	(extendsftf2, extenddftf2): New.
	(trunctfsf2, trunctfdf2): New.
	(floatditf2, fix_trunctfdi2): New.
	(floatunsditf2, fixuns_trunctfdi2): New.
	(addtf3, subtf3, multf3, abstf2): New.
	(negtf2, nabstf2, mintf3, maxtf3): New.
	(maddtf3, msubtf3, nmultf3, nmaddtf3): New.
	(cmptf): New.
	(fr_spill): Use TFmode, not XFmode.
	(fr_restore): Likewise.
	* config/ia64/lib1funcs.asm (__divtf3): New.
	* config/ia64/t-ia64 (LIB1ASMFUNCS): Add it.

From-SVN: r35689
parent b6767a49
2000-08-14 Richard Henderson <rth@cygnus.com>
* configure.in (ia64-*): Set float_format for i386 long double.
* real.c (GET_REAL): Treat 128-bit INTEL_EXTENDED_IEEE_FORMAT
as we would for i386 XFmode.
(PUT_REAL): Likewise.
(endian, ereal_atof, real_value_truncate): Likewise.
(ereal_isneg, toe64, etens, make_nan): Likewise.
* real.h (REAL_VALUE_TO_TARGET_LONG_DOUBLE): Likewise.
* config/ia64/ia64-protos.h: Update.
* config/ia64/ia64.c (general_tfmode_operand): New.
(destination_tfmode_operand): New.
(tfreg_or_fp01_operand): New.
(ia64_split_timode): New.
(spill_tfmode_operand): New.
(ia64_expand_prologue): Use TFmode not XFmode.
(ia64_expand_epilogue): Likewise.
(ia64_function_arg): Likewise.
(ia64_function_arg_advance): Likewise.
(ia64_return_in_memory): Likewise.
(ia64_function_value): Likewise.
(ia64_print_operand): Likewise.
(ia64_register_move_cost): Set GR<->FR to 5.
(ia64_secondary_reload_class): Get GR for TImode memory op.
* config/ia64/ia64.h (ROUND_TYPE_SIZE): Remove.
(ROUND_TYPE_ALIGN): Remove.
(LONG_DOUBLE_TYPE_SIZE): Set to 128.
(INTEL_EXTENDED_IEEE_FORMAT): Define.
(HARD_REGNO_NREGS): Use TFmode, not XFmode.
(HARD_REGNO_MODE_OK): Likewise. Disallow TImode in FRs.
(MODES_TIEABLE_P): Use TFmode, not XFmode.
(CLASS_MAX_NREGS): Likewise.
(ASM_OUTPUT_LONG_DOUBLE): Output by 4 byte hunks.
(PREDICATE_CODES): Update.
* config/ia64/ia64.md (movti): New.
(movti_internal): Use a clobber for memory alternatives.
(reload_inti, reload_outti): New.
(movsfcc_astep): Predicate properly.
(movdfcc_astep): Likewise.
(movxf): Remove.
(movtf): New.
(extendsftf2, extenddftf2): New.
(trunctfsf2, trunctfdf2): New.
(floatditf2, fix_trunctfdi2): New.
(floatunsditf2, fixuns_trunctfdi2): New.
(addtf3, subtf3, multf3, abstf2): New.
(negtf2, nabstf2, mintf3, maxtf3): New.
(maddtf3, msubtf3, nmultf3, nmaddtf3): New.
(cmptf): New.
(fr_spill): Use TFmode, not XFmode.
(fr_restore): Likewise.
* config/ia64/lib1funcs.asm (__divtf3): New.
* config/ia64/t-ia64 (LIB1ASMFUNCS): Add it.
2000-08-14 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* cse.c (fold_rtx): Avoid empty body in an if-statement.
......
......@@ -59,9 +59,14 @@ extern int ia64_direct_return PARAMS((void));
extern int predicate_operator PARAMS((rtx, enum machine_mode));
extern int ar_lc_reg_operand PARAMS((rtx, enum machine_mode));
extern int ar_ccv_reg_operand PARAMS((rtx, enum machine_mode));
extern int general_tfmode_operand PARAMS((rtx, enum machine_mode));
extern int destination_tfmode_operand PARAMS((rtx, enum machine_mode));
extern int tfreg_or_fp01_operand PARAMS((rtx, enum machine_mode));
extern int ia64_move_ok PARAMS((rtx, rtx));
extern rtx ia64_gp_save_reg PARAMS((int));
extern rtx ia64_split_timode PARAMS((rtx[], rtx, rtx));
extern rtx spill_tfmode_operand PARAMS((rtx, int));
extern void ia64_expand_load_address PARAMS((rtx, rtx));
extern void ia64_expand_fetch_and_op PARAMS ((enum fetchop_code,
......@@ -112,6 +117,3 @@ extern void ia64_output_end_prologue PARAMS((FILE *));
extern void ia64_init_builtins PARAMS((void));
extern void ia64_override_options PARAMS((void));
extern int ia64_dbx_register_number PARAMS((int));
/* ??? Flag defined in toplev.c, for ia64.md -fssa hack. */
extern int flag_ssa;
......@@ -570,6 +570,46 @@ ar_ccv_reg_operand (op, mode)
&& GET_CODE (op) == REG
&& REGNO (op) == AR_CCV_REGNUM);
}
/* Like general_operand, but don't allow (mem (addressof)). */
int
general_tfmode_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (! general_operand (op, mode))
return 0;
if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == ADDRESSOF)
return 0;
return 1;
}
/* Similarly. */
int
destination_tfmode_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (! destination_operand (op, mode))
return 0;
if (GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) == ADDRESSOF)
return 0;
return 1;
}
/* Similarly. */
int
tfreg_or_fp01_operand (op, mode)
rtx op;
enum machine_mode mode;
{
if (GET_CODE (op) == SUBREG)
return 0;
return reg_or_fp01_operand (op, mode);
}
/* Return 1 if the operands of a move are ok. */
......@@ -681,6 +721,106 @@ ia64_gp_save_reg (setjmp_p)
return save;
}
/* Split a post-reload TImode reference into two DImode components. */
rtx
ia64_split_timode (out, in, scratch)
rtx out[2];
rtx in, scratch;
{
switch (GET_CODE (in))
{
case REG:
out[0] = gen_rtx_REG (DImode, REGNO (in));
out[1] = gen_rtx_REG (DImode, REGNO (in) + 1);
return NULL_RTX;
case MEM:
{
HOST_WIDE_INT offset;
rtx base = XEXP (in, 0);
rtx offset_rtx;
switch (GET_CODE (base))
{
case REG:
out[0] = change_address (in, DImode, NULL_RTX);
break;
case POST_MODIFY:
base = XEXP (base, 0);
out[0] = change_address (in, DImode, NULL_RTX);
break;
/* Since we're changing the mode, we need to change to POST_MODIFY
as well to preserve the size of the increment. Either that or
do the update in two steps, but we've already got this scratch
register handy so let's use it. */
case POST_INC:
base = XEXP (base, 0);
out[0] = change_address (in, DImode,
gen_rtx_POST_MODIFY (Pmode, base,plus_constant (base, 16)));
break;
case POST_DEC:
base = XEXP (base, 0);
out[0] = change_address (in, DImode,
gen_rtx_POST_MODIFY (Pmode, base,plus_constant (base, -16)));
break;
default:
abort ();
}
if (scratch == NULL_RTX)
abort ();
out[1] = change_address (in, DImode, scratch);
return gen_adddi3 (scratch, base, GEN_INT (8));
}
case CONST_INT:
case CONST_DOUBLE:
split_double (in, &out[0], &out[1]);
return NULL_RTX;
default:
abort ();
}
}
/* ??? Fixing GR->FR TFmode moves during reload is hard. You need to go
through memory plus an extra GR scratch register. Except that you can
either get the first from SECONDARY_MEMORY_NEEDED or the second from
SECONDARY_RELOAD_CLASS, but not both.
We got into problems in the first place by allowing a construct like
(subreg:TF (reg:TI)), which we got from a union containing a long double.
This solution attempts to prevent this situation from ocurring. When
we see something like the above, we spill the inner register to memory. */
rtx
spill_tfmode_operand (in, force)
rtx in;
int force;
{
if (GET_CODE (in) == SUBREG
&& GET_MODE (SUBREG_REG (in)) == TImode
&& GET_CODE (SUBREG_REG (in)) == REG)
{
rtx mem = gen_mem_addressof (SUBREG_REG (in), NULL_TREE);
return gen_rtx_MEM (TFmode, copy_to_reg (XEXP (mem, 0)));
}
else if (force && GET_CODE (in) == REG)
{
rtx mem = gen_mem_addressof (in, NULL_TREE);
return gen_rtx_MEM (TFmode, copy_to_reg (XEXP (mem, 0)));
}
else if (GET_CODE (in) == MEM
&& GET_CODE (XEXP (in, 0)) == ADDRESSOF)
{
return change_address (in, TFmode, copy_to_reg (XEXP (in, 0)));
}
else
return in;
}
/* Begin the assembly file. */
......@@ -1702,7 +1842,7 @@ ia64_expand_prologue ()
{
if (cfa_off & 15)
abort ();
reg = gen_rtx_REG (XFmode, regno);
reg = gen_rtx_REG (TFmode, regno);
do_spill (gen_fr_spill_x, reg, cfa_off, reg);
cfa_off -= 16;
}
......@@ -1867,7 +2007,7 @@ ia64_expand_epilogue ()
{
if (cfa_off & 15)
abort ();
reg = gen_rtx_REG (XFmode, regno);
reg = gen_rtx_REG (TFmode, regno);
do_restore (gen_fr_restore_x, reg, cfa_off);
cfa_off -= 16;
}
......@@ -2304,7 +2444,6 @@ ia64_function_arg (cum, mode, type, named, incoming)
gen_rtx_REG (hfa_mode, (FR_ARG_FIRST
+ fp_regs)),
GEN_INT (offset));
/* ??? Padding for XFmode type? */
offset += hfa_size;
args_byte_size += hfa_size;
fp_regs++;
......@@ -2484,7 +2623,6 @@ ia64_function_arg_advance (cum, mode, type, named)
for (; (offset < byte_size && fp_regs < MAX_ARGUMENT_SLOTS
&& args_byte_size < (MAX_ARGUMENT_SLOTS * UNITS_PER_WORD));)
{
/* ??? Padding for XFmode type? */
offset += hfa_size;
args_byte_size += hfa_size;
fp_regs++;
......@@ -2586,7 +2724,6 @@ ia64_return_in_memory (valtype)
{
int hfa_size = GET_MODE_SIZE (hfa_mode);
/* ??? Padding for XFmode type? */
if (byte_size / hfa_size > MAX_ARGUMENT_SLOTS)
return 1;
else
......@@ -2629,7 +2766,6 @@ ia64_function_value (valtype, func)
loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (hfa_mode, FR_ARG_FIRST + i),
GEN_INT (offset));
/* ??? Padding for XFmode type? */
offset += hfa_size;
}
......@@ -2782,19 +2918,10 @@ ia64_print_operand (file, x, code)
case POST_INC:
value = GET_MODE_SIZE (GET_MODE (x));
/* ??? This is for ldf.fill and stf.spill which use XFmode,
but which actually need 16 bytes increments. Perhaps we
can change them to use TFmode instead. Or don't use
POST_DEC/POST_INC for them. */
if (value == 12)
value = 16;
break;
case POST_DEC:
value = - (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (x));
if (value == -12)
value = -16;
break;
}
......@@ -2930,17 +3057,28 @@ ia64_register_move_cost (from, to)
{
int from_hard, to_hard;
int from_gr, to_gr;
int from_fr, to_fr;
from_hard = (from == BR_REGS || from == AR_M_REGS || from == AR_I_REGS);
to_hard = (to == BR_REGS || to == AR_M_REGS || to == AR_I_REGS);
from_gr = (from == GENERAL_REGS);
to_gr = (to == GENERAL_REGS);
from_fr = (from == FR_REGS);
to_fr = (to == FR_REGS);
if (from_hard && to_hard)
return 8;
else if ((from_hard && !to_gr) || (!from_gr && to_hard))
return 6;
/* ??? Moving from FR<->GR must be more expensive than 2, so that we get
secondary memory reloads for TFmode moves. Unfortunately, we don't
have the mode here, so we can't check that. */
/* Moreover, we have to make this at least as high as MEMORY_MOVE_COST
to avoid spectacularly poor register class preferencing for TFmode. */
else if (from_fr != to_fr)
return 5;
return 2;
}
......@@ -3018,6 +3156,13 @@ ia64_secondary_reload_class (class, mode, x)
return GR_REGS;
break;
case GR_REGS:
/* Since we have no offsettable memory addresses, we need a temporary
to hold the address of the second word. */
if (mode == TImode)
return GR_REGS;
break;
default:
break;
}
......
......@@ -383,23 +383,6 @@ while (0)
a field, not crossing a boundary for it. */
#define PCC_BITFIELD_TYPE_MATTERS 1
/* Define this macro as an expression for the overall size of a structure
(given by STRUCT as a tree node) when the size computed from the fields is
SIZE and the alignment is ALIGN.
The default is to round SIZE up to a multiple of ALIGN. */
/* ??? Might need this for 80-bit double-extended floats. */
/* #define ROUND_TYPE_SIZE(STRUCT, SIZE, ALIGN) */
/* Define this macro as an expression for the alignment of a structure (given
by STRUCT as a tree node) if the alignment computed in the usual way is
COMPUTED and the alignment explicitly specified was SPECIFIED.
The default is to use SPECIFIED if it is larger; otherwise, use the smaller
of COMPUTED and `BIGGEST_ALIGNMENT' */
/* ??? Might need this for 80-bit double-extended floats. */
/* #define ROUND_TYPE_ALIGN(STRUCT, COMPUTED, SPECIFIED) */
/* An integer expression for the size in bits of the largest integer machine
mode that should actually be used. */
......@@ -465,8 +448,11 @@ while (0)
/* A C expression for the size in bits of the type `long double' on the target
machine. If you don't define this, the default is two words. */
/* ??? We have an 80 bit extended double format. */
#define LONG_DOUBLE_TYPE_SIZE 64
#define LONG_DOUBLE_TYPE_SIZE 128
/* Tell real.c that this is the 80-bit Intel extended float format
packaged in a 128-bit entity. */
#define INTEL_EXTENDED_IEEE_FORMAT
/* An expression whose value is 1 or 0, according to whether the type `char'
should be signed or unsigned by default. The user can always override this
......@@ -812,7 +798,6 @@ while (0)
/* A C expression for the number of consecutive hard registers, starting at
register number REGNO, required to hold a value of mode MODE. */
/* ??? x86 80-bit FP values only require 1 register. */
/* ??? We say that CCmode values require two registers. This allows us to
easily store the normal and inverted values. We use CCImode to indicate
a single predicate register. */
......@@ -821,19 +806,20 @@ while (0)
((REGNO) == PR_REG (0) && (MODE) == DImode ? 64 \
: PR_REGNO_P (REGNO) && (MODE) == CCmode ? 2 \
: PR_REGNO_P (REGNO) && (MODE) == CCImode ? 1 \
: FR_REGNO_P (REGNO) && (MODE) == XFmode ? 1 \
: FR_REGNO_P (REGNO) && (MODE) == TFmode ? 1 \
: (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* A C expression that is nonzero if it is permissible to store a value of mode
MODE in hard register number REGNO (or in several registers starting with
that one). */
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
(FR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) != MODE_CC \
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
(FR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) != MODE_CC && (MODE) != TImode \
: PR_REGNO_P (REGNO) ? GET_MODE_CLASS (MODE) == MODE_CC \
: GR_REGNO_P (REGNO) ? (MODE) != XFmode && (MODE) != CCImode \
: GR_REGNO_P (REGNO) ? (MODE) != CCImode && (MODE) != TFmode \
: AR_REGNO_P (REGNO) ? (MODE) == DImode \
: 1)
: BR_REGNO_P (REGNO) ? (MODE) == DImode \
: 0)
/* A C expression that is nonzero if it is desirable to choose register
allocation so as to avoid move instructions between a value of mode MODE1
......@@ -846,11 +832,11 @@ while (0)
INTEGRAL_MODE_P or FLOAT_MODE_P and the other is not. Otherwise, it is
true. */
/* Don't tie integer and FP modes, as that causes us to get integer registers
allocated for FP instructions. XFmode only supported in FP registers at
the moment, so we can't tie it with any other modes. */
allocated for FP instructions. TFmode only supported in FP registers so
we can't tie it with any other modes. */
#define MODES_TIEABLE_P(MODE1, MODE2) \
((GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) \
&& (((MODE1) == XFmode) == ((MODE2) == XFmode)))
&& (((MODE1) == TFmode) == ((MODE2) == TFmode)))
/* Define this macro if the compiler should avoid copies to/from CCmode
registers. You should only define this macro if support fo copying to/from
......@@ -1044,10 +1030,16 @@ enum reg_class
registers of CLASS1 can only be copied to registers of class CLASS2 by
storing a register of CLASS1 into memory and loading that memory location
into a register of CLASS2. */
/* ??? We may need this for XFmode moves between FR and GR regs. Using
getf.sig/getf.exp almost works, but the result in the GR regs is not
properly formatted and has two extra bits. */
/* #define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, M) */
#if 0
/* ??? May need this, but since we've disallowed TFmode in GR_REGS,
I'm not quite sure how it could be invoked. The normal problems
with unions should be solved with the addressof fiddling done by
movtf and friends. */
#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
((MODE) == TFmode && (((CLASS1) == GR_REGS && (CLASS2) == FR_REGS) \
|| ((CLASS1) == FR_REGS && (CLASS2) == GR_REGS)))
#endif
/* A C expression for the maximum number of consecutive registers of
class CLASS needed to hold a value of mode MODE.
......@@ -1055,7 +1047,7 @@ enum reg_class
#define CLASS_MAX_NREGS(CLASS, MODE) \
((MODE) == CCmode && (CLASS) == PR_REGS ? 2 \
: ((CLASS) == FR_REGS && (MODE) == XFmode) ? 1 \
: ((CLASS) == FR_REGS && (MODE) == TFmode) ? 1 \
: (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* If defined, gives a class of registers that cannot be used as the
......@@ -1786,11 +1778,7 @@ do { \
on the machine mode of the memory reference it is used for or if the address
is valid for some modes but not others. */
/* ??? Strictly speaking this isn't true, because we can use any increment with
any mode. Unfortunately, the RTL implies that the increment depends on the
mode, so we need this for now. */
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
if (GET_CODE (ADDR) == POST_DEC || GET_CODE (ADDR) == POST_INC) \
goto LABEL;
......@@ -1996,20 +1984,17 @@ do { \
/* Output of Data. */
/* A C statement to output to the stdio stream STREAM an assembler instruction
to assemble a floating-point constant of `XFmode', `DFmode', `SFmode',
to assemble a floating-point constant of `TFmode', `DFmode', `SFmode',
respectively, whose value is VALUE. */
/* ??? This has not been tested. Long doubles are really 10 bytes not 12
bytes on ia64. */
/* ??? Must reverse the word order for big-endian code? */
#define ASM_OUTPUT_LONG_DOUBLE(FILE, VALUE) \
do { \
long t[3]; \
REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, t); \
fprintf (FILE, "\tdata8 0x%08lx, 0x%08lx, 0x%08lx\n", \
t[0] & 0xffffffff, t[1] & 0xffffffff, t[2] & 0xffffffff); \
fprintf (FILE, "\tdata4 0x%08lx, 0x%08lx, 0x%08lx, 0x%08lx\n", \
t[0] & 0xffffffff, t[1] & 0xffffffff, t[2] & 0xffffffff, 0); \
} while (0)
/* ??? Must reverse the word order for big-endian code? */
......@@ -2667,13 +2652,16 @@ do { \
CONSTANT_P_RTX}}, \
{ "shladd_operand", {CONST_INT}}, \
{ "fetchadd_operand", {CONST_INT}}, \
{ "reg_or_fp01_operand", {SUBREG, REG, CONST_DOUBLE, CONSTANT_P_RTX}}, \
{ "reg_or_fp01_operand", {SUBREG, REG, CONST_DOUBLE}}, \
{ "normal_comparison_operator", {EQ, NE, GT, LE, GTU, LEU}}, \
{ "adjusted_comparison_operator", {LT, GE, LTU, GEU}}, \
{ "call_multiple_values_operation", {PARALLEL}}, \
{ "predicate_operator", {NE, EQ}}, \
{ "ar_lc_reg_operand", {REG}}, \
{ "ar_ccv_reg_operand", {REG}},
{ "ar_ccv_reg_operand", {REG}}, \
{ "general_tfmode_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \
{ "destination_tfmode_operand", {SUBREG, REG, MEM}}, \
{ "tfreg_or_fp01_operand", {REG, CONST_DOUBLE}},
/* An alias for a machine mode name. This is the machine mode that elements of
a jump-table should have. */
......
#ifdef L__divtf3
// Compute a 80-bit IEEE double-extended quotient.
//
// From the Intel IA-64 Optimization Guide, choose the minimum latency
// alternative.
//
// farg0 holds the dividend. farg1 holds the divisor.
.text
.align 16
.global __divtf3
.proc __divtf3
__divtf3:
frcpa f10, p6 = farg0, farg1
;;
(p6) fnma.s1 f11 = farg1, f10, f1
;;
(p6) fma.s1 f12 = f11, f10, f10
(p6) fma.s1 f11 = f11, f11, f0
;;
(p6) fma.s1 f11 = f11, f12, f12
;;
(p6) fnma.s1 f12 = farg1, f11, f1
(p6) fma.s1 f10 = farg0, f10, f0
;;
(p6) fma.s1 f11 = f12, f11, f11
(p6) fnma.s1 f12 = farg1, f10, farg0
;;
(p6) fma.s1 f10 = f12, f11, f10
(p6) fnma.s1 f12 = farg1, f11, f1
;;
(p6) fnma.s1 f8 = farg1, f10, farg0
(p6) fma.s1 f9 = f12, f11, f11
;;
(p6) fma f10 = f8, f9, f10
;;
mov fret0 = f10
br.ret.sptk rp
;;
.endp __divtf3
#endif
#ifdef L__divdf3
// Compute a 64-bit IEEE double quotient.
//
......
......@@ -8,7 +8,7 @@ LIB1ASMSRC = ia64/lib1funcs.asm
# ??? We change the names of the DImode div/mod files so that they won't
# accidentally be overridden by libgcc2.c files. We used to use __ia64 as
# a prefix, now we use __ as the prefix.
LIB1ASMFUNCS = __divdf3 __divsf3 \
LIB1ASMFUNCS = __divtf3 __divdf3 __divsf3 \
__divdi3 __moddi3 __udivdi3 __umoddi3 \
__divsi3 __modsi3 __udivsi3 __umodsi3 __save_stack_nonlocal \
__nonlocal_goto __restore_stack_nonlocal __trampoline
......
......@@ -2020,6 +2020,7 @@ changequote([,])dnl
then
target_cpu_default="${target_cpu_default}|MASK_GNU_LD"
fi
float_format=i386
;;
ia64*-*-linux*)
tm_file=ia64/linux.h
......@@ -2028,6 +2029,7 @@ changequote([,])dnl
if test x$enable_threads = xyes; then
thread_file='posix'
fi
float_format=i386
;;
m32r-*-elf*)
extra_parts="crtinit.o crtfini.o"
......
......@@ -95,7 +95,9 @@ netlib.att.com: netlib/cephes. */
The case LONG_DOUBLE_TYPE_SIZE = 128 activates TFmode support
and may deactivate XFmode since `long double' is used to refer
to both modes.
to both modes. Defining INTEL_EXTENDED_IEEE_FORMAT at the same
time enables 80387-style 80-bit floats in a 128-bit padded
image, as seen on IA-64.
The macros FLOAT_WORDS_BIG_ENDIAN, HOST_FLOAT_WORDS_BIG_ENDIAN,
contributed by Richard Earnshaw <Richard.Earnshaw@cl.cam.ac.uk>,
......@@ -244,30 +246,31 @@ unknown arithmetic type
A REAL_VALUE_TYPE is guaranteed to occupy contiguous locations
in memory, with no holes. */
#if MAX_LONG_DOUBLE_TYPE_SIZE == 96
#if MAX_LONG_DOUBLE_TYPE_SIZE == 96 || \
(defined(INTEL_EXTENDED_IEEE_FORMAT) && MAX_LONG_DOUBLE_TYPE_SIZE == 128)
/* Number of 16 bit words in external e type format */
#define NE 6
#define MAXDECEXP 4932
#define MINDECEXP -4956
#define GET_REAL(r,e) bcopy ((char *) r, (char *) e, 2*NE)
#define PUT_REAL(e,r) \
do { \
if (2*NE < sizeof(*r)) \
bzero((char *)r, sizeof(*r)); \
bcopy ((char *) e, (char *) r, 2*NE); \
} while (0)
#else /* no XFmode */
#if MAX_LONG_DOUBLE_TYPE_SIZE == 128
#define NE 10
#define MAXDECEXP 4932
#define MINDECEXP -4977
#define GET_REAL(r,e) bcopy ((char *) r, (char *) e, 2*NE)
#define PUT_REAL(e,r) \
do { \
if (2*NE < sizeof(*r)) \
bzero((char *)r, sizeof(*r)); \
bcopy ((char *) e, (char *) r, 2*NE); \
} while (0)
# define NE 6
# define MAXDECEXP 4932
# define MINDECEXP -4956
# define GET_REAL(r,e) memcpy ((char *)(e), (char *)(r), 2*NE)
# define PUT_REAL(e,r) \
do { \
memcpy ((char *)(r), (char *)(e), 2*NE); \
if (2*NE < sizeof(*r)) \
memset ((char *)(r) + 2*NE, 0, sizeof(*r) - 2*NE); \
} while (0)
# else /* no XFmode */
# if MAX_LONG_DOUBLE_TYPE_SIZE == 128
# define NE 10
# define MAXDECEXP 4932
# define MINDECEXP -4977
# define GET_REAL(r,e) memcpy ((char *)(e), (char *)(r), 2*NE)
# define PUT_REAL(e,r) \
do { \
memcpy ((char *)(r), (char *)(e), 2*NE); \
if (2*NE < sizeof(*r)) \
memset ((char *)(r) + 2*NE, 0, sizeof(*r) - 2*NE); \
} while (0)
#else
#define NE 6
#define MAXDECEXP 4932
......@@ -497,11 +500,13 @@ endian (e, x, mode)
switch (mode)
{
case TFmode:
#ifndef INTEL_EXTENDED_IEEE_FORMAT
/* Swap halfwords in the fourth long. */
th = (unsigned long) e[6] & 0xffff;
t = (unsigned long) e[7] & 0xffff;
t |= th << 16;
x[3] = (long) t;
#endif
case XFmode:
/* Swap halfwords in the third long. */
......@@ -539,11 +544,13 @@ endian (e, x, mode)
switch (mode)
{
case TFmode:
#ifndef INTEL_EXTENDED_IEEE_FORMAT
/* Pack the fourth long. */
th = (unsigned long) e[7] & 0xffff;
t = (unsigned long) e[6] & 0xffff;
t |= th << 16;
x[3] = (long) t;
#endif
case XFmode:
/* Pack the third long.
......@@ -737,15 +744,18 @@ ereal_atof (s, t)
e53toe (tem, e);
break;
case XFmode:
asctoe64 (s, tem);
e64toe (tem, e);
break;
case TFmode:
#ifndef INTEL_EXTENDED_IEEE_FORMAT
asctoe113 (s, tem);
e113toe (tem, e);
break;
#endif
/* FALLTHRU */
case XFmode:
asctoe64 (s, tem);
e64toe (tem, e);
break;
default:
asctoe (s, e);
......@@ -1070,9 +1080,12 @@ real_value_truncate (mode, arg)
switch (mode)
{
case TFmode:
#ifndef INTEL_EXTENDED_IEEE_FORMAT
etoe113 (e, t);
e113toe (t, t);
break;
#endif
/* FALLTHRU */
case XFmode:
etoe64 (e, t);
......@@ -1486,7 +1499,7 @@ ereal_isneg (x)
/* e type constants used by high precision check routines */
#if MAX_LONG_DOUBLE_TYPE_SIZE == 128
#if MAX_LONG_DOUBLE_TYPE_SIZE == 128 && !defined(INTEL_EXTENDED_IEEE_FORMAT)
/* 0.0 */
unsigned EMUSHORT ezero[NE] =
{0x0000, 0x0000, 0x0000, 0x0000,
......@@ -3660,6 +3673,15 @@ toe64 (a, b)
/* Clear the last two bytes of 12-byte Intel format */
*(q+1) = 0;
}
#ifdef INTEL_EXTENDED_IEEE_FORMAT
if (LONG_DOUBLE_TYPE_SIZE == 128)
{
/* Clear the last 6 bytes of 16-byte Intel format. */
q[1] = 0;
q[2] = 0;
q[3] = 0;
}
#endif
}
#endif
......@@ -4560,7 +4582,7 @@ enormlz (x)
#define NTEN 12
#define MAXP 4096
#if MAX_LONG_DOUBLE_TYPE_SIZE == 128
#if MAX_LONG_DOUBLE_TYPE_SIZE == 128 && !defined(INTEL_EXTENDED_IEEE_FORMAT)
static unsigned EMUSHORT etens[NTEN + 1][NE] =
{
{0x6576, 0x4a92, 0x804a, 0x153f,
......@@ -6276,12 +6298,15 @@ make_nan (nan, sign, mode)
used like NaN's, but probably not in the same way as IEEE. */
#if !defined(DEC) && !defined(IBM) && !defined(C4X)
case TFmode:
#ifndef INTEL_EXTENDED_IEEE_FORMAT
n = 8;
if (REAL_WORDS_BIG_ENDIAN)
p = TFbignan;
else
p = TFlittlenan;
break;
#endif
/* FALLTHRU */
case XFmode:
n = 6;
......
......@@ -207,11 +207,15 @@ extern REAL_VALUE_TYPE real_value_truncate PARAMS ((enum machine_mode,
ereal_from_uint (&d, lo, hi, mode)
/* IN is a REAL_VALUE_TYPE. OUT is an array of longs. */
#if defined(INTEL_EXTENDED_IEEE_FORMAT) && MAX_LONG_DOUBLE_TYPE_SIZE == 128
#define REAL_VALUE_TO_TARGET_LONG_DOUBLE(IN, OUT) (etarldouble ((IN), (OUT)))
#else
#define REAL_VALUE_TO_TARGET_LONG_DOUBLE(IN, OUT) \
(LONG_DOUBLE_TYPE_SIZE == 64 ? etardouble ((IN), (OUT)) \
: LONG_DOUBLE_TYPE_SIZE == 96 ? etarldouble ((IN), (OUT)) \
: LONG_DOUBLE_TYPE_SIZE == 128 ? etartdouble ((IN), (OUT)) \
: abort())
#endif
#define REAL_VALUE_TO_TARGET_DOUBLE(IN, OUT) (etardouble ((IN), (OUT)))
/* IN is a REAL_VALUE_TYPE. OUT is a long. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment