Skip to content

Commit f0d7e47

Browse files
authored
Adjust OpVariable's users and Lifetime ptr operand storage classes (#2650)
While clang is generating alloca in private address space for OpenCL following target's datalayout, some of the passes might generate it in different generic AS and for this cases we have to create OpVariable in function storage class and create a cast to generic. Additionally if such alloca was an operand of lifetime instruction - then SPIR-V without storage class adjustment validation for lifetime instruction will be violated (pointer operand must be with Function storage class). This became exposed after llvm/llvm-project#97306 which was fixing handling of byval pointer parameter of a function during inlining, byval pointer for OpenCL will be generated in default (under an option - generic) address space making the alloca to store value of the function's operand also be generic. Signed-off-by: Sidorov, Dmitry <[email protected]>
1 parent c5c3d71 commit f0d7e47

File tree

3 files changed

+96
-19
lines changed

3 files changed

+96
-19
lines changed

lib/SPIRV/SPIRVWriter.cpp

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,10 +2269,20 @@ LLVMToSPIRVBase::transValueWithoutDecoration(Value *V, SPIRVBasicBlock *BB,
22692269
BM->addInstTemplate(OpVariableLengthArrayINTEL,
22702270
{Length->getId()}, BB, TranslatedTy));
22712271
}
2272-
return mapValue(V, BM->addVariable(TranslatedTy, false,
2273-
spv::internal::LinkageTypeInternal,
2274-
nullptr, Alc->getName().str(),
2275-
StorageClassFunction, BB));
2272+
SPIRVType *VarTy =
2273+
V->getType()->getPointerAddressSpace() == SPIRAS_Generic
2274+
? BM->addPointerType(StorageClassFunction,
2275+
TranslatedTy->getPointerElementType())
2276+
: TranslatedTy;
2277+
SPIRVValue *Var = BM->addVariable(
2278+
VarTy, false, spv::internal::LinkageTypeInternal, nullptr,
2279+
Alc->getName().str(), StorageClassFunction, BB);
2280+
if (V->getType()->getPointerAddressSpace() == SPIRAS_Generic) {
2281+
SPIRVValue *Cast =
2282+
BM->addUnaryInst(OpPtrCastToGeneric, TranslatedTy, Var, BB);
2283+
return mapValue(V, Cast);
2284+
}
2285+
return mapValue(V, Var);
22762286
}
22772287

22782288
if (auto *Switch = dyn_cast<SwitchInst>(V)) {
@@ -4538,7 +4548,21 @@ SPIRVValue *LLVMToSPIRVBase::transIntrinsicInst(IntrinsicInst *II,
45384548
int64_t Size = dyn_cast<ConstantInt>(II->getOperand(0))->getSExtValue();
45394549
if (Size == -1)
45404550
Size = 0;
4541-
return BM->addLifetimeInst(OC, transValue(II->getOperand(1), BB), Size, BB);
4551+
Value *LLVMPtrOp = II->getOperand(1);
4552+
unsigned PtrAS = cast<PointerType>(LLVMPtrOp->getType())->getAddressSpace();
4553+
auto *PtrOp = transValue(LLVMPtrOp, BB);
4554+
if (PtrAS == SPIRAS_Private)
4555+
return BM->addLifetimeInst(OC, PtrOp, Size, BB);
4556+
// If pointer address space is Generic - cast to private first
4557+
BM->getErrorLog().checkError(
4558+
PtrAS == SPIRAS_Generic, SPIRVEC_InvalidInstruction, II,
4559+
"lifetime intrinsic pointer operand must be in private or generic AS");
4560+
auto *SrcTy = PtrOp->getType();
4561+
auto *DstTy = BM->addPointerType(StorageClassFunction,
4562+
SrcTy->getPointerElementType());
4563+
PtrOp = BM->addUnaryInst(OpGenericCastToPtr, DstTy, PtrOp, BB);
4564+
ValueMap[LLVMPtrOp] = PtrOp;
4565+
return BM->addLifetimeInst(OC, PtrOp, Size, BB);
45424566
}
45434567
// We don't want to mix translation of regular code and debug info, because
45444568
// it creates a mess, therefore translation of debug intrinsics is

lib/SPIRV/libSPIRV/SPIRVModule.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,8 @@ class SPIRVModuleImpl : public SPIRVModule {
565565
SPIRVTypeVoid *VoidTy;
566566
SmallDenseMap<unsigned, SPIRVTypeInt *, 4> IntTypeMap;
567567
SmallDenseMap<unsigned, SPIRVTypeFloat *, 4> FloatTypeMap;
568+
SmallDenseMap<std::pair<unsigned, SPIRVType *>, SPIRVTypePointer *, 4>
569+
PointerTypeMap;
568570
std::unordered_map<unsigned, SPIRVConstant *> LiteralMap;
569571
std::vector<SPIRVExtInst *> DebugInstVec;
570572
std::vector<SPIRVExtInst *> AuxDataInstVec;
@@ -1003,8 +1005,13 @@ SPIRVTypeFloat *SPIRVModuleImpl::addFloatType(unsigned BitWidth) {
10031005
SPIRVTypePointer *
10041006
SPIRVModuleImpl::addPointerType(SPIRVStorageClassKind StorageClass,
10051007
SPIRVType *ElementType) {
1006-
return addType(
1007-
new SPIRVTypePointer(this, getId(), StorageClass, ElementType));
1008+
auto Desc = std::make_pair(StorageClass, ElementType);
1009+
auto Loc = PointerTypeMap.find(Desc);
1010+
if (Loc != PointerTypeMap.end())
1011+
return Loc->second;
1012+
auto *Ty = new SPIRVTypePointer(this, getId(), StorageClass, ElementType);
1013+
PointerTypeMap[Desc] = Ty;
1014+
return addType(Ty);
10081015
}
10091016

10101017
SPIRVTypeFunction *SPIRVModuleImpl::addFunctionType(

test/llvm-intrinsics/lifetime.ll

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,47 @@
66
; RUN: llvm-spirv -r %t.spv -o %t.spv.bc
77
; RUN: llvm-dis < %t.spv.bc | FileCheck %s --check-prefix=CHECK-LLVM
88

9-
; CHECK-SPIRV: 3 LifetimeStart [[tmp:[0-9]+]] 0
10-
; CHECK-SPIRV: 3 LifetimeStop [[tmp]] 0
9+
; CHECK-SPIRV-DAG: Name [[#SimpleF:]] "lifetime_simple"
10+
; CHECK-SPIRV-DAG: Name [[#SizedF:]] "lifetime_sized"
11+
; CHECK-SPIRV-DAG: Name [[#GenericF:]] "lifetime_generic"
12+
; CHECK-SPIRV-DAG: TypeStruct [[#StructTy:]] [[#]]
13+
; CHECK-SPIRV-COUNT-1: TypePointer [[#PrivatePtrTy:]] [[#StructTy]]
1114

15+
; CHECK-SPIRV: Function [[#]] [[#SimpleF:]]
16+
; CHECK-SPIRV: LifetimeStart [[#Tmp:]] 0
17+
; CHECK-SPIRV: LifetimeStop [[#Tmp]] 0
18+
19+
; CHECK-SPIRV: Function [[#]] [[#SizedF:]]
20+
; CHECK-SPIRV: LifetimeStart [[#Tmp:]] 1
21+
; CHECK-SPIRV: Bitcast [[#]] [[#Cast:]]
22+
; CHECK-SPIRV: LifetimeStop [[#Cast]] 1
23+
24+
; CHECK-SPIRV: Function [[#]] [[#GenericF:]]
25+
; CHECK-SPIRV: Variable [[#PrivatePtrTy]] [[#Var:]] 7
26+
; CHECK-SPIRV: PtrCastToGeneric [[#]] [[#Cast1:]] [[#Var]]
27+
; CHECK-SPIRV: Bitcast [[#]] [[#Cast2:]] [[#Cast1]]
28+
; CHECK-SPIRV: GenericCastToPtr [[#]] [[#Cast3:]] [[#Cast2]]
29+
; CHECK-SPIRV: LifetimeStart [[#Cast3]] 1
30+
; CHECK-SPIRV: GenericCastToPtr [[#]] [[#Cast4:]]
31+
; CHECK-SPIRV: LifetimeStop [[#Cast4]] 1
32+
33+
; CHECK-LLVM-LABEL: lifetime_simple
1234
; CHECK-LLVM: %[[tmp1:[0-9]+]] = bitcast ptr %{{[0-9]+}} to ptr
1335
; CHECK-LLVM: call void @llvm.lifetime.start.p0(i64 -1, ptr %[[tmp1]])
1436
; CHECK-LLVM: call void @llvm.lifetime.end.p0(i64 -1, ptr %[[tmp1]])
15-
; CHECK-LLVM: declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
16-
; CHECK-LLVM: declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
37+
38+
; CHECK-LLVM-LABEL: lifetime_sized
39+
; CHECK-LLVM: call void @llvm.lifetime.start.p0(i64 1, ptr %[[#]])
40+
; CHECK-LLVM: call void @llvm.lifetime.end.p0(i64 1, ptr %[[#]])
41+
42+
; CHECK-LLVM-LABEL: lifetime_generic
43+
; CHECK-LLVM: %[[#Alloca:]] = alloca %class.anon
44+
; CHECK-LLVM: %[[#Cast1:]] = addrspacecast ptr %[[#Alloca]] to ptr addrspace(4)
45+
; CHECK-LLVM: %[[#Cast2:]] = bitcast ptr addrspace(4) %[[#Cast1]] to ptr addrspace(4)
46+
; CHECK-LLVM: %[[#Cast3:]] = addrspacecast ptr addrspace(4) %[[#Cast2:]] to ptr
47+
; CHECK-LLVM: call void @llvm.lifetime.start.p0(i64 1, ptr %[[#Cast3]])
48+
; CHECK-LLVM: %[[#Cast4:]] = addrspacecast ptr addrspace(4) %[[#]] to ptr
49+
; CHECK-LLVM: call void @llvm.lifetime.end.p0(i64 1, ptr %[[#Cast4]])
1750

1851
; ModuleID = 'main'
1952
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
@@ -53,14 +86,7 @@ entry:
5386
ret void
5487
}
5588

56-
; Function Attrs: inlinehint nounwind
57-
define internal spir_func void @foo(%class.anon* %this) #0 align 2 {
58-
entry:
59-
%this.addr = alloca %class.anon*, align 8
60-
store %class.anon* %this, %class.anon** %this.addr, align 8
61-
%this1 = load %class.anon*, %class.anon** %this.addr, align 8
62-
ret void
63-
}
89+
declare spir_func void @foo(%class.anon* %this) #0
6490

6591
; Function Attrs: nounwind
6692
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #0
@@ -71,6 +97,26 @@ declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #0
7197
; Function Attrs: nounwind readnone
7298
declare spir_func i64 @_Z13get_global_idj(i32) #1
7399

100+
define spir_kernel void @lifetime_generic() #0 !kernel_arg_addr_space !8 !kernel_arg_access_qual !8 !kernel_arg_type !8 !kernel_arg_base_type !8 !kernel_arg_type_qual !8 {
101+
entry:
102+
%0 = alloca %class.anon, align 1, addrspace(4)
103+
%1 = bitcast %class.anon addrspace(4)* %0 to i8 addrspace(4)*
104+
call void @llvm.lifetime.start.p4i8(i64 1, i8 addrspace(4)* %1) #0
105+
call spir_func void @boo(%class.anon addrspace(4)* %0)
106+
%2 = bitcast %class.anon addrspace(4)* %0 to i8 addrspace(4)*
107+
call void @llvm.lifetime.end.p4i8(i64 1, i8 addrspace(4)* %2) #0
108+
ret void
109+
}
110+
111+
declare spir_func void @boo(%class.anon addrspace(4)* %this) #0
112+
113+
; Function Attrs: nounwind
114+
declare void @llvm.lifetime.start.p4i8(i64 immarg, i8 addrspace(4)* nocapture) #0
115+
116+
; Function Attrs: nounwind
117+
declare void @llvm.lifetime.end.p4i8(i64 immarg, i8 addrspace(4)* nocapture) #0
118+
119+
74120
attributes #0 = { nounwind }
75121
attributes #1 = { nounwind readnone }
76122

0 commit comments

Comments
 (0)