On Tue, Nov 5, 2024 at 8:48 AM Jeff Law <jeffreya...@gmail.com> wrote: > > > > On 11/4/24 5:42 PM, H.J. Lu wrote: > > On Tue, Nov 5, 2024 at 8:07 AM Jeff Law <jeffreya...@gmail.com> wrote: > >> > >> > >> > >> On 11/1/24 4:32 PM, H.J. Lu wrote: > >>> For targets, like x86, which define TARGET_PROMOTE_PROTOTYPES to return > >>> true, all integer arguments smaller than int are passed as int: > >>> > >>> [hjl@gnu-tgl-3 pr14907]$ cat x.c > >>> extern int baz (char c1); > >>> > >>> int > >>> foo (char c1) > >>> { > >>> return baz (c1); > >>> } > >>> [hjl@gnu-tgl-3 pr14907]$ gcc -S -O2 -m32 x.c > >>> [hjl@gnu-tgl-3 pr14907]$ cat x.s > >>> .file "x.c" > >>> .text > >>> .p2align 4 > >>> .globl foo > >>> .type foo, @function > >>> foo: > >>> .LFB0: > >>> .cfi_startproc > >>> movsbl 4(%esp), %eax > >>> movl %eax, 4(%esp) > >>> jmp baz > >>> .cfi_endproc > >>> .LFE0: > >>> .size foo, .-foo > >>> .ident "GCC: (GNU) 14.2.1 20240912 (Red Hat 14.2.1-3)" > >>> .section .note.GNU-stack,"",@progbits > >>> [hjl@gnu-tgl-3 pr14907]$ > >>> > >>> But integer promotion: > >>> > >>> movsbl 4(%esp), %eax > >>> movl %eax, 4(%esp) > >>> > >>> isn't necessary if incoming arguments and outgoing arguments are the > >>> same. Use unpromoted incoming integer arguments as outgoing arguments > >>> if incoming integer arguments are the same as outgoing arguments to > >>> avoid unnecessary integer promotion. > >> Is there a particular reason x86 can't use the same mechanisms that > > > > Other targets define TARGET_PROMOTE_PROTOTYPES to return false > > to avoid this issue. Changing x86 TARGET_PROMOTE_PROTOTYPES > > to return false will break LLVM which assumes that incoming char/short > > arguments on x86 are always extended to int. The following targets > Then my suggestion would be to cover this in REE somehow. We started > looking at that a couple years ago and set it aside. But the basic > idea was to expose the ABI guarantees to REE, then let REE do its thing. > > Jeff >
For extern int baz (char c1); int foo (char c1) { return baz (c1); } on i386, we get these (insn 7 4 8 2 (set (reg:SI 0 ax [orig:102 c1 ] [102]) (sign_extend:SI (mem/c:QI (plus:SI (reg/f:SI 7 sp) (const_int 4 [0x4])) [0 c1+0 S1 A32]))) "x.c":6:10 190 {extendqisi2} (expr_list:REG_EQUIV (mem:SI (reg/f:SI 16 argp) [0 S4 A32]) (nil))) (insn 8 7 9 2 (set (mem:SI (plus:SI (reg/f:SI 7 sp) (const_int 4 [0x4])) [0 S4 A32]) (reg:SI 0 ax [orig:102 c1 ] [102])) "x.c":6:10 95 {*movsi_internal} (nil)) (call_insn/j 9 8 10 2 (set (reg:SI 0 ax) (call (mem:QI (symbol_ref:SI ("baz") [flags 0x41] <function_decl 0x7f27347aae00 baz>) [0 baz S1 A8]) (const_int 4 [0x4]))) "x.c":6:10 1420 {*sibcall_value} (expr_list:REG_CALL_DECL (symbol_ref:SI ("baz") [flags 0x41] <function_decl 0x7f273 47aae00 baz>) (nil)) (expr_list:SI (use (mem:SI (reg/f:SI 16 argp) [0 S4 A32])) (nil))) before REE. How should REE work to elimate (insn 7 4 8 2 (set (reg:SI 0 ax [orig:102 c1 ] [102]) (sign_extend:SI (mem/c:QI (plus:SI (reg/f:SI 7 sp) (const_int 4 [0x4])) [0 c1+0 S1 A32]))) "x.c":6:10 190 {extendqisi2} (expr_list:REG_EQUIV (mem:SI (reg/f:SI 16 argp) [0 S4 A32]) (nil))) (insn 8 7 9 2 (set (mem:SI (plus:SI (reg/f:SI 7 sp) (const_int 4 [0x4])) [0 S4 A32]) (reg:SI 0 ax [orig:102 c1 ] [102])) "x.c":6:10 95 {*movsi_internal} (nil)) -- H.J.