Skip to content

Commit 74a3c3b

Browse files
committed
Add writable test.
1 parent 1805f85 commit 74a3c3b

File tree

6 files changed

+127
-40
lines changed

6 files changed

+127
-40
lines changed

llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3050,23 +3050,11 @@ static SPIRVType *getVulkanBufferType(const TargetExtType *ExtensionType,
30503050
"Vulkan buffer have 2 integer parameters: storage class and is "
30513051
"writable.");
30523052

3053-
auto *T = StructType::create(ExtensionType->getTypeParameter(0));
3054-
auto *BlockType = GR->getOrCreateSPIRVType(
3055-
T, MIRBuilder, SPIRV::AccessQualifier::None, false);
3056-
buildOpDecorate(BlockType->defs().begin()->getReg(), MIRBuilder,
3057-
SPIRV::Decoration::Block, {});
3058-
buildOpMemberDecorate(BlockType->defs().begin()->getReg(), MIRBuilder,
3059-
SPIRV::Decoration::Offset, 0, {0});
3060-
3061-
bool IsWritable = ExtensionType->getIntParameter(1);
3062-
if (!IsWritable) {
3063-
buildOpMemberDecorate(BlockType->defs().begin()->getReg(), MIRBuilder,
3064-
SPIRV::Decoration::NonWritable, 0, {});
3065-
}
3066-
3053+
auto *T = ExtensionType->getTypeParameter(0);
30673054
auto SC = static_cast<SPIRV::StorageClass::StorageClass>(
30683055
ExtensionType->getIntParameter(0));
3069-
return GR->getOrCreateSPIRVPointerType(BlockType, MIRBuilder, SC);
3056+
bool IsWritable = ExtensionType->getIntParameter(1);
3057+
return GR->getOrCreateVulkanBufferType(MIRBuilder, T, SC, IsWritable);
30703058
}
30713059

30723060
namespace SPIRV {

llvm/lib/Target/SPIRV/SPIRVDuplicatesTracker.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ enum SpecialTypeKind {
6464
STK_Pipe,
6565
STK_DeviceEvent,
6666
STK_Pointer,
67+
STK_Buffer,
6768
STK_Last = -1
6869
};
6970

@@ -137,6 +138,29 @@ inline SpecialTypeDescriptor make_descr_pointee(const Type *ElementType,
137138
return std::make_tuple(ElementType, AddressSpace,
138139
SpecialTypeKind::STK_Pointer);
139140
}
141+
142+
union BufferAttrs {
143+
struct BitFlags {
144+
unsigned IsStorageBuffer : 1;
145+
unsigned IsWriteable : 1;
146+
} Flags;
147+
unsigned Val;
148+
149+
BufferAttrs(bool IsStorageBuffer, bool IsWriteable) {
150+
Val = 0;
151+
Flags.IsStorageBuffer = IsStorageBuffer;
152+
Flags.IsWriteable = IsWriteable;
153+
}
154+
};
155+
156+
inline SpecialTypeDescriptor make_descr_buffer(const Type *ElementType,
157+
bool IsStorageBuffer,
158+
bool IsWriteable) {
159+
return std::make_tuple(ElementType,
160+
BufferAttrs(IsStorageBuffer, IsWriteable).Val,
161+
SpecialTypeKind::STK_Buffer);
162+
}
163+
140164
} // namespace SPIRV
141165

142166
template <typename KeyTy> class SPIRVDuplicatesTrackerBase {

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,6 +1377,35 @@ SPIRVGlobalRegistry::getPointerStorageClass(const SPIRVType *Type) const {
13771377
Type->getOperand(1).getImm());
13781378
}
13791379

1380+
SPIRVType *SPIRVGlobalRegistry::getOrCreateVulkanBufferType(
1381+
MachineIRBuilder &MIRBuilder, Type *ElemType,
1382+
SPIRV::StorageClass::StorageClass SC, bool IsWritable, bool EmitIr) {
1383+
auto TD = SPIRV::make_descr_buffer(
1384+
ElemType, SC == SPIRV::StorageClass::StorageBuffer, IsWritable);
1385+
if (auto *Res = checkSpecialInstr(TD, MIRBuilder))
1386+
return Res;
1387+
1388+
// TODO: Check that I will not collide with a similar struct that does not
1389+
// have the decorations.
1390+
auto *T = StructType::create(ElemType);
1391+
auto *BlockType =
1392+
getOrCreateSPIRVType(T, MIRBuilder, SPIRV::AccessQualifier::None, EmitIr);
1393+
1394+
buildOpDecorate(BlockType->defs().begin()->getReg(), MIRBuilder,
1395+
SPIRV::Decoration::Block, {});
1396+
buildOpMemberDecorate(BlockType->defs().begin()->getReg(), MIRBuilder,
1397+
SPIRV::Decoration::Offset, 0, {0});
1398+
1399+
if (!IsWritable) {
1400+
buildOpMemberDecorate(BlockType->defs().begin()->getReg(), MIRBuilder,
1401+
SPIRV::Decoration::NonWritable, 0, {});
1402+
}
1403+
1404+
SPIRVType *R = getOrCreateSPIRVPointerType(BlockType, MIRBuilder, SC);
1405+
DT.add(TD, &MIRBuilder.getMF(), getSPIRVTypeID(R));
1406+
return R;
1407+
}
1408+
13801409
SPIRVType *SPIRVGlobalRegistry::getOrCreateOpTypeImage(
13811410
MachineIRBuilder &MIRBuilder, SPIRVType *SampledType, SPIRV::Dim::Dim Dim,
13821411
uint32_t Depth, uint32_t Arrayed, uint32_t Multisampled, uint32_t Sampled,

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,11 @@ class SPIRVGlobalRegistry {
592592
SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII,
593593
SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function);
594594

595+
SPIRVType *getOrCreateVulkanBufferType(MachineIRBuilder &MIRBuilder,
596+
Type *ElemType,
597+
SPIRV::StorageClass::StorageClass SC,
598+
bool IsWritable, bool EmitIr = false);
599+
595600
SPIRVType *
596601
getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType,
597602
SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed,

llvm/lib/Target/SPIRV/SPIRVModuleAnalysis.cpp

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,20 +217,48 @@ void SPIRVModuleAnalysis::setBaseInfo(const Module &M) {
217217
}
218218
}
219219

220+
static InstrSignature instrToSignature(const MachineInstr &MI,
221+
SPIRV::ModuleAnalysisInfo &MAI,
222+
bool UseDefReg);
223+
224+
// Appends the signature of the decoration instructions that decorate R to
225+
// Signature.
226+
static void AppendDecorationsForReg(const MachineRegisterInfo &MRI, Register R,
227+
InstrSignature &Signature) {
228+
for (MachineInstr &UseMI : MRI.use_instructions(R)) {
229+
// We don't handle OpDecorateId because getting the register alias for the
230+
// ID can cause problems, and we do not need it for now.
231+
if (UseMI.getOpcode() != SPIRV::OpDecorate &&
232+
UseMI.getOpcode() != SPIRV::OpMemberDecorate)
233+
continue;
234+
235+
for (unsigned i = 0; i < UseMI.getNumOperands(); ++i) {
236+
const MachineOperand &MO = UseMI.getOperand(i);
237+
if (MO.isReg())
238+
continue;
239+
Signature.push_back(hash_value(MO));
240+
}
241+
}
242+
}
243+
220244
// Returns a representation of an instruction as a vector of MachineOperand
221245
// hash values, see llvm::hash_value(const MachineOperand &MO) for details.
222246
// This creates a signature of the instruction with the same content
223247
// that MachineOperand::isIdenticalTo uses for comparison.
224248
static InstrSignature instrToSignature(const MachineInstr &MI,
225249
SPIRV::ModuleAnalysisInfo &MAI,
226250
bool UseDefReg) {
251+
Register DefReg;
227252
InstrSignature Signature{MI.getOpcode()};
228253
for (unsigned i = 0; i < MI.getNumOperands(); ++i) {
229254
const MachineOperand &MO = MI.getOperand(i);
230255
size_t h;
231256
if (MO.isReg()) {
232-
if (!UseDefReg && MO.isDef())
257+
if (!UseDefReg && MO.isDef()) {
258+
assert(!DefReg.isValid() && "Multiple def registers.");
259+
DefReg = MO.getReg();
233260
continue;
261+
}
234262
Register RegAlias = MAI.getRegisterAlias(MI.getMF(), MO.getReg());
235263
if (!RegAlias.isValid()) {
236264
LLVM_DEBUG({
@@ -250,6 +278,13 @@ static InstrSignature instrToSignature(const MachineInstr &MI,
250278
}
251279
Signature.push_back(h);
252280
}
281+
282+
if (DefReg.isValid()) {
283+
// Decorations change the semantics of the current instruction. So two
284+
// identical instruction with different decorations cannot be merged. That
285+
// is why we add the decorations to the signature.
286+
AppendDecorationsForReg(MI.getMF()->getRegInfo(), DefReg, Signature);
287+
}
253288
return Signature;
254289
}
255290

llvm/test/CodeGen/SPIRV/hlsl-resources/StructuredBuffer.ll

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,50 +7,56 @@ target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:
77
declare target("spirv.VulkanBuffer", [0 x i32], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_0t(i32, i32, i32, i32, i1) #0
88

99
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
10-
declare target("spirv.Image", i32, 5, 2, 0, 0, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.Image_i32_5_2_0_0_2_0t(i32, i32, i32, i32, i1) #0
11-
12-
; CHECK-DAG: OpDecorate [[BufferVar:%.+]] DescriptorSet 0
13-
; CHECK-DAG: OpDecorate [[BufferVar]] Binding 0
14-
; CHECK-DAG: OpDecorate [[BufferType:%.+]] Block
15-
; STVEN-CHECK-DAG: OpMemberDecorate [[BufferType]] 0 Offset 0 // The decoration is not output correctly in the assembly output
16-
; CHECK-DAG: OpMemberDecorate [[BufferType]] 0 NonWritable
17-
; CHECK-DAG: OpDecorate [[ImageVar:%.+]] DescriptorSet 0
18-
; CHECK-DAG: OpDecorate [[ImageVar]] Binding 1
19-
20-
21-
; CHECK-DAG: [[ArrayType:%.+]] = OpTypeRuntimeArray
22-
; CHECK-DAG: [[BufferType]] = OpTypeStruct [[ArrayType]]
23-
; CHECK-DAG: [[BufferPtrType:%.+]] = OpTypePointer StorageBuffer [[BufferType]]
24-
; CHECK-DAG: [[int:%[0-9]+]] = OpTypeInt 32 0
10+
declare target("spirv.VulkanBuffer", [0 x i32], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32, i32, i32, i32, i1) #0
11+
12+
; CHECK: OpDecorate [[BufferVar:%.+]] DescriptorSet 0
13+
; CHECK: OpDecorate [[BufferVar]] Binding 0
14+
; CHECK: OpDecorate [[BufferType:%.+]] Block
15+
; CHECK: OpMemberDecorate [[BufferType]] 0 NonWritable
16+
; CHECK-DISABLE: OpMemberDecorate [[RWBufferType]] 0 Offset 0 // The 0 at the end is not output for some reason
17+
; CHECK: OpDecorate [[RWBufferVar:%.+]] DescriptorSet 0
18+
; CHECK: OpDecorate [[RWBufferVar]] Binding 1
19+
; CHECK: OpDecorate [[RWBufferType:%.+]] Block
20+
; CHECK-DISABLE: OpMemberDecorate [[BufferType]] 0 Offset 0 // Same as above
21+
22+
23+
; CHECK: [[int:%[0-9]+]] = OpTypeInt 32 0
24+
; CHECK: [[ArrayType:%.+]] = OpTypeRuntimeArray
25+
; CHECK: [[RWBufferType]] = OpTypeStruct [[ArrayType]]
26+
; CHECK: [[RWBufferPtrType:%.+]] = OpTypePointer StorageBuffer [[RWBufferType]]
27+
; CHECK: [[BufferType]] = OpTypeStruct [[ArrayType]]
28+
; CHECK: [[BufferPtrType:%.+]] = OpTypePointer StorageBuffer [[BufferType]]
2529
; CHECK-DAG: [[zero:%[0-9]+]] = OpConstant [[int]] 0
2630
; CHECK-DAG: [[one:%[0-9]+]] = OpConstant [[int]] 1
2731
; CHECK-DAG: [[BufferVar]] = OpVariable [[BufferPtrType]] StorageBuffer
28-
; CHECK-DAG: [[ImageVar]] = OpVariable {{.*}} UniformConstant
32+
; CHECK-DAG: [[RWBufferVar]] = OpVariable [[RWBufferPtrType]] StorageBuffer
2933

3034
; Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none)
3135
define void @main() local_unnamed_addr #1 {
3236
entry:
33-
; CHECK: [[BufferHandle:%.+]] = OpCopyObject [[BufferPtrType]] [[BufferVar]]
34-
%i_h.i.i = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_0t(i32 0, i32 0, i32 1, i32 0, i1 false)
3537

36-
%o_h.i.i = tail call target("spirv.Image", i32, 5, 2, 0, 0, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.Image_i32_5_2_0_0_2_0t(i32 0, i32 1, i32 1, i32 0, i1 false)
38+
; CHECK-DAG: [[BufferHandle:%.+]] = OpCopyObject [[BufferPtrType]] [[BufferVar]]
39+
; CHECK-DAG: [[RWBufferHandle:%.+]] = OpCopyObject [[RWBufferPtrType]] [[RWBufferVar]]
40+
%_ZL1i_h.i.i = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 0) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_0t(i32 0, i32 0, i32 1, i32 0, i1 false)
41+
42+
%_ZL1o_h.i.i = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 0, i32 1, i32 1, i32 0, i1 false)
3743

3844
; CHECK: [[AC:%.+]] = OpAccessChain {{.*}} [[BufferHandle]] [[zero]] [[one]]
39-
%0 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_0t(target("spirv.VulkanBuffer", [0 x i32], 12, 0) %i_h.i.i, i32 1)
45+
%0 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_0t(target("spirv.VulkanBuffer", [0 x i32], 12, 0) %_ZL1i_h.i.i, i32 1)
4046

4147
; CHECK: [[LD:%.+]] = OpLoad [[int]] [[AC]] Aligned 4
4248
%1 = load i32, ptr addrspace(11) %0, align 4, !tbaa !3
4349

44-
; CHECK: [[ImageHandle:%.+]] = OpLoad {{.*}} [[ImageVar]]
45-
%2 = tail call noundef align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_i32_5_2_0_0_2_0t(target("spirv.Image", i32, 5, 2, 0, 0, 2, 0) %o_h.i.i, i32 0)
50+
; CHECK: [[AC:%.+]] = OpAccessChain {{.*}} [[RWBufferHandle]] [[zero]] [[zero]]
51+
%2 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer", [0 x i32], 12, 1) %_ZL1o_h.i.i, i32 0)
4652

47-
; CHECK: OpImageWrite [[ImageHandle]] [[zero]] [[LD]]
53+
; CHECK: OpStore [[AC]] [[LD]]
4854
store i32 %1, ptr addrspace(11) %2, align 4, !tbaa !3
4955
ret void
5056
}
5157

5258
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
53-
declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.Image_i32_5_2_0_0_2_0t(target("spirv.Image", i32, 5, 2, 0, 0, 2, 0), i32) #0
59+
declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer", [0 x i32], 12, 1), i32) #0
5460

5561
; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(none)
5662
declare ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_0t(target("spirv.VulkanBuffer", [0 x i32], 12, 0), i32) #0

0 commit comments

Comments
 (0)