diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 198f06e0769..55042e7ae15 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -6641,6 +6641,22 @@ (define_insn "*add_5" (const_string "*"))) (set_attr "mode" "")]) +(define_insn "*addqi_ext_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 @@ (define_insn "*subsi_2_zext" [(set_attr "type" "alu") (set_attr "mode" "SI")]) +(define_insn "*subqi_ext_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_2" [(set (zero_extract:SWI248 (match_operand 0 "int248_register_operand" "+Q") @@ -10528,6 +10560,22 @@ (define_insn "*and_2" [(set_attr "type" "alu") (set_attr "mode" "")]) +(define_insn "*andqi_ext_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 @@ (define_insn "*_3" [(set_attr "type" "alu") (set_attr "mode" "")]) +(define_insn "*qi_ext_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))] + "" + "{b}\t{%h2, %0|%0, %h2}" + [(set_attr "isa" "*,nox64") + (set_attr "type" "alu") + (set_attr "mode" "QI")]) + (define_insn "*qi_ext_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 2f079a6fad8..7b3db0cc851 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -109,6 +109,13 @@ (define_special_predicate "int_nonimmediate_operand" (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 00000000000..3499b187cbe --- /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 00000000000..a415391f69d --- /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" } } */