diff --git a/gcc/expr.cc b/gcc/expr.cc index c90cde35006..8fb2dc917f7 100644 --- a/gcc/expr.cc +++ b/gcc/expr.cc @@ -11186,37 +11186,58 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, machine_mode mode1, mode2; poly_int64 bitsize, bitpos, bytepos; tree offset; - int reversep, volatilep = 0, must_force_mem; + int reversep, volatilep = 0; tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset, &mode1, &unsignedp, &reversep, &volatilep); rtx orig_op0, memloc; bool clear_mem_expr = false; + bool must_force_mem; /* If we got back the original object, something is wrong. Perhaps we are evaluating an expression too early. In any event, don't infinitely recurse. */ gcc_assert (tem != exp); - /* If tem is a VAR_DECL, we need a memory reference. */ - enum expand_modifier tem_modifier = modifier; - if (tem_modifier == EXPAND_SUM) - tem_modifier = EXPAND_NORMAL; - if (TREE_CODE (tem) == VAR_DECL) - tem_modifier = EXPAND_MEMORY; + /* Make sure bitpos is not negative, this can wreak havoc later. */ + if (maybe_lt (bitpos, 0)) + { + gcc_checking_assert (offset == NULL_TREE); + offset = size_int (bits_to_bytes_round_down (bitpos)); + bitpos = num_trailing_bits (bitpos); + } + + /* If we have either an offset, a BLKmode result, or a reference + outside the underlying object, we must force it to memory. + Such a case can occur in Ada if we have unchecked conversion + of an expression from a scalar type to an aggregate type or + for an ARRAY_RANGE_REF whose type is BLKmode, or if we were + passed a partially uninitialized object or a view-conversion + to a larger size. */ + must_force_mem = offset != NULL_TREE + || mode1 == BLKmode + || (mode == BLKmode + && !int_mode_for_size (bitsize, 1).exists ()); + + const enum expand_modifier tem_modifier + = must_force_mem + ? EXPAND_MEMORY + : modifier == EXPAND_SUM ? EXPAND_NORMAL : modifier; /* If TEM's type is a union of variable size, pass TARGET to the inner computation, since it will need a temporary and TARGET is known to have to do. This occurs in unchecked conversion in Ada. */ + const rtx tem_target + = TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE + && COMPLETE_TYPE_P (TREE_TYPE (tem)) + && TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) != INTEGER_CST + && modifier != EXPAND_STACK_PARM + ? target + : NULL_RTX; + orig_op0 = op0 - = expand_expr_real (tem, - (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE - && COMPLETE_TYPE_P (TREE_TYPE (tem)) - && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem))) - != INTEGER_CST) - && modifier != EXPAND_STACK_PARM - ? target : NULL_RTX), - VOIDmode, tem_modifier, NULL, true); + = expand_expr_real (tem, tem_target, VOIDmode, tem_modifier, NULL, + true); /* If the field has a mode, we want to access it in the field's mode, not the computed mode. @@ -11233,27 +11254,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, mode2 = CONSTANT_P (op0) ? TYPE_MODE (TREE_TYPE (tem)) : GET_MODE (op0); - /* Make sure bitpos is not negative, it can wreak havoc later. */ - if (maybe_lt (bitpos, 0)) - { - gcc_checking_assert (offset == NULL_TREE); - offset = size_int (bits_to_bytes_round_down (bitpos)); - bitpos = num_trailing_bits (bitpos); - } - - /* If we have either an offset, a BLKmode result, or a reference - outside the underlying object, we must force it to memory. - Such a case can occur in Ada if we have unchecked conversion - of an expression from a scalar type to an aggregate type or - for an ARRAY_RANGE_REF whose type is BLKmode, or if we were - passed a partially uninitialized object or a view-conversion - to a larger size. */ - must_force_mem = (offset - || mode1 == BLKmode - || (mode == BLKmode - && !int_mode_for_size (bitsize, 1).exists ()) - || maybe_gt (bitpos + bitsize, - GET_MODE_BITSIZE (mode2))); + /* See above for the rationale. */ + if (maybe_gt (bitpos + bitsize, GET_MODE_BITSIZE (mode2))) + must_force_mem = true; /* Handle CONCAT first. */ if (GET_CODE (op0) == CONCAT && !must_force_mem) @@ -11311,7 +11314,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, } else /* Otherwise force into memory. */ - must_force_mem = 1; + must_force_mem = true; } /* If this is a constant, put it in a register if it is a legitimate