20 #include "llvm/IR/IntrinsicsSPIRV.h"
49 class SPIRVEmitIntrinsics
51 public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
55 bool TrackConstants =
true;
58 void preprocessCompositeConstants();
100 return isa<IntrinsicInst>(
I) &&
101 cast<IntrinsicInst>(
I)->getIntrinsicID() == Intrinsic::spv_assign_type;
105 return isa<StoreInst>(
I) || isa<LoadInst>(
I) || isa<InsertValueInst>(
I) ||
106 isa<ExtractValueInst>(
I);
110 return isa<ConstantAggregate>(V) || isa<ConstantDataArray>(V) ||
116 B.SetInsertPoint(
I->getParent(),
I->getParent()->getFirstInsertionPt());
124 switch (
Intr->getIntrinsicID()) {
125 case Intrinsic::invariant_start:
126 case Intrinsic::invariant_end:
133 void SPIRVEmitIntrinsics::replaceMemInstrUses(
Instruction *Old,
139 }
else if (isAssignTypeInstr(U)) {
151 void SPIRVEmitIntrinsics::preprocessCompositeConstants() {
152 std::queue<Instruction *> Worklist;
156 while (!Worklist.empty()) {
157 auto *
I = Worklist.front();
159 bool KeepInst =
false;
160 for (
const auto &
Op :
I->operands()) {
161 auto BuildCompositeIntrinsic = [&KeepInst, &Worklist, &
I, &
Op,
168 I->replaceUsesOfWith(
Op, CCI);
170 AggrConsts[CCI] = AggrC;
173 if (
auto *AggrC = dyn_cast<ConstantAggregate>(
Op)) {
175 BuildCompositeIntrinsic(AggrC,
Args);
176 }
else if (
auto *AggrC = dyn_cast<ConstantDataArray>(
Op)) {
178 for (
unsigned i = 0;
i < AggrC->getNumElements(); ++
i)
179 Args.push_back(AggrC->getElementAsConstant(
i));
180 BuildCompositeIntrinsic(AggrC,
Args);
181 }
else if (isa<ConstantAggregateZero>(
Op) &&
182 !
Op->getType()->isVectorTy()) {
183 auto *AggrC = cast<ConstantAggregateZero>(
Op);
185 BuildCompositeIntrinsic(AggrC,
Args);
195 for (
auto &
Op :
I.operands())
196 if (
Op.get()->getType()->isSized())
207 for (
auto &
Op :
I.operands())
210 I.replaceAllUsesWith(NewI);
219 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
220 I.replaceAllUsesWith(NewI);
222 NewI->setName(InstName);
228 I.getOperand(1)->getType(),
229 I.getOperand(2)->getType()};
232 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
233 I.replaceAllUsesWith(NewI);
235 NewI->setName(InstName);
242 I.getIndexOperand()->getType()};
245 std::string InstName =
I.hasName() ?
I.getName().str() :
"";
246 I.replaceAllUsesWith(NewI);
248 NewI->setName(InstName);
255 for (
auto &
Op :
I.operands())
256 if (isa<UndefValue>(
Op))
260 for (
auto &
Op :
I.indices())
264 replaceMemInstrUses(&
I, NewI);
270 for (
auto &
Op :
I.operands())
272 for (
auto &
Op :
I.indices())
276 I.replaceAllUsesWith(NewI);
282 if (!
I.getType()->isAggregateType())
284 TrackConstants =
false;
285 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
287 TLI->getLoadMemOperandFlags(
I,
F->getParent()->getDataLayout());
290 {
I.getPointerOperand(), IRB->
getInt16(Flags),
291 IRB->
getInt8(
I.getAlign().value())});
292 replaceMemInstrUses(&
I, NewI);
299 TrackConstants =
false;
300 const auto *TLI =
TM->getSubtargetImpl()->getTargetLowering();
302 TLI->getStoreMemOperandFlags(
I,
F->getParent()->getDataLayout());
303 auto *PtrOp =
I.getPointerOperand();
306 {
I.getValueOperand(), PtrOp, IRB->
getInt16(Flags),
307 IRB->
getInt8(
I.getAlign().value())});
313 TrackConstants =
false;
317 void SPIRVEmitIntrinsics::processGlobalValue(
GlobalVariable &GV) {
319 if (GV.
getName() ==
"llvm.global.annotations")
334 void SPIRVEmitIntrinsics::insertAssignTypeIntrs(
Instruction *
I) {
335 Type *Ty =
I->getType();
338 Type *TypeToAssign = Ty;
339 if (
auto *II = dyn_cast<IntrinsicInst>(
I)) {
340 if (II->getIntrinsicID() == Intrinsic::spv_const_composite) {
341 auto t = AggrConsts.
find(II);
343 TypeToAssign =
t->second->getType();
347 buildIntrWithMD(Intrinsic::spv_assign_type, {Ty},
Const,
I);
349 for (
const auto &
Op :
I->operands()) {
350 if (isa<ConstantPointerNull>(
Op) || isa<UndefValue>(
Op) ||
352 (isa<ConstantExpr>(
Op) && isa<GEPOperator>(
Op))) {
354 buildIntrWithMD(Intrinsic::spv_assign_type, {
Op->getType()},
Op,
Op);
359 if (isa<StoreInst>(
I) &&
360 cast<StoreInst>(
I)->getValueOperand()->
getType()->isAggregateType())
364 void SPIRVEmitIntrinsics::processInstrAfterVisit(
Instruction *
I) {
365 auto *II = dyn_cast<IntrinsicInst>(
I);
366 if (II && II->getIntrinsicID() == Intrinsic::spv_const_composite &&
370 auto t = AggrConsts.
find(
I);
373 buildIntrWithMD(Intrinsic::spv_track_constant, {Ty, Ty},
t->second,
I);
374 I->replaceAllUsesWith(NewOp);
375 NewOp->setArgOperand(0,
I);
377 for (
const auto &
Op :
I->operands()) {
378 if ((isa<ConstantAggregateZero>(
Op) &&
Op->getType()->isVectorTy()) ||
379 isa<PHINode>(
I) || isa<SwitchInst>(
I))
380 TrackConstants =
false;
381 if (isa<ConstantData>(
Op) && TrackConstants) {
382 unsigned OpNo =
Op.getOperandNo();
383 if (II && ((II->getIntrinsicID() == Intrinsic::spv_gep && OpNo == 0) ||
384 (II->paramHasAttr(OpNo, Attribute::ImmArg))))
387 auto *NewOp = buildIntrWithMD(Intrinsic::spv_track_constant,
388 {
Op->getType(),
Op->getType()},
Op,
Op);
389 I->setOperand(OpNo, NewOp);
394 std::vector<Value *>
Args = {
I};
401 if (
Func.isDeclaration())
410 for (
auto &GV :
Func.getParent()->globals())
411 processGlobalValue(GV);
413 preprocessCompositeConstants();
416 Worklist.push_back(&
I);
418 for (
auto &
I : Worklist)
419 insertAssignTypeIntrs(
I);
421 for (
auto *
I : Worklist) {
422 TrackConstants =
true;
423 if (!
I->getType()->isVoidTy() || isa<StoreInst>(
I))
426 processInstrAfterVisit(
I);
432 return new SPIRVEmitIntrinsics(
TM);