Skip to content

Commit 9189822

Browse files
authored
[LVI] Handle icmp of ashr. (#68010)
This handles the case where this combine: icmp sgt (ashr X, ShAmtC), C --> icmp sgt X, ((C + 1) << ShAmtC) - 1 wasn't performed by instcombine. Proof of the original combine: https://alive2.llvm.org/ce/z/SfpsvX This is a port of the review in https://reviews.llvm.org/D151911 to GitHub.
1 parent 3a4b0e9 commit 9189822

File tree

2 files changed

+144
-0
lines changed

2 files changed

+144
-0
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/IR/Constants.h"
2727
#include "llvm/IR/DataLayout.h"
2828
#include "llvm/IR/Dominators.h"
29+
#include "llvm/IR/InstrTypes.h"
2930
#include "llvm/IR/Instructions.h"
3031
#include "llvm/IR/IntrinsicInst.h"
3132
#include "llvm/IR/Intrinsics.h"
@@ -1083,6 +1084,26 @@ static ValueLatticeElement getValueFromSimpleICmpCondition(
10831084
return ValueLatticeElement::getRange(TrueValues.subtract(Offset));
10841085
}
10851086

1087+
static std::optional<ConstantRange>
1088+
getRangeViaSLT(CmpInst::Predicate Pred, APInt RHS,
1089+
function_ref<std::optional<ConstantRange>(const APInt &)> Fn) {
1090+
bool Invert = false;
1091+
if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) {
1092+
Pred = ICmpInst::getInversePredicate(Pred);
1093+
Invert = true;
1094+
}
1095+
if (Pred == ICmpInst::ICMP_SLE) {
1096+
Pred = ICmpInst::ICMP_SLT;
1097+
if (RHS.isMaxSignedValue())
1098+
return std::nullopt; // Could also return full/empty here, if we wanted.
1099+
++RHS;
1100+
}
1101+
assert(Pred == ICmpInst::ICMP_SLT && "Must be signed predicate");
1102+
if (auto CR = Fn(RHS))
1103+
return Invert ? CR->inverse() : CR;
1104+
return std::nullopt;
1105+
}
1106+
10861107
static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI,
10871108
bool isTrueDest) {
10881109
Value *LHS = ICI->getOperand(0);
@@ -1148,6 +1169,25 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI,
11481169
CR.getUnsignedMin().zext(BitWidth), APInt(BitWidth, 0)));
11491170
}
11501171

1172+
// Recognize:
1173+
// icmp slt (ashr X, ShAmtC), C --> icmp slt X, C << ShAmtC
1174+
// Preconditions: (C << ShAmtC) >> ShAmtC == C
1175+
const APInt *ShAmtC;
1176+
if (CmpInst::isSigned(EdgePred) &&
1177+
match(LHS, m_AShr(m_Specific(Val), m_APInt(ShAmtC))) &&
1178+
match(RHS, m_APInt(C))) {
1179+
auto CR = getRangeViaSLT(
1180+
EdgePred, *C, [&](const APInt &RHS) -> std::optional<ConstantRange> {
1181+
APInt New = RHS << *ShAmtC;
1182+
if ((New.ashr(*ShAmtC)) != RHS)
1183+
return std::nullopt;
1184+
return ConstantRange::getNonEmpty(
1185+
APInt::getSignedMinValue(New.getBitWidth()), New);
1186+
});
1187+
if (CR)
1188+
return ValueLatticeElement::getRange(*CR);
1189+
}
1190+
11511191
return ValueLatticeElement::getOverdefined();
11521192
}
11531193

llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,6 +1240,110 @@ define <2 x i1> @non_const_range_minmax_vec(<2 x i8> %a, <2 x i8> %b) {
12401240
ret <2 x i1> %cmp1
12411241
}
12421242

1243+
define void @ashr_sgt(i8 %x) {
1244+
; CHECK-LABEL: @ashr_sgt(
1245+
; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
1246+
; CHECK-NEXT: [[C:%.*]] = icmp sgt i8 [[S]], 1
1247+
; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
1248+
; CHECK: if:
1249+
; CHECK-NEXT: call void @check1(i1 true)
1250+
; CHECK-NEXT: [[C3:%.*]] = icmp ugt i8 [[X]], 8
1251+
; CHECK-NEXT: call void @check1(i1 [[C3]])
1252+
; CHECK-NEXT: ret void
1253+
; CHECK: else:
1254+
; CHECK-NEXT: ret void
1255+
;
1256+
%s = ashr i8 %x, 2
1257+
%c = icmp sgt i8 %s, 1
1258+
br i1 %c, label %if, label %else
1259+
if:
1260+
%c2 = icmp sgt i8 %x, 7
1261+
call void @check1(i1 %c2)
1262+
%c3 = icmp sgt i8 %x, 8
1263+
call void @check1(i1 %c3)
1264+
ret void
1265+
else:
1266+
ret void
1267+
}
1268+
1269+
define void @ashr_sge(i8 %x) {
1270+
; CHECK-LABEL: @ashr_sge(
1271+
; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
1272+
; CHECK-NEXT: [[C:%.*]] = icmp sge i8 [[S]], 1
1273+
; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
1274+
; CHECK: if:
1275+
; CHECK-NEXT: call void @check1(i1 true)
1276+
; CHECK-NEXT: [[C3:%.*]] = icmp uge i8 [[X]], 5
1277+
; CHECK-NEXT: call void @check1(i1 [[C3]])
1278+
; CHECK-NEXT: ret void
1279+
; CHECK: else:
1280+
; CHECK-NEXT: ret void
1281+
;
1282+
%s = ashr i8 %x, 2
1283+
%c = icmp sge i8 %s, 1
1284+
br i1 %c, label %if, label %else
1285+
if:
1286+
%c2 = icmp sge i8 %x, 4
1287+
call void @check1(i1 %c2)
1288+
%c3 = icmp sge i8 %x, 5
1289+
call void @check1(i1 %c3)
1290+
ret void
1291+
else:
1292+
ret void
1293+
}
1294+
1295+
define void @ashr_slt(i8 %x) {
1296+
; CHECK-LABEL: @ashr_slt(
1297+
; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
1298+
; CHECK-NEXT: [[C:%.*]] = icmp slt i8 [[S]], 1
1299+
; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
1300+
; CHECK: if:
1301+
; CHECK-NEXT: call void @check1(i1 true)
1302+
; CHECK-NEXT: [[C3:%.*]] = icmp slt i8 [[X]], 3
1303+
; CHECK-NEXT: call void @check1(i1 [[C3]])
1304+
; CHECK-NEXT: ret void
1305+
; CHECK: else:
1306+
; CHECK-NEXT: ret void
1307+
;
1308+
%s = ashr i8 %x, 2
1309+
%c = icmp slt i8 %s, 1
1310+
br i1 %c, label %if, label %else
1311+
if:
1312+
%c2 = icmp slt i8 %x, 4
1313+
call void @check1(i1 %c2)
1314+
%c3 = icmp slt i8 %x, 3
1315+
call void @check1(i1 %c3)
1316+
ret void
1317+
else:
1318+
ret void
1319+
}
1320+
1321+
define void @ashr_sle(i8 %x) {
1322+
; CHECK-LABEL: @ashr_sle(
1323+
; CHECK-NEXT: [[S:%.*]] = ashr i8 [[X:%.*]], 2
1324+
; CHECK-NEXT: [[C:%.*]] = icmp sle i8 [[S]], 1
1325+
; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
1326+
; CHECK: if:
1327+
; CHECK-NEXT: call void @check1(i1 true)
1328+
; CHECK-NEXT: [[C3:%.*]] = icmp sle i8 [[X]], 6
1329+
; CHECK-NEXT: call void @check1(i1 [[C3]])
1330+
; CHECK-NEXT: ret void
1331+
; CHECK: else:
1332+
; CHECK-NEXT: ret void
1333+
;
1334+
%s = ashr i8 %x, 2
1335+
%c = icmp sle i8 %s, 1
1336+
br i1 %c, label %if, label %else
1337+
if:
1338+
%c2 = icmp sle i8 %x, 7
1339+
call void @check1(i1 %c2)
1340+
%c3 = icmp sle i8 %x, 6
1341+
call void @check1(i1 %c3)
1342+
ret void
1343+
else:
1344+
ret void
1345+
}
1346+
12431347
declare i8 @llvm.umin.i8(i8, i8)
12441348
declare i8 @llvm.umax.i8(i8, i8)
12451349
declare <2 x i8> @llvm.umin.v2i8(<2 x i8>, <2 x i8>)

0 commit comments

Comments
 (0)