summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/bytecode.cpp3
-rw-r--r--source/slang/emit.cpp261
-rw-r--r--source/slang/ir-inst-defs.h8
-rw-r--r--source/slang/ir-insts.h26
-rw-r--r--source/slang/ir-legalize-types.cpp50
-rw-r--r--source/slang/ir-ssa.cpp1
-rw-r--r--source/slang/ir.cpp85
-rw-r--r--source/slang/lower-to-ir.cpp60
-rw-r--r--source/slang/vm.cpp8
9 files changed, 388 insertions, 114 deletions
diff --git a/source/slang/bytecode.cpp b/source/slang/bytecode.cpp
index 3b92b78e1..eb6b755fc 100644
--- a/source/slang/bytecode.cpp
+++ b/source/slang/bytecode.cpp
@@ -918,12 +918,15 @@ BytecodeGenerationPtr<BCSymbol> generateBytecodeSymbolForInst(
break;
case kIROp_global_var:
+ case kIROp_global_constant:
{
auto bcVar = allocate<BCSymbol>(context);
bcVar->op = inst->op;
bcVar->typeID = getTypeID(context, inst->type);
+ // TODO: actually need to intialize with body instructions
+
return bcVar;
}
break;
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index 0a71c7fa9..335662ab3 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -4728,6 +4728,7 @@ emitDeclImpl(decl, nullptr);
switch (inst->op)
{
case kIROp_global_var:
+ case kIROp_global_constant:
case kIROp_Func:
{
auto& mangledName = ((IRGlobalValue*)inst)->mangledName;
@@ -4786,7 +4787,7 @@ emitDeclImpl(decl, nullptr);
case IRDeclaratorInfo::Flavor::Array:
emitDeclarator(ctx, declarator->next);
emit("[");
- emitIROperand(ctx, declarator->elementCount);
+ emitIROperand(ctx, declarator->elementCount, IREmitMode::Default);
emit("]");
break;
}
@@ -5041,9 +5042,17 @@ emitDeclImpl(decl, nullptr);
}
#endif
+ // Hack to allow IR emit for global constant to override behavior
+ enum class IREmitMode
+ {
+ Default,
+ GlobalConstant,
+ };
+
bool shouldFoldIRInstIntoUseSites(
EmitContext* ctx,
- IRValue* inst)
+ IRValue* inst,
+ IREmitMode mode)
{
// Certain opcodes should always be folded in
switch( inst->op )
@@ -5053,6 +5062,7 @@ emitDeclImpl(decl, nullptr);
case kIROp_Var:
case kIROp_global_var:
+ case kIROp_global_constant:
case kIROp_Param:
return false;
@@ -5066,6 +5076,10 @@ emitDeclImpl(decl, nullptr);
return true;
}
+ // Always fold when we are inside a global constant initializer
+ if (mode == IREmitMode::GlobalConstant)
+ return true;
+
// Certain *types* will usually want to be folded in,
// because they aren't allowed as types for temporary
// variables.
@@ -5137,12 +5151,13 @@ emitDeclImpl(decl, nullptr);
void emitIROperand(
EmitContext* ctx,
- IRValue* inst)
+ IRValue* inst,
+ IREmitMode mode)
{
- if( shouldFoldIRInstIntoUseSites(ctx, inst) )
+ if( shouldFoldIRInstIntoUseSites(ctx, inst, mode) )
{
emit("(");
- emitIRInstExpr(ctx, inst);
+ emitIRInstExpr(ctx, inst, mode);
emit(")");
return;
}
@@ -5158,7 +5173,8 @@ emitDeclImpl(decl, nullptr);
void emitIRArgs(
EmitContext* ctx,
- IRInst* inst)
+ IRInst* inst,
+ IREmitMode mode)
{
UInt argCount = inst->argCount;
IRUse* args = inst->getArgs();
@@ -5167,7 +5183,7 @@ emitDeclImpl(decl, nullptr);
for(UInt aa = 0; aa < argCount; ++aa)
{
if(aa != 0) emit(", ");
- emitIROperand(ctx, args[aa].usedValue);
+ emitIROperand(ctx, args[aa].usedValue, mode);
}
emit(")");
}
@@ -5450,7 +5466,8 @@ emitDeclImpl(decl, nullptr);
EmitContext* ctx,
IRCall* inst,
IRFunc* /* func */,
- IRTargetIntrinsicDecoration* targetIntrinsic)
+ IRTargetIntrinsicDecoration* targetIntrinsic,
+ IREmitMode mode)
{
IRUse* args = inst->getArgs();
UInt argCount = inst->getArgCount();
@@ -5471,7 +5488,7 @@ emitDeclImpl(decl, nullptr);
for (UInt aa = 0; aa < argCount; ++aa)
{
if (aa != 0) Emit(", ");
- emitIROperand(ctx, args[aa].usedValue);
+ emitIROperand(ctx, args[aa].usedValue, mode);
}
Emit(")");
return;
@@ -5507,7 +5524,7 @@ emitDeclImpl(decl, nullptr);
UInt argIndex = d - '0';
SLANG_RELEASE_ASSERT((0 <= argIndex) && (argIndex < argCount));
Emit("(");
- emitIROperand(ctx, args[argIndex].usedValue);
+ emitIROperand(ctx, args[argIndex].usedValue, mode);
Emit(")");
}
break;
@@ -5535,9 +5552,9 @@ emitDeclImpl(decl, nullptr);
}
Emit("(");
- emitIROperand(ctx, textureArg);
+ emitIROperand(ctx, textureArg, mode);
Emit(",");
- emitIROperand(ctx, samplerArg);
+ emitIROperand(ctx, samplerArg, mode);
Emit(")");
}
else
@@ -5564,7 +5581,7 @@ emitDeclImpl(decl, nullptr);
{
emitGLSLTextureOrTextureSamplerType(baseTextureType, "sampler");
Emit("(");
- emitIROperand(ctx, textureArg);
+ emitIROperand(ctx, textureArg, mode);
Emit(",");
Emit("SLANG_hack_samplerForTexelFetch");
context->shared->needHackSamplerForTexelFetch = true;
@@ -5631,7 +5648,8 @@ emitDeclImpl(decl, nullptr);
void emitIntrinsicCallExpr(
EmitContext* ctx,
IRCall* inst,
- IRFunc* func)
+ IRFunc* func,
+ IREmitMode mode)
{
// For a call with N arguments, the instruction will
// have N+1 operands. We will start consuming operands
@@ -5648,7 +5666,8 @@ emitDeclImpl(decl, nullptr);
ctx,
inst,
func,
- targetIntrinsicDecoration);
+ targetIntrinsicDecoration,
+ mode);
return;
}
@@ -5676,15 +5695,15 @@ emitDeclImpl(decl, nullptr);
{
// The user is invoking a built-in subscript operator
emit("(");
- emitIROperand(ctx, inst->getArg(operandIndex++));
+ emitIROperand(ctx, inst->getArg(operandIndex++), mode);
emit(")[");
- emitIROperand(ctx, inst->getArg(operandIndex++));
+ emitIROperand(ctx, inst->getArg(operandIndex++), mode);
emit("]");
if(operandIndex < operandCount)
{
emit(" = ");
- emitIROperand(ctx, inst->getArg(operandIndex++));
+ emitIROperand(ctx, inst->getArg(operandIndex++), mode);
}
return;
}
@@ -5700,7 +5719,7 @@ emitDeclImpl(decl, nullptr);
{
// Looks like a member function call
emit("(");
- emitIROperand(ctx, inst->getArg(operandIndex));
+ emitIROperand(ctx, inst->getArg(operandIndex), mode);
emit(").");
operandIndex++;
@@ -5712,7 +5731,7 @@ emitDeclImpl(decl, nullptr);
for(; operandIndex < operandCount; ++operandIndex )
{
if(!first) emit(", ");
- emitIROperand(ctx, inst->getArg(operandIndex));
+ emitIROperand(ctx, inst->getArg(operandIndex), mode);
first = false;
}
emit(")");
@@ -5720,24 +5739,25 @@ emitDeclImpl(decl, nullptr);
void emitIRCallExpr(
EmitContext* ctx,
- IRCall* inst)
+ IRCall* inst,
+ IREmitMode mode)
{
// We want to detect any call to an intrinsic operation,
// that we can emit it directly without mangling, etc.
auto funcValue = inst->getArg(0);
if(auto irFunc = asTargetIntrinsic(ctx, funcValue))
{
- emitIntrinsicCallExpr(ctx, inst, irFunc);
+ emitIntrinsicCallExpr(ctx, inst, irFunc, mode);
}
else
{
- emitIROperand(ctx, funcValue);
+ emitIROperand(ctx, funcValue, mode);
emit("(");
UInt argCount = inst->getArgCount();
for( UInt aa = 1; aa < argCount; ++aa )
{
if(aa != 1) emit(", ");
- emitIROperand(ctx, inst->getArg(aa));
+ emitIROperand(ctx, inst->getArg(aa), mode);
}
emit(")");
}
@@ -5745,7 +5765,8 @@ emitDeclImpl(decl, nullptr);
void emitIRInstExpr(
EmitContext* ctx,
- IRValue* value)
+ IRValue* value,
+ IREmitMode mode)
{
IRInst* inst = (IRInst*) value;
@@ -5760,6 +5781,8 @@ emitDeclImpl(decl, nullptr);
break;
case kIROp_Construct:
+ case kIROp_makeVector:
+ case kIROp_makeMatrix:
// Simple constructor call
if( inst->getArgCount() == 1 && getTarget(ctx) == CodeGenTarget::HLSL)
{
@@ -5767,12 +5790,12 @@ emitDeclImpl(decl, nullptr);
emit("(");
emitIRType(ctx, inst->getType());
emit(") ");
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
}
else
{
emitIRType(ctx, inst->getType());
- emitIRArgs(ctx, inst);
+ emitIRArgs(ctx, inst, mode);
}
break;
@@ -5789,7 +5812,7 @@ emitDeclImpl(decl, nullptr);
emitIRType(ctx, inst->getType());
}
emit("(");
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(")");
break;
@@ -5801,7 +5824,7 @@ emitDeclImpl(decl, nullptr);
if (!isDerefBaseImplicit(ctx, fieldExtract->getBase()))
{
- emitIROperand(ctx, fieldExtract->getBase());
+ emitIROperand(ctx, fieldExtract->getBase(), mode);
emit(".");
}
emit(getIRName(fieldExtract->getField()));
@@ -5816,7 +5839,7 @@ emitDeclImpl(decl, nullptr);
if (!isDerefBaseImplicit(ctx, ii->getBase()))
{
- emitIROperand(ctx, ii->getBase());
+ emitIROperand(ctx, ii->getBase(), mode);
emit(".");
}
@@ -5826,9 +5849,9 @@ emitDeclImpl(decl, nullptr);
#define CASE(OPCODE, OP) \
case OPCODE: \
- emitIROperand(ctx, inst->getArg(0)); \
+ emitIROperand(ctx, inst->getArg(0), mode); \
emit(" " #OP " "); \
- emitIROperand(ctx, inst->getArg(1)); \
+ emitIROperand(ctx, inst->getArg(1), mode); \
break
CASE(kIROp_Add, +);
@@ -5866,18 +5889,18 @@ emitDeclImpl(decl, nullptr);
&& inst->type->As<MatrixExpressionType>())
{
emit("matrixCompMult(");
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(", ");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit(")");
}
else
{
// Default handling is to just rely on infix
// `operator*`.
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(" * ");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
}
break;
@@ -5891,77 +5914,77 @@ emitDeclImpl(decl, nullptr);
{
emit("~");
}
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
}
break;
case kIROp_Neg:
{
emit("-");
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
}
break;
case kIROp_BitNot:
{
emit("~");
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
}
break;
case kIROp_Sample:
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(".Sample(");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit(", ");
- emitIROperand(ctx, inst->getArg(2));
+ emitIROperand(ctx, inst->getArg(2), mode);
emit(")");
break;
case kIROp_SampleGrad:
// argument 0 is the instruction's type
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(".SampleGrad(");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit(", ");
- emitIROperand(ctx, inst->getArg(2));
+ emitIROperand(ctx, inst->getArg(2), mode);
emit(", ");
- emitIROperand(ctx, inst->getArg(3));
+ emitIROperand(ctx, inst->getArg(3), mode);
emit(", ");
- emitIROperand(ctx, inst->getArg(4));
+ emitIROperand(ctx, inst->getArg(4), mode);
emit(")");
break;
case kIROp_Load:
// TODO: this logic will really only work for a simple variable reference...
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
break;
case kIROp_Store:
// TODO: this logic will really only work for a simple variable reference...
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(" = ");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
break;
case kIROp_Call:
{
- emitIRCallExpr(ctx, (IRCall*)inst);
+ emitIRCallExpr(ctx, (IRCall*)inst, mode);
}
break;
case kIROp_BufferLoad:
case kIROp_BufferElementRef:
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit("[");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit("]");
break;
case kIROp_BufferStore:
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit("[");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit("] = ");
- emitIROperand(ctx, inst->getArg(2));
+ emitIROperand(ctx, inst->getArg(2), mode);
break;
case kIROp_GroupMemoryBarrierWithGroupSync:
@@ -5970,9 +5993,9 @@ emitDeclImpl(decl, nullptr);
case kIROp_getElement:
case kIROp_getElementPtr:
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit("[");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit("]");
break;
@@ -5989,16 +6012,16 @@ emitDeclImpl(decl, nullptr);
// because the notion of what is a "row" vs. a "column"
// is reversed between HLSL/Slang and GLSL.
//
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit(" * ");
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
}
else
{
emit("mul(");
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(", ");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit(")");
}
break;
@@ -6006,7 +6029,7 @@ emitDeclImpl(decl, nullptr);
case kIROp_swizzle:
{
auto ii = (IRSwizzle*)inst;
- emitIROperand(ctx, ii->getBase());
+ emitIROperand(ctx, ii->getBase(), mode);
emit(".");
UInt elementCount = ii->getElementCount();
for (UInt ee = 0; ee < elementCount; ++ee)
@@ -6026,17 +6049,17 @@ emitDeclImpl(decl, nullptr);
case kIROp_specialize:
{
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
}
break;
case kIROp_Select:
{
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(" ? ");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit(" : ");
- emitIROperand(ctx, inst->getArg(2));
+ emitIROperand(ctx, inst->getArg(2), mode);
}
break;
@@ -6044,6 +6067,24 @@ emitDeclImpl(decl, nullptr);
emit(getIRName(inst));
break;
+ case kIROp_makeArray:
+ case kIROp_makeStruct:
+ {
+ // TODO: initializer-list syntax may not always
+ // be appropriate, depending on the context
+ // of the expression.
+
+ emit("{ ");
+ UInt argCount = inst->getArgCount();
+ for (UInt aa = 0; aa < argCount; ++aa)
+ {
+ if (aa != 0) emit(", ");
+ emitIROperand(ctx, inst->getArg(aa), mode);
+ }
+ emit(" }");
+ }
+ break;
+
default:
emit("/* unhandled */");
break;
@@ -6052,9 +6093,10 @@ emitDeclImpl(decl, nullptr);
void emitIRInst(
EmitContext* ctx,
- IRInst* inst)
+ IRInst* inst,
+ IREmitMode mode)
{
- if (shouldFoldIRInstIntoUseSites(ctx, inst))
+ if (shouldFoldIRInstIntoUseSites(ctx, inst, mode))
{
return;
}
@@ -6065,7 +6107,7 @@ emitDeclImpl(decl, nullptr);
{
default:
emitIRInstResultDecl(ctx, inst);
- emitIRInstExpr(ctx, inst);
+ emitIRInstExpr(ctx, inst, mode);
emit(";\n");
break;
@@ -6103,7 +6145,7 @@ emitDeclImpl(decl, nullptr);
case kIROp_ReturnVal:
emit("return ");
- emitIROperand(ctx, ((IRReturnVal*) inst)->getVal());
+ emitIROperand(ctx, ((IRReturnVal*) inst)->getVal(), mode);
emit(";\n");
break;
@@ -6115,9 +6157,9 @@ emitDeclImpl(decl, nullptr);
{
auto ii = (IRSwizzleSet*)inst;
emitIRInstResultDecl(ctx, inst);
- emitIROperand(ctx, inst->getArg(0));
+ emitIROperand(ctx, inst->getArg(0), mode);
emit(";\n");
- emitIROperand(ctx, inst);
+ emitIROperand(ctx, inst, mode);
emit(".");
UInt elementCount = ii->getElementCount();
for (UInt ee = 0; ee < elementCount; ++ee)
@@ -6133,7 +6175,7 @@ emitDeclImpl(decl, nullptr);
emit(kComponents[elementIndex]);
}
emit(" = ");
- emitIROperand(ctx, inst->getArg(1));
+ emitIROperand(ctx, inst->getArg(1), mode);
emit(";\n");
}
break;
@@ -6229,9 +6271,9 @@ emitDeclImpl(decl, nullptr);
IRValue* arg = args[argIndex].usedValue;
- emitIROperand(ctx, pp);
+ emitIROperand(ctx, pp, IREmitMode::Default);
emit(" = ");
- emitIROperand(ctx, arg);
+ emitIROperand(ctx, arg, IREmitMode::Default);
emit(";\n");
}
}
@@ -6331,7 +6373,7 @@ emitDeclImpl(decl, nullptr);
assert(isTerminatorInst(terminator));
for (auto inst = block->getFirstInst(); inst != terminator; inst = inst->getNextInst())
{
- emitIRInst(ctx, inst);
+ emitIRInst(ctx, inst, IREmitMode::Default);
}
// Now look at the terminator instruction, which will tell us what we need to emit next.
@@ -6350,7 +6392,7 @@ emitDeclImpl(decl, nullptr);
case kIROp_ReturnVal:
case kIROp_ReturnVoid:
case kIROp_discard:
- emitIRInst(ctx, terminator);
+ emitIRInst(ctx, terminator, IREmitMode::Default);
return;
case kIROp_ifElse:
@@ -6368,7 +6410,7 @@ emitDeclImpl(decl, nullptr);
// instead of the current `if(cond) {} else {falseBlock}`
emit("if(");
- emitIROperand(ctx, t->getCondition());
+ emitIROperand(ctx, t->getCondition(), IREmitMode::Default);
emit(")\n{\n");
emitIRStmtsForBlocks(
ctx,
@@ -6606,7 +6648,7 @@ emitDeclImpl(decl, nullptr);
// Emit the start of our statement.
emit("switch(");
- emitIROperand(ctx, conditionVal);
+ emitIROperand(ctx, conditionVal, IREmitMode::Default);
emit(")\n{\n");
// Now iterate over the `case`s of the branch
@@ -6634,7 +6676,7 @@ emitDeclImpl(decl, nullptr);
for(;;)
{
emit("case ");
- emitIROperand(ctx, caseVal);
+ emitIROperand(ctx, caseVal, IREmitMode::Default);
emit(":\n");
if(caseIndex >= caseCount)
@@ -7744,6 +7786,51 @@ emitDeclImpl(decl, nullptr);
emit(";\n");
}
+ void emitIRGlobalConstantInitializer(
+ EmitContext* ctx,
+ IRGlobalConstant* valDecl)
+ {
+ // We expect to see only a single block
+ auto block = valDecl->getFirstBlock();
+ assert(block);
+ assert(!block->getNextBlock());
+
+ // We expect the terminator to be a `return`
+ // instruction with a value.
+ auto returnInst = (IRReturnVal*) block->getLastInst();
+ assert(returnInst->op == kIROp_ReturnVal);
+
+ // Now we want to emit the expression form of
+ // the value being returned, and force any
+ // sub-expressions to be included.
+ emitIRInstExpr(ctx, returnInst->getVal(), IREmitMode::GlobalConstant);
+ }
+
+ void emitIRGlobalConstant(
+ EmitContext* ctx,
+ IRGlobalConstant* valDecl)
+ {
+ auto valType = valDecl->getType();
+
+ emit("static const ");
+ emitIRType(ctx, valType, getIRName(valDecl));
+
+ if (valDecl->firstBlock)
+ {
+ // There is an initializer (which we expect for
+ // any global constant...).
+
+ emit(" = ");
+
+ // We need to emit the entire initializer as
+ // a single expression.
+ emitIRGlobalConstantInitializer(ctx, valDecl);
+ }
+
+
+ emit(";\n");
+ }
+
void emitIRGlobalInst(
EmitContext* ctx,
IRGlobalValue* inst)
@@ -7760,6 +7847,10 @@ emitDeclImpl(decl, nullptr);
emitIRGlobalVar(ctx, (IRGlobalVar*) inst);
break;
+ case kIROp_global_constant:
+ emitIRGlobalConstant(ctx, (IRGlobalConstant*) inst);
+ break;
+
case kIROp_Var:
emitIRVar(ctx, (IRVar*) inst);
break;
@@ -7921,6 +8012,14 @@ emitDeclImpl(decl, nullptr);
}
break;
+ case kIROp_global_constant:
+ {
+ auto irGlobal = (IRGlobalConstant*) value;
+ emitIRUsedType(ctx, irGlobal->type);
+ emitIRUsedTypesForGlobalValueWithCode(ctx, irGlobal);
+ }
+ break;
+
default:
{
emitIRUsedType(ctx, value->type);
diff --git a/source/slang/ir-inst-defs.h b/source/slang/ir-inst-defs.h
index 41e614807..9d6330eae 100644
--- a/source/slang/ir-inst-defs.h
+++ b/source/slang/ir-inst-defs.h
@@ -103,6 +103,12 @@ INST(lookup_interface_method, lookup_interface_method, 2, 0)
INST(lookup_witness_table, lookup_witness_table, 2, 0)
INST(Construct, construct, 0, 0)
+
+INST(makeVector, makeVector, 0, 0)
+INST(makeMatrix, makeMatrix, 0, 0)
+INST(makeArray, makeArray, 0, 0)
+INST(makeStruct, makeStruct, 0, 0)
+
INST(Call, call, 1, 0)
INST(Module, module, 0, PARENT)
@@ -110,6 +116,8 @@ INST(Func, func, 0, PARENT)
INST(Block, block, 0, PARENT)
INST(global_var, global_var, 0, 0)
+INST(global_constant, global_constant, 0, 0)
+
INST(witness_table, witness_table, 0, 0)
INST(witness_table_entry, witness_table_entry, 2, 0)
diff --git a/source/slang/ir-insts.h b/source/slang/ir-insts.h
index 266374545..eec42d59a 100644
--- a/source/slang/ir-insts.h
+++ b/source/slang/ir-insts.h
@@ -304,6 +304,15 @@ struct IRGlobalVar : IRGlobalValueWithCode
PtrType* getType() { return type.As<PtrType>(); }
};
+/// @brief A global constant.
+///
+/// Represents a global-scope constant value in the IR.
+/// The initializer for the constant is represented by
+/// the code in the basic block(s) nested in this value.
+struct IRGlobalConstant : IRGlobalValueWithCode
+{
+};
+
// An entry in a witness table (see below)
struct IRWitnessTableEntry : IRUser
{
@@ -453,6 +462,21 @@ struct IRBuilder
UInt argCount,
IRValue* const* args);
+ IRInst* emitMakeVector(
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args);
+
+ IRInst* emitMakeArray(
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args);
+
+ IRInst* emitMakeStruct(
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args);
+
IRUndefined* emitUndefined(IRType* type);
@@ -462,6 +486,8 @@ struct IRBuilder
IRFunc* createFunc();
IRGlobalVar* createGlobalVar(
IRType* valueType);
+ IRGlobalConstant* createGlobalConstant(
+ 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 d4f6d2a64..9234af8f5 100644
--- a/source/slang/ir-legalize-types.cpp
+++ b/source/slang/ir-legalize-types.cpp
@@ -104,7 +104,7 @@ static void registerLegalizedValue(
static void maybeRegisterLegalizedGlobal(
IRTypeLegalizationContext* context,
- IRGlobalVar* irGlobalVar,
+ IRGlobalValue* irGlobalVar,
LegalVal const& legalVal)
{
// Check the mangled name of the symbol and don't register
@@ -122,7 +122,7 @@ static void maybeRegisterLegalizedGlobal(
struct IRGlobalNameInfo
{
- IRGlobalVar* globalVar;
+ IRGlobalValue* globalVar;
UInt counter;
};
@@ -1095,6 +1095,48 @@ static void legalizeGlobalVar(
}
}
+static void legalizeGlobalConstant(
+ IRTypeLegalizationContext* context,
+ IRGlobalConstant* irGlobalConstant)
+{
+ // Legalize the type for the variable's value
+ auto legalValueType = legalizeType(
+ context,
+ irGlobalConstant->getType());
+
+ switch (legalValueType.flavor)
+ {
+ case LegalType::Flavor::simple:
+ // Easy case: the type is usable as-is, and we
+ // should just do that.
+ irGlobalConstant->type = legalValueType.getSimple();
+ break;
+
+ default:
+ {
+ context->insertBeforeGlobal = irGlobalConstant->getNextValue();
+
+ IRGlobalNameInfo globalNameInfo;
+ globalNameInfo.globalVar = irGlobalConstant;
+ globalNameInfo.counter = 0;
+
+ // TODO: need to handle initializer here!
+ LegalVal newVal = declareVars(context, kIROp_global_constant, legalValueType, nullptr, nullptr, &globalNameInfo);
+
+ // Register the new value as the replacement for the old
+ registerLegalizedValue(context, irGlobalConstant, newVal);
+
+ // Also register the variable according to its mangled name, if any.
+ maybeRegisterLegalizedGlobal(context, irGlobalConstant, newVal);
+
+ // Remove the old global from the module.
+ irGlobalConstant->removeFromParent();
+ // TODO: actually clean up the global!
+ }
+ break;
+ }
+}
+
static void legalizeGlobalValue(
IRTypeLegalizationContext* context,
IRGlobalValue* irValue)
@@ -1113,6 +1155,10 @@ static void legalizeGlobalValue(
legalizeGlobalVar(context, (IRGlobalVar*)irValue);
break;
+ case kIROp_global_constant:
+ legalizeGlobalConstant(context, (IRGlobalConstant*)irValue);
+ break;
+
default:
SLANG_UNEXPECTED("unknown global value type");
break;
diff --git a/source/slang/ir-ssa.cpp b/source/slang/ir-ssa.cpp
index 8a2d201dd..d58fd22e4 100644
--- a/source/slang/ir-ssa.cpp
+++ b/source/slang/ir-ssa.cpp
@@ -857,6 +857,7 @@ void constructSSA(IRModule* module, IRGlobalValue* globalVal)
{
case kIROp_Func:
case kIROp_global_var:
+ case kIROp_global_constant:
constructSSA(module, (IRGlobalValueWithCode*)globalVal);
default:
diff --git a/source/slang/ir.cpp b/source/slang/ir.cpp
index 824af64ae..40c7e20d5 100644
--- a/source/slang/ir.cpp
+++ b/source/slang/ir.cpp
@@ -1004,6 +1004,30 @@ namespace Slang
return inst;
}
+ IRInst* IRBuilder::emitMakeVector(
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return emitIntrinsicInst(type, kIROp_makeVector, argCount, args);
+ }
+
+ IRInst* IRBuilder::emitMakeArray(
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return emitIntrinsicInst(type, kIROp_makeArray, argCount, args);
+ }
+
+ IRInst* IRBuilder::emitMakeStruct(
+ IRType* type,
+ UInt argCount,
+ IRValue* const* args)
+ {
+ return emitIntrinsicInst(type, kIROp_makeStruct, argCount, args);
+ }
+
IRModule* IRBuilder::createModule()
{
auto module = new IRModule();
@@ -1176,6 +1200,18 @@ namespace Slang
return globalVar;
}
+ IRGlobalConstant* IRBuilder::createGlobalConstant(
+ IRType* valueType)
+ {
+ IRGlobalConstant* globalConstant = createValue<IRGlobalConstant>(
+ this,
+ kIROp_global_constant,
+ valueType);
+ maybeSetSourceLoc(this, globalConstant);
+ addGlobalValue(getModule(), globalConstant);
+ return globalConstant;
+ }
+
IRWitnessTable* IRBuilder::createWitnessTable()
{
IRWitnessTable* witnessTable = createValue<IRWitnessTable>(
@@ -1747,6 +1783,7 @@ namespace Slang
{
case kIROp_Func:
case kIROp_global_var:
+ case kIROp_global_constant:
case kIROp_witness_table:
{
auto irFunc = (IRFunc*) inst;
@@ -2391,6 +2428,22 @@ namespace Slang
dump(context, ";\n");
}
+ void dumpIRGlobalConstant(
+ IRDumpContext* context,
+ IRGlobalConstant* val)
+ {
+ dump(context, "\n");
+ dumpIndent(context);
+ dump(context, "ir_global_constant ");
+ dumpID(context, val);
+ dumpInstTypeClause(context, val->getType());
+
+ // TODO: deal with the case where a global
+ // might have embedded initialization logic.
+
+ dump(context, ";\n");
+ }
+
void dumpIRWitnessTableEntry(
IRDumpContext* context,
IRWitnessTableEntry* entry)
@@ -2436,6 +2489,10 @@ namespace Slang
dumpIRGlobalVar(context, (IRGlobalVar*)value);
break;
+ case kIROp_global_constant:
+ dumpIRGlobalConstant(context, (IRGlobalConstant*)value);
+ break;
+
case kIROp_witness_table:
dumpIRWitnessTable(context, (IRWitnessTable*)value);
break;
@@ -3501,6 +3558,7 @@ namespace Slang
switch (originalValue->op)
{
case kIROp_global_var:
+ case kIROp_global_constant:
case kIROp_Func:
case kIROp_witness_table:
return cloneGlobalValue(this, (IRGlobalValue*) originalValue);
@@ -3776,6 +3834,29 @@ namespace Slang
return clonedVar;
}
+ IRGlobalConstant* cloneGlobalConstantImpl(
+ IRSpecContext* context,
+ IRGlobalConstant* originalVal,
+ IROriginalValuesForClone const& originalValues)
+ {
+ auto clonedVal = context->builder->createGlobalConstant(context->maybeCloneType(originalVal->getType()));
+ registerClonedValue(context, clonedVal, originalValues);
+
+ auto mangledName = originalVal->mangledName;
+ clonedVal->mangledName = mangledName;
+
+ cloneDecorations(context, clonedVal, originalVal);
+
+ // Clone any code in the body of the constant, since this
+ // represents the initializer.
+ cloneGlobalValueWithCodeCommon(
+ context,
+ clonedVal,
+ originalVal);
+
+ return clonedVal;
+ }
+
IRWitnessTable* cloneWitnessTableImpl(
IRSpecContextBase* context,
IRWitnessTable* originalTable,
@@ -4051,6 +4132,7 @@ namespace Slang
return ((IRWitnessTable*)val)->entries.first != nullptr;
case kIROp_global_var:
+ case kIROp_global_constant:
case kIROp_Func:
return ((IRGlobalValueWithCode*)val)->firstBlock != nullptr;
@@ -4149,6 +4231,9 @@ namespace Slang
case kIROp_global_var:
return cloneGlobalVarImpl(context, (IRGlobalVar*)originalVal, sym);
+ case kIROp_global_constant:
+ return cloneGlobalConstantImpl(context, (IRGlobalConstant*)originalVal, sym);
+
case kIROp_witness_table:
return cloneWitnessTableImpl(context, (IRWitnessTable*)originalVal, sym);
diff --git a/source/slang/lower-to-ir.cpp b/source/slang/lower-to-ir.cpp
index 5c6f62c38..53cb2e772 100644
--- a/source/slang/lower-to-ir.cpp
+++ b/source/slang/lower-to-ir.cpp
@@ -1295,7 +1295,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
{
// Allocate a temporary of the given type
RefPtr<Type> type = lowerSimpleType(context, expr->type);
- LoweredValInfo val = createVar(context, type);
+ List<IRValue*> args;
UInt argCount = expr->args.Count();
@@ -1305,28 +1305,23 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
{
UInt elementCount = (UInt) GetIntVal(arrayType->ArrayLength);
auto elementType = lowerType(context, arrayType->baseType);
+
for (UInt ee = 0; ee < elementCount; ++ee)
{
- IRValue* indexVal = context->irBuilder->getIntValue(
- getIntType(context),
- ee);
- LoweredValInfo elemVal = subscriptValue(
- elementType,
- val,
- indexVal);
-
if (ee < argCount)
{
auto argExpr = expr->args[ee];
LoweredValInfo argVal = lowerRValueExpr(context, argExpr);
-
- assign(context, elemVal, argVal);
+ args.Add(getSimpleVal(context, argVal));
}
else
{
SLANG_UNEXPECTED("need to default-initialize array elements");
}
}
+
+ return LoweredValInfo::simple(
+ getBuilder()->emitMakeArray(type, args.Count(), args.Buffer()));
}
else if (auto vectorType = type->As<VectorExpressionType>())
{
@@ -1335,7 +1330,6 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
UInt elementCount = (UInt) GetIntVal(vectorType->elementCount);
UInt argCounter = 0;
- List<IRValue*> elements;
for (UInt ee = 0; ee < elementCount; ++ee)
{
UInt argIndex = argCounter++;
@@ -1343,8 +1337,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
{
auto argExpr = expr->args[argIndex];
LoweredValInfo argVal = lowerRValueExpr(context, argExpr);
-
- elements.Add(getSimpleVal(context, argVal));
+ args.Add(getSimpleVal(context, argVal));
}
else
{
@@ -1352,10 +1345,8 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
}
}
- assign(context, val, LoweredValInfo::simple(getBuilder()->emitConstructorInst(
- lowerSimpleType(context, vectorType),
- elementCount,
- elements.Buffer())));
+ return LoweredValInfo::simple(
+ getBuilder()->emitMakeVector(type, args.Count(), args.Buffer()));
}
else if (auto declRefType = type->As<DeclRefType>())
{
@@ -1368,26 +1359,21 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
if (ff.getDecl()->HasModifier<HLSLStaticModifier>())
continue;
- auto loweredFieldType = lowerType(
- context,
- GetType(ff));
- LoweredValInfo fieldVal = extractField(
- loweredFieldType,
- val,
- ff);
-
UInt argIndex = argCounter++;
if (argIndex < argCount)
{
auto argExpr = expr->args[argIndex];
LoweredValInfo argVal = lowerRValueExpr(context, argExpr);
- assign(context, fieldVal, argVal);
+ args.Add(getSimpleVal(context, argVal));
}
else
{
SLANG_UNEXPECTED("need to default-initialize struct fields");
}
}
+
+ return LoweredValInfo::simple(
+ getBuilder()->emitMakeStruct(type, args.Count(), args.Buffer()));
}
else
{
@@ -1399,8 +1385,7 @@ struct ExprLoweringVisitorBase : ExprVisitor<Derived, LoweredValInfo>
SLANG_UNEXPECTED("not sure how to initialize this type");
}
-
- return val;
+ UNREACHABLE_RETURN(LoweredValInfo());
}
LoweredValInfo visitConstantExpr(ConstantExpr* expr)
@@ -2997,7 +2982,21 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// to a variable over to its type, when it makes sense.
auto builder = getBuilder();
- auto irGlobal = builder->createGlobalVar(varType);
+
+ IRGlobalValueWithCode* irGlobal = nullptr;
+ LoweredValInfo globalVal;
+
+ // a `static const` global is actually a compile-time constant
+ if (decl->HasModifier<HLSLStaticModifier>() && decl->HasModifier<ConstModifier>())
+ {
+ irGlobal = builder->createGlobalConstant(varType);
+ globalVal = LoweredValInfo::simple(irGlobal);
+ }
+ else
+ {
+ irGlobal = builder->createGlobalVar(varType);
+ globalVal = LoweredValInfo::ptr(irGlobal);
+ }
irGlobal->mangledName = getMangledName(decl);
if (decl)
@@ -3007,7 +3006,6 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// A global variable's SSA value is a *pointer* to
// the underlying storage.
- auto globalVal = LoweredValInfo::ptr(irGlobal);
context->shared->declValues[
DeclRef<VarDeclBase>(decl, nullptr)] = globalVal;
diff --git a/source/slang/vm.cpp b/source/slang/vm.cpp
index e910870ba..38083d631 100644
--- a/source/slang/vm.cpp
+++ b/source/slang/vm.cpp
@@ -650,6 +650,14 @@ void* loadVMSymbol(
}
break;
+ case kIROp_global_constant:
+ {
+ auto type = getType(vmModule, bcSymbol->typeID);
+ void* valPtr = allocate(vm, type);
+ return valPtr;
+ }
+ break;
+
case kIROp_Func:
{
auto bcFunc = (BCFunc*) bcSymbol;