@@ -11793,6 +11793,10 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
|| mode_dependent_address_p (XEXP (x, 0), MEM_ADDR_SPACE (x)))
goto fail;
+ if (GET_MODE_ALIGNMENT (omode) > GET_MODE_ALIGNMENT (imode)
+ && GET_MODE_ALIGNMENT (omode) > MEM_ALIGN (x))
+ goto fail;
+
/* If we want to refer to something bigger than the original memref,
generate a paradoxical subreg instead. That will force a reload
of the original memref X. */
@@ -11362,7 +11362,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
{
if (!REG_P (op0) && !MEM_P (op0))
op0 = force_reg (GET_MODE (op0), op0);
- op0 = gen_lowpart (mode, op0);
+ rtx tmp = gen_lowpart (mode, op0);
+ if (!MEM_P (tmp))
+ op0 = tmp;
}
}
/* If both types are integral, convert from one mode to the other. */
@@ -11383,6 +11385,8 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
force_const_mem for constants because we don't allow pool
constants to change mode. */
tree inner_type = TREE_TYPE (treeop0);
+ /* ??? Should probably modify the INNER_TYPE to bigger alignemnt if
+ TYPE requires it. */
gcc_assert (!TREE_ADDRESSABLE (exp));
@@ -11430,6 +11434,14 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode,
}
else if (STRICT_ALIGNMENT)
{
+ machine_mode inner_mode = TYPE_MODE (TREE_TYPE (treeop0));
+ if (GET_MODE (op0) == inner_mode
+ && targetm.can_change_mode_class
+ (inner_mode, mode, GENERAL_REGS))
+ {
+ op0 = force_reg (inner_mode, op0);
+ return gen_lowpart (mode, op0);
+ }
poly_uint64 mode_size = GET_MODE_SIZE (mode);
poly_uint64 temp_size = mode_size;
if (GET_MODE (op0) != BLKmode)
@@ -7206,6 +7206,9 @@ simplify_context::simplify_subreg (machine_mode outermode, rtx op,
if (MEM_P (op)
&& ! mode_dependent_address_p (XEXP (op, 0), MEM_ADDR_SPACE (op))
+ /* Don't imply a larger alignment than is available. */
+ && (GET_MODE_ALIGNMENT (outermode) <= GET_MODE_ALIGNMENT (innermode)
+ || GET_MODE_ALIGNMENT (outermode) <= MEM_ALIGN (op))
/* Allow splitting of volatile memory references in case we don't
have instruction to move the whole thing. */
&& (! MEM_VOLATILE_P (op)