diff options
author | Uros Bizjak <ubizjak@gmail.com> | 2023-02-17 17:00:12 +0100 |
---|---|---|
committer | Uros Bizjak <ubizjak@gmail.com> | 2023-02-17 17:00:12 +0100 |
commit | 6245441e124846d0c3551f312d2feef598fe251c (patch) | |
tree | dfe7182168c6286506401f44e0c29a32364c7ec9 /gcc | |
parent | 6ac3ebed5ffbac0d81c5a1d0cb1e345cfad202a8 (diff) | |
download | gcc-6245441e124846d0c3551f312d2feef598fe251c.zip gcc-6245441e124846d0c3551f312d2feef598fe251c.tar.gz gcc-6245441e124846d0c3551f312d2feef598fe251c.tar.bz2 |
ii386: Generate QImode binary ops with high-part input register [PR108831]
Following testcase:
--cut here--
struct S
{
unsigned char pad1;
unsigned char val;
unsigned short pad2;
};
unsigned char
test_add (unsigned char a, struct S b)
{
a += b.val;
return a;
}
--cut here--
should be compiled to something like:
addb %dh, %al
but is currently compiled to:
movzbl %dh, %edx
addl %edx, %eax
The patch implements insn patterns that model QImode binary ops with
high-part QImode input register. These ops can not be encoded with
REX prefix, so only Q registers and constant memory output operands
are allowed on x86_64 targets.
2023-02-17 Uroš Bizjak <ubizjak@gmail.com>
gcc/ChangeLog:
PR target/108831
* config/i386/predicates.md
(nonimm_x64constmem_operand): New predicate.
* config/i386/i386.md (*addqi_ext<mode>_0): New insn pattern.
(*subqi_ext<mode>_0): Ditto.
(*andqi_ext<mode>_0): Ditto.
(*<any_or:code>qi_ext<mode>_0): Ditto.
gcc/testsuite/ChangeLog:
PR target/108831
* gcc.target/i386/pr108831-1.c: New test.
* gcc.target/i386/pr108831-2.c: Ditto.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/i386/i386.md | 64 | ||||
-rw-r--r-- | gcc/config/i386/predicates.md | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr108831-1.c | 63 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr108831-2.c | 55 |
4 files changed, 189 insertions, 0 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 198f06e..55042e7 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -6641,6 +6641,22 @@ (const_string "*"))) (set_attr "mode" "<MODE>")]) +(define_insn "*addqi_ext<mode>_0" + [(set (match_operand:QI 0 "nonimm_x64constmem_operand" "=QBc,m") + (plus:QI + (subreg:QI + (zero_extract:SWI248 + (match_operand 2 "int248_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0) + (match_operand:QI 1 "nonimm_x64constmem_operand" "0,0"))) + (clobber (reg:CC FLAGS_REG))] + "" + "add{b}\t{%h2, %0|%0, %h2}" + [(set_attr "isa" "*,nox64") + (set_attr "type" "alu") + (set_attr "mode" "QI")]) + (define_expand "addqi_ext_1" [(parallel [(set (zero_extract:HI (match_operand:HI 0 "register_operand") @@ -7265,6 +7281,22 @@ [(set_attr "type" "alu") (set_attr "mode" "SI")]) +(define_insn "*subqi_ext<mode>_0" + [(set (match_operand:QI 0 "nonimm_x64constmem_operand" "=QBc,m") + (minus:QI + (match_operand:QI 1 "nonimm_x64constmem_operand" "0,0") + (subreg:QI + (zero_extract:SWI248 + (match_operand 2 "int248_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0))) + (clobber (reg:CC FLAGS_REG))] + "" + "sub{b}\t{%h2, %0|%0, %h2}" + [(set_attr "isa" "*,nox64") + (set_attr "type" "alu") + (set_attr "mode" "QI")]) + (define_insn "*subqi_ext<mode>_2" [(set (zero_extract:SWI248 (match_operand 0 "int248_register_operand" "+Q") @@ -10528,6 +10560,22 @@ [(set_attr "type" "alu") (set_attr "mode" "<MODE>")]) +(define_insn "*andqi_ext<mode>_0" + [(set (match_operand:QI 0 "nonimm_x64constmem_operand" "=QBc,m") + (and:QI + (subreg:QI + (zero_extract:SWI248 + (match_operand 2 "int248_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0) + (match_operand:QI 1 "nonimm_x64constmem_operand" "0,0"))) + (clobber (reg:CC FLAGS_REG))] + "" + "and{b}\t{%h2, %0|%0, %h2}" + [(set_attr "isa" "*,nox64") + (set_attr "type" "alu") + (set_attr "mode" "QI")]) + (define_expand "andqi_ext_1" [(parallel [(set (zero_extract:HI (match_operand:HI 0 "register_operand") @@ -11269,6 +11317,22 @@ [(set_attr "type" "alu") (set_attr "mode" "<MODE>")]) +(define_insn "*<code>qi_ext<mode>_0" + [(set (match_operand:QI 0 "nonimm_x64constmem_operand" "=QBc,m") + (any_or:QI + (subreg:QI + (zero_extract:SWI248 + (match_operand 2 "int248_register_operand" "Q,Q") + (const_int 8) + (const_int 8)) 0) + (match_operand:QI 1 "nonimm_x64constmem_operand" "0,0"))) + (clobber (reg:CC FLAGS_REG))] + "" + "<logic>{b}\t{%h2, %0|%0, %h2}" + [(set_attr "isa" "*,nox64") + (set_attr "type" "alu") + (set_attr "mode" "QI")]) + (define_insn "*<code>qi_ext<mode>_1" [(set (zero_extract:SWI248 (match_operand 0 "int248_register_operand" "+Q,Q") diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 2f079a6..7b3db0c 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -109,6 +109,13 @@ (match_test "GET_MODE (op) == HImode") (match_test "GET_MODE (op) == QImode")))) +;; Match nonimmediate operand, but exclude non-constant addresses for x86_64. +(define_predicate "nonimm_x64constmem_operand" + (ior (match_operand 0 "register_operand") + (and (match_operand 0 "memory_operand") + (ior (not (match_test "TARGET_64BIT")) + (match_test "constant_address_p (XEXP (op, 0))"))))) + ;; Match register operands, but include memory operands for TARGET_SSE_MATH. (define_predicate "register_ssemem_operand" (if_then_else diff --git a/gcc/testsuite/gcc.target/i386/pr108831-1.c b/gcc/testsuite/gcc.target/i386/pr108831-1.c new file mode 100644 index 0000000..3499b18 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr108831-1.c @@ -0,0 +1,63 @@ +/* PR target/108831 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -masm=att" } */ +/* { dg-additional-options "-mregparm=3" { target ia32 } } */ +/* { dg-final { scan-assembler-not "movzbl" } } */ +/* { dg-final { scan-assembler-not "movb" } } */ + +struct S +{ + unsigned char pad1; + unsigned char val; + unsigned short pad2; +}; + +unsigned char +test_and (unsigned char a, struct S b) +{ + a &= b.val; + + return a; +} + +/* { dg-final { scan-assembler "\[ \t\]andb" } } */ + +unsigned char +test_or (unsigned char a, struct S b) +{ + a |= b.val; + + return a; +} + +/* { dg-final { scan-assembler "\[ \t\]orb" } } */ + +unsigned char +test_xor (unsigned char a, struct S b) +{ + a ^= b.val; + + return a; +} + +/* { dg-final { scan-assembler "\[ \t\]xorb" } } */ + +unsigned char +test_add (unsigned char a, struct S b) +{ + a += b.val; + + return a; +} + +/* { dg-final { scan-assembler "\[ \t\]addb" } } */ + +unsigned char +test_sub (unsigned char a, struct S b) +{ + a -= b.val; + + return a; +} + +/* { dg-final { scan-assembler "\[ \t\]subb" } } */ diff --git a/gcc/testsuite/gcc.target/i386/pr108831-2.c b/gcc/testsuite/gcc.target/i386/pr108831-2.c new file mode 100644 index 0000000..a415391 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr108831-2.c @@ -0,0 +1,55 @@ +/* PR target/108831 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -masm=att" } */ +/* { dg-additional-options "-mregparm=3" { target ia32 } } */ +/* { dg-final { scan-assembler-not "movzbl" } } */ +/* { dg-final { scan-assembler-not "movb" } } */ + +struct S +{ + unsigned char pad1; + unsigned char val; + unsigned short pad2; +}; + +unsigned char a; + +void +test_and (struct S b) +{ + a &= b.val; +} + +/* { dg-final { scan-assembler "\[ \t\]andb" } } */ + +void +test_or (struct S b) +{ + a |= b.val; +} + +/* { dg-final { scan-assembler "\[ \t\]orb" } } */ + +void +test_xor (struct S b) +{ + a ^= b.val; +} + +/* { dg-final { scan-assembler "\[ \t\]xorb" } } */ + +void +test_add (struct S b) +{ + a += b.val; +} + +/* { dg-final { scan-assembler "\[ \t\]addb" } } */ + +void +test_sub (struct S b) +{ + a -= b.val; +} + +/* { dg-final { scan-assembler "\[ \t\]subb" } } */ |