summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/check.h7
-rw-r--r--source/slang/emit.cpp110
-rw-r--r--source/slang/ir-inst-defs.h2
-rw-r--r--source/slang/ir-insts.h8
-rw-r--r--source/slang/ir-legalize-types.cpp292
-rw-r--r--source/slang/ir.cpp180
-rw-r--r--source/slang/lower-to-ir.cpp34
-rw-r--r--source/slang/slang.vcxproj1
-rw-r--r--source/slang/slang.vcxproj.filters3
9 files changed, 482 insertions, 155 deletions
diff --git a/source/slang/check.h b/source/slang/check.h
new file mode 100644
index 000000000..1f378ec7b
--- /dev/null
+++ b/source/slang/check.h
@@ -0,0 +1,7 @@
+// check.h
+#pragma once
+
+namespace Slang
+{
+ bool isGlobalShaderParameter(VarDeclBase* decl);
+} \ No newline at end of file
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 930520892..39616b3df 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -2355,6 +2355,7 @@ struct EmitVisitor
case kIROp_Var:
case kIROp_GlobalVar:
case kIROp_GlobalConstant:
+ case kIROp_GlobalParam:
case kIROp_Param:
return false;
@@ -5558,7 +5559,7 @@ struct EmitVisitor
void emitHLSLParameterGroup(
EmitContext* ctx,
- IRGlobalVar* varDecl,
+ IRGlobalParam* varDecl,
IRUniformParameterGroupType* type)
{
if(as<IRTextureBufferType>(type))
@@ -5623,7 +5624,7 @@ struct EmitVisitor
void emitGLSLParameterGroup(
EmitContext* ctx,
- IRGlobalVar* varDecl,
+ IRGlobalParam* varDecl,
IRUniformParameterGroupType* type)
{
auto varLayout = getVarLayout(ctx, varDecl);
@@ -5680,14 +5681,14 @@ struct EmitVisitor
// 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());
+ emitArrayBrackets(ctx, varDecl->getDataType());
emit(";\n");
}
void emitIRParameterGroup(
EmitContext* ctx,
- IRGlobalVar* varDecl,
+ IRGlobalParam* varDecl,
IRUniformParameterGroupType* type)
{
switch (ctx->shared->target)
@@ -5763,7 +5764,7 @@ struct EmitVisitor
void emitIRStructuredBuffer_GLSL(
EmitContext* ctx,
- IRGlobalVar* varDecl,
+ IRGlobalParam* varDecl,
IRHLSLStructuredBufferTypeBase* structuredBufferType)
{
// Shader storage buffer is an OpenGL 430 feature
@@ -5809,14 +5810,14 @@ struct EmitVisitor
emit("} ");
emit(getIRName(varDecl));
- emitArrayBrackets(ctx, varDecl->getDataType()->getValueType());
+ emitArrayBrackets(ctx, varDecl->getDataType());
emit(";\n");
}
void emitIRByteAddressBuffer_GLSL(
EmitContext* ctx,
- IRGlobalVar* varDecl,
+ IRGlobalParam* varDecl,
IRByteAddressBufferTypeBase* /* byteAddressBufferType */)
{
// TODO: A lot of this logic is copy-pasted from `emitIRStructuredBuffer_GLSL`.
@@ -5862,7 +5863,7 @@ struct EmitVisitor
emit("} ");
emit(getIRName(varDecl));
- emitArrayBrackets(ctx, varDecl->getDataType()->getValueType());
+ emitArrayBrackets(ctx, varDecl->getDataType());
emit(";\n");
}
@@ -5894,6 +5895,63 @@ struct EmitVisitor
Emit("}\n");
}
+ // An ordinary global variable won't have a layout
+ // associated with it, since it is not a shader
+ // parameter.
+ //
+ SLANG_ASSERT(!getVarLayout(ctx, varDecl));
+ VarLayout* layout = nullptr;
+
+ // An ordinary global variable (which is not a
+ // shader parameter) may need special
+ // modifiers to indicate it as such.
+ //
+ switch (getTarget(ctx))
+ {
+ case CodeGenTarget::HLSL:
+ // HLSL requires the `static` modifier on any
+ // global variables; otherwise they are assumed
+ // to be uniforms.
+ Emit("static ");
+ break;
+
+ default:
+ break;
+ }
+
+ emitIRVarModifiers(ctx, layout, varDecl, varType);
+
+ emitIRRateQualifiers(ctx, varDecl);
+ emitIRType(ctx, varType, getIRName(varDecl));
+
+ // TODO: These shouldn't be needed for ordinary
+ // global variables.
+ //
+ emitIRSemantics(ctx, varDecl);
+ emitIRLayoutSemantics(ctx, varDecl);
+
+ if (varDecl->getFirstBlock())
+ {
+ Emit(" = ");
+ emit(initFuncName);
+ Emit("()");
+ }
+
+ emit(";\n\n");
+ }
+
+ void emitIRGlobalParam(
+ EmitContext* ctx,
+ IRGlobalParam* varDecl)
+ {
+ auto rawType = varDecl->getDataType();
+
+ auto varType = rawType;
+ if( auto outType = as<IROutTypeBase>(varType) )
+ {
+ varType = outType->getValueType();
+ }
+
// 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`
@@ -5985,26 +6043,11 @@ struct EmitVisitor
// Need to emit appropriate modifiers here.
+ // We expect/require all shader parameters to
+ // have some kind of layout information associted with them.
+ //
auto layout = getVarLayout(ctx, varDecl);
-
- if (!layout)
- {
- // A global variable without a layout is just an
- // ordinary global variable, and may need special
- // modifiers to indicate it as such.
- switch (getTarget(ctx))
- {
- case CodeGenTarget::HLSL:
- // HLSL requires the `static` modifier on any
- // global variables; otherwise they are assumed
- // to be uniforms.
- Emit("static ");
- break;
-
- default:
- break;
- }
- }
+ SLANG_ASSERT(layout);
emitIRVarModifiers(ctx, layout, varDecl, varType);
@@ -6015,16 +6058,13 @@ struct EmitVisitor
emitIRLayoutSemantics(ctx, varDecl);
- if (varDecl->getFirstBlock())
- {
- Emit(" = ");
- emit(initFuncName);
- Emit("()");
- }
+ // A shader parameter cannot have an initializer,
+ // so we do need to consider emitting one here.
emit(";\n\n");
}
+
void emitIRGlobalConstantInitializer(
EmitContext* ctx,
IRGlobalConstant* valDecl)
@@ -6098,6 +6138,10 @@ struct EmitVisitor
emitIRGlobalVar(ctx, (IRGlobalVar*) inst);
break;
+ case kIROp_GlobalParam:
+ emitIRGlobalParam(ctx, (IRGlobalParam*) inst);
+ break;
+
case kIROp_GlobalConstant:
emitIRGlobalConstant(ctx, (IRGlobalConstant*) inst);
break;
diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h
index 35a73c2f1..69940a79d 100644
--- a/source/slang/ir-inst-defs.h
+++ b/source/slang/ir-inst-defs.h
@@ -163,6 +163,8 @@ INST_RANGE(Type, VoidType, StructType)
INST(GlobalConstant, global_constant, 0, 0)
INST_RANGE(GlobalValueWithCode, Func, GlobalConstant)
+INST(GlobalParam, global_param, 0, 0)
+
INST(StructKey, key, 0, 0)
INST(GlobalGenericParam, global_generic_param, 0, 0)
INST(WitnessTable, witness_table, 0, 0)
diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h
index 1dfd52d8a..737675d87 100644
--- a/source/slang/ir-insts.h
+++ b/source/slang/ir-insts.h
@@ -558,6 +558,12 @@ struct IRGlobalConstant : IRGlobalValueWithCode
IR_LEAF_ISA(GlobalConstant)
};
+struct IRGlobalParam : IRInst
+{
+ IR_LEAF_ISA(GlobalParam)
+};
+
+
// An entry in a witness table (see below)
struct IRWitnessTableEntry : IRInst
{
@@ -798,6 +804,8 @@ struct IRBuilder
IRType* valueType);
IRGlobalConstant* createGlobalConstant(
IRType* valueType);
+ IRGlobalParam* createGlobalParam(
+ IRType* valueType);
IRWitnessTable* createWitnessTable();
IRWitnessTableEntry* createWitnessTableEntry(
IRWitnessTable* witnessTable,
diff --git a/source/slang/ir-legalize-types.cpp b/source/slang/ir-legalize-types.cpp
index 901d8705b..a97cc0393 100644
--- a/source/slang/ir-legalize-types.cpp
+++ b/source/slang/ir-legalize-types.cpp
@@ -335,31 +335,31 @@ static LegalVal legalizeStore(
}
}
-static LegalVal legalizeFieldAddress(
- IRTypeLegalizationContext* context,
+static LegalVal legalizeFieldExtract(
+ IRTypeLegalizationContext* context,
LegalType type,
- LegalVal legalPtrOperand,
+ LegalVal legalStructOperand,
IRStructKey* fieldKey)
{
auto builder = context->builder;
- switch (legalPtrOperand.flavor)
+ switch (legalStructOperand.flavor)
{
case LegalVal::Flavor::none:
return LegalVal();
case LegalVal::Flavor::simple:
return LegalVal::simple(
- builder->emitFieldAddress(
+ builder->emitFieldExtract(
type.getSimple(),
- legalPtrOperand.getSimple(),
+ legalStructOperand.getSimple(),
fieldKey));
case LegalVal::Flavor::pair:
{
// There are two sides, the ordinary and the special,
// and we basically just dispatch to both of them.
- auto pairVal = legalPtrOperand.getPair();
+ auto pairVal = legalStructOperand.getPair();
auto pairInfo = pairVal->pairInfo;
auto pairElement = pairInfo->findElement(fieldKey);
if (!pairElement)
@@ -387,7 +387,7 @@ static LegalVal legalizeFieldAddress(
if (pairElement->flags & PairInfo::kFlag_hasOrdinary)
{
- ordinaryVal = legalizeFieldAddress(
+ ordinaryVal = legalizeFieldExtract(
context,
ordinaryType,
pairVal->ordinaryVal,
@@ -396,7 +396,7 @@ static LegalVal legalizeFieldAddress(
if (pairElement->flags & PairInfo::kFlag_hasSpecial)
{
- specialVal = legalizeFieldAddress(
+ specialVal = legalizeFieldExtract(
context,
specialType,
pairVal->specialVal,
@@ -413,7 +413,7 @@ static LegalVal legalizeFieldAddress(
// corresponding to a field. We will handle
// this by simply returning the corresponding
// element from the operand.
- auto ptrTupleInfo = legalPtrOperand.getTuple();
+ auto ptrTupleInfo = legalStructOperand.getTuple();
for (auto ee : ptrTupleInfo->elements)
{
if (ee.key == fieldKey)
@@ -435,7 +435,7 @@ static LegalVal legalizeFieldAddress(
}
}
-static LegalVal legalizeFieldAddress(
+static LegalVal legalizeFieldExtract(
IRTypeLegalizationContext* context,
LegalType type,
LegalVal legalPtrOperand,
@@ -445,38 +445,38 @@ static LegalVal legalizeFieldAddress(
// the "field" argument.
auto fieldKey = legalFieldOperand.getSimple();
- return legalizeFieldAddress(
+ return legalizeFieldExtract(
context,
type,
legalPtrOperand,
(IRStructKey*) fieldKey);
}
-static LegalVal legalizeFieldExtract(
- IRTypeLegalizationContext* context,
+static LegalVal legalizeFieldAddress(
+ IRTypeLegalizationContext* context,
LegalType type,
- LegalVal legalStructOperand,
+ LegalVal legalPtrOperand,
IRStructKey* fieldKey)
{
auto builder = context->builder;
- switch (legalStructOperand.flavor)
+ switch (legalPtrOperand.flavor)
{
case LegalVal::Flavor::none:
return LegalVal();
case LegalVal::Flavor::simple:
return LegalVal::simple(
- builder->emitFieldExtract(
+ builder->emitFieldAddress(
type.getSimple(),
- legalStructOperand.getSimple(),
+ legalPtrOperand.getSimple(),
fieldKey));
case LegalVal::Flavor::pair:
{
// There are two sides, the ordinary and the special,
// and we basically just dispatch to both of them.
- auto pairVal = legalStructOperand.getPair();
+ auto pairVal = legalPtrOperand.getPair();
auto pairInfo = pairVal->pairInfo;
auto pairElement = pairInfo->findElement(fieldKey);
if (!pairElement)
@@ -504,7 +504,7 @@ static LegalVal legalizeFieldExtract(
if (pairElement->flags & PairInfo::kFlag_hasOrdinary)
{
- ordinaryVal = legalizeFieldExtract(
+ ordinaryVal = legalizeFieldAddress(
context,
ordinaryType,
pairVal->ordinaryVal,
@@ -513,7 +513,7 @@ static LegalVal legalizeFieldExtract(
if (pairElement->flags & PairInfo::kFlag_hasSpecial)
{
- specialVal = legalizeFieldExtract(
+ specialVal = legalizeFieldAddress(
context,
specialType,
pairVal->specialVal,
@@ -530,7 +530,7 @@ static LegalVal legalizeFieldExtract(
// corresponding to a field. We will handle
// this by simply returning the corresponding
// element from the operand.
- auto ptrTupleInfo = legalStructOperand.getTuple();
+ auto ptrTupleInfo = legalPtrOperand.getTuple();
for (auto ee : ptrTupleInfo->elements)
{
if (ee.key == fieldKey)
@@ -546,13 +546,27 @@ static LegalVal legalizeFieldExtract(
UNREACHABLE_RETURN(LegalVal());
}
+ case LegalVal::Flavor::implicitDeref:
+ {
+ // The original value had a level of indirection
+ // that is now being removed, so should not be
+ // able to get at the *address* of the field any
+ // more, and need to resign ourselves to just
+ // getting at the field *value* and then
+ // adding an implicit dereference on top of that.
+ //
+ auto implicitDerefVal = legalPtrOperand.getImplicitDeref();
+
+ return LegalVal::implicitDeref(legalizeFieldExtract(context,type, implicitDerefVal, fieldKey));
+ }
+
default:
SLANG_UNEXPECTED("unhandled");
UNREACHABLE_RETURN(LegalVal());
}
}
-static LegalVal legalizeFieldExtract(
+static LegalVal legalizeFieldAddress(
IRTypeLegalizationContext* context,
LegalType type,
LegalVal legalPtrOperand,
@@ -562,13 +576,125 @@ static LegalVal legalizeFieldExtract(
// the "field" argument.
auto fieldKey = legalFieldOperand.getSimple();
- return legalizeFieldExtract(
+ return legalizeFieldAddress(
context,
type,
legalPtrOperand,
(IRStructKey*) fieldKey);
}
+static LegalVal legalizeGetElement(
+ IRTypeLegalizationContext* context,
+ LegalType type,
+ LegalVal legalPtrOperand,
+ IRInst* indexOperand)
+{
+ auto builder = context->builder;
+
+ switch (legalPtrOperand.flavor)
+ {
+ case LegalVal::Flavor::none:
+ return LegalVal();
+
+ case LegalVal::Flavor::simple:
+ return LegalVal::simple(
+ builder->emitElementExtract(
+ type.getSimple(),
+ legalPtrOperand.getSimple(),
+ indexOperand));
+
+ case LegalVal::Flavor::pair:
+ {
+ // There are two sides, the ordinary and the special,
+ // and we basically just dispatch to both of them.
+ auto pairVal = legalPtrOperand.getPair();
+ auto pairInfo = pairVal->pairInfo;
+
+ LegalType ordinaryType = type;
+ LegalType specialType = type;
+ if (type.flavor == LegalType::Flavor::pair)
+ {
+ auto pairType = type.getPair();
+ ordinaryType = pairType->ordinaryType;
+ specialType = pairType->specialType;
+ }
+
+ LegalVal ordinaryVal = legalizeGetElement(
+ context,
+ ordinaryType,
+ pairVal->ordinaryVal,
+ indexOperand);
+
+ LegalVal specialVal = legalizeGetElement(
+ context,
+ specialType,
+ pairVal->specialVal,
+ indexOperand);
+
+ return LegalVal::pair(ordinaryVal, specialVal, pairInfo);
+ }
+ break;
+
+ 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.
+ auto ptrTupleInfo = legalPtrOperand.getTuple();
+
+ RefPtr<TuplePseudoVal> resTupleInfo = new TuplePseudoVal();
+
+ auto tupleType = type.getTuple();
+ SLANG_ASSERT(tupleType);
+
+ auto elemCount = ptrTupleInfo->elements.Count();
+ SLANG_ASSERT(elemCount == tupleType->elements.Count());
+
+ for(UInt ee = 0; ee < elemCount; ++ee)
+ {
+ auto ptrElem = ptrTupleInfo->elements[ee];
+ auto elemType = tupleType->elements[ee].type;
+
+ TuplePseudoVal::Element resElem;
+ resElem.key = ptrElem.key;
+ resElem.val = legalizeGetElement(
+ context,
+ elemType,
+ ptrElem.val,
+ indexOperand);
+
+ resTupleInfo->elements.Add(resElem);
+ }
+
+ return LegalVal::tuple(resTupleInfo);
+ }
+
+ default:
+ SLANG_UNEXPECTED("unhandled");
+ UNREACHABLE_RETURN(LegalVal());
+ }
+}
+
+static LegalVal legalizeGetElement(
+ IRTypeLegalizationContext* context,
+ LegalType type,
+ LegalVal legalPtrOperand,
+ LegalVal legalIndexOperand)
+{
+ // We don't expect any legalization to affect
+ // the "index" argument.
+ auto indexOperand = legalIndexOperand.getSimple();
+
+ return legalizeGetElement(
+ context,
+ type,
+ legalPtrOperand,
+ indexOperand);
+}
+
+
static LegalVal legalizeGetElementPtr(
IRTypeLegalizationContext* context,
LegalType type,
@@ -657,6 +783,23 @@ static LegalVal legalizeGetElementPtr(
return LegalVal::tuple(resTupleInfo);
}
+ case LegalVal::Flavor::implicitDeref:
+ {
+ // The original value used to be a pointer to an array,
+ // and somebody is trying to get at an element pointer.
+ // Now we just have an array (wrapped with an implicit
+ // dereference) and need to just fetch the chosen element
+ // instead (and then wrapp the element value with an
+ // implicit dereference).
+ //
+ auto implicitDerefVal = legalPtrOperand.getImplicitDeref();
+ return LegalVal::implicitDeref(legalizeGetElement(
+ context,
+ type,
+ implicitDerefVal,
+ indexOperand));
+ }
+
default:
SLANG_UNEXPECTED("unhandled");
UNREACHABLE_RETURN(LegalVal());
@@ -816,6 +959,9 @@ static LegalVal legalizeInst(
case kIROp_FieldExtract:
return legalizeFieldExtract(context, type, args[0], args[1]);
+ case kIROp_getElement:
+ return legalizeGetElement(context, type, args[0], args[1]);
+
case kIROp_getElementPtr:
return legalizeGetElementPtr(context, type, args[0], args[1]);
@@ -965,6 +1111,9 @@ static LegalVal legalizeGlobalConstant(
IRTypeLegalizationContext* context,
IRGlobalConstant* irGlobalConstant);
+static LegalVal legalizeGlobalParam(
+ IRTypeLegalizationContext* context,
+ IRGlobalParam* irGlobalParam);
static LegalVal legalizeInst(
IRTypeLegalizationContext* context,
@@ -992,6 +1141,9 @@ static LegalVal legalizeInst(
case kIROp_GlobalConstant:
return legalizeGlobalConstant(context, cast<IRGlobalConstant>(inst));
+ case kIROp_GlobalParam:
+ return legalizeGlobalParam(context, cast<IRGlobalParam>(inst));
+
default:
break;
}
@@ -1184,6 +1336,28 @@ static LegalVal declareSimpleVar(
}
break;
+ case kIROp_GlobalConstant:
+ {
+ auto globalConst = builder->createGlobalConstant(type);
+ globalConst->removeFromParent();
+ globalConst->insertBefore(context->insertBeforeGlobal);
+
+ irVar = globalConst;
+ legalVarVal = LegalVal::simple(globalConst);
+ }
+ break;
+
+ case kIROp_GlobalParam:
+ {
+ auto globalParam = builder->createGlobalParam(type);
+ globalParam->removeFromParent();
+ globalParam->insertBefore(context->insertBeforeGlobal);
+
+ irVar = globalParam;
+ legalVarVal = LegalVal::simple(globalParam);
+ }
+ break;
+
case kIROp_Var:
{
auto localVar = builder->emitVar(type);
@@ -1355,9 +1529,6 @@ static LegalVal legalizeGlobalVar(
context,
irGlobalVar->getDataType()->getValueType());
- RefPtr<VarLayout> varLayout = findVarLayout(irGlobalVar);
- RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr;
-
switch (legalValueType.flavor)
{
case LegalType::Flavor::simple:
@@ -1373,21 +1544,12 @@ static LegalVal legalizeGlobalVar(
{
context->insertBeforeGlobal = irGlobalVar->getNextInst();
- LegalVarChain* varChain = nullptr;
- LegalVarChain varChainStorage;
- if (varLayout)
- {
- varChainStorage.next = nullptr;
- varChainStorage.varLayout = varLayout;
- varChain = &varChainStorage;
- }
-
IRGlobalNameInfo globalNameInfo;
globalNameInfo.globalVar = irGlobalVar;
globalNameInfo.counter = 0;
UnownedStringSlice nameHint = findNameHint(irGlobalVar);
- LegalVal newVal = declareVars(context, kIROp_GlobalVar, legalValueType, typeLayout, varChain, nameHint, &globalNameInfo);
+ LegalVal newVal = declareVars(context, kIROp_GlobalVar, legalValueType, nullptr, nullptr, nameHint, &globalNameInfo);
// Register the new value as the replacement for the old
registerLegalizedValue(context, irGlobalVar, newVal);
@@ -1445,6 +1607,62 @@ static LegalVal legalizeGlobalConstant(
}
}
+static LegalVal legalizeGlobalParam(
+ IRTypeLegalizationContext* context,
+ IRGlobalParam* irGlobalParam)
+{
+ // Legalize the type for the variable's value
+ auto legalValueType = legalizeType(
+ context,
+ irGlobalParam->getFullType());
+
+ RefPtr<VarLayout> varLayout = findVarLayout(irGlobalParam);
+ RefPtr<TypeLayout> typeLayout = varLayout ? varLayout->typeLayout : nullptr;
+
+ switch (legalValueType.flavor)
+ {
+ case LegalType::Flavor::simple:
+ // Easy case: the type is usable as-is, and we
+ // should just do that.
+ irGlobalParam->setFullType(legalValueType.getSimple());
+ return LegalVal::simple(irGlobalParam);
+
+ default:
+ {
+ context->insertBeforeGlobal = irGlobalParam->getNextInst();
+
+ LegalVarChain* varChain = nullptr;
+ LegalVarChain varChainStorage;
+ if (varLayout)
+ {
+ varChainStorage.next = nullptr;
+ varChainStorage.varLayout = varLayout;
+ varChain = &varChainStorage;
+ }
+
+ IRGlobalNameInfo globalNameInfo;
+ globalNameInfo.globalVar = irGlobalParam;
+ globalNameInfo.counter = 0;
+
+ // TODO: need to handle initializer here!
+
+ UnownedStringSlice nameHint = findNameHint(irGlobalParam);
+ LegalVal newVal = declareVars(context, kIROp_GlobalParam, legalValueType, typeLayout, varChain, nameHint, &globalNameInfo);
+
+ // Register the new value as the replacement for the old
+ registerLegalizedValue(context, irGlobalParam, newVal);
+
+ // Remove the old global from the module.
+ irGlobalParam->removeFromParent();
+ context->replacedInstructions.Add(irGlobalParam);
+
+ return newVal;
+ }
+ break;
+ }
+}
+
+
static void legalizeTypes(
IRTypeLegalizationContext* context)
{
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index b8892cc02..0d93957c8 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -1966,6 +1966,18 @@ namespace Slang
return globalConstant;
}
+ IRGlobalParam* IRBuilder::createGlobalParam(
+ IRType* valueType)
+ {
+ IRGlobalParam* inst = createInst<IRGlobalParam>(
+ this,
+ kIROp_GlobalParam,
+ valueType);
+ maybeSetSourceLoc(this, inst);
+ addGlobalValue(this, inst);
+ return inst;
+ }
+
IRWitnessTable* IRBuilder::createWitnessTable()
{
IRWitnessTable* witnessTable = createInst<IRWitnessTable>(
@@ -3730,6 +3742,7 @@ namespace Slang
case kIROp_Generic:
case kIROp_GlobalVar:
case kIROp_GlobalConstant:
+ case kIROp_GlobalParam:
case kIROp_StructKey:
case kIROp_GlobalGenericParam:
case kIROp_WitnessTable:
@@ -3800,7 +3813,7 @@ namespace Slang
// Legalization of entry points for GLSL:
//
- IRGlobalVar* addGlobalVariable(
+ IRGlobalParam* addGlobalParam(
IRModule* module,
IRType* valueType)
{
@@ -3812,7 +3825,7 @@ namespace Slang
IRBuilder builder;
builder.sharedBuilder = &shared;
- return builder.createGlobalVar(valueType);
+ return builder.createGlobalParam(valueType);
}
void moveValueBefore(
@@ -4277,18 +4290,26 @@ namespace Slang
varLayout->stage = inVarLayout->stage;
varLayout->AddResourceInfo(kind)->index = bindingIndex;
- // Simple case: just create a global variable of the matching type,
- // and then use the value of the global as a replacement for the
- // value of the original parameter.
+ // We are going to be creating a global parameter to replace
+ // the function parameter, but we need to handle the case
+ // where the parameter represents a varying *output* and not
+ // just an input.
+ //
+ // Our IR global shader parameters are read-only, just
+ // like our IR function parameters, and need a wrapper
+ // `Out<...>` type to represent otuputs.
//
- auto globalVariable = addGlobalVariable(builder->getModule(), type);
- moveValueBefore(globalVariable, builder->getFunc());
+ bool isOutput = kind == LayoutResourceKind::VaryingOutput;
+ IRType* paramType = isOutput ? builder->getOutType(type) : type;
+
+ auto globalParam = addGlobalParam(builder->getModule(), paramType);
+ moveValueBefore(globalParam, builder->getFunc());
- ScalarizedVal val = ScalarizedVal::address(globalVariable);
+ ScalarizedVal val = isOutput ? ScalarizedVal::address(globalParam) : ScalarizedVal::value(globalParam);
if( systemValueInfo )
{
- builder->addImportDecoration(globalVariable, UnownedTerminatedStringSlice(systemValueInfo->name));
+ builder->addImportDecoration(globalParam, UnownedTerminatedStringSlice(systemValueInfo->name));
if( auto fromType = systemValueInfo->requiredType )
{
@@ -4309,11 +4330,11 @@ namespace Slang
if(auto outerArrayName = systemValueInfo->outerArrayName)
{
- builder->addGLSLOuterArrayDecoration(globalVariable, UnownedTerminatedStringSlice(outerArrayName));
+ builder->addGLSLOuterArrayDecoration(globalParam, UnownedTerminatedStringSlice(outerArrayName));
}
}
- builder->addLayoutDecoration(globalVariable, varLayout);
+ builder->addLayoutDecoration(globalParam, varLayout);
return val;
}
@@ -4865,46 +4886,22 @@ namespace Slang
auto builder = context->getBuilder();
auto paramType = pp->getDataType();
- if(auto paramPtrType = as<IROutTypeBase>(paramType) )
- {
- // This is either an `out` or `in out` parameter.
- // We want to treat `out` parameters the same
- // as `in out` for our purposes, since there are
- // no pure `out` parameters defined for the ray
- // tracing stages.
-
- // Unlike the default legalization strategy for
- // `out` and `in out` entry point parameters,
- // we will not introduce an intermediate temporary.
- //
- // Instead we will simply create a global variable
- // and replace uses of the parameter with uses
- // of that global variable.
-
- auto valueType = paramPtrType->getValueType();
-
- auto globalVariable = addGlobalVariable(builder->getModule(), valueType);
- builder->addLayoutDecoration(globalVariable, paramLayout);
- moveValueBefore(globalVariable, builder->getFunc());
-
- pp->replaceUsesWith(globalVariable);
- }
- else
- {
- // This is the `in` parameter case, so that the parameter
- // was not a pointer. We will allocate a global variable
- // to represent the parameter, and then perform a load
- // form it at the start of the function.
- //
- auto valueType = paramType;
- auto globalVariable = addGlobalVariable(builder->getModule(), valueType);
- builder->addLayoutDecoration(globalVariable, paramLayout);
- moveValueBefore(globalVariable, builder->getFunc());
-
- auto irLoad = builder->emitLoad(globalVariable);
- pp->replaceUsesWith(irLoad);
- }
-
+ // The parameter might be either an `in` parameter,
+ // or an `out` or `in out` parameter, and in those
+ // latter cases its IR-level type will include a
+ // wrapping "pointer-like" type (e.g., `Out<Float>`
+ // instead of just `Float`).
+ //
+ // Because global shader parameters are read-only
+ // in the same way function types are, we can take
+ // care of that detail here just by allocating a
+ // global shader parameter with exactly the type
+ // of the original function parameter.
+ //
+ auto globalParam = addGlobalParam(builder->getModule(), paramType);
+ builder->addLayoutDecoration(globalParam, paramLayout);
+ moveValueBefore(globalParam, builder->getFunc());
+ pp->replaceUsesWith(globalParam);
}
void legalizeEntryPointParameterForGLSL(
@@ -5629,6 +5626,7 @@ namespace Slang
case kIROp_Generic:
case kIROp_GlobalVar:
case kIROp_GlobalConstant:
+ case kIROp_GlobalParam:
case kIROp_StructKey:
case kIROp_GlobalGenericParam:
case kIROp_WitnessTable:
@@ -5779,21 +5777,6 @@ namespace Slang
registerClonedValue(context, clonedVar, originalValues);
-#if 0
- auto mangledName = originalVar->mangledName;
- clonedVar->mangledName = mangledName;
-#endif
-
- if(auto linkage = originalVar->findDecoration<IRLinkageDecoration>())
- {
- auto mangledName = String(linkage->getMangledName());
- VarLayout* layout = nullptr;
- if (context->globalVarLayouts.TryGetValue(mangledName, layout))
- {
- builder->addLayoutDecoration(clonedVar, layout);
- }
- }
-
// Clone any code in the body of the variable, since this
// represents the initializer.
cloneGlobalValueWithCodeCommon(
@@ -5824,25 +5807,6 @@ namespace Slang
return clonedVal;
}
- IRGeneric* cloneGenericImpl(
- IRSpecContextBase* context,
- IRBuilder* builder,
- IRGeneric* originalVal,
- IROriginalValuesForClone const& originalValues)
- {
- auto clonedVal = builder->emitGeneric();
- registerClonedValue(context, clonedVal, originalValues);
-
- // Clone any code in the body of the generic, since this
- // computes its result value.
- cloneGlobalValueWithCodeCommon(
- context,
- clonedVal,
- originalVal);
-
- return clonedVal;
- }
-
void cloneSimpleGlobalValueImpl(
IRSpecContextBase* context,
IRInst* originalInst,
@@ -5865,6 +5829,48 @@ namespace Slang
}
}
+ IRGlobalParam* cloneGlobalParamImpl(
+ IRSpecContextBase* context,
+ IRBuilder* builder,
+ IRGlobalParam* originalVal,
+ IROriginalValuesForClone const& originalValues)
+ {
+ auto clonedVal = builder->createGlobalParam(
+ cloneType(context, originalVal->getFullType()));
+ cloneSimpleGlobalValueImpl(context, originalVal, originalValues, clonedVal);
+
+ if(auto linkage = originalVal->findDecoration<IRLinkageDecoration>())
+ {
+ auto mangledName = String(linkage->getMangledName());
+ VarLayout* layout = nullptr;
+ if (context->globalVarLayouts.TryGetValue(mangledName, layout))
+ {
+ builder->addLayoutDecoration(clonedVal, layout);
+ }
+ }
+
+ return clonedVal;
+ }
+
+ IRGeneric* cloneGenericImpl(
+ IRSpecContextBase* context,
+ IRBuilder* builder,
+ IRGeneric* originalVal,
+ IROriginalValuesForClone const& originalValues)
+ {
+ auto clonedVal = builder->emitGeneric();
+ registerClonedValue(context, clonedVal, originalValues);
+
+ // Clone any code in the body of the generic, since this
+ // computes its result value.
+ cloneGlobalValueWithCodeCommon(
+ context,
+ clonedVal,
+ originalVal);
+
+ return clonedVal;
+ }
+
IRStructKey* cloneStructKeyImpl(
IRSpecContextBase* context,
IRBuilder* builder,
@@ -6254,6 +6260,7 @@ namespace Slang
case kIROp_StructType:
case kIROp_GlobalVar:
+ case kIROp_GlobalParam:
return true;
default:
@@ -6350,6 +6357,9 @@ namespace Slang
case kIROp_GlobalConstant:
return cloneGlobalConstantImpl(context, builder, cast<IRGlobalConstant>(originalInst), originalValues);
+ case kIROp_GlobalParam:
+ return cloneGlobalParamImpl(context, builder, cast<IRGlobalParam>(originalInst), originalValues);
+
case kIROp_WitnessTable:
return cloneWitnessTableImpl(context, builder, cast<IRWitnessTable>(originalInst), originalValues);
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index bf5aeff24..18d42feab 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -3,6 +3,7 @@
#include "../../slang.h"
+#include "check.h"
#include "ir.h"
#include "ir-constexpr.h"
#include "ir-insts.h"
@@ -3828,8 +3829,41 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
return false;
}
+ LoweredValInfo lowerGlobalShaderParam(VarDeclBase* decl)
+ {
+ IRType* paramType = lowerType(context, decl->getType());
+
+ auto builder = getBuilder();
+
+ auto irParam = builder->createGlobalParam(paramType);
+ auto paramVal = LoweredValInfo::simple(irParam);
+
+ addLinkageDecoration(context, irParam, decl);
+ addNameHint(context, irParam, decl);
+ maybeSetRate(context, irParam, decl);
+ addVarDecorations(context, irParam, decl);
+
+ if (decl)
+ {
+ builder->addHighLevelDeclDecoration(irParam, decl);
+ }
+
+ // A global variable's SSA value is a *pointer* to
+ // the underlying storage.
+ setGlobalValue(context, decl, paramVal);
+
+ irParam->moveToEnd();
+
+ return paramVal;
+ }
+
LoweredValInfo lowerGlobalVarDecl(VarDeclBase* decl)
{
+ if(isGlobalShaderParameter(decl))
+ {
+ return lowerGlobalShaderParam(decl);
+ }
+
IRType* varType = lowerType(context, decl->getType());
auto builder = getBuilder();
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index c502780df..427127c05 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -171,6 +171,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\..\slang.h" />
+ <ClInclude Include="check.h" />
<ClInclude Include="compiler.h" />
<ClInclude Include="core.meta.slang.h" />
<ClInclude Include="decl-defs.h" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index dc5630504..d72909bc1 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -162,6 +162,9 @@
<ClInclude Include="visitor.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="check.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="check.cpp">