Skip to content

Commit 7c8b127

Browse files
Keenutss-perron
andauthored
[SPIR-V] Add pass to remove spv_ptrcast intrinsics (#128896)
OpenCL is allowed to cast pointers, meaning they can resolve some type mismatches this way. In logical SPIR-V, those are restricted. This new pass legalizes such pointer cast when targeting logical SPIR-V. For now, this pass supports 3 cases we witnessed: - loading a vec3 from a vec4*. - loading a scalar from a vec*. - loading the 1st element of an array. --------- Co-authored-by: Steven Perron <[email protected]>
1 parent 2bef21f commit 7c8b127

11 files changed

+510
-113
lines changed

llvm/lib/Target/SPIRV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_llvm_target(SPIRVCodeGen
2727
SPIRVInstrInfo.cpp
2828
SPIRVInstructionSelector.cpp
2929
SPIRVStripConvergentIntrinsics.cpp
30+
SPIRVLegalizePointerCast.cpp
3031
SPIRVMergeRegionExitTargets.cpp
3132
SPIRVISelLowering.cpp
3233
SPIRVLegalizerInfo.cpp

llvm/lib/Target/SPIRV/SPIRV.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ ModulePass *createSPIRVPrepareFunctionsPass(const SPIRVTargetMachine &TM);
2323
FunctionPass *createSPIRVStructurizerPass();
2424
FunctionPass *createSPIRVMergeRegionExitTargetsPass();
2525
FunctionPass *createSPIRVStripConvergenceIntrinsicsPass();
26+
FunctionPass *createSPIRVLegalizePointerCastPass(SPIRVTargetMachine *TM);
2627
FunctionPass *createSPIRVRegularizerPass();
2728
FunctionPass *createSPIRVPreLegalizerCombiner();
2829
FunctionPass *createSPIRVPreLegalizerPass();

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 28 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,6 @@ void initializeSPIRVEmitIntrinsicsPass(PassRegistry &);
5757

5858
namespace {
5959

60-
inline MetadataAsValue *buildMD(Value *Arg) {
61-
LLVMContext &Ctx = Arg->getContext();
62-
return MetadataAsValue::get(
63-
Ctx, MDNode::get(Ctx, ValueAsMetadata::getConstant(Arg)));
64-
}
65-
6660
class SPIRVEmitIntrinsics
6761
: public ModulePass,
6862
public InstVisitor<SPIRVEmitIntrinsics, Instruction *> {
@@ -142,24 +136,9 @@ class SPIRVEmitIntrinsics
142136
void preprocessCompositeConstants(IRBuilder<> &B);
143137
void preprocessUndefs(IRBuilder<> &B);
144138

145-
CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
146-
Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
147-
IRBuilder<> &B) {
148-
SmallVector<Value *, 4> Args;
149-
Args.push_back(Arg2);
150-
Args.push_back(buildMD(Arg));
151-
for (auto *Imm : Imms)
152-
Args.push_back(Imm);
153-
return B.CreateIntrinsic(IntrID, {Types}, Args);
154-
}
155-
156139
Type *reconstructType(Value *Op, bool UnknownElemTypeI8,
157140
bool IsPostprocessing);
158141

159-
void buildAssignType(IRBuilder<> &B, Type *ElemTy, Value *Arg);
160-
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
161-
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType);
162-
163142
void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
164143
void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
165144
bool insertAssignPtrTypeIntrs(Instruction *I, IRBuilder<> &B,
@@ -273,18 +252,6 @@ bool expectIgnoredInIRTranslation(const Instruction *I) {
273252
}
274253
}
275254

276-
bool allowEmitFakeUse(const Value *Arg) {
277-
if (isSpvIntrinsic(Arg))
278-
return false;
279-
if (dyn_cast<AtomicCmpXchgInst>(Arg) || dyn_cast<InsertValueInst>(Arg) ||
280-
dyn_cast<UndefValue>(Arg))
281-
return false;
282-
if (const auto *LI = dyn_cast<LoadInst>(Arg))
283-
if (LI->getType()->isAggregateType())
284-
return false;
285-
return true;
286-
}
287-
288255
} // namespace
289256

290257
char SPIRVEmitIntrinsics::ID = 0;
@@ -355,10 +322,7 @@ static void emitAssignName(Instruction *I, IRBuilder<> &B) {
355322

356323
void SPIRVEmitIntrinsics::replaceAllUsesWith(Value *Src, Value *Dest,
357324
bool DeleteOld) {
358-
Src->replaceAllUsesWith(Dest);
359-
// Update deduced type records
360-
GR->updateIfExistDeducedElementType(Src, Dest, DeleteOld);
361-
GR->updateIfExistAssignPtrTypeInstr(Src, Dest, DeleteOld);
325+
GR->replaceAllUsesWith(Src, Dest, DeleteOld);
362326
// Update uncomplete type records if any
363327
if (isTodoType(Src)) {
364328
if (DeleteOld)
@@ -425,57 +389,6 @@ Type *SPIRVEmitIntrinsics::reconstructType(Value *Op, bool UnknownElemTypeI8,
425389
return nullptr;
426390
}
427391

428-
void SPIRVEmitIntrinsics::buildAssignType(IRBuilder<> &B, Type *Ty,
429-
Value *Arg) {
430-
Value *OfType = getNormalizedPoisonValue(Ty);
431-
CallInst *AssignCI = nullptr;
432-
if (Arg->getType()->isAggregateType() && Ty->isAggregateType() &&
433-
allowEmitFakeUse(Arg)) {
434-
LLVMContext &Ctx = Arg->getContext();
435-
SmallVector<Metadata *, 2> ArgMDs{
436-
MDNode::get(Ctx, ValueAsMetadata::getConstant(OfType)),
437-
MDString::get(Ctx, Arg->getName())};
438-
B.CreateIntrinsic(Intrinsic::spv_value_md, {},
439-
{MetadataAsValue::get(Ctx, MDTuple::get(Ctx, ArgMDs))});
440-
AssignCI = B.CreateIntrinsic(Intrinsic::fake_use, {}, {Arg});
441-
} else {
442-
AssignCI = buildIntrWithMD(Intrinsic::spv_assign_type, {Arg->getType()},
443-
OfType, Arg, {}, B);
444-
}
445-
GR->addAssignPtrTypeInstr(Arg, AssignCI);
446-
}
447-
448-
void SPIRVEmitIntrinsics::buildAssignPtr(IRBuilder<> &B, Type *ElemTy,
449-
Value *Arg) {
450-
ElemTy = normalizeType(ElemTy);
451-
Value *OfType = PoisonValue::get(ElemTy);
452-
CallInst *AssignPtrTyCI = GR->findAssignPtrTypeInstr(Arg);
453-
if (AssignPtrTyCI == nullptr ||
454-
AssignPtrTyCI->getParent()->getParent() != CurrF) {
455-
AssignPtrTyCI = buildIntrWithMD(
456-
Intrinsic::spv_assign_ptr_type, {Arg->getType()}, OfType, Arg,
457-
{B.getInt32(getPointerAddressSpace(Arg->getType()))}, B);
458-
GR->addDeducedElementType(AssignPtrTyCI, ElemTy);
459-
GR->addDeducedElementType(Arg, ElemTy);
460-
GR->addAssignPtrTypeInstr(Arg, AssignPtrTyCI);
461-
} else {
462-
updateAssignType(AssignPtrTyCI, Arg, OfType);
463-
}
464-
}
465-
466-
void SPIRVEmitIntrinsics::updateAssignType(CallInst *AssignCI, Value *Arg,
467-
Value *OfType) {
468-
AssignCI->setArgOperand(1, buildMD(OfType));
469-
if (cast<IntrinsicInst>(AssignCI)->getIntrinsicID() !=
470-
Intrinsic::spv_assign_ptr_type)
471-
return;
472-
473-
// update association with the pointee type
474-
Type *ElemTy = normalizeType(OfType->getType());
475-
GR->addDeducedElementType(AssignCI, ElemTy);
476-
GR->addDeducedElementType(Arg, ElemTy);
477-
}
478-
479392
CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
480393
Type *ElemTy) {
481394
IRBuilder<> B(Op->getContext());
@@ -495,7 +408,7 @@ CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
495408
B.getInt32(getPointerAddressSpace(OpTy))};
496409
CallInst *PtrCasted =
497410
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
498-
buildAssignPtr(B, ElemTy, PtrCasted);
411+
GR->buildAssignPtr(B, ElemTy, PtrCasted);
499412
return PtrCasted;
500413
}
501414

@@ -1032,7 +945,8 @@ bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1032945
continue;
1033946
if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(CI)) {
1034947
if (Type *PrevElemTy = GR->findDeducedElementType(CI)) {
1035-
updateAssignType(AssignCI, CI, getNormalizedPoisonValue(OpElemTy));
948+
GR->updateAssignType(AssignCI, CI,
949+
getNormalizedPoisonValue(OpElemTy));
1036950
propagateElemType(CI, PrevElemTy, VisitedSubst);
1037951
}
1038952
}
@@ -1218,7 +1132,7 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(
12181132
{B.getInt32(getPointerAddressSpace(OpTy))}, B);
12191133
GR->addAssignPtrTypeInstr(Op, CI);
12201134
} else {
1221-
updateAssignType(AssignCI, Op, OpTyVal);
1135+
GR->updateAssignType(AssignCI, Op, OpTyVal);
12221136
DenseSet<std::pair<Value *, Value *>> VisitedSubst{
12231137
std::make_pair(I, Op)};
12241138
propagateElemTypeRec(Op, KnownElemTy, PrevElemTy, VisitedSubst);
@@ -1508,7 +1422,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
15081422

15091423
CallInst *AssignCI = GR->findAssignPtrTypeInstr(V);
15101424
if (!AssignCI) {
1511-
buildAssignType(B, AssignedType, V);
1425+
GR->buildAssignType(B, AssignedType, V);
15121426
return;
15131427
}
15141428

@@ -1528,7 +1442,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
15281442

15291443
// Our previous guess about the type seems to be wrong, let's update
15301444
// inferred type according to a new, more precise type information.
1531-
updateAssignType(AssignCI, V, getNormalizedPoisonValue(AssignedType));
1445+
GR->updateAssignType(AssignCI, V, getNormalizedPoisonValue(AssignedType));
15321446
}
15331447

15341448
void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
@@ -1585,7 +1499,7 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
15851499
if (FirstPtrCastOrAssignPtrType) {
15861500
// If this would be the first spv_ptrcast, do not emit spv_ptrcast and
15871501
// emit spv_assign_ptr_type instead.
1588-
buildAssignPtr(B, ExpectedElementType, Pointer);
1502+
GR->buildAssignPtr(B, ExpectedElementType, Pointer);
15891503
return;
15901504
} else if (isTodoType(Pointer)) {
15911505
eraseTodoType(Pointer);
@@ -1597,10 +1511,10 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
15971511
assert(PrevElemTy);
15981512
DenseSet<std::pair<Value *, Value *>> VisitedSubst{
15991513
std::make_pair(I, Pointer)};
1600-
updateAssignType(AssignCI, Pointer, ExpectedElementVal);
1514+
GR->updateAssignType(AssignCI, Pointer, ExpectedElementVal);
16011515
propagateElemType(Pointer, PrevElemTy, VisitedSubst);
16021516
} else {
1603-
buildAssignPtr(B, ExpectedElementType, Pointer);
1517+
GR->buildAssignPtr(B, ExpectedElementType, Pointer);
16041518
}
16051519
return;
16061520
}
@@ -1613,7 +1527,7 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
16131527
auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
16141528
I->setOperand(OperandToReplace, PtrCastI);
16151529
// We need to set up a pointee type for the newly created spv_ptrcast.
1616-
buildAssignPtr(B, ExpectedElementType, PtrCastI);
1530+
GR->buildAssignPtr(B, ExpectedElementType, PtrCastI);
16171531
}
16181532

16191533
void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
@@ -1929,7 +1843,7 @@ bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
19291843

19301844
setInsertPointAfterDef(B, I);
19311845
if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {
1932-
buildAssignPtr(B, ElemTy, I);
1846+
GR->buildAssignPtr(B, ElemTy, I);
19331847
return false;
19341848
}
19351849
return true;
@@ -1962,8 +1876,8 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
19621876
setInsertPointAfterDef(B, I);
19631877
switch (ResIt->second) {
19641878
case WellKnownTypes::Event:
1965-
buildAssignType(B, TargetExtType::get(I->getContext(), "spirv.Event"),
1966-
I);
1879+
GR->buildAssignType(
1880+
B, TargetExtType::get(I->getContext(), "spirv.Event"), I);
19671881
break;
19681882
}
19691883
}
@@ -2008,7 +1922,7 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
20081922
}
20091923
}
20101924
TypeToAssign = restoreMutatedType(GR, I, TypeToAssign);
2011-
buildAssignType(B, TypeToAssign, I);
1925+
GR->buildAssignType(B, TypeToAssign, I);
20121926
}
20131927
for (const auto &Op : I->operands()) {
20141928
if (isa<ConstantPointerNull>(Op) || isa<UndefValue>(Op) ||
@@ -2025,10 +1939,11 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
20251939
Type *OpTy = Op->getType();
20261940
Type *OpTyElem = getPointeeType(OpTy);
20271941
if (OpTyElem) {
2028-
buildAssignPtr(B, OpTyElem, Op);
1942+
GR->buildAssignPtr(B, OpTyElem, Op);
20291943
} else if (isPointerTy(OpTy)) {
20301944
Type *ElemTy = GR->findDeducedElementType(Op);
2031-
buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true), Op);
1945+
GR->buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true),
1946+
Op);
20321947
} else {
20331948
CallInst *AssignCI =
20341949
buildIntrWithMD(Intrinsic::spv_assign_type, {OpTy},
@@ -2089,14 +2004,14 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
20892004
if (!IsConstComposite && isPointerTy(OpTy) &&
20902005
(OpElemTy = GR->findDeducedElementType(Op)) != nullptr &&
20912006
OpElemTy != IntegerType::getInt8Ty(I->getContext())) {
2092-
buildAssignPtr(B, IntegerType::getInt8Ty(I->getContext()), NewOp);
2007+
GR->buildAssignPtr(B, IntegerType::getInt8Ty(I->getContext()), NewOp);
20932008
SmallVector<Type *, 2> Types = {OpTy, OpTy};
20942009
SmallVector<Value *, 2> Args = {
20952010
NewOp, buildMD(getNormalizedPoisonValue(OpElemTy)),
20962011
B.getInt32(getPointerAddressSpace(OpTy))};
20972012
CallInst *PtrCasted =
20982013
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
2099-
buildAssignPtr(B, OpElemTy, PtrCasted);
2014+
GR->buildAssignPtr(B, OpElemTy, PtrCasted);
21002015
NewOp = PtrCasted;
21012016
}
21022017
I->setOperand(OpNo, NewOp);
@@ -2178,7 +2093,7 @@ void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
21782093
continue;
21792094
if (hasPointeeTypeAttr(Arg) &&
21802095
(ElemTy = getPointeeTypeByAttr(Arg)) != nullptr) {
2181-
buildAssignPtr(B, ElemTy, Arg);
2096+
GR->buildAssignPtr(B, ElemTy, Arg);
21822097
continue;
21832098
}
21842099
// search in function's call sites
@@ -2194,7 +2109,7 @@ void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
21942109
break;
21952110
}
21962111
if (ElemTy) {
2197-
buildAssignPtr(B, ElemTy, Arg);
2112+
GR->buildAssignPtr(B, ElemTy, Arg);
21982113
continue;
21992114
}
22002115
if (HaveFunPtrs) {
@@ -2206,7 +2121,7 @@ void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
22062121
SmallVector<std::pair<Value *, unsigned>> Ops;
22072122
deduceOperandElementTypeFunctionPointer(CI, Ops, ElemTy, false);
22082123
if (ElemTy) {
2209-
buildAssignPtr(B, ElemTy, Arg);
2124+
GR->buildAssignPtr(B, ElemTy, Arg);
22102125
break;
22112126
}
22122127
}
@@ -2225,11 +2140,11 @@ void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
22252140
if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr) {
22262141
if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Arg)) {
22272142
DenseSet<std::pair<Value *, Value *>> VisitedSubst;
2228-
updateAssignType(AssignCI, Arg, getNormalizedPoisonValue(ElemTy));
2143+
GR->updateAssignType(AssignCI, Arg, getNormalizedPoisonValue(ElemTy));
22292144
propagateElemType(Arg, IntegerType::getInt8Ty(F->getContext()),
22302145
VisitedSubst);
22312146
} else {
2232-
buildAssignPtr(B, ElemTy, Arg);
2147+
GR->buildAssignPtr(B, ElemTy, Arg);
22332148
}
22342149
}
22352150
}
@@ -2279,7 +2194,7 @@ bool SPIRVEmitIntrinsics::processFunctionPointers(Module &M) {
22792194
continue;
22802195
if (II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
22812196
II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
2282-
updateAssignType(II, &F, getNormalizedPoisonValue(FPElemTy));
2197+
GR->updateAssignType(II, &F, getNormalizedPoisonValue(FPElemTy));
22832198
break;
22842199
}
22852200
}
@@ -2331,7 +2246,7 @@ void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {
23312246
if (!hasPointeeTypeAttr(Arg)) {
23322247
B.SetInsertPointPastAllocas(Arg->getParent());
23332248
B.SetCurrentDebugLocation(DebugLoc());
2334-
buildAssignPtr(B, ElemTy, Arg);
2249+
GR->buildAssignPtr(B, ElemTy, Arg);
23352250
}
23362251
} else if (isa<GetElementPtrInst>(Param)) {
23372252
replaceUsesOfWithSpvPtrcast(Param, normalizeType(ElemTy), CI,
@@ -2344,7 +2259,7 @@ void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {
23442259
->getParent()
23452260
->getEntryBlock()
23462261
.getFirstNonPHIOrDbgOrAlloca());
2347-
buildAssignPtr(B, ElemTy, Param);
2262+
GR->buildAssignPtr(B, ElemTy, Param);
23482263
}
23492264
CallInst *Ref = dyn_cast<CallInst>(Param);
23502265
if (!Ref)

0 commit comments

Comments
 (0)