/* 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)