Skip to content

Commit 0ed4b57

Browse files
committed
[SPIR-V] Add pass to remove spv_ptrcast intrinsics
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.
1 parent defe43b commit 0ed4b57

File tree

11 files changed

+517
-71
lines changed

11 files changed

+517
-71
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+
SPIRVLegalizePointerLoad.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 *createSPIRVLegalizePointerLoadPass(SPIRVTargetMachine *TM);
2627
FunctionPass *createSPIRVRegularizerPass();
2728
FunctionPass *createSPIRVPreLegalizerCombiner();
2829
FunctionPass *createSPIRVPreLegalizerPass();

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 23 additions & 71 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,23 +136,10 @@ 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

159142
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);
162143

163144
void replaceMemInstrUses(Instruction *Old, Instruction *New, IRBuilder<> &B);
164145
void processInstrAfterVisit(Instruction *I, IRBuilder<> &B);
@@ -445,37 +426,6 @@ void SPIRVEmitIntrinsics::buildAssignType(IRBuilder<> &B, Type *Ty,
445426
GR->addAssignPtrTypeInstr(Arg, AssignCI);
446427
}
447428

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-
479429
CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
480430
Type *ElemTy) {
481431
IRBuilder<> B(Op->getContext());
@@ -495,7 +445,7 @@ CallInst *SPIRVEmitIntrinsics::buildSpvPtrcast(Function *F, Value *Op,
495445
B.getInt32(getPointerAddressSpace(OpTy))};
496446
CallInst *PtrCasted =
497447
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
498-
buildAssignPtr(B, ElemTy, PtrCasted);
448+
GR->buildAssignPtr(B, ElemTy, PtrCasted);
499449
return PtrCasted;
500450
}
501451

@@ -1026,7 +976,8 @@ bool SPIRVEmitIntrinsics::deduceOperandElementTypeFunctionRet(
1026976
continue;
1027977
if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(CI)) {
1028978
if (Type *PrevElemTy = GR->findDeducedElementType(CI)) {
1029-
updateAssignType(AssignCI, CI, getNormalizedPoisonValue(OpElemTy));
979+
GR->updateAssignType(AssignCI, CI,
980+
getNormalizedPoisonValue(OpElemTy));
1030981
propagateElemType(CI, PrevElemTy, VisitedSubst);
1031982
}
1032983
}
@@ -1212,7 +1163,7 @@ void SPIRVEmitIntrinsics::deduceOperandElementType(
12121163
{B.getInt32(getPointerAddressSpace(OpTy))}, B);
12131164
GR->addAssignPtrTypeInstr(Op, CI);
12141165
} else {
1215-
updateAssignType(AssignCI, Op, OpTyVal);
1166+
GR->updateAssignType(AssignCI, Op, OpTyVal);
12161167
DenseSet<std::pair<Value *, Value *>> VisitedSubst{
12171168
std::make_pair(I, Op)};
12181169
propagateElemTypeRec(Op, KnownElemTy, PrevElemTy, VisitedSubst);
@@ -1522,7 +1473,7 @@ void SPIRVEmitIntrinsics::insertAssignPtrTypeTargetExt(
15221473

15231474
// Our previous guess about the type seems to be wrong, let's update
15241475
// inferred type according to a new, more precise type information.
1525-
updateAssignType(AssignCI, V, getNormalizedPoisonValue(AssignedType));
1476+
GR->updateAssignType(AssignCI, V, getNormalizedPoisonValue(AssignedType));
15261477
}
15271478

15281479
void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
@@ -1579,7 +1530,7 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
15791530
if (FirstPtrCastOrAssignPtrType) {
15801531
// If this would be the first spv_ptrcast, do not emit spv_ptrcast and
15811532
// emit spv_assign_ptr_type instead.
1582-
buildAssignPtr(B, ExpectedElementType, Pointer);
1533+
GR->buildAssignPtr(B, ExpectedElementType, Pointer);
15831534
return;
15841535
} else if (isTodoType(Pointer)) {
15851536
eraseTodoType(Pointer);
@@ -1591,10 +1542,10 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
15911542
assert(PrevElemTy);
15921543
DenseSet<std::pair<Value *, Value *>> VisitedSubst{
15931544
std::make_pair(I, Pointer)};
1594-
updateAssignType(AssignCI, Pointer, ExpectedElementVal);
1545+
GR->updateAssignType(AssignCI, Pointer, ExpectedElementVal);
15951546
propagateElemType(Pointer, PrevElemTy, VisitedSubst);
15961547
} else {
1597-
buildAssignPtr(B, ExpectedElementType, Pointer);
1548+
GR->buildAssignPtr(B, ExpectedElementType, Pointer);
15981549
}
15991550
return;
16001551
}
@@ -1607,7 +1558,7 @@ void SPIRVEmitIntrinsics::replacePointerOperandWithPtrCast(
16071558
auto *PtrCastI = B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
16081559
I->setOperand(OperandToReplace, PtrCastI);
16091560
// We need to set up a pointee type for the newly created spv_ptrcast.
1610-
buildAssignPtr(B, ExpectedElementType, PtrCastI);
1561+
GR->buildAssignPtr(B, ExpectedElementType, PtrCastI);
16111562
}
16121563

16131564
void SPIRVEmitIntrinsics::insertPtrCastOrAssignTypeInstr(Instruction *I,
@@ -1923,7 +1874,7 @@ bool SPIRVEmitIntrinsics::insertAssignPtrTypeIntrs(Instruction *I,
19231874

19241875
setInsertPointAfterDef(B, I);
19251876
if (Type *ElemTy = deduceElementType(I, UnknownElemTypeI8)) {
1926-
buildAssignPtr(B, ElemTy, I);
1877+
GR->buildAssignPtr(B, ElemTy, I);
19271878
return false;
19281879
}
19291880
return true;
@@ -2019,10 +1970,11 @@ void SPIRVEmitIntrinsics::insertAssignTypeIntrs(Instruction *I,
20191970
Type *OpTy = Op->getType();
20201971
Type *OpTyElem = getPointeeType(OpTy);
20211972
if (OpTyElem) {
2022-
buildAssignPtr(B, OpTyElem, Op);
1973+
GR->buildAssignPtr(B, OpTyElem, Op);
20231974
} else if (isPointerTy(OpTy)) {
20241975
Type *ElemTy = GR->findDeducedElementType(Op);
2025-
buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true), Op);
1976+
GR->buildAssignPtr(B, ElemTy ? ElemTy : deduceElementType(Op, true),
1977+
Op);
20261978
} else {
20271979
CallInst *AssignCI =
20281980
buildIntrWithMD(Intrinsic::spv_assign_type, {OpTy},
@@ -2083,14 +2035,14 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
20832035
if (!IsConstComposite && isPointerTy(OpTy) &&
20842036
(OpElemTy = GR->findDeducedElementType(Op)) != nullptr &&
20852037
OpElemTy != IntegerType::getInt8Ty(I->getContext())) {
2086-
buildAssignPtr(B, IntegerType::getInt8Ty(I->getContext()), NewOp);
2038+
GR->buildAssignPtr(B, IntegerType::getInt8Ty(I->getContext()), NewOp);
20872039
SmallVector<Type *, 2> Types = {OpTy, OpTy};
20882040
SmallVector<Value *, 2> Args = {
20892041
NewOp, buildMD(getNormalizedPoisonValue(OpElemTy)),
20902042
B.getInt32(getPointerAddressSpace(OpTy))};
20912043
CallInst *PtrCasted =
20922044
B.CreateIntrinsic(Intrinsic::spv_ptrcast, {Types}, Args);
2093-
buildAssignPtr(B, OpElemTy, PtrCasted);
2045+
GR->buildAssignPtr(B, OpElemTy, PtrCasted);
20942046
NewOp = PtrCasted;
20952047
}
20962048
I->setOperand(OpNo, NewOp);
@@ -2172,7 +2124,7 @@ void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
21722124
continue;
21732125
if (hasPointeeTypeAttr(Arg) &&
21742126
(ElemTy = getPointeeTypeByAttr(Arg)) != nullptr) {
2175-
buildAssignPtr(B, ElemTy, Arg);
2127+
GR->buildAssignPtr(B, ElemTy, Arg);
21762128
continue;
21772129
}
21782130
// search in function's call sites
@@ -2188,7 +2140,7 @@ void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
21882140
break;
21892141
}
21902142
if (ElemTy) {
2191-
buildAssignPtr(B, ElemTy, Arg);
2143+
GR->buildAssignPtr(B, ElemTy, Arg);
21922144
continue;
21932145
}
21942146
if (HaveFunPtrs) {
@@ -2200,7 +2152,7 @@ void SPIRVEmitIntrinsics::processParamTypesByFunHeader(Function *F,
22002152
SmallVector<std::pair<Value *, unsigned>> Ops;
22012153
deduceOperandElementTypeFunctionPointer(CI, Ops, ElemTy, false);
22022154
if (ElemTy) {
2203-
buildAssignPtr(B, ElemTy, Arg);
2155+
GR->buildAssignPtr(B, ElemTy, Arg);
22042156
break;
22052157
}
22062158
}
@@ -2219,11 +2171,11 @@ void SPIRVEmitIntrinsics::processParamTypes(Function *F, IRBuilder<> &B) {
22192171
if (!ElemTy && (ElemTy = deduceFunParamElementType(F, OpIdx)) != nullptr) {
22202172
if (CallInst *AssignCI = GR->findAssignPtrTypeInstr(Arg)) {
22212173
DenseSet<std::pair<Value *, Value *>> VisitedSubst;
2222-
updateAssignType(AssignCI, Arg, getNormalizedPoisonValue(ElemTy));
2174+
GR->updateAssignType(AssignCI, Arg, getNormalizedPoisonValue(ElemTy));
22232175
propagateElemType(Arg, IntegerType::getInt8Ty(F->getContext()),
22242176
VisitedSubst);
22252177
} else {
2226-
buildAssignPtr(B, ElemTy, Arg);
2178+
GR->buildAssignPtr(B, ElemTy, Arg);
22272179
}
22282180
}
22292181
}
@@ -2273,7 +2225,7 @@ bool SPIRVEmitIntrinsics::processFunctionPointers(Module &M) {
22732225
continue;
22742226
if (II->getIntrinsicID() == Intrinsic::spv_assign_ptr_type ||
22752227
II->getIntrinsicID() == Intrinsic::spv_ptrcast) {
2276-
updateAssignType(II, &F, getNormalizedPoisonValue(FPElemTy));
2228+
GR->updateAssignType(II, &F, getNormalizedPoisonValue(FPElemTy));
22772229
break;
22782230
}
22792231
}
@@ -2324,7 +2276,7 @@ void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {
23242276
if (!hasPointeeTypeAttr(Arg)) {
23252277
B.SetInsertPointPastAllocas(Arg->getParent());
23262278
B.SetCurrentDebugLocation(DebugLoc());
2327-
buildAssignPtr(B, ElemTy, Arg);
2279+
GR->buildAssignPtr(B, ElemTy, Arg);
23282280
}
23292281
} else if (isa<Instruction>(Param)) {
23302282
GR->addDeducedElementType(Param, normalizeType(ElemTy));
@@ -2334,7 +2286,7 @@ void SPIRVEmitIntrinsics::applyDemangledPtrArgTypes(IRBuilder<> &B) {
23342286
->getParent()
23352287
->getEntryBlock()
23362288
.getFirstNonPHIOrDbgOrAlloca());
2337-
buildAssignPtr(B, ElemTy, Param);
2289+
GR->buildAssignPtr(B, ElemTy, Param);
23382290
}
23392291
CallInst *Ref = dyn_cast<CallInst>(Param);
23402292
if (!Ref)

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
#include "SPIRVUtils.h"
2323
#include "llvm/ADT/APInt.h"
2424
#include "llvm/IR/Constants.h"
25+
#include "llvm/IR/IntrinsicInst.h"
26+
#include "llvm/IR/Intrinsics.h"
27+
#include "llvm/IR/IntrinsicsSPIRV.h"
2528
#include "llvm/IR/Type.h"
2629
#include "llvm/Support/Casting.h"
2730
#include <cassert>
@@ -1739,3 +1742,35 @@ LLT SPIRVGlobalRegistry::getRegType(SPIRVType *SpvType) const {
17391742
}
17401743
return LLT::scalar(64);
17411744
}
1745+
1746+
void SPIRVGlobalRegistry::buildAssignPtr(IRBuilder<> &B, Type *ElemTy,
1747+
Value *Arg) {
1748+
Value *OfType = PoisonValue::get(ElemTy);
1749+
CallInst *AssignPtrTyCI = findAssignPtrTypeInstr(Arg);
1750+
Function *CurrF =
1751+
B.GetInsertBlock() ? B.GetInsertBlock()->getParent() : nullptr;
1752+
if (AssignPtrTyCI == nullptr ||
1753+
AssignPtrTyCI->getParent()->getParent() != CurrF) {
1754+
AssignPtrTyCI = buildIntrWithMD(
1755+
Intrinsic::spv_assign_ptr_type, {Arg->getType()}, OfType, Arg,
1756+
{B.getInt32(getPointerAddressSpace(Arg->getType()))}, B);
1757+
addDeducedElementType(AssignPtrTyCI, ElemTy);
1758+
addDeducedElementType(Arg, ElemTy);
1759+
addAssignPtrTypeInstr(Arg, AssignPtrTyCI);
1760+
} else {
1761+
updateAssignType(AssignPtrTyCI, Arg, OfType);
1762+
}
1763+
}
1764+
1765+
void SPIRVGlobalRegistry::updateAssignType(CallInst *AssignCI, Value *Arg,
1766+
Value *OfType) {
1767+
AssignCI->setArgOperand(1, buildMD(OfType));
1768+
if (cast<IntrinsicInst>(AssignCI)->getIntrinsicID() !=
1769+
Intrinsic::spv_assign_ptr_type)
1770+
return;
1771+
1772+
// update association with the pointee type
1773+
Type *ElemTy = OfType->getType();
1774+
addDeducedElementType(AssignCI, ElemTy);
1775+
addDeducedElementType(Arg, ElemTy);
1776+
}

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,9 @@ class SPIRVGlobalRegistry {
620620

621621
const TargetRegisterClass *getRegClass(SPIRVType *SpvType) const;
622622
LLT getRegType(SPIRVType *SpvType) const;
623+
624+
void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg);
625+
void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType);
623626
};
624627
} // end namespace llvm
625628
#endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H

0 commit comments

Comments
 (0)