diff options
Diffstat (limited to 'gcc/emit-rtl.c')
-rw-r--r-- | gcc/emit-rtl.c | 65 |
1 files changed, 60 insertions, 5 deletions
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index 2aa51aca4da..36b030ae7b6 100644 --- a/gcc/emit-rtl.c +++ b/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) |