rtx temp;
rtx alt_rtl = NULL_RTX;
location_t loc = curr_insn_location ();
+ bool shortened_string_cst = false;
if (VOID_TYPE_P (TREE_TYPE (exp)))
{
/* If we want to use a nontemporal or a reverse order store, force the
value into a register first. */
tmp_target = nontemporal || reverse ? NULL_RTX : target;
- temp = expand_expr_real (exp, tmp_target, GET_MODE (target),
+ tree rexp = exp;
+ if (TREE_CODE (exp) == STRING_CST
+ && tmp_target == target
+ && GET_MODE (target) == BLKmode
+ && TYPE_MODE (TREE_TYPE (exp)) == BLKmode)
+ {
+ rtx size = expr_size (exp);
+ if (CONST_INT_P (size)
+ && size != const0_rtx
+ && (UINTVAL (size)
+ > ((unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (exp) + 32)))
+ {
+ /* If the STRING_CST has much larger array type than
+ TREE_STRING_LENGTH, only emit the TREE_STRING_LENGTH part of
+ it into the rodata section as the code later on will use
+ memset zero for the remainder anyway. See PR95052. */
+ tmp_target = NULL_RTX;
+ rexp = copy_node (exp);
+ tree index
+ = build_index_type (size_int (TREE_STRING_LENGTH (exp) - 1));
+ TREE_TYPE (rexp) = build_array_type (TREE_TYPE (TREE_TYPE (exp)),
+ index);
+ shortened_string_cst = true;
+ }
+ }
+ temp = expand_expr_real (rexp, tmp_target, GET_MODE (target),
(call_param_p
? EXPAND_STACK_PARM : EXPAND_NORMAL),
&alt_rtl, false);
&& TREE_CODE (exp) != ERROR_MARK
&& GET_MODE (target) != TYPE_MODE (TREE_TYPE (exp)))
{
+ gcc_assert (!shortened_string_cst);
if (GET_MODE_CLASS (GET_MODE (target))
!= GET_MODE_CLASS (TYPE_MODE (TREE_TYPE (exp)))
&& known_eq (GET_MODE_BITSIZE (GET_MODE (target)),
{
if (GET_MODE (temp) != GET_MODE (target) && GET_MODE (temp) != VOIDmode)
{
+ gcc_assert (!shortened_string_cst);
if (GET_MODE (target) == BLKmode)
{
/* Handle calls that return BLKmode values in registers. */
emit_label (label);
}
}
+ else if (shortened_string_cst)
+ gcc_unreachable ();
/* Handle calls that return values in multiple non-contiguous locations.
The Irix 6 ABI has examples of this. */
else if (GET_CODE (target) == PARALLEL)
emit_move_insn (target, temp);
}
}
+ else
+ gcc_assert (!shortened_string_cst);
return NULL_RTX;
}
--- /dev/null
+/* PR middle-end/95052 */
+/* { dg-do compile } */
+/* { dg-options "-Os -mtune=skylake" } */
+/* Verify we don't waste almost 2 megabytes of .rodata. */
+/* { dg-final { scan-assembler-not "\.zero\t1048\[0-9]\[0-9]\[0-9]" } } */
+extern void foo (char *, unsigned);
+
+int
+main ()
+{
+ char str[1024 * 1024] =
+ "fooiuhluhpiuhliuhliyfyukyfklyugkiuhpoipoipoipoipoipoipoipoipoipoipoipoipoimipoipiuhoulouihnliuhl";
+ char arr[1024 * 1024] =
+ { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 6, 2, 3,
+ 4, 5, 6, 7, 8, 9, 0, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+ foo (str, sizeof (str));
+ foo (arr, sizeof (arr));
+ return 0;
+}