51#include <system_error>
57#define DEBUG_TYPE "instrumentor"
63 "instrumentor-write-config-file",
65 "Write the instrumentor configuration into the specified JSON file"),
70 "instrumentor-read-config-file",
72 "Read the instrumentor configuration from the specified JSON file"),
77template <
typename IRBuilderTy>
void ensureDbgLoc(IRBuilderTy &IRB) {
78 if (IRB.getCurrentDebugLocation())
80 auto *BB = IRB.GetInsertBlock();
81 if (
auto *SP = BB->getParent()->getSubprogram())
82 IRB.SetCurrentDebugLocation(
DILocation::get(BB->getContext(), 0, 0, SP));
86template <
typename IRBTy>
88 bool AllowTruncate =
false) {
91 Type *VTy = V->getType();
96 TypeSize RequestedSize =
DL.getTypeSizeInBits(Ty);
97 TypeSize ValueSize =
DL.getTypeSizeInBits(VTy);
98 bool ShouldTruncate = RequestedSize < ValueSize;
99 if (ShouldTruncate && !AllowTruncate)
101 if (ShouldTruncate && AllowTruncate)
102 return tryToCast(IRB,
103 IRB.CreateIntCast(V, IRB.getIntNTy(RequestedSize),
105 Ty,
DL, AllowTruncate);
107 return IRB.CreatePointerBitCastOrAddrSpaceCast(V, Ty);
109 return IRB.CreateIntCast(V, Ty,
false);
111 return tryToCast(IRB, IRB.CreateBitCast(V, IRB.getIntNTy(ValueSize)), Ty,
114 return IRB.CreateBitOrPointerCast(V, Ty);
118template <
typename Ty>
120 return ConstantInt::get(
IT, Val, IsSigned);
125class InstrumentorImpl final {
130 : IConf(IConf), M(M), IIRB(IIRB) {
139 bool shouldInstrumentTarget();
142 bool shouldInstrumentFunction(
Function &Fn);
149 bool instrumentFunction(
Function &Fn);
169bool InstrumentorImpl::shouldInstrumentTarget() {
171 const bool IsGPU =
T.
isAMDGPU() ||
T.isNVPTX();
173 bool RegexMatches =
true;
175 if (!TargetRegexStr.empty()) {
176 llvm::Regex TargetRegex(TargetRegexStr);
178 if (!TargetRegex.isValid(ErrMsg)) {
180 Twine(
"failed to parse target regex: ") + ErrMsg,
DS_Warning));
183 RegexMatches = TargetRegex.match(
T.str());
192bool InstrumentorImpl::shouldInstrumentFunction(Function &Fn) {
199bool InstrumentorImpl::instrumentInstruction(Instruction &
I,
200 InstrumentationCaches &ICaches) {
211 if (
auto *IO = InstChoicesPRE.lookup(
I.getOpcode())) {
212 IIRB.
IRB.SetInsertPoint(&
I);
213 ensureDbgLoc(IIRB.
IRB);
214 Changed |= bool(IO->instrument(IPtr, IConf, IIRB, ICaches));
217 if (
auto *IO = InstChoicesPOST.lookup(
I.getOpcode())) {
218 IIRB.
IRB.SetInsertPoint(
I.getNextNode());
219 ensureDbgLoc(IIRB.
IRB);
220 Changed |= bool(IO->instrument(IPtr, IConf, IIRB, ICaches));
227bool InstrumentorImpl::instrumentFunction(Function &Fn) {
229 if (!shouldInstrumentFunction(Fn))
232 InstrumentationCaches ICaches;
233 ReversePostOrderTraversal<Function *> RPOT(&Fn);
234 for (
auto &It : RPOT)
236 Changed |= instrumentInstruction(
I, ICaches);
241bool InstrumentorImpl::instrument() {
243 if (!shouldInstrumentTarget())
247 if (It.second->Enabled)
248 InstChoicesPRE[It.second->getOpcode()] = It.second;
250 if (It.second->Enabled)
251 InstChoicesPOST[It.second->getOpcode()] = It.second;
253 for (Function &Fn : M)
254 Changed |= instrumentFunction(Fn);
259PreservedAnalyses InstrumentorPass::run(
Module &M, InstrumentationConfig &IConf,
260 InstrumentorIRBuilderTy &IIRB,
262 InstrumentorImpl Impl(IConf, IIRB, M);
268 bool Changed = Impl.instrument();
276 std::unique_ptr<InstrumentationConfig> IConfInt(
277 !UserIConf ?
new InstrumentationConfig() :
nullptr);
278 std::unique_ptr<InstrumentorIRBuilderTy> IIRBInt(
279 !UserIIRB ?
new InstrumentorIRBuilderTy(M) :
nullptr);
281 auto *IConf = IConfInt ? IConfInt.get() : UserIConf;
282 auto *IIRB = IIRBInt ? IIRBInt.get() : UserIIRB;
284 auto PA = run(M, *IConf, *IIRB, !UserIConf);
295 BCO->setBool(DefaultValue);
304 BCO->setString(DefaultValue);
320 Twine(
"registered two instrumentation opportunities for the same "
342 if (V.getType()->isVoidTy())
344 return tryToCast(IIRB.
IRB, &V, &Ty,
345 IIRB.
IRB.GetInsertBlock()->getDataLayout());
351 if (V.getType()->isVoidTy())
354 auto *NewVCasted = &NewV;
357 IIRB.
IRB.SetInsertPoint(
I->getNextNode());
358 ensureDbgLoc(IIRB.
IRB);
359 NewVCasted = tryToCast(IIRB.
IRB, &NewV, V.
getType(), IIRB.
DL,
374 for (
auto &It :
IO.IRTArgs) {
377 NumReplaceableArgs += bool(It.Flags & IRTArg::REPLACABLE);
378 MightRequireIndirection |= It.Flags & IRTArg::POTENTIALLY_INDIRECT;
389 "Wrong indirection setting!");
392 for (
auto &It :
IO.IRTArgs) {
421 auto IP = IIRB.
IRB.GetInsertPoint();
424 for (
auto &It :
IO.IRTArgs) {
428 if (!Param || It.NoCache)
430 Param = It.GetterCB(*V, *It.Ty, IConf, IIRB);
433 if (Param->getType()->isVoidTy()) {
435 }
else if (Param->getType()->isAggregateType() ||
436 DL.getTypeSizeInBits(Param->getType()) >
437 DL.getTypeSizeInBits(It.Ty)) {
440 Twine(
"indirection needed for ") + It.Name +
Twine(
" in ") +
442 Twine(
", but not indicated. Instrumentation is skipped"),
446 ForceIndirection =
true;
448 Param = tryToCast(IIRB.
IRB, Param, It.Ty,
DL);
453 if (ForceIndirection) {
454 Function *Fn = IIRB.
IRB.GetInsertBlock()->getParent();
457 for (
auto &It :
IO.IRTArgs) {
465 auto *&CallParam = CallParams[
Offset++];
467 CallParams.
insert(&CallParam + 1, IIRB.
IRB.getInt32(
DL.getTypeStoreSize(
468 CallParam->getType())));
475 CallParam = CachedParam;
480 IIRB.
IRB.CreateStore(CallParam, AI);
481 CallParam = CachedParam = AI;
485 if (!ForceIndirection)
486 IIRB.
IRB.SetInsertPoint(IP);
487 ensureDbgLoc(IIRB.
IRB);
491 IConf.
getRTName(
IO.IP.isPRE() ?
"pre_" :
"post_",
IO.getName(),
492 ForceIndirection ?
"_ind" :
"");
493 auto FC = IIRB.
IRB.GetInsertBlock()->getModule()->getOrInsertFunction(
495 auto *CI = IIRB.
IRB.CreateCall(FC, CallParams);
498 for (
unsigned I = 0, E =
IO.IRTArgs.size();
I < E; ++
I) {
499 if (!
IO.IRTArgs[
I].Enabled)
504 Value *NewValue = FnTy->isVoidTy() || IsCustomReplaceable
509 if (ForceIndirection && !IsCustomReplaceable &&
514 NewValue = IIRB.
IRB.CreateLoad(V->getType(), Q);
516 V =
IO.IRTArgs[
I].SetterCB(*V, *NewValue, IConf, IIRB);
529 IRTArg(IIRB.
PtrTy,
"pointer",
"The accessed pointer.",
536 "The address space of the accessed pointer.",
564 "The atomicity ordering of the store.",
585 return SI.getPointerOperand();
591 SI.setOperand(
SI.getPointerOperandIndex(), &NewV);
598 return getCI(&Ty,
SI.getPointerAddressSpace());
604 return SI.getValueOperand();
610 auto &
DL =
SI.getDataLayout();
611 return getCI(&Ty,
DL.getTypeStoreSize(
SI.getValueOperand()->getType()));
617 return getCI(&Ty,
SI.getAlign().value());
623 return getCI(&Ty,
SI.getValueOperand()->getType()->getTypeID());
630 return getCI(&Ty,
uint64_t(
SI.getOrdering()));
636 return getCI(&Ty,
uint64_t(
SI.getSyncScopeID()));
642 return getCI(&Ty,
SI.isVolatile());
652 IRTArg(IIRB.
PtrTy,
"pointer",
"The accessed pointer.",
659 "The address space of the accessed pointer.",
689 "The atomicity ordering of the load.",
710 return LI.getPointerOperand();
716 LI.setOperand(LI.getPointerOperandIndex(), &NewV);
723 return getCI(&Ty, LI.getPointerAddressSpace());
734 auto &
DL = LI.getDataLayout();
735 return getCI(&Ty,
DL.getTypeStoreSize(LI.getType()));
741 return getCI(&Ty, LI.getAlign().value());
747 return getCI(&Ty, LI.getType()->getTypeID());
754 return getCI(&Ty,
uint64_t(LI.getOrdering()));
760 return getCI(&Ty,
uint64_t(LI.getSyncScopeID()));
766 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.
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.
An option for the base configuration.
static 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 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...
BaseConfigurationOption(StringRef Name, StringRef Desc, KindTy Kind)
}
StringRef getString() const
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.
BaseConfigurationOption * GPUEnabled
void addChoice(InstrumentationOpportunity &IO, LLVMContext &Ctx)
Register instrumentation opportunity IO.
BaseConfigurationOption * TargetRegex
BaseConfigurationOption * HostEnabled
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.
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)