From 2e60048641e86b7a414aec51d920bc4e1e3fbeb6 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Thu, 21 Nov 2024 20:47:24 +0800 Subject: [PATCH] [InstCombine] Fold zext(X) + C2 pred C -> X + C3 pred C4 (#110511) Motivating case from https://github.com/torvalds/linux/blob/9852d85ec9d492ebef56dc5f229416c925758edc/drivers/gpu/drm/drm_edid.c#L5238-L5240: ``` define i1 @src(i8 noundef %v13) { entry: %conv1 = zext i8 %v13 to i32 %add = add nsw i32 %conv1, -4 %cmp = icmp ult i32 %add, 3 %cmp4 = icmp slt i8 %v13, 4 %cond = select i1 %cmp4, i1 true, i1 %cmp ret i1 %cond } define i1 @tgt(i8 noundef %v13) { entry: %cmp4 = icmp slt i8 %v13, 7 ret i1 %cmp4 } ``` --- .../InstCombine/InstCombineCompares.cpp | 24 ++++ llvm/test/Transforms/InstCombine/icmp-add.ll | 106 ++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index d602a907e72bcd..4be576c8ce3b0f 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3183,6 +3183,30 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp, Builder.CreateAdd(X, ConstantInt::get(Ty, *C2 - C - 1)), ConstantInt::get(Ty, ~C)); + // zext(V) + C2 pred C -> V + C3 pred' C4 + Value *V; + if (match(X, m_ZExt(m_Value(V)))) { + Type *NewCmpTy = V->getType(); + unsigned CmpBW = Ty->getScalarSizeInBits(); + unsigned NewCmpBW = NewCmpTy->getScalarSizeInBits(); + if (shouldChangeType(Ty, NewCmpTy)) { + if (CR.getActiveBits() <= NewCmpBW) { + ConstantRange SrcCR = CR.truncate(NewCmpBW); + CmpInst::Predicate EquivPred; + APInt EquivInt; + APInt EquivOffset; + + SrcCR.getEquivalentICmp(EquivPred, EquivInt, EquivOffset); + return new ICmpInst( + EquivPred, + EquivOffset.isZero() + ? V + : Builder.CreateAdd(V, ConstantInt::get(NewCmpTy, EquivOffset)), + ConstantInt::get(NewCmpTy, EquivInt)); + } + } + } + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll index dd8e9c1a45ea10..579247aaccf282 100644 --- a/llvm/test/Transforms/InstCombine/icmp-add.ll +++ b/llvm/test/Transforms/InstCombine/icmp-add.ll @@ -3183,3 +3183,109 @@ define i1 @icmp_of_ucmp_plus_const_with_const(i32 %x, i32 %y) { %cmp2 = icmp ult i8 %add, 2 ret i1 %cmp2 } + +define i1 @zext_range_check_ult(i8 %x) { +; CHECK-LABEL: @zext_range_check_ult( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[X:%.*]], -4 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[TMP0]], 3 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %conv = zext i8 %x to i32 + %add = add i32 %conv, -4 + %cmp = icmp ult i32 %add, 3 + ret i1 %cmp +} + +; TODO: should be canonicalized to (x - 4) u> 2 +define i1 @zext_range_check_ugt(i8 %x) { +; CHECK-LABEL: @zext_range_check_ugt( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[X:%.*]] to i32 +; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[CONV]], -7 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[TMP0]], -3 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %conv = zext i8 %x to i32 + %add = add i32 %conv, -4 + %cmp = icmp ugt i32 %add, 2 + ret i1 %cmp +} + +; TODO: should be canonicalized to (x - 4) u> 2 +define i1 @zext_range_check_ult_alter(i8 %x) { +; CHECK-LABEL: @zext_range_check_ult_alter( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[X:%.*]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV]], -7 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ADD]], -3 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %conv = zext i8 %x to i32 + %add = add i32 %conv, -7 + %cmp = icmp ult i32 %add, -3 + ret i1 %cmp +} + +define i1 @zext_range_check_mergable(i8 %x) { +; CHECK-LABEL: @zext_range_check_mergable( +; CHECK-NEXT: [[COND:%.*]] = icmp slt i8 [[X:%.*]], 7 +; CHECK-NEXT: ret i1 [[COND]] +; + %conv = zext i8 %x to i32 + %add = add nsw i32 %conv, -4 + %cmp1 = icmp ult i32 %add, 3 + %cmp2 = icmp slt i8 %x, 4 + %cond = select i1 %cmp2, i1 true, i1 %cmp1 + ret i1 %cond +} + +; Negative tests + +define i1 @sext_range_check_ult(i8 %x) { +; CHECK-LABEL: @sext_range_check_ult( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = sext i8 [[X:%.*]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV]], -4 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ADD]], 3 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %conv = sext i8 %x to i32 + %add = add i32 %conv, -4 + %cmp = icmp ult i32 %add, 3 + ret i1 %cmp +} + +define i1 @zext_range_check_ult_illegal_type(i7 %x) { +; CHECK-LABEL: @zext_range_check_ult_illegal_type( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = zext i7 [[X:%.*]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV]], -4 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ADD]], 3 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %conv = zext i7 %x to i32 + %add = add i32 %conv, -4 + %cmp = icmp ult i32 %add, 3 + ret i1 %cmp +} + +define i1 @zext_range_check_ult_range_check_failure(i8 %x) { +; CHECK-LABEL: @zext_range_check_ult_range_check_failure( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[X:%.*]] to i32 +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV]], -4 +; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[ADD]], 253 +; CHECK-NEXT: ret i1 [[CMP]] +; +entry: + %conv = zext i8 %x to i32 + %add = add i32 %conv, -4 + %cmp = icmp ult i32 %add, 253 + ret i1 %cmp +}