summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.cpp11
-rw-r--r--source/slang/emit.cpp401
-rw-r--r--source/slang/hlsl.meta.slang72
-rw-r--r--source/slang/hlsl.meta.slang.h72
-rw-r--r--source/slang/ir-inst-defs.h4
-rw-r--r--source/slang/ir.cpp1
-rw-r--r--source/slang/type-layout.cpp11
-rw-r--r--source/slang/type-layout.h7
-rw-r--r--source/slang/vm.cpp66
9 files changed, 212 insertions, 433 deletions
diff --git a/source/slang/check.cpp b/source/slang/check.cpp
index e07bdf156..21e3b894b 100644
--- a/source/slang/check.cpp
+++ b/source/slang/check.cpp
@@ -7922,16 +7922,15 @@ namespace Slang
RefPtr<Expr> expr = inExpr;
for (;;)
{
- auto& type = expr->type;
- if (auto pointerLikeType = type->As<PointerLikeType>())
+ auto baseType = expr->type;
+ if (auto pointerLikeType = baseType->As<PointerLikeType>())
{
- type = QualType(pointerLikeType->elementType);
+ auto elementType = QualType(pointerLikeType->elementType);
+ elementType.IsLeftValue = baseType.IsLeftValue;
auto derefExpr = new DerefExpr();
derefExpr->base = expr;
- derefExpr->type = QualType(pointerLikeType->elementType);
-
- // TODO(tfoley): deal with l-value-ness here
+ derefExpr->type = elementType;
expr = derefExpr;
continue;
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,
diff --git a/source/slang/hlsl.meta.slang b/source/slang/hlsl.meta.slang
index 950931fc2..98b50e574 100644
--- a/source/slang/hlsl.meta.slang
+++ b/source/slang/hlsl.meta.slang
@@ -18,26 +18,26 @@ __magic_type(HLSLByteAddressBufferType)
__intrinsic_type($(kIROp_HLSLByteAddressBufferType))
struct ByteAddressBuffer
{
- __target_intrinsic(glsl, "$1 = $0.length()")
+ __target_intrinsic(glsl, "$1 = $0._data.length()")
void GetDimensions(
out uint dim);
- __target_intrinsic(glsl, "$0[$1]")
+ __target_intrinsic(glsl, "$0._data[$1]")
uint Load(int location);
uint Load(int location, out uint status);
- __target_intrinsic(glsl, "uvec2($0[$1], $0[$1+1])")
+ __target_intrinsic(glsl, "uvec2($0._data[$1], $0._data[$1+1])")
uint2 Load2(int location);
uint2 Load2(int location, out uint status);
- __target_intrinsic(glsl, "uvec3($0[$1], $0[$1+1], $0[$1+2])")
+ __target_intrinsic(glsl, "uvec3($0._data[$1], $0._data[$1+1], $0._data[$1+2])")
uint3 Load3(int location);
uint3 Load3(int location, out uint status);
- __target_intrinsic(glsl, "uvec4($0[$1], $0[$1+1], $0[$1+2], $0[$1+3])")
+ __target_intrinsic(glsl, "uvec4($0._data[$1], $0._data[$1+1], $0._data[$1+2], $0._data[$1+3])")
uint4 Load4(int location);
uint4 Load4(int location, out uint status);
@@ -55,7 +55,11 @@ struct StructuredBuffer
T Load(int location);
T Load(int location, out uint status);
- __subscript(uint index) -> T { __intrinsic_op(bufferLoad) get; };
+ __subscript(uint index) -> T
+ {
+ __target_intrinsic(glsl, "$0._data[$1]")
+ get;
+ };
};
__generic<T>
@@ -105,133 +109,133 @@ struct $(item.name)
// Note(tfoley): supports all operations from `ByteAddressBuffer`
// TODO(tfoley): can this be made a sub-type?
- __target_intrinsic(glsl, "$1 = $0.length()")
+ __target_intrinsic(glsl, "$1 = $0._data.length()")
void GetDimensions(
out uint dim);
- __target_intrinsic(glsl, "$0[$1]")
+ __target_intrinsic(glsl, "$0._data[$1]")
uint Load(int location);
uint Load(int location, out uint status);
- __target_intrinsic(glsl, "uvec2($0[$1], $0[$1+4])")
+ __target_intrinsic(glsl, "uvec2($0._data[$1], $0._data[$1+4])")
uint2 Load2(int location);
uint2 Load2(int location, out uint status);
- __target_intrinsic(glsl, "uvec3($0[$1], $0[$1+4], $0[$1+8])")
+ __target_intrinsic(glsl, "uvec3($0._data[$1], $0._data[$1+4], $0._data[$1+8])")
uint3 Load3(int location);
uint3 Load3(int location, out uint status);
- __target_intrinsic(glsl, "uvec4($0[$1], $0[$1+4], $0[$1+8], $0[$1+12])")
+ __target_intrinsic(glsl, "uvec4($0._data[$1], $0._data[$1+4], $0._data[$1+8], $0._data[$1+12])")
uint4 Load4(int location);
uint4 Load4(int location, out uint status);
// Added operations:
- __target_intrinsic(glsl, "($3 = atomicAdd($0[$1], $2))")
+ __target_intrinsic(glsl, "($3 = atomicAdd($0._data[$1], $2))")
void InterlockedAdd(
UINT dest,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "atomicAdd($0[$1], $2)")
+ __target_intrinsic(glsl, "atomicAdd($0._data[$1], $2)")
void InterlockedAdd(
UINT dest,
UINT value);
- __target_intrinsic(glsl, "($3 = atomicAnd($0[$1], $2))")
+ __target_intrinsic(glsl, "($3 = atomicAnd($0._data[$1], $2))")
void InterlockedAnd(
UINT dest,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "atomicAnd($0[$1], $2)")
+ __target_intrinsic(glsl, "atomicAnd($0._data[$1], $2)")
void InterlockedAnd(
UINT dest,
UINT value);
- __target_intrinsic(glsl, "($4 = atomicCompSwap($0[$1], $2, $3))")
+ __target_intrinsic(glsl, "($4 = atomicCompSwap($0._data[$1], $2, $3))")
void InterlockedCompareExchange(
UINT dest,
UINT compare_value,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "atomicCompSwap($0[$1], $2, $3)")
+ __target_intrinsic(glsl, "atomicCompSwap($0._data[$1], $2, $3)")
void InterlockedCompareStore(
UINT dest,
UINT compare_value,
UINT value);
- __target_intrinsic(glsl, "($3 = atomicExchange($0[$1], $2))")
+ __target_intrinsic(glsl, "($3 = atomicExchange($0._data[$1], $2))")
void InterlockedExchange(
UINT dest,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "($3 = atomicMax($0[$1], $2))")
+ __target_intrinsic(glsl, "($3 = atomicMax($0._data[$1], $2))")
void InterlockedMax(
UINT dest,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "atomicMax($0[$1], $2)")
+ __target_intrinsic(glsl, "atomicMax($0._data[$1], $2)")
void InterlockedMax(
UINT dest,
UINT value);
- __target_intrinsic(glsl, "($3 = atomicMin($0[$1], $2))")
+ __target_intrinsic(glsl, "($3 = atomicMin($0._data[$1], $2))")
void InterlockedMin(
UINT dest,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "atomicMin($0[$1], $2)")
+ __target_intrinsic(glsl, "atomicMin($0._data[$1], $2)")
void InterlockedMin(
UINT dest,
UINT value);
- __target_intrinsic(glsl, "($3 = atomicOr($0[$1], $2))")
+ __target_intrinsic(glsl, "($3 = atomicOr($0._data[$1], $2))")
void InterlockedOr(
UINT dest,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "atomicOr($0[$1], $2)")
+ __target_intrinsic(glsl, "atomicOr($0._data[$1], $2)")
void InterlockedOr(
UINT dest,
UINT value);
- __target_intrinsic(glsl, "($3 = atomicXor($0[$1], $2))")
+ __target_intrinsic(glsl, "($3 = atomicXor($0._data[$1], $2))")
void InterlockedXor(
UINT dest,
UINT value,
out UINT original_value);
- __target_intrinsic(glsl, "atomicXor($0[$1], $2)")
+ __target_intrinsic(glsl, "atomicXor($0._data[$1], $2)")
void InterlockedXor(
UINT dest,
UINT value);
- __target_intrinsic(glsl, "$0[$1] = $2")
+ __target_intrinsic(glsl, "$0._data[$1] = $2")
void Store(
uint address,
uint value);
- __target_intrinsic(glsl, "$0[$1] = $2.x, $0[$1+4] = $2.y")
+ __target_intrinsic(glsl, "$0._data[$1] = $2.x, $0._data[$1+4] = $2.y")
void Store2(
uint address,
uint2 value);
- __target_intrinsic(glsl, "$0[$1] = $2.x, $0[$1+4] = $2.y, $0[$1+8] = $2.z")
+ __target_intrinsic(glsl, "$0._data[$1] = $2.x, $0._data[$1+4] = $2.y, $0._data[$1+8] = $2.z")
void Store3(
uint address,
uint3 value);
- __target_intrinsic(glsl, "$0[$1] = $2.x, $0[$1+4] = $2.y, $0[$1+8] = $2.z, $0[$1+12] = $2.w")
+ __target_intrinsic(glsl, "$0._data[$1] = $2.x, $0._data[$1+4] = $2.y, $0._data[$1+8] = $2.z, $0._data[$1+12] = $2.w")
void Store4(
uint address,
uint4 value);
@@ -270,11 +274,11 @@ struct $(item.name)
T Load(int location);
T Load(int location, out uint status);
- __subscript(uint index) -> T
- {
- __intrinsic_op(bufferElementRef)
+ __subscript(uint index) -> T
+ {
+ __target_intrinsic(glsl, "$0._data[$1]")
ref;
- }
+ }
};
${{{{
diff --git a/source/slang/hlsl.meta.slang.h b/source/slang/hlsl.meta.slang.h
index 8d908c13d..ea21a0fde 100644
--- a/source/slang/hlsl.meta.slang.h
+++ b/source/slang/hlsl.meta.slang.h
@@ -24,26 +24,26 @@ SLANG_SPLICE(kIROp_HLSLByteAddressBufferType
SLANG_RAW(")\n")
SLANG_RAW("struct ByteAddressBuffer\n")
SLANG_RAW("{\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$1 = $0.length()\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$1 = $0._data.length()\")\n")
SLANG_RAW(" void GetDimensions(\n")
SLANG_RAW(" out uint dim);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$0[$1]\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1]\")\n")
SLANG_RAW(" uint Load(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint Load(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"uvec2($0[$1], $0[$1+1])\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"uvec2($0._data[$1], $0._data[$1+1])\")\n")
SLANG_RAW(" uint2 Load2(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint2 Load2(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"uvec3($0[$1], $0[$1+1], $0[$1+2])\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"uvec3($0._data[$1], $0._data[$1+1], $0._data[$1+2])\")\n")
SLANG_RAW(" uint3 Load3(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint3 Load3(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"uvec4($0[$1], $0[$1+1], $0[$1+2], $0[$1+3])\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"uvec4($0._data[$1], $0._data[$1+1], $0._data[$1+2], $0._data[$1+3])\")\n")
SLANG_RAW(" uint4 Load4(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint4 Load4(int location, out uint status);\n")
@@ -64,7 +64,11 @@ SLANG_RAW("\n")
SLANG_RAW(" T Load(int location);\n")
SLANG_RAW(" T Load(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __subscript(uint index) -> T { __intrinsic_op(bufferLoad) get; };\n")
+SLANG_RAW(" __subscript(uint index) -> T\n")
+SLANG_RAW(" {\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1]\")\n")
+SLANG_RAW(" get;\n")
+SLANG_RAW(" };\n")
SLANG_RAW("};\n")
SLANG_RAW("\n")
SLANG_RAW("__generic<T>\n")
@@ -132,133 +136,133 @@ SLANG_RAW("{\n")
SLANG_RAW(" // Note(tfoley): supports all operations from `ByteAddressBuffer`\n")
SLANG_RAW(" // TODO(tfoley): can this be made a sub-type?\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$1 = $0.length()\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$1 = $0._data.length()\")\n")
SLANG_RAW(" void GetDimensions(\n")
SLANG_RAW(" out uint dim);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$0[$1]\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1]\")\n")
SLANG_RAW(" uint Load(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint Load(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"uvec2($0[$1], $0[$1+4])\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"uvec2($0._data[$1], $0._data[$1+4])\")\n")
SLANG_RAW(" uint2 Load2(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint2 Load2(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"uvec3($0[$1], $0[$1+4], $0[$1+8])\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"uvec3($0._data[$1], $0._data[$1+4], $0._data[$1+8])\")\n")
SLANG_RAW(" uint3 Load3(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint3 Load3(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"uvec4($0[$1], $0[$1+4], $0[$1+8], $0[$1+12])\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"uvec4($0._data[$1], $0._data[$1+4], $0._data[$1+8], $0._data[$1+12])\")\n")
SLANG_RAW(" uint4 Load4(int location);\n")
SLANG_RAW("\n")
SLANG_RAW(" uint4 Load4(int location, out uint status);\n")
SLANG_RAW("\n")
SLANG_RAW(" // Added operations:\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicAdd($0[$1], $2))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicAdd($0._data[$1], $2))\")\n")
SLANG_RAW(" void InterlockedAdd(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"atomicAdd($0[$1], $2)\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"atomicAdd($0._data[$1], $2)\")\n")
SLANG_RAW(" void InterlockedAdd(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicAnd($0[$1], $2))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicAnd($0._data[$1], $2))\")\n")
SLANG_RAW(" void InterlockedAnd(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"atomicAnd($0[$1], $2)\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"atomicAnd($0._data[$1], $2)\")\n")
SLANG_RAW(" void InterlockedAnd(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($4 = atomicCompSwap($0[$1], $2, $3))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($4 = atomicCompSwap($0._data[$1], $2, $3))\")\n")
SLANG_RAW(" void InterlockedCompareExchange(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT compare_value,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"atomicCompSwap($0[$1], $2, $3)\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"atomicCompSwap($0._data[$1], $2, $3)\")\n")
SLANG_RAW(" void InterlockedCompareStore(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT compare_value,\n")
SLANG_RAW(" UINT value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicExchange($0[$1], $2))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicExchange($0._data[$1], $2))\")\n")
SLANG_RAW(" void InterlockedExchange(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicMax($0[$1], $2))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicMax($0._data[$1], $2))\")\n")
SLANG_RAW(" void InterlockedMax(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"atomicMax($0[$1], $2)\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"atomicMax($0._data[$1], $2)\")\n")
SLANG_RAW(" void InterlockedMax(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicMin($0[$1], $2))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicMin($0._data[$1], $2))\")\n")
SLANG_RAW(" void InterlockedMin(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"atomicMin($0[$1], $2)\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"atomicMin($0._data[$1], $2)\")\n")
SLANG_RAW(" void InterlockedMin(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicOr($0[$1], $2))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicOr($0._data[$1], $2))\")\n")
SLANG_RAW(" void InterlockedOr(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"atomicOr($0[$1], $2)\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"atomicOr($0._data[$1], $2)\")\n")
SLANG_RAW(" void InterlockedOr(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicXor($0[$1], $2))\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"($3 = atomicXor($0._data[$1], $2))\")\n")
SLANG_RAW(" void InterlockedXor(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value,\n")
SLANG_RAW(" out UINT original_value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"atomicXor($0[$1], $2)\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"atomicXor($0._data[$1], $2)\")\n")
SLANG_RAW(" void InterlockedXor(\n")
SLANG_RAW(" UINT dest,\n")
SLANG_RAW(" UINT value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$0[$1] = $2\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1] = $2\")\n")
SLANG_RAW(" void Store(\n")
SLANG_RAW(" uint address,\n")
SLANG_RAW(" uint value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$0[$1] = $2.x, $0[$1+4] = $2.y\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1] = $2.x, $0._data[$1+4] = $2.y\")\n")
SLANG_RAW(" void Store2(\n")
SLANG_RAW(" uint address,\n")
SLANG_RAW(" uint2 value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$0[$1] = $2.x, $0[$1+4] = $2.y, $0[$1+8] = $2.z\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1] = $2.x, $0._data[$1+4] = $2.y, $0._data[$1+8] = $2.z\")\n")
SLANG_RAW(" void Store3(\n")
SLANG_RAW(" uint address,\n")
SLANG_RAW(" uint3 value);\n")
SLANG_RAW("\n")
-SLANG_RAW(" __target_intrinsic(glsl, \"$0[$1] = $2.x, $0[$1+4] = $2.y, $0[$1+8] = $2.z, $0[$1+12] = $2.w\")\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1] = $2.x, $0._data[$1+4] = $2.y, $0._data[$1+8] = $2.z, $0._data[$1+12] = $2.w\")\n")
SLANG_RAW(" void Store4(\n")
SLANG_RAW(" uint address,\n")
SLANG_RAW(" uint4 value);\n")
@@ -306,11 +310,11 @@ SLANG_RAW("\n")
SLANG_RAW(" T Load(int location);\n")
SLANG_RAW(" T Load(int location, out uint status);\n")
SLANG_RAW("\n")
-SLANG_RAW("\t__subscript(uint index) -> T\n")
-SLANG_RAW("\t{\n")
-SLANG_RAW(" __intrinsic_op(bufferElementRef)\n")
+SLANG_RAW(" __subscript(uint index) -> T\n")
+SLANG_RAW(" {\n")
+SLANG_RAW(" __target_intrinsic(glsl, \"$0._data[$1]\")\n")
SLANG_RAW(" ref;\n")
-SLANG_RAW("\t}\n")
+SLANG_RAW(" }\n")
SLANG_RAW("};\n")
SLANG_RAW("\n")
diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h
index 8f997cbe2..09c11ed16 100644
--- a/source/slang/ir-inst-defs.h
+++ b/source/slang/ir-inst-defs.h
@@ -217,10 +217,6 @@ INST(Var, var, 0, 0)
INST(Load, load, 1, 0)
INST(Store, store, 2, 0)
-INST(BufferLoad, bufferLoad, 2, 0)
-INST(BufferStore, bufferStore, 3, 0)
-INST(BufferElementRef, bufferElementRef, 2, 0)
-
INST(FieldExtract, get_field, 2, 0)
INST(FieldAddress, get_field_addr, 2, 0)
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index 599b02ea7..2f16f4ebc 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -3576,7 +3576,6 @@ namespace Slang
case kIROp_makeArray:
case kIROp_makeStruct:
case kIROp_Load: // We are ignoring the possibility of loads from bad addresses, or `volatile` loads
- case kIROp_BufferLoad:
case kIROp_FieldExtract:
case kIROp_FieldAddress:
case kIROp_getElement:
diff --git a/source/slang/type-layout.cpp b/source/slang/type-layout.cpp
index 8fc48fe4f..2d21d7aef 100644
--- a/source/slang/type-layout.cpp
+++ b/source/slang/type-layout.cpp
@@ -2276,6 +2276,17 @@ RefPtr<TypeLayout> CreateTypeLayout(
return typeLayout;
}
+RefPtr<TypeLayout> TypeLayout::unwrapArray()
+{
+ TypeLayout* typeLayout = this;
+
+ while(auto arrayTypeLayout = dynamic_cast<ArrayTypeLayout*>(typeLayout))
+ typeLayout = arrayTypeLayout->elementTypeLayout;
+
+ return typeLayout;
+}
+
+
RefPtr<GlobalGenericParamDecl> GenericParamTypeLayout::getGlobalGenericParamDecl()
{
auto declRefType = type->AsDeclRefType();
diff --git a/source/slang/type-layout.h b/source/slang/type-layout.h
index fa874cb80..6f6dad055 100644
--- a/source/slang/type-layout.h
+++ b/source/slang/type-layout.h
@@ -354,6 +354,13 @@ public:
info.count = count;
addResourceUsage(info);
}
+
+ /// "Unwrap" any layers of array-ness from this type layout.
+ ///
+ /// If this is an `ArrayTypeLayout`, returns the result of unwrapping the elemnt type layout.
+ /// Otherwise, returns this type layout.
+ ///
+ RefPtr<TypeLayout> unwrapArray();
};
typedef unsigned int VarLayoutFlags;
diff --git a/source/slang/vm.cpp b/source/slang/vm.cpp
index fa59a741b..0f79c763b 100644
--- a/source/slang/vm.cpp
+++ b/source/slang/vm.cpp
@@ -846,72 +846,6 @@ void resumeThread(
}
break;
- case kIROp_BufferLoad:
- {
- VMType type = decodeType(frame, &ip);
- UInt argCount = decodeUInt(&ip);
- void* argPtrs[16] = { 0 };
- for( UInt aa = 0; aa < argCount; ++aa )
- {
- void* argPtr = decodeOperandPtr<void>(frame, &ip);
- argPtrs[aa] = argPtr;
- }
-
- void* dest = decodeOperandPtr<void>(frame, &ip);
-
- char* bufferData = *(char**)argPtrs[0];
- uint32_t index = *(uint32_t*)argPtrs[1];
-
- auto size = type.getSize();
- char* elementData = bufferData + index*size;
- memcpy(dest, elementData, size);
- }
- break;
-
- case kIROp_BufferStore:
- {
- VMType resultType = decodeType(frame, &ip);
- /*UInt argCount = */decodeUInt(&ip);
-
- char* bufferData = decodeOperand<char*>(frame, &ip);
- uint32_t index = decodeOperand<uint32_t>(frame, &ip);
-
- auto srcPtrAndType = decodeOperandPtrAndType(frame, &ip);
- void* srcPtr = srcPtrAndType.ptr;
- VMType type = srcPtrAndType.type;
-
- auto size = type.getSize();
- char* elementData = bufferData + index*size;
- memcpy(elementData, srcPtr, size);
- }
- break;
-
- case kIROp_BufferElementRef:
- {
- VMType ptrType = decodeType(frame, &ip);
- VMType type = ((VMPtrTypeImpl*)ptrType.getImpl())->base;
-
- UInt argCount = decodeUInt(&ip);
- void* argPtrs[16] = { 0 };
- for( UInt aa = 0; aa < argCount; ++aa )
- {
- void* argPtr = decodeOperandPtr<void>(frame, &ip);
- argPtrs[aa] = argPtr;
- }
-
- void* dest = decodeOperandPtr<void>(frame, &ip);
-
- char* bufferData = *(char**)argPtrs[0];
- uint32_t index = *(uint32_t*)argPtrs[1];
-
- auto size = type.getSize();
- char* elementData = bufferData + index*size;
-
- *(void**)dest = elementData;
- }
- break;
-
-
case kIROp_Call:
{
VMType type = decodeType(frame, &ip);