https://gcc.gnu.org/g:ae80ad655d514d7c275b21f5d1ad155793ae4cc0
commit r17-1923-gae80ad655d514d7c275b21f5d1ad155793ae4cc0 Author: Roger Sayle <[email protected]> Date: Fri Jun 26 16:20:05 2026 +0100 i386: ix86_expand_sse_movcc improvements This patch implements Alexander Monakov's suggestion from PR 123238. Traditionally, the x86_64 backend implements VCOND_MASK using a three instruction sequence of pand, pandn and por (requiring three registers), however when op_true and op_false are both constant vectors, this can be done using just two instructions, pand and pxor (requiring only two registers). This requires delaying forcing const_vector operands to memory (the constant pool) as late as possible, including changing the predicates on the define_expand patterns that call ix86_expand_sse_movcc to (consistently) accept vector_or_const_vector_operand. void f(char c[]) { for (int i = 0; i < 8; i++) c[i] = c[i] ? 'a' : 'c'; } Before with -O2 (12 instructions): f: movq (%rdi), %xmm0 pxor %xmm1, %xmm1 movabsq $7016996765293437281, %rdx // {'a','a','a'...} movabsq $7161677110969590627, %rax // {'c','c','c'...} movq %rdx, %xmm2 pcmpeqb %xmm1, %xmm0 movq %rax, %xmm1 pand %xmm0, %xmm1 pandn %xmm2, %xmm0 por %xmm1, %xmm0 movq %xmm0, (%rdi) ret After with -O2 (11 instructions): f: movq (%rdi), %xmm0 pxor %xmm1, %xmm1 movabsq $144680345676153346, %rdx // {2,2,2...} movabsq $7016996765293437281, %rax // {'a','a','a'...} pcmpeqb %xmm1, %xmm0 movq %rdx, %xmm1 pand %xmm1, %xmm0 movq %rax, %xmm1 pxor %xmm1, %xmm0 movq %xmm0, (%rdi) ret 2026-06-26 Roger Sayle <[email protected]> Hongtao Liu <[email protected]> gcc/ChangeLog PR target/123238 * config/i386/i386-expand.cc: Delay calling force_reg on op_true and op_false. Generate an AND then XOR sequence if op_true and op_false are both CONST_VECTOR_P. * config/i386/mmx.md (vcond_mask_<mode>v4hi): Allow operands 1 and 2 to be vector_or_const_vector_operand. (vcond_mask_<mode>v2hi): Likewise. (vcond_mask_<mode><mmxintvecmodelower>): Likewise. (vcond_mask_<mode><mode>): Likewise. * config/i386/sse.md (vcond_mask_<mode><sseintvecmodelower>): Likewise. (vcond_mask_<mode><sseintvecmodelower>): Likewise. (vcond_mask_v1tiv1ti): Likewise. (vcond_mask_<mode><sseintvecmodelower>): Likewise. (vcond_mask_<mode><sseintvecmodelower>): Likewise. * config/i386/predicates.md (vector_or_0_or_1s_operand): Delete predicate with no remaining uses. gcc/testsuite/ChangeLog PR target/123238 * gcc.target/i386/pr123238-2.c: New test case. Diff: --- gcc/config/i386/i386-expand.cc | 30 +++++++++++++++++++----------- gcc/config/i386/mmx.md | 16 ++++++++-------- gcc/config/i386/predicates.md | 8 -------- gcc/config/i386/sse.md | 20 ++++++++++---------- gcc/testsuite/gcc.target/i386/pr123238-2.c | 10 ++++++++++ 5 files changed, 47 insertions(+), 37 deletions(-) diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index 99b6343106a1..8e7b90c9744c 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -4462,12 +4462,6 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, rtx op_false) rtx (*gen) (rtx, rtx, rtx, rtx) = NULL; machine_mode blend_mode = mode; - if (GET_MODE_SIZE (mode) < 16 - || !vector_operand (op_true, mode)) - op_true = force_reg (mode, op_true); - - op_false = force_reg (mode, op_false); - switch (mode) { case E_V2SFmode: @@ -4580,6 +4574,11 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, rtx op_false) if (gen != NULL) { + if (GET_MODE_SIZE (mode) < 16 + || !vector_operand (op_true, mode)) + op_true = force_reg (mode, op_true); + op_false = force_reg (mode, op_false); + if (blend_mode == mode) x = dest; else @@ -4595,15 +4594,24 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, rtx op_false) if (x != dest) emit_move_insn (dest, gen_lowpart (mode, x)); } + else if (CONST_VECTOR_P (op_true) && CONST_VECTOR_P (op_false)) + { + rtx tmp = simplify_const_binary_operation (XOR, mode, op_true, op_false); + tmp = expand_simple_binop (mode, AND, cmp, tmp, + NULL, 1, OPTAB_DIRECT); + tmp = expand_simple_binop (mode, XOR, tmp, op_false, + dest, 1, OPTAB_DIRECT); + if (tmp != dest) + emit_move_insn (dest, tmp); + } else { - rtx t2, t3; + rtx t2 = expand_simple_binop (mode, AND, cmp, op_true, + NULL, 1, OPTAB_DIRECT); - t2 = expand_simple_binop (mode, AND, op_true, cmp, - NULL, 1, OPTAB_DIRECT); - - t3 = gen_reg_rtx (mode); + rtx t3 = gen_reg_rtx (mode); x = gen_rtx_NOT (mode, cmp); + op_false = force_reg (mode, op_false); ix86_emit_vec_binop (AND, mode, t3, x, op_false); x = expand_simple_binop (mode, IOR, t3, t2, diff --git a/gcc/config/i386/mmx.md b/gcc/config/i386/mmx.md index d747146776b8..f61335af0b9c 100644 --- a/gcc/config/i386/mmx.md +++ b/gcc/config/i386/mmx.md @@ -2313,8 +2313,8 @@ (define_expand "vcond_mask_<mode>v4hi" [(set (match_operand:V4F_64 0 "register_operand") (vec_merge:V4F_64 - (match_operand:V4F_64 1 "register_operand") - (match_operand:V4F_64 2 "register_operand") + (match_operand:V4F_64 1 "vector_or_const_vector_operand") + (match_operand:V4F_64 2 "vector_or_const_vector_operand") (match_operand:V4HI 3 "register_operand")))] "TARGET_MMX_WITH_SSE && TARGET_SSE4_1" { @@ -2362,8 +2362,8 @@ (define_expand "vcond_mask_<mode>v2hi" [(set (match_operand:V2F_32 0 "register_operand") (vec_merge:V2F_32 - (match_operand:V2F_32 1 "register_operand") - (match_operand:V2F_32 2 "register_operand") + (match_operand:V2F_32 1 "vector_or_const_vector_operand") + (match_operand:V2F_32 2 "vector_or_const_vector_operand") (match_operand:V2HI 3 "register_operand")))] "TARGET_SSE4_1" { @@ -4313,8 +4313,8 @@ (define_expand "vcond_mask_<mode><mmxintvecmodelower>" [(set (match_operand:MMXMODE124 0 "register_operand") (vec_merge:MMXMODE124 - (match_operand:MMXMODE124 1 "register_operand") - (match_operand:MMXMODE124 2 "register_operand") + (match_operand:MMXMODE124 1 "vector_or_const_vector_operand") + (match_operand:MMXMODE124 2 "vector_or_const_vector_operand") (match_operand:<mmxintvecmode> 3 "register_operand")))] "TARGET_MMX_WITH_SSE" { @@ -4326,8 +4326,8 @@ (define_expand "vcond_mask_<mode><mode>" [(set (match_operand:VI_16_32 0 "register_operand") (vec_merge:VI_16_32 - (match_operand:VI_16_32 1 "register_operand") - (match_operand:VI_16_32 2 "register_operand") + (match_operand:VI_16_32 1 "vector_or_const_vector_operand") + (match_operand:VI_16_32 2 "vector_or_const_vector_operand") (match_operand:VI_16_32 3 "register_operand")))] "TARGET_SSE2" { diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 998a3eeac41a..6a2ced036044 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1288,14 +1288,6 @@ (match_operand 0 "vector_memory_operand") (match_code "const_vector"))) -; Return true when OP is register_operand, vector_memory_operand, -; const_vector zero or const_vector all ones. -(define_predicate "vector_or_0_or_1s_operand" - (ior (match_operand 0 "register_operand") - (match_operand 0 "vector_memory_operand") - (match_operand 0 "const0_operand") - (match_operand 0 "int_float_vector_all_ones_operand"))) - (define_predicate "bcst_mem_operand" (and (match_code "vec_duplicate") (and (match_test "TARGET_AVX512F") diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index 3425baea3b62..7a0029ecedb4 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -5530,8 +5530,8 @@ (define_expand "vcond_mask_<mode><sseintvecmodelower>" [(set (match_operand:VI_256_AVX2 0 "register_operand") (vec_merge:VI_256_AVX2 - (match_operand:VI_256_AVX2 1 "nonimm_or_0_or_1s_operand") - (match_operand:VI_256_AVX2 2 "nonimm_or_0_operand") + (match_operand:VI_256_AVX2 1 "vector_or_const_vector_operand") + (match_operand:VI_256_AVX2 2 "vector_or_const_vector_operand") (match_operand:<sseintvecmode> 3 "register_operand")))] "TARGET_AVX" { @@ -5543,8 +5543,8 @@ (define_expand "vcond_mask_<mode><sseintvecmodelower>" [(set (match_operand:VI_128 0 "register_operand") (vec_merge:VI_128 - (match_operand:VI_128 1 "vector_or_0_or_1s_operand") - (match_operand:VI_128 2 "nonimm_or_0_operand") + (match_operand:VI_128 1 "vector_or_const_vector_operand") + (match_operand:VI_128 2 "vector_or_const_vector_operand") (match_operand:<sseintvecmode> 3 "register_operand")))] "TARGET_SSE2" { @@ -5556,8 +5556,8 @@ (define_expand "vcond_mask_v1tiv1ti" [(set (match_operand:V1TI 0 "register_operand") (vec_merge:V1TI - (match_operand:V1TI 1 "vector_or_0_or_1s_operand") - (match_operand:V1TI 2 "nonimm_or_0_operand") + (match_operand:V1TI 1 "vector_or_const_vector_operand") + (match_operand:V1TI 2 "vector_or_const_vector_operand") (match_operand:V1TI 3 "register_operand")))] "TARGET_SSE2" { @@ -5569,8 +5569,8 @@ (define_expand "vcond_mask_<mode><sseintvecmodelower>" [(set (match_operand:VF_256 0 "register_operand") (vec_merge:VF_256 - (match_operand:VF_256 1 "nonimm_or_0_or_1s_operand") - (match_operand:VF_256 2 "nonimm_or_0_operand") + (match_operand:VF_256 1 "vector_or_const_vector_operand") + (match_operand:VF_256 2 "vector_or_const_vector_operand") (match_operand:<sseintvecmode> 3 "register_operand")))] "TARGET_AVX" { @@ -5582,8 +5582,8 @@ (define_expand "vcond_mask_<mode><sseintvecmodelower>" [(set (match_operand:VF_128 0 "register_operand") (vec_merge:VF_128 - (match_operand:VF_128 1 "vector_or_0_or_1s_operand") - (match_operand:VF_128 2 "nonimm_or_0_operand") + (match_operand:VF_128 1 "vector_or_const_vector_operand") + (match_operand:VF_128 2 "vector_or_const_vector_operand") (match_operand:<sseintvecmode> 3 "register_operand")))] "TARGET_SSE" { diff --git a/gcc/testsuite/gcc.target/i386/pr123238-2.c b/gcc/testsuite/gcc.target/i386/pr123238-2.c new file mode 100644 index 000000000000..6cf5b3e35c4d --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr123238-2.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +void f(char c[]) +{ + for (int i = 0; i < 8; i++) + c[i] = c[i] ? 'a' : 'c'; +} + +/* { dg-final { scan-assembler-not "pandn" } } */
