summaryrefslogtreecommitdiffstats
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp401
1 files changed, 113 insertions, 288 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index fb9968232..ba1b2177a 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -2383,7 +2383,6 @@ struct EmitVisitor
case kIROp_FieldAddress:
case kIROp_getElementPtr:
case kIROp_Specialize:
- case kIROp_BufferElementRef:
return true;
}
@@ -2536,25 +2535,6 @@ struct EmitVisitor
return true;
}
- bool isDerefBaseImplicit(
- EmitContext* /*context*/,
- IRInst* inst)
- {
- auto type = inst->getDataType();
-
- if(as<IRUniformParameterGroupType>(type) && !as<IRParameterBlockType>(type))
- {
- // TODO: we need to be careful here, because
- // HLSL shader model 6 allows these as explicit
- // types.
- return true;
- }
-
- return false;
- }
-
-
-
void emitIROperand(
EmitContext* ctx,
IRInst* inst,
@@ -3645,13 +3625,16 @@ struct EmitVisitor
IRFieldExtract* fieldExtract = (IRFieldExtract*) inst;
- if (!isDerefBaseImplicit(ctx, fieldExtract->getBase()))
- {
- auto prec = kEOp_Postfix;
- needClose = maybeEmitParens(outerPrec, prec);
+ auto prec = kEOp_Postfix;
+ needClose = maybeEmitParens(outerPrec, prec);
- emitIROperand(ctx, fieldExtract->getBase(), mode, leftSide(outerPrec, prec));
- emit(".");
+ auto base = fieldExtract->getBase();
+ emitIROperand(ctx, base, mode, leftSide(outerPrec, prec));
+ emit(".");
+ if(getTarget(ctx) == CodeGenTarget::GLSL
+ && as<IRUniformParameterGroupType>(base->getDataType()))
+ {
+ emit("_data.");
}
emit(getIRName(fieldExtract->getField()));
}
@@ -3663,15 +3646,17 @@ struct EmitVisitor
IRFieldAddress* ii = (IRFieldAddress*) inst;
- if (!isDerefBaseImplicit(ctx, ii->getBase()))
- {
- auto prec = kEOp_Postfix;
- needClose = maybeEmitParens(outerPrec, prec);
+ auto prec = kEOp_Postfix;
+ needClose = maybeEmitParens(outerPrec, prec);
- emitIROperand(ctx, ii->getBase(), mode, leftSide(outerPrec, prec));
- emit(".");
+ auto base = ii->getBase();
+ emitIROperand(ctx, base, mode, leftSide(outerPrec, prec));
+ emit(".");
+ if(getTarget(ctx) == CodeGenTarget::GLSL
+ && as<IRUniformParameterGroupType>(base->getDataType()))
+ {
+ emit("_data.");
}
-
emit(getIRName(ii->getField()));
}
break;
@@ -3774,7 +3759,15 @@ struct EmitVisitor
break;
case kIROp_Load:
- emitIROperand(ctx, inst->getOperand(0), mode, outerPrec);
+ {
+ auto base = inst->getOperand(0);
+ emitIROperand(ctx, base, mode, outerPrec);
+ if(getTarget(ctx) == CodeGenTarget::GLSL
+ && as<IRUniformParameterGroupType>(base->getDataType()))
+ {
+ emit("._data");
+ }
+ }
break;
case kIROp_Store:
@@ -3794,39 +3787,6 @@ struct EmitVisitor
}
break;
- case kIROp_BufferLoad:
- case kIROp_BufferElementRef:
- {
- auto prec = kEOp_Postfix;
- needClose = maybeEmitParens(outerPrec, prec);
-
- emitIROperand(ctx, inst->getOperand(0), mode, leftSide(outerPrec, prec));
- emit("[");
- emitIROperand(ctx, inst->getOperand(1), mode, kEOp_General);
- emit("]");
- }
- break;
-
- case kIROp_BufferStore:
- {
- auto precAssign = kEOp_Assign;
- needClose = maybeEmitParens(outerPrec, precAssign);
-
- auto outerPrecSubscript = precAssign;
- auto precSubscript = kEOp_Postfix;
- bool needCloseSubscript = maybeEmitParens(outerPrecSubscript, precSubscript);
-
- emitIROperand(ctx, inst->getOperand(0), mode, leftSide(outerPrecSubscript, precSubscript));
- emit("[");
- emitIROperand(ctx, inst->getOperand(1), mode, kEOp_General);
- emit("]");
- maybeCloseParens(needCloseSubscript);
-
- emit(" = ");
- emitIROperand(ctx, inst->getOperand(2), mode, rightSide(outerPrec, precAssign));
- }
- break;
-
case kIROp_GroupMemoryBarrierWithGroupSync:
emit("GroupMemoryBarrierWithGroupSync()");
break;
@@ -5618,63 +5578,19 @@ struct EmitVisitor
}
}
- void emitHLSLParameterBlock(
- EmitContext* ctx,
- IRGlobalVar* varDecl,
- IRParameterBlockType* type)
- {
- emit("cbuffer ");
-
- // Generate a dummy name for the block
- emit("_S");
- Emit(ctx->shared->uniqueIDCounter++);
-
- auto varLayout = getVarLayout(ctx, varDecl);
- SLANG_RELEASE_ASSERT(varLayout);
-
- EmitVarChain blockChain(varLayout);
-
- EmitVarChain containerChain = blockChain;
- EmitVarChain elementChain = blockChain;
-
- auto typeLayout = varLayout->typeLayout;
- if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() )
- {
- containerChain = EmitVarChain(parameterGroupTypeLayout->containerVarLayout, &blockChain);
- elementChain = EmitVarChain(parameterGroupTypeLayout->elementVarLayout, &blockChain);
-
- typeLayout = parameterGroupTypeLayout->elementVarLayout->getTypeLayout();
- }
-
- emitHLSLRegisterSemantic(LayoutResourceKind::ConstantBuffer, &containerChain);
-
- emit("\n{\n");
- indent();
-
- auto elementType = type->getElementType();
-
-
- emitIRType(ctx, elementType, getIRName(varDecl));
-
- emitHLSLParameterGroupFieldLayoutSemantics(&elementChain);
- emit(";\n");
-
- dedent();
- emit("}\n");
- }
-
void emitHLSLParameterGroup(
EmitContext* ctx,
IRGlobalVar* varDecl,
IRUniformParameterGroupType* type)
{
- if(auto parameterBlockType = as<IRParameterBlockType>(type))
+ if(as<IRTextureBufferType>(type))
{
- emitHLSLParameterBlock(ctx, varDecl, parameterBlockType);
- return;
+ emit("tbuffer ");
+ }
+ else
+ {
+ emit("cbuffer ");
}
-
- emit("cbuffer ");
emit(getIRName(varDecl));
auto varLayout = getVarLayout(ctx, varDecl);
@@ -5701,111 +5617,37 @@ struct EmitVisitor
auto elementType = type->getElementType();
- if(auto structType = as<IRStructType>(elementType))
- {
- auto structTypeLayout = typeLayout.As<StructTypeLayout>();
- SLANG_RELEASE_ASSERT(structTypeLayout);
-
- UInt fieldIndex = 0;
- for(auto ff : structType->getFields())
- {
- // TODO: need a plan to deal with the case where the IR-level
- // `struct` type might not match the high-level type, so that
- // the numbering of fields is different.
- //
- // The right plan is probably to require that the lowering pass
- // create a fresh layout for any type/variable that it splits
- // in this fashion, so that the layout information it attaches
- // can always be assumed to apply to the actual instruciton.
- //
-
- auto fieldLayout = structTypeLayout->fields[fieldIndex++];
-
- auto fieldKey = ff->getKey();
- auto fieldType = ff->getFieldType();
-
- // Fields of `void` type aren't valid in HLSL/GLSL.
- //
- // TODO: legalization should get rid of any fields that have
- // empty, or effectively empty types (e.g., emptry structs
- // should be translated over to `void`).
- if(as<IRVoidType>(fieldType))
- continue;
-
- emitIRVarModifiers(ctx, fieldLayout, fieldKey, fieldType);
-
- emitIRType(ctx, fieldType, getIRName(fieldKey));
-
- emitHLSLParameterGroupFieldLayoutSemantics(fieldLayout, &elementChain);
-
- emit(";\n");
- }
- }
- else
- {
- // TODO: during legalization we should turn `ParameterGroup<X>` where `X`
- // is not a `struct` type into `ParameterGroup<S>` where `S` is defined
- // as something like `struct S { X _; };`
- //
- emit("/* unexpected */");
- }
+ emitIRType(ctx, elementType, getIRName(varDecl));
+ emit(";\n");
dedent();
emit("}\n");
}
- void emitGLSLParameterBlock(
- EmitContext* ctx,
- IRGlobalVar* varDecl,
- IRParameterBlockType* type)
+ void emitArrayBrackets(
+ EmitContext* ctx,
+ IRType* type)
{
- auto varLayout = getVarLayout(ctx, varDecl);
- SLANG_RELEASE_ASSERT(varLayout);
-
- EmitVarChain blockChain(varLayout);
-
- EmitVarChain containerChain = blockChain;
- EmitVarChain elementChain = blockChain;
+ SLANG_UNUSED(ctx);
- auto typeLayout = varLayout->typeLayout;
- if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() )
+ if(auto arrayType = as<IRArrayType>(type))
{
- containerChain = EmitVarChain(parameterGroupTypeLayout->containerVarLayout, &blockChain);
- elementChain = EmitVarChain(parameterGroupTypeLayout->elementVarLayout, &blockChain);
-
- typeLayout = parameterGroupTypeLayout->elementVarLayout->getTypeLayout();
+ emit("[");
+ EmitVal(arrayType->getElementCount(), kEOp_General);
+ emit("]");
+ }
+ else if(auto unsizedArrayType = as<IRUnsizedArrayType>(type))
+ {
+ emit("[]");
}
-
- emitGLSLLayoutQualifier(LayoutResourceKind::DescriptorTableSlot, &containerChain);
- emit("layout(std140) uniform ");
-
- // Generate a dummy name for the block
- emit("_S");
- Emit(ctx->shared->uniqueIDCounter++);
-
- emit("\n{\n");
- indent();
-
- auto elementType = type->getElementType();
-
- emitIRType(ctx, elementType, getIRName(varDecl));
- emit(";\n");
-
- dedent();
- emit("};\n");
}
+
void emitGLSLParameterGroup(
EmitContext* ctx,
IRGlobalVar* varDecl,
IRUniformParameterGroupType* type)
{
- if(auto parameterBlockType = as<IRParameterBlockType>(type))
- {
- emitGLSLParameterBlock(ctx, varDecl, parameterBlockType);
- return;
- }
-
auto varLayout = getVarLayout(ctx, varDecl);
SLANG_RELEASE_ASSERT(varLayout);
@@ -5814,7 +5656,7 @@ struct EmitVisitor
EmitVarChain containerChain = blockChain;
EmitVarChain elementChain = blockChain;
- auto typeLayout = varLayout->typeLayout;
+ auto typeLayout = varLayout->typeLayout->unwrapArray();
if( auto parameterGroupTypeLayout = typeLayout.As<ParameterGroupTypeLayout>() )
{
containerChain = EmitVarChain(parameterGroupTypeLayout->containerVarLayout, &blockChain);
@@ -5841,71 +5683,28 @@ struct EmitVisitor
emit("layout(std140) uniform ");
}
- emit(getIRName(varDecl));
+ // Generate a dummy name for the block
+ emit("_S");
+ Emit(ctx->shared->uniqueIDCounter++);
emit("\n{\n");
indent();
auto elementType = type->getElementType();
- if(auto structType = as<IRStructType>(elementType))
- {
- auto structTypeLayout = typeLayout.As<StructTypeLayout>();
- SLANG_RELEASE_ASSERT(structTypeLayout);
-
- UInt fieldIndex = 0;
- for(auto ff : structType->getFields())
- {
- // TODO: need a plan to deal with the case where the IR-level
- // `struct` type might not match the high-level type, so that
- // the numbering of fields is different.
- //
- // The right plan is probably to require that the lowering pass
- // create a fresh layout for any type/variable that it splits
- // in this fashion, so that the layout information it attaches
- // can always be assumed to apply to the actual instruciton.
- //
-
- auto fieldLayout = structTypeLayout->fields[fieldIndex++];
-
- auto fieldKey = ff->getKey();
- auto fieldType = ff->getFieldType();
- if(as<IRVoidType>(fieldType))
- continue;
-
- // Note: we will emit matrix-layout modifiers here, but
- // we will refrain from emitting other modifiers that
- // might not be appropriate to the context (e.g., we
- // shouldn't go emitting `uniform` just because these
- // things are uniform...).
- //
- // TODO: we need a more refined set of modifiers that
- // we should allow on fields, because we might end
- // up supporting layout that isn't the default for
- // the given block type (e.g., something other than
- // `std140` for a uniform block).
- //
- emitIRMatrixLayoutModifiers(ctx, fieldLayout);
-
- emitIRType(ctx, fieldType, getIRName(fieldKey));
+ emitIRType(ctx, elementType, "_data");
+ emit(";\n");
-// emitHLSLParameterGroupFieldLayoutSemantics(layout, fieldLayout);
+ dedent();
+ emit("} ");
- emit(";\n");
- }
- }
- else
- {
- emit("/* unexpected */");
- }
+ emit(getIRName(varDecl));
- // TODO: we should consider always giving parameter blocks
- // names when outputting GLSL, since that shouldn't affect
- // the semantics of things, and will reduce the risk of
- // collisions in the global namespace...
+ // If the underlying variable was an array (or array of arrays, etc.)
+ // we need to emit all those array brackets here.
+ emitArrayBrackets(ctx, varDecl->getDataType()->getValueType());
- dedent();
- emit("};\n");
+ emit(";\n");
}
void emitIRParameterGroup(
@@ -6025,19 +5824,14 @@ struct EmitVisitor
auto elementType = structuredBufferType->getElementType();
- emitIRType(ctx, elementType, getIRName(varDecl) + "[]");
+ emitIRType(ctx, elementType, "_data[]");
emit(";\n");
dedent();
- emit("}");
+ emit("} ");
- // TODO: we need to consider the case where the type of the variable is
- // an *array* of structured buffers, in which case we need to declare
- // the block as an array too.
- //
- // The main challenge here is that then the block will have a name,
- // and also the field inside the block will have a name, so that when
- // the user had written `a[i][j]` we now need to emit `a[i].someName[j]`.
+ emit(getIRName(varDecl));
+ emitArrayBrackets(ctx, varDecl->getDataType()->getValueType());
emit(";\n");
}
@@ -6084,20 +5878,13 @@ struct EmitVisitor
emit("\n{\n");
indent();
- emit("uint ");
- emit(getIRName(varDecl));
- emit("[];\n");
+ emit("uint _data[];\n");
dedent();
- emit("}");
+ emit("} ");
- // TODO: we need to consider the case where the type of the variable is
- // an *array* of structured buffers, in which case we need to declare
- // the block as an array too.
- //
- // The main challenge here is that then the block will have a name,
- // and also the field inside the block will have a name, so that when
- // the user had written `a[i][j]` we now need to emit `a[i].someName[j]`.
+ emit(getIRName(varDecl));
+ emitArrayBrackets(ctx, varDecl->getDataType()->getValueType());
emit(";\n");
}
@@ -6129,6 +5916,16 @@ struct EmitVisitor
Emit("}\n");
}
+ // When a global shader parameter represents a "parameter group"
+ // (either a constant buffer or a parameter block with non-resource
+ // data in it), we will prefer to emit it as an ordinary `cbuffer`
+ // declaration or `uniform` block, even when emitting HLSL for
+ // D3D profiles that support the explicit `ConstantBuffer<T>` type.
+ //
+ // Alternatively, we could make this choice based on profile, and
+ // prefer `ConstantBuffer<T>` on profiles that support it and/or when
+ // the input code used that syntax.
+ //
if (auto paramBlockType = as<IRUniformParameterGroupType>(varType))
{
emitIRParameterGroup(
@@ -6140,8 +5937,31 @@ struct EmitVisitor
if(getTarget(ctx) == CodeGenTarget::GLSL)
{
- // When outputting GLSL, we need to transform any declaration of
- // a `*StructuredBuffer<T>` into an ordinary `buffer` declaration.
+ // There are a number of types that are (or can be)
+ // "first-class" in D3D HLSL, but are second-class in GLSL in
+ // that they require explicit global declarations for each value/object,
+ // and don't support declaration as ordinary variables.
+ //
+ // This includes constant buffers (`uniform` blocks) and well as
+ // structured and byte-address buffers (both mapping to `buffer` blocks).
+ //
+ // We intercept these types, and arrays thereof, to produce the required
+ // global declarations. This assumes that earlier "legalization" passes
+ // already performed the work of pulling fields with these types out of
+ // aggregates.
+ //
+ // Note: this also assumes that these types are not used as function
+ // parameters/results, local variables, etc. Additional legalization
+ // steps are required to guarantee these conditions.
+ //
+ if (auto paramBlockType = as<IRUniformParameterGroupType>(unwrapArray(varType)))
+ {
+ emitGLSLParameterGroup(
+ ctx,
+ varDecl,
+ paramBlockType);
+ return;
+ }
if( auto structuredBufferType = as<IRHLSLStructuredBufferTypeBase>(unwrapArray(varType)) )
{
emitIRStructuredBuffer_GLSL(
@@ -6150,9 +5970,6 @@ struct EmitVisitor
structuredBufferType);
return;
}
-
- // When outputting GLSL, we need to transform any declaration of
- // a `*ByteAddressBuffer<T>` into an ordinary `buffer` declaration.
if( auto byteAddressBufferType = as<IRByteAddressBufferTypeBase>(unwrapArray(varType)) )
{
emitIRByteAddressBuffer_GLSL(
@@ -6166,7 +5983,15 @@ struct EmitVisitor
// when outputting GLSL (well, except in the case where they
// actually *require* redeclaration...).
//
- // TODO: can we detect this more robustly?
+ // Note: these won't be variables the user declare explicitly
+ // in their code, but rather variables that we generated as
+ // part of legalizing the varying input/output signature of
+ // an entry point for GL/Vulkan.
+ //
+ // TODO: This could be handled more robustly by attaching an
+ // appropriate decoration to these variables to indicate their
+ // purpose.
+ //
if(getText(varDecl->mangledName).StartsWith("gl_"))
{
// The variable represents an OpenGL system value,