diff --git a/llvm/include/llvm/IR/FloatingPoint.h b/llvm/include/llvm/IR/FloatingPoint.h --- a/llvm/include/llvm/IR/FloatingPoint.h +++ b/llvm/include/llvm/IR/FloatingPoint.h @@ -21,6 +21,12 @@ namespace llvm { +namespace Intrinsic { +enum ID : unsigned; +} + +class Instruction; + /// Rounding mode used for floating point operations. /// /// Each of these values correspond to some metadata argument value of a @@ -62,5 +68,11 @@ /// input in constrained intrinsic exception behavior metadata. Optional ExceptionBehaviorToStr(ExceptionBehavior); +/// Returns constrained intrinsic id to represent the source instruction, if +/// it involves floating point operations. If the instruction is already a +/// constrained intrinsic or does not involve floating point operations, the +/// function returns zero. +Intrinsic::ID getConstainedIntrinsic(const Instruction &Instr); + } #endif diff --git a/llvm/lib/IR/FloatingPoint.cpp b/llvm/lib/IR/FloatingPoint.cpp --- a/llvm/lib/IR/FloatingPoint.cpp +++ b/llvm/lib/IR/FloatingPoint.cpp @@ -14,6 +14,9 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/IR/FloatingPoint.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/IntrinsicInst.h" namespace llvm { @@ -75,4 +78,106 @@ return ExceptStr; } +Intrinsic::ID getConstainedIntrinsic(const Instruction &Instr) { + Intrinsic::ID IID = Intrinsic::not_intrinsic; + switch (Instr.getOpcode()) { + case Instruction::FAdd: + IID = Intrinsic::experimental_constrained_fadd; + break; + case Instruction::FSub: + IID = Intrinsic::experimental_constrained_fsub; + break; + case Instruction::FMul: + IID = Intrinsic::experimental_constrained_fmul; + break; + case Instruction::FDiv: + IID = Intrinsic::experimental_constrained_fdiv; + break; + case Instruction::FRem: + IID = Intrinsic::experimental_constrained_frem; + break; + case Instruction::FPExt: + IID = Intrinsic::experimental_constrained_fpext; + break; + case Instruction::FPToSI: + IID = Intrinsic::experimental_constrained_fptosi; + break; + case Instruction::FPToUI: + IID = Intrinsic::experimental_constrained_fptoui; + break; + case Instruction::FPTrunc: + IID = Intrinsic::experimental_constrained_fptrunc; + break; + case Instruction::Call: + if (auto *IntrinCall = dyn_cast(&Instr)) { + switch (IntrinCall->getIntrinsicID()) { + case Intrinsic::ceil: + IID = Intrinsic::experimental_constrained_ceil; + break; + case Intrinsic::cos: + IID = Intrinsic::experimental_constrained_cos; + break; + case Intrinsic::exp: + IID = Intrinsic::experimental_constrained_exp; + break; + case Intrinsic::exp2: + IID = Intrinsic::experimental_constrained_exp2; + break; + case Intrinsic::floor: + IID = Intrinsic::experimental_constrained_floor; + break; + case Intrinsic::fma: + IID = Intrinsic::experimental_constrained_fma; + break; + case Intrinsic::log: + IID = Intrinsic::experimental_constrained_log; + break; + case Intrinsic::log10: + IID = Intrinsic::experimental_constrained_log10; + break; + case Intrinsic::log2: + IID = Intrinsic::experimental_constrained_log2; + break; + case Intrinsic::maxnum: + IID = Intrinsic::experimental_constrained_maxnum; + break; + case Intrinsic::minnum: + IID = Intrinsic::experimental_constrained_minnum; + break; + case Intrinsic::nearbyint: + IID = Intrinsic::experimental_constrained_nearbyint; + break; + case Intrinsic::pow: + IID = Intrinsic::experimental_constrained_pow; + break; + case Intrinsic::powi: + IID = Intrinsic::experimental_constrained_powi; + break; + case Intrinsic::rint: + IID = Intrinsic::experimental_constrained_rint; + break; + case Intrinsic::round: + IID = Intrinsic::experimental_constrained_round; + break; + case Intrinsic::sin: + IID = Intrinsic::experimental_constrained_sin; + break; + case Intrinsic::sqrt: + IID = Intrinsic::experimental_constrained_sqrt; + break; + case Intrinsic::trunc: + IID = Intrinsic::experimental_constrained_trunc; + break; + default: + break; + } + } + break; + default: + break; + } + + return IID; +} + } \ No newline at end of file diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp --- a/llvm/unittests/IR/InstructionsTest.cpp +++ b/llvm/unittests/IR/InstructionsTest.cpp @@ -14,6 +14,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/FloatingPoint.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LLVMContext.h" @@ -419,6 +420,49 @@ I->deleteValue(); } +TEST(InstructionTest, ConstrainedTrans) { + LLVMContext Context; + std::unique_ptr M(new Module("MyModule", Context)); + FunctionType *FTy = FunctionType::get(Type::getVoidTy(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 *I = cast(Builder.CreateFAdd(Arg0, Arg0)); + EXPECT_TRUE(getConstainedIntrinsic(*I) + == Intrinsic::experimental_constrained_fadd); + } + + { + auto *I = cast( + Builder.CreateFPToSI(Arg0, Type::getInt32Ty(Context))); + EXPECT_TRUE(getConstainedIntrinsic(*I) == + Intrinsic::experimental_constrained_fptosi); + } + + { + auto *I = cast(Builder.CreateIntrinsic(Intrinsic::ceil, + { Type::getFloatTy(Context) }, { Arg0 })); + EXPECT_TRUE(getConstainedIntrinsic(*I) + == Intrinsic::experimental_constrained_ceil); + } + + { + auto *Arg1 = F->arg_begin() + 1; + auto *I = cast(Builder.CreateAdd(Arg1, Arg1)); + EXPECT_TRUE(getConstainedIntrinsic(*I) == Intrinsic::not_intrinsic); + } + + { + auto *I = cast(Builder.CreateConstrainedFPBinOp( + Intrinsic::experimental_constrained_fadd, Arg0, Arg0)); + EXPECT_TRUE(getConstainedIntrinsic(*I) == Intrinsic::not_intrinsic); + } +} TEST(InstructionsTest, isEliminableCastPair) { LLVMContext C;