[llvm] [X86] Fix commuteSelect miscompile with double-used condition value (PR #219436)

Timur Golubovich via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 28 07:54:44 PDT 2026


================
@@ -52,3 +52,70 @@ exit:
   store <16 x float> %res_max, ptr %pMax, align 64
   ret void
 }
+
+; Verify that commuteSelect does not miscompile when the inverted setcc already
+; exists (CSE). Both icmp eq and icmp ne are present so getSetCCInverse must
+; not create an infinite loop or corrupt operands.
+
+define <8 x i32> @commute_select_existing_inverse_cmp(<8 x i32> %src) {
+; CHECK-LABEL: commute_select_existing_inverse_cmp:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    subq $56, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 64
+; CHECK-NEXT:    vmovdqa {{.*#+}} ymm1 = [0,1,2,3,4,5,6,7]
+; CHECK-NEXT:    vmovdqu %ymm0, {{[-0-9]+}}(%r{{[sb]}}p) # 32-byte Spill
+; CHECK-NEXT:    vpcmpneqd %ymm1, %ymm0, %k1
+; CHECK-NEXT:    kmovw %k1, {{[-0-9]+}}(%r{{[sb]}}p) # 2-byte Spill
+; CHECK-NEXT:    vpcmpeqd %ymm1, %ymm0, %ymm2
+; CHECK-NEXT:    vpcmpeqd %ymm1, %ymm1, %ymm1
+; CHECK-NEXT:    vpsubd %ymm1, %ymm2, %ymm1 {%k1} {z}
+; CHECK-NEXT:    xorl %eax, %eax
+; CHECK-NEXT:    vpxor %xmm0, %xmm0, %xmm0
+; CHECK-NEXT:    xorl %edi, %edi
+; CHECK-NEXT:    xorl %esi, %esi
+; CHECK-NEXT:    callq *%rax
+; CHECK-NEXT:    vpxor %xmm0, %xmm0, %xmm0
+; CHECK-NEXT:    kmovw {{[-0-9]+}}(%r{{[sb]}}p), %k1 # 2-byte Reload
+; CHECK-NEXT:    vpsubd {{[-0-9]+}}(%r{{[sb]}}p), %ymm0, %ymm0 {%k1} {z} # 32-byte Folded Reload
+; CHECK-NEXT:    addq $56, %rsp
+; CHECK-NEXT:    .cfi_def_cfa_offset 8
+; CHECK-NEXT:    retq
+entry:
+  %eq = icmp eq <8 x i32> %src, <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  %ne = icmp ne <8 x i32> %src, <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+  %ne_ext = sext <8 x i1> %ne to <8 x i32>
+  %sel1 = select <8 x i1> %eq, <8 x i32> zeroinitializer, <8 x i32> %ne_ext
+  %neg1 = sub <8 x i32> zeroinitializer, %sel1
+  %cast = bitcast <8 x i32> %neg1 to <4 x i64>
+  tail call void null(<4 x i64> zeroinitializer, <4 x i64> %cast, ptr null, i32 0)
+  %sel2 = select <8 x i1> %eq, <8 x i32> zeroinitializer, <8 x i32> %src
+  %neg2 = sub <8 x i32> zeroinitializer, %sel2
+  ret <8 x i32> %neg2
+}
+
+; Verify that commuteSelect handles a setcc used both as the condition and as a
+; value operand (double-use). The double-use select stays uncommmuted while the
+; other select still gets the masked-add optimization.
+
+define <16 x i32> @commute_select_cond_used_as_value(<16 x i32> %a, <16 x i32> %b, <16 x i32> %c, <16 x i32> %d, <16 x i1> %mask1, <16 x i1> %mask2, ptr %out) {
+; CHECK-LABEL: commute_select_cond_used_as_value:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vpcmpnltd %zmm1, %zmm0, %k1
+; CHECK-NEXT:    vpcmpgtd %zmm0, %zmm1, %k0
+; CHECK-NEXT:    vpxor %xmm5, %xmm4, %xmm1
+; CHECK-NEXT:    vpsllw $7, %xmm1, %xmm1
+; CHECK-NEXT:    vpmovb2m %xmm1, %k2
+; CHECK-NEXT:    korw %k2, %k0, %k0
+; CHECK-NEXT:    vpaddd %zmm3, %zmm2, %zmm0 {%k1}
+; CHECK-NEXT:    kmovw %k0, (%rdi)
+; CHECK-NEXT:    retq
+entry:
+  %cmp = icmp slt <16 x i32> %a, %b
+  %mask_or = xor <16 x i1> %mask1, %mask2
+  %sel_mask = select <16 x i1> %cmp, <16 x i1> %cmp, <16 x i1> %mask_or
----------------
timurgol007 wrote:

Yeah, I was thinking of that fix but it seemed to be too specific

https://github.com/llvm/llvm-project/pull/219436


More information about the llvm-commits mailing list