aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorUros Bizjak <ubizjak@gmail.com>2023-02-17 17:00:12 +0100
committerUros Bizjak <ubizjak@gmail.com>2023-02-17 17:00:12 +0100
commit6245441e124846d0c3551f312d2feef598fe251c (patch)
treedfe7182168c6286506401f44e0c29a32364c7ec9 /gcc
parent6ac3ebed5ffbac0d81c5a1d0cb1e345cfad202a8 (diff)
downloadgcc-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.md64
-rw-r--r--gcc/config/i386/predicates.md7
-rw-r--r--gcc/testsuite/gcc.target/i386/pr108831-1.c63
-rw-r--r--gcc/testsuite/gcc.target/i386/pr108831-2.c55
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" } } */