[SPIR-V] Fix push_constant and shader_record_ext to work with LowerTypeVisitor (#6011)

Since `ConstantBuffer` is now lowered in `LowerTypeVisitor`, lower
`push_constant` and `shader_record_*` with `ConstantBuffer` types there
as well.

Fixes #5808.
This commit is contained in:
Cassandra Beckley 2023-11-22 06:19:32 -08:00 коммит произвёл GitHub
Родитель 773fed3060
Коммит 2c913d608d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
12 изменённых файлов: 165 добавлений и 106 удалений

Просмотреть файл

@ -1307,7 +1307,7 @@ SpirvVariable *DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
const bool forShaderRecordNV =
usageKind == ContextUsageKind::ShaderRecordBufferNV;
const bool forShaderRecordEXT =
usageKind == ContextUsageKind::ShaderRecordBufferEXT;
usageKind == ContextUsageKind::ShaderRecordBufferKHR;
const auto &declGroup = collectDeclsInDeclContext(decl);
@ -1357,9 +1357,6 @@ SpirvVariable *DeclResultIdMapper::createStructOrStructArrayVarOfExplicitLayout(
}
}
// Register the <type-id> for this decl
ctBufferPCTypes[decl] = resultType;
const auto sc = forPC ? spv::StorageClass::PushConstant
: forShaderRecordNV ? spv::StorageClass::ShaderRecordBufferNV
: forShaderRecordEXT
@ -1451,19 +1448,31 @@ SpirvVariable *DeclResultIdMapper::createPushConstant(const VarDecl *decl) {
const QualType type = decl->getType();
const auto *recordType = type->getAs<RecordType>();
SpirvVariable *var = nullptr;
if (isConstantBuffer(type)) {
// Get the templated type for ConstantBuffer.
recordType = hlsl::GetHLSLResourceResultType(type)->getAs<RecordType>();
// Constant buffers already have Block decoration. The variable will need
// the PushConstant storage class.
// Create the variable for the whole struct / struct array.
// The fields may be 'precise', but the structure itself is not.
var = spvBuilder.addModuleVar(type, spv::StorageClass::PushConstant,
/*isPrecise*/ false,
/*isNoInterp*/ false, decl->getName());
const SpirvLayoutRule layoutRule = spirvOptions.sBufferLayoutRule;
var->setHlslUserType("");
var->setLayoutRule(layoutRule);
} else {
assert(recordType);
const std::string structName =
"type.PushConstant." + recordType->getDecl()->getName().str();
var = createStructOrStructArrayVarOfExplicitLayout(
recordType->getDecl(), /*arraySize*/ 0, ContextUsageKind::PushConstant,
structName, decl->getName());
}
assert(recordType);
const std::string structName =
"type.PushConstant." + recordType->getDecl()->getName().str();
SpirvVariable *var = createStructOrStructArrayVarOfExplicitLayout(
recordType->getDecl(), /*arraySize*/ 0, ContextUsageKind::PushConstant,
structName, decl->getName());
// Register the VarDecl
astDecls[decl] = createDeclSpirvInfo(var);
@ -1476,22 +1485,44 @@ SpirvVariable *DeclResultIdMapper::createPushConstant(const VarDecl *decl) {
SpirvVariable *
DeclResultIdMapper::createShaderRecordBuffer(const VarDecl *decl,
ContextUsageKind kind) {
const QualType type = decl->getType();
const auto *recordType =
hlsl::GetHLSLResourceResultType(decl->getType())->getAs<RecordType>();
hlsl::GetHLSLResourceResultType(type)->getAs<RecordType>();
assert(recordType);
assert(kind == ContextUsageKind::ShaderRecordBufferEXT ||
assert(kind == ContextUsageKind::ShaderRecordBufferKHR ||
kind == ContextUsageKind::ShaderRecordBufferNV);
const auto typeName = kind == ContextUsageKind::ShaderRecordBufferEXT
? "type.ShaderRecordBufferEXT."
: "type.ShaderRecordBufferNV.";
SpirvVariable *var = nullptr;
if (isConstantBuffer(type)) {
// Constant buffers already have Block decoration. The variable will need
// the appropriate storage class.
const std::string structName =
typeName + recordType->getDecl()->getName().str();
SpirvVariable *var = createStructOrStructArrayVarOfExplicitLayout(
recordType->getDecl(), /*arraySize*/ 0, kind, structName,
decl->getName());
const auto sc = kind == ContextUsageKind::ShaderRecordBufferNV
? spv::StorageClass::ShaderRecordBufferNV
: spv::StorageClass::ShaderRecordBufferKHR;
// Create the variable for the whole struct / struct array.
// The fields may be 'precise', but the structure itself is not.
var = spvBuilder.addModuleVar(type, sc,
/*isPrecise*/ false,
/*isNoInterp*/ false, decl->getName());
const SpirvLayoutRule layoutRule = spirvOptions.sBufferLayoutRule;
var->setHlslUserType("");
var->setLayoutRule(layoutRule);
} else {
const auto typeName = kind == ContextUsageKind::ShaderRecordBufferKHR
? "type.ShaderRecordBufferKHR."
: "type.ShaderRecordBufferNV.";
const std::string structName =
typeName + recordType->getDecl()->getName().str();
var = createStructOrStructArrayVarOfExplicitLayout(
recordType->getDecl(), /*arraySize*/ 0, kind, structName,
decl->getName());
}
// Register the VarDecl
astDecls[decl] = createDeclSpirvInfo(var);
@ -1505,11 +1536,11 @@ DeclResultIdMapper::createShaderRecordBuffer(const VarDecl *decl,
SpirvVariable *
DeclResultIdMapper::createShaderRecordBuffer(const HLSLBufferDecl *decl,
ContextUsageKind kind) {
assert(kind == ContextUsageKind::ShaderRecordBufferEXT ||
assert(kind == ContextUsageKind::ShaderRecordBufferKHR ||
kind == ContextUsageKind::ShaderRecordBufferNV);
const auto typeName = kind == ContextUsageKind::ShaderRecordBufferEXT
? "type.ShaderRecordBufferEXT."
const auto typeName = kind == ContextUsageKind::ShaderRecordBufferKHR
? "type.ShaderRecordBufferKHR."
: "type.ShaderRecordBufferNV.";
const std::string structName = typeName + decl->getName().str();
@ -1769,13 +1800,6 @@ void DeclResultIdMapper::createFieldCounterVars(
}
}
const SpirvType *
DeclResultIdMapper::getCTBufferPushConstantType(const DeclContext *decl) {
const auto found = ctBufferPCTypes.find(decl);
assert(found != ctBufferPCTypes.end());
return found->second;
}
std::vector<SpirvVariable *>
DeclResultIdMapper::collectStageVars(SpirvFunction *entryPoint) const {
std::vector<SpirvVariable *> vars;

Просмотреть файл

@ -352,7 +352,7 @@ public:
PushConstant,
Globals,
ShaderRecordBufferNV,
ShaderRecordBufferEXT
ShaderRecordBufferKHR
};
/// Raytracing specific functions
@ -432,19 +432,6 @@ public:
/// buffers. Returns nullptr if it does not.
const CounterVarFields *getCounterVarFields(const DeclaratorDecl *decl);
/// \brief Returns the <type-id> for the given cbuffer, tbuffer,
/// ConstantBuffer, TextureBuffer, or push constant block.
///
/// Note: we need this method because constant/texture buffers and push
/// constant blocks are all represented as normal struct types upon which
/// they are parameterized. That is different from structured buffers,
/// for which we can tell they are not normal structs by investigating
/// the name. But for constant/texture buffers and push constant blocks,
/// we need to have the additional Block/BufferBlock decoration to keep
/// type consistent. Normal translation path for structs via TypeTranslator
/// won't attach Block/BufferBlock decoration.
const SpirvType *getCTBufferPushConstantType(const DeclContext *decl);
/// \brief Returns all defined stage (builtin/input/ouput) variables for the
/// entry point function entryPoint in this mapper.
std::vector<SpirvVariable *>
@ -825,10 +812,6 @@ private:
/// until a Increment/DecrementCounter method is called on it.
llvm::DenseMap<const DeclaratorDecl *, SpirvInstruction *> declRWSBuffers;
/// Mapping from cbuffer/tbuffer/ConstantBuffer/TextureBufer/push-constant
/// to the SPIR-V type.
llvm::DenseMap<const DeclContext *, const SpirvType *> ctBufferPCTypes;
/// The execution mode to use for rasterizer ordered views. Should be set to
/// PixelInterlockOrderedEXT (default), SampleInterlockOrderedEXT, or
/// ShadingRateInterlockOrderedEXT. This will be set based on which semantics

Просмотреть файл

@ -1677,7 +1677,7 @@ void SpirvEmitter::doHLSLBufferDecl(const HLSLBufferDecl *bufferDecl) {
} else if (bufferDecl->hasAttr<VKShaderRecordEXTAttr>()) {
(void)declIdMapper.createShaderRecordBuffer(
bufferDecl,
DeclResultIdMapper::ContextUsageKind::ShaderRecordBufferEXT);
DeclResultIdMapper::ContextUsageKind::ShaderRecordBufferKHR);
} else {
(void)declIdMapper.createCTBuffer(bufferDecl);
}
@ -1793,7 +1793,7 @@ void SpirvEmitter::doVarDecl(const VarDecl *decl) {
if (decl->hasAttr<VKShaderRecordEXTAttr>()) {
(void)declIdMapper.createShaderRecordBuffer(
decl, DeclResultIdMapper::ContextUsageKind::ShaderRecordBufferEXT);
decl, DeclResultIdMapper::ContextUsageKind::ShaderRecordBufferKHR);
return;
}

Просмотреть файл

@ -25,13 +25,13 @@ struct T {
row_major float3x2 f3[2];
};
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 1 Offset 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 2 Offset 32
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 3 Offset 224
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 4 Offset 256
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 4 MatrixStride 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 4 ColMajor
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 1 Offset 16
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 2 Offset 32
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 3 Offset 224
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 4 Offset 256
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 4 MatrixStride 16
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 4 ColMajor
struct S {
float f1;
@ -44,14 +44,14 @@ struct S {
[[vk::shader_record_ext]]
ConstantBuffer<S> cbuf;
// CHECK: OpDecorate %type_ShaderRecordBufferEXT_S Block
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_block 0 Offset 0
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_block 1 Offset 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_block 2 Offset 32
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_block 3 Offset 224
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_block 4 Offset 256
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_block 4 MatrixStride 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_block 4 ColMajor
// CHECK: OpDecorate %type_ConstantBuffer_S Block
// CHECK: OpMemberDecorate %type_ShaderRecordBufferKHR_block 0 Offset 0
// CHECK: OpMemberDecorate %type_ShaderRecordBufferKHR_block 1 Offset 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferKHR_block 2 Offset 32
// CHECK: OpMemberDecorate %type_ShaderRecordBufferKHR_block 3 Offset 224
// CHECK: OpMemberDecorate %type_ShaderRecordBufferKHR_block 4 Offset 256
// CHECK: OpMemberDecorate %type_ShaderRecordBufferKHR_block 4 MatrixStride 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferKHR_block 4 ColMajor
[[vk::shader_record_ext]]
@ -63,10 +63,13 @@ cbuffer block {
row_major float2x3 f3;
}
// CHECK: OpDecorate %type_ShaderRecordBufferEXT_block Block
// CHECK: OpDecorate %type_ShaderRecordBufferKHR_block Block
struct Payload { float p; };
struct Attr { float a; };
// CHECK: %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S = OpTypePointer ShaderRecordBufferNV %type_ConstantBuffer_S
// CHECK: %cbuf = OpVariable %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S ShaderRecordBufferNV
[shader("closesthit")]
void chs1(inout Payload P, in Attr A) {
P.p = cbuf.f1;

Просмотреть файл

@ -25,13 +25,13 @@ struct T {
row_major float3x2 f3[2];
};
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 1 Offset 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 2 Offset 32
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 3 Offset 224
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 4 Offset 256
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 4 MatrixStride 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 4 ColMajor
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 1 Offset 16
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 2 Offset 32
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 3 Offset 224
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 4 Offset 256
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 4 MatrixStride 16
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 4 ColMajor
struct S {
float f1;
@ -44,7 +44,7 @@ struct S {
[[vk::shader_record_nv]]
ConstantBuffer<S> cbuf;
// CHECK: OpDecorate %type_ShaderRecordBufferNV_S Block
// CHECK: OpDecorate %type_ConstantBuffer_S Block
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_block 0 Offset 0
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_block 1 Offset 16
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_block 2 Offset 32
@ -67,6 +67,9 @@ cbuffer block {
struct Payload { float p; };
struct Attr { float a; };
// CHECK: %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S = OpTypePointer ShaderRecordBufferNV %type_ConstantBuffer_S
// CHECK: %cbuf = OpVariable %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S ShaderRecordBufferNV
[shader("closesthit")]
void chs1(inout Payload P, in Attr A) {
P.p = cbuf.f1;

Просмотреть файл

@ -0,0 +1,21 @@
// RUN: %dxc -T cs_6_0 -E main -fcgl %s -spirv | FileCheck %s
struct Foo
{
float m_x;
};
// CHECK: %g_pc = OpVariable %_ptr_PushConstant_type_ConstantBuffer_Foo PushConstant
[[vk::push_constant]] ConstantBuffer<Foo> g_pc;
RWStructuredBuffer<float> g_buff;
float mul1(Foo m, float4 v)
{
return m.m_x + v.x;
}
[numthreads(1, 1, 1)] void main()
{
// CHECK: OpLoad %type_ConstantBuffer_Foo %g_pc
g_buff[0] = mul1(g_pc, float4(1, 0, 0, 1));
}

Просмотреть файл

@ -6,8 +6,8 @@ struct StructA
float3 two;
};
// CHECK: %type_PushConstant_StructA = OpTypeStruct %v3float %v3float
// CHECK: %PushConstants = OpVariable %_ptr_PushConstant_type_PushConstant_StructA PushConstant
// CHECK: %type_ConstantBuffer_StructA = OpTypeStruct %v3float %v3float
// CHECK: %PushConstants = OpVariable %_ptr_PushConstant_type_ConstantBuffer_StructA PushConstant
[[vk::push_constant]] ConstantBuffer<StructA> PushConstants;
void main()

Просмотреть файл

@ -0,0 +1,25 @@
// RUN: %dxc -T lib_6_7 -fspv-target-env=vulkan1.1spirv1.4 -E main -fcgl %s -spirv | FileCheck %s
// CHECK: OpCapability RayTracingKHR
// CHECK: OpExtension "SPV_KHR_ray_query"
// CHECK: OpExtension "SPV_KHR_ray_tracing"
struct Foo
{
float m_x;
};
// CHECK: %g_pc = OpVariable %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_Foo ShaderRecordBufferNV
[[vk::shader_record_ext]] ConstantBuffer<Foo> g_pc;
RWStructuredBuffer<float> g_buff;
float mul1(Foo m, float4 v)
{
return m.m_x + v.x;
}
[shader("raygeneration")] void main()
{
// CHECK: OpLoad %type_ConstantBuffer_Foo %g_pc
g_buff[0] = mul1(g_pc, float4(1, 0, 0, 1));
}

Просмотреть файл

@ -4,24 +4,24 @@ struct T {
float2 val[3];
};
// CHECK: OpName %type_ShaderRecordBufferEXT_S "type.ShaderRecordBufferEXT.S"
// CHECK: OpMemberName %type_ShaderRecordBufferEXT_S 0 "f1"
// CHECK: OpMemberName %type_ShaderRecordBufferEXT_S 1 "f2"
// CHECK: OpMemberName %type_ShaderRecordBufferEXT_S 2 "f3"
// CHECK: OpMemberName %type_ShaderRecordBufferEXT_S 3 "f4"
// CHECK: OpName %type_ConstantBuffer_S "type.ConstantBuffer.S"
// CHECK: OpMemberName %type_ConstantBuffer_S 0 "f1"
// CHECK: OpMemberName %type_ConstantBuffer_S 1 "f2"
// CHECK: OpMemberName %type_ConstantBuffer_S 2 "f3"
// CHECK: OpMemberName %type_ConstantBuffer_S 3 "f4"
// CHECK-NOT: OpDecorate %srb DescriptorSet
// CHECK-NOT: OpDecorate %srb Binding
// CHECK: %type_ShaderRecordBufferEXT_S = OpTypeStruct %float %v3float %mat2v3float %T
// CHECK: %type_ConstantBuffer_S = OpTypeStruct %float %v3float %mat2v3float %T
struct S {
float f1;
float3 f2;
float2x3 f3;
T f4;
};
// CHECK: %_ptr_ShaderRecordBufferNV_type_ShaderRecordBufferEXT_S = OpTypePointer ShaderRecordBufferNV %type_ShaderRecordBufferEXT_S
// CHECK: %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S = OpTypePointer ShaderRecordBufferNV %type_ConstantBuffer_S
// CHECK: %srb = OpVariable %_ptr_ShaderRecordBufferNV_type_ShaderRecordBufferEXT_S ShaderRecordBufferNV
// CHECK: %srb = OpVariable %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S ShaderRecordBufferNV
[[vk::shader_record_ext]]
ConstantBuffer<S> srb;
@ -29,9 +29,9 @@ struct Payload { float p; };
struct Attribute { float a; };
[shader("miss")]
void main(inout Payload P)
void main(inout Payload P)
{
P.p =
P.p =
// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_ShaderRecordBufferNV_float %srb %int_0
srb.f1 +
// CHECK: [[ptr:%[0-9]+]] = OpAccessChain %_ptr_ShaderRecordBufferNV_v3float %srb %int_1

Просмотреть файл

@ -1,8 +1,8 @@
// RUN: %dxc -T lib_6_3 -fspv-target-env=vulkan1.2 -fcgl %s -spirv | FileCheck %s
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 1 Offset 8
// CHECK: OpMemberDecorate %type_ShaderRecordBufferEXT_S 2 Offset 32
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 1 Offset 8
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 2 Offset 32
struct S {
float a;

Просмотреть файл

@ -4,24 +4,24 @@ struct T {
float2 val[3];
};
// CHECK: OpName %type_ShaderRecordBufferNV_S "type.ShaderRecordBufferNV.S"
// CHECK: OpMemberName %type_ShaderRecordBufferNV_S 0 "f1"
// CHECK: OpMemberName %type_ShaderRecordBufferNV_S 1 "f2"
// CHECK: OpMemberName %type_ShaderRecordBufferNV_S 2 "f3"
// CHECK: OpMemberName %type_ShaderRecordBufferNV_S 3 "f4"
// CHECK: OpName %type_ConstantBuffer_S "type.ConstantBuffer.S"
// CHECK: OpMemberName %type_ConstantBuffer_S 0 "f1"
// CHECK: OpMemberName %type_ConstantBuffer_S 1 "f2"
// CHECK: OpMemberName %type_ConstantBuffer_S 2 "f3"
// CHECK: OpMemberName %type_ConstantBuffer_S 3 "f4"
// CHECK-NOT: OpDecorate %srb DescriptorSet
// CHECK-NOT: OpDecorate %srb Binding
// CHECK: %type_ShaderRecordBufferNV_S = OpTypeStruct %float %v3float %mat2v3float %T
// CHECK: %type_ConstantBuffer_S = OpTypeStruct %float %v3float %mat2v3float %T
struct S {
float f1;
float3 f2;
float2x3 f3;
T f4;
};
// CHECK: %_ptr_ShaderRecordBufferNV_type_ShaderRecordBufferNV_S = OpTypePointer ShaderRecordBufferNV %type_ShaderRecordBufferNV_S
// CHECK: %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S = OpTypePointer ShaderRecordBufferNV %type_ConstantBuffer_S
// CHECK: %srb = OpVariable %_ptr_ShaderRecordBufferNV_type_ShaderRecordBufferNV_S ShaderRecordBufferNV
// CHECK: %srb = OpVariable %_ptr_ShaderRecordBufferNV_type_ConstantBuffer_S ShaderRecordBufferNV
[[vk::shader_record_nv]]
ConstantBuffer<S> srb;
@ -29,9 +29,9 @@ struct Payload { float p; };
struct Attribute { float a; };
[shader("miss")]
void main(inout Payload P)
void main(inout Payload P)
{
P.p =
P.p =
// CHECK: {{%[0-9]+}} = OpAccessChain %_ptr_ShaderRecordBufferNV_float %srb %int_0
srb.f1 +
// CHECK: [[ptr:%[0-9]+]] = OpAccessChain %_ptr_ShaderRecordBufferNV_v3float %srb %int_1

Просмотреть файл

@ -1,8 +1,8 @@
// RUN: %dxc -T lib_6_3 -fspv-extension=SPV_NV_ray_tracing -fcgl %s -spirv | FileCheck %s
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 1 Offset 8
// CHECK: OpMemberDecorate %type_ShaderRecordBufferNV_S 2 Offset 32
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 0 Offset 0
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 1 Offset 8
// CHECK: OpMemberDecorate %type_ConstantBuffer_S 2 Offset 32
struct S {
float a;