+2002-02-08 Richard Henderson <rth@redhat.com>
+
+ * expr.c (expand_expr): Mind EXPAND_INITIALIZER for truncation also.
+ * final.c (output_addr_const): Accept and discard SUBREG.
+ * varasm.c (decode_addr_const): Don't abort on unknown expressions --
+ mark them unknown instead.
+ (simplify_subtraction): Handle RTX_UNKNOWN.
+ (initializer_constant_valid_p): Strip NOP_EXPRs that narrow the mode.
+
2002-02-08 David Edelsohn <edelsohn@gnu.org>
* doc/invoke.texi (RS/6000 and PowerPC Options): Fix typo.
return op0;
}
- op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, 0);
+ op0 = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, mode, modifier);
if (GET_MODE (op0) == mode)
return op0;
/* If OP0 is a constant, just convert it into the proper mode. */
if (CONSTANT_P (op0))
- return
- convert_modes (mode, TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0))),
- op0, TREE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))));
+ {
+ tree inner_type = TREE_TYPE (TREE_OPERAND (exp, 0));
+ enum machine_mode inner_mode = TYPE_MODE (inner_type);
+
+ if (modifier == EXPAND_INITIALIZER)
+ return simplify_gen_subreg (mode, op0, inner_mode,
+ subreg_lowpart_offset (mode,
+ inner_mode));
+ else
+ return convert_modes (mode, inner_mode, op0,
+ TREE_UNSIGNED (inner_type));
+ }
if (modifier == EXPAND_INITIALIZER)
return gen_rtx_fmt_e (unsignedp ? ZERO_EXTEND : SIGN_EXTEND, mode, op0);
value->offset = offset;
}
\f
-enum kind { RTX_DOUBLE, RTX_INT, RTX_UNSPEC };
+enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_INT, RTX_UNSPEC };
struct rtx_const
{
ENUM_BITFIELD(kind) kind : 16;
break;
default:
- abort ();
+ value->kind = RTX_UNKNOWN;
+ break;
}
if (value->kind == RTX_INT && value->un.addr.base != 0
}
}
- if (value->kind != RTX_DOUBLE && value->un.addr.base != 0)
+ if (value->kind > RTX_DOUBLE && value->un.addr.base != 0)
switch (GET_CODE (value->un.addr.base))
{
case SYMBOL_REF:
decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
- if (val0.kind != RTX_DOUBLE && val0.kind == val1.kind
+ if (val0.kind > RTX_DOUBLE
+ && val0.kind == val1.kind
&& val0.un.addr.base == val1.un.addr.base)
return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
+
return x;
}
tree op0, op1;
op0 = TREE_OPERAND (value, 0);
op1 = TREE_OPERAND (value, 1);
- STRIP_NOPS (op0);
- STRIP_NOPS (op1);
+
+ /* Like STRIP_NOPS except allow the operand mode to widen.
+ This works around a feature of fold that simplfies
+ (int)(p1 - p2) to ((int)p1 - (int)p2) under the theory
+ that the narrower operation is cheaper. */
+
+ while (TREE_CODE (op0) == NOP_EXPR
+ || TREE_CODE (op0) == CONVERT_EXPR
+ || TREE_CODE (op0) == NON_LVALUE_EXPR)
+ {
+ tree inner = TREE_OPERAND (op0, 0);
+ if (inner == error_mark_node
+ || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+ || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op0)))
+ > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+ break;
+ op0 = inner;
+ }
+
+ while (TREE_CODE (op1) == NOP_EXPR
+ || TREE_CODE (op1) == CONVERT_EXPR
+ || TREE_CODE (op1) == NON_LVALUE_EXPR)
+ {
+ tree inner = TREE_OPERAND (op1, 0);
+ if (inner == error_mark_node
+ || ! INTEGRAL_MODE_P (TYPE_MODE (TREE_TYPE (inner)))
+ || (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (op1)))
+ > GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (inner)))))
+ break;
+ op1 = inner;
+ }
if (TREE_CODE (op0) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (op0, 0)) == LABEL_DECL