summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Espie <espie@cvs.openbsd.org>2000-09-25 00:33:17 +0000
committerMarc Espie <espie@cvs.openbsd.org>2000-09-25 00:33:17 +0000
commitca0303bd93ded42cd3c56ff95dd955ade41e415f (patch)
tree53555906d21e7433708b18165e2c0029a0751e03
parent8a7531e06b2c9ad239d5417d7937618823789374 (diff)
Patch from Alexander N. Kabaev <ak03@gte.com>
Fixes GCC GNATS PR 258 and 413.
-rw-r--r--gnu/egcs/gcc/emit-rtl.c73
-rw-r--r--gnu/egcs/gcc/integrate.c27
-rw-r--r--gnu/egcs/gcc/rtl.def2
-rw-r--r--gnu/egcs/gcc/rtl.h5
4 files changed, 96 insertions, 11 deletions
diff --git a/gnu/egcs/gcc/emit-rtl.c b/gnu/egcs/gcc/emit-rtl.c
index 2aa51aca4da..ddbf026e2c2 100644
--- a/gnu/egcs/gcc/emit-rtl.c
+++ b/gnu/egcs/gcc/emit-rtl.c
@@ -630,9 +630,15 @@ mark_reg_pointer (reg, align)
rtx reg;
int align;
{
- REGNO_POINTER_FLAG (REGNO (reg)) = 1;
+ if (! REGNO_POINTER_FLAG (REGNO (reg)))
+ {
+ REGNO_POINTER_FLAG (REGNO (reg)) = 1;
- if (align)
+ if (align)
+ REGNO_POINTER_ALIGN (REGNO (reg)) = align;
+ }
+ else if (align && align < REGNO_POINTER_ALIGN (REGNO (reg)))
+ /* We can no-longer be sure just how aligned this pointer is */
REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}
@@ -896,6 +902,22 @@ gen_lowpart_common (mode, x)
r = REAL_VALUE_FROM_TARGET_SINGLE (i);
return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
}
+ else if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
+ && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
+ || flag_pretend_float)
+ && GET_MODE_CLASS (mode) == MODE_FLOAT
+ && GET_MODE_SIZE (mode) == UNITS_PER_WORD
+ && GET_CODE (x) == CONST_INT
+ && (sizeof (double) * HOST_BITS_PER_CHAR
+ == HOST_BITS_PER_WIDE_INT))
+ {
+ REAL_VALUE_TYPE r;
+ HOST_WIDE_INT i;
+
+ i = INTVAL (x);
+ r = REAL_VALUE_FROM_TARGET_DOUBLE (&i);
+ return CONST_DOUBLE_FROM_REAL_VALUE (r, mode);
+ }
#endif
/* Similarly, if this is converting a floating-point value into a
@@ -950,6 +972,11 @@ gen_realpart (mode, x)
{
if (GET_CODE (x) == CONCAT && GET_MODE (XEXP (x, 0)) == mode)
return XEXP (x, 0);
+ else if (WORDS_BIG_ENDIAN
+ && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
+ && REG_P (x)
+ && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ fatal ("Unable to access real part of complex value in a hard register on this target");
else if (WORDS_BIG_ENDIAN)
return gen_highpart (mode, x);
else
@@ -968,6 +995,11 @@ gen_imagpart (mode, x)
return XEXP (x, 1);
else if (WORDS_BIG_ENDIAN)
return gen_lowpart (mode, x);
+ else if (!WORDS_BIG_ENDIAN
+ && GET_MODE_BITSIZE (mode) < BITS_PER_WORD
+ && REG_P (x)
+ && REGNO (x) < FIRST_PSEUDO_REGISTER)
+ fatal ("Unable to access imaginary part of complex value in a hard register on this target");
else
return gen_highpart (mode, x);
}
@@ -1196,10 +1228,33 @@ operand_subword (op, i, validate_address, mode)
/* If OP is a REG or SUBREG, we can handle it very simply. */
if (GET_CODE (op) == REG)
{
- /* If the register is not valid for MODE, return 0. If we don't
- do this, there is no way to fix up the resulting REG later. */
+ /* ??? There is a potential problem with this code. It does not
+ properly handle extractions of a subword from a hard register
+ that is larger than word_mode. Presumably the check for
+ HARD_REGNO_MODE_OK catches these most of these cases. */
+
+ /* If OP is a hard register, but OP + I is not a hard register,
+ then extracting a subword is impossible.
+
+ For example, consider if OP is the last hard register and it is
+ larger than word_mode. If we wanted word N (for N > 0) because a
+ part of that hard register was known to contain a useful value,
+ then OP + I would refer to a pseudo, not the hard register we
+ actually wanted. */
+ if (REGNO (op) < FIRST_PSEUDO_REGISTER
+ && REGNO (op) + i >= FIRST_PSEUDO_REGISTER)
+ return 0;
+
+ /* If the register is not valid for MODE, return 0. Note we
+ have to check both OP and OP + I since they may refer to
+ different parts of the register file.
+
+ Consider if OP refers to the last 96bit FP register and we want
+ subword 3 because that subword is known to contain a value we
+ needed. */
if (REGNO (op) < FIRST_PSEUDO_REGISTER
- && ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode))
+ && (! HARD_REGNO_MODE_OK (REGNO (op), word_mode)
+ || ! HARD_REGNO_MODE_OK (REGNO (op) + i, word_mode)))
return 0;
else if (REGNO (op) >= FIRST_PSEUDO_REGISTER
|| (REG_FUNCTION_VALUE_P (op)
@@ -1596,7 +1651,8 @@ gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,
pops_args, stack_slots, forced_labels, function_flags,
outgoing_args_size, original_arg_vector,
original_decl_initial, regno_rtx, regno_flag,
- regno_align, parm_reg_stack_loc)
+ regno_align, parm_reg_stack_loc,
+ nonlocal_goto_handler_labels)
rtx first_insn, first_parm_insn;
int first_labelno, last_labelno, max_parm_regnum, max_regnum, args_size;
int pops_args;
@@ -1610,6 +1666,7 @@ gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,
char *regno_flag;
char *regno_align;
rtvec parm_reg_stack_loc;
+ rtx nonlocal_goto_handler_labels;
{
rtx header = gen_rtx_INLINE_HEADER (VOIDmode,
cur_insn_uid++, NULL_RTX,
@@ -1621,7 +1678,9 @@ gen_inline_header_rtx (first_insn, first_parm_insn, first_labelno,
original_arg_vector,
original_decl_initial,
regno_rtx, regno_flag, regno_align,
- parm_reg_stack_loc);
+ parm_reg_stack_loc,
+ nonlocal_goto_handler_labels,
+ nonlocal_goto_handler_labels);
return header;
}
diff --git a/gnu/egcs/gcc/integrate.c b/gnu/egcs/gcc/integrate.c
index 33a96c40f91..4165611e480 100644
--- a/gnu/egcs/gcc/integrate.c
+++ b/gnu/egcs/gcc/integrate.c
@@ -151,6 +151,10 @@ function_cannot_inline_p (fndecl)
if (current_function_contains_functions)
return N_("function with nested functions cannot be inline");
+ if (forced_labels)
+ return
+ N_("function with label addresses used in initializers cannot inline");
+
if (current_function_cannot_inline)
return current_function_cannot_inline;
@@ -425,7 +429,8 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
arg_vector, (rtx) DECL_INITIAL (fndecl),
(rtvec) regno_reg_rtx, regno_pointer_flag,
regno_pointer_align,
- (rtvec) parm_reg_stack_loc);
+ (rtvec) parm_reg_stack_loc,
+ nonlocal_goto_handler_labels);
}
/* Subroutine for `save_for_inline{copying,nocopy}'. Finishes up the
@@ -746,6 +751,15 @@ save_for_inline_copying (fndecl)
REG_NOTES (insn_map[INSN_UID (insn)])
= copy_for_inline (REG_NOTES (insn));
+ /* Now adjust nonlocal_goto_handler_labels list */
+ copy = NULL_RTX;
+ for (insn = nonlocal_goto_handler_labels; insn ; insn = XEXP (insn, 1))
+ if (label_map[CODE_LABEL_NUMBER (XEXP (insn,0))] != NULL_RTX)
+ copy = gen_rtx_EXPR_LIST (VOIDmode,
+ label_map[CODE_LABEL_NUMBER (XEXP (insn,0))],
+ copy);
+ NONLOCAL_GOTO_LABELS_TRAN(head) = copy;
+
NEXT_INSN (last_insn) = NULL;
finish_inline (fndecl, head);
@@ -2130,6 +2144,14 @@ expand_inline_function (fndecl, parms, target, ignore, type,
REG_NOTES (map->insn_map[INSN_UID (insn)]) = tem;
}
+ /* Now copy nonlocal_goto_handler_list from the function being
+ inlined into the current list. */
+ for (insn = NONLOCAL_GOTO_LABELS_TRAN(header); insn ; insn = XEXP (insn, 1))
+ if ( map->label_map[CODE_LABEL_NUMBER (XEXP (insn,0))] != NULL_RTX)
+ nonlocal_goto_handler_labels = gen_rtx_EXPR_LIST (VOIDmode,
+ map->label_map[CODE_LABEL_NUMBER (XEXP (insn,0))],
+ nonlocal_goto_handler_labels);
+
if (local_return_label)
emit_label (local_return_label);
@@ -3402,9 +3424,10 @@ output_inline_function (fndecl)
regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (head);
max_parm_reg = MAX_PARMREG (head);
parm_reg_stack_loc = (rtx *) PARMREG_STACK_LOC (head);
-
+
stack_slot_list = STACK_SLOT_LIST (head);
forced_labels = FORCED_LABELS (head);
+ nonlocal_goto_handler_labels = NONLOCAL_GOTO_LABELS (head);
if (FUNCTION_FLAGS (head) & FUNCTION_FLAGS_HAS_COMPUTED_JUMP)
current_function_has_computed_jump = 1;
diff --git a/gnu/egcs/gcc/rtl.def b/gnu/egcs/gcc/rtl.def
index 7b8c84571f0..0d9e08abd8e 100644
--- a/gnu/egcs/gcc/rtl.def
+++ b/gnu/egcs/gcc/rtl.def
@@ -396,7 +396,7 @@ DEF_RTL_EXPR(NOTE, "note", "iuusn", 'x')
it contains helps to build the mapping function between the rtx's of
the function to be inlined and the current function being expanded. */
-DEF_RTL_EXPR(INLINE_HEADER, "inline_header", "iuuuiiiiiieeiiEeEssE", 'x')
+DEF_RTL_EXPR(INLINE_HEADER, "inline_header", "iuuuiiiiiieeiiEeEssEee", 'x')
/* ----------------------------------------------------------------------
Top level constituents of INSN, JUMP_INSN and CALL_INSN.
diff --git a/gnu/egcs/gcc/rtl.h b/gnu/egcs/gcc/rtl.h
index 8eba5eab5d9..c18ba1dc523 100644
--- a/gnu/egcs/gcc/rtl.h
+++ b/gnu/egcs/gcc/rtl.h
@@ -704,6 +704,8 @@ extern char *note_insn_name[];
#define INLINE_REGNO_POINTER_FLAG(RTX) ((RTX)->fld[17].rtstr)
#define INLINE_REGNO_POINTER_ALIGN(RTX) ((RTX)->fld[18].rtstr)
#define PARMREG_STACK_LOC(RTX) ((RTX)->fld[19].rtvec)
+#define NONLOCAL_GOTO_LABELS(RTX) ((RTX)->fld[20].rtx)
+#define NONLOCAL_GOTO_LABELS_TRAN(RTX) ((RTX)->fld[21].rtx)
/* In FUNCTION_FLAGS we save some variables computed when emitting the code
for the function and which must be `or'ed into the current flag values when
@@ -936,7 +938,8 @@ extern rtx gen_label_rtx PROTO((void));
extern rtx gen_inline_header_rtx PROTO((rtx, rtx, int, int, int, int,
int, int, rtx, rtx, int, int,
rtvec, rtx,
- rtvec, char *, char *, rtvec));
+ rtvec, char *, char *, rtvec,
+ rtx));
extern rtx gen_lowpart_common PROTO((enum machine_mode, rtx));
extern rtx gen_lowpart PROTO((enum machine_mode, rtx));
extern rtx gen_lowpart_if_possible PROTO((enum machine_mode, rtx));