20#include "llvm/IR/IntrinsicsSPIRV.h"
49class SPIRVEmitIntrinsics
51 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
55 bool TrackConstants =
true;
58 void preprocessCompositeConstants();
59 void preprocessUndefs();
97char SPIRVEmitIntrinsics::ID = 0;
103 return isa<IntrinsicInst>(
I) &&
104 cast<IntrinsicInst>(
I)->getIntrinsicID() == Intrinsic::spv_assign_type;
108 return isa<StoreInst>(
I) || isa<LoadInst>(
I) || isa<InsertValueInst>(
I) ||
109 isa<ExtractValueInst>(
I) || isa<AtomicCmpXchgInst>(
I);
113 return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) ||
114 (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
119 B.SetInsertPoint(
I->getParent(),
I->getParent()->getFirstInsertionPt());
127 switch (
Intr->getIntrinsicID()) {
128 case Intrinsic::invariant_start:
129 case Intrinsic::invariant_end:
136void SPIRVEmitIntrinsics::replaceMemInstrUses(
Instruction *Old,
140 if (isAssignTypeInstr(U)) {
144 U->eraseFromParent();
147 U->replaceUsesOfWith(Old, New);
155void SPIRVEmitIntrinsics::preprocessUndefs() {
156 std::queue<Instruction *> Worklist;
160 while (!Worklist.empty()) {
164 for (
auto &Op :
I->operands()) {
165 auto *AggrUndef = dyn_cast<UndefValue>(Op);
166 if (!AggrUndef || !
Op->getType()->isAggregateType())
171 Worklist.push(IntrUndef);
172 I->replaceUsesOfWith(Op, IntrUndef);
173 AggrConsts[IntrUndef] = AggrUndef;
178void SPIRVEmitIntrinsics::preprocessCompositeConstants() {
179 std::queue<Instruction *> Worklist;
183 while (!Worklist.empty()) {
184 auto *
I = Worklist.front();
186 bool KeepInst =
false;
187 for (
const auto &Op :
I->operands()) {
188 auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &
I, &
Op,
195 I->replaceUsesOfWith(Op, CCI);
197 AggrConsts[CCI] = AggrC;
200 if (
auto *AggrC = dyn_cast<ConstantAggregate>(Op)) {
202 BuildCompositeIntrinsic(AggrC, Args);
203 }
else if (
auto *AggrC = dyn_cast<ConstantDataArray>(Op)) {
205 for (
unsigned i = 0; i < AggrC->getNumElements(); ++i)
206 Args.push_back(AggrC->getElementAsConstant(i));
207 BuildCompositeIntrinsic(AggrC, Args);
208 }
else if (isa<ConstantAggregateZero>(Op) &&
209 !
Op->getType()->isVectorTy()) {
210 auto *AggrC = cast<ConstantAggregateZero>(Op);
212 BuildCompositeIntrinsic(AggrC, Args);
222 for (
auto &Op :
I.operands())
223 if (
Op.get()->getType()->isSized())
235 for (
auto &Op :
I.operands())
238 I.replaceAllUsesWith(NewI);
247 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
248 I.replaceAllUsesWith(NewI);
250 NewI->setName(InstName);
256 I.getOperand(1)->getType(),
257 I.getOperand(2)->getType()};
260 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
261 I.replaceAllUsesWith(NewI);
263 NewI->setName(InstName);
270 I.getIndexOperand()->getType()};
273 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
274 I.replaceAllUsesWith(NewI);
276 NewI->setName(InstName);
283 for (
auto &Op :
I.operands())
284 if (isa<UndefValue>(Op))
288 for (
auto &Op :
I.indices())
292 replaceMemInstrUses(&
I, NewI);
298 for (
auto &Op :
I.operands())
300 for (
auto &Op :
I.indices())
304 I.replaceAllUsesWith(NewI);
310 if (!
I.getType()->isAggregateType())
312 TrackConstants =
false;
313 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
315 TLI->getLoadMemOperandFlags(
I,
F->getParent()->getDataLayout());
318 {
I.getPointerOperand(), IRB->
getInt16(Flags),
319 IRB->
getInt8(
I.getAlign().value())});
320 replaceMemInstrUses(&
I, NewI);
327 TrackConstants =
false;
328 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
330 TLI->getStoreMemOperandFlags(
I,
F->getParent()->getDataLayout());
331 auto *PtrOp =
I.getPointerOperand();
333 Intrinsic::spv_store, {
I.getValueOperand()->
getType(), PtrOp->getType()},
334 {
I.getValueOperand(), PtrOp, IRB->
getInt16(Flags),
335 IRB->
getInt8(
I.getAlign().value())});
341 TrackConstants =
false;
342 Type *PtrTy =
I.getType();
344 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
345 I.replaceAllUsesWith(NewI);
352 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
354 for (
auto &Op :
I.operands())
363 replaceMemInstrUses(&
I, NewI);
375 if (GV.
getName() ==
"llvm.global.annotations")
390void SPIRVEmitIntrinsics::insertAssignTypeIntrs(
Instruction *
I) {
391 Type *Ty =
I->getType();
394 Type *TypeToAssign = Ty;
395 if (
auto *II = dyn_cast<IntrinsicInst>(
I)) {
396 if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
397 II->getIntrinsicID() == Intrinsic::spv_undef) {
398 auto t = AggrConsts.
find(II);
400 TypeToAssign = t->second->getType();
404 buildIntrWithMD(Intrinsic::spv_assign_type, {Ty},
Const,
I);
406 for (
const auto &Op :
I->operands()) {
407 if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
409 (isa<ConstantExpr>(Op) && isa<GEPOperator>(Op))) {
411 if (isa<UndefValue>(Op) &&
Op->getType()->isAggregateType())
412 buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->
getInt32Ty()},
Op,
415 buildIntrWithMD(Intrinsic::spv_assign_type, {
Op->getType()},
Op,
Op);
420void SPIRVEmitIntrinsics::processInstrAfterVisit(
Instruction *
I) {
421 auto *II = dyn_cast<IntrinsicInst>(
I);
422 if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
426 auto t = AggrConsts.
find(
I);
429 buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty}, t->second,
I);
430 I->replaceAllUsesWith(NewOp);
431 NewOp->setArgOperand(0,
I);
433 for (
const auto &Op :
I->operands()) {
434 if ((isa<ConstantAggregateZero>(Op) &&
Op->getType()->isVectorTy()) ||
435 isa<PHINode>(
I) || isa<SwitchInst>(
I))
436 TrackConstants =
false;
437 if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) {
438 unsigned OpNo =
Op.getOperandNo();
439 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
440 (II->paramHasAttr(OpNo, Attribute::ImmArg))))
443 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
444 {
Op->getType(),
Op->getType()},
Op,
Op);
445 I->setOperand(OpNo, NewOp);
450 std::vector<Value *>
Args = {
I};
456bool SPIRVEmitIntrinsics::runOnFunction(
Function &Func) {
457 if (
Func.isDeclaration())
470 Type *ElTy =
SI->getValueOperand()->getType();
471 PointerType *PTy = cast<PointerType>(
SI->getOperand(1)->getType());
473 !PTy->isOpaqueOrPointeeTypeMatches(ElTy))
478 for (
auto &GV :
Func.getParent()->globals())
479 processGlobalValue(GV);
482 preprocessCompositeConstants();
487 for (
auto &
I : Worklist)
488 insertAssignTypeIntrs(
I);
490 for (
auto *
I : Worklist) {
491 TrackConstants =
true;
492 if (!
I->getType()->isVoidTy() || isa<StoreInst>(
I))
495 processInstrAfterVisit(
I);
501 return new SPIRVEmitIntrinsics(
TM);
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
print must be executed print the must be executed context for all instructions
const char LLVMTargetMachineRef TM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool isMemInstrToReplace(Instruction *I)
static bool isAggrToReplace(const Value *V)
static void setInsertPointSkippingPhis(IRBuilder<> &B, Instruction *I)
static bool requireAssignType(Instruction *I)
static SymbolRef::Type getType(const Symbol *Sym)
an instruction to allocate memory on the stack
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
An instruction that atomically checks whether a specified value is in a memory location,...
This class represents a no-op cast from one type to another.
void setArgOperand(unsigned i, Value *v)
This class represents a function call, abstracting a target machine's calling convention.
This is an important base class in LLVM.
static Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
iterator find(const_arg_type_t< KeyT > Val)
Implements a dense probed hash-table based set.
FunctionPass class - This class is used to implement most global optimizations.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
PointerType * getType() const
Global values are always pointers.
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
bool hasInitializer() const
Definitions have initializers, declarations don't.
ConstantInt * getInt1(bool V)
Get a constant value representing either true or false.
CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, Instruction *FMFSource=nullptr, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
ConstantInt * getInt8(uint8_t C)
Get a constant 8-bit value.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
ConstantInt * getInt16(uint16_t C)
Get a constant 16-bit value.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
This instruction inserts a single (scalar) element into a VectorType value.
This instruction inserts a struct field of array element value into an aggregate value.
Base class for instruction visitors.
RetTy visitExtractElementInst(ExtractElementInst &I)
RetTy visitInsertValueInst(InsertValueInst &I)
RetTy visitUnreachableInst(UnreachableInst &I)
RetTy visitAtomicCmpXchgInst(AtomicCmpXchgInst &I)
RetTy visitBitCastInst(BitCastInst &I)
RetTy visitSwitchInst(SwitchInst &I)
RetTy visitExtractValueInst(ExtractValueInst &I)
RetTy visitStoreInst(StoreInst &I)
RetTy visitInsertElementInst(InsertElementInst &I)
RetTy visitAllocaInst(AllocaInst &I)
RetTy visitGetElementPtrInst(GetElementPtrInst &I)
void visitInstruction(Instruction &I)
RetTy visitLoadInst(LoadInst &I)
Instruction * user_back()
Specialize the methods defined in Value, as we know that an instruction can only be used by other ins...
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A wrapper class for inspecting calls to intrinsic functions.
An instruction for reading from memory.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Flags
Flags values. These may be or'd together.
PassRegistry - This class manages the registration and intitialization of the pass subsystem as appli...
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
bool isAggregateType() const
Return true if the type is an aggregate type.
bool isVoidTy() const
Return true if this is 'void'.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
This function has undefined behavior.
LLVM Value Representation.
void setName(const Twine &Name)
Change the name of the value.
unsigned getNumUses() const
This method computes the number of uses of this Value.
StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
void initializeSPIRVEmitIntrinsicsPass(PassRegistry &)
FunctionPass * createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM)
void addStringImm(const StringRef &Str, MCInst &Inst)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)