Skip to content

Commit fcb5293

Browse files
authored
[InstCombine]: Canonicalize to a mask when trunc nuw (#163628)
The canonicalize is also triggered when the `trunc` is `nuw`. Proof: https://alive2.llvm.org/ce/z/eWvWe3 Fixes: #162451
1 parent f7a5264 commit fcb5293

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1481,13 +1481,13 @@ Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp,
14811481
return new ICmpInst(Pred, Y, ConstantInt::get(SrcTy, C.logBase2()));
14821482
}
14831483

1484-
if (Cmp.isEquality() && Trunc->hasOneUse()) {
1484+
if (Cmp.isEquality() && (Trunc->hasOneUse() || Trunc->hasNoUnsignedWrap())) {
14851485
// Canonicalize to a mask and wider compare if the wide type is suitable:
14861486
// (trunc X to i8) == C --> (X & 0xff) == (zext C)
14871487
if (!SrcTy->isVectorTy() && shouldChangeType(DstBits, SrcBits)) {
14881488
Constant *Mask =
14891489
ConstantInt::get(SrcTy, APInt::getLowBitsSet(SrcBits, DstBits));
1490-
Value *And = Builder.CreateAnd(X, Mask);
1490+
Value *And = Trunc->hasNoUnsignedWrap() ? X : Builder.CreateAnd(X, Mask);
14911491
Constant *WideC = ConstantInt::get(SrcTy, C.zext(SrcBits));
14921492
return new ICmpInst(Pred, And, WideC);
14931493
}

llvm/test/Transforms/InstCombine/icmp-trunc.ll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
; RUN: opt < %s -passes=instcombine -S -data-layout="n8" | FileCheck %s --check-prefixes=CHECK,DL8
44

55
declare void @use(i8)
6+
declare void @use2(i4)
67

78
define i1 @ult_2(i32 %x) {
89
; CHECK-LABEL: @ult_2(
@@ -785,3 +786,32 @@ define <2 x i1> @uge_nsw_non_splat(<2 x i32> %x) {
785786
ret <2 x i1> %r
786787
}
787788

789+
define i1 @trunc_icmp(i8 %a0) {
790+
; CHECK-LABEL: @trunc_icmp(
791+
; CHECK-NEXT: [[TZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0:%.*]], i1 false)
792+
; CHECK-NEXT: [[TR:%.*]] = trunc nuw i8 [[TZ]] to i4
793+
; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[A0]], 0
794+
; CHECK-NEXT: call void @use2(i4 [[TR]])
795+
; CHECK-NEXT: ret i1 [[C]]
796+
;
797+
%tz = tail call range(i8 0, 9) i8 @llvm.cttz.i8(i8 %a0, i1 false)
798+
%tr = trunc i8 %tz to i4
799+
%c = icmp eq i4 %tr, 8
800+
call void @use2(i4 %tr)
801+
ret i1 %c
802+
}
803+
804+
define i1 @do_not_mask_trunc_eq_i32_i8(i32 %x) {
805+
; DL64-LABEL: @do_not_mask_trunc_eq_i32_i8(
806+
; DL64-NEXT: [[R:%.*]] = icmp eq i32 [[X:%.*]], 42
807+
; DL64-NEXT: ret i1 [[R]]
808+
;
809+
; DL8-LABEL: @do_not_mask_trunc_eq_i32_i8(
810+
; DL8-NEXT: [[T:%.*]] = trunc nuw i32 [[X:%.*]] to i8
811+
; DL8-NEXT: [[R:%.*]] = icmp eq i8 [[T]], 42
812+
; DL8-NEXT: ret i1 [[R]]
813+
;
814+
%t = trunc nuw i32 %x to i8
815+
%r = icmp eq i8 %t, 42
816+
ret i1 %r
817+
}

0 commit comments

Comments
 (0)