mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-19 05:50:46 +00:00
Mapping of FP operations to constrained intrinsics
A new function 'getConstrainedIntrinsic' is added, which for any gived instruction returns id of the corresponding constrained intrinsic. If there is no constrained counterpart for the instruction or the instruction is already a constrained intrinsic, the function returns zero. Differential Revision: https://reviews.llvm.org/D69562
This commit is contained in:
parent
793b7f903d
commit
115b3ace36
@ -22,6 +22,12 @@
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
|
||||
namespace Intrinsic {
|
||||
typedef unsigned ID;
|
||||
}
|
||||
|
||||
class Instruction;
|
||||
|
||||
namespace fp {
|
||||
|
||||
/// Exception behavior used for floating point operations.
|
||||
@ -60,6 +66,12 @@ inline bool isDefaultFPEnvironment(fp::ExceptionBehavior EB, RoundingMode RM) {
|
||||
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) {
|
||||
|
@ -14,6 +14,9 @@
|
||||
|
||||
#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 {
|
||||
|
||||
@ -82,4 +85,46 @@ convertExceptionBehaviorToStr(fp::ExceptionBehavior UseExcept) {
|
||||
}
|
||||
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
|
||||
|
@ -17,6 +17,7 @@
|
||||
#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"
|
||||
@ -507,6 +508,59 @@ TEST(InstructionsTest, FPMathOperator) {
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user