From 07bdb2ccb3d2123fec40b4696feaee08f73a9faa Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Wed, 15 Oct 2025 20:32:36 +0000 Subject: [PATCH 1/4] [InstCombine]: Canonicalize to a mask when trunc nuw --- .../InstCombine/InstCombineCompares.cpp | 2 +- llvm/test/Transforms/InstCombine/icmp-trunc.ll | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 07ad65c8b7d42..5594f37b02b31 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1481,7 +1481,7 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp, return new ICmpInst(Pred, Y, ConstantInt::get(SrcTy, C.logBase2())); } - if (Cmp.isEquality() && Trunc->hasOneUse()) { + if (Cmp.isEquality() && (Trunc->hasOneUse() || Trunc->hasNoUnsignedWrap())) { // Canonicalize to a mask and wider compare if the wide type is suitable: // (trunc X to i8) == C --> (X & 0xff) == (zext C) if (!SrcTy->isVectorTy() && shouldChangeType(DstBits, SrcBits)) { diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc.ll b/llvm/test/Transforms/InstCombine/icmp-trunc.ll index b85deabf5fa06..acaec2bce03a2 100644 --- a/llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ b/llvm/test/Transforms/InstCombine/icmp-trunc.ll @@ -3,6 +3,7 @@ ; RUN: opt < %s -passes=instcombine -S -data-layout="n8" | FileCheck %s --check-prefixes=CHECK,DL8 declare void @use(i8) +declare void @use2(i4) define i1 @ult_2(i32 %x) { ; CHECK-LABEL: @ult_2( @@ -785,3 +786,17 @@ define <2 x i1> @uge_nsw_non_splat(<2 x i32> %x) { ret <2 x i1> %r } +define i1 @trunc_icmp(i8 %a0) { +; CHECK-LABEL: @trunc_icmp( +; CHECK-NEXT: [[TZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0:%.*]], i1 false) +; CHECK-NEXT: [[TR:%.*]] = trunc nuw i8 [[TZ]] to i4 +; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A0]], 0 +; CHECK-NEXT: call void @use(i4 [[TR]]) +; CHECK-NEXT: ret i1 [[C]] +; + %tz = tail call range(i8 0, 9) i8 @llvm.cttz.i8(i8 %a0, i1 false) + %tr = trunc i8 %tz to i4 + %c = icmp eq i4 %tr, 8 + call void @use(i4 %tr) + ret i1 %c +} \ No newline at end of file From 6a7e2bd497d7691784b0fc0b2fd2532374457e26 Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Wed, 15 Oct 2025 20:36:49 +0000 Subject: [PATCH 2/4] [InstCombine]: Use other `use2` function --- llvm/test/Transforms/InstCombine/icmp-trunc.ll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc.ll b/llvm/test/Transforms/InstCombine/icmp-trunc.ll index acaec2bce03a2..4a80d0de45767 100644 --- a/llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ b/llvm/test/Transforms/InstCombine/icmp-trunc.ll @@ -791,12 +791,12 @@ define i1 @trunc_icmp(i8 %a0) { ; CHECK-NEXT: [[TZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0:%.*]], i1 false) ; CHECK-NEXT: [[TR:%.*]] = trunc nuw i8 [[TZ]] to i4 ; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A0]], 0 -; CHECK-NEXT: call void @use(i4 [[TR]]) +; CHECK-NEXT: call void @use2(i4 [[TR]]) ; CHECK-NEXT: ret i1 [[C]] ; %tz = tail call range(i8 0, 9) i8 @llvm.cttz.i8(i8 %a0, i1 false) %tr = trunc i8 %tz to i4 %c = icmp eq i4 %tr, 8 - call void @use(i4 %tr) + call void @use2(i4 %tr) ret i1 %c -} \ No newline at end of file +} From 0e2d832ab303c6a6dd945623ecb2c630b415459c Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Thu, 16 Oct 2025 20:45:17 +0000 Subject: [PATCH 3/4] [InstCombine]: Do not mask when trunc nuw --- .../InstCombine/InstCombineCompares.cpp | 2 +- llvm/test/Transforms/InstCombine/icmp-trunc.ll | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 5594f37b02b31..0bf43e5c3718d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1487,7 +1487,7 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp, if (!SrcTy->isVectorTy() && shouldChangeType(DstBits, SrcBits)) { Constant *Mask = ConstantInt::get(SrcTy, APInt::getLowBitsSet(SrcBits, DstBits)); - Value *And = Builder.CreateAnd(X, Mask); + Value *And = Trunc->hasNoUnsignedWrap() ? X : Builder.CreateAnd(X, Mask); Constant *WideC = ConstantInt::get(SrcTy, C.zext(SrcBits)); return new ICmpInst(Pred, And, WideC); } diff --git a/llvm/test/Transforms/InstCombine/icmp-trunc.ll b/llvm/test/Transforms/InstCombine/icmp-trunc.ll index 4a80d0de45767..ad76ef7329b0a 100644 --- a/llvm/test/Transforms/InstCombine/icmp-trunc.ll +++ b/llvm/test/Transforms/InstCombine/icmp-trunc.ll @@ -800,3 +800,18 @@ define i1 @trunc_icmp(i8 %a0) { call void @use2(i4 %tr) ret i1 %c } + +define i1 @do_not_mask_trunc_eq_i32_i8(i32 %x) { +; DL64-LABEL: @do_not_mask_trunc_eq_i32_i8( +; DL64-NEXT: [[R:%.*]] = icmp eq i32 [[X:%.*]], 42 +; DL64-NEXT: ret i1 [[R]] +; +; DL8-LABEL: @do_not_mask_trunc_eq_i32_i8( +; DL8-NEXT: [[T:%.*]] = trunc nuw i32 [[X:%.*]] to i8 +; DL8-NEXT: [[R:%.*]] = icmp eq i8 [[T]], 42 +; DL8-NEXT: ret i1 [[R]] +; + %t = trunc nuw i32 %x to i8 + %r = icmp eq i8 %t, 42 + ret i1 %r +} From df5680c9ef864c12263b1050a8e4e64f541a1c30 Mon Sep 17 00:00:00 2001 From: Kevin Per Date: Fri, 17 Oct 2025 05:00:26 +0000 Subject: [PATCH 4/4] [InstCombine]: Run formatter --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 0bf43e5c3718d..fba1ccf2c8c9b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1487,7 +1487,7 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp, if (!SrcTy->isVectorTy() && shouldChangeType(DstBits, SrcBits)) { Constant *Mask = ConstantInt::get(SrcTy, APInt::getLowBitsSet(SrcBits, DstBits)); - Value *And = Trunc->hasNoUnsignedWrap() ? X : Builder.CreateAnd(X, Mask); + Value *And = Trunc->hasNoUnsignedWrap() ? X : Builder.CreateAnd(X, Mask); Constant *WideC = ConstantInt::get(SrcTy, C.zext(SrcBits)); return new ICmpInst(Pred, And, WideC); }