52#include <system_error>
58#define DEBUG_TYPE "instrumentor"
64 "instrumentor-write-config-file",
66 "Write the instrumentor configuration into the specified JSON file"),
71 "instrumentor-read-config-file",
73 "Read the instrumentor configuration from the specified JSON file"),
78template <
typename IRBuilderTy>
void ensureDbgLoc(IRBuilderTy &IRB) {
79 if (IRB.getCurrentDebugLocation())
81 auto *BB = IRB.GetInsertBlock();
82 if (
auto *SP = BB->getParent()->getSubprogram())
83 IRB.SetCurrentDebugLocation(
DILocation::get(BB->getContext(), 0, 0, SP));
87template <
typename IRBTy>
89 bool AllowTruncate =
false) {
92 Type *VTy = V->getType();
97 TypeSize RequestedSize =
DL.getTypeSizeInBits(Ty);
98 TypeSize ValueSize =
DL.getTypeSizeInBits(VTy);
99 bool ShouldTruncate = RequestedSize < ValueSize;
100 if (ShouldTruncate && !AllowTruncate)
102 if (ShouldTruncate && AllowTruncate)
103 return tryToCast(IRB,
104 IRB.CreateIntCast(V, IRB.getIntNTy(RequestedSize),
106 Ty,
DL, AllowTruncate);
108 return IRB.CreatePointerBitCastOrAddrSpaceCast(V, Ty);
110 return IRB.CreateIntCast(V, Ty,
false);
112 return tryToCast(IRB, IRB.CreateBitCast(V, IRB.getIntNTy(ValueSize)), Ty,
115 return IRB.CreateBitOrPointerCast(V, Ty);
119template <
typename Ty>
121 return ConstantInt::get(
IT, Val, IsSigned);
126class InstrumentorImpl final {
131 : IConf(IConf), M(M), IIRB(IIRB) {
140 bool shouldInstrumentTarget();
143 bool shouldInstrumentFunction(
Function &Fn);
150 bool instrumentFunction(
Function &Fn);
170bool InstrumentorImpl::shouldInstrumentTarget() {
172 const bool IsGPU =
T.
isAMDGPU() ||
T.isNVPTX();
174 bool RegexMatches =
true;
175 const auto TargetRegexStr = IConf.
TargetRegex->getString();
176 if (!TargetRegexStr.empty()) {
177 llvm::Regex TargetRegex(TargetRegexStr);
179 if (!TargetRegex.isValid(ErrMsg)) {
181 Twine(
"failed to parse target regex: ") + ErrMsg,
DS_Warning));
184 RegexMatches = TargetRegex.match(
T.str());
188 return ((IsGPU && IConf.
GPUEnabled->getBool()) ||
193bool InstrumentorImpl::shouldInstrumentFunction(Function &Fn) {
200bool InstrumentorImpl::instrumentInstruction(Instruction &
I,
201 InstrumentationCaches &ICaches) {
212 if (
auto *IO = InstChoicesPRE.lookup(
I.getOpcode())) {
213 IIRB.
IRB.SetInsertPoint(&
I);
214 ensureDbgLoc(IIRB.
IRB);
215 Changed |= bool(IO->instrument(IPtr, IConf, IIRB, ICaches));
218 if (
auto *IO = InstChoicesPOST.lookup(
I.getOpcode())) {
219 IIRB.
IRB.SetInsertPoint(
I.getNextNode());
220 ensureDbgLoc(IIRB.
IRB);
221 Changed |= bool(IO->instrument(IPtr, IConf, IIRB, ICaches));
228bool InstrumentorImpl::instrumentFunction(Function &Fn) {
230 if (!shouldInstrumentFunction(Fn))
233 InstrumentationCaches ICaches;
234 ReversePostOrderTraversal<Function *> RPOT(&Fn);
235 for (
auto &It : RPOT)
237 Changed |= instrumentInstruction(
I, ICaches);
242bool InstrumentorImpl::instrument() {
244 if (!shouldInstrumentTarget())
248 if (It.second->Enabled)
249 InstChoicesPRE[It.second->getOpcode()] = It.second;
251 if (It.second->Enabled)
252 InstChoicesPOST[It.second->getOpcode()] = It.second;
254 for (Function &Fn : M)
255 Changed |= instrumentFunction(Fn);
260PreservedAnalyses InstrumentorPass::run(
Module &M, InstrumentationConfig &IConf,
261 InstrumentorIRBuilderTy &IIRB,
263 InstrumentorImpl Impl(IConf, IIRB, M);
271 bool Changed = Impl.instrument();
279 std::unique_ptr<InstrumentationConfig> IConfInt(
280 !UserIConf ?
new InstrumentationConfig() :
nullptr);
281 std::unique_ptr<InstrumentorIRBuilderTy> IIRBInt(
282 !UserIIRB ?
new InstrumentorIRBuilderTy(M) :
nullptr);
284 auto *IConf = IConfInt ? IConfInt.get() : UserIConf;
285 auto *IIRB = IIRBInt ? IIRBInt.get() : UserIIRB;
287 auto PA = run(M, *IConf, *IIRB, !UserIConf);
293std::unique_ptr<BaseConfigurationOption>
299 BCO->setBool(DefaultValue);
304std::unique_ptr<BaseConfigurationOption>
311 BCO->setString(DefaultValue);
327 Twine(
"registered two instrumentation opportunities for the same "
349 if (V.getType()->isVoidTy())
351 return tryToCast(IIRB.
IRB, &V, &Ty,
352 IIRB.
IRB.GetInsertBlock()->getDataLayout());
358 if (V.getType()->isVoidTy())
361 auto *NewVCasted = &NewV;
364 IIRB.
IRB.SetInsertPoint(
I->getNextNode());
365 ensureDbgLoc(IIRB.
IRB);
366 NewVCasted = tryToCast(IIRB.
IRB, &NewV, V.
getType(), IIRB.
DL,
381 for (
auto &It :
IO.IRTArgs) {
384 NumReplaceableArgs += bool(It.Flags & IRTArg::REPLACABLE);
385 MightRequireIndirection |= It.Flags & IRTArg::POTENTIALLY_INDIRECT;
396 "Wrong indirection setting!");
399 for (
auto &It :
IO.IRTArgs) {
428 auto IP = IIRB.
IRB.GetInsertPoint();
431 for (
auto &It :
IO.IRTArgs) {
435 if (!Param || It.NoCache)
437 Param = It.GetterCB(*V, *It.Ty, IConf, IIRB);
440 if (Param->getType()->isVoidTy()) {
442 }
else if (Param->getType()->isAggregateType() ||
443 DL.getTypeSizeInBits(Param->getType()) >
444 DL.getTypeSizeInBits(It.Ty)) {
447 Twine(
"indirection needed for ") + It.Name +
Twine(
" in ") +
449 Twine(
", but not indicated. Instrumentation is skipped"),
453 ForceIndirection =
true;
455 Param = tryToCast(IIRB.
IRB, Param, It.Ty,
DL);
460 if (ForceIndirection) {
461 Function *Fn = IIRB.
IRB.GetInsertBlock()->getParent();
464 for (
auto &It :
IO.IRTArgs) {
472 auto *&CallParam = CallParams[
Offset++];
474 CallParams.
insert(&CallParam + 1, IIRB.
IRB.getInt32(
DL.getTypeStoreSize(
475 CallParam->getType())));
482 CallParam = CachedParam;
487 IIRB.
IRB.CreateStore(CallParam, AI);
488 CallParam = CachedParam = AI;
492 if (!ForceIndirection)
493 IIRB.
IRB.SetInsertPoint(IP);
494 ensureDbgLoc(IIRB.
IRB);
498 IConf.
getRTName(
IO.IP.isPRE() ?
"pre_" :
"post_",
IO.getName(),
499 ForceIndirection ?
"_ind" :
"");
500 auto FC = IIRB.
IRB.GetInsertBlock()->getModule()->getOrInsertFunction(
502 auto *CI = IIRB.
IRB.CreateCall(FC, CallParams);
505 for (
unsigned I = 0, E =
IO.IRTArgs.size();
I < E; ++
I) {
506 if (!
IO.IRTArgs[
I].Enabled)
511 Value *NewValue = FnTy->isVoidTy() || IsCustomReplaceable
516 if (ForceIndirection && !IsCustomReplaceable &&
521 NewValue = IIRB.
IRB.CreateLoad(V->getType(), Q);
523 V =
IO.IRTArgs[
I].SetterCB(*V, *NewValue, IConf, IIRB);
536 IRTArg(IIRB.
PtrTy,
"pointer",
"The accessed pointer.",
543 "The address space of the accessed pointer.",
571 "The atomicity ordering of the store.",
592 return SI.getPointerOperand();
598 SI.setOperand(
SI.getPointerOperandIndex(), &NewV);
605 return getCI(&Ty,
SI.getPointerAddressSpace());
611 return SI.getValueOperand();
617 auto &
DL =
SI.getDataLayout();
618 return getCI(&Ty,
DL.getTypeStoreSize(
SI.getValueOperand()->getType()));
624 return getCI(&Ty,
SI.getAlign().value());
630 return getCI(&Ty,
SI.getValueOperand()->getType()->getTypeID());
637 return getCI(&Ty,
uint64_t(
SI.getOrdering()));
643 return getCI(&Ty,
uint64_t(
SI.getSyncScopeID()));
649 return getCI(&Ty,
SI.isVolatile());
659 IRTArg(IIRB.
PtrTy,
"pointer",
"The accessed pointer.",
666 "The address space of the accessed pointer.",
696 "The atomicity ordering of the load.",
717 return LI.getPointerOperand();
723 LI.setOperand(LI.getPointerOperandIndex(), &NewV);
730 return getCI(&Ty, LI.getPointerAddressSpace());
741 auto &
DL = LI.getDataLayout();
742 return getCI(&Ty,
DL.getTypeStoreSize(LI.getType()));
748 return getCI(&Ty, LI.getAlign().value());
754 return getCI(&Ty, LI.getType()->getTypeID());
761 return getCI(&Ty,
uint64_t(LI.getOrdering()));
767 return getCI(&Ty,
uint64_t(LI.getSyncScopeID()));
773 return getCI(&Ty, LI.isVolatile());
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the StringMap class.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static cl::opt< ITMode > IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), cl::values(clEnumValN(DefaultIT, "arm-default-it", "Generate any type of IT block"), clEnumValN(RestrictedIT, "arm-restrict-it", "Disallow complex IT blocks")))
This file contains the declarations for the subclasses of Constant, which represent the different fla...
post inline ee instrument
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
Machine Check Debug Module
ModuleAnalysisManager MAM
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
This class represents a function call, abstracting a target machine's calling convention.
This is an important base class in LLVM.
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
Diagnostic information for IR instrumentation reporting.
Class to represent function types.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
PointerType * getType() const
Global values are always pointers.
This is an important class for using LLVM in a threaded context.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
A Module instance is used to store all the information related to an LLVM module.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
iterator insert(iterator I, T &&Elt)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
bool isPointerTy() const
True if this is an instance of PointerType.
bool isAggregateType() const
Return true if the type is an aggregate type.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI bool replaceUsesWithIf(Value *New, llvm::function_ref< bool(Use &U)> ShouldReplace)
Go through the uses list for this definition and make each use point to "V" if the callback ShouldRep...
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
initializer< Ty > init(const Ty &Val)
bool readConfigFromJSON(InstrumentationConfig &IConf, StringRef InputFile, LLVMContext &Ctx)
Read the configuration from the file with path InputFile into /p IConf.
void writeConfigToJSON(InstrumentationConfig &IConf, StringRef OutputFile, LLVMContext &Ctx)
Write the configuration in /p IConf to the file with path OutputFile.
void printRuntimeStub(const InstrumentationConfig &IConf, StringRef StubRuntimeName, LLVMContext &Ctx)
Print a runtime stub file with the implementation of the instrumentation runtime functions correspond...
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI bool verifyModule(const Module &M, raw_ostream *OS=nullptr, bool *BrokenDebugInfo=nullptr)
Check a module for errors.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
static std::unique_ptr< BaseConfigurationOption > createStringOption(InstrumentationConfig &IC, StringRef Name, StringRef Description, StringRef DefaultValue)
Create a string option with Name name, Description description and DefaultValue as string default val...
static std::unique_ptr< BaseConfigurationOption > createBoolOption(InstrumentationConfig &IC, StringRef Name, StringRef Description, bool DefaultValue)
Create a boolean option with Name name, Description description and DefaultValue as boolean default v...
bool isReplacable(IRTArg &IRTA) const
Return whether the IRTA argument can be replaced.
IRTCallDescription(InstrumentationOpportunity &IO, Type *RetTy=nullptr)
Construct an instrumentation function description linked to the IO instrumentation opportunity and Re...
bool MightRequireIndirection
Whether any argument may require indirection.
CallInst * createLLVMCall(Value *&V, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB, const DataLayout &DL, InstrumentationCaches &ICaches)
Create a call instruction that calls to the instrumentation function and passes the corresponding arg...
Type * RetTy
The return type of the instrumentation function.
InstrumentationOpportunity & IO
The instrumentation opportunity which it is linked to.
FunctionType * createLLVMSignature(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB, const DataLayout &DL, bool ForceIndirection)
Create the type of the instrumentation function.
unsigned NumReplaceableArgs
The number of arguments that can be replaced.
bool RequiresIndirection
Whether the function requires indirection in some argument.
bool isPotentiallyIndirect(IRTArg &IRTA) const
Return whether the function may have any indirect argument.
Helper that represent the caches for instrumentation call arguments.
DenseMap< std::tuple< unsigned, StringRef, StringRef >, Value * > DirectArgCache
A cache for direct and indirect arguments.
DenseMap< std::tuple< unsigned, StringRef, StringRef >, Value * > IndirectArgCache
The class that contains the configuration for the instrumentor.
virtual void populate(InstrumentorIRBuilderTy &IIRB)
Populate the instrumentation opportunities.
void addChoice(InstrumentationOpportunity &IO, LLVMContext &Ctx)
Register instrumentation opportunity IO.
std::unique_ptr< BaseConfigurationOption > HostEnabled
std::unique_ptr< BaseConfigurationOption > GPUEnabled
std::unique_ptr< BaseConfigurationOption > RuntimeStubsFile
StringRef getRTName() const
Get the runtime prefix for the instrumentation runtime functions.
void addBaseChoice(BaseConfigurationOption *BCO)
Add the base configuration option BCO into the list of base options.
std::unique_ptr< BaseConfigurationOption > TargetRegex
EnumeratedArray< StringMap< InstrumentationOpportunity * >, InstrumentationLocation::KindTy > IChoices
The map registered instrumentation opportunities.
Base class for instrumentation opportunities.
InstrumentationLocation::KindTy getLocationKind() const
Get the location kind of the instrumentation opportunity.
static Value * getIdPre(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
Get the opportunity identifier for the pre and post positions.
static Value * forceCast(Value &V, Type &Ty, InstrumentorIRBuilderTy &IIRB)
Helpers to cast values, pass them to the runtime, and replace them.
static int32_t getIdFromEpoch(uint32_t CurrentEpoch)
}
static Value * getIdPost(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * replaceValue(Value &V, Value &NewV, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
virtual StringRef getName() const =0
Get the name of the instrumentation opportunity.
SmallVector< IRTArg > IRTArgs
The list of possible arguments for the instrumentation runtime function.
void addCommonArgs(InstrumentationConfig &IConf, LLVMContext &Ctx, bool PassId)
}
An IR builder augmented with extra information for the instrumentor pass.
IRBuilder< ConstantFolder, IRBuilderCallbackInserter > IRB
The underlying IR builder with insertion callback.
unsigned Epoch
The current epoch number.
AllocaInst * getAlloca(Function *Fn, Type *Ty, bool MatchType=false)
Get a temporary alloca to communicate (large) values with the runtime.
void returnAllocas()
Return the temporary allocas.
DenseMap< Instruction *, unsigned > NewInsts
A mapping from instrumentation instructions to the epoch they have been created.
static Value * getValueSize(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getSyncScopeId(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getAtomicityOrdering(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
virtual Type * getValueType(InstrumentorIRBuilderTy &IIRB) const
}
static Value * getValue(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getAlignment(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getPointer(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
Getters and setters for the arguments of the instrumentation function for the load opportunity.
static Value * isVolatile(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * setPointer(Value &V, Value &NewV, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
BaseConfigTy< ConfigKind > ConfigTy
static Value * getPointerAS(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static void populate(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
}
static Value * getValueTypeId(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
void init(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB, ConfigTy *UserConfig=nullptr)
Initialize the load opportunity using the instrumentation config IConf and the user config UserConfig...
static Value * getPointer(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
Getters and setters for the arguments of the instrumentation function for the store opportunity.
static void populate(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
}
static Value * getValueTypeId(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
virtual Type * getValueType(InstrumentorIRBuilderTy &IIRB) const
}
static Value * getSyncScopeId(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getPointerAS(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getAlignment(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getValue(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * setPointer(Value &V, Value &NewV, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * isVolatile(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
static Value * getValueSize(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)
BaseConfigTy< ConfigKind > ConfigTy
void init(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB, ConfigTy *UserConfig=nullptr)
Initialize the store opportunity using the instrumentation config IConf and the user config UserConfi...
static Value * getAtomicityOrdering(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB)