summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--slang.h3
-rw-r--r--source/slang/bytecode.cpp2
-rw-r--r--source/slang/compiler.h4
-rw-r--r--source/slang/core.meta.slang2
-rw-r--r--source/slang/core.meta.slang.h2
-rw-r--r--source/slang/emit.cpp130
-rw-r--r--source/slang/glsl.meta.slang4
-rw-r--r--source/slang/glsl.meta.slang.h4
-rw-r--r--source/slang/ir-legalize-types.cpp1356
-rw-r--r--source/slang/ir.cpp27
-rw-r--r--source/slang/ir.h7
-rw-r--r--source/slang/lower.cpp6
-rw-r--r--source/slang/modifier-defs.h6
-rw-r--r--source/slang/parameter-binding.cpp56
-rw-r--r--source/slang/parser.cpp24
-rw-r--r--source/slang/profile-defs.h7
-rw-r--r--source/slang/reflection.cpp12
-rw-r--r--source/slang/slang.vcxproj1
-rw-r--r--source/slang/slang.vcxproj.filters1
-rw-r--r--source/slang/syntax.cpp16
-rw-r--r--source/slang/type-defs.h19
-rw-r--r--source/slang/type-layout.cpp180
-rw-r--r--source/slang/type-layout.h42
-rw-r--r--tests/bindings/multiple-parameter-blocks.slang48
-rw-r--r--tests/bindings/parameter-blocks.slang39
-rw-r--r--tests/bugs/gh-171.slang6
-rw-r--r--tests/bugs/gh-172.slang10
-rw-r--r--tests/rewriter/resources-in-structs.glsl8
-rw-r--r--tests/rewriter/type-splitting.hlsl6
29 files changed, 1828 insertions, 200 deletions
diff --git a/slang.h b/slang.h
index 5c84ce6f3..6ccf04d83 100644
--- a/slang.h
+++ b/slang.h
@@ -564,6 +564,7 @@ extern "C"
SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT,
SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT,
SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER,
+ SLANG_PAREMTER_CATEGORY_PARAMETER_BLOCK,
//
SLANG_PARAMETER_CATEGORY_COUNT,
@@ -817,6 +818,7 @@ namespace slang
DescriptorTableSlot = SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT,
SpecializationConstant = SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT,
PushConstantBuffer = SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER,
+ ParameterBlock = SLANG_PAREMTER_CATEGORY_PARAMETER_BLOCK,
};
struct TypeLayoutReflection
@@ -1084,6 +1086,7 @@ namespace slang
#include "source/slang/dxc-support.cpp"
#include "source/slang/emit.cpp"
#include "source/slang/ir.cpp"
+#include "source/slang/ir-legalize-types.cpp"
#include "source/slang/lexer.cpp"
#include "source/slang/mangle.cpp"
#include "source/slang/name.cpp"
diff --git a/source/slang/bytecode.cpp b/source/slang/bytecode.cpp
index 943a9a5a3..3b92b78e1 100644
--- a/source/slang/bytecode.cpp
+++ b/source/slang/bytecode.cpp
@@ -653,7 +653,7 @@ BytecodeGenerationPtr<char> tryGenerateNameForSymbol(
if (auto highLevelDeclDecoration = inst->findDecoration<IRHighLevelDeclDecoration>())
{
auto decl = highLevelDeclDecoration->decl;
- if (auto reflectionNameMod = decl->FindModifier<ParameterBlockReflectionName>())
+ if (auto reflectionNameMod = decl->FindModifier<ParameterGroupReflectionName>())
{
return allocateString(context, reflectionNameMod->name);
}
diff --git a/source/slang/compiler.h b/source/slang/compiler.h
index 7b539ce69..7a045d23c 100644
--- a/source/slang/compiler.h
+++ b/source/slang/compiler.h
@@ -433,6 +433,10 @@ namespace Slang
// Construct pointer types on-demand
RefPtr<PtrType> getPtrType(RefPtr<Type> valueType);
+ RefPtr<ArrayExpressionType> getArrayType(
+ Type* elementType,
+ IntVal* elementCount);
+
RefPtr<GroupSharedType> getGroupSharedType(RefPtr<Type> valueType);
SyntaxClass<RefObject> findSyntaxClass(Name* name);
diff --git a/source/slang/core.meta.slang b/source/slang/core.meta.slang
index b792a74a3..8accc83a4 100644
--- a/source/slang/core.meta.slang
+++ b/source/slang/core.meta.slang
@@ -170,6 +170,8 @@ sb << "__generic<T>\n";
sb << "__intrinsic_type(" << kIROp_TextureBufferType << ")\n";
sb << "__magic_type(TextureBuffer) struct TextureBuffer {};\n";
+sb << "__generic<T>\n";
+sb << "__magic_type(ParameterBlockType) struct ParameterBlock {};\n";
static const char* kComponentNames[]{ "x", "y", "z", "w" };
static const char* kVectorNames[]{ "", "x", "xy", "xyz", "xyzw" };
diff --git a/source/slang/core.meta.slang.h b/source/slang/core.meta.slang.h
index e47e2a90b..6b60d2896 100644
--- a/source/slang/core.meta.slang.h
+++ b/source/slang/core.meta.slang.h
@@ -173,6 +173,8 @@ sb << "__generic<T>\n";
sb << "__intrinsic_type(" << kIROp_TextureBufferType << ")\n";
sb << "__magic_type(TextureBuffer) struct TextureBuffer {};\n";
+sb << "__generic<T>\n";
+sb << "__magic_type(ParameterBlockType) struct ParameterBlock {};\n";
static const char* kComponentNames[]{ "x", "y", "z", "w" };
static const char* kVectorNames[]{ "", "x", "xy", "xyz", "xyzw" };
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 056454845..d95946204 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -3316,7 +3316,7 @@ struct EmitVisitor
{
// Don't emit a declaration that was only generated implicitly, for
// the purposes of semantic checking.
- if(decl->HasModifier<ImplicitParameterBlockElementTypeModifier>())
+ if(decl->HasModifier<ImplicitParameterGroupElementTypeModifier>())
return;
Emit("struct ");
@@ -3498,7 +3498,7 @@ struct EmitVisitor
return varLayout;
}
- void emitHLSLParameterBlockFieldLayoutSemantics(
+ void emitHLSLParameterGroupFieldLayoutSemantics(
RefPtr<VarLayout> layout,
RefPtr<VarLayout> fieldLayout)
{
@@ -3528,13 +3528,13 @@ struct EmitVisitor
}
}
- void emitHLSLParameterBlockDecl(
+ void emitHLSLParameterGroupDecl(
RefPtr<VarDeclBase> varDecl,
- RefPtr<ParameterBlockType> parameterBlockType,
+ RefPtr<ParameterGroupType> parameterGroupType,
RefPtr<VarLayout> layout)
{
// The data type that describes where stuff in the constant buffer should go
- RefPtr<Type> dataType = parameterBlockType->elementType;
+ RefPtr<Type> dataType = parameterGroupType->elementType;
// We expect/require the data type to be a user-defined `struct` type
auto declRefType = dataType->As<DeclRefType>();
@@ -3545,22 +3545,22 @@ struct EmitVisitor
SLANG_RELEASE_ASSERT(layout);
// We expect the layout to be for a structured type...
- RefPtr<ParameterBlockTypeLayout> bufferLayout = layout->typeLayout.As<ParameterBlockTypeLayout>();
+ RefPtr<ParameterGroupTypeLayout> bufferLayout = layout->typeLayout.As<ParameterGroupTypeLayout>();
SLANG_RELEASE_ASSERT(bufferLayout);
RefPtr<StructTypeLayout> structTypeLayout = bufferLayout->elementTypeLayout.As<StructTypeLayout>();
SLANG_RELEASE_ASSERT(structTypeLayout);
- if( auto constantBufferType = parameterBlockType->As<ConstantBufferType>() )
+ if( auto constantBufferType = parameterGroupType->As<ConstantBufferType>() )
{
Emit("cbuffer ");
}
- else if( auto textureBufferType = parameterBlockType->As<TextureBufferType>() )
+ else if( auto textureBufferType = parameterGroupType->As<TextureBufferType>() )
{
Emit("tbuffer ");
}
- if( auto reflectionNameModifier = varDecl->FindModifier<ParameterBlockReflectionName>() )
+ if( auto reflectionNameModifier = varDecl->FindModifier<ParameterGroupReflectionName>() )
{
Emit(" ");
emitName(reflectionNameModifier->nameAndLoc);
@@ -3587,7 +3587,7 @@ struct EmitVisitor
SLANG_RELEASE_ASSERT(fieldLayout->varDecl.GetName() == field.GetName());
// Emit explicit layout annotations for every field
- emitHLSLParameterBlockFieldLayoutSemantics(layout, fieldLayout);
+ emitHLSLParameterGroupFieldLayoutSemantics(layout, fieldLayout);
emitVarDeclInit(field);
@@ -3696,13 +3696,13 @@ struct EmitVisitor
}
}
- void emitGLSLParameterBlockDecl(
+ void emitGLSLParameterGroupDecl(
RefPtr<VarDeclBase> varDecl,
- RefPtr<ParameterBlockType> parameterBlockType,
+ RefPtr<ParameterGroupType> parameterGroupType,
RefPtr<VarLayout> layout)
{
// The data type that describes where stuff in the constant buffer should go
- RefPtr<Type> dataType = parameterBlockType->elementType;
+ RefPtr<Type> dataType = parameterGroupType->elementType;
// We expect/require the data type to be a user-defined `struct` type
auto declRefType = dataType->As<DeclRefType>();
@@ -3714,7 +3714,7 @@ struct EmitVisitor
{
auto typeLayout = layout->typeLayout;
- if (auto bufferLayout = typeLayout.As<ParameterBlockTypeLayout>())
+ if (auto bufferLayout = typeLayout.As<ParameterGroupTypeLayout>())
{
typeLayout = bufferLayout->elementTypeLayout;
}
@@ -3729,19 +3729,19 @@ struct EmitVisitor
EmitModifiers(varDecl);
// Emit an apprpriate declaration keyword based on the kind of block
- if (parameterBlockType->As<ConstantBufferType>())
+ if (parameterGroupType->As<ConstantBufferType>())
{
Emit("uniform");
}
- else if (parameterBlockType->As<GLSLInputParameterBlockType>())
+ else if (parameterGroupType->As<GLSLInputParameterGroupType>())
{
Emit("in");
}
- else if (parameterBlockType->As<GLSLOutputParameterBlockType>())
+ else if (parameterGroupType->As<GLSLOutputParameterGroupType>())
{
Emit("out");
}
- else if (parameterBlockType->As<GLSLShaderStorageBufferType>())
+ else if (parameterGroupType->As<GLSLShaderStorageBufferType>())
{
Emit("buffer");
}
@@ -3751,7 +3751,7 @@ struct EmitVisitor
Emit("uniform");
}
- if( auto reflectionNameModifier = varDecl->FindModifier<ParameterBlockReflectionName>() )
+ if( auto reflectionNameModifier = varDecl->FindModifier<ParameterGroupReflectionName>() )
{
Emit(" ");
emitName(reflectionNameModifier->nameAndLoc);
@@ -3789,19 +3789,19 @@ struct EmitVisitor
Emit(";\n");
}
- void emitParameterBlockDecl(
+ void emitParameterGroupDecl(
RefPtr<VarDeclBase> varDecl,
- RefPtr<ParameterBlockType> parameterBlockType,
+ RefPtr<ParameterGroupType> parameterGroupType,
RefPtr<VarLayout> layout)
{
switch(context->shared->target)
{
case CodeGenTarget::HLSL:
- emitHLSLParameterBlockDecl(varDecl, parameterBlockType, layout);
+ emitHLSLParameterGroupDecl(varDecl, parameterGroupType, layout);
break;
case CodeGenTarget::GLSL:
- emitGLSLParameterBlockDecl(varDecl, parameterBlockType, layout);
+ emitGLSLParameterGroupDecl(varDecl, parameterGroupType, layout);
break;
default:
@@ -3843,9 +3843,9 @@ struct EmitVisitor
//
// TODO(tfoley): there might be a better way to detect this, e.g.,
// with an attribute that gets attached to the variable declaration.
- if (auto parameterBlockType = decl->type->As<ParameterBlockType>())
+ if (auto parameterGroupType = decl->type->As<ParameterGroupType>())
{
- emitParameterBlockDecl(decl, parameterBlockType, layout);
+ emitParameterGroupDecl(decl, parameterGroupType, layout);
return;
}
@@ -4145,7 +4145,7 @@ emitDeclImpl(decl, nullptr);
if(auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>())
{
auto decl = decoration->decl;
- if (auto reflectionNameMod = decl->FindModifier<ParameterBlockReflectionName>())
+ if (auto reflectionNameMod = decl->FindModifier<ParameterGroupReflectionName>())
{
return getText(reflectionNameMod->nameAndLoc.name);
}
@@ -4492,7 +4492,7 @@ emitDeclImpl(decl, nullptr);
// because they aren't allowed as types for temporary
// variables.
auto type = inst->getType();
- if(type->As<UniformParameterBlockType>())
+ if(type->As<UniformParameterGroupType>())
{
// TODO: we need to be careful here, because
// HLSL shader model 6 allows these as explicit
@@ -4518,7 +4518,7 @@ emitDeclImpl(decl, nullptr);
{
auto type = inst->getType();
- if(type->As<UniformParameterBlockType>())
+ if(type->As<UniformParameterGroupType>())
{
// TODO: we need to be careful here, because
// HLSL shader model 6 allows these as explicit
@@ -5812,10 +5812,10 @@ emitDeclImpl(decl, nullptr);
}
}
- void emitHLSLParameterBlock(
+ void emitHLSLParameterGroup(
EmitContext* ctx,
IRGlobalVar* varDecl,
- UniformParameterBlockType* type)
+ UniformParameterGroupType* type)
{
emit("cbuffer ");
emit(getIRName(varDecl));
@@ -5832,9 +5832,9 @@ emitDeclImpl(decl, nullptr);
auto elementType = type->getElementType();
auto typeLayout = layout->typeLayout;
- if( auto parameterBlockTypeLayout = typeLayout.As<ParameterBlockTypeLayout>() )
+ if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() )
{
- typeLayout = parameterBlockTypeLayout->elementTypeLayout;
+ typeLayout = parameterGroupTypeLayout->elementTypeLayout;
}
if(auto declRefType = elementType->As<DeclRefType>())
@@ -5864,7 +5864,7 @@ emitDeclImpl(decl, nullptr);
auto fieldType = GetType(ff);
emitIRType(ctx, fieldType, getIRName(ff));
- emitHLSLParameterBlockFieldLayoutSemantics(layout, fieldLayout);
+ emitHLSLParameterGroupFieldLayoutSemantics(layout, fieldLayout);
emit(";\n");
}
@@ -5878,10 +5878,10 @@ emitDeclImpl(decl, nullptr);
emit("}\n");
}
- void emitGLSLParameterBlock(
+ void emitGLSLParameterGroup(
EmitContext* ctx,
IRGlobalVar* varDecl,
- UniformParameterBlockType* type)
+ UniformParameterGroupType* type)
{
auto layout = getVarLayout(ctx, varDecl);
assert(layout);
@@ -5909,9 +5909,9 @@ emitDeclImpl(decl, nullptr);
auto elementType = type->getElementType();
auto typeLayout = layout->typeLayout;
- if( auto parameterBlockTypeLayout = typeLayout.As<ParameterBlockTypeLayout>() )
+ if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() )
{
- typeLayout = parameterBlockTypeLayout->elementTypeLayout;
+ typeLayout = parameterGroupTypeLayout->elementTypeLayout;
}
if(auto declRefType = elementType->As<DeclRefType>())
@@ -5941,7 +5941,7 @@ emitDeclImpl(decl, nullptr);
auto fieldType = GetType(ff);
emitIRType(ctx, fieldType, getIRName(ff));
-// emitHLSLParameterBlockFieldLayoutSemantics(layout, fieldLayout);
+// emitHLSLParameterGroupFieldLayoutSemantics(layout, fieldLayout);
emit(";\n");
}
@@ -5960,19 +5960,19 @@ emitDeclImpl(decl, nullptr);
emit("};\n");
}
- void emitIRParameterBlock(
+ void emitIRParameterGroup(
EmitContext* ctx,
IRGlobalVar* varDecl,
- UniformParameterBlockType* type)
+ UniformParameterGroupType* type)
{
switch (ctx->shared->target)
{
case CodeGenTarget::HLSL:
- emitHLSLParameterBlock(ctx, varDecl, type);
+ emitHLSLParameterGroup(ctx, varDecl, type);
break;
case CodeGenTarget::GLSL:
- emitGLSLParameterBlock(ctx, varDecl, type);
+ emitGLSLParameterGroup(ctx, varDecl, type);
break;
}
}
@@ -5990,7 +5990,7 @@ emitDeclImpl(decl, nullptr);
{
case kIROp_ConstantBufferType:
case kIROp_TextureBufferType:
- emitIRParameterBlock(ctx, varDecl, (IRUniformBufferType*) varType);
+ emitIRParameterGroup(ctx, varDecl, (IRUniformBufferType*) varType);
return;
default:
@@ -6033,9 +6033,9 @@ emitDeclImpl(decl, nullptr);
auto varType = allocatedType->getValueType();
// auto addressSpace = allocatedType->getAddressSpace();
- if (auto paramBlockType = varType->As<UniformParameterBlockType>())
+ if (auto paramBlockType = varType->As<UniformParameterGroupType>())
{
- emitIRParameterBlock(
+ emitIRParameterGroup(
ctx,
varDecl,
paramBlockType);
@@ -6305,7 +6305,7 @@ StructTypeLayout* getGlobalStructLayout(
{
return gs.Ptr();
}
- else if( auto globalConstantBufferLayout = globalScopeLayout.As<ParameterBlockTypeLayout>() )
+ else if( auto globalConstantBufferLayout = globalScopeLayout.As<ParameterGroupTypeLayout>() )
{
// TODO: the `cbuffer` case really needs to be emitted very
// carefully, but that is beyond the scope of what a simple rewriter
@@ -6338,6 +6338,9 @@ StructTypeLayout* getGlobalStructLayout(
}
}
+void legalizeTypes(
+ IRModule* module);
+
String emitEntryPoint(
EntryPointRequest* entryPoint,
ProgramLayout* programLayout,
@@ -6401,20 +6404,37 @@ String emitEntryPoint(
// so that we "just" need to specialize it as needed for the
// specific target and entry point in use.
//
+ // The first pass is to extract the IR code of the entry point,
+ // and any other symbols it references. At the same time,
+ // we go ahead and select the target-specific version of
+ // any such functions if they are available. We also go
+ // ahead and apply the layout information (from `programLayout`)
+ // to the IR code (which previously had no layout).
+ //
+ // Note: it is important that we extract a *copy* of all the
+ // relevant IR, so that transformations we make for one
+ // entry point (or target) don't mess up the IR used for other
+ // entry points (targets).
+ //
auto lowered = specializeIRForEntryPoint(
entryPoint,
programLayout,
target);
- // debugging:
+ // If the user specified the flag that they want us to dump
+ // IR, then do it here, for the target-specific, but
+ // un-specialized IR.
if (translationUnit->compileRequest->shouldDumpIR)
{
dumpIR(lowered);
}
- // TODO: we should apply some guaranteed transformations here,
- // to eliminate constructs that aren't legal downstream (e.g. generics).
-
+ // Next, we need to ensure that the code we emit for
+ // the target doesn't contain any operations that would
+ // be illegal on the target platform. For example,
+ // none of our target supports generics, or interfaces,
+ // so we need to specialize those away.
+ //
specializeGenerics(lowered);
// Debugging code for IR transformations...
@@ -6424,10 +6444,12 @@ String emitEntryPoint(
fprintf(stderr, "###\n");
#endif
- //
- // TODO: Need to decide whether to do these before or after
- // target-specific legalization steps. Currently I've folded
- // legalization into the specialization above.
+ // After we've fully specialized all generics, and
+ // "devirtualized" all the calls through interfaces,
+ // we need to ensure that the code only uses types
+ // that are legal on the chosen target.
+ //
+ legalizeTypes(lowered);
// TODO: do we want to emit directly from IR, or translate the
// IR back into AST for emission?
diff --git a/source/slang/glsl.meta.slang b/source/slang/glsl.meta.slang
index 4aa3f059c..a9f4fcb3c 100644
--- a/source/slang/glsl.meta.slang
+++ b/source/slang/glsl.meta.slang
@@ -150,8 +150,8 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt)
}
}
-sb << "__generic<T> __magic_type(GLSLInputParameterBlockType) struct __GLSLInputParameterBlock {};\n";
-sb << "__generic<T> __magic_type(GLSLOutputParameterBlockType) struct __GLSLOutputParameterBlock {};\n";
+sb << "__generic<T> __magic_type(GLSLInputParameterGroupType) struct __GLSLInputParameterGroup {};\n";
+sb << "__generic<T> __magic_type(GLSLOutputParameterGroupType) struct __GLSLOutputParameterGroup {};\n";
sb << "__generic<T> __magic_type(GLSLShaderStorageBufferType) struct __GLSLShaderStorageBuffer {};\n";
sb << "__magic_type(SamplerState," << int(SamplerStateType::Flavor::SamplerState) << ") struct sampler {};";
diff --git a/source/slang/glsl.meta.slang.h b/source/slang/glsl.meta.slang.h
index a735b3beb..24c219c29 100644
--- a/source/slang/glsl.meta.slang.h
+++ b/source/slang/glsl.meta.slang.h
@@ -151,8 +151,8 @@ for (int tt = 0; tt < kBaseTextureTypeCount; ++tt)
}
}
-sb << "__generic<T> __magic_type(GLSLInputParameterBlockType) struct __GLSLInputParameterBlock {};\n";
-sb << "__generic<T> __magic_type(GLSLOutputParameterBlockType) struct __GLSLOutputParameterBlock {};\n";
+sb << "__generic<T> __magic_type(GLSLInputParameterGroupType) struct __GLSLInputParameterGroup {};\n";
+sb << "__generic<T> __magic_type(GLSLOutputParameterGroupType) struct __GLSLOutputParameterGroup {};\n";
sb << "__generic<T> __magic_type(GLSLShaderStorageBufferType) struct __GLSLShaderStorageBuffer {};\n";
sb << "__magic_type(SamplerState," << int(SamplerStateType::Flavor::SamplerState) << ") struct sampler {};";
diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp
new file mode 100644
index 000000000..677ccedd3
--- /dev/null
+++ b/source/slang/ir-legalize-types.cpp
@@ -0,0 +1,1356 @@
+// ir-legalize-types.cpp
+
+// This file implements a pass that takes IR
+// that has been fully specialized (no more
+// generics/interfaces needing to be specialized
+// away) and replaces any types that can't actually
+// be used as-is on the target.
+//
+// The particular case we are focused on is
+// aggregate types (e.g., `struct` types) that
+// contain resources (textures, samplers, etc.)
+// or that mix resources and ordinary "uniform"
+// data.
+
+#include "ir.h"
+#include "ir-insts.h"
+
+namespace Slang
+{
+
+struct LegalTypeImpl : RefObject
+{
+};
+struct ImplicitDerefType;
+struct TupleType;
+
+struct LegalType
+{
+ enum class Flavor
+ {
+ // Nothing: a NULL type
+ none,
+
+ // A simple type that can be represented directly as a `Type`
+ simple,
+
+ // Logically, we have a pointer-like type, but we are
+ // going to represnet it as the pointed-to type
+ implicitDeref,
+
+ tuple,
+ };
+
+ Flavor flavor = Flavor::none;
+ RefPtr<RefObject> obj;
+
+ static LegalType simple(Type* type)
+ {
+ LegalType result;
+ result.flavor = Flavor::simple;
+ result.obj = type;
+ return result;
+ }
+
+ RefPtr<Type> getSimple()
+ {
+ assert(flavor == Flavor::simple);
+ return obj.As<Type>();
+ }
+
+ static LegalType implicitDeref(
+ LegalType const& valueType);
+
+ RefPtr<ImplicitDerefType> getImplicitDeref()
+ {
+ assert(flavor == Flavor::implicitDeref);
+ return obj.As<ImplicitDerefType>();
+ }
+
+ static LegalType tuple(
+ RefPtr<TupleType> tupleType);
+
+ RefPtr<TupleType> getTuple()
+ {
+ assert(flavor == Flavor::tuple);
+ return obj.As<TupleType>();
+ }
+};
+
+struct ImplicitDerefType : LegalTypeImpl
+{
+ LegalType valueType;
+};
+
+LegalType LegalType::implicitDeref(
+ LegalType const& valueType)
+{
+ RefPtr<ImplicitDerefType> obj = new ImplicitDerefType();
+ obj->valueType = valueType;
+
+ LegalType result;
+ result.flavor = Flavor::implicitDeref;
+ result.obj = obj;
+ return result;
+}
+
+struct TupleType : LegalTypeImpl
+{
+ struct Element
+ {
+ DeclRef<VarDeclBase> fieldDeclRef;
+ LegalType type;
+ };
+
+ List<Element> elements;
+};
+
+LegalType LegalType::tuple(
+ RefPtr<TupleType> tupleType)
+{
+ LegalType result;
+ result.flavor = Flavor::tuple;
+ result.obj = tupleType;
+ return result;
+}
+
+struct LegalValImpl : RefObject
+{
+};
+struct TupleVal;
+
+struct LegalVal
+{
+ enum class Flavor
+ {
+ none,
+ simple,
+ implicitDeref,
+ tuple,
+ };
+
+ Flavor flavor;
+ RefPtr<RefObject> obj;
+ IRValue* irValue;
+
+ static LegalVal simple(IRValue* irValue)
+ {
+ LegalVal result;
+ result.flavor = Flavor::simple;
+ result.irValue = irValue;
+ return result;
+ }
+
+ IRValue* getSimple()
+ {
+ assert(flavor == Flavor::simple);
+ return irValue;
+ }
+
+ static LegalVal tuple(RefPtr<TupleVal> tupleVal);
+
+ RefPtr<TupleVal> getTuple()
+ {
+ assert(flavor == Flavor::tuple);
+ return obj.As<TupleVal>();
+ }
+
+ static LegalVal implicitDeref(LegalVal const& val);
+ LegalVal getImplicitDeref();
+};
+
+struct TupleVal : LegalValImpl
+{
+ struct Element
+ {
+ DeclRef<VarDeclBase> fieldDeclRef;
+ LegalVal val;
+ };
+
+ List<Element> elements;
+};
+
+LegalVal LegalVal::tuple(RefPtr<TupleVal> tupleVal)
+{
+ LegalVal result;
+ result.flavor = LegalVal::Flavor::tuple;
+ result.obj = tupleVal;
+ return result;
+}
+
+struct ImplicitDerefVal : LegalValImpl
+{
+ LegalVal val;
+};
+
+LegalVal LegalVal::implicitDeref(LegalVal const& val)
+{
+ RefPtr<ImplicitDerefVal> implicitDerefVal = new ImplicitDerefVal();
+ implicitDerefVal->val = val;
+
+ LegalVal result;
+ result.flavor = LegalVal::Flavor::implicitDeref;
+ result.obj = implicitDerefVal;
+ return result;
+}
+
+LegalVal LegalVal::getImplicitDeref()
+{
+ assert(flavor == Flavor::implicitDeref);
+ return obj.As<ImplicitDerefVal>()->val;
+}
+
+
+struct TypeLegalizationContext
+{
+ Session* session;
+ IRModule* module;
+ IRBuilder* builder;
+
+ // When inserting new globals, put them before this one.
+ IRGlobalValue* insertBeforeGlobal = nullptr;
+
+ Dictionary<IRValue*, LegalVal> mapValToLegalVal;
+};
+
+static void registerLegalizedValue(
+ TypeLegalizationContext* context,
+ IRValue* irValue,
+ LegalVal const& legalVal)
+{
+ context->mapValToLegalVal.Add(irValue, legalVal);
+}
+
+
+static bool isResourceType(Type* type)
+{
+ while (auto arrayType = type->As<ArrayExpressionType>())
+ {
+ type = arrayType->baseType;
+ }
+
+ if (auto textureTypeBase = type->As<TextureTypeBase>())
+ {
+ return true;
+ }
+ else if (auto samplerType = type->As<SamplerStateType>())
+ {
+ return true;
+ }
+
+ // TODO: need more comprehensive coverage here
+
+ return false;
+}
+
+// Legalize a type, including any nested types
+// that it transitively contains.
+static LegalType legalizeType(
+ TypeLegalizationContext* context,
+ Type* type)
+{
+ if (auto parameterBlockType = type->As<ParameterBlockType>())
+ {
+ // We basically legalize the `ParameterBlock<T>` type
+ // over to `T`. In order to represent this preoperly,
+ // we need to be careful to wrap it up in a way that
+ // tells us to eliminate downstream deferences...
+
+ auto legalElementType = legalizeType(context,
+ parameterBlockType->getElementType());
+ return LegalType::implicitDeref(legalElementType);
+ }
+ else if (isResourceType(type))
+ {
+ // We assume that any resource types not handled above
+ // are legal as-is.
+ return LegalType::simple(type);
+ }
+ else if (type->As<BasicExpressionType>())
+ {
+ return LegalType::simple(type);
+ }
+ else if (type->As<VectorExpressionType>())
+ {
+ return LegalType::simple(type);
+ }
+ else if (type->As<MatrixExpressionType>())
+ {
+ return LegalType::simple(type);
+ }
+ else if (auto declRefType = type->As<DeclRefType>())
+ {
+ auto declRef = declRefType->declRef;
+ if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>())
+ {
+ // Look at the (non-static) fields, and
+ // see if anything needs to be cleaned up.
+
+ // We collect the legalized types for the fields,
+ // along with whether we've seen anything non-simple.
+ List<TupleType::Element> legalizedElements;
+ bool anyComplex = false;
+ bool anyResource = false;
+
+ for (auto ff : getMembersOfType<StructField>(aggTypeDeclRef))
+ {
+ if (ff.getDecl()->HasModifier<HLSLStaticModifier>())
+ continue;
+
+ auto fieldType = GetType(ff);
+ if (isResourceType(fieldType))
+ {
+ anyResource = true;
+ }
+
+ auto legalFieldType = legalizeType(context, fieldType);
+
+ TupleType::Element element;
+ element.fieldDeclRef = ff;
+ element.type = legalFieldType;
+ legalizedElements.Add(element);
+
+ switch (legalFieldType.flavor)
+ {
+ case LegalType::Flavor::simple:
+ break;
+
+ default:
+ anyComplex = true;
+ break;
+ }
+ }
+
+ // If we didn't see anything that requires work,
+ // we can conceivably just use the type as-is
+ //
+ // TODO: this might be a good place to turn
+ // a reference to a generic `struct` type into
+ // a concrete non-generic type so that downstream
+ // codegen doesn't have to deal with generics...
+ //
+ // TODO: In fact, why not just fully replace
+ // all aggregate types here with some structural
+ // types defined in the IR?
+ if (!anyComplex && !anyResource)
+ {
+ return LegalType::simple(type);
+ }
+
+ // Okay, we are going to have to generate a
+ // "tuple" type.
+ //
+ // TODO: split out the "simple" fields into
+ // their own sub-type?
+
+ RefPtr<TupleType> tupleType = new TupleType();
+ tupleType->elements = legalizedElements;
+
+ return LegalType::tuple(tupleType);
+ }
+ }
+
+ return LegalType::simple(type);
+}
+
+// Legalize a type, and then expect it to
+// result in a simple type.
+static RefPtr<Type> legalizeSimpleType(
+ TypeLegalizationContext* context,
+ Type* type)
+{
+ auto legalType = legalizeType(context, type);
+ switch (legalType.flavor)
+ {
+ case LegalType::Flavor::simple:
+ return legalType.getSimple();
+
+ default:
+ // TODO: need to issue a diagnostic here.
+ SLANG_UNEXPECTED("unexpected type case");
+ break;
+ }
+}
+
+// Take a value that is being used as an operand,
+// and turn it into the equivalent legalized value.
+static LegalVal legalizeOperand(
+ TypeLegalizationContext* context,
+ IRValue* irValue)
+{
+ LegalVal legalVal;
+ if (context->mapValToLegalVal.TryGetValue(irValue, legalVal))
+ return legalVal;
+
+ // For now, assume that anything not covered
+ // by the mapping is legal as-is.
+
+ return LegalVal::simple(irValue);
+}
+
+static LegalVal legalizeLoad(
+ TypeLegalizationContext* context,
+ LegalVal legalPtrVal)
+{
+ switch (legalPtrVal.flavor)
+ {
+ case LegalVal::Flavor::simple:
+ {
+ return LegalVal::simple(
+ context->builder->emitLoad(legalPtrVal.getSimple()));
+ }
+ break;
+
+ case LegalVal::Flavor::implicitDeref:
+ // We have turne a pointer(-like) type into its pointed-to (value)
+ // type, and so the operation of loading goes away; we just use
+ // the underlying value.
+ return legalPtrVal.getImplicitDeref();
+
+ case LegalVal::Flavor::tuple:
+ {
+ // We need to emit a load for each element of
+ // the tuple.
+ RefPtr<TupleVal> tupleVal = new TupleVal();
+ for (auto ee : legalPtrVal.getTuple()->elements)
+ {
+ TupleVal::Element element;
+ element.fieldDeclRef = ee.fieldDeclRef;
+ element.val = legalizeLoad(context, ee.val);
+
+
+ tupleVal->elements.Add(element);
+ }
+ return LegalVal::tuple(tupleVal);
+ }
+ break;
+
+ default:
+ SLANG_UNEXPECTED("unhandled case");
+ break;
+ }
+}
+
+static LegalVal legalizeFieldAddress(
+ TypeLegalizationContext* context,
+ LegalType type,
+ LegalVal legalPtrOperand,
+ LegalVal legalFieldOperand)
+{
+ auto builder = context->builder;
+
+ // We don't expect any legalization to affect
+ // the "field" argument.
+ auto fieldOperand = legalFieldOperand.getSimple();
+ assert(fieldOperand->op == kIROp_decl_ref);
+ auto fieldDeclRef = ((IRDeclRef*)fieldOperand)->declRef;
+
+ switch (legalPtrOperand.flavor)
+ {
+ case LegalVal::Flavor::simple:
+ return LegalVal::simple(
+ builder->emitFieldAddress(
+ type.getSimple(),
+ legalPtrOperand.getSimple(),
+ fieldOperand));
+
+ case LegalVal::Flavor::tuple:
+ {
+ // The operand is a tuple of pointer-like
+ // values, we want to extract the element
+ // corresponding to a field. We will handle
+ // this by simply returning the corresponding
+ // element from the operand.
+ for (auto ee : legalPtrOperand.getTuple()->elements)
+ {
+ if (ee.fieldDeclRef.Equals(fieldDeclRef))
+ {
+ return ee.val;
+ }
+ }
+ SLANG_UNEXPECTED("didn't find tuple element");
+ return LegalVal();
+ }
+
+ default:
+ SLANG_UNEXPECTED("unhandled");
+ return LegalVal();
+ }
+}
+
+static LegalVal legalizeInst(
+ TypeLegalizationContext* context,
+ IRInst* inst,
+ LegalType type,
+ LegalVal const* args)
+{
+ switch (inst->op)
+ {
+ case kIROp_Load:
+ return legalizeLoad(context, args[0]);
+
+ case kIROp_FieldAddress:
+ return legalizeFieldAddress(context, type, args[0], args[1]);
+
+ default:
+ // TODO: produce a user-visible diagnostic here
+ SLANG_UNEXPECTED("non-simple operand(s)!");
+ break;
+ }
+}
+
+static LegalVal legalizeInst(
+ TypeLegalizationContext* context,
+ IRInst* inst)
+{
+ // Need to legalize all the operands.
+ auto argCount = inst->getArgCount();
+ List<LegalVal> legalArgs;
+ bool anyComplex = false;
+ for (UInt aa = 0; aa < argCount; ++aa)
+ {
+ auto oldArg = inst->getArg(aa);
+ auto legalArg = legalizeOperand(context, oldArg);
+ legalArgs.Add(legalArg);
+
+ if (legalArg.flavor != LegalVal::Flavor::simple)
+ anyComplex = true;
+ }
+
+ // Also legalize the type of the instruction
+ LegalType legalType = legalizeType(context, inst->type);
+
+ if (!anyComplex && legalType.flavor == LegalType::Flavor::simple)
+ {
+ // Nothing interesting happened to the operands,
+ // so we seem to be okay, right?
+
+ for (UInt aa = 0; aa < argCount; ++aa)
+ {
+ auto legalArg = legalArgs[aa];
+ inst->setArg(aa, legalArg.getSimple());
+ }
+
+ inst->type = legalType.getSimple();
+
+ return LegalVal::simple(inst);
+ }
+
+ // We have at least one "complex" operand, and we
+ // need to figure out what to do with it. The anwer
+ // will, in general, depend on what we are doing.
+
+ // We will set up the IR builder so that any new
+ // instructions generated will be placed after
+ // the location of the original instruct.
+ auto builder = context->builder;
+ builder->curBlock = inst->getParentBlock();
+ builder->insertBeforeInst = inst->getNextInst();
+
+ LegalVal legalVal = legalizeInst(
+ context,
+ inst,
+ legalType,
+ legalArgs.Buffer());
+
+ // After we are done, we will eliminate the
+ // original instruction by removing it from
+ // the IR.
+ //
+ // TODO: we need to add it to a list of
+ // instructions to be cleaned up...
+ inst->removeFromParent();
+
+ // The value to be used when referencing
+ // the original instruction will now be
+ // whatever value(s) we created to replace it.
+ return legalVal;
+}
+
+static void legalizeFunc(
+ TypeLegalizationContext* context,
+ IRFunc* irFunc)
+{
+ // Overwrite the function's type with
+ // the result of legalization.
+ irFunc->type = legalizeSimpleType(context, irFunc->type);
+
+ // Go through the blocks of the function
+ for (auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock())
+ {
+ // Legalize the parameters of the block, which may
+ // involve increasing the number of parameters
+ for (auto pp = bb->getFirstParam(); pp; pp = pp->getNextParam())
+ {
+ auto legalParamType = legalizeType(context, pp->getType());
+
+ switch (legalParamType.flavor)
+ {
+ case LegalType::Flavor::simple:
+ // The type is simple, so we can just rewrite it in place
+ pp->type = legalParamType.getSimple();
+ break;
+
+ default:
+ // We have something like a tuple, and will need
+ // to expand into multiple parameters now.
+ SLANG_UNEXPECTED("need to handle it!");
+ break;
+ }
+
+ }
+
+
+ // Now legalize the instructions inside the block
+ IRInst* nextInst = nullptr;
+ for (auto ii = bb->getFirstInst(); ii; ii = nextInst)
+ {
+ nextInst = ii->getNextInst();
+
+ LegalVal legalVal = legalizeInst(context, ii);
+
+ registerLegalizedValue(context, ii, legalVal);
+ }
+ }
+}
+
+// Represents the "chain" of declarations that
+// were followed to get to a variable that we
+// are now declaring as a leaf variable.
+struct LegalVarChain
+{
+ LegalVarChain* next;
+ VarLayout* varLayout;
+};
+
+static LegalVal declareSimpleVar(
+ TypeLegalizationContext* context,
+ IROp op,
+ Type* type,
+ TypeLayout* typeLayout,
+ LegalVarChain* varChain)
+{
+ RefPtr<VarLayout> varLayout;
+ if (typeLayout)
+ {
+ // We need to construct a layout for the new variable
+ // that reflects both the type we have given it, as
+ // well as all the offset information that has accumulated
+ // along the chain of parent variables.
+
+ varLayout = new VarLayout();
+ varLayout->typeLayout = typeLayout;
+
+ for (auto rr : typeLayout->resourceInfos)
+ {
+ auto resInfo = varLayout->findOrAddResourceInfo(rr.kind);
+
+ for (auto vv = varChain; vv; vv = vv->next)
+ {
+ if (auto parentResInfo = vv->varLayout->FindResourceInfo(rr.kind))
+ {
+ resInfo->index += parentResInfo->index;
+ resInfo->space += parentResInfo->space;
+ }
+ }
+ }
+
+ // Some of the parent variables might actually contain offsets
+ // to the `space` or `set` of the field, and we need to apply
+ // those to all the nested resource infos.
+ for (auto vv = varChain; vv; vv = vv->next)
+ {
+ auto parentSpaceInfo = vv->varLayout->findOrAddResourceInfo(LayoutResourceKind::ParameterBlock);
+ if (!parentSpaceInfo)
+ continue;
+
+ for (auto& rr : varLayout->resourceInfos)
+ {
+ if (rr.kind == LayoutResourceKind::ParameterBlock)
+ {
+ rr.index += parentSpaceInfo->index;
+ }
+ else
+ {
+ rr.space += parentSpaceInfo->index;
+ }
+ }
+ }
+ }
+
+ switch (op)
+ {
+ case kIROp_global_var:
+ {
+ IRBuilder* builder = context->builder;
+
+ auto globalVar = builder->createGlobalVar(type);
+ globalVar->removeFromParent();
+ globalVar->insertBefore(context->insertBeforeGlobal);
+
+ if (varLayout)
+ {
+ builder->addLayoutDecoration(globalVar, varLayout);
+ }
+
+ return LegalVal::simple(globalVar);
+ }
+ break;
+
+ default:
+ SLANG_UNEXPECTED("unexpected IR opcode");
+ break;
+ }
+}
+
+static RefPtr<TypeLayout> getDerefTypeLayout(
+ TypeLayout* typeLayout)
+{
+ if (!typeLayout)
+ return nullptr;
+
+ if (auto parameterGroupTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout))
+ {
+ return parameterGroupTypeLayout->elementTypeLayout;
+ }
+
+ return typeLayout;
+}
+
+static RefPtr<VarLayout> getFieldLayout(
+ TypeLayout* typeLayout,
+ DeclRef<VarDeclBase> fieldDeclRef)
+{
+ if (!typeLayout)
+ return nullptr;
+
+ if (auto structTypeLayout = dynamic_cast<StructTypeLayout*>(typeLayout))
+ {
+ RefPtr<VarLayout> fieldLayout;
+ if (structTypeLayout->mapVarToLayout.TryGetValue(fieldDeclRef.getDecl(), fieldLayout))
+ return fieldLayout;
+ }
+
+ return nullptr;
+}
+
+static LegalVal declareVars(
+ TypeLegalizationContext* context,
+ IROp op,
+ LegalType type,
+ TypeLayout* typeLayout,
+ LegalVarChain* varChain)
+{
+ switch (type.flavor)
+ {
+ case LegalType::Flavor::simple:
+ return declareSimpleVar(context, op, type.getSimple(), typeLayout, varChain);
+ break;
+
+ case LegalType::Flavor::implicitDeref:
+ {
+ // Just declare a variable of the pointed-to type,
+ // since we are removing the indirection.
+
+ auto val = declareVars(
+ context,
+ op,
+ type.getImplicitDeref()->valueType,
+ getDerefTypeLayout(typeLayout),
+ varChain);
+ return LegalVal::implicitDeref(val);
+ }
+ break;
+
+ case LegalType::Flavor::tuple:
+ {
+ // Declare one variable for each element of the tuple
+ auto tupleType = type.getTuple();
+
+ RefPtr<TupleVal> tupleVal = new TupleVal();
+
+ for (auto ee : tupleType->elements)
+ {
+ auto fieldLayout = getFieldLayout(typeLayout, ee.fieldDeclRef);
+ RefPtr<TypeLayout> fieldTypeLayout = fieldLayout ? fieldLayout->typeLayout : nullptr;
+
+ // If we are processing layout information, then
+ // we need to create a new link in the chain
+ // of variables that will determine offsets
+ // for the eventual leaf fields...
+ LegalVarChain newVarChainStorage;
+ LegalVarChain* newVarChain = varChain;
+ if (fieldLayout)
+ {
+ newVarChainStorage.next = varChain;
+ newVarChainStorage.varLayout = fieldLayout;
+ newVarChain = &newVarChainStorage;
+ }
+
+ TupleVal::Element element;
+ element.fieldDeclRef = ee.fieldDeclRef;
+ element.val = declareVars(
+ context,
+ op,
+ ee.type,
+ fieldTypeLayout,
+ newVarChain);
+ tupleVal->elements.Add(element);
+ }
+
+ return LegalVal::tuple(tupleVal);
+ }
+ break;
+
+ default:
+ SLANG_UNEXPECTED("unhandled");
+ break;
+ }
+}
+
+RefPtr<VarLayout> findVarLayout(IRValue* value)
+{
+ if (auto layoutDecoration = value->findDecoration<IRLayoutDecoration>())
+ return layoutDecoration->layout.As<VarLayout>();
+ return nullptr;
+}
+
+static void legalizeGlobalVar(
+ TypeLegalizationContext* context,
+ IRGlobalVar* irGlobalVar)
+{
+ // Legalize the type for the variable's value
+ auto legalValueType = legalizeType(
+ context,
+ irGlobalVar->getType()->getValueType());
+
+ RefPtr<VarLayout> varLayout = findVarLayout(irGlobalVar);
+ RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr;
+
+ // If we've decided to do implicit deref on the type,
+ // then go ahead and declare a value of the pointed-to type.
+ LegalType maybeSimpleType = legalValueType;
+ while (maybeSimpleType.flavor == LegalType::Flavor::implicitDeref)
+ {
+ maybeSimpleType = maybeSimpleType.getImplicitDeref()->valueType;
+ }
+
+ switch (maybeSimpleType.flavor)
+ {
+ case LegalType::Flavor::simple:
+ // Easy case: the type is usable as-is, and we
+ // should just do that.
+ irGlobalVar->type = context->session->getPtrType(
+ maybeSimpleType.getSimple());
+ break;
+
+ default:
+ {
+ context->insertBeforeGlobal = irGlobalVar->getNextValue();
+
+ LegalVarChain* varChain = nullptr;
+ LegalVarChain varChainStorage;
+ if (varLayout)
+ {
+ varChainStorage.next = nullptr;
+ varChainStorage.varLayout = varLayout;
+ varChain = &varChainStorage;
+ }
+
+ LegalVal newVal = declareVars(context, kIROp_global_var, legalValueType, typeLayout, varChain);
+
+ // Register the new value as the replacement for the old
+ registerLegalizedValue(context, irGlobalVar, newVal);
+
+ // Remove the old global from the module.
+ irGlobalVar->removeFromParent();
+ // TODO: actually clean up the global!
+ }
+ break;
+ }
+}
+
+static void legalizeGlobalValue(
+ TypeLegalizationContext* context,
+ IRGlobalValue* irValue)
+{
+ switch (irValue->op)
+ {
+ case kIROp_witness_table:
+ // Just skip these.
+ break;
+
+ case kIROp_Func:
+ legalizeFunc(context, (IRFunc*)irValue);
+ break;
+
+ case kIROp_global_var:
+ legalizeGlobalVar(context, (IRGlobalVar*)irValue);
+ break;
+
+ default:
+ SLANG_UNEXPECTED("unknown global value type");
+ break;
+ }
+}
+
+static void legalizeTypes(
+ TypeLegalizationContext* context)
+{
+ auto module = context->module;
+ for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue())
+ {
+ legalizeGlobalValue(context, gv);
+ }
+}
+
+
+void legalizeTypes(
+ IRModule* module)
+{
+ auto session = module->session;
+
+ SharedIRBuilder sharedBuilderStorage;
+ auto sharedBuilder = &sharedBuilderStorage;
+
+ sharedBuilder->session = session;
+ sharedBuilder->module = module;
+
+ IRBuilder builderStorage;
+ auto builder = &builderStorage;
+
+ builder->sharedBuilder = sharedBuilder;
+
+
+ TypeLegalizationContext contextStorage;
+ auto context = &contextStorage;
+
+ context->session = session;
+ context->module = module;
+ context->builder = builder;
+
+ legalizeTypes(context);
+
+}
+
+#if 0
+ typedef unsigned int TypeScalarizationFlags;
+ enum TypeScalarizationFlag
+ {
+ anyResource = 0x1,
+ anyNonResource = 0x2,
+ anyAggregate = 0x4,
+ };
+
+ bool isResourceType(Type* type)
+ {
+ while (auto arrayType = type->As<ArrayExpressionType>())
+ {
+ type = arrayType->baseType;
+ }
+
+ if (auto textureTypeBase = type->As<TextureTypeBase>())
+ {
+ return true;
+ }
+ else if (auto samplerType = type->As<SamplerStateType>())
+ {
+ return true;
+ }
+
+ // TODO: need more comprehensive coverage here
+
+ return false;
+ }
+
+ TypeScalarizationFlags getTypeScalarizationFlags(
+ Session* session,
+ Type* type)
+ {
+ // TODO: we should probably cache flags once
+ // they are computed, to avoid O(N^2) sorts
+ // of behavior.
+
+ if (isResourceType(type))
+ return TypeScalarizationFlag::anyNonResource;
+
+ if(type->As<BasicExpressionType>())
+ {
+ return TypeScalarizationFlag::anyNonResource;
+ }
+ if(type->As<VectorExpressionType>())
+ {
+ return TypeScalarizationFlag::anyNonResource;
+ }
+ if(type->As<MatrixExpressionType>())
+ {
+ return TypeScalarizationFlag::anyNonResource;
+ }
+ else if (auto declRefType = type->As<DeclRefType>())
+ {
+ auto declRef = declRefType->declRef;
+ if (auto structDeclRef = declRef.As<StructDecl>())
+ {
+ TypeScalarizationFlags flags = TypeScalarizationFlag::anyAggregate;
+
+ // For structure types, the basic rule will be
+ // that if the type contains *any* resource-type
+ // fields, then it needs to be scalarized.
+ // If it contains any non-resource-type fields,
+ // then we should aggregate these into a single
+ // new `struct` type with just the non-resource
+ // fields.
+ for (auto fieldDeclRef : getMembersOfType<StructField>(structDeclRef))
+ {
+ auto fieldType = GetType(fieldDeclRef);
+
+ // TODO: we are making a recursive call here, so
+ // this will break if/when we ever allowed a recursive type!
+ auto fieldFlags = getTypeScalarizationFlags(session, fieldType);
+ flags |= fieldFlags;
+
+ }
+
+ return flags;
+ }
+ }
+ else if (auto arrayType = type->As<ArrayExpressionType>())
+ {
+ return getTypeScalarizationFlags(
+ session,
+ arrayType->baseType);
+ }
+
+ // Default behavior: assume we have a non-resource type
+ return TypeScalarizationFlag::anyNonResource;
+ }
+
+ struct ArrayScalarizationInfo
+ {
+ ArrayScalarizationInfo* next;
+ RefPtr<IntVal> elementCount;
+ RefPtr<ArrayTypeLayout> typeLayout;
+ };
+
+ struct SharedScalarizationContext
+ {
+
+ };
+
+ struct ScalarizationContext
+ {
+ SharedScalarizationContext* shared;
+
+ IRBuilder* builder;
+ IRGlobalVar* globalVar;
+ VarLayout* globalVarLayout;
+
+ IRGlobalValue* valueToInsertAfter;
+ };
+
+ IRValue* emitSimpleScalarizedField(
+ ScalarizationContext* context,
+ Type* inType,
+ VarLayout* fieldLayout,
+ TypeLayout* inTypeLayout,
+ ArrayScalarizationInfo* arrayInfo)
+ {
+ auto builder = context->builder;
+ auto globalVar = context->globalVar;
+ auto globalVarLayout = context->globalVarLayout;
+ auto valueToInsertAfter = context->valueToInsertAfter;
+
+ RefPtr<Type> type = inType;
+ RefPtr<TypeLayout> typeLayout = inTypeLayout;
+
+ // If we are turning an array-of-structs into
+ // a struct-of-arrays, then we need to apply
+ // all the appropriate array dimensions here.
+ for (auto aa = arrayInfo; aa; aa = aa->next)
+ {
+ type = builder->getSession()->getArrayType(type, aa->elementCount);
+
+ if (typeLayout)
+ {
+ RefPtr<ArrayTypeLayout> arrayTypeLayout = new ArrayTypeLayout();
+ arrayTypeLayout->elementTypeLayout = typeLayout;
+
+ // TODO: fill in the other fields!
+
+ typeLayout = arrayTypeLayout;
+ }
+ }
+
+ RefPtr<VarLayout> newVarLayout;
+ if (typeLayout)
+ {
+ newVarLayout = new VarLayout();
+ newVarLayout->typeLayout = typeLayout;
+
+ if (fieldLayout)
+ {
+ for (auto fieldResourceInfo : fieldLayout->resourceInfos)
+ {
+ auto newResourceInfo = newVarLayout->findOrAddResourceInfo(fieldResourceInfo.kind);
+
+ if (globalVarLayout)
+ {
+ if (auto globalResourceInfo = globalVarLayout->FindResourceInfo(fieldResourceInfo.kind))
+ {
+ newResourceInfo->index += globalResourceInfo->index;
+ newResourceInfo->space += globalResourceInfo->space;
+ }
+ }
+
+ newResourceInfo->index += fieldResourceInfo.index;
+ newResourceInfo->space += fieldResourceInfo.space;
+ }
+ }
+ }
+
+ auto newGlobalVar = addGlobalVariable(builder->getModule(), type);
+ builder->addLayoutDecoration(newGlobalVar, newVarLayout);
+
+ newGlobalVar->removeFromParent();
+ newGlobalVar->insertAfter(valueToInsertAfter);
+
+ context->valueToInsertAfter = newGlobalVar;
+
+ return newGlobalVar;
+ }
+
+ void scalarizeGlobalVariable(
+ ScalarizationContext* context,
+ Type* valueType,
+ TypeLayout* valueTypeLayout,
+ ArrayScalarizationInfo* arrayInfo)
+ {
+ if (auto arrayType = valueType->As<ArrayExpressionType>())
+ {
+ // Okay, we need to recurse down and scalarize the
+ // array element type, wrapping up each field in
+ // an array declarator as needed.
+
+ ArrayScalarizationInfo newArrayInfo;
+ newArrayInfo.next = arrayInfo;
+ newArrayInfo.elementCount = arrayType->ArrayLength;
+
+ RefPtr<TypeLayout> elementTypeLayout;
+ if (auto arrayTypeLayout = dynamic_cast<ArrayTypeLayout*>(valueTypeLayout))
+ {
+ newArrayInfo.typeLayout = arrayTypeLayout;
+ elementTypeLayout = arrayTypeLayout->elementTypeLayout;
+ }
+
+ scalarizeGlobalVariable(
+ context,
+ arrayType->baseType,
+ elementTypeLayout,
+ &newArrayInfo);
+
+ // Now we need to look at all uses of the variable,
+ // and properly rework element-index operations
+ // to instead index into the sub-arrays...
+ }
+ else if (auto declRefType = valueType->As<DeclRefType>())
+ {
+ auto declRef = declRefType->declRef;
+ if (auto aggTypeDeclRef = declRef.As<AggTypeDecl>())
+ {
+ RefPtr<StructTypeLayout> structTypeLayout = dynamic_cast<StructTypeLayout*>(valueTypeLayout);
+
+ // Okay, we need to look through the fields, and
+ // create a new variable for each of them.
+ Dictionary<Decl*, IRValue*> fieldMap;
+ UInt fieldCounter = 0;
+ for (auto fieldDeclRef : getMembersOfType<StructField>(aggTypeDeclRef))
+ {
+ UInt fieldIndex = fieldCounter++;
+
+ RefPtr<VarLayout> fieldLayout;
+ RefPtr<TypeLayout> fieldTypeLayout;
+ if (structTypeLayout)
+ {
+ fieldLayout = structTypeLayout->fields[fieldIndex];
+ fieldTypeLayout = fieldLayout->typeLayout;
+ }
+
+ // Note: we do *not* try to deal with recursive
+ // expansion of the fields here, and instead
+ // prefer to handle those in further
+ // simplification passes.
+
+ auto fieldGlobalVar = emitSimpleScalarizedField(
+ context,
+ GetType(fieldDeclRef),
+ fieldLayout,
+ fieldTypeLayout,
+ arrayInfo);
+
+ fieldMap.Add(fieldDeclRef.getDecl(), fieldGlobalVar);
+ }
+
+ // Now we need to scan for uses of the original variable,
+ // and replace them with uses of the individual fields.
+ auto globalVar = context->globalVar;
+ IRUse* nextUse = nullptr;
+ for (IRUse* use = globalVar->firstUse; use; use = nextUse)
+ {
+ nextUse = use->nextUse;
+
+ IRUser* user = use->user;
+ switch (user->op)
+ {
+ case kIROp_FieldAddress:
+ {
+ // This should be the easy case: we are taking
+ // the address of a field inside this global
+ // value, so we can just return the adress
+ // of the global value that replaced that field.
+ IRFieldAddress* fieldAddressInst = (IRFieldAddress*)user;
+
+ IRValue* fieldOperand = fieldAddressInst->getField();
+ assert(fieldOperand->op == kIROp_decl_ref);
+ auto fieldDeclRef = ((IRDeclRef*)fieldOperand)->declRef;
+ auto fieldDecl = fieldDeclRef.getDecl();
+
+ IRValue* fieldVar = *fieldMap.TryGetValue(fieldDecl);
+
+ fieldAddressInst->replaceUsesWith(fieldVar);
+ }
+ break;
+
+ default:
+ SLANG_UNEXPECTED("what to do?");
+ break;
+ }
+ }
+ }
+ else
+ {
+ SLANG_UNEXPECTED("not handled");
+ }
+ }
+ else
+ {
+ SLANG_UNEXPECTED("not handled");
+ }
+ }
+
+ void scalarizeGlobalVariable(
+ SharedScalarizationContext* sharedContext,
+ IRBuilder* builder,
+ IRGlobalVar* globalVar,
+ VarLayout* globalVarLayout,
+ Type* valueType,
+ TypeLayout* valueTypeLayout)
+ {
+ ScalarizationContext contextStorage;
+ auto context = &contextStorage;
+
+ context->shared = sharedContext;
+ context->builder = builder;
+ context->globalVar = globalVar;
+ context->globalVarLayout = globalVarLayout;
+ context->valueToInsertAfter = globalVar;
+
+ scalarizeGlobalVariable(
+ context,
+ valueType,
+ valueTypeLayout,
+ nullptr);
+ }
+
+ RefPtr<VarLayout> findVarLayout(IRValue* value)
+ {
+ if (auto layoutDecoration = value->findDecoration<IRLayoutDecoration>())
+ return layoutDecoration->layout.As<VarLayout>();
+ return nullptr;
+ }
+
+ void scalarizeMixedResourceTypes(
+ Session* session,
+ IRModule* module)
+ {
+ SharedIRBuilder sharedBuilderStorage;
+ auto sharedBuilder = &sharedBuilderStorage;
+
+ sharedBuilder->session = session;
+ sharedBuilder->module = module;
+
+ IRBuilder builderStorage;
+ auto builder = &builderStorage;
+
+ builder->shared = sharedBuilder;
+
+ SharedScalarizationContext sharedContextStorage;
+ auto sharedContext = &sharedContextStorage;
+
+
+ List<IRValue*> workList;
+ for (auto gv = module->getFirstGlobalValue(); gv; gv = gv->getNextValue())
+ {
+ workList.Add(gv);
+ }
+
+ while (workList.Count())
+ {
+ IRValue* value = workList[0];
+ workList.FastRemoveAt(0);
+
+ switch (value->op)
+ {
+ case kIROp_Func:
+ {
+ // TODO: need to iterate over parameters of
+ // the function (and its blocks) to make
+ // sure that any types that need scalarization
+ // are properly handled.
+ }
+ break;
+
+ case kIROp_global_var:
+ {
+ IRGlobalVar* globalVar = (IRGlobalVar*)value;
+ auto valueType = globalVar->getType()->getValueType();
+
+ auto flags = getTypeScalarizationFlags(session, valueType);
+ if (!(flags & (TypeScalarizationFlag::anyNonResource | TypeScalarizationFlag::anyAggregate)))
+ continue;
+
+ auto varLayout = findVarLayout(globalVar);
+ RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr;
+
+ // Okay, we have a variable of some composite type
+ // that we need to scalarize. Since this is a global,
+ // we also need to be careful to deal with any
+ // layout information that has been attached.
+
+ scalarizeGlobalVariable(
+ sharedContext,
+ builder,
+ globalVar,
+ varLayout,
+ valueType,
+ typeLayout);
+
+ globalVar->removeFromParent();
+ // TODO: need to destroy this global!
+ }
+ break;
+
+ default:
+ {
+ // TODO: look at the type of the value,
+ // and if it needs scalarization, replace
+ // it with a tuple here.
+ }
+ break;
+ }
+ }
+ }
+
+
+#endif
+
+}
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index ab961a159..d6a01a484 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -55,6 +55,28 @@ namespace Slang
}
}
+ void IRUse::set(IRValue* usedValue)
+ {
+ // clear out the old value
+ if (usedValue)
+ {
+ *prevLink = nextUse;
+ }
+
+ init(user, usedValue);
+ }
+
+ void IRUse::clear()
+ {
+ if (usedValue)
+ {
+ *prevLink = nextUse;
+ }
+
+ user = nullptr;
+ usedValue = nullptr;
+ }
+
//
IRUse* IRUser::getArgs()
@@ -3683,9 +3705,8 @@ namespace Slang
// these should get run whether or not the entry point
// references them.
- // Depending on the downstream target, we may need to apply some
- // guaranteed transformations to legalize things. We will go
- // ahead and apply there here for now.
+ // For GLSL only, we will need to perform "legalization" of
+ // the entry point and any entry-point parameters.
switch (target)
{
case CodeGenTarget::GLSL:
diff --git a/source/slang/ir.h b/source/slang/ir.h
index 2e15e39d6..12dc08e13 100644
--- a/source/slang/ir.h
+++ b/source/slang/ir.h
@@ -93,6 +93,8 @@ struct IRUse
IRUse** prevLink;
void init(IRUser* user, IRValue* usedValue);
+ void set(IRValue* usedValue);
+ void clear();
};
enum IRDecorationOp : uint16_t
@@ -255,6 +257,11 @@ struct IRUser : IRChildValue
{
return getArgs()[index].usedValue;
}
+
+ void setArg(UInt index, IRValue* value)
+ {
+ getArgs()[index].set(value);
+ }
};
// Instructions are values that are children of a basic block,
diff --git a/source/slang/lower.cpp b/source/slang/lower.cpp
index 44ad5c272..ccf302027 100644
--- a/source/slang/lower.cpp
+++ b/source/slang/lower.cpp
@@ -3357,9 +3357,9 @@ struct LoweringVisitor
if (!typeLayout)
return nullptr;
- while (auto parameterBlockTypeLayout = typeLayout.As<ParameterBlockTypeLayout>())
+ while (auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>())
{
- typeLayout = parameterBlockTypeLayout->elementTypeLayout;
+ typeLayout = parameterGroupTypeLayout->elementTypeLayout;
}
while (auto arrayTypeLayout = typeLayout.As<ArrayTypeLayout>())
@@ -3435,7 +3435,7 @@ struct LoweringVisitor
shared->loweredDecls.Add(decl, tupleDecl);
return tupleDecl;
}
- if (auto bufferType = loweredType->As<UniformParameterBlockType>())
+ if (auto bufferType = loweredType->As<UniformParameterGroupType>())
{
auto varLayout = tryToFindLayout(decl).As<VarLayout>();
diff --git a/source/slang/modifier-defs.h b/source/slang/modifier-defs.h
index c563d35cf..0f92fcd61 100644
--- a/source/slang/modifier-defs.h
+++ b/source/slang/modifier-defs.h
@@ -144,11 +144,11 @@ SIMPLE_SYNTAX_CLASS(GLSLPatchModifier , SimpleModifier)
// Indicates that this is a variable declaration that corresponds to
// a parameter block declaration in the source program.
-SIMPLE_SYNTAX_CLASS(ImplicitParameterBlockVariableModifier , Modifier)
+SIMPLE_SYNTAX_CLASS(ImplicitParameterGroupVariableModifier , Modifier)
// Indicates that this is a type that corresponds to the element
// type of a parameter block declaration in the source program.
-SIMPLE_SYNTAX_CLASS(ImplicitParameterBlockElementTypeModifier, Modifier)
+SIMPLE_SYNTAX_CLASS(ImplicitParameterGroupElementTypeModifier, Modifier)
// An HLSL semantic
ABSTRACT_SYNTAX_CLASS(HLSLSemantic, Modifier)
@@ -197,7 +197,7 @@ SYNTAX_CLASS(GLSLExtensionDirective, GLSLPreprocessorDirective)
FIELD(Token, dispositionToken)
END_SYNTAX_CLASS()
-SYNTAX_CLASS(ParameterBlockReflectionName, Modifier)
+SYNTAX_CLASS(ParameterGroupReflectionName, Modifier)
FIELD(NameLoc, nameAndLoc)
END_SYNTAX_CLASS()
diff --git a/source/slang/parameter-binding.cpp b/source/slang/parameter-binding.cpp
index 18294bb3e..05b9d924e 100644
--- a/source/slang/parameter-binding.cpp
+++ b/source/slang/parameter-binding.cpp
@@ -205,6 +205,9 @@ struct SharedParameterBindingContext
// This is only used for varying input/output.
//
Dictionary<TranslationUnitRequest*, RefPtr<UsedRangeSet>> translationUnitUsedRangeSets;
+
+ // Which register spaces have been claimed so far?
+ UsedRanges usedSpaces;
};
static DiagnosticSink* getSink(SharedParameterBindingContext* shared)
@@ -379,7 +382,7 @@ static bool findLayoutArg(
static Name* getReflectionName(VarDeclBase* varDecl)
{
- if (auto reflectionNameModifier = varDecl->FindModifier<ParameterBlockReflectionName>())
+ if (auto reflectionNameModifier = varDecl->FindModifier<ParameterGroupReflectionName>())
return reflectionNameModifier->nameAndLoc.name;
return varDecl->getName();
@@ -398,7 +401,7 @@ RefPtr<Type> tryGetEffectiveTypeForGLSLVaryingInput(
return nullptr;
auto type = varDecl->getType();
- if( varDecl->HasModifier<InModifier>() || type->As<GLSLInputParameterBlockType>())
+ if( varDecl->HasModifier<InModifier>() || type->As<GLSLInputParameterGroupType>())
{
// Special case to handle "arrayed" shader inputs, as used
// for Geometry and Hull input
@@ -436,7 +439,7 @@ RefPtr<Type> tryGetEffectiveTypeForGLSLVaryingOutput(
return nullptr;
auto type = varDecl->getType();
- if( varDecl->HasModifier<OutModifier>() || type->As<GLSLOutputParameterBlockType>())
+ if( varDecl->HasModifier<OutModifier>() || type->As<GLSLOutputParameterGroupType>())
{
// Special case to handle "arrayed" shader outputs, as used
// for Hull Shader output
@@ -716,6 +719,24 @@ static RefPtr<UsedRangeSet> findUsedRangeSetForSpace(
return usedRangeSet;
}
+// Record that a particular register space (or set, in the GLSL case)
+// has been used in at least one binding, and so it should not
+// be used by auto-generated bindings that need to claim entire
+// spaces.
+static void markSpaceUsed(
+ ParameterBindingContext* context,
+ UInt space)
+{
+ context->shared->usedSpaces.Add(nullptr, space, space+1);
+}
+
+static UInt allocateUnusedSpaces(
+ ParameterBindingContext* context,
+ UInt count)
+{
+ return context->shared->usedSpaces.Allocate(nullptr, count);
+}
+
static RefPtr<UsedRangeSet> findUsedRangeSetForTranslationUnit(
ParameterBindingContext* context,
TranslationUnitRequest* translationUnit)
@@ -773,6 +794,12 @@ static void addExplicitParameterBinding(
if (!usedRangeSet)
{
usedRangeSet = findUsedRangeSetForSpace(context, semanticInfo.space);
+
+ // Record that the particular binding space was
+ // used by an explicit binding, so that we don't
+ // claim it for auto-generated bindings that
+ // need to grab a full space
+ markSpaceUsed(context, semanticInfo.space);
}
auto overlappedParameterInfo = usedRangeSet->usedResourceRanges[(int)semanticInfo.kind].Add(
parameterInfo,
@@ -950,6 +977,26 @@ static void completeBindingsForParameter(
continue;
}
+ auto count = typeRes.count;
+
+ // We need to special-case the scenario where
+ // a parameter wants to claim an entire register
+ // space to itself (for a parameter block), since
+ // that can't be handled like other resources.
+ if (kind == LayoutResourceKind::ParameterBlock)
+ {
+ // We need to snag a register space of our own.
+
+ UInt space = allocateUnusedSpaces(context, count);
+
+ bindingInfo.count = count;
+ bindingInfo.index = space;
+ bindingInfo.space = 0;
+
+ continue;
+ }
+
+
// For now we only auto-generate bindings in space zero
//
// TODO: we may want to support searching for a space with
@@ -970,7 +1017,6 @@ static void completeBindingsForParameter(
break;
}
- auto count = typeRes.count;
bindingInfo.count = count;
bindingInfo.index = usedRangeSet->usedResourceRanges[(int)kind].Allocate(parameterInfo, (int) count);
@@ -1699,7 +1745,7 @@ void generateParameterBindings(
// up a global constant buffer type layout to hold them
if( anyGlobalUniforms )
{
- auto globalConstantBufferLayout = createParameterBlockTypeLayout(
+ auto globalConstantBufferLayout = createParameterGroupTypeLayout(
nullptr,
globalScopeRules,
globalScopeRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer),
diff --git a/source/slang/parser.cpp b/source/slang/parser.cpp
index 57956485a..595d58d7e 100644
--- a/source/slang/parser.cpp
+++ b/source/slang/parser.cpp
@@ -1738,16 +1738,16 @@ namespace Slang
auto reflectionNameToken = parser->ReadToken(TokenType::Identifier);
// Attach the reflection name to the block so we can use it
- auto reflectionNameModifier = new ParameterBlockReflectionName();
+ auto reflectionNameModifier = new ParameterGroupReflectionName();
reflectionNameModifier->nameAndLoc = NameLoc(reflectionNameToken);
addModifier(bufferVarDecl, reflectionNameModifier);
// Both the buffer variable and its type need to have names generated
- bufferVarDecl->nameAndLoc.name = generateName(parser, "parameterBlock_" + reflectionNameToken.Content);
- bufferDataTypeDecl->nameAndLoc.name = generateName(parser, "ParameterBlock_" + reflectionNameToken.Content);
+ bufferVarDecl->nameAndLoc.name = generateName(parser, "parameterGroup_" + reflectionNameToken.Content);
+ bufferDataTypeDecl->nameAndLoc.name = generateName(parser, "ParameterGroup_" + reflectionNameToken.Content);
- addModifier(bufferDataTypeDecl, new ImplicitParameterBlockElementTypeModifier());
- addModifier(bufferVarDecl, new ImplicitParameterBlockVariableModifier());
+ addModifier(bufferDataTypeDecl, new ImplicitParameterGroupElementTypeModifier());
+ addModifier(bufferVarDecl, new ImplicitParameterGroupVariableModifier());
// TODO(tfoley): We end up constructing unchecked syntax here that
// is expected to type check into the right form, but it might be
@@ -1875,12 +1875,12 @@ namespace Slang
else if( auto inMod = modifiers.findModifier<InModifier>() )
{
removeModifier(modifiers, inMod);
- blockWrapperTypeName = "__GLSLInputParameterBlock";
+ blockWrapperTypeName = "__GLSLInputParameterGroup";
}
else if( auto outMod = modifiers.findModifier<OutModifier>() )
{
removeModifier(modifiers, outMod);
- blockWrapperTypeName = "__GLSLOutputParameterBlock";
+ blockWrapperTypeName = "__GLSLOutputParameterGroup";
}
else if( auto bufferMod = modifiers.findModifier<GLSLBufferModifier>() )
{
@@ -1899,11 +1899,11 @@ namespace Slang
RefPtr<StructDecl> blockDataTypeDecl = new StructDecl();
RefPtr<Variable> blockVarDecl = new Variable();
- addModifier(blockDataTypeDecl, new ImplicitParameterBlockElementTypeModifier());
- addModifier(blockVarDecl, new ImplicitParameterBlockVariableModifier());
+ addModifier(blockDataTypeDecl, new ImplicitParameterGroupElementTypeModifier());
+ addModifier(blockVarDecl, new ImplicitParameterGroupVariableModifier());
// Attach the reflection name to the block so we can use it
- auto reflectionNameModifier = new ParameterBlockReflectionName();
+ auto reflectionNameModifier = new ParameterGroupReflectionName();
reflectionNameModifier->nameAndLoc = NameLoc(reflectionNameToken);
addModifier(blockVarDecl, reflectionNameModifier);
@@ -1912,7 +1912,7 @@ namespace Slang
parser->FillPosition(blockVarDecl.Ptr());
// Generate a unique name for the data type
- blockDataTypeDecl->nameAndLoc.name = generateName(parser, "ParameterBlock_" + reflectionNameToken.Content);
+ blockDataTypeDecl->nameAndLoc.name = generateName(parser, "ParameterGroup_" + reflectionNameToken.Content);
// TODO(tfoley): We end up constructing unchecked syntax here that
// is expected to type check into the right form, but it might be
@@ -1957,7 +1957,7 @@ namespace Slang
else
{
// synthesize a dummy name
- blockVarDecl->nameAndLoc.name = generateName(parser, "parameterBlock_" + reflectionNameToken.Content);
+ blockVarDecl->nameAndLoc.name = generateName(parser, "parameterGroup_" + reflectionNameToken.Content);
// Otherwise we have a transparent declaration, similar
// to an HLSL `cbuffer`
diff --git a/source/slang/profile-defs.h b/source/slang/profile-defs.h
index ea23398e1..177c4a0c5 100644
--- a/source/slang/profile-defs.h
+++ b/source/slang/profile-defs.h
@@ -77,6 +77,7 @@ PROFILE_VERSION(DX_4_0_Level_9_1, DX)
PROFILE_VERSION(DX_4_0_Level_9_3, DX)
PROFILE_VERSION(DX_4_1, DX)
PROFILE_VERSION(DX_5_0, DX)
+PROFILE_VERSION(DX_5_1, DX)
PROFILE_VERSION(DX_6_0, DX)
PROFILE_VERSION(DX_6_1, DX)
PROFILE_VERSION(DX_6_2, DX)
@@ -100,11 +101,13 @@ PROFILE_VERSION(GLSL_450, GLSL)
PROFILE(DX_Compute_4_0, cs_4_0, Compute, DX_4_0)
PROFILE(DX_Compute_4_1, cs_4_1, Compute, DX_4_1)
PROFILE(DX_Compute_5_0, cs_5_0, Compute, DX_5_0)
+PROFILE(DX_Compute_5_1, cs_5_1, Compute, DX_5_1)
PROFILE(DX_Compute_6_0, cs_6_0, Compute, DX_6_0)
PROFILE(DX_Compute_6_1, cs_6_1, Compute, DX_6_1)
PROFILE(DX_Compute_6_2, cs_6_2, Compute, DX_6_2)
PROFILE(DX_Domain_5_0, ds_5_0, Domain, DX_5_0)
+PROFILE(DX_Domain_5_1, ds_5_1, Domain, DX_5_1)
PROFILE(DX_Domain_6_0, ds_6_0, Domain, DX_6_0)
PROFILE(DX_Domain_6_1, ds_6_1, Domain, DX_6_1)
PROFILE(DX_Domain_6_2, ds_6_2, Domain, DX_6_2)
@@ -112,12 +115,14 @@ PROFILE(DX_Domain_6_2, ds_6_2, Domain, DX_6_2)
PROFILE(DX_Geometry_4_0, gs_4_0, Geometry, DX_4_0)
PROFILE(DX_Geometry_4_1, gs_4_1, Geometry, DX_4_1)
PROFILE(DX_Geometry_5_0, gs_5_0, Geometry, DX_5_0)
+PROFILE(DX_Geometry_5_1, gs_5_1, Geometry, DX_5_1)
PROFILE(DX_Geometry_6_0, gs_6_0, Geometry, DX_6_0)
PROFILE(DX_Geometry_6_1, gs_6_1, Geometry, DX_6_1)
PROFILE(DX_Geometry_6_2, gs_6_2, Geometry, DX_6_2)
PROFILE(DX_Hull_5_0, hs_5_0, Hull, DX_5_0)
+PROFILE(DX_Hull_5_1, hs_5_1, Hull, DX_5_1)
PROFILE(DX_Hull_6_0, hs_6_0, Hull, DX_6_0)
PROFILE(DX_Hull_6_1, hs_6_1, Hull, DX_6_1)
PROFILE(DX_Hull_6_2, hs_6_2, Hull, DX_6_2)
@@ -129,6 +134,7 @@ PROFILE(DX_Fragment_4_0_Level_9_1, ps_4_0_level_9_1, Fragment, DX_4_0_Level_9_1)
PROFILE(DX_Fragment_4_0_Level_9_3, ps_4_0_level_9_3, Fragment, DX_4_0_Level_9_3)
PROFILE(DX_Fragment_4_1, ps_4_1, Fragment, DX_4_1)
PROFILE(DX_Fragment_5_0, ps_5_0, Fragment, DX_5_0)
+PROFILE(DX_Fragment_5_1, ps_5_1, Fragment, DX_5_1)
PROFILE(DX_Fragment_6_0, ps_6_0, Fragment, DX_6_0)
PROFILE(DX_Fragment_6_1, ps_6_1, Fragment, DX_6_1)
PROFILE(DX_Fragment_6_2, ps_6_2, Fragment, DX_6_2)
@@ -140,6 +146,7 @@ PROFILE(DX_Vertex_4_0_Level_9_1, vs_4_0_level_9_1, Vertex, DX_4_0_Level_9_1)
PROFILE(DX_Vertex_4_0_Level_9_3, vs_4_0_level_9_3, Vertex, DX_4_0_Level_9_3)
PROFILE(DX_Vertex_4_1, vs_4_1, Vertex, DX_4_1)
PROFILE(DX_Vertex_5_0, vs_5_0, Vertex, DX_5_0)
+PROFILE(DX_Vertex_5_1, vs_5_1, Vertex, DX_5_1)
PROFILE(DX_Vertex_6_0, vs_6_0, Vertex, DX_6_0)
PROFILE(DX_Vertex_6_1, vs_6_1, Vertex, DX_6_1)
PROFILE(DX_Vertex_6_2, vs_6_2, Vertex, DX_6_2)
diff --git a/source/slang/reflection.cpp b/source/slang/reflection.cpp
index d7e8820c0..3ed182750 100644
--- a/source/slang/reflection.cpp
+++ b/source/slang/reflection.cpp
@@ -502,7 +502,7 @@ SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_GetElementTypeLayout
{
return (SlangReflectionTypeLayout*) arrayTypeLayout->elementTypeLayout.Ptr();
}
- else if( auto constantBufferTypeLayout = dynamic_cast<ParameterBlockTypeLayout*>(typeLayout))
+ else if( auto constantBufferTypeLayout = dynamic_cast<ParameterGroupTypeLayout*>(typeLayout))
{
return convert(constantBufferTypeLayout->elementTypeLayout.Ptr());
}
@@ -569,7 +569,7 @@ SLANG_API char const* spReflectionVariable_GetName(SlangReflectionVariable* inVa
// If the variable is one that has an "external" name that is supposed
// to be exposed for reflection, then report it here
- if(auto reflectionNameMod = var->FindModifier<ParameterBlockReflectionName>())
+ if(auto reflectionNameMod = var->FindModifier<ParameterGroupReflectionName>())
return getText(reflectionNameMod->nameAndLoc.name).Buffer();
return getText(var->getName()).Buffer();
@@ -680,9 +680,9 @@ namespace Slang
{
static unsigned getParameterCount(RefPtr<TypeLayout> typeLayout)
{
- if(auto parameterBlockLayout = typeLayout.As<ParameterBlockTypeLayout>())
+ if(auto parameterGroupLayout = typeLayout.As<ParameterGroupTypeLayout>())
{
- typeLayout = parameterBlockLayout->elementTypeLayout;
+ typeLayout = parameterGroupLayout->elementTypeLayout;
}
if(auto structLayout = typeLayout.As<StructTypeLayout>())
@@ -695,9 +695,9 @@ namespace Slang
static VarLayout* getParameterByIndex(RefPtr<TypeLayout> typeLayout, unsigned index)
{
- if(auto parameterBlockLayout = typeLayout.As<ParameterBlockTypeLayout>())
+ if(auto parameterGroupLayout = typeLayout.As<ParameterGroupTypeLayout>())
{
- typeLayout = parameterBlockLayout->elementTypeLayout;
+ typeLayout = parameterGroupLayout->elementTypeLayout;
}
if(auto structLayout = typeLayout.As<StructTypeLayout>())
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index b09eae3ab..c50eaaae4 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -211,6 +211,7 @@
<ClCompile Include="diagnostics.cpp" />
<ClCompile Include="dxc-support.cpp" />
<ClCompile Include="emit.cpp" />
+ <ClCompile Include="ir-legalize-types.cpp" />
<ClCompile Include="ir.cpp" />
<ClCompile Include="lexer.cpp" />
<ClCompile Include="lookup.cpp" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index ef9b3c8e5..ce933db6e 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -71,6 +71,7 @@
<ClCompile Include="vm.cpp" />
<ClCompile Include="mangle.cpp" />
<ClCompile Include="dxc-support.cpp" />
+ <ClCompile Include="ir-legalize-types.cpp" />
</ItemGroup>
<ItemGroup>
<CustomBuild Include="core.meta.slang" />
diff --git a/source/slang/syntax.cpp b/source/slang/syntax.cpp
index 9acdadad6..9025c545a 100644
--- a/source/slang/syntax.cpp
+++ b/source/slang/syntax.cpp
@@ -294,6 +294,17 @@ void Type::accept(IValVisitor* visitor, void* extra)
declRef)->As<PtrType>();
}
+ RefPtr<ArrayExpressionType> Session::getArrayType(
+ Type* elementType,
+ IntVal* elementCount)
+ {
+ RefPtr<ArrayExpressionType> arrayType = new ArrayExpressionType();
+ arrayType->baseType = elementType;
+ arrayType->ArrayLength = elementCount;
+ return arrayType;
+ }
+
+
RefPtr<GroupSharedType> Session::getGroupSharedType(RefPtr<Type> valueType)
{
RefPtr<GroupSharedType> groupSharedType = new GroupSharedType();
@@ -641,8 +652,9 @@ void Type::accept(IValVisitor* visitor, void* extra)
CASE(ConstantBuffer, ConstantBufferType)
CASE(TextureBuffer, TextureBufferType)
- CASE(GLSLInputParameterBlockType, GLSLInputParameterBlockType)
- CASE(GLSLOutputParameterBlockType, GLSLOutputParameterBlockType)
+ CASE(ParameterBlockType, ParameterBlockType)
+ CASE(GLSLInputParameterGroupType, GLSLInputParameterGroupType)
+ CASE(GLSLOutputParameterGroupType, GLSLOutputParameterGroupType)
CASE(GLSLShaderStorageBufferType, GLSLShaderStorageBufferType)
CASE(HLSLStructuredBufferType, HLSLStructuredBufferType)
diff --git a/source/slang/type-defs.h b/source/slang/type-defs.h
index 60f519c82..34c5b5936 100644
--- a/source/slang/type-defs.h
+++ b/source/slang/type-defs.h
@@ -278,24 +278,27 @@ SIMPLE_SYNTAX_CLASS(GLSLInputAttachmentType, DeclRefType)
// Base class for types used when desugaring parameter block
// declarations, includeing HLSL `cbuffer` or GLSL `uniform` blocks.
-SIMPLE_SYNTAX_CLASS(ParameterBlockType, PointerLikeType)
+SIMPLE_SYNTAX_CLASS(ParameterGroupType, PointerLikeType)
-SIMPLE_SYNTAX_CLASS(UniformParameterBlockType, ParameterBlockType)
-SIMPLE_SYNTAX_CLASS(VaryingParameterBlockType, ParameterBlockType)
+SIMPLE_SYNTAX_CLASS(UniformParameterGroupType, ParameterGroupType)
+SIMPLE_SYNTAX_CLASS(VaryingParameterGroupType, ParameterGroupType)
// type for HLSL `cbuffer` declarations, and `ConstantBuffer<T>`
// ALso used for GLSL `uniform` blocks.
-SIMPLE_SYNTAX_CLASS(ConstantBufferType, UniformParameterBlockType)
+SIMPLE_SYNTAX_CLASS(ConstantBufferType, UniformParameterGroupType)
// type for HLSL `tbuffer` declarations, and `TextureBuffer<T>`
-SIMPLE_SYNTAX_CLASS(TextureBufferType, UniformParameterBlockType)
+SIMPLE_SYNTAX_CLASS(TextureBufferType, UniformParameterGroupType)
// type for GLSL `in` and `out` blocks
-SIMPLE_SYNTAX_CLASS(GLSLInputParameterBlockType, VaryingParameterBlockType)
-SIMPLE_SYNTAX_CLASS(GLSLOutputParameterBlockType, VaryingParameterBlockType)
+SIMPLE_SYNTAX_CLASS(GLSLInputParameterGroupType, VaryingParameterGroupType)
+SIMPLE_SYNTAX_CLASS(GLSLOutputParameterGroupType, VaryingParameterGroupType)
// type for GLLSL `buffer` blocks
-SIMPLE_SYNTAX_CLASS(GLSLShaderStorageBufferType, UniformParameterBlockType)
+SIMPLE_SYNTAX_CLASS(GLSLShaderStorageBufferType, UniformParameterGroupType)
+
+// type for Slang `ParameterBlock<T>` type
+SIMPLE_SYNTAX_CLASS(ParameterBlockType, ParameterGroupType)
SYNTAX_CLASS(ArrayExpressionType, Type)
SYNTAX_FIELD(RefPtr<Type>, baseType)
diff --git a/source/slang/type-layout.cpp b/source/slang/type-layout.cpp
index 822311f60..9f2aee922 100644
--- a/source/slang/type-layout.cpp
+++ b/source/slang/type-layout.cpp
@@ -427,6 +427,7 @@ struct GLSLLayoutRulesFamilyImpl : LayoutRulesFamilyImpl
virtual LayoutRulesImpl* getVaryingOutputRules() override;
virtual LayoutRulesImpl* getSpecializationConstantRules() override;
virtual LayoutRulesImpl* getShaderStorageBufferRules() override;
+ virtual LayoutRulesImpl* getParameterBlockRules() override;
virtual MatrixLayoutMode getDefaultMatrixLayoutMode() override
{
@@ -457,6 +458,7 @@ struct HLSLLayoutRulesFamilyImpl : LayoutRulesFamilyImpl
virtual LayoutRulesImpl* getVaryingOutputRules() override;
virtual LayoutRulesImpl* getSpecializationConstantRules() override;
virtual LayoutRulesImpl* getShaderStorageBufferRules() override;
+ virtual LayoutRulesImpl* getParameterBlockRules() override;
virtual MatrixLayoutMode getDefaultMatrixLayoutMode() override
{
@@ -519,6 +521,12 @@ LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getConstantBufferRules()
return &kStd140LayoutRulesImpl_;
}
+LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getParameterBlockRules()
+{
+ // TODO: actually pick something appropriate
+ return &kStd140LayoutRulesImpl_;
+}
+
LayoutRulesImpl* GLSLLayoutRulesFamilyImpl::getPushConstantBufferRules()
{
return &kGLSLPushConstantLayoutRulesImpl_;
@@ -556,6 +564,13 @@ LayoutRulesImpl* HLSLLayoutRulesFamilyImpl::getConstantBufferRules()
return &kHLSLConstantBufferLayoutRulesImpl_;
}
+LayoutRulesImpl* HLSLLayoutRulesFamilyImpl::getParameterBlockRules()
+{
+ // TODO: actually pick something appropriate...
+ return &kHLSLConstantBufferLayoutRulesImpl_;
+}
+
+
LayoutRulesImpl* HLSLLayoutRulesFamilyImpl::getPushConstantBufferRules()
{
return &kHLSLConstantBufferLayoutRulesImpl_;
@@ -685,8 +700,8 @@ SimpleLayoutInfo GetSimpleLayoutImpl(
return info;
}
-static SimpleLayoutInfo getParameterBlockLayoutInfo(
- RefPtr<ParameterBlockType> type,
+static SimpleLayoutInfo getParameterGroupLayoutInfo(
+ RefPtr<ParameterGroupType> type,
LayoutRulesImpl* rules)
{
if( type->As<ConstantBufferType>() )
@@ -701,14 +716,22 @@ static SimpleLayoutInfo getParameterBlockLayoutInfo(
{
return rules->GetObjectLayout(ShaderParameterKind::ShaderStorageBuffer);
}
+ else if (type->As<ParameterBlockType>())
+ {
+ // TODO(tfoley): Should a parameter block *always* consume at least
+ // one `set`/`space`, or should we hold back and just allocate this
+ // if it actually contains anything?
+ return SimpleLayoutInfo(LayoutResourceKind::ParameterBlock, 1);
+ }
+
// TODO: the vertex-input and fragment-output cases should
// only actually apply when we are at the appropriate stage in
// the pipeline...
- else if( type->As<GLSLInputParameterBlockType>() )
+ else if( type->As<GLSLInputParameterGroupType>() )
{
return SimpleLayoutInfo(LayoutResourceKind::VertexInput, 0);
}
- else if( type->As<GLSLOutputParameterBlockType>() )
+ else if( type->As<GLSLOutputParameterGroupType>() )
{
return SimpleLayoutInfo(LayoutResourceKind::FragmentOutput, 0);
}
@@ -736,19 +759,19 @@ RefPtr<TypeLayout> createTypeLayout(
Type* type,
SimpleLayoutInfo offset);
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
TypeLayoutContext* context,
- RefPtr<ParameterBlockType> parameterBlockType,
- SimpleLayoutInfo parameterBlockInfo,
+ RefPtr<ParameterGroupType> parameterGroupType,
+ SimpleLayoutInfo parameterGroupInfo,
RefPtr<TypeLayout> elementTypeLayout)
{
- auto parameterBlockRules = context->rules;
+ auto parameterGroupRules = context->rules;
- auto typeLayout = new ParameterBlockTypeLayout();
+ auto typeLayout = new ParameterGroupTypeLayout();
- typeLayout->type = parameterBlockType;
- typeLayout->rules = parameterBlockRules;
+ typeLayout->type = parameterGroupType;
+ typeLayout->rules = parameterGroupRules;
typeLayout->elementTypeLayout = elementTypeLayout;
@@ -757,7 +780,7 @@ createParameterBlockTypeLayout(
// originally (which should be a single binding "slot"
// and hence no uniform data).
//
- typeLayout->uniformAlignment = parameterBlockInfo.alignment;
+ typeLayout->uniformAlignment = parameterGroupInfo.alignment;
SLANG_RELEASE_ASSERT(!typeLayout->FindResourceInfo(LayoutResourceKind::Uniform));
SLANG_RELEASE_ASSERT(typeLayout->uniformAlignment == 1);
@@ -771,73 +794,96 @@ createParameterBlockTypeLayout(
// Make sure that we allocate resource usage for the
// parameter block itself.
- if( parameterBlockInfo.size )
+ if( parameterGroupInfo.size )
{
typeLayout->addResourceUsage(
- parameterBlockInfo.kind,
- parameterBlockInfo.size);
+ parameterGroupInfo.kind,
+ parameterGroupInfo.size);
}
- // Now, if the element type itself had any resources, then
- // we need to make these part of the layout for our block
+ // The layout rules for a constant buffer, vs. a "parameter block"
+ // are different, with respect to how they expose layout information
+ // for underlying resources.
//
- // TODO: re-consider this decision, since it creates
- // complications...
- for( auto elementResourceInfo : elementTypeLayout->resourceInfos )
+ // A parameter block should *not* expose the fine-grained resource
+ // prameters it contains, and should only expose a total number
+ // of `space`s or `set`s that it consumes.
+ if (parameterGroupInfo.kind == LayoutResourceKind::ParameterBlock)
{
- // Skip uniform data, since that is encapsualted behind the constant buffer
- if(elementResourceInfo.kind == LayoutResourceKind::Uniform)
- break;
+ // Iterate over element types, but *only* accumulate usage
+ // info for types that consume whole register sets/spaces.
+ for( auto elementResourceInfo : elementTypeLayout->resourceInfos )
+ {
+ if(elementResourceInfo.kind != LayoutResourceKind::ParameterBlock)
+ break;
+
+ typeLayout->addResourceUsage(elementResourceInfo);
+ }
+ }
+ else
+ {
+ // In the ordinary case (e.g., a constant buffer) then we need
+ // to make sure that any resources nested in the element type
+ // get counted against the container type, so that we can
+ // allocate registers to it directly.
+ for( auto elementResourceInfo : elementTypeLayout->resourceInfos )
+ {
+ // Skip uniform data, since that is encapsualted behind the constant buffer
+ if(elementResourceInfo.kind == LayoutResourceKind::Uniform)
+ break;
- typeLayout->addResourceUsage(elementResourceInfo);
+ typeLayout->addResourceUsage(elementResourceInfo);
+ }
}
+
+
return typeLayout;
}
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
- RefPtr<ParameterBlockType> parameterBlockType,
- LayoutRulesImpl* parameterBlockRules,
- SimpleLayoutInfo parameterBlockInfo,
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
+ RefPtr<ParameterGroupType> parameterGroupType,
+ LayoutRulesImpl* parameterGroupRules,
+ SimpleLayoutInfo parameterGroupInfo,
RefPtr<TypeLayout> elementTypeLayout)
{
TypeLayoutContext context;
- context.rules = parameterBlockRules;
- context.matrixLayoutMode = parameterBlockRules->getDefaultMatrixLayoutMode();
+ context.rules = parameterGroupRules;
+ context.matrixLayoutMode = parameterGroupRules->getDefaultMatrixLayoutMode();
- return createParameterBlockTypeLayout(
+ return createParameterGroupTypeLayout(
&context,
- parameterBlockType,
- parameterBlockInfo,
+ parameterGroupType,
+ parameterGroupInfo,
elementTypeLayout);
}
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
TypeLayoutContext* context,
- RefPtr<ParameterBlockType> parameterBlockType,
+ RefPtr<ParameterGroupType> parameterGroupType,
RefPtr<Type> elementType,
LayoutRulesImpl* elementTypeRules)
{
- auto parameterBlockRules = context->rules;
+ auto parameterGroupRules = context->rules;
// First compute resource usage of the block itself.
// For now we assume that the layout of the block can
// always be described in a `SimpleLayoutInfo` (only
// a single resource kind consumed).
SimpleLayoutInfo info;
- if (parameterBlockType)
+ if (parameterGroupType)
{
- info = getParameterBlockLayoutInfo(
- parameterBlockType,
- parameterBlockRules);
+ info = getParameterGroupLayoutInfo(
+ parameterGroupType,
+ parameterGroupRules);
}
else
{
// If there is no concrete type, then it seems like we are
// being asked to compute layout for the global scope
- info = parameterBlockRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer);
+ info = parameterGroupRules->GetObjectLayout(ShaderParameterKind::ConstantBuffer);
}
// Now compute a layout for the elements of the parameter block.
@@ -852,37 +898,41 @@ createParameterBlockTypeLayout(
elementType,
info);
- return createParameterBlockTypeLayout(
+ return createParameterGroupTypeLayout(
context,
- parameterBlockType,
+ parameterGroupType,
info,
elementTypeLayout);
}
LayoutRulesImpl* getParameterBufferElementTypeLayoutRules(
- RefPtr<ParameterBlockType> parameterBlockType,
+ RefPtr<ParameterGroupType> parameterGroupType,
LayoutRulesImpl* rules)
{
- if( parameterBlockType->As<ConstantBufferType>() )
+ if( parameterGroupType->As<ConstantBufferType>() )
{
return rules->getLayoutRulesFamily()->getConstantBufferRules();
}
- else if( parameterBlockType->As<TextureBufferType>() )
+ else if( parameterGroupType->As<TextureBufferType>() )
{
return rules->getLayoutRulesFamily()->getTextureBufferRules();
}
- else if( parameterBlockType->As<GLSLInputParameterBlockType>() )
+ else if( parameterGroupType->As<GLSLInputParameterGroupType>() )
{
return rules->getLayoutRulesFamily()->getVaryingInputRules();
}
- else if( parameterBlockType->As<GLSLOutputParameterBlockType>() )
+ else if( parameterGroupType->As<GLSLOutputParameterGroupType>() )
{
return rules->getLayoutRulesFamily()->getVaryingOutputRules();
}
- else if( parameterBlockType->As<GLSLShaderStorageBufferType>() )
+ else if( parameterGroupType->As<GLSLShaderStorageBufferType>() )
{
return rules->getLayoutRulesFamily()->getShaderStorageBufferRules();
}
+ else if (parameterGroupType->As<ParameterBlockType>())
+ {
+ return rules->getLayoutRulesFamily()->getParameterBlockRules();
+ }
else
{
SLANG_UNEXPECTED("uhandled parameter block type");
@@ -890,23 +940,23 @@ LayoutRulesImpl* getParameterBufferElementTypeLayoutRules(
}
}
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
TypeLayoutContext* context,
- RefPtr<ParameterBlockType> parameterBlockType)
+ RefPtr<ParameterGroupType> parameterGroupType)
{
- auto parameterBlockRules = context->rules;
+ auto parameterGroupRules = context->rules;
// Determine the layout rules to use for the contents of the block
auto elementTypeRules = getParameterBufferElementTypeLayoutRules(
- parameterBlockType,
- parameterBlockRules);
+ parameterGroupType,
+ parameterGroupRules);
- auto elementType = parameterBlockType->elementType;
+ auto elementType = parameterGroupType->elementType;
- return createParameterBlockTypeLayout(
+ return createParameterGroupTypeLayout(
context,
- parameterBlockType,
+ parameterGroupType,
elementType,
elementTypeRules);
}
@@ -1015,14 +1065,14 @@ SimpleLayoutInfo GetLayoutImpl(
{
auto rules = context->rules;
- if (auto parameterBlockType = type->As<ParameterBlockType>())
+ if (auto parameterGroupType = type->As<ParameterGroupType>())
{
// If the user is just interested in uniform layout info,
// then this is easy: a `ConstantBuffer<T>` is really no
// different from a `Texture2D<U>` in terms of how it
// should be handled as a member of a container.
//
- auto info = getParameterBlockLayoutInfo(parameterBlockType, rules);
+ auto info = getParameterGroupLayoutInfo(parameterGroupType, rules);
// The more interesting case, though, is when the user
// is requesting us to actually create a `TypeLayout`,
@@ -1037,9 +1087,9 @@ SimpleLayoutInfo GetLayoutImpl(
//
if (outTypeLayout)
{
- *outTypeLayout = createParameterBlockTypeLayout(
+ *outTypeLayout = createParameterGroupTypeLayout(
context,
- parameterBlockType);
+ parameterGroupType);
}
return info;
diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h
index d078d9554..257bfa310 100644
--- a/source/slang/type-layout.h
+++ b/source/slang/type-layout.h
@@ -296,7 +296,7 @@ public:
};
// type layout for a variable that has a constant-buffer type
-class ParameterBlockTypeLayout : public TypeLayout
+class ParameterGroupTypeLayout : public TypeLayout
{
public:
RefPtr<TypeLayout> elementTypeLayout;
@@ -391,7 +391,7 @@ public:
// We store a layout for the declarations at the global
// scope. Note that this will *either* be a single
// `StructTypeLayout` with the fields stored directly,
- // or it will be a single `ParameterBlockTypeLayout`,
+ // or it will be a single `ParameterGroupTypeLayout`,
// where the global-scope fields are the members of
// that constant buffer.
//
@@ -450,6 +450,8 @@ enum class ShaderParameterKind
Image,
MutableImage,
+
+ RegisterSpace,
};
struct SimpleLayoutRulesImpl
@@ -550,8 +552,10 @@ struct LayoutRulesFamilyImpl
virtual LayoutRulesImpl* getTextureBufferRules() = 0;
virtual LayoutRulesImpl* getVaryingInputRules() = 0;
virtual LayoutRulesImpl* getVaryingOutputRules() = 0;
- virtual LayoutRulesImpl* getSpecializationConstantRules() = 0;
- virtual LayoutRulesImpl* getShaderStorageBufferRules() = 0;
+ virtual LayoutRulesImpl* getSpecializationConstantRules()= 0;
+ virtual LayoutRulesImpl* getShaderStorageBufferRules() = 0;
+ virtual LayoutRulesImpl* getParameterBlockRules() = 0;
+
virtual MatrixLayoutMode getDefaultMatrixLayoutMode() = 0;
};
@@ -571,30 +575,30 @@ RefPtr<TypeLayout> CreateTypeLayout(Type* type, LayoutRulesImpl* rules, SimpleLa
struct TypeLayoutContext;
// Create a type layout for a parameter block type.
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
TypeLayoutContext* context,
- RefPtr<ParameterBlockType> parameterBlockType);
+ RefPtr<ParameterGroupType> parameterGroupType);
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
TypeLayoutContext* context,
- RefPtr<ParameterBlockType> parameterBlockType,
+ RefPtr<ParameterGroupType> parameterGroupType,
RefPtr<Type> elementType,
LayoutRulesImpl* elementTypeRules);
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
TypeLayoutContext* context,
- RefPtr<ParameterBlockType> parameterBlockType,
- SimpleLayoutInfo parameterBlockInfo,
+ RefPtr<ParameterGroupType> parameterGroupType,
+ SimpleLayoutInfo parameterGroupInfo,
RefPtr<TypeLayout> elementTypeLayout);
-RefPtr<ParameterBlockTypeLayout>
-createParameterBlockTypeLayout(
- RefPtr<ParameterBlockType> parameterBlockType,
- LayoutRulesImpl* parameterBlockRules,
- SimpleLayoutInfo parameterBlockInfo,
+RefPtr<ParameterGroupTypeLayout>
+createParameterGroupTypeLayout(
+ RefPtr<ParameterGroupType> parameterGroupType,
+ LayoutRulesImpl* parameterGroupRules,
+ SimpleLayoutInfo parameterGroupInfo,
RefPtr<TypeLayout> elementTypeLayout);
// Create a type layout for a structured buffer type.
diff --git a/tests/bindings/multiple-parameter-blocks.slang b/tests/bindings/multiple-parameter-blocks.slang
new file mode 100644
index 000000000..0fdf7d429
--- /dev/null
+++ b/tests/bindings/multiple-parameter-blocks.slang
@@ -0,0 +1,48 @@
+//TEST:COMPARE_HLSL:-no-mangle -use-ir -target dxbc-assembly -profile ps_5_1 -entry main
+
+// Confirm that Slang `ParameterBlock<T>` generates
+// parameter bindings like we expect.
+
+
+float4 use(float4 val) { return val; };
+float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); }
+
+#ifdef __SLANG__
+
+struct S
+{
+ Texture2D t;
+ Texture2D ta[4];
+ SamplerState s;
+};
+
+ParameterBlock<S> p;
+ParameterBlock<S> p1;
+
+float4 main(float v : V) : SV_Target
+{
+ return use(p.t, p.s)
+ + use(p.ta[int(v)], p.s)
+ + use(p1.t, p1.s)
+ + use(p1.ta[int(v)], p1.s);
+}
+
+#else
+
+Texture2D _S1 : register(t0, space0);
+Texture2D _S2[4] : register(t1, space0);
+SamplerState _S3 : register(s0, space0);
+
+Texture2D _S12 : register(t0, space1);
+Texture2D _S13[4] : register(t1, space1);
+SamplerState _S14 : register(s0, space1);
+
+float4 main(float v : V) : SV_Target
+{
+ return use(_S1, _S3)
+ + use(_S2[int(v)], _S3)
+ + use(_S12, _S14)
+ + use(_S13[int(v)], _S14);
+}
+
+#endif
diff --git a/tests/bindings/parameter-blocks.slang b/tests/bindings/parameter-blocks.slang
new file mode 100644
index 000000000..cd916f144
--- /dev/null
+++ b/tests/bindings/parameter-blocks.slang
@@ -0,0 +1,39 @@
+//TEST:COMPARE_HLSL:-no-mangle -use-ir -target dxbc-assembly -profile ps_5_1 -entry main
+
+// Confirm that Slang `ParameterBlock<T>` generates
+// parameter bindings like we expect.
+
+
+float4 use(float4 val) { return val; };
+float4 use(Texture2D t, SamplerState s) { return t.Sample(s, 0.0); }
+
+#ifdef __SLANG__
+
+struct S
+{
+ Texture2D t;
+ Texture2D ta[4];
+ SamplerState s;
+};
+
+ParameterBlock<S> p;
+
+float4 main(float v : V) : SV_Target
+{
+ return use(p.ta[int(v)], p.s)
+ + use(p.t, p.s);
+}
+
+#else
+
+Texture2D _S1 : register(t0, space0);
+Texture2D _S2[4] : register(t1, space0);
+SamplerState _S3 : register(s0, space0);
+
+float4 main(float v : V) : SV_Target
+{
+ return use(_S2[int(v)], _S3)
+ + use(_S1, _S3);
+}
+
+#endif
diff --git a/tests/bugs/gh-171.slang b/tests/bugs/gh-171.slang
index b37f77ce2..1df82501e 100644
--- a/tests/bugs/gh-171.slang
+++ b/tests/bugs/gh-171.slang
@@ -17,12 +17,12 @@ float4 main(float2 uv: UV) : SV_Target
#else
-Texture2D SLANG_parameterBlock_C_t : register(t0);
-SamplerState SLANG_parameterBlock_C_s : register(s0);
+Texture2D SLANG_parameterGroup_C_t : register(t0);
+SamplerState SLANG_parameterGroup_C_s : register(s0);
float4 main(float2 uv: UV) : SV_Target
{
- return SLANG_parameterBlock_C_t.Sample(SLANG_parameterBlock_C_s, uv);
+ return SLANG_parameterGroup_C_t.Sample(SLANG_parameterGroup_C_s, uv);
}
#endif
diff --git a/tests/bugs/gh-172.slang b/tests/bugs/gh-172.slang
index f898b5f4b..f959c7ac6 100644
--- a/tests/bugs/gh-172.slang
+++ b/tests/bugs/gh-172.slang
@@ -26,14 +26,14 @@ cbuffer C : register(b0)
float2 uv;
};
-Texture2D SLANG_parameterBlock_C_t0 : register(t0);
-Texture2D SLANG_parameterBlock_C_t1 : register(t1);
-SamplerState SLANG_parameterBlock_C_s : register(s0);
+Texture2D SLANG_parameterGroup_C_t0 : register(t0);
+Texture2D SLANG_parameterGroup_C_t1 : register(t1);
+SamplerState SLANG_parameterGroup_C_s : register(s0);
float4 main() : SV_Target
{
- return SLANG_parameterBlock_C_t0.Sample(SLANG_parameterBlock_C_s, uv)
- + SLANG_parameterBlock_C_t1.Sample(SLANG_parameterBlock_C_s, uv);
+ return SLANG_parameterGroup_C_t0.Sample(SLANG_parameterGroup_C_s, uv)
+ + SLANG_parameterGroup_C_t1.Sample(SLANG_parameterGroup_C_s, uv);
}
#endif
diff --git a/tests/rewriter/resources-in-structs.glsl b/tests/rewriter/resources-in-structs.glsl
index 206e4a8d8..8df64f244 100644
--- a/tests/rewriter/resources-in-structs.glsl
+++ b/tests/rewriter/resources-in-structs.glsl
@@ -42,10 +42,10 @@ uniform U
};
layout(binding = 1)
-uniform texture2D SLANG_parameterBlock_U_m_t;
+uniform texture2D SLANG_parameterGroup_U_m_t;
layout(binding = 2)
-uniform sampler SLANG_parameterBlock_U_m_s;
+uniform sampler SLANG_parameterGroup_U_m_s;
layout(location = 0)
in vec2 uv;
@@ -58,8 +58,8 @@ void main()
Material SLANG_tmp_0 = m;
color = evaluateMaterial(
SLANG_tmp_0,
- SLANG_parameterBlock_U_m_t,
- SLANG_parameterBlock_U_m_s, uv);
+ SLANG_parameterGroup_U_m_t,
+ SLANG_parameterGroup_U_m_s, uv);
}
#endif
diff --git a/tests/rewriter/type-splitting.hlsl b/tests/rewriter/type-splitting.hlsl
index c8d69f5fd..b3cad1ce0 100644
--- a/tests/rewriter/type-splitting.hlsl
+++ b/tests/rewriter/type-splitting.hlsl
@@ -47,12 +47,12 @@ cbuffer C
Foo foo;
}
-Texture2D SLANG_parameterBlock_C_foo_t;
-SamplerState SLANG_parameterBlock_C_foo_s;
+Texture2D SLANG_parameterGroup_C_foo_t;
+SamplerState SLANG_parameterGroup_C_foo_s;
float4 main() : SV_Target
{
- return SLANG_parameterBlock_C_foo_t.Sample(SLANG_parameterBlock_C_foo_s, foo.u);
+ return SLANG_parameterGroup_C_foo_t.Sample(SLANG_parameterGroup_C_foo_s, foo.u);
}
#endif