summaryrefslogtreecommitdiffstats
path: root/source/slang/emit.cpp
diff options
context:
space:
mode:
authorTim Foley <tfoleyNV@users.noreply.github.com>2017-10-04 13:54:25 -0700
committerGitHub <noreply@github.com>2017-10-04 13:54:25 -0700
commit54f016e7ef36b7505bf47d188cf4b7e1fdc443a4 (patch)
treef8a385c8a3bbac807c2c0d08a9b1e4cd208db95c /source/slang/emit.cpp
parent8a0ebb9fa25fd44def17b03b3f8aa1a33ad77940 (diff)
IR: overhaul IR design/implementation (#195)
* IR: overhaul IR design/implementation Closes #192 Closes #188 This is a major overhaul of how the IR is implemented, with the primary goal of just using the AST-level type representation as the IR's type representation, rather than inventing an entire shadow set of types (as captured in issue #192). One consequence of this choice is that types in the IR are no longer explicit "instructions" and are not represented as ordinary operands (so a bunch of `+ 1` cases end up going away when enumerating ordinary operands). Along the way I also got rid of the embedded IDs in the IR (issue #188) because this wasn't too hard to deal with at the same time. Another related change was to split the `IRValue` and `IRInst` cases, so that there are values that are not also instructions. Non-instruction values are now used to represent literals, references to declarations, and would eventually be used for an `undef` value if we need one. IR functions, global variables, and basic blocks are all values (because they can appear as operands), but not instructions. The main benefit of this approach is that the top-level structure of a bytecode (BC) module is much simpler to understand and walk, and BC-level types are represented much more directly (such that we could conceivably use them for reflection soon). * fixup: 64-bit build fix * fixup: try to silence clang's pedantic dependent-type errors * fixup: bug in VM loading of constants
Diffstat (limited to 'source/slang/emit.cpp')
-rw-r--r--source/slang/emit.cpp487
1 files changed, 344 insertions, 143 deletions
diff --git a/source/slang/emit.cpp b/source/slang/emit.cpp
index d4c1be706..64ac85bd4 100644
--- a/source/slang/emit.cpp
+++ b/source/slang/emit.cpp
@@ -93,6 +93,10 @@ struct SharedEmitContext
bool needHackSamplerForTexelFetch = false;
ExtensionUsageTracker extensionUsageTracker;
+
+ Dictionary<IRValue*, UInt> mapIRValueToID;
+
+ HashSet<Decl*> irDeclsVisited;
};
struct EmitContext
@@ -1025,6 +1029,9 @@ struct EmitVisitor
UNEXPECTED(GenericDeclRefType);
UNEXPECTED(InitializerListType);
+ UNEXPECTED(IRBasicBlockType);
+ UNEXPECTED(PtrType);
+
#undef UNEXPECTED
void visitNamedExpressionType(NamedExpressionType* type, TypeEmitArg const& arg)
@@ -1231,6 +1238,17 @@ struct EmitVisitor
EmitType(type, SourceLoc(), name, SourceLoc());
}
+ void EmitType(RefPtr<Type> type, String const& name)
+ {
+ // HACK: the rest of the code wants a `Name`,
+ // so we'll create one for a bit...
+ Name tempName;
+ tempName.text = name;
+
+ EmitType(type, SourceLoc(), &tempName, SourceLoc());
+ }
+
+
void EmitType(RefPtr<Type> type)
{
emitTypeImpl(type, nullptr);
@@ -3942,8 +3960,34 @@ emitDeclImpl(decl, nullptr);
// IR-level emit logc
- String getName(IRInst* inst)
+ UInt getID(IRValue* value)
+ {
+ auto& mapIRValueToID = context->shared->mapIRValueToID;
+
+ UInt id = 0;
+ if (mapIRValueToID.TryGetValue(value, id))
+ return id;
+
+ id = mapIRValueToID.Count() + 1;
+ mapIRValueToID.Add(value, id);
+ return id;
+ }
+
+ String getName(IRValue* inst)
{
+ switch(inst->op)
+ {
+ case kIROp_decl_ref:
+ {
+ auto irDeclRef = (IRDeclRef*) inst;
+ return getText(irDeclRef->declRef.GetName());
+ }
+ break;
+
+ default:
+ break;
+ }
+
if(auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>())
{
auto decl = decoration->decl;
@@ -3957,7 +4001,7 @@ emitDeclImpl(decl, nullptr);
StringBuilder sb;
sb << "_S";
- sb << inst->id;
+ sb << getID(inst);
return sb.ProduceString();
}
@@ -4035,7 +4079,7 @@ emitDeclImpl(decl, nullptr);
}
-
+#if 0
void emitIRSimpleType(
EmitContext* context,
IRType* type)
@@ -4153,12 +4197,14 @@ emitDeclImpl(decl, nullptr);
}
}
+#endif
CodeGenTarget getTarget(EmitContext* context)
{
return context->shared->target;
}
+#if 0
void emitGLSLTypePrefix(
EmitContext* context,
IRType* type)
@@ -4194,44 +4240,9 @@ emitDeclImpl(decl, nullptr);
break;
}
}
+#endif
- void emitIRVectorType(
- EmitContext* context,
- IRVectorType* type)
- {
- switch(getTarget(context))
- {
- case CodeGenTarget::GLSL:
- // HLSL style: `<elementTypePrefix>vec<elementCount>`
- // e.g., `ivec4`
- //
- emitGLSLTypePrefix(context, type->getElementType());
- emit("vec");
- emitIRSimpleValue(context, type->getElementCount());
- break;
-
- default:
- // HLSL style: `<elementTypeName><elementCount>`
- // e.g., `int4`
- //
- emitIRSimpleType(context, type->getElementType());
- emitIRSimpleValue(context, type->getElementCount());
- break;
- }
- }
-
- void emitIRMatrixType(
- EmitContext* context,
- IRMatrixType* type)
- {
- // TODO: this is a GLSL-vs-HLSL decision point
-
- emitIRSimpleType(context, type->getElementType());
- emitIRSimpleValue(context, type->getRowCount());
- emit("x");
- emitIRSimpleValue(context, type->getColumnCount());
- }
-
+#if 0
void emitIRType(
EmitContext* context,
IRType* type,
@@ -4287,10 +4298,11 @@ emitDeclImpl(decl, nullptr);
{
emitIRType(context, type, (IRDeclaratorInfo*) nullptr);
}
+#endif
bool shouldFoldIRInstIntoUseSites(
EmitContext* context,
- IRInst* inst)
+ IRValue* inst)
{
// Certain opcodes should always be folded in
switch( inst->op )
@@ -4306,27 +4318,24 @@ emitDeclImpl(decl, nullptr);
return true;
}
- // Certain *types* will usually want to be folded in
+ // Certain *types* will usually want to be folded in,
+ // because they aren't allowed as types for temporary
+ // variables.
auto type = inst->getType();
- switch (type->op)
+ if(type->As<UniformParameterBlockType>())
{
- case kIROp_ConstantBufferType:
- case kIROp_TextureBufferType:
// TODO: we need to be careful here, because
// HLSL shader model 6 allows these as explicit
// types.
return true;
-
- case kIROp_TextureType:
+ }
+ else if(type->As<TextureTypeBase>())
+ {
// GLSL doesn't allow texture/resource types to
// be used as first-class values, so we need
// to fold them into their use sites in all cases
if(getTarget(context) == CodeGenTarget::GLSL)
return true;
- break;
-
- default:
- break;
}
// By default we will *not* fold things into their use sites.
@@ -4335,20 +4344,16 @@ emitDeclImpl(decl, nullptr);
bool isDerefBaseImplicit(
EmitContext* context,
- IRInst* inst)
+ IRValue* inst)
{
auto type = inst->getType();
- switch (type->op)
+
+ if(type->As<UniformParameterBlockType>())
{
- case kIROp_ConstantBufferType:
- case kIROp_TextureBufferType:
// TODO: we need to be careful here, because
// HLSL shader model 6 allows these as explicit
// types.
return true;
-
- default:
- break;
}
return false;
@@ -4358,7 +4363,7 @@ emitDeclImpl(decl, nullptr);
void emitIROperand(
EmitContext* context,
- IRInst* inst)
+ IRValue* inst)
{
if( shouldFoldIRInstIntoUseSites(context, inst) )
{
@@ -4380,8 +4385,8 @@ emitDeclImpl(decl, nullptr);
EmitContext* context,
IRInst* inst)
{
- UInt argCount = inst->argCount - 1;
- IRUse* args = inst->getArgs() + 1;
+ UInt argCount = inst->argCount;
+ IRUse* args = inst->getArgs();
emit("(");
for(UInt aa = 0; aa < argCount; ++aa)
@@ -4392,12 +4397,35 @@ emitDeclImpl(decl, nullptr);
emit(")");
}
+ void emitIRType(
+ EmitContext* context,
+ IRType* type,
+ String const& name)
+ {
+ EmitType(type, name);
+ }
+
+ void emitIRType(
+ EmitContext* context,
+ IRType* type,
+ Name* name)
+ {
+ EmitType(type, name);
+ }
+
+ void emitIRType(
+ EmitContext* context,
+ IRType* type)
+ {
+ EmitType(type);
+ }
+
void emitIRInstResultDecl(
EmitContext* context,
IRInst* inst)
{
auto type = inst->getType();
- if(!type || type->op == kIROp_VoidType)
+ if(!type)
return;
emitIRType(context, type, getName(inst));
@@ -4406,9 +4434,10 @@ emitDeclImpl(decl, nullptr);
void emitIRInstExpr(
EmitContext* context,
- IRInst* inst)
+ IRValue* value)
{
- switch(inst->op)
+ IRInst* inst = (IRInst*) value;
+ switch(value->op)
{
case kIROp_IntLit:
case kIROp_FloatLit:
@@ -4418,13 +4447,13 @@ emitDeclImpl(decl, nullptr);
case kIROp_Construct:
// Simple constructor call
- if( inst->getArgCount() == 2 && getTarget(context) == CodeGenTarget::HLSL)
+ if( inst->getArgCount() == 1 && getTarget(context) == CodeGenTarget::HLSL)
{
// Need to emit as cast for HLSL
emit("(");
emitIRType(context, inst->getType());
emit(") ");
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
}
else
{
@@ -4446,7 +4475,7 @@ emitDeclImpl(decl, nullptr);
emitIRType(context, inst->getType());
}
emit("(");
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit(")");
break;
@@ -4480,9 +4509,9 @@ emitDeclImpl(decl, nullptr);
#define CASE(OPCODE, OP) \
case OPCODE: \
- emitIROperand(context, inst->getArg(1)); \
+ emitIROperand(context, inst->getArg(0)); \
emit("" #OP " "); \
- emitIROperand(context, inst->getArg(2)); \
+ emitIROperand(context, inst->getArg(1)); \
break
CASE(kIROp_Add, +);
@@ -4512,7 +4541,7 @@ emitDeclImpl(decl, nullptr);
case kIROp_Not:
{
- if (inst->getType()->op == kIROp_BoolType)
+ if (inst->getType()->Equals(getSession()->getBoolType()))
{
emit("!");
}
@@ -4520,73 +4549,72 @@ emitDeclImpl(decl, nullptr);
{
emit("~");
}
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
}
break;
case kIROp_Sample:
- // argument 0 is the instruction's type
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit(".Sample(");
- emitIROperand(context, inst->getArg(2));
+ emitIROperand(context, inst->getArg(1));
emit(", ");
- emitIROperand(context, inst->getArg(3));
+ emitIROperand(context, inst->getArg(2));
emit(")");
break;
case kIROp_SampleGrad:
// argument 0 is the instruction's type
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit(".SampleGrad(");
+ emitIROperand(context, inst->getArg(1));
+ emit(", ");
emitIROperand(context, inst->getArg(2));
emit(", ");
emitIROperand(context, inst->getArg(3));
emit(", ");
emitIROperand(context, inst->getArg(4));
- emit(", ");
- emitIROperand(context, inst->getArg(5));
emit(")");
break;
case kIROp_Load:
// TODO: this logic will really only work for a simple variable reference...
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
break;
case kIROp_Store:
// TODO: this logic will really only work for a simple variable reference...
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit(" = ");
- emitIROperand(context, inst->getArg(2));
+ emitIROperand(context, inst->getArg(1));
break;
case kIROp_Call:
{
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit("(");
- UInt argCount = inst->getArgCount() - 2;
+ UInt argCount = inst->getArgCount() - 1;
for( UInt aa = 0; aa < argCount; ++aa )
{
if(aa != 0) emit(", ");
- emitIROperand(context, inst->getArg(aa + 2));
+ emitIROperand(context, inst->getArg(aa + 1));
}
emit(")");
}
break;
case kIROp_BufferLoad:
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit("[");
- emitIROperand(context, inst->getArg(2));
+ emitIROperand(context, inst->getArg(1));
emit("]");
break;
case kIROp_BufferStore:
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit("[");
- emitIROperand(context, inst->getArg(2));
+ emitIROperand(context, inst->getArg(1));
emit("] = ");
- emitIROperand(context, inst->getArg(3));
+ emitIROperand(context, inst->getArg(2));
break;
case kIROp_GroupMemoryBarrierWithGroupSync:
@@ -4595,9 +4623,9 @@ emitDeclImpl(decl, nullptr);
case kIROp_getElement:
case kIROp_getElementPtr:
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit("[");
- emitIROperand(context, inst->getArg(2));
+ emitIROperand(context, inst->getArg(1));
emit("]");
break;
@@ -4605,9 +4633,9 @@ emitDeclImpl(decl, nullptr);
case kIROp_Mul_Matrix_Vector:
case kIROp_Mul_Matrix_Matrix:
emit("mul(");
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit(", ");
- emitIROperand(context, inst->getArg(2));
+ emitIROperand(context, inst->getArg(1));
emit(")");
break;
@@ -4619,7 +4647,7 @@ emitDeclImpl(decl, nullptr);
UInt elementCount = ii->getElementCount();
for (UInt ee = 0; ee < elementCount; ++ee)
{
- IRInst* irElementIndex = ii->getElementIndex(ee);
+ IRValue* irElementIndex = ii->getElementIndex(ee);
assert(irElementIndex->op == kIROp_IntLit);
IRConstant* irConst = (IRConstant*)irElementIndex;
@@ -4658,7 +4686,7 @@ emitDeclImpl(decl, nullptr);
case kIROp_Var:
{
auto ptrType = inst->getType();
- auto valType = ((IRPtrType*)ptrType)->getValueType();
+ auto valType = ((PtrType*)ptrType)->getValueType();
auto name = getName(inst);
emitIRType(context, valType, name);
@@ -4689,14 +4717,14 @@ emitDeclImpl(decl, nullptr);
{
auto ii = (IRSwizzleSet*)inst;
emitIRInstResultDecl(context, inst);
- emitIROperand(context, inst->getArg(1));
+ emitIROperand(context, inst->getArg(0));
emit(";\n");
emitIROperand(context, inst);
emit(".");
UInt elementCount = ii->getElementCount();
for (UInt ee = 0; ee < elementCount; ++ee)
{
- IRInst* irElementIndex = ii->getElementIndex(ee);
+ IRValue* irElementIndex = ii->getElementIndex(ee);
assert(irElementIndex->op == kIROp_IntLit);
IRConstant* irConst = (IRConstant*)irElementIndex;
@@ -4707,34 +4735,16 @@ emitDeclImpl(decl, nullptr);
emit(kComponents[elementIndex]);
}
emit(" = ");
- emitIROperand(context, inst->getArg(2));
+ emitIROperand(context, inst->getArg(1));
emit(";\n");
}
break;
-
-#if 0
- case kIROp_unconditionalBranch:
- emit("// unconditionalBranch ");
- emitIROperand(context, inst->getArg(1));
- emit("\n");
- break;
-
- case kIROp_conditionalBranch:
- emit("// conditionalBranch ");
- emitIROperand(context, inst->getArg(1));
- emit(" ");
- emitIROperand(context, inst->getArg(2));
- emit(" ");
- emitIROperand(context, inst->getArg(3));
- emit("\n");
- break;
-#endif
}
}
void emitIRSemantics(
EmitContext* context,
- IRInst* inst)
+ IRValue* inst)
{
auto decoration = inst->findDecoration<IRHighLevelDeclDecoration>();
if( decoration )
@@ -4745,7 +4755,7 @@ emitDeclImpl(decl, nullptr);
VarLayout* getVarLayout(
EmitContext* context,
- IRInst* var)
+ IRValue* var)
{
auto decoration = var->findDecoration<IRLayoutDecoration>();
if (!decoration)
@@ -4756,7 +4766,7 @@ emitDeclImpl(decl, nullptr);
void emitIRLayoutSemantics(
EmitContext* context,
- IRInst* inst,
+ IRValue* inst,
char const* uniformSemanticSpelling = "register")
{
auto layout = getVarLayout(context, inst);
@@ -4784,9 +4794,9 @@ emitDeclImpl(decl, nullptr);
while(block != end)
{
// Start by emitting the non-terminator instructions in the block.
- auto terminator = block->lastChild;
+ auto terminator = block->getLastInst();
assert(isTerminatorInst(terminator));
- for (auto inst = block->firstChild; inst != terminator; inst = inst->nextInst)
+ for (auto inst = block->getFirstInst(); inst != terminator; inst = inst->nextInst)
{
emitIRInst(context, inst);
}
@@ -5095,10 +5105,8 @@ emitDeclImpl(decl, nullptr);
// encoded as a parameter of pointer type, so
// we need to decode that here.
//
- if( paramType->op == kIROp_PtrType )
+ if( auto ptrType = paramType->As<PtrType>() )
{
- auto ptrType = (IRPtrType*) paramType;
-
// TODO: we need a way to distinguish `out`
// from `inout`. The easiest way to do
// that might be to have each be a distinct
@@ -5243,7 +5251,7 @@ emitDeclImpl(decl, nullptr);
}
}
-
+#if 0
void emitIRStruct(
EmitContext* context,
IRStructDecl* structType)
@@ -5263,6 +5271,7 @@ emitDeclImpl(decl, nullptr);
}
emit("};\n");
}
+#endif
void emitIRVarModifiers(
EmitContext* context,
@@ -5317,9 +5326,9 @@ emitDeclImpl(decl, nullptr);
}
void emitIRParameterBlock(
- EmitContext* context,
- IRVar* varDecl,
- IRUniformBufferType* type)
+ EmitContext* context,
+ IRGlobalVar* varDecl,
+ UniformParameterBlockType* type)
{
emit("cbuffer ");
emit(getName(varDecl));
@@ -5341,17 +5350,15 @@ emitDeclImpl(decl, nullptr);
typeLayout = parameterBlockTypeLayout->elementTypeLayout;
}
- switch( elementType->op )
+ if(auto declRefType = elementType->As<DeclRefType>())
{
- case kIROp_StructType:
+ if(auto structDeclRef = declRefType->declRef.As<StructDecl>())
{
- auto structType = (IRStructDecl*) elementType;
-
auto structTypeLayout = typeLayout.As<StructTypeLayout>();
assert(structTypeLayout);
UInt fieldIndex = 0;
- for(auto ff = structType->getFirstField(); ff; ff = ff->getNextField())
+ for(auto ff : GetFields(structDeclRef))
{
// TODO: need a plan to deal with the case where the IR-level
// `struct` type might not match the high-level type, so that
@@ -5367,19 +5374,18 @@ emitDeclImpl(decl, nullptr);
emitIRVarModifiers(context, fieldLayout);
- auto fieldType = ff->getFieldType();
- emitIRType(context, fieldType, getName(ff));
+ auto fieldType = GetType(ff);
+ emitIRType(context, fieldType, ff.GetName());
emitHLSLParameterBlockFieldLayoutSemantics(layout, fieldLayout);
emit(";\n");
}
}
- break;
-
- default:
+ }
+ else
+ {
emit("/* unexpected */");
- break;
}
emit("}\n");
@@ -5391,8 +5397,9 @@ emitDeclImpl(decl, nullptr);
{
auto allocatedType = varDecl->getType();
auto varType = allocatedType->getValueType();
- auto addressSpace = allocatedType->getAddressSpace();
+// auto addressSpace = allocatedType->getAddressSpace();
+#if 0
switch( varType->op )
{
case kIROp_ConstantBufferType:
@@ -5403,6 +5410,7 @@ emitDeclImpl(decl, nullptr);
default:
break;
}
+#endif
// Need to emit appropriate modifiers here.
@@ -5410,6 +5418,7 @@ emitDeclImpl(decl, nullptr);
emitIRVarModifiers(context, layout);
+#if 0
switch (addressSpace)
{
default:
@@ -5419,6 +5428,51 @@ emitDeclImpl(decl, nullptr);
emit("groupshared ");
break;
}
+#endif
+
+ emitIRType(context, varType, getName(varDecl));
+
+ emitIRSemantics(context, varDecl);
+
+ emitIRLayoutSemantics(context, varDecl);
+
+ emit(";\n");
+ }
+
+ void emitIRGlobalVar(
+ EmitContext* context,
+ IRGlobalVar* varDecl)
+ {
+ auto allocatedType = varDecl->getType();
+ auto varType = allocatedType->getValueType();
+// auto addressSpace = allocatedType->getAddressSpace();
+
+ if (auto paramBlockType = varType->As<UniformParameterBlockType>())
+ {
+ emitIRParameterBlock(
+ context,
+ varDecl,
+ paramBlockType);
+ return;
+ }
+
+ // Need to emit appropriate modifiers here.
+
+ auto layout = getVarLayout(context, varDecl);
+
+ emitIRVarModifiers(context, layout);
+
+#if 0
+ switch (addressSpace)
+ {
+ default:
+ break;
+
+ case kIRAddressSpace_GroupShared:
+ emit("groupshared ");
+ break;
+ }
+#endif
emitIRType(context, varType, getName(varDecl));
@@ -5431,7 +5485,7 @@ emitDeclImpl(decl, nullptr);
void emitIRGlobalInst(
EmitContext* context,
- IRInst* inst)
+ IRGlobalValue* inst)
{
// TODO: need to be able to `switch` on the IR opcode here,
// so there is some work to be done.
@@ -5441,9 +5495,15 @@ emitDeclImpl(decl, nullptr);
emitIRFunc(context, (IRFunc*) inst);
break;
+ case kIROp_global_var:
+ emitIRGlobalVar(context, (IRGlobalVar*) inst);
+ break;
+
+#if 0
case kIROp_StructType:
emitIRStruct(context, (IRStructDecl*) inst);
break;
+#endif
case kIROp_Var:
emitIRVar(context, (IRVar*) inst);
@@ -5454,13 +5514,154 @@ emitDeclImpl(decl, nullptr);
}
}
+ void ensureStructDecl(
+ EmitContext* context,
+ DeclRef<StructDecl> declRef)
+ {
+ // TODO: Eventually need to deal with the case where
+ // we have user-defined generic types.
+ //
+ auto decl = declRef.getDecl();
+
+ if(context->shared->irDeclsVisited.Contains(decl))
+ return;
+
+ context->shared->irDeclsVisited.Add(decl);
+
+ // First emit any types used by fields of this type
+ for( auto ff : GetFields(declRef) )
+ {
+ if(ff.getDecl()->HasModifier<HLSLStaticModifier>())
+ continue;
+
+ auto fieldType = GetType(ff);
+ emitIRUsedType(context, fieldType);
+ }
+
+ Emit("struct ");
+ emit(declRef.GetName());
+ Emit("\n{\n");
+ for( auto ff : GetFields(declRef) )
+ {
+ if(ff.getDecl()->HasModifier<HLSLStaticModifier>())
+ continue;
+
+ auto fieldType = GetType(ff);
+ emitIRType(context, fieldType, ff.GetName());
+
+ EmitSemantics(ff.getDecl());
+
+ emit(";\n");
+ }
+ Emit("};\n");
+ }
+
+ // A type is going to be used by the IR, so
+ // make sure that we have emitted whatever
+ // it needs.
+ void emitIRUsedType(
+ EmitContext* context,
+ Type* type)
+ {
+ if(type->As<BasicExpressionType>())
+ {}
+ else if(type->As<VectorExpressionType>())
+ {}
+ else if(type->As<MatrixExpressionType>())
+ {}
+ else if(auto arrayType = type->As<ArrayExpressionType>())
+ {
+ emitIRUsedType(context, arrayType->baseType);
+ }
+ else if( auto textureType = type->As<TextureTypeBase>() )
+ {
+ emitIRUsedType(context, textureType->elementType);
+ }
+ else if( auto genericType = type->As<BuiltinGenericType>() )
+ {
+ emitIRUsedType(context, genericType->elementType);
+ }
+ else if( auto ptrType = type->As<PtrType>() )
+ {
+ emitIRUsedType(context, ptrType->getValueType());
+ }
+ else if(type->As<SamplerStateType>() )
+ {
+ }
+ else if( auto declRefType = type->As<DeclRefType>() )
+ {
+ auto declRef = declRefType->declRef;
+ auto decl = declRef.getDecl();
+
+ if(decl->HasModifier<BuiltinTypeModifier>()
+ || decl->HasModifier<MagicTypeModifier>())
+ {
+ return;
+ }
+
+ if( auto structDeclRef = declRef.As<StructDecl>() )
+ {
+ //
+ ensureStructDecl(context, structDeclRef);
+ }
+ }
+ else
+ {}
+ }
+
+ void emitIRUsedTypesForValue(
+ EmitContext* context,
+ IRValue* value)
+ {
+ if(!value) return;
+ switch( value->op )
+ {
+ case kIROp_Func:
+ {
+ auto irFunc = (IRFunc*) value;
+ emitIRUsedType(context, irFunc->getResultType());
+ for( auto bb = irFunc->getFirstBlock(); bb; bb = bb->getNextBlock() )
+ {
+ for( auto pp = bb->getFirstParam(); pp; pp = pp->getNextParam() )
+ {
+ emitIRUsedTypesForValue(context, pp);
+ }
+
+ for( auto ii = bb->getFirstInst(); ii; ii = ii->nextInst )
+ {
+ emitIRUsedTypesForValue(context, ii);
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ emitIRUsedType(context, value->type);
+ }
+ break;
+ }
+ }
+
+ void emitIRUsedTypesForModule(
+ EmitContext* context,
+ IRModule* module)
+ {
+ for (auto gv : module->globalValues)
+ {
+ emitIRUsedTypesForValue(context, gv);
+ }
+ }
+
void emitIRModule(
EmitContext* context,
IRModule* module)
{
- for(auto ii = module->firstChild; ii; ii = ii->nextInst )
+ emitIRUsedTypesForModule(context, module);
+
+ for (auto gv : module->globalValues)
{
- emitIRGlobalInst(context, ii);
+ emitIRGlobalInst(context, gv);
}
}