Skip to content

Commit

Permalink
[InstCombine] Fold zext(X) + C2 pred C -> X + C3 pred C4 (llvm#110511)
Browse files Browse the repository at this point in the history
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
}
```
  • Loading branch information
dtcxzyw authored Nov 21, 2024
1 parent 4872ecf commit 2e60048
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 0 deletions.
24 changes: 24 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
106 changes: 106 additions & 0 deletions llvm/test/Transforms/InstCombine/icmp-add.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit 2e60048

Please sign in to comment.