namespace llvm {
class StringRef;
+namespace Intrinsic {
+typedef unsigned ID;
+}
+
+class Instruction;
+
namespace fp {
/// Exception behavior used for floating point operations.
return EB == fp::ebIgnore && RM == RoundingMode::NearestTiesToEven;
}
+/// Returns constrained intrinsic id to represent the given instruction in
+/// strictfp function. If the instruction is already a constrained intrinsic or
+/// does not have a constrained intrinsic counterpart, the function returns
+/// zero.
+Intrinsic::ID getConstrainedIntrinsicID(const Instruction &Instr);
+
/// Returns true if the rounding mode RM may be QRM at compile time or
/// at run time.
inline bool canRoundingModeBe(RoundingMode RM, RoundingMode QRM) {
#include "llvm/IR/FPEnv.h"
#include "llvm/ADT/StringSwitch.h"
+#include "llvm/IR/InstrTypes.h"
+#include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Intrinsics.h"
namespace llvm {
}
return ExceptStr;
}
+
+Intrinsic::ID getConstrainedIntrinsicID(const Instruction &Instr) {
+ Intrinsic::ID IID = Intrinsic::not_intrinsic;
+ switch (Instr.getOpcode()) {
+ case Instruction::FCmp:
+ // Unlike other instructions FCmp can be mapped to one of two intrinsic
+ // functions. We choose the non-signaling variant.
+ IID = Intrinsic::experimental_constrained_fcmp;
+ break;
+
+ // Instructions
+#define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \
+ case Instruction::NAME: \
+ IID = Intrinsic::INTRINSIC; \
+ break;
+#define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
+#define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
+#include "llvm/IR/ConstrainedOps.def"
+
+ // Intrinsic calls.
+ case Instruction::Call:
+ if (auto *IntrinCall = dyn_cast<IntrinsicInst>(&Instr)) {
+ switch (IntrinCall->getIntrinsicID()) {
+#define FUNCTION(NAME, NARG, ROUND_MODE, INTRINSIC) \
+ case Intrinsic::NAME: \
+ IID = Intrinsic::INTRINSIC; \
+ break;
+#define INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC)
+#define CMP_INSTRUCTION(NAME, NARG, ROUND_MODE, INTRINSIC, DAGN)
+#include "llvm/IR/ConstrainedOps.def"
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return IID;
+}
+
} // namespace llvm
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/FPEnv.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/LLVMContext.h"
I->deleteValue();
}
+TEST(InstructionTest, ConstrainedTrans) {
+ LLVMContext Context;
+ std::unique_ptr<Module> M(new Module("MyModule", Context));
+ FunctionType *FTy =
+ FunctionType::get(Type::getVoidTy(Context),
+ {Type::getFloatTy(Context), Type::getFloatTy(Context),
+ Type::getInt32Ty(Context)},
+ false);
+ auto *F = Function::Create(FTy, Function::ExternalLinkage, "", M.get());
+ auto *BB = BasicBlock::Create(Context, "bb", F);
+ IRBuilder<> Builder(Context);
+ Builder.SetInsertPoint(BB);
+ auto *Arg0 = F->arg_begin();
+ auto *Arg1 = F->arg_begin() + 1;
+
+ {
+ auto *I = cast<Instruction>(Builder.CreateFAdd(Arg0, Arg1));
+ EXPECT_EQ(Intrinsic::experimental_constrained_fadd,
+ getConstrainedIntrinsicID(*I));
+ }
+
+ {
+ auto *I = cast<Instruction>(
+ Builder.CreateFPToSI(Arg0, Type::getInt32Ty(Context)));
+ EXPECT_EQ(Intrinsic::experimental_constrained_fptosi,
+ getConstrainedIntrinsicID(*I));
+ }
+
+ {
+ auto *I = cast<Instruction>(Builder.CreateIntrinsic(
+ Intrinsic::ceil, {Type::getFloatTy(Context)}, {Arg0}));
+ EXPECT_EQ(Intrinsic::experimental_constrained_ceil,
+ getConstrainedIntrinsicID(*I));
+ }
+
+ {
+ auto *I = cast<Instruction>(Builder.CreateFCmpOEQ(Arg0, Arg1));
+ EXPECT_EQ(Intrinsic::experimental_constrained_fcmp,
+ getConstrainedIntrinsicID(*I));
+ }
+
+ {
+ auto *Arg2 = F->arg_begin() + 2;
+ auto *I = cast<Instruction>(Builder.CreateAdd(Arg2, Arg2));
+ EXPECT_EQ(Intrinsic::not_intrinsic, getConstrainedIntrinsicID(*I));
+ }
+
+ {
+ auto *I = cast<Instruction>(Builder.CreateConstrainedFPBinOp(
+ Intrinsic::experimental_constrained_fadd, Arg0, Arg0));
+ EXPECT_EQ(Intrinsic::not_intrinsic, getConstrainedIntrinsicID(*I));
+ }
+}
TEST(InstructionsTest, isEliminableCastPair) {
LLVMContext C;