20#include "llvm/IR/IntrinsicsSPIRV.h"
49class SPIRVEmitIntrinsics
51 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
55 bool TrackConstants =
true;
58 void preprocessCompositeConstants();
59 void preprocessUndefs();
69 for (
auto *Imm : Imms)
104char SPIRVEmitIntrinsics::ID = 0;
110 return isa<IntrinsicInst>(
I) &&
111 cast<IntrinsicInst>(
I)->getIntrinsicID() == Intrinsic::spv_assign_type;
115 return isa<StoreInst>(
I) || isa<LoadInst>(
I) || isa<InsertValueInst>(
I) ||
116 isa<ExtractValueInst>(
I) || isa<AtomicCmpXchgInst>(
I);
120 return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) ||
121 (isa<ConstantAggregateZero>(V) && !V->getType()->isVectorTy());
126 B.SetInsertPoint(
I->getParent(),
I->getParent()->getFirstInsertionPt());
132 if (isa<AllocaInst>(
I) || isa<GetElementPtrInst>(
I))
141 switch (
Intr->getIntrinsicID()) {
142 case Intrinsic::invariant_start:
143 case Intrinsic::invariant_end:
150void SPIRVEmitIntrinsics::replaceMemInstrUses(
Instruction *Old,
154 if (isAssignTypeInstr(U)) {
158 U->eraseFromParent();
161 U->replaceUsesOfWith(Old, New);
169void SPIRVEmitIntrinsics::preprocessUndefs() {
170 std::queue<Instruction *> Worklist;
174 while (!Worklist.empty()) {
178 for (
auto &
Op :
I->operands()) {
179 auto *AggrUndef = dyn_cast<UndefValue>(
Op);
180 if (!AggrUndef || !
Op->getType()->isAggregateType())
185 Worklist.push(IntrUndef);
186 I->replaceUsesOfWith(
Op, IntrUndef);
187 AggrConsts[IntrUndef] = AggrUndef;
192void SPIRVEmitIntrinsics::preprocessCompositeConstants() {
193 std::queue<Instruction *> Worklist;
197 while (!Worklist.empty()) {
198 auto *
I = Worklist.front();
200 bool KeepInst =
false;
201 for (
const auto &
Op :
I->operands()) {
202 auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &
I, &
Op,
209 I->replaceUsesOfWith(
Op, CCI);
211 AggrConsts[CCI] = AggrC;
214 if (
auto *AggrC = dyn_cast<ConstantAggregate>(
Op)) {
216 BuildCompositeIntrinsic(AggrC, Args);
217 }
else if (
auto *AggrC = dyn_cast<ConstantDataArray>(
Op)) {
219 for (
unsigned i = 0; i < AggrC->getNumElements(); ++i)
220 Args.push_back(AggrC->getElementAsConstant(i));
221 BuildCompositeIntrinsic(AggrC, Args);
222 }
else if (isa<ConstantAggregateZero>(
Op) &&
223 !
Op->getType()->isVectorTy()) {
224 auto *AggrC = cast<ConstantAggregateZero>(
Op);
226 BuildCompositeIntrinsic(AggrC, Args);
236 for (
auto &
Op :
I.operands())
237 if (
Op.get()->getType()->isSized())
249 for (
auto &
Op :
I.operands())
252 I.replaceAllUsesWith(NewI);
261 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
262 I.replaceAllUsesWith(NewI);
264 NewI->setName(InstName);
270 I.getOperand(1)->getType(),
271 I.getOperand(2)->getType()};
274 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
275 I.replaceAllUsesWith(NewI);
277 NewI->setName(InstName);
284 I.getIndexOperand()->getType()};
287 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
288 I.replaceAllUsesWith(NewI);
290 NewI->setName(InstName);
297 for (
auto &
Op :
I.operands())
298 if (isa<UndefValue>(
Op))
302 for (
auto &
Op :
I.indices())
306 replaceMemInstrUses(&
I, NewI);
312 for (
auto &
Op :
I.operands())
314 for (
auto &
Op :
I.indices())
318 I.replaceAllUsesWith(NewI);
324 if (!
I.getType()->isAggregateType())
326 TrackConstants =
false;
327 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
329 TLI->getLoadMemOperandFlags(
I,
F->getParent()->getDataLayout());
332 {
I.getPointerOperand(), IRB->
getInt16(Flags),
333 IRB->
getInt8(
I.getAlign().value())});
334 replaceMemInstrUses(&
I, NewI);
341 TrackConstants =
false;
342 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
344 TLI->getStoreMemOperandFlags(
I,
F->getParent()->getDataLayout());
345 auto *PtrOp =
I.getPointerOperand();
347 Intrinsic::spv_store, {
I.getValueOperand()->
getType(), PtrOp->getType()},
348 {
I.getValueOperand(), PtrOp, IRB->
getInt16(Flags),
349 IRB->
getInt8(
I.getAlign().value())});
355 TrackConstants =
false;
356 Type *PtrTy =
I.getType();
358 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
359 I.replaceAllUsesWith(NewI);
366 assert(
I.getType()->isAggregateType() &&
"Aggregate result is expected");
368 for (
auto &
Op :
I.operands())
377 replaceMemInstrUses(&
I, NewI);
389 if (GV.
getName() ==
"llvm.global.annotations")
404void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(
Instruction *
I) {
412 if (
auto *AI = dyn_cast<AllocaInst>(
I)) {
415 }
else if (
auto *
GEP = dyn_cast<GetElementPtrInst>(
I)) {
422 buildIntrWithMD(Intrinsic::spv_assign_ptr_type, {
I->getType()}, EltTyConst,
I,
426void SPIRVEmitIntrinsics::insertAssignTypeIntrs(
Instruction *
I) {
427 Type *Ty =
I->getType();
430 Type *TypeToAssign = Ty;
431 if (
auto *II = dyn_cast<IntrinsicInst>(
I)) {
432 if (II->getIntrinsicID() == Intrinsic::spv_const_composite ||
433 II->getIntrinsicID() == Intrinsic::spv_undef) {
434 auto t = AggrConsts.
find(II);
436 TypeToAssign = t->second->getType();
440 buildIntrWithMD(Intrinsic::spv_assign_type, {Ty},
Const,
I, {});
442 for (
const auto &
Op :
I->operands()) {
443 if (isa<ConstantPointerNull>(
Op) || isa<UndefValue>(
Op) ||
445 (isa<ConstantExpr>(
Op) && isa<GEPOperator>(
Op))) {
447 if (isa<UndefValue>(
Op) &&
Op->getType()->isAggregateType())
448 buildIntrWithMD(Intrinsic::spv_assign_type, {IRB->
getInt32Ty()},
Op,
451 buildIntrWithMD(Intrinsic::spv_assign_type, {
Op->getType()},
Op,
Op,
457void SPIRVEmitIntrinsics::processInstrAfterVisit(
Instruction *
I) {
458 auto *II = dyn_cast<IntrinsicInst>(
I);
459 if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
463 auto t = AggrConsts.
find(
I);
465 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty},
467 I->replaceAllUsesWith(NewOp);
468 NewOp->setArgOperand(0,
I);
470 for (
const auto &
Op :
I->operands()) {
471 if ((isa<ConstantAggregateZero>(
Op) &&
Op->getType()->isVectorTy()) ||
472 isa<PHINode>(
I) || isa<SwitchInst>(
I))
473 TrackConstants =
false;
474 if ((isa<ConstantData>(
Op) || isa<ConstantExpr>(
Op)) && TrackConstants) {
475 unsigned OpNo =
Op.getOperandNo();
476 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
477 (II->paramHasAttr(OpNo, Attribute::ImmArg))))
480 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
481 {
Op->getType(),
Op->getType()},
Op,
Op, {});
482 I->setOperand(OpNo, NewOp);
487 std::vector<Value *>
Args = {
I};
493bool SPIRVEmitIntrinsics::runOnFunction(
Function &Func) {
494 if (
Func.isDeclaration())
507 Type *ElTy =
SI->getValueOperand()->getType();
508 PointerType *PTy = cast<PointerType>(
SI->getOperand(1)->getType());
510 !PTy->isOpaqueOrPointeeTypeMatches(ElTy))
515 for (
auto &GV :
Func.getParent()->globals())
516 processGlobalValue(GV);
519 preprocessCompositeConstants();
524 for (
auto &
I : Worklist) {
525 insertAssignPtrTypeIntrs(
I);
526 insertAssignTypeIntrs(
I);
529 for (
auto *
I : Worklist) {
530 TrackConstants =
true;
531 if (!
I->getType()->isVoidTy() || isa<StoreInst>(
I))
534 processInstrAfterVisit(
I);
540 return new SPIRVEmitIntrinsics(
TM);
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Select target instructions out of generic 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 bool requireAssignPtrType(Instruction *I)
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.
This class represents an Operation in the Expression.
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.
NodeAddr< FuncNode * > Func
This is an optimization pass for GlobalISel generic memory operations.
void initializeSPIRVEmitIntrinsicsPass(PassRegistry &)
FunctionPass * createSPIRVEmitIntrinsicsPass(SPIRVTargetMachine *TM)
DWARFExpression::Operation Op
void addStringImm(const StringRef &Str, MCInst &Inst)
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord)