Skip to content

Commit aa85774

Browse files
committed
[LVI] Add support for fp operations
1 parent 8e2db8c commit aa85774

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,19 +412,27 @@ class LazyValueInfoImpl {
412412
BasicBlock *BB);
413413
std::optional<ConstantRange> getRangeFor(Value *V, Instruction *CxtI,
414414
BasicBlock *BB);
415+
std::optional<ConstantFPRange> getFPRangeFor(Value *V, Instruction *CxtI,
416+
BasicBlock *BB);
415417
std::optional<ValueLatticeElement> solveBlockValueBinaryOpImpl(
416418
Instruction *I, BasicBlock *BB,
417419
std::function<ConstantRange(const ConstantRange &, const ConstantRange &)>
418420
OpFn);
419421
std::optional<ValueLatticeElement>
420422
solveBlockValueBinaryOp(BinaryOperator *BBI, BasicBlock *BB);
423+
std::optional<ValueLatticeElement>
424+
solveBlockValueFPBinaryOp(BinaryOperator *BBI, BasicBlock *BB);
421425
std::optional<ValueLatticeElement> solveBlockValueCast(CastInst *CI,
422426
BasicBlock *BB);
427+
std::optional<ValueLatticeElement> solveBlockValueFPCast(CastInst *CI,
428+
BasicBlock *BB);
423429
std::optional<ValueLatticeElement>
424430
solveBlockValueOverflowIntrinsic(WithOverflowInst *WO, BasicBlock *BB);
425431
std::optional<ValueLatticeElement> solveBlockValueIntrinsic(IntrinsicInst *II,
426432
BasicBlock *BB);
427433
std::optional<ValueLatticeElement>
434+
solveBlockValueFPIntrinsic(IntrinsicInst *II, BasicBlock *BB);
435+
std::optional<ValueLatticeElement>
428436
solveBlockValueInsertElement(InsertElementInst *IEI, BasicBlock *BB);
429437
std::optional<ValueLatticeElement>
430438
solveBlockValueExtractValue(ExtractValueInst *EVI, BasicBlock *BB);
@@ -671,6 +679,26 @@ LazyValueInfoImpl::solveBlockValueImpl(Value *Val, BasicBlock *BB) {
671679
return solveBlockValueIntrinsic(II, BB);
672680
}
673681

682+
if (BBI->getType()->isFPOrFPVectorTy()) {
683+
if (BBI->getOpcode() == Instruction::FNeg) {
684+
std::optional<ConstantFPRange> OpRes =
685+
getFPRangeFor(BBI->getOperand(0), BBI, BB);
686+
if (!OpRes)
687+
// More work to do before applying this transfer rule.
688+
return std::nullopt;
689+
return ValueLatticeElement::getFPRange(OpRes->negate());
690+
}
691+
692+
if (auto *CI = dyn_cast<CastInst>(BBI))
693+
return solveBlockValueFPCast(CI, BB);
694+
695+
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(BBI))
696+
return solveBlockValueFPBinaryOp(BO, BB);
697+
698+
if (auto *II = dyn_cast<IntrinsicInst>(BBI))
699+
return solveBlockValueFPIntrinsic(II, BB);
700+
}
701+
674702
LLVM_DEBUG(dbgs() << " compute BB '" << BB->getName()
675703
<< "' - unknown inst def found.\n");
676704
return getFromRangeMetadata(BBI);
@@ -967,6 +995,14 @@ LazyValueInfoImpl::getRangeFor(Value *V, Instruction *CxtI, BasicBlock *BB) {
967995
return OptVal->asConstantRange(V->getType());
968996
}
969997

998+
std::optional<ConstantFPRange>
999+
LazyValueInfoImpl::getFPRangeFor(Value *V, Instruction *CxtI, BasicBlock *BB) {
1000+
std::optional<ValueLatticeElement> OptVal = getBlockValue(V, BB, CxtI);
1001+
if (!OptVal)
1002+
return std::nullopt;
1003+
return OptVal->asConstantFPRange(V->getType());
1004+
}
1005+
9701006
std::optional<ValueLatticeElement>
9711007
LazyValueInfoImpl::solveBlockValueCast(CastInst *CI, BasicBlock *BB) {
9721008
// Filter out casts we don't know how to reason about before attempting to
@@ -1007,6 +1043,47 @@ LazyValueInfoImpl::solveBlockValueCast(CastInst *CI, BasicBlock *BB) {
10071043
return ValueLatticeElement::getRange(Res);
10081044
}
10091045

1046+
static void postProcessFPRange(ConstantFPRange &R,
1047+
DenormalMode::DenormalModeKind Mode,
1048+
FastMathFlags FMF) {
1049+
if (FMF.noNaNs())
1050+
R = R.getWithoutNaN();
1051+
if (FMF.noInfs())
1052+
R = R.getWithoutInf();
1053+
R.flushDenormals(Mode);
1054+
}
1055+
1056+
std::optional<ValueLatticeElement>
1057+
LazyValueInfoImpl::solveBlockValueFPCast(CastInst *CI, BasicBlock *BB) {
1058+
// Filter out casts we don't know how to reason about before attempting to
1059+
// recurse on our operand. This can cut a long search short if we know we're
1060+
// not going to be able to get any useful information anways.
1061+
switch (CI->getOpcode()) {
1062+
case Instruction::FPExt:
1063+
case Instruction::FPTrunc:
1064+
break;
1065+
default:
1066+
// Unhandled instructions are overdefined.
1067+
LLVM_DEBUG(dbgs() << " compute BB '" << BB->getName()
1068+
<< "' - overdefined (unknown cast).\n");
1069+
return ValueLatticeElement::getOverdefined();
1070+
}
1071+
1072+
std::optional<ConstantFPRange> OpRes =
1073+
getFPRangeFor(CI->getOperand(0), CI, BB);
1074+
if (!OpRes)
1075+
// More work to do before applying this transfer rule.
1076+
return std::nullopt;
1077+
ConstantFPRange &Op = *OpRes;
1078+
FastMathFlags FMF = CI->getFastMathFlags();
1079+
auto &Sem = CI->getDestTy()->getScalarType()->getFltSemantics();
1080+
auto DenormalMode = BB->getParent()->getDenormalMode(Sem);
1081+
postProcessFPRange(Op, DenormalMode.Input, FMF);
1082+
ConstantFPRange Res = Op.cast(Sem);
1083+
postProcessFPRange(Res, DenormalMode.Output, FMF);
1084+
return ValueLatticeElement::getFPRange(std::move(Res));
1085+
}
1086+
10101087
std::optional<ValueLatticeElement>
10111088
LazyValueInfoImpl::solveBlockValueBinaryOpImpl(
10121089
Instruction *I, BasicBlock *BB,
@@ -1165,6 +1242,46 @@ LazyValueInfoImpl::solveBlockValueBinaryOp(BinaryOperator *BO, BasicBlock *BB) {
11651242
});
11661243
}
11671244

1245+
std::optional<ValueLatticeElement>
1246+
LazyValueInfoImpl::solveBlockValueFPBinaryOp(BinaryOperator *BO,
1247+
BasicBlock *BB) {
1248+
FastMathFlags FMF = BO->getFastMathFlags();
1249+
Function *F = BB->getParent();
1250+
auto LHSRes = getFPRangeFor(BO->getOperand(0), BO, BB);
1251+
if (!LHSRes)
1252+
return std::nullopt;
1253+
auto RHSRes = getFPRangeFor(BO->getOperand(1), BO, BB);
1254+
if (!RHSRes)
1255+
return std::nullopt;
1256+
auto &LHSRange = *LHSRes;
1257+
auto &RHSRange = *RHSRes;
1258+
auto &Sem = LHSRange.getSemantics();
1259+
auto DenormalMode = F->getDenormalMode(Sem);
1260+
postProcessFPRange(LHSRange, DenormalMode.Input, FMF);
1261+
postProcessFPRange(RHSRange, DenormalMode.Output, FMF);
1262+
ConstantFPRange Res = ConstantFPRange::getFull(Sem);
1263+
switch (BO->getOpcode()) {
1264+
case Instruction::FAdd:
1265+
Res = LHSRange.add(RHSRange);
1266+
break;
1267+
case Instruction::FSub:
1268+
Res = LHSRange.sub(RHSRange);
1269+
break;
1270+
case Instruction::FMul:
1271+
Res = LHSRange.mul(RHSRange);
1272+
break;
1273+
case Instruction::FDiv:
1274+
Res = LHSRange.div(RHSRange);
1275+
break;
1276+
case Instruction::FRem:
1277+
break;
1278+
default:
1279+
llvm_unreachable("Unknown FP binary operator.");
1280+
}
1281+
postProcessFPRange(Res, DenormalMode.Output, FMF);
1282+
return ValueLatticeElement::getFPRange(Res);
1283+
}
1284+
11681285
std::optional<ValueLatticeElement>
11691286
LazyValueInfoImpl::solveBlockValueOverflowIntrinsic(WithOverflowInst *WO,
11701287
BasicBlock *BB) {
@@ -1196,6 +1313,42 @@ LazyValueInfoImpl::solveBlockValueIntrinsic(IntrinsicInst *II, BasicBlock *BB) {
11961313
.intersect(MetadataVal);
11971314
}
11981315

1316+
std::optional<ValueLatticeElement>
1317+
LazyValueInfoImpl::solveBlockValueFPIntrinsic(IntrinsicInst *II,
1318+
BasicBlock *BB) {
1319+
Intrinsic::ID IID = II->getIntrinsicID();
1320+
switch (IID) {
1321+
case Intrinsic::fabs:
1322+
case Intrinsic::copysign:
1323+
break;
1324+
default:
1325+
return ValueLatticeElement::getOverdefined();
1326+
}
1327+
SmallVector<ConstantFPRange, 2> OpRanges;
1328+
for (Value *Op : II->args()) {
1329+
std::optional<ConstantFPRange> Range = getFPRangeFor(Op, II, BB);
1330+
if (!Range)
1331+
return std::nullopt;
1332+
OpRanges.push_back(*Range);
1333+
}
1334+
switch (IID) {
1335+
case Intrinsic::fabs:
1336+
return ValueLatticeElement::getFPRange(OpRanges[0].abs());
1337+
case Intrinsic::copysign: {
1338+
ConstantFPRange Mag = OpRanges[0].abs();
1339+
std::optional<bool> Sign = OpRanges[1].getSignBit();
1340+
if (Sign.has_value()) {
1341+
if (*Sign)
1342+
return ValueLatticeElement::getFPRange(Mag.negate());
1343+
return ValueLatticeElement::getFPRange(Mag);
1344+
}
1345+
return ValueLatticeElement::getFPRange(Mag.negate().unionWith(Mag));
1346+
}
1347+
default:
1348+
llvm_unreachable("Unsupported FP intrinsic.");
1349+
}
1350+
}
1351+
11991352
std::optional<ValueLatticeElement>
12001353
LazyValueInfoImpl::solveBlockValueInsertElement(InsertElementInst *IEI,
12011354
BasicBlock *BB) {

0 commit comments

Comments
 (0)