Skip to content

Commit ff80e1f

Browse files
authored
[InstSimplify] Simplify uadd.sat(X, Y) u>= X + Y and usub.sat(X, Y) u<= X, Y (#104698)
These patterns are found in harfbuzz/typst. Alive2: https://alive2.llvm.org/ce/z/cxyjYV
1 parent e9e3a18 commit ff80e1f

File tree

2 files changed

+132
-0
lines changed

2 files changed

+132
-0
lines changed

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3718,6 +3718,14 @@ static Value *simplifyICmpWithIntrinsicOnLHS(CmpInst::Predicate Pred,
37183718
if (Pred == ICmpInst::ICMP_ULT)
37193719
return ConstantInt::getFalse(getCompareTy(II));
37203720
}
3721+
// uadd.sat(X, Y) uge X + Y
3722+
if (match(RHS, m_c_Add(m_Specific(II->getArgOperand(0)),
3723+
m_Specific(II->getArgOperand(1))))) {
3724+
if (Pred == ICmpInst::ICMP_UGE)
3725+
return ConstantInt::getTrue(getCompareTy(II));
3726+
if (Pred == ICmpInst::ICMP_ULT)
3727+
return ConstantInt::getFalse(getCompareTy(II));
3728+
}
37213729
return nullptr;
37223730
case Intrinsic::usub_sat:
37233731
// usub.sat(X, Y) ule X
@@ -3727,6 +3735,14 @@ static Value *simplifyICmpWithIntrinsicOnLHS(CmpInst::Predicate Pred,
37273735
if (Pred == ICmpInst::ICMP_UGT)
37283736
return ConstantInt::getFalse(getCompareTy(II));
37293737
}
3738+
// usub.sat(X, Y) ule X - Y
3739+
if (match(RHS, m_Sub(m_Specific(II->getArgOperand(0)),
3740+
m_Specific(II->getArgOperand(1))))) {
3741+
if (Pred == ICmpInst::ICMP_ULE)
3742+
return ConstantInt::getTrue(getCompareTy(II));
3743+
if (Pred == ICmpInst::ICMP_UGT)
3744+
return ConstantInt::getFalse(getCompareTy(II));
3745+
}
37303746
return nullptr;
37313747
default:
37323748
return nullptr;

llvm/test/Transforms/InstSimplify/saturating-add-sub.ll

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,3 +932,119 @@ define i1 @usub_uge_fail(i8 %x, i8 %y) {
932932
%cmp = icmp uge i8 %sat, %x
933933
ret i1 %cmp
934934
}
935+
936+
define i1 @icmp_ult_uaddsat_add(i32 %x, i32 %y) {
937+
; CHECK-LABEL: @icmp_ult_uaddsat_add(
938+
; CHECK-NEXT: ret i1 false
939+
;
940+
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
941+
%add = add i32 %x, %y
942+
%cmp = icmp ult i32 %uaddsat, %add
943+
ret i1 %cmp
944+
}
945+
946+
define i1 @icmp_uge_uaddsat_add(i32 %x, i32 %y) {
947+
; CHECK-LABEL: @icmp_uge_uaddsat_add(
948+
; CHECK-NEXT: ret i1 true
949+
;
950+
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
951+
%add = add i32 %x, %y
952+
%cmp = icmp uge i32 %uaddsat, %add
953+
ret i1 %cmp
954+
}
955+
956+
define i1 @icmp_ugt_uaddsat_add_commuted1(i32 %x, i32 %y) {
957+
; CHECK-LABEL: @icmp_ugt_uaddsat_add_commuted1(
958+
; CHECK-NEXT: ret i1 false
959+
;
960+
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
961+
%add = add i32 %x, %y
962+
%cmp = icmp ugt i32 %add, %uaddsat
963+
ret i1 %cmp
964+
}
965+
966+
define i1 @icmp_ult_uaddsat_add_commuted2(i32 %x, i32 %y) {
967+
; CHECK-LABEL: @icmp_ult_uaddsat_add_commuted2(
968+
; CHECK-NEXT: ret i1 false
969+
;
970+
%xx = mul i32 %x, 998244353
971+
%yy = mul i32 %y, 998244353
972+
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %xx, i32 %yy)
973+
%add = add i32 %yy, %xx ; thwart complexity-based canonicalization
974+
%cmp = icmp ult i32 %uaddsat, %add
975+
ret i1 %cmp
976+
}
977+
978+
define i1 @icmp_ule_usubsat_sub(i32 %x, i32 %y) {
979+
; CHECK-LABEL: @icmp_ule_usubsat_sub(
980+
; CHECK-NEXT: ret i1 true
981+
;
982+
%usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
983+
%add = sub i32 %x, %y
984+
%cmp = icmp ule i32 %usubsat, %add
985+
ret i1 %cmp
986+
}
987+
988+
define i1 @icmp_ugt_usubsat_sub(i32 %x, i32 %y) {
989+
; CHECK-LABEL: @icmp_ugt_usubsat_sub(
990+
; CHECK-NEXT: ret i1 false
991+
;
992+
%usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
993+
%add = sub i32 %x, %y
994+
%cmp = icmp ugt i32 %usubsat, %add
995+
ret i1 %cmp
996+
}
997+
998+
; Negative tests
999+
1000+
define i1 @icmp_ult_uaddsat_add_mismatch(i32 %x, i32 %y, i32 %z) {
1001+
; CHECK-LABEL: @icmp_ult_uaddsat_add_mismatch(
1002+
; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Z:%.*]])
1003+
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y:%.*]]
1004+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[ADD]]
1005+
; CHECK-NEXT: ret i1 [[CMP]]
1006+
;
1007+
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %z)
1008+
%add = add i32 %x, %y
1009+
%cmp = icmp ult i32 %uaddsat, %add
1010+
ret i1 %cmp
1011+
}
1012+
1013+
define i1 @icmp_ult_uaddsat_add_wrong_pred(i32 %x, i32 %y) {
1014+
; CHECK-LABEL: @icmp_ult_uaddsat_add_wrong_pred(
1015+
; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
1016+
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X]], [[Y]]
1017+
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[UADDSAT]], [[ADD]]
1018+
; CHECK-NEXT: ret i1 [[CMP]]
1019+
;
1020+
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
1021+
%add = add i32 %x, %y
1022+
%cmp = icmp ule i32 %uaddsat, %add
1023+
ret i1 %cmp
1024+
}
1025+
1026+
define i1 @icmp_ult_uaddsat_add_wrong_op(i32 %x, i32 %y) {
1027+
; CHECK-LABEL: @icmp_ult_uaddsat_add_wrong_op(
1028+
; CHECK-NEXT: [[UADDSAT:%.*]] = call i32 @llvm.uadd.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
1029+
; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[X]], [[Y]]
1030+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[UADDSAT]], [[SUB]]
1031+
; CHECK-NEXT: ret i1 [[CMP]]
1032+
;
1033+
%uaddsat = call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)
1034+
%sub = sub i32 %x, %y
1035+
%cmp = icmp ult i32 %uaddsat, %sub
1036+
ret i1 %cmp
1037+
}
1038+
1039+
define i1 @icmp_ule_usubsat_sub_commuted(i32 %x, i32 %y) {
1040+
; CHECK-LABEL: @icmp_ule_usubsat_sub_commuted(
1041+
; CHECK-NEXT: [[USUBSAT:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[X:%.*]], i32 [[Y:%.*]])
1042+
; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]]
1043+
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[USUBSAT]], [[ADD]]
1044+
; CHECK-NEXT: ret i1 [[CMP]]
1045+
;
1046+
%usubsat = call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)
1047+
%add = sub i32 %y, %x
1048+
%cmp = icmp ule i32 %usubsat, %add
1049+
ret i1 %cmp
1050+
}

0 commit comments

Comments
 (0)