@@ -51,7 +51,7 @@ void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);
51
51
52
52
namespace {
53
53
class SPIRVEmitIntrinsics
54
- : public FunctionPass ,
54
+ : public ModulePass ,
55
55
public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
56
56
SPIRVTargetMachine *TM = nullptr ;
57
57
SPIRVGlobalRegistry *GR = nullptr ;
@@ -61,6 +61,9 @@ class SPIRVEmitIntrinsics
61
61
DenseMap<Instruction *, Type *> AggrConstTypes;
62
62
DenseSet<Instruction *> AggrStores;
63
63
64
+ // a registry of created Intrinsic::spv_assign_ptr_type instructions
65
+ DenseMap<Value *, CallInst *> AssignPtrTypeInstr;
66
+
64
67
// deduce element type of untyped pointers
65
68
Type *deduceElementType (Value *I);
66
69
Type *deduceElementTypeHelper (Value *I);
@@ -75,6 +78,9 @@ class SPIRVEmitIntrinsics
75
78
Type *deduceNestedTypeHelper (User *U, Type *Ty,
76
79
std::unordered_set<Value *> &Visited);
77
80
81
+ // deduce Types of operands of the Instruction if possible
82
+ void deduceOperandElementType (Instruction *I);
83
+
78
84
void preprocessCompositeConstants (IRBuilder<> &B);
79
85
void preprocessUndefs (IRBuilder<> &B);
80
86
@@ -111,10 +117,10 @@ class SPIRVEmitIntrinsics
111
117
112
118
public:
113
119
static char ID;
114
- SPIRVEmitIntrinsics () : FunctionPass (ID) {
120
+ SPIRVEmitIntrinsics () : ModulePass (ID) {
115
121
initializeSPIRVEmitIntrinsicsPass (*PassRegistry::getPassRegistry ());
116
122
}
117
- SPIRVEmitIntrinsics (SPIRVTargetMachine *_TM) : FunctionPass (ID), TM(_TM) {
123
+ SPIRVEmitIntrinsics (SPIRVTargetMachine *_TM) : ModulePass (ID), TM(_TM) {
118
124
initializeSPIRVEmitIntrinsicsPass (*PassRegistry::getPassRegistry ());
119
125
}
120
126
Instruction *visitInstruction (Instruction &I) { return &I; }
@@ -130,7 +136,15 @@ class SPIRVEmitIntrinsics
130
136
Instruction *visitAllocaInst (AllocaInst &I);
131
137
Instruction *visitAtomicCmpXchgInst (AtomicCmpXchgInst &I);
132
138
Instruction *visitUnreachableInst (UnreachableInst &I);
133
- bool runOnFunction (Function &F) override ;
139
+
140
+ StringRef getPassName () const override { return " SPIRV emit intrinsics" ; }
141
+
142
+ bool runOnModule (Module &M) override ;
143
+ bool runOnFunction (Function &F);
144
+
145
+ void getAnalysisUsage (AnalysisUsage &AU) const override {
146
+ ModulePass::getAnalysisUsage (AU);
147
+ }
134
148
};
135
149
} // namespace
136
150
@@ -269,6 +283,12 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
269
283
if (Ty)
270
284
break ;
271
285
}
286
+ } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
287
+ for (Value *Op : {Ref->getTrueValue (), Ref->getFalseValue ()}) {
288
+ Ty = deduceElementTypeByUsersDeep (Op, Visited);
289
+ if (Ty)
290
+ break ;
291
+ }
272
292
}
273
293
274
294
// remember the found relationship
@@ -368,6 +388,112 @@ Type *SPIRVEmitIntrinsics::deduceElementType(Value *I) {
368
388
return IntegerType::getInt8Ty (I->getContext ());
369
389
}
370
390
391
+ // If the Instruction has Pointer operands with unresolved types, this function
392
+ // tries to deduce them. If the Instruction has Pointer operands with known
393
+ // types which differ from expected, this function tries to insert a bitcast to
394
+ // resolve the issue.
395
+ void SPIRVEmitIntrinsics::deduceOperandElementType (Instruction *I) {
396
+ SmallVector<std::pair<Value *, unsigned >> Ops;
397
+ Type *KnownElemTy = nullptr ;
398
+ // look for known basic patterns of type inference
399
+ if (auto *Ref = dyn_cast<PHINode>(I)) {
400
+ if (!isPointerTy (I->getType ()) ||
401
+ !(KnownElemTy = GR->findDeducedElementType (I)))
402
+ return ;
403
+ for (unsigned i = 0 ; i < Ref->getNumIncomingValues (); i++) {
404
+ Value *Op = Ref->getIncomingValue (i);
405
+ if (isPointerTy (Op->getType ()))
406
+ Ops.push_back (std::make_pair (Op, i));
407
+ }
408
+ } else if (auto *Ref = dyn_cast<SelectInst>(I)) {
409
+ if (!isPointerTy (I->getType ()) ||
410
+ !(KnownElemTy = GR->findDeducedElementType (I)))
411
+ return ;
412
+ for (unsigned i = 0 ; i < Ref->getNumOperands (); i++) {
413
+ Value *Op = Ref->getOperand (i);
414
+ if (isPointerTy (Op->getType ()))
415
+ Ops.push_back (std::make_pair (Op, i));
416
+ }
417
+ } else if (auto *Ref = dyn_cast<ReturnInst>(I)) {
418
+ Type *RetTy = F->getReturnType ();
419
+ if (!isPointerTy (RetTy))
420
+ return ;
421
+ Value *Op = Ref->getReturnValue ();
422
+ if (!Op)
423
+ return ;
424
+ if (!(KnownElemTy = GR->findDeducedElementType (F))) {
425
+ if (Type *OpElemTy = GR->findDeducedElementType (Op)) {
426
+ GR->addDeducedElementType (F, OpElemTy);
427
+ TypedPointerType *DerivedTy =
428
+ TypedPointerType::get (OpElemTy, getPointerAddressSpace (RetTy));
429
+ GR->addReturnType (F, DerivedTy);
430
+ }
431
+ return ;
432
+ }
433
+ Ops.push_back (std::make_pair (Op, 0 ));
434
+ } else if (auto *Ref = dyn_cast<ICmpInst>(I)) {
435
+ if (!isPointerTy (Ref->getOperand (0 )->getType ()))
436
+ return ;
437
+ Value *Op0 = Ref->getOperand (0 );
438
+ Value *Op1 = Ref->getOperand (1 );
439
+ Type *ElemTy0 = GR->findDeducedElementType (Op0);
440
+ Type *ElemTy1 = GR->findDeducedElementType (Op1);
441
+ if (ElemTy0) {
442
+ KnownElemTy = ElemTy0;
443
+ Ops.push_back (std::make_pair (Op1, 1 ));
444
+ } else if (ElemTy1) {
445
+ KnownElemTy = ElemTy1;
446
+ Ops.push_back (std::make_pair (Op0, 0 ));
447
+ }
448
+ }
449
+
450
+ // There is no enough info to deduce types or all is valid.
451
+ if (!KnownElemTy || Ops.size () == 0 )
452
+ return ;
453
+
454
+ LLVMContext &Ctx = F->getContext ();
455
+ IRBuilder<> B (Ctx);
456
+ for (auto &OpIt : Ops) {
457
+ Value *Op = OpIt.first ;
458
+ if (Op->use_empty ())
459
+ continue ;
460
+ Type *Ty = GR->findDeducedElementType (Op);
461
+ if (Ty == KnownElemTy)
462
+ continue ;
463
+ if (Instruction *User = dyn_cast<Instruction>(Op->use_begin ()->get ()))
464
+ setInsertPointSkippingPhis (B, User->getNextNode ());
465
+ else
466
+ B.SetInsertPoint (I);
467
+ Value *OpTyVal = Constant::getNullValue (KnownElemTy);
468
+ Type *OpTy = Op->getType ();
469
+ if (!Ty) {
470
+ GR->addDeducedElementType (Op, KnownElemTy);
471
+ // check if there is existing Intrinsic::spv_assign_ptr_type instruction
472
+ auto It = AssignPtrTypeInstr.find (Op);
473
+ if (It == AssignPtrTypeInstr.end ()) {
474
+ CallInst *CI =
475
+ buildIntrWithMD (Intrinsic::spv_assign_ptr_type, {OpTy}, OpTyVal, Op,
476
+ {B.getInt32 (getPointerAddressSpace (OpTy))}, B);
477
+ AssignPtrTypeInstr[Op] = CI;
478
+ } else {
479
+ It->second ->setArgOperand (
480
+ 1 ,
481
+ MetadataAsValue::get (
482
+ Ctx, MDNode::get (Ctx, ValueAsMetadata::getConstant (OpTyVal))));
483
+ }
484
+ } else {
485
+ SmallVector<Type *, 2 > Types = {OpTy, OpTy};
486
+ MetadataAsValue *VMD = MetadataAsValue::get (
487
+ Ctx, MDNode::get (Ctx, ValueAsMetadata::getConstant (OpTyVal)));
488
+ SmallVector<Value *, 2 > Args = {Op, VMD,
489
+ B.getInt32 (getPointerAddressSpace (OpTy))};
490
+ CallInst *PtrCastI =
491
+ B.CreateIntrinsic (Intrinsic::spv_ptrcast, {Types}, Args);
492
+ I->setOperand (OpIt.second , PtrCastI);
493
+ }
494
+ }
495
+ }
496
+
371
497
void SPIRVEmitIntrinsics::replaceMemInstrUses (Instruction *Old,
372
498
Instruction *New,
373
499
IRBuilder<> &B) {
@@ -630,6 +756,7 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
630
756
ExpectedElementTypeConst, Pointer, {B.getInt32 (AddressSpace)}, B);
631
757
GR->addDeducedElementType (CI, ExpectedElementType);
632
758
GR->addDeducedElementType (Pointer, ExpectedElementType);
759
+ AssignPtrTypeInstr[Pointer] = CI;
633
760
return ;
634
761
}
635
762
@@ -914,6 +1041,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
914
1041
CallInst *CI = buildIntrWithMD (Intrinsic::spv_assign_ptr_type, {I->getType ()},
915
1042
EltTyConst, I, {B.getInt32 (AddressSpace)}, B);
916
1043
GR->addDeducedElementType (CI, ElemTy);
1044
+ AssignPtrTypeInstr[I] = CI;
917
1045
}
918
1046
919
1047
void SPIRVEmitIntrinsics::insertAssignTypeIntrs (Instruction *I,
@@ -1070,6 +1198,7 @@ void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
1070
1198
{B.getInt32 (getPointerAddressSpace (Arg->getType ()))}, B);
1071
1199
GR->addDeducedElementType (AssignPtrTyCI, ElemTy);
1072
1200
GR->addDeducedElementType (Arg, ElemTy);
1201
+ AssignPtrTypeInstr[Arg] = AssignPtrTyCI;
1073
1202
}
1074
1203
}
1075
1204
}
@@ -1114,6 +1243,10 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
1114
1243
insertAssignTypeIntrs (I, B);
1115
1244
insertPtrCastOrAssignTypeInstr (I, B);
1116
1245
}
1246
+
1247
+ for (auto &I : instructions (Func))
1248
+ deduceOperandElementType (&I);
1249
+
1117
1250
for (auto *I : Worklist) {
1118
1251
TrackConstants = true ;
1119
1252
if (!I->getType ()->isVoidTy () || isa<StoreInst>(I))
@@ -1126,13 +1259,29 @@ bool SPIRVEmitIntrinsics::runOnFunction(Function &Func) {
1126
1259
processInstrAfterVisit (I, B);
1127
1260
}
1128
1261
1129
- // check if function parameter types are set
1130
- if (!F->isIntrinsic ())
1131
- processParamTypes (F, B);
1132
-
1133
1262
return true ;
1134
1263
}
1135
1264
1136
- FunctionPass *llvm::createSPIRVEmitIntrinsicsPass (SPIRVTargetMachine *TM) {
1265
+ bool SPIRVEmitIntrinsics::runOnModule (Module &M) {
1266
+ bool Changed = false ;
1267
+
1268
+ for (auto &F : M) {
1269
+ Changed |= runOnFunction (F);
1270
+ }
1271
+
1272
+ for (auto &F : M) {
1273
+ // check if function parameter types are set
1274
+ if (!F.isDeclaration () && !F.isIntrinsic ()) {
1275
+ const SPIRVSubtarget &ST = TM->getSubtarget <SPIRVSubtarget>(F);
1276
+ GR = ST.getSPIRVGlobalRegistry ();
1277
+ IRBuilder<> B (F.getContext ());
1278
+ processParamTypes (&F, B);
1279
+ }
1280
+ }
1281
+
1282
+ return Changed;
1283
+ }
1284
+
1285
+ ModulePass *llvm::createSPIRVEmitIntrinsicsPass (SPIRVTargetMachine *TM) {
1137
1286
return new SPIRVEmitIntrinsics (TM);
1138
1287
}
0 commit comments