aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/FloatingPointOps.def1
-rw-r--r--llvm/lib/IR/Instructions.cpp10
-rw-r--r--llvm/unittests/IR/IRBuilderTest.cpp65
3 files changed, 76 insertions, 0 deletions
diff --git a/llvm/include/llvm/IR/FloatingPointOps.def b/llvm/include/llvm/IR/FloatingPointOps.def
index 8567b5d..468227e 100644
--- a/llvm/include/llvm/IR/FloatingPointOps.def
+++ b/llvm/include/llvm/IR/FloatingPointOps.def
@@ -18,6 +18,7 @@
// - intrinsic function name,
// - DAG node corresponding to the intrinsic.
+FUNCTION(experimental_constrained_fadd, FADD)
FUNCTION(nearbyint, FNEARBYINT)
FUNCTION(trunc, FTRUNC)
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index 0e362d7..1073c29 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -636,6 +636,11 @@ RoundingMode CallBase::getRoundingMode() const {
if (RM)
return *RM;
+ // If this is a constrained intrinsic, get rounding mode from its metadata
+ // arguments.
+ if (auto *CI = dyn_cast<ConstrainedFPIntrinsic>(this))
+ return CI->getRoundingMode().value_or(RoundingMode::Dynamic);
+
// No FP bundle, try to guess from the current mode.
if (getParent())
if (auto *F = getFunction(); F)
@@ -658,6 +663,11 @@ fp::ExceptionBehavior CallBase::getExceptionBehavior() const {
if (EB)
return *EB;
+ // If this is a constrained intrinsic, get exception behavior from its
+ // metadata arguments.
+ if (auto *CI = dyn_cast<ConstrainedFPIntrinsic>(this))
+ return CI->getExceptionBehavior().value_or(fp::ebStrict);
+
// No FP bundle, try to guess from the current mode.
if (getParent())
if (auto *F = getFunction(); F)
diff --git a/llvm/unittests/IR/IRBuilderTest.cpp b/llvm/unittests/IR/IRBuilderTest.cpp
index 48a76c9..660dc45 100644
--- a/llvm/unittests/IR/IRBuilderTest.cpp
+++ b/llvm/unittests/IR/IRBuilderTest.cpp
@@ -662,6 +662,71 @@ TEST_F(IRBuilderTest, FPBundlesStrict) {
}
}
+TEST_F(IRBuilderTest, FPBundlesConstrained) {
+ F->addFnAttr(Attribute::StrictFP);
+
+ IRBuilder<> Builder(BB);
+ LLVMContext &Context = Builder.getContext();
+ Builder.setDefaultConstrainedExcept(fp::ebStrict);
+ Builder.setDefaultConstrainedRounding(RoundingMode::TowardZero);
+ Builder.setIsFPConstrained(true);
+
+ GlobalVariable *GVDouble = new GlobalVariable(
+ *M, Type::getDoubleTy(Ctx), true, GlobalValue::ExternalLinkage, nullptr);
+ Value *FnArg = Builder.CreateLoad(GVDouble->getValueType(), GVDouble);
+ Function *Fn = Intrinsic::getOrInsertDeclaration(
+ M.get(), Intrinsic::experimental_constrained_fadd,
+ {Type::getDoubleTy(Ctx)});
+
+ const auto createConstrainedRounding = [&](RoundingMode RM) {
+ std::optional<StringRef> RoundingStr = convertRoundingModeToStr(RM);
+ assert(RoundingStr);
+ auto *RoundingMDS = MDString::get(Context, *RoundingStr);
+ return MetadataAsValue::get(Context, RoundingMDS);
+ };
+ const auto createConstrainedExcept = [&](fp::ExceptionBehavior EB) {
+ std::optional<StringRef> ExceptStr = convertExceptionBehaviorToStr(EB);
+ assert(ExceptStr);
+ auto *ExceptMDS = MDString::get(Context, *ExceptStr);
+ return MetadataAsValue::get(Context, ExceptMDS);
+ };
+
+ // Constrained function call without bundles.
+ {
+ Value *V = Builder.CreateFAdd(FnArg, FnArg);
+ auto *I = cast<IntrinsicInst>(V);
+ EXPECT_FALSE(I->getOperandBundle(LLVMContext::OB_fp_control).has_value());
+ EXPECT_FALSE(I->getOperandBundle(LLVMContext::OB_fp_except).has_value());
+ EXPECT_EQ(Intrinsic::experimental_constrained_fadd, I->getIntrinsicID());
+ EXPECT_EQ(RoundingMode::TowardZero, I->getRoundingMode());
+ EXPECT_EQ(fp::ebStrict, I->getExceptionBehavior());
+ MemoryEffects ME = I->getMemoryEffects();
+ EXPECT_TRUE(ME.doesAccessInaccessibleMem());
+ }
+
+ // Operand bundles have precedence over constrained intrinsic metadata
+ // arguments.
+ {
+ SmallVector<OperandBundleDef, 1> Bundles;
+ llvm::addFPRoundingBundle(Ctx, Bundles, RoundingMode::TowardNegative);
+ llvm::addFPExceptionBundle(Ctx, Bundles, fp::ebIgnore);
+ Value *V = Builder.CreateCall(
+ Fn,
+ {FnArg, FnArg, createConstrainedRounding(RoundingMode::TowardZero),
+ createConstrainedExcept(fp::ebStrict)},
+ Bundles);
+
+ auto *I = cast<IntrinsicInst>(V);
+ EXPECT_TRUE(I->getOperandBundle(LLVMContext::OB_fp_control).has_value());
+ EXPECT_TRUE(I->getOperandBundle(LLVMContext::OB_fp_except).has_value());
+ EXPECT_EQ(Intrinsic::experimental_constrained_fadd, I->getIntrinsicID());
+ EXPECT_EQ(RoundingMode::TowardNegative, I->getRoundingMode());
+ EXPECT_EQ(fp::ebIgnore, I->getExceptionBehavior());
+ MemoryEffects ME = I->getMemoryEffects();
+ EXPECT_TRUE(ME.doesAccessInaccessibleMem());
+ }
+}
+
TEST_F(IRBuilderTest, Lifetime) {
IRBuilder<> Builder(BB);
AllocaInst *Var1 = Builder.CreateAlloca(Builder.getInt8Ty());