diff options
author | Roger Sayle <roger@nextmovesoftware.com> | 2022-06-04 12:21:51 +0100 |
---|---|---|
committer | Roger Sayle <roger@nextmovesoftware.com> | 2022-06-04 12:21:51 +0100 |
commit | ed6fd2aed58f2cca99f15331bf68999c0e6df370 (patch) | |
tree | f45d2ecac85e6636ee9ec5ce1ecbe7b3fc771e5c /gcc/calls.cc | |
parent | 53718316afa45eb0d1c236fbbf2fc0959b08510f (diff) | |
download | gcc-ed6fd2aed58f2cca99f15331bf68999c0e6df370.zip gcc-ed6fd2aed58f2cca99f15331bf68999c0e6df370.tar.gz gcc-ed6fd2aed58f2cca99f15331bf68999c0e6df370.tar.bz2 |
PR middle-end/95126: Expand small const structs as immediate constants.
This patch resolves PR middle-end/95126 which is a code quality regression,
by teaching the RTL expander to emit small const structs/unions as integer
immediate constants.
The motivating example from the bugzilla PR is:
struct small{ short a,b; signed char c; };
extern int func(struct small X);
void call_func(void)
{
static struct small const s = { 1, 2, 0 };
func(s);
}
which on x86_64 is currently compiled to:
call_func:
movzwl s.0+2(%rip), %eax
movzwl s.0(%rip), %edx
movzwl s.0+4(%rip), %edi
salq $16, %rax
orq %rdx, %rax
salq $32, %rdi
orq %rax, %rdi
jmp func
but with this patch is now optimized to:
call_func:
movl $131073, %edi
jmp func
2022-06-04 Roger Sayle <roger@nextmovesoftware.com>
gcc/ChangeLog
PR middle-end/95126
* calls.cc (load_register_parameters): When loading a suitable
immediate_const_ctor_p VAR_DECL into a single word_mode register,
construct it directly in a pseudo rather than read it (by parts)
from memory.
* expr.cc (int_expr_size): Make tree argument a const_tree.
(immediate_const_ctor_p): Helper predicate. Return true for
simple constructors that may be materialized in a register.
(expand_expr_real_1) [VAR_DECL]: When expanding a constant
VAR_DECL with a suitable immediate_const_ctor_p constructor
use store_constructor to materialize it directly in a pseudo.
* expr.h (immediate_const_ctor_p): Prototype here.
* varasm.cc (initializer_constant_valid_for_bitfield_p): Change
VALUE argument from tree to const_tree.
* varasm.h (initializer_constant_valid_for_bitfield_p): Update
prototype.
gcc/testsuite/ChangeLog
PR middle-end/95126
* gcc.target/i386/pr95126-m32-1.c: New test case.
* gcc.target/i386/pr95126-m32-2.c: New test case.
* gcc.target/i386/pr95126-m32-3.c: New test case.
* gcc.target/i386/pr95126-m32-4.c: New test case.
* gcc.target/i386/pr95126-m64-1.c: New test case.
* gcc.target/i386/pr95126-m64-2.c: New test case.
* gcc.target/i386/pr95126-m64-3.c: New test case.
* gcc.target/i386/pr95126-m64-4.c: New test case.
Diffstat (limited to 'gcc/calls.cc')
-rw-r--r-- | gcc/calls.cc | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/gcc/calls.cc b/gcc/calls.cc index bbaf69c..a4336c1 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -2095,7 +2095,8 @@ load_register_parameters (struct arg_data *args, int num_actuals, poly_int64 size = 0; HOST_WIDE_INT const_size = 0; rtx_insn *before_arg = get_last_insn (); - tree type = TREE_TYPE (args[i].tree_value); + tree tree_value = args[i].tree_value; + tree type = TREE_TYPE (tree_value); if (RECORD_OR_UNION_TYPE_P (type) && TYPE_TRANSPARENT_AGGR (type)) type = TREE_TYPE (first_field (type)); /* Set non-negative if we must move a word at a time, even if @@ -2172,6 +2173,24 @@ load_register_parameters (struct arg_data *args, int num_actuals, emit_move_insn (gen_rtx_REG (word_mode, REGNO (reg) + j), args[i].aligned_regs[j]); + /* If we need a single register and the source is a constant + VAR_DECL with a simple constructor, expand that constructor + via a pseudo rather than read from (possibly misaligned) + memory. PR middle-end/95126. */ + else if (nregs == 1 + && partial == 0 + && !args[i].pass_on_stack + && VAR_P (tree_value) + && TREE_READONLY (tree_value) + && !TREE_SIDE_EFFECTS (tree_value) + && immediate_const_ctor_p (DECL_INITIAL (tree_value))) + { + rtx target = gen_reg_rtx (word_mode); + rtx x = expand_expr (DECL_INITIAL (tree_value), + target, word_mode, EXPAND_NORMAL); + reg = gen_rtx_REG (word_mode, REGNO (reg)); + emit_move_insn (reg, x); + } else if (partial == 0 || args[i].pass_on_stack) { /* SIZE and CONST_SIZE are 0 for partial arguments and |