17
17
#include " SPIRVSubtarget.h"
18
18
#include " SPIRVTargetMachine.h"
19
19
#include " SPIRVUtils.h"
20
+ #include " llvm/ADT/DenseSet.h"
20
21
#include " llvm/IR/IRBuilder.h"
21
22
#include " llvm/IR/InstIterator.h"
22
23
#include " llvm/IR/InstVisitor.h"
@@ -80,7 +81,8 @@ class SPIRVEmitIntrinsics
80
81
unsigned TodoTypeSz = 0 ;
81
82
DenseMap<Value *, bool > TodoType;
82
83
void insertTodoType (Value *Op) {
83
- if (CanTodoType) {
84
+ // TODO: add isa<CallInst>(Op) to no-insert
85
+ if (CanTodoType && !isa<GetElementPtrInst>(Op)) {
84
86
auto It = TodoType.try_emplace (Op, true );
85
87
if (It.second )
86
88
++TodoTypeSz;
@@ -94,9 +96,14 @@ class SPIRVEmitIntrinsics
94
96
}
95
97
}
96
98
bool isTodoType (Value *Op) {
99
+ if (isa<GetElementPtrInst>(Op))
100
+ return false ;
97
101
auto It = TodoType.find (Op);
98
102
return It != TodoType.end () && It->second ;
99
103
}
104
+ // a register of Instructions that were visited by deduceOperandElementType()
105
+ // to validate operand types with an instruction
106
+ std::unordered_set<Instruction *> TypeValidated;
100
107
101
108
// well known result types of builtins
102
109
enum WellKnownTypes { Event };
@@ -178,10 +185,17 @@ class SPIRVEmitIntrinsics
178
185
Type *&KnownElemTy, bool IsPostprocessing);
179
186
180
187
CallInst *buildSpvPtrcast (Function *F, Value *Op, Type *ElemTy);
181
- void propagateElemType (Value *Op, Type *ElemTy);
182
- void propagateElemTypeRec (Value *Op, Type *PtrElemTy, Type *CastElemTy);
188
+ void replaceUsesOfWithSpvPtrcast (Value *Op, Type *ElemTy, Instruction *I,
189
+ DenseMap<Function *, CallInst *> Ptrcasts);
190
+ void propagateElemType (Value *Op, Type *ElemTy,
191
+ DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
192
+ void
193
+ propagateElemTypeRec (Value *Op, Type *PtrElemTy, Type *CastElemTy,
194
+ DenseSet<std::pair<Value *, Value *>> &VisitedSubst);
183
195
void propagateElemTypeRec (Value *Op, Type *PtrElemTy, Type *CastElemTy,
184
- std::unordered_set<Value *> &Visited);
196
+ DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
197
+ std::unordered_set<Value *> &Visited,
198
+ DenseMap<Function *, CallInst *> Ptrcasts);
185
199
186
200
void replaceAllUsesWith (Value *Src, Value *Dest, bool DeleteOld = true );
187
201
@@ -439,38 +453,63 @@ CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
439
453
return PtrCasted;
440
454
}
441
455
442
- void SPIRVEmitIntrinsics::propagateElemType (Value *Op, Type *ElemTy) {
456
+ void SPIRVEmitIntrinsics::replaceUsesOfWithSpvPtrcast (
457
+ Value *Op, Type *ElemTy, Instruction *I,
458
+ DenseMap<Function *, CallInst *> Ptrcasts) {
459
+ Function *F = I->getParent ()->getParent ();
460
+ CallInst *PtrCastedI = nullptr ;
461
+ auto It = Ptrcasts.find (F);
462
+ if (It == Ptrcasts.end ()) {
463
+ PtrCastedI = buildSpvPtrcast (F, Op, ElemTy);
464
+ Ptrcasts[F] = PtrCastedI;
465
+ } else {
466
+ PtrCastedI = It->second ;
467
+ }
468
+ I->replaceUsesOfWith (Op, PtrCastedI);
469
+ }
470
+
471
+ void SPIRVEmitIntrinsics::propagateElemType (
472
+ Value *Op, Type *ElemTy,
473
+ DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
474
+ DenseMap<Function *, CallInst *> Ptrcasts;
443
475
SmallVector<User *> Users (Op->users ());
444
476
for (auto *U : Users) {
445
- if (!isa<Instruction>(U))
477
+ if (!isa<Instruction>(U) || isa<BitCastInst>(U) || isSpvIntrinsic (U) )
446
478
continue ;
447
- if (isa<BitCastInst>(U) || isa<GetElementPtrInst>(U) || isSpvIntrinsic (U) )
479
+ if (!VisitedSubst. insert ( std::make_pair (U, Op)). second )
448
480
continue ;
449
- U->replaceUsesOfWith (
450
- Op, buildSpvPtrcast (dyn_cast<Instruction>(U)->getParent ()->getParent (),
451
- Op, ElemTy));
481
+ Instruction *UI = dyn_cast<Instruction>(U);
482
+ // If the instruction was validated already, we need to keep it valid by
483
+ // keeping current Op type.
484
+ if (isa<GetElementPtrInst>(UI) ||
485
+ TypeValidated.find (UI) != TypeValidated.end ())
486
+ replaceUsesOfWithSpvPtrcast (Op, ElemTy, UI, Ptrcasts);
452
487
}
453
488
}
454
489
455
- void SPIRVEmitIntrinsics::propagateElemTypeRec (Value *Op, Type *PtrElemTy,
456
- Type *CastElemTy) {
457
- if (!isNestedPointer (PtrElemTy))
458
- return ;
490
+ void SPIRVEmitIntrinsics::propagateElemTypeRec (
491
+ Value *Op, Type *PtrElemTy, Type *CastElemTy,
492
+ DenseSet<std::pair<Value *, Value *>> &VisitedSubst) {
459
493
std::unordered_set<Value *> Visited;
460
- propagateElemTypeRec (Op, PtrElemTy, CastElemTy, Visited);
494
+ DenseMap<Function *, CallInst *> Ptrcasts;
495
+ propagateElemTypeRec (Op, PtrElemTy, CastElemTy, VisitedSubst, Visited,
496
+ Ptrcasts);
461
497
}
462
498
463
499
void SPIRVEmitIntrinsics::propagateElemTypeRec (
464
500
Value *Op, Type *PtrElemTy, Type *CastElemTy,
465
- std::unordered_set<Value *> &Visited) {
501
+ DenseSet<std::pair<Value *, Value *>> &VisitedSubst,
502
+ std::unordered_set<Value *> &Visited,
503
+ DenseMap<Function *, CallInst *> Ptrcasts) {
466
504
if (!Visited.insert (Op).second )
467
505
return ;
468
506
SmallVector<User *> Users (Op->users ());
469
507
for (auto *U : Users) {
470
- if (!isa<Instruction>(U))
508
+ if (!isa<Instruction>(U) || isa<BitCastInst>(U) || isSpvIntrinsic (U) )
471
509
continue ;
472
- if (isa<BitCastInst>(U) || isSpvIntrinsic (U) )
510
+ if (!VisitedSubst. insert ( std::make_pair (U, Op)). second )
473
511
continue ;
512
+ /*
474
513
if (auto *Ref = dyn_cast<GetElementPtrInst>(U)) {
475
514
CallInst *AssignCI = GR->findAssignPtrTypeInstr(Ref);
476
515
if (AssignCI && Ref->getPointerOperand() == Op) {
@@ -485,14 +524,18 @@ void SPIRVEmitIntrinsics::propagateElemTypeRec(
485
524
assert(NewElemTy && "Expected valid GEP indices");
486
525
updateAssignType(AssignCI, Ref, PoisonValue::get(NewElemTy));
487
526
// recursively propagate change
488
- if ( isNestedPointer ( NewElemTy))
489
- propagateElemTypeRec (Ref, NewElemTy, PrevElemTy, Visited );
527
+ propagateElemTypeRec(Ref, NewElemTy, PrevElemTy, VisitedSubst, Visited,
528
+ Ptrcasts );
490
529
}
491
530
continue;
492
531
}
493
- U->replaceUsesOfWith (
494
- Op, buildSpvPtrcast (dyn_cast<Instruction>(U)->getParent ()->getParent (),
495
- Op, CastElemTy));
532
+ */
533
+ Instruction *UI = dyn_cast<Instruction>(U);
534
+ // If the instruction was validated already, we need to keep it valid by
535
+ // keeping current Op type.
536
+ if (isa<GetElementPtrInst>(UI) ||
537
+ TypeValidated.find (UI) != TypeValidated.end ())
538
+ replaceUsesOfWithSpvPtrcast (Op, CastElemTy, UI, Ptrcasts);
496
539
}
497
540
}
498
541
@@ -600,13 +643,34 @@ Type *SPIRVEmitIntrinsics::deduceElementTypeHelper(
600
643
if (auto *Ref = dyn_cast<AllocaInst>(I)) {
601
644
maybeAssignPtrType (Ty, I, Ref->getAllocatedType (), UnknownElemTypeI8);
602
645
} else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
603
- Ty = Ref->getResultElementType ();
646
+ // TODO: not sure if GetElementPtrInst::getTypeAtIndex() does anything
647
+ // useful here
648
+ if (isNestedPointer (Ref->getSourceElementType ())) {
649
+ Ty = Ref->getSourceElementType ();
650
+ for (Use &U : drop_begin (Ref->indices ()))
651
+ Ty = GetElementPtrInst::getTypeAtIndex (Ty, U.get ());
652
+ } else {
653
+ Ty = Ref->getResultElementType ();
654
+ }
655
+ /*
656
+ if (Type *PtrElemTy = GR->findDeducedElementType(Ref->getPointerOperand()))
657
+ { Ty = PtrElemTy; for (Use &U : drop_begin(Ref->indices())) Ty =
658
+ GetElementPtrInst::getTypeAtIndex(Ty, U.get()); if
659
+ (isTodoType(Ref->getPointerOperand())) insertTodoType(Ref); } else if
660
+ (isNestedPointer(Ref->getSourceElementType())) { Ty =
661
+ Ref->getSourceElementType(); for (Use &U : drop_begin(Ref->indices())) Ty =
662
+ GetElementPtrInst::getTypeAtIndex(Ty, U.get()); } else { Ty =
663
+ Ref->getResultElementType();
664
+ }
665
+ */
666
+ /*
604
667
if (isNestedPointer(Ref->getSourceElementType())) {
605
668
Type *PtrElemTy = GR->findDeducedElementType(Ref->getPointerOperand());
606
669
Ty = PtrElemTy ? PtrElemTy : Ref->getSourceElementType();
607
670
for (Use &U : drop_begin(Ref->indices()))
608
671
Ty = GetElementPtrInst::getTypeAtIndex(Ty, U.get());
609
672
}
673
+ */
610
674
} else if (auto *Ref = dyn_cast<LoadInst>(I)) {
611
675
Value *Op = Ref->getPointerOperand ();
612
676
Type *KnownTy = GR->findDeducedElementType (Op);
@@ -934,7 +998,6 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(
934
998
Uncomplete = isTodoType (I);
935
999
Ops.push_back (std::make_pair (Ref->getPointerOperand (), 0 ));
936
1000
} else if (auto *Ref = dyn_cast<GetElementPtrInst>(I)) {
937
- // TODO: ensure that getPointerOperand() and GEP result type are consistent
938
1001
if (GR->findDeducedElementType (Ref->getPointerOperand ()))
939
1002
return ;
940
1003
KnownElemTy = Ref->getSourceElementType ();
@@ -992,17 +1055,20 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(
992
1055
GR->addDeducedElementType (CurrF, OpElemTy);
993
1056
GR->addReturnType (CurrF, TypedPointerType::get (
994
1057
OpElemTy, getPointerAddressSpace (RetTy)));
1058
+ DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1059
+ std::make_pair (I, Op)};
995
1060
for (User *U : CurrF->users ()) {
996
1061
CallInst *CI = dyn_cast<CallInst>(U);
997
1062
if (!CI || CI->getCalledFunction () != CurrF)
998
1063
continue ;
999
1064
if (CallInst *AssignCI = GR->findAssignPtrTypeInstr (CI)) {
1000
1065
if (Type *PrevElemTy = GR->findDeducedElementType (CI)) {
1001
1066
updateAssignType (AssignCI, CI, PoisonValue::get (OpElemTy));
1002
- propagateElemType (CI, PrevElemTy);
1067
+ propagateElemType (CI, PrevElemTy, VisitedSubst );
1003
1068
}
1004
1069
}
1005
1070
}
1071
+ TypeValidated.insert (I);
1006
1072
}
1007
1073
return ;
1008
1074
}
@@ -1075,7 +1141,9 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(
1075
1141
} else {
1076
1142
Type *PrevElemTy = GR->findDeducedElementType (Op);
1077
1143
updateAssignType (AssignCI, Op, OpTyVal);
1078
- propagateElemTypeRec (Op, KnownElemTy, PrevElemTy);
1144
+ DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1145
+ std::make_pair (I, Op)};
1146
+ propagateElemTypeRec (Op, KnownElemTy, PrevElemTy, VisitedSubst);
1079
1147
}
1080
1148
} else {
1081
1149
eraseTodoType (Op);
@@ -1087,6 +1155,7 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(
1087
1155
I->setOperand (OpIt.second , PtrCastI);
1088
1156
}
1089
1157
}
1158
+ TypeValidated.insert (I);
1090
1159
}
1091
1160
1092
1161
void SPIRVEmitIntrinsics::replaceMemInstrUses (Instruction *Old,
@@ -1293,10 +1362,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
1293
1362
Type *VTy = V->getType ();
1294
1363
1295
1364
// A couple of sanity checks.
1296
- assert ((isPointerTy (VTy) ||
1297
- (isa<TargetExtType>(VTy) &&
1298
- isTypedPointerWrapper (dyn_cast<TargetExtType>(VTy)))) &&
1299
- " Expect a pointer type!" );
1365
+ assert ((isPointerTy (VTy)) && " Expect a pointer type!" );
1300
1366
if (Type *ElemTy = getPointeeType (VTy))
1301
1367
if (ElemTy != AssignedType)
1302
1368
report_fatal_error (" Unexpected pointer element type!" );
@@ -1329,6 +1395,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
1329
1395
void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast (
1330
1396
Instruction *I, Value *Pointer, Type *ExpectedElementType,
1331
1397
unsigned OperandToReplace, IRBuilder<> &B) {
1398
+ TypeValidated.insert (I);
1332
1399
// If Pointer is the result of nop BitCastInst (ptr -> ptr), use the source
1333
1400
// pointer instead. The BitCastInst should be later removed when visited.
1334
1401
while (BitCastInst *BC = dyn_cast<BitCastInst>(Pointer))
@@ -1392,8 +1459,11 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
1392
1459
// uncomplete, update spv_assign_ptr_type arguments.
1393
1460
if (CallInst *AssignCI = GR->findAssignPtrTypeInstr (Pointer)) {
1394
1461
Type *PrevElemTy = GR->findDeducedElementType (Pointer);
1462
+ assert (PrevElemTy);
1463
+ DenseSet<std::pair<Value *, Value *>> VisitedSubst{
1464
+ std::make_pair (I, Pointer)};
1395
1465
updateAssignType (AssignCI, Pointer, ExpectedElementVal);
1396
- propagateElemTypeRec (Pointer, ExpectedElementType, PrevElemTy );
1466
+ propagateElemType (Pointer, PrevElemTy, VisitedSubst );
1397
1467
} else {
1398
1468
buildAssignPtr (B, ExpectedElementType, Pointer);
1399
1469
}
@@ -1422,15 +1492,20 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
1422
1492
}
1423
1493
if (SI) {
1424
1494
Value *Op = SI->getValueOperand ();
1495
+ Value *Pointer = SI->getPointerOperand ();
1496
+ // if (!GR->findDeducedElementType(Pointer) || isTodoType(Pointer)) {
1425
1497
Type *OpTy = Op->getType ();
1426
1498
if (auto *OpI = dyn_cast<Instruction>(Op))
1427
1499
OpTy = restoreMutatedType (GR, OpI, OpTy);
1428
1500
if (OpTy == Op->getType ())
1429
1501
OpTy = deduceElementTypeByValueDeep (OpTy, Op, false );
1430
- return replacePointerOperandWithPtrCast (I, SI->getPointerOperand (), OpTy, 1 ,
1431
- B);
1432
- } else if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
1502
+ replacePointerOperandWithPtrCast (I, Pointer, OpTy, 1 , B);
1503
+ // }
1504
+ return ;
1505
+ }
1506
+ if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
1433
1507
Value *Pointer = LI->getPointerOperand ();
1508
+ // if (!GR->findDeducedElementType(Pointer) || isTodoType(Pointer)) {
1434
1509
Type *OpTy = LI->getType ();
1435
1510
if (auto *PtrTy = dyn_cast<PointerType>(OpTy)) {
1436
1511
// TODO: isNestedPointer() instead of dyn_cast<PointerType>
@@ -1443,8 +1518,11 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
1443
1518
insertTodoType (Pointer);
1444
1519
}
1445
1520
}
1446
- return replacePointerOperandWithPtrCast (I, Pointer, OpTy, 0 , B);
1447
- } else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
1521
+ replacePointerOperandWithPtrCast (I, Pointer, OpTy, 0 , B);
1522
+ // }
1523
+ return ;
1524
+ }
1525
+ if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
1448
1526
Value *Pointer = GEPI->getPointerOperand ();
1449
1527
Type *OpTy = GEPI->getSourceElementType ();
1450
1528
replacePointerOperandWithPtrCast (I, Pointer, OpTy, 0 , B);
@@ -1522,7 +1600,8 @@ void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
1522
1600
if (!ExpectedType || ExpectedType->isVoidTy ())
1523
1601
continue ;
1524
1602
1525
- if (ExpectedType->isTargetExtTy ())
1603
+ if (ExpectedType->isTargetExtTy () &&
1604
+ !isTypedPointerWrapper (cast<TargetExtType>(ExpectedType)))
1526
1605
insertAssignPtrTypeTargetExt (cast<TargetExtType>(ExpectedType),
1527
1606
ArgOperand, B);
1528
1607
else
@@ -2155,6 +2234,7 @@ bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {
2155
2234
unsigned SzTodo = TodoTypeSz;
2156
2235
DenseMap<Value *, SmallPtrSet<Value *, 4 >> ToProcess;
2157
2236
for (auto [Op, Enabled] : TodoType) {
2237
+ // TODO: add isa<CallInst>(Op) to continue
2158
2238
if (!Enabled || isa<GetElementPtrInst>(Op))
2159
2239
continue ;
2160
2240
CallInst *AssignCI = GR->findAssignPtrTypeInstr (Op);
@@ -2168,11 +2248,12 @@ bool SPIRVEmitIntrinsics::postprocessTypes(Module &M) {
2168
2248
std::unordered_set<Value *> Visited;
2169
2249
if (Type *ElemTy = deduceElementTypeHelper (Op, Visited, false , true )) {
2170
2250
if (ElemTy != KnownTy) {
2251
+ DenseSet<std::pair<Value *, Value *>> VisitedSubst;
2171
2252
if (isa<CallInst>(Op)) {
2172
- propagateElemType (CI, ElemTy);
2253
+ propagateElemType (CI, ElemTy, VisitedSubst );
2173
2254
} else {
2174
2255
updateAssignType (AssignCI, CI, PoisonValue::get (ElemTy));
2175
- propagateElemTypeRec (CI, ElemTy, KnownTy);
2256
+ propagateElemTypeRec (CI, ElemTy, KnownTy, VisitedSubst );
2176
2257
}
2177
2258
eraseTodoType (Op);
2178
2259
continue ;
0 commit comments