diff options
29 files changed, 1828 insertions, 200 deletions
@@ -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 |
