diff options
author | Uros Bizjak <ubizjak@gmail.com> | 2024-06-09 12:09:13 +0200 |
---|---|---|
committer | Uros Bizjak <ubizjak@gmail.com> | 2024-06-09 12:10:28 +0200 |
commit | 8bb6b2f4ae19c3aab7d7a5e5c8f5965f89d90e01 (patch) | |
tree | b22aa103dfdd6c37bbedbd139a74aad38d5da2b5 /gcc | |
parent | ad2775b0e3d65b0b844bfd13e2f8b15240fb3b93 (diff) | |
download | gcc-8bb6b2f4ae19c3aab7d7a5e5c8f5965f89d90e01.zip gcc-8bb6b2f4ae19c3aab7d7a5e5c8f5965f89d90e01.tar.gz gcc-8bb6b2f4ae19c3aab7d7a5e5c8f5965f89d90e01.tar.bz2 |
i386: Implement .SAT_SUB for unsigned scalar integers [PR112600]
The following testcase:
unsigned
sub_sat (unsigned x, unsigned y)
{
unsigned res;
res = x - y;
res &= -(x >= y);
return res;
}
currently compiles (-O2) to:
sub_sat:
movl %edi, %edx
xorl %eax, %eax
subl %esi, %edx
cmpl %esi, %edi
setnb %al
negl %eax
andl %edx, %eax
ret
We can expand through ussub{m}3 optab to use carry flag from the subtraction
and generate code using SBB instruction implementing:
unsigned res = x - y;
res &= ~(-(x < y));
sub_sat:
subl %esi, %edi
sbbl %eax, %eax
notl %eax
andl %edi, %eax
ret
PR target/112600
gcc/ChangeLog:
* config/i386/i386.md (ussub<mode>3): New expander.
(sub<mode>_3): Ditto.
gcc/testsuite/ChangeLog:
* gcc.target/i386/pr112600-b.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/i386/i386.md | 31 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/i386/pr112600-b.c | 40 |
2 files changed, 70 insertions, 1 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bc2ef81..d69bc8d 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -8436,6 +8436,14 @@ "ix86_fixup_binary_operands_no_copy (MINUS, <MODE>mode, operands, TARGET_APX_NDD);") +(define_expand "sub<mode>_3" + [(parallel [(set (reg:CC FLAGS_REG) + (compare:CC + (match_operand:SWI 1 "nonimmediate_operand") + (match_operand:SWI 2 "<general_operand>"))) + (set (match_operand:SWI 0 "register_operand") + (minus:SWI (match_dup 1) (match_dup 2)))])]) + (define_insn "*sub<mode>_3" [(set (reg FLAGS_REG) (compare (match_operand:SWI 1 "nonimmediate_operand" "0,0,rm,r") @@ -9883,7 +9891,28 @@ emit_insn (gen_add<mode>3_cc_overflow_1 (res, operands[1], operands[2])); emit_insn (gen_x86_mov<mode>cc_0_m1_neg (msk)); dst = expand_simple_binop (<MODE>mode, IOR, res, msk, - operands[0], 1, OPTAB_DIRECT); + operands[0], 1, OPTAB_WIDEN); + + if (!rtx_equal_p (dst, operands[0])) + emit_move_insn (operands[0], dst); + DONE; +}) + +(define_expand "ussub<mode>3" + [(set (match_operand:SWI 0 "register_operand") + (us_minus:SWI (match_operand:SWI 1 "register_operand") + (match_operand:SWI 2 "<general_operand>")))] + "" +{ + rtx res = gen_reg_rtx (<MODE>mode); + rtx msk = gen_reg_rtx (<MODE>mode); + rtx dst; + + emit_insn (gen_sub<mode>_3 (res, operands[1], operands[2])); + emit_insn (gen_x86_mov<mode>cc_0_m1_neg (msk)); + msk = expand_simple_unop (<MODE>mode, NOT, msk, NULL, 1); + dst = expand_simple_binop (<MODE>mode, AND, res, msk, + operands[0], 1, OPTAB_WIDEN); if (!rtx_equal_p (dst, operands[0])) emit_move_insn (operands[0], dst); diff --git a/gcc/testsuite/gcc.target/i386/pr112600-b.c b/gcc/testsuite/gcc.target/i386/pr112600-b.c new file mode 100644 index 0000000..ea14bb9 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr112600-b.c @@ -0,0 +1,40 @@ +/* PR target/112600 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler-times "sbb" 4 } } */ + +unsigned char +sub_sat_char (unsigned char x, unsigned char y) +{ + unsigned char res; + res = x - y; + res &= -(x >= y); + return res; +} + +unsigned short +sub_sat_short (unsigned short x, unsigned short y) +{ + unsigned short res; + res = x - y; + res &= -(x >= y); + return res; +} + +unsigned int +sub_sat_int (unsigned int x, unsigned int y) +{ + unsigned int res; + res = x - y; + res &= -(x >= y); + return res; +} + +unsigned long +sub_sat_long (unsigned long x, unsigned long y) +{ + unsigned long res; + res = x - y; + res &= -(x >= y); + return res; +} |