From 01804609bc8209e95ddd7491440261362ced8a5a Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Wed, 12 Nov 2025 13:55:46 +0000 Subject: [PATCH 1/2] Add tests --- llvm/test/Transforms/InstCombine/not.ll | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll index d693b9d8f8557..f6a0f0baff98c 100644 --- a/llvm/test/Transforms/InstCombine/not.ll +++ b/llvm/test/Transforms/InstCombine/not.ll @@ -1061,3 +1061,85 @@ if.else: call void @f2() unreachable } + +define i8 @invert_bitcasted_icmp(<8 x i32> %a, <8 x i32> %b) { +; CHECK-LABEL: @invert_bitcasted_icmp( +; CHECK-NEXT: [[CMP:%.*]] = icmp sle <8 x i32> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 +; CHECK-NEXT: ret i8 [[NOT]] +; + %cmp = icmp sle <8 x i32> %a, %b + %mask.as.int = bitcast <8 x i1> %cmp to i8 + %not = xor i8 %mask.as.int, 255 + ret i8 %not +} + +define i8 @invert_bitcasted_icmp_samesign(<8 x i32> %a, <8 x i32> %b) { +; CHECK-LABEL: @invert_bitcasted_icmp_samesign( +; CHECK-NEXT: [[CMP:%.*]] = icmp samesign sle <8 x i32> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 +; CHECK-NEXT: ret i8 [[NOT]] +; + %cmp = icmp samesign sle <8 x i32> %a, %b + %mask.as.int = bitcast <8 x i1> %cmp to i8 + %not = xor i8 %mask.as.int, 255 + ret i8 %not +} + +define i8 @invert_bitcasted_icmp_multi_use_1(<8 x i32> %a, <8 x i32> %b) { +; CHECK-LABEL: @invert_bitcasted_icmp_multi_use_1( +; CHECK-NEXT: [[CMP:%.*]] = icmp sle <8 x i32> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: call void (...) @llvm.fake.use(<8 x i1> [[CMP]]) +; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 +; CHECK-NEXT: ret i8 [[NOT]] +; + %cmp = icmp sle <8 x i32> %a, %b + call void (...) @llvm.fake.use(<8 x i1> %cmp) + %mask.as.int = bitcast <8 x i1> %cmp to i8 + %not = xor i8 %mask.as.int, -1 + ret i8 %not +} + +define i8 @invert_bitcasted_icmp_multi_use_2(<8 x i32> %a, <8 x i32> %b) { +; CHECK-LABEL: @invert_bitcasted_icmp_multi_use_2( +; CHECK-NEXT: [[CMP:%.*]] = icmp sle <8 x i32> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 +; CHECK-NEXT: call void (...) @llvm.fake.use(i8 [[MASK_AS_INT]]) +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 +; CHECK-NEXT: ret i8 [[NOT]] +; + %cmp = icmp sle <8 x i32> %a, %b + %mask.as.int = bitcast <8 x i1> %cmp to i8 + call void (...) @llvm.fake.use(i8 %mask.as.int) + %not = xor i8 %mask.as.int, -1 + ret i8 %not +} + +define i8 @invert_bitcasted_fcmp(<8 x float> %a, <8 x float> %b) { +; CHECK-LABEL: @invert_bitcasted_fcmp( +; CHECK-NEXT: [[CMP:%.*]] = fcmp olt <8 x float> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 +; CHECK-NEXT: ret i8 [[NOT]] +; + %cmp = fcmp olt <8 x float> %a, %b + %mask.as.int = bitcast <8 x i1> %cmp to i8 + %not = xor i8 %mask.as.int, 255 + ret i8 %not +} + +define i8 @invert_bitcasted_fcmp_fast(<8 x float> %a, <8 x float> %b) { +; CHECK-LABEL: @invert_bitcasted_fcmp_fast( +; CHECK-NEXT: [[CMP:%.*]] = fcmp fast olt <8 x float> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 +; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 +; CHECK-NEXT: ret i8 [[NOT]] +; + %cmp = fcmp fast olt <8 x float> %a, %b + %mask.as.int = bitcast <8 x i1> %cmp to i8 + %not = xor i8 %mask.as.int, 255 + ret i8 %not +} From 468cdd5cbd2c1c708da55c66f8bc0fb17cb545b3 Mon Sep 17 00:00:00 2001 From: Paul Walker Date: Wed, 12 Nov 2025 12:07:48 +0000 Subject: [PATCH 2/2] [LLVM][InstCombine] not (bitcast (cmp A, B) --> bitcast (!cmp A, B) --- .../InstCombine/InstCombineAndOrXor.cpp | 10 +++++++++- llvm/test/Transforms/InstCombine/not.ll | 20 ++++++++----------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index cbaff294819a2..ba5568b00441b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -5096,9 +5096,17 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) { return &I; } + // not (bitcast (cmp A, B) --> bitcast (!cmp A, B) + if (match(NotOp, m_OneUse(m_BitCast(m_Value(X)))) && + match(X, m_OneUse(m_Cmp(Pred, m_Value(), m_Value())))) { + cast(X)->setPredicate(CmpInst::getInversePredicate(Pred)); + return new BitCastInst(X, Ty); + } + // Move a 'not' ahead of casts of a bool to enable logic reduction: // not (bitcast (sext i1 X)) --> bitcast (sext (not i1 X)) - if (match(NotOp, m_OneUse(m_BitCast(m_OneUse(m_SExt(m_Value(X)))))) && X->getType()->isIntOrIntVectorTy(1)) { + if (match(NotOp, m_OneUse(m_BitCast(m_OneUse(m_SExt(m_Value(X)))))) && + X->getType()->isIntOrIntVectorTy(1)) { Type *SextTy = cast(NotOp)->getSrcTy(); Value *NotX = Builder.CreateNot(X); Value *Sext = Builder.CreateSExt(NotX, SextTy); diff --git a/llvm/test/Transforms/InstCombine/not.ll b/llvm/test/Transforms/InstCombine/not.ll index f6a0f0baff98c..1acf55a50208d 100644 --- a/llvm/test/Transforms/InstCombine/not.ll +++ b/llvm/test/Transforms/InstCombine/not.ll @@ -1064,10 +1064,9 @@ if.else: define i8 @invert_bitcasted_icmp(<8 x i32> %a, <8 x i32> %b) { ; CHECK-LABEL: @invert_bitcasted_icmp( -; CHECK-NEXT: [[CMP:%.*]] = icmp sle <8 x i32> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <8 x i32> [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 -; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 -; CHECK-NEXT: ret i8 [[NOT]] +; CHECK-NEXT: ret i8 [[MASK_AS_INT]] ; %cmp = icmp sle <8 x i32> %a, %b %mask.as.int = bitcast <8 x i1> %cmp to i8 @@ -1077,10 +1076,9 @@ define i8 @invert_bitcasted_icmp(<8 x i32> %a, <8 x i32> %b) { define i8 @invert_bitcasted_icmp_samesign(<8 x i32> %a, <8 x i32> %b) { ; CHECK-LABEL: @invert_bitcasted_icmp_samesign( -; CHECK-NEXT: [[CMP:%.*]] = icmp samesign sle <8 x i32> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp samesign sgt <8 x i32> [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 -; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 -; CHECK-NEXT: ret i8 [[NOT]] +; CHECK-NEXT: ret i8 [[MASK_AS_INT]] ; %cmp = icmp samesign sle <8 x i32> %a, %b %mask.as.int = bitcast <8 x i1> %cmp to i8 @@ -1120,10 +1118,9 @@ define i8 @invert_bitcasted_icmp_multi_use_2(<8 x i32> %a, <8 x i32> %b) { define i8 @invert_bitcasted_fcmp(<8 x float> %a, <8 x float> %b) { ; CHECK-LABEL: @invert_bitcasted_fcmp( -; CHECK-NEXT: [[CMP:%.*]] = fcmp olt <8 x float> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp uge <8 x float> [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 -; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 -; CHECK-NEXT: ret i8 [[NOT]] +; CHECK-NEXT: ret i8 [[MASK_AS_INT]] ; %cmp = fcmp olt <8 x float> %a, %b %mask.as.int = bitcast <8 x i1> %cmp to i8 @@ -1133,10 +1130,9 @@ define i8 @invert_bitcasted_fcmp(<8 x float> %a, <8 x float> %b) { define i8 @invert_bitcasted_fcmp_fast(<8 x float> %a, <8 x float> %b) { ; CHECK-LABEL: @invert_bitcasted_fcmp_fast( -; CHECK-NEXT: [[CMP:%.*]] = fcmp fast olt <8 x float> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = fcmp fast uge <8 x float> [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: [[MASK_AS_INT:%.*]] = bitcast <8 x i1> [[CMP]] to i8 -; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[MASK_AS_INT]], -1 -; CHECK-NEXT: ret i8 [[NOT]] +; CHECK-NEXT: ret i8 [[MASK_AS_INT]] ; %cmp = fcmp fast olt <8 x float> %a, %b %mask.as.int = bitcast <8 x i1> %cmp to i8