llvm.org GIT mirror llvm / fb8a52a
Teach the IRBuilder about fadd and friends. The IRBuilder has calls to create floating point instructions like fadd. It does not have calls to create constrained versions of them. This patch adds support for constrained creation of fadd, fsub, fmul, fdiv, and frem. Reviewed by: John McCall, Sanjay Patel Approved by: John McCall Differential Revision: https://reviews.llvm.org/D53157 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365339 91177308-0d34-0410-b5e6-96231b3b80d8 Kevin P. Neal 1 year, 4 months ago
5 changed file(s) with 289 addition(s) and 31 deletion(s). Raw diff Collapse all Expand all
3030 #include "llvm/IR/InstrTypes.h"
3131 #include "llvm/IR/Instruction.h"
3232 #include "llvm/IR/Instructions.h"
33 #include "llvm/IR/Intrinsics.h"
33 #include "llvm/IR/IntrinsicInst.h"
3434 #include "llvm/IR/LLVMContext.h"
3535 #include "llvm/IR/Module.h"
3636 #include "llvm/IR/Operator.h"
9595 MDNode *DefaultFPMathTag;
9696 FastMathFlags FMF;
9797
98 bool IsFPConstrained;
99 ConstrainedFPIntrinsic::ExceptionBehavior DefaultConstrainedExcept;
100 ConstrainedFPIntrinsic::RoundingMode DefaultConstrainedRounding;
101
98102 ArrayRef DefaultOperandBundles;
99103
100104 public:
101105 IRBuilderBase(LLVMContext &context, MDNode *FPMathTag = nullptr,
102106 ArrayRef OpBundles = None)
103 : Context(context), DefaultFPMathTag(FPMathTag),
107 : Context(context), DefaultFPMathTag(FPMathTag), IsFPConstrained(false),
108 DefaultConstrainedExcept(ConstrainedFPIntrinsic::ebStrict),
109 DefaultConstrainedRounding(ConstrainedFPIntrinsic::rmDynamic),
104110 DefaultOperandBundles(OpBundles) {
105111 ClearInsertionPoint();
106112 }
216222
217223 /// Set the fast-math flags to be used with generated fp-math operators
218224 void setFastMathFlags(FastMathFlags NewFMF) { FMF = NewFMF; }
225
226 /// Enable/Disable use of constrained floating point math. When
227 /// enabled the CreateF() calls instead create constrained
228 /// floating point intrinsic calls. Fast math flags are unaffected
229 /// by this setting.
230 void setIsFPConstrained(bool IsCon) { IsFPConstrained = IsCon; }
231
232 /// Query for the use of constrained floating point math
233 bool getIsFPConstrained() { return IsFPConstrained; }
234
235 /// Set the exception handling to be used with constrained floating point
236 void setDefaultConstrainedExcept(
237 ConstrainedFPIntrinsic::ExceptionBehavior NewExcept) {
238 DefaultConstrainedExcept = NewExcept;
239 }
240
241 /// Set the rounding mode handling to be used with constrained floating point
242 void setDefaultConstrainedRounding(
243 ConstrainedFPIntrinsic::RoundingMode NewRounding) {
244 DefaultConstrainedRounding = NewRounding;
245 }
246
247 /// Get the exception handling used with constrained floating point
248 ConstrainedFPIntrinsic::ExceptionBehavior getDefaultConstrainedExcept() {
249 return DefaultConstrainedExcept;
250 }
251
252 /// Get the rounding mode handling used with constrained floating point
253 ConstrainedFPIntrinsic::RoundingMode getDefaultConstrainedRounding() {
254 return DefaultConstrainedRounding;
255 }
219256
220257 //===--------------------------------------------------------------------===//
221258 // RAII helpers.
10441081 return (LC && RC) ? Insert(Folder.CreateBinOp(Opc, LC, RC), Name) : nullptr;
10451082 }
10461083
1084 Value *getConstrainedFPRounding(
1085 Optional Rounding) {
1086 ConstrainedFPIntrinsic::RoundingMode UseRounding =
1087 DefaultConstrainedRounding;
1088
1089 if (Rounding.hasValue())
1090 UseRounding = Rounding.getValue();
1091
1092 Optional RoundingStr =
1093 ConstrainedFPIntrinsic::RoundingModeToStr(UseRounding);
1094 assert(RoundingStr.hasValue() && "Garbage strict rounding mode!");
1095 auto *RoundingMDS = MDString::get(Context, RoundingStr.getValue());
1096
1097 return MetadataAsValue::get(Context, RoundingMDS);
1098 }
1099
1100 Value *getConstrainedFPExcept(
1101 Optional Except) {
1102 ConstrainedFPIntrinsic::ExceptionBehavior UseExcept =
1103 DefaultConstrainedExcept;
1104
1105 if (Except.hasValue())
1106 UseExcept = Except.getValue();
1107
1108 Optional ExceptStr =
1109 ConstrainedFPIntrinsic::ExceptionBehaviorToStr(UseExcept);
1110 assert(ExceptStr.hasValue() && "Garbage strict exception behavior!");
1111 auto *ExceptMDS = MDString::get(Context, ExceptStr.getValue());
1112
1113 return MetadataAsValue::get(Context, ExceptMDS);
1114 }
1115
10471116 public:
10481117 Value *CreateAdd(Value *LHS, Value *RHS, const Twine &Name = "",
10491118 bool HasNUW = false, bool HasNSW = false) {
12621331
12631332 Value *CreateFAdd(Value *L, Value *R, const Twine &Name = "",
12641333 MDNode *FPMD = nullptr) {
1334 if (IsFPConstrained)
1335 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fadd,
1336 L, R, nullptr, Name, FPMD);
1337
12651338 if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V;
12661339 Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), FPMD, FMF);
12671340 return Insert(I, Name);
12711344 /// default FMF.
12721345 Value *CreateFAddFMF(Value *L, Value *R, Instruction *FMFSource,
12731346 const Twine &Name = "") {
1347 if (IsFPConstrained)
1348 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fadd,
1349 L, R, FMFSource, Name);
1350
12741351 if (Value *V = foldConstant(Instruction::FAdd, L, R, Name)) return V;
12751352 Instruction *I = setFPAttrs(BinaryOperator::CreateFAdd(L, R), nullptr,
12761353 FMFSource->getFastMathFlags());
12791356
12801357 Value *CreateFSub(Value *L, Value *R, const Twine &Name = "",
12811358 MDNode *FPMD = nullptr) {
1359 if (IsFPConstrained)
1360 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fsub,
1361 L, R, nullptr, Name, FPMD);
1362
12821363 if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V;
12831364 Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), FPMD, FMF);
12841365 return Insert(I, Name);
12881369 /// default FMF.
12891370 Value *CreateFSubFMF(Value *L, Value *R, Instruction *FMFSource,
12901371 const Twine &Name = "") {
1372 if (IsFPConstrained)
1373 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fsub,
1374 L, R, FMFSource, Name);
1375
12911376 if (Value *V = foldConstant(Instruction::FSub, L, R, Name)) return V;
12921377 Instruction *I = setFPAttrs(BinaryOperator::CreateFSub(L, R), nullptr,
12931378 FMFSource->getFastMathFlags());
12961381
12971382 Value *CreateFMul(Value *L, Value *R, const Twine &Name = "",
12981383 MDNode *FPMD = nullptr) {
1384 if (IsFPConstrained)
1385 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fmul,
1386 L, R, nullptr, Name, FPMD);
1387
12991388 if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V;
13001389 Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), FPMD, FMF);
13011390 return Insert(I, Name);
13051394 /// default FMF.
13061395 Value *CreateFMulFMF(Value *L, Value *R, Instruction *FMFSource,
13071396 const Twine &Name = "") {
1397 if (IsFPConstrained)
1398 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fmul,
1399 L, R, FMFSource, Name);
1400
13081401 if (Value *V = foldConstant(Instruction::FMul, L, R, Name)) return V;
13091402 Instruction *I = setFPAttrs(BinaryOperator::CreateFMul(L, R), nullptr,
13101403 FMFSource->getFastMathFlags());
13131406
13141407 Value *CreateFDiv(Value *L, Value *R, const Twine &Name = "",
13151408 MDNode *FPMD = nullptr) {
1409 if (IsFPConstrained)
1410 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fdiv,
1411 L, R, nullptr, Name, FPMD);
1412
13161413 if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V;
13171414 Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), FPMD, FMF);
13181415 return Insert(I, Name);
13221419 /// default FMF.
13231420 Value *CreateFDivFMF(Value *L, Value *R, Instruction *FMFSource,
13241421 const Twine &Name = "") {
1422 if (IsFPConstrained)
1423 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_fdiv,
1424 L, R, FMFSource, Name);
1425
13251426 if (Value *V = foldConstant(Instruction::FDiv, L, R, Name)) return V;
13261427 Instruction *I = setFPAttrs(BinaryOperator::CreateFDiv(L, R), nullptr,
13271428 FMFSource->getFastMathFlags());
13301431
13311432 Value *CreateFRem(Value *L, Value *R, const Twine &Name = "",
13321433 MDNode *FPMD = nullptr) {
1434 if (IsFPConstrained)
1435 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_frem,
1436 L, R, nullptr, Name, FPMD);
1437
13331438 if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V;
13341439 Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), FPMD, FMF);
13351440 return Insert(I, Name);
13391444 /// default FMF.
13401445 Value *CreateFRemFMF(Value *L, Value *R, Instruction *FMFSource,
13411446 const Twine &Name = "") {
1447 if (IsFPConstrained)
1448 return CreateConstrainedFPBinOp(Intrinsic::experimental_constrained_frem,
1449 L, R, FMFSource, Name);
1450
13421451 if (Value *V = foldConstant(Instruction::FRem, L, R, Name)) return V;
13431452 Instruction *I = setFPAttrs(BinaryOperator::CreateFRem(L, R), nullptr,
13441453 FMFSource->getFastMathFlags());
13531462 if (isa(BinOp))
13541463 BinOp = setFPAttrs(BinOp, FPMathTag, FMF);
13551464 return Insert(BinOp, Name);
1465 }
1466
1467 CallInst *CreateConstrainedFPBinOp(
1468 Intrinsic::ID ID, Value *L, Value *R, Instruction *FMFSource = nullptr,
1469 const Twine &Name = "", MDNode *FPMathTag = nullptr,
1470 Optional Rounding = None,
1471 Optional Except = None) {
1472 Value *RoundingV = getConstrainedFPRounding(Rounding);
1473 Value *ExceptV = getConstrainedFPExcept(Except);
1474
1475 FastMathFlags UseFMF = FMF;
1476 if (FMFSource)
1477 UseFMF = FMFSource->getFastMathFlags();
1478
1479 CallInst *C = CreateIntrinsic(ID, {L->getType()},
1480 {L, R, RoundingV, ExceptV}, nullptr, Name);
1481 return cast(setFPAttrs(C, FPMathTag, UseFMF));
13561482 }
13571483
13581484 Value *CreateNeg(Value *V, const Twine &Name = "",
207207 /// This is the common base class for constrained floating point intrinsics.
208208 class ConstrainedFPIntrinsic : public IntrinsicInst {
209209 public:
210 enum RoundingMode {
211 rmInvalid,
212 rmDynamic,
213 rmToNearest,
214 rmDownward,
215 rmUpward,
216 rmTowardZero
210 /// Specifies the rounding mode to be assumed. This is only used when
211 /// when constrained floating point is enabled. See the LLVM Language
212 /// Reference Manual for details.
213 enum RoundingMode : uint8_t {
214 rmDynamic, ///< This corresponds to "fpround.dynamic".
215 rmToNearest, ///< This corresponds to "fpround.tonearest".
216 rmDownward, ///< This corresponds to "fpround.downward".
217 rmUpward, ///< This corresponds to "fpround.upward".
218 rmTowardZero ///< This corresponds to "fpround.tozero".
217219 };
218220
219 enum ExceptionBehavior {
220 ebInvalid,
221 ebIgnore,
222 ebMayTrap,
223 ebStrict
221 /// Specifies the required exception behavior. This is only used when
222 /// when constrained floating point is used. See the LLVM Language
223 /// Reference Manual for details.
224 enum ExceptionBehavior : uint8_t {
225 ebIgnore, ///< This corresponds to "fpexcept.ignore".
226 ebMayTrap, ///< This corresponds to "fpexcept.maytrap".
227 ebStrict ///< This corresponds to "fpexcept.strict".
224228 };
225229
226230 bool isUnaryOp() const;
227231 bool isTernaryOp() const;
228 RoundingMode getRoundingMode() const;
229 ExceptionBehavior getExceptionBehavior() const;
232 Optional getRoundingMode() const;
233 Optional getExceptionBehavior() const;
234
235 /// Returns a valid RoundingMode enumerator when given a string
236 /// that is valid as input in constrained intrinsic rounding mode
237 /// metadata.
238 static Optional StrToRoundingMode(StringRef);
239
240 /// For any RoundingMode enumerator, returns a string valid as input in
241 /// constrained intrinsic rounding mode metadata.
242 static Optional RoundingModeToStr(RoundingMode);
243
244 /// Returns a valid ExceptionBehavior enumerator when given a string
245 /// valid as input in constrained intrinsic exception behavior metadata.
246 static Optional StrToExceptionBehavior(StringRef);
247
248 /// For any ExceptionBehavior enumerator, returns a string valid as
249 /// input in constrained intrinsic exception behavior metadata.
250 static Optional ExceptionBehaviorToStr(ExceptionBehavior);
230251
231252 // Methods for support type inquiry through isa, cast, and dyn_cast:
232253 static bool classof(const IntrinsicInst *I) {
102102 return ConstantInt::get(Type::getInt64Ty(Context), 1);
103103 }
104104
105 ConstrainedFPIntrinsic::RoundingMode
105 Optional
106106 ConstrainedFPIntrinsic::getRoundingMode() const {
107107 unsigned NumOperands = getNumArgOperands();
108108 Metadata *MD =
109109 dyn_cast(getArgOperand(NumOperands - 2))->getMetadata();
110110 if (!MD || !isa(MD))
111 return rmInvalid;
112 StringRef RoundingArg = cast(MD)->getString();
113
111 return None;
112 return StrToRoundingMode(cast(MD)->getString());
113 }
114
115 Optional
116 ConstrainedFPIntrinsic::StrToRoundingMode(StringRef RoundingArg) {
114117 // For dynamic rounding mode, we use round to nearest but we will set the
115118 // 'exact' SDNodeFlag so that the value will not be rounded.
116 return StringSwitch<RoundingMode>(RoundingArg)
119 return StringSwitch<Optional>(RoundingArg)
117120 .Case("round.dynamic", rmDynamic)
118121 .Case("round.tonearest", rmToNearest)
119122 .Case("round.downward", rmDownward)
120123 .Case("round.upward", rmUpward)
121124 .Case("round.towardzero", rmTowardZero)
122 .Default(rmInvalid);
123 }
124
125 ConstrainedFPIntrinsic::ExceptionBehavior
125 .Default(None);
126 }
127
128 Optional
129 ConstrainedFPIntrinsic::RoundingModeToStr(RoundingMode UseRounding) {
130 Optional RoundingStr = None;
131 switch (UseRounding) {
132 case ConstrainedFPIntrinsic::rmDynamic:
133 RoundingStr = "round.dynamic";
134 break;
135 case ConstrainedFPIntrinsic::rmToNearest:
136 RoundingStr = "round.tonearest";
137 break;
138 case ConstrainedFPIntrinsic::rmDownward:
139 RoundingStr = "round.downward";
140 break;
141 case ConstrainedFPIntrinsic::rmUpward:
142 RoundingStr = "round.upward";
143 break;
144 case ConstrainedFPIntrinsic::rmTowardZero:
145 RoundingStr = "round.tozero";
146 break;
147 }
148 return RoundingStr;
149 }
150
151 Optional
126152 ConstrainedFPIntrinsic::getExceptionBehavior() const {
127153 unsigned NumOperands = getNumArgOperands();
128154 Metadata *MD =
129155 dyn_cast(getArgOperand(NumOperands - 1))->getMetadata();
130156 if (!MD || !isa(MD))
131 return ebInvalid;
132 StringRef ExceptionArg = cast(MD)->getString();
133 return StringSwitch(ExceptionArg)
157 return None;
158 return StrToExceptionBehavior(cast(MD)->getString());
159 }
160
161 Optional
162 ConstrainedFPIntrinsic::StrToExceptionBehavior(StringRef ExceptionArg) {
163 return StringSwitch>(ExceptionArg)
134164 .Case("fpexcept.ignore", ebIgnore)
135165 .Case("fpexcept.maytrap", ebMayTrap)
136166 .Case("fpexcept.strict", ebStrict)
137 .Default(ebInvalid);
167 .Default(None);
168 }
169
170 Optional
171 ConstrainedFPIntrinsic::ExceptionBehaviorToStr(ExceptionBehavior UseExcept) {
172 Optional ExceptStr = None;
173 switch (UseExcept) {
174 case ConstrainedFPIntrinsic::ebStrict:
175 ExceptStr = "fpexcept.strict";
176 break;
177 case ConstrainedFPIntrinsic::ebIgnore:
178 ExceptStr = "fpexcept.ignore";
179 break;
180 case ConstrainedFPIntrinsic::ebMayTrap:
181 ExceptStr = "fpexcept.maytrap";
182 break;
183 }
184 return ExceptStr;
138185 }
139186
140187 bool ConstrainedFPIntrinsic::isUnaryOp() const {
47754775 // argument type check is needed here.
47764776
47774777 if (HasExceptionMD) {
4778 Assert(FPI.getExceptionBehavior() != ConstrainedFPIntrinsic::ebInvalid,
4778 Assert(FPI.getExceptionBehavior().hasValue(),
47794779 "invalid exception behavior argument", &FPI);
47804780 }
47814781 if (HasRoundingMD) {
4782 Assert(FPI.getRoundingMode() != ConstrainedFPIntrinsic::rmInvalid,
4782 Assert(FPI.getRoundingMode().hasValue(),
47834783 "invalid rounding mode argument", &FPI);
47844784 }
47854785 }
119119 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::fma);
120120 EXPECT_TRUE(II->hasNoInfs());
121121 EXPECT_FALSE(II->hasNoNaNs());
122 }
123
124 TEST_F(IRBuilderTest, ConstrainedFP) {
125 IRBuilder<> Builder(BB);
126 Value *V;
127 CallInst *Call;
128 IntrinsicInst *II;
129
130 V = Builder.CreateLoad(GV);
131
132 // See if we get constrained intrinsics instead of non-constrained
133 // instructions.
134 Builder.setIsFPConstrained(true);
135
136 V = Builder.CreateFAdd(V, V);
137 ASSERT_TRUE(isa(V));
138 II = cast(V);
139 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fadd);
140
141 V = Builder.CreateFSub(V, V);
142 ASSERT_TRUE(isa(V));
143 II = cast(V);
144 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fsub);
145
146 V = Builder.CreateFMul(V, V);
147 ASSERT_TRUE(isa(V));
148 II = cast(V);
149 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fmul);
150
151 V = Builder.CreateFDiv(V, V);
152 ASSERT_TRUE(isa(V));
153 II = cast(V);
154 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_fdiv);
155
156 V = Builder.CreateFRem(V, V);
157 ASSERT_TRUE(isa(V));
158 II = cast(V);
159 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::experimental_constrained_frem);
160
161 // Verify the codepaths for setting and overriding the default metadata.
162 V = Builder.CreateFAdd(V, V);
163 ASSERT_TRUE(isa(V));
164 auto *CII = cast(V);
165 ASSERT_TRUE(CII->getExceptionBehavior() == ConstrainedFPIntrinsic::ebStrict);
166 ASSERT_TRUE(CII->getRoundingMode() == ConstrainedFPIntrinsic::rmDynamic);
167
168 Builder.setDefaultConstrainedExcept(ConstrainedFPIntrinsic::ebIgnore);
169 Builder.setDefaultConstrainedRounding(ConstrainedFPIntrinsic::rmUpward);
170 V = Builder.CreateFAdd(V, V);
171 CII = cast(V);
172 ASSERT_TRUE(CII->getExceptionBehavior() == ConstrainedFPIntrinsic::ebIgnore);
173 ASSERT_TRUE(CII->getRoundingMode() == ConstrainedFPIntrinsic::rmUpward);
174
175 // Now override the defaults.
176 Call = Builder.CreateConstrainedFPBinOp(
177 Intrinsic::experimental_constrained_fadd, V, V, nullptr, "", nullptr,
178 ConstrainedFPIntrinsic::rmDownward, ConstrainedFPIntrinsic::ebMayTrap);
179 CII = cast(Call);
180 EXPECT_EQ(CII->getIntrinsicID(), Intrinsic::experimental_constrained_fadd);
181 ASSERT_TRUE(CII->getExceptionBehavior() == ConstrainedFPIntrinsic::ebMayTrap);
182 ASSERT_TRUE(CII->getRoundingMode() == ConstrainedFPIntrinsic::rmDownward);
183
184 Builder.CreateRetVoid();
185 EXPECT_FALSE(verifyModule(*M));
122186 }
123187
124188 TEST_F(IRBuilderTest, Lifetime) {