aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorUros Bizjak <ubizjak@gmail.com>2024-07-09 17:34:25 +0200
committerUros Bizjak <ubizjak@gmail.com>2024-07-09 17:35:20 +0200
commitd17889dbffd5dcdb2df22d42586ac0363704e1f1 (patch)
treec69cee19a91852ff486d176bbbd380ee094b628e /gcc
parent2d6e6a77e840b7b93d1f18708aa08ced8b46282e (diff)
downloadgcc-d17889dbffd5dcdb2df22d42586ac0363704e1f1.zip
gcc-d17889dbffd5dcdb2df22d42586ac0363704e1f1.tar.gz
gcc-d17889dbffd5dcdb2df22d42586ac0363704e1f1.tar.bz2
i386: Implement .SAT_TRUNC for unsigned integers
The following testcase: unsigned short foo (unsigned int x) { _Bool overflow = x > (unsigned int)(unsigned short)(-1); return ((unsigned short)x | (unsigned short)-overflow); } currently compiles (-O2) to: foo: xorl %eax, %eax cmpl $65535, %edi seta %al negl %eax orl %edi, %eax ret We can expand through ustrunc{m}{n}2 optab to use carry flag from the comparison and generate code using SBB: foo: cmpl $65535, %edi sbbl %eax, %eax orl %edi, %eax ret or CMOV instruction: foo: movl $65535, %eax cmpl %eax, %edi cmovnc %edi, %eax ret gcc/ChangeLog: * config/i386/i386.md (@cmp<mode>_1): Use SWI mode iterator. (ustruncdi<mode>2): New expander. (ustruncsi<mode>2): Ditto. (ustrunchiqi2): Ditto. gcc/testsuite/ChangeLog: * gcc.target/i386/sattrunc-1.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/i386/i386.md112
-rw-r--r--gcc/testsuite/gcc.target/i386/sattrunc-1.c24
2 files changed, 134 insertions, 2 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 214cb2e..e2f3069 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -1533,8 +1533,8 @@
(define_expand "@cmp<mode>_1"
[(set (reg:CC FLAGS_REG)
- (compare:CC (match_operand:SWI48 0 "nonimmediate_operand")
- (match_operand:SWI48 1 "<general_operand>")))])
+ (compare:CC (match_operand:SWI 0 "nonimmediate_operand")
+ (match_operand:SWI 1 "<general_operand>")))])
(define_mode_iterator SWI1248_AVX512BWDQ_64
[(QI "TARGET_AVX512DQ") HI
@@ -9981,6 +9981,114 @@
DONE;
})
+(define_expand "ustruncdi<mode>2"
+ [(set (match_operand:SWI124 0 "register_operand")
+ (us_truncate:DI (match_operand:DI 1 "nonimmediate_operand")))]
+ "TARGET_64BIT"
+{
+ rtx op1 = force_reg (DImode, operands[1]);
+ rtx sat = force_reg (DImode, GEN_INT (GET_MODE_MASK (<MODE>mode)));
+ rtx dst;
+
+ emit_insn (gen_cmpdi_1 (op1, sat));
+
+ if (TARGET_CMOVE)
+ {
+ rtx cmp = gen_rtx_GEU (VOIDmode, gen_rtx_REG (CCCmode, FLAGS_REG),
+ const0_rtx);
+
+ dst = force_reg (<MODE>mode, operands[0]);
+ emit_insn (gen_movsicc (gen_lowpart (SImode, dst), cmp,
+ gen_lowpart (SImode, op1),
+ gen_lowpart (SImode, sat)));
+ }
+ else
+ {
+ rtx msk = gen_reg_rtx (<MODE>mode);
+
+ emit_insn (gen_x86_mov<mode>cc_0_m1_neg (msk));
+ dst = expand_simple_binop (<MODE>mode, IOR,
+ gen_lowpart (<MODE>mode, op1), msk,
+ operands[0], 1, OPTAB_WIDEN);
+ }
+
+ if (!rtx_equal_p (dst, operands[0]))
+ emit_move_insn (operands[0], dst);
+ DONE;
+})
+
+(define_expand "ustruncsi<mode>2"
+ [(set (match_operand:SWI12 0 "register_operand")
+ (us_truncate:SI (match_operand:SI 1 "nonimmediate_operand")))]
+ ""
+{
+ rtx op1 = force_reg (SImode, operands[1]);
+ rtx sat = force_reg (SImode, GEN_INT (GET_MODE_MASK (<MODE>mode)));
+ rtx dst;
+
+ emit_insn (gen_cmpsi_1 (op1, sat));
+
+ if (TARGET_CMOVE)
+ {
+ rtx cmp = gen_rtx_GEU (VOIDmode, gen_rtx_REG (CCCmode, FLAGS_REG),
+ const0_rtx);
+
+ dst = force_reg (<MODE>mode, operands[0]);
+ emit_insn (gen_movsicc (gen_lowpart (SImode, dst), cmp,
+ gen_lowpart (SImode, op1),
+ gen_lowpart (SImode, sat)));
+ }
+ else
+ {
+ rtx msk = gen_reg_rtx (<MODE>mode);
+
+ emit_insn (gen_x86_mov<mode>cc_0_m1_neg (msk));
+ dst = expand_simple_binop (<MODE>mode, IOR,
+ gen_lowpart (<MODE>mode, op1), msk,
+ operands[0], 1, OPTAB_WIDEN);
+ }
+
+ if (!rtx_equal_p (dst, operands[0]))
+ emit_move_insn (operands[0], dst);
+ DONE;
+})
+
+(define_expand "ustrunchiqi2"
+ [(set (match_operand:QI 0 "register_operand")
+ (us_truncate:HI (match_operand:HI 1 "nonimmediate_operand")))]
+ ""
+{
+ rtx op1 = force_reg (HImode, operands[1]);
+ rtx sat = force_reg (HImode, GEN_INT (GET_MODE_MASK (QImode)));
+ rtx dst;
+
+ emit_insn (gen_cmphi_1 (op1, sat));
+
+ if (TARGET_CMOVE)
+ {
+ rtx cmp = gen_rtx_GEU (VOIDmode, gen_rtx_REG (CCCmode, FLAGS_REG),
+ const0_rtx);
+
+ dst = force_reg (QImode, operands[0]);
+ emit_insn (gen_movsicc (gen_lowpart (SImode, dst), cmp,
+ gen_lowpart (SImode, op1),
+ gen_lowpart (SImode, sat)));
+ }
+ else
+ {
+ rtx msk = gen_reg_rtx (QImode);
+
+ emit_insn (gen_x86_movqicc_0_m1_neg (msk));
+ dst = expand_simple_binop (QImode, IOR,
+ gen_lowpart (QImode, op1), msk,
+ operands[0], 1, OPTAB_WIDEN);
+ }
+
+ if (!rtx_equal_p (dst, operands[0]))
+ emit_move_insn (operands[0], dst);
+ DONE;
+})
+
;; The patterns that match these are at the end of this file.
(define_expand "<insn>xf3"
diff --git a/gcc/testsuite/gcc.target/i386/sattrunc-1.c b/gcc/testsuite/gcc.target/i386/sattrunc-1.c
new file mode 100644
index 0000000..b1116a8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sattrunc-1.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "sbb|cmov" 6 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "sbb|cmov" 3 { target ia32 } } } */
+
+#include <stdint.h>
+
+#define DEF_SAT_U_TRUNC(WT, NT) \
+NT sat_u_truc_##WT##_to_##NT (WT x) \
+{ \
+ _Bool overflow = x > (WT)(NT)(-1); \
+ return (NT)x | (NT)-overflow; \
+}
+
+#ifdef __x86_64__
+DEF_SAT_U_TRUNC(uint64_t, uint32_t)
+DEF_SAT_U_TRUNC(uint64_t, uint16_t)
+DEF_SAT_U_TRUNC(uint64_t, uint8_t)
+#endif
+
+DEF_SAT_U_TRUNC(uint32_t, uint16_t)
+DEF_SAT_U_TRUNC(uint32_t, uint8_t)
+
+DEF_SAT_U_TRUNC(uint16_t, uint8_t)