summaryrefslogtreecommitdiffstats
path: root/source/slang
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang')
-rw-r--r--source/slang/slang-emit-spirv.cpp27
-rw-r--r--source/slang/slang-ir-any-value-marshalling.cpp18
-rw-r--r--source/slang/slang-ir-augment-make-existential.cpp6
-rw-r--r--source/slang/slang-ir-bind-existentials.cpp8
-rw-r--r--source/slang/slang-ir-byte-address-legalize.cpp9
-rw-r--r--source/slang/slang-ir-clone.cpp12
-rw-r--r--source/slang/slang-ir-collect-global-uniforms.cpp9
-rw-r--r--source/slang/slang-ir-constexpr.cpp17
-rw-r--r--source/slang/slang-ir-deduplicate.cpp16
-rw-r--r--source/slang/slang-ir-generics-lowering-context.cpp3
-rw-r--r--source/slang/slang-ir-generics-lowering-context.h3
-rw-r--r--source/slang/slang-ir-glsl-legalize.cpp19
-rw-r--r--source/slang/slang-ir-hoist-local-types.cpp10
-rw-r--r--source/slang/slang-ir-inline.cpp7
-rw-r--r--source/slang/slang-ir-insts.h195
-rw-r--r--source/slang/slang-ir-layout.cpp22
-rw-r--r--source/slang/slang-ir-legalize-types.cpp5
-rw-r--r--source/slang/slang-ir-legalize-varying-params.cpp4
-rw-r--r--source/slang/slang-ir-link.cpp14
-rw-r--r--source/slang/slang-ir-lower-bit-cast.cpp6
-rw-r--r--source/slang/slang-ir-lower-existential.cpp15
-rw-r--r--source/slang/slang-ir-lower-generic-call.cpp9
-rw-r--r--source/slang/slang-ir-lower-generic-function.cpp12
-rw-r--r--source/slang/slang-ir-lower-generic-type.cpp6
-rw-r--r--source/slang/slang-ir-lower-generics.cpp9
-rw-r--r--source/slang/slang-ir-lower-reinterpret.cpp6
-rw-r--r--source/slang/slang-ir-lower-tuple-types.cpp12
-rw-r--r--source/slang/slang-ir-restructure-scoping.cpp7
-rw-r--r--source/slang/slang-ir-sccp.cpp5
-rw-r--r--source/slang/slang-ir-specialize-dispatch.cpp9
-rw-r--r--source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp18
-rw-r--r--source/slang/slang-ir-specialize-function-call.cpp23
-rw-r--r--source/slang/slang-ir-specialize-resources.cpp3
-rw-r--r--source/slang/slang-ir-specialize.cpp43
-rw-r--r--source/slang/slang-ir-spirv-legalize.cpp18
-rw-r--r--source/slang/slang-ir-ssa.cpp12
-rw-r--r--source/slang/slang-ir-string-hash.cpp14
-rw-r--r--source/slang/slang-ir-synthesize-active-mask.cpp24
-rw-r--r--source/slang/slang-ir-type-set.cpp17
-rw-r--r--source/slang/slang-ir-union.cpp5
-rw-r--r--source/slang/slang-ir-validate.cpp4
-rw-r--r--source/slang/slang-ir-witness-table-wrapper.cpp9
-rw-r--r--source/slang/slang-ir-wrap-structured-buffers.cpp9
-rw-r--r--source/slang/slang-ir.cpp359
-rw-r--r--source/slang/slang-ir.h224
-rw-r--r--source/slang/slang-lower-to-ir.cpp74
-rw-r--r--source/slang/slang-lower-to-ir.h2
-rw-r--r--source/slang/slang-serialize-ir.cpp73
-rw-r--r--source/slang/slang.cpp2
49 files changed, 796 insertions, 637 deletions
diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp
index 21f5c1bc8..38e60649a 100644
--- a/source/slang/slang-emit-spirv.cpp
+++ b/source/slang/slang-emit-spirv.cpp
@@ -1209,8 +1209,7 @@ struct SPIRVEmitContext
{
if (!inst)
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertInto(m_irModule->getModuleInst());
inst = builder.getVectorType(
builder.getBasicType(baseType),
@@ -1970,8 +1969,7 @@ struct SPIRVEmitContext
{
return result;
}
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertBefore(type);
auto ptrType = as<IRPtrTypeBase>(type);
SLANG_ASSERT(ptrType && "`getBuiltinGlobalVar`: `type` must be ptr type.");
@@ -1995,8 +1993,7 @@ struct SPIRVEmitContext
SpvInst* maybeEmitSystemVal(IRInst* inst)
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertBefore(inst);
if (auto layout = getVarLayout(inst))
{
@@ -2214,8 +2211,7 @@ struct SPIRVEmitContext
{
for (auto storageClass : snippet->usedResultTypeStorageClasses)
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertBefore(inst);
auto newPtrType = builder.getPtrType(
oldPtrType->getOp(), oldPtrType->getValueType(), storageClass);
@@ -2234,8 +2230,7 @@ struct SPIRVEmitContext
if (m_spvSnippetConstantInsts.TryGetValue(constant, result))
return result;
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertInto(m_irModule->getModuleInst());
switch (constant.type)
{
@@ -2282,8 +2277,7 @@ struct SPIRVEmitContext
// Emit SPV Inst that represents a type defined in a SpvSnippet.
void emitSpvSnippetASMTypeOperand(SpvSnippet::ASMType type)
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertInto(m_irModule->getModuleInst());
IRType* irType = nullptr;
switch (type)
@@ -2449,8 +2443,7 @@ struct SPIRVEmitContext
SpvInst* emitFieldAddress(SpvInstParent* parent, IRFieldAddress* fieldAddress)
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertBefore(fieldAddress);
auto base = fieldAddress->getBase();
@@ -2493,8 +2486,7 @@ struct SPIRVEmitContext
SpvInst* emitFieldExtract(SpvInstParent* parent, IRFieldExtract* inst)
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertBefore(inst);
IRStructType* baseStructType = as<IRStructType>(inst->getBase()->getDataType());
@@ -2566,8 +2558,7 @@ struct SPIRVEmitContext
}
SLANG_ASSERT(baseArrayType && "getElement require base to be an array.");
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedIRBuilder;
+ IRBuilder builder(m_sharedIRBuilder);
builder.setInsertBefore(inst);
auto ptr = emitInst(
diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp
index 2c6dcb84c..b61f0b273 100644
--- a/source/slang/slang-ir-any-value-marshalling.cpp
+++ b/source/slang/slang-ir-any-value-marshalling.cpp
@@ -52,8 +52,7 @@ namespace Slang
if (auto typeInfo = generatedAnyValueTypes.TryGetValue(size))
return typeInfo->Ptr();
RefPtr<AnyValueTypeInfo> info = new AnyValueTypeInfo();
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(type);
auto structType = builder.createStructType();
info->type = structType;
@@ -344,8 +343,7 @@ namespace Slang
IRFunc* generatePackingFunc(IRType* type, IRAnyValueType* anyValueType)
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(type);
auto anyValInfo = ensureAnyValueType(anyValueType);
@@ -507,8 +505,7 @@ namespace Slang
IRFunc* generateUnpackingFunc(IRType* type, IRAnyValueType* anyValueType)
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(type);
auto anyValInfo = ensureAnyValueType(anyValueType);
@@ -563,9 +560,8 @@ namespace Slang
auto func = ensureMarshallingFunc(
operand->getDataType(),
cast<IRAnyValueType>(packInst->getDataType()));
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(packInst);
auto callInst = builder->emitCallInst(packInst->getDataType(), func.packFunc, 1, &operand);
packInst->replaceUsesWith(callInst);
@@ -578,9 +574,8 @@ namespace Slang
auto func = ensureMarshallingFunc(
unpackInst->getDataType(),
cast<IRAnyValueType>(operand->getDataType()));
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(unpackInst);
auto callInst = builder->emitCallInst(unpackInst->getDataType(), func.unpackFunc, 1, &operand);
unpackInst->replaceUsesWith(callInst);
@@ -612,8 +607,7 @@ namespace Slang
// generate along the way.
//
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
+ sharedBuilder->init(sharedContext->module);
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
diff --git a/source/slang/slang-ir-augment-make-existential.cpp b/source/slang/slang-ir-augment-make-existential.cpp
index 2fe820721..c088a1650 100644
--- a/source/slang/slang-ir-augment-make-existential.cpp
+++ b/source/slang/slang-ir-augment-make-existential.cpp
@@ -24,9 +24,8 @@ struct AugmentMakeExistentialContext
void processMakeExistential(IRMakeExistential* inst)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(inst);
auto augInst = builder->emitMakeExistentialWithRTTI(
@@ -53,8 +52,7 @@ struct AugmentMakeExistentialContext
void processModule()
{
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = module;
- sharedBuilder->session = module->session;
+ sharedBuilder->init(module);
addToWorkList(module->getModuleInst());
diff --git a/source/slang/slang-ir-bind-existentials.cpp b/source/slang/slang-ir-bind-existentials.cpp
index 2ceda3c06..7af93037b 100644
--- a/source/slang/slang-ir-bind-existentials.cpp
+++ b/source/slang/slang-ir-bind-existentials.cpp
@@ -275,12 +275,8 @@ struct BindExistentialSlots
auto fullType = inst->getFullType();
- SharedIRBuilder sharedBuilder;
- sharedBuilder.session = module->getSession();
- sharedBuilder.module = module;
-
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ SharedIRBuilder sharedBuilder(module);
+ IRBuilder builder(sharedBuilder);
// Every argument that is filling an existential
// type param/slot comprises both a type and
diff --git a/source/slang/slang-ir-byte-address-legalize.cpp b/source/slang/slang-ir-byte-address-legalize.cpp
index da0689a5b..42382d91c 100644
--- a/source/slang/slang-ir-byte-address-legalize.cpp
+++ b/source/slang/slang-ir-byte-address-legalize.cpp
@@ -39,10 +39,8 @@ struct ByteAddressBufferLegalizationContext
//
void processModule(IRModule* module)
{
- m_sharedBuilder.session = m_session;
- m_sharedBuilder.module = module;
-
- m_builder.sharedBuilder = &m_sharedBuilder;
+ m_sharedBuilder.init(module);
+ m_builder.init(m_sharedBuilder);
processInstRec(module->getModuleInst());
}
@@ -704,8 +702,7 @@ struct ByteAddressBufferLegalizationContext
// of legalizing a load or store, and we don't want to mess with
// the insertion location of `m_builder`.
//
- IRBuilder paramBuilder;
- paramBuilder.sharedBuilder = &m_sharedBuilder;
+ IRBuilder paramBuilder(m_sharedBuilder);
paramBuilder.setInsertBefore(byteAddressBufferParam);
auto structuredBufferParam = paramBuilder.createGlobalParam(structuredBufferParamType);
diff --git a/source/slang/slang-ir-clone.cpp b/source/slang/slang-ir-clone.cpp
index a6c462501..c8b0ba401 100644
--- a/source/slang/slang-ir-clone.cpp
+++ b/source/slang/slang-ir-clone.cpp
@@ -134,9 +134,8 @@ static void _cloneInstDecorationsAndChildren(
// We will set up an IR builder that inserts
// into the new parent instruction.
//
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilder);
auto builder = &builderStorage;
- builder->sharedBuilder = sharedBuilder;
builder->setInsertInto(newInst);
// If `newInst` already has non-decoration children, we want to
@@ -264,7 +263,7 @@ IRInst* cloneInst(
env->mapOldValToNew.Add(oldInst, newInst);
cloneInstDecorationsAndChildren(
- env, builder->sharedBuilder, oldInst, newInst);
+ env, builder->getSharedBuilder(), oldInst, newInst);
return newInst;
}
@@ -274,11 +273,8 @@ void cloneDecoration(
IRInst* newParent,
IRModule* module)
{
- SharedIRBuilder sharedBuilder;
- sharedBuilder.module = module;
-
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ SharedIRBuilder sharedBuilder(module);
+ IRBuilder builder(sharedBuilder);
if(auto first = newParent->getFirstDecorationOrChild())
builder.setInsertBefore(first);
diff --git a/source/slang/slang-ir-collect-global-uniforms.cpp b/source/slang/slang-ir-collect-global-uniforms.cpp
index a845dd43b..88ebe9940 100644
--- a/source/slang/slang-ir-collect-global-uniforms.cpp
+++ b/source/slang/slang-ir-collect-global-uniforms.cpp
@@ -122,14 +122,9 @@ struct CollectGlobalUniformParametersContext
// the collected global-scope parameters. The `IRBuilder` we construct
// for this will also be used when replacing the individual parameters.
//
- SharedIRBuilder sharedBuilder;
- sharedBuilder.module = this->module;
- sharedBuilder.session = module->session;
-
- IRBuilder builderStorage;
+ SharedIRBuilder sharedBuilder(module);
+ IRBuilder builderStorage(sharedBuilder);
IRBuilder* builder = &builderStorage;
-
- builder->sharedBuilder = &sharedBuilder;
builder->setInsertInto(module->getModuleInst());
// The packaged-up global parameters will be turned into fields of
diff --git a/source/slang/slang-ir-constexpr.cpp b/source/slang/slang-ir-constexpr.cpp
index 98af664d7..bc669fa6b 100644
--- a/source/slang/slang-ir-constexpr.cpp
+++ b/source/slang/slang-ir-constexpr.cpp
@@ -21,7 +21,7 @@ struct PropagateConstExprContext
IRBuilder* getBuilder() { return &builder; }
- Session* getSession() { return sharedBuilder.session; }
+ Session* getSession() { return sharedBuilder.getSession(); }
DiagnosticSink* getSink() { return sink; }
};
@@ -229,12 +229,9 @@ bool propagateConstExprBackward(
PropagateConstExprContext* context,
IRGlobalValueWithCode* code)
{
- SharedIRBuilder sharedBuilder;
- sharedBuilder.module = context->getModule();
- sharedBuilder.session = sharedBuilder.module->session;
+ SharedIRBuilder sharedBuilder(context->getModule());
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ IRBuilder builder(sharedBuilder);
builder.setInsertInto(code);
bool anyChanges = false;
@@ -454,15 +451,11 @@ void propagateConstExpr(
IRModule* module,
DiagnosticSink* sink)
{
- auto session = module->session;
-
PropagateConstExprContext context;
context.module = module;
context.sink = sink;
- context.sharedBuilder.module = module;
- context.sharedBuilder.session = session;
- context.builder.sharedBuilder = &context.sharedBuilder;
-
+ context.sharedBuilder.init(module);
+ context.builder.init(context.sharedBuilder);
// We need to propagate information both forward and backward.
//
diff --git a/source/slang/slang-ir-deduplicate.cpp b/source/slang/slang-ir-deduplicate.cpp
index 7f676477c..953344850 100644
--- a/source/slang/slang-ir-deduplicate.cpp
+++ b/source/slang/slang-ir-deduplicate.cpp
@@ -18,9 +18,9 @@ namespace Slang
{
IRConstantKey key = { value };
value->setFullType((IRType*)addValue(value->getFullType()));
- if (auto newValue = builder->constantMap.TryGetValue(key))
+ if (auto newValue = builder->getConstantMap().TryGetValue(key))
return *newValue;
- builder->constantMap[key] = value;
+ builder->getConstantMap()[key] = value;
return value;
}
IRInst* addTypeValue(IRInst* value)
@@ -41,9 +41,9 @@ namespace Slang
}
value->setFullType((IRType*)addValue(value->getFullType()));
IRInstKey key = { value };
- if (auto newValue = builder->globalValueNumberingMap.TryGetValue(key))
+ if (auto newValue = builder->getGlobalValueNumberingMap().TryGetValue(key))
return *newValue;
- builder->globalValueNumberingMap[key] = value;
+ builder->getGlobalValueNumberingMap()[key] = value;
return value;
}
};
@@ -52,9 +52,9 @@ namespace Slang
DeduplicateContext context;
context.builder = this;
bool changed = true;
- constantMap.Clear();
- globalValueNumberingMap.Clear();
- for (auto inst : module->getGlobalInsts())
+ m_constantMap.Clear();
+ m_globalValueNumberingMap.Clear();
+ for (auto inst : m_module->getGlobalInsts())
{
if (auto constVal = as<IRConstant>(inst))
{
@@ -62,7 +62,7 @@ namespace Slang
}
}
List<IRInst*> instToRemove;
- for (auto inst : module->getGlobalInsts())
+ for (auto inst : m_module->getGlobalInsts())
{
if (as<IRType>(inst))
{
diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp
index 0633dbc10..4fb4e007b 100644
--- a/source/slang/slang-ir-generics-lowering-context.cpp
+++ b/source/slang/slang-ir-generics-lowering-context.cpp
@@ -57,9 +57,8 @@ namespace Slang
IRInst* result = nullptr;
if (mapTypeToRTTIObject.TryGetValue(typeInst, result))
return result;
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(typeInst->next);
result = builder->emitMakeRTTIObject(typeInst);
diff --git a/source/slang/slang-ir-generics-lowering-context.h b/source/slang/slang-ir-generics-lowering-context.h
index c875566b0..23bdcc78b 100644
--- a/source/slang/slang-ir-generics-lowering-context.h
+++ b/source/slang/slang-ir-generics-lowering-context.h
@@ -107,8 +107,7 @@ namespace Slang
void workOnModule(SharedGenericsLoweringContext* sharedContext, const TFunc& func)
{
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
+ sharedBuilder->init(sharedContext->module);
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp
index 052b4fb29..bb40ecca9 100644
--- a/source/slang/slang-ir-glsl-legalize.cpp
+++ b/source/slang/slang-ir-glsl-legalize.cpp
@@ -17,14 +17,9 @@ IRGlobalParam* addGlobalParam(
IRModule* module,
IRType* valueType)
{
- auto session = module->session;
+ SharedIRBuilder shared(module);
+ IRBuilder builder(shared);
- SharedIRBuilder shared;
- shared.module = module;
- shared.session = session;
-
- IRBuilder builder;
- builder.sharedBuilder = &shared;
return builder.createGlobalParam(valueType);
}
@@ -1597,8 +1592,7 @@ void legalizeEntryPointParameterForGLSL(
// disrupt the source location it is using for inserting
// temporary variables at the top of the function.
//
- IRBuilder terminatorBuilder;
- terminatorBuilder.sharedBuilder = builder->sharedBuilder;
+ IRBuilder terminatorBuilder(builder->getSharedBuilder());
terminatorBuilder.setInsertBefore(terminatorInst);
// Assign from the local variabel to the global output
@@ -1668,11 +1662,8 @@ void legalizeEntryPointForGLSL(
//
// TODO: make some of these free functions...
//
- SharedIRBuilder shared;
- shared.module = module;
- shared.session = session;
- IRBuilder builder;
- builder.sharedBuilder = &shared;
+ SharedIRBuilder shared(module);
+ IRBuilder builder(shared);
builder.setInsertInto(func);
context.builder = &builder;
diff --git a/source/slang/slang-ir-hoist-local-types.cpp b/source/slang/slang-ir-hoist-local-types.cpp
index 0293703ea..756a25c49 100644
--- a/source/slang/slang-ir-hoist-local-types.cpp
+++ b/source/slang/slang-ir-hoist-local-types.cpp
@@ -38,21 +38,20 @@ struct HoistLocalTypesContext
if (inst->getParent() == module->getModuleInst())
return;
IRInstKey key = {inst};
- if (auto value = sharedBuilder->globalValueNumberingMap.TryGetValue(key))
+ if (auto value = sharedBuilder->getGlobalValueNumberingMap().TryGetValue(key))
{
inst->replaceUsesWith(*value);
inst->removeAndDeallocate();
return;
}
- IRBuilder builder;
- builder.sharedBuilder = sharedBuilder;
+ IRBuilder builder(sharedBuilder);
builder.setInsertInto(module->getModuleInst());
bool hoistable = true;
ShortList<IRInst*> mappedOperands;
for (UInt i = 0; i < inst->getOperandCount(); i++)
{
IRInstKey opKey = {inst->getOperand(i)};
- if (auto value = sharedBuilder->globalValueNumberingMap.TryGetValue(opKey))
+ if (auto value = sharedBuilder->getGlobalValueNumberingMap().TryGetValue(opKey))
{
mappedOperands.add(*value);
}
@@ -75,8 +74,7 @@ struct HoistLocalTypesContext
void processModule()
{
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = module;
- sharedBuilder->session = module->session;
+ sharedBuilder->init(module);
// Deduplicate equivalent types and build numbering map for global types.
sharedBuilder->deduplicateAndRebuildGlobalNumberingMap();
diff --git a/source/slang/slang-ir-inline.cpp b/source/slang/slang-ir-inline.cpp
index d61fe7f79..a8347438b 100644
--- a/source/slang/slang-ir-inline.cpp
+++ b/source/slang/slang-ir-inline.cpp
@@ -230,11 +230,8 @@ struct InliningPassBase
// and will set it up to insert before the `call` that
// is going to be replaced.
//
- SharedIRBuilder sharedBuilder;
- sharedBuilder.session = m_module->getSession();
- sharedBuilder.module = m_module;
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ SharedIRBuilder sharedBuilder(m_module);
+ IRBuilder builder(sharedBuilder);
builder.setInsertBefore(call);
// If the callee is a generic function, then we will
diff --git a/source/slang/slang-ir-insts.h b/source/slang/slang-ir-insts.h
index 36ffcbbaf..cbcefa56a 100644
--- a/source/slang/slang-ir-insts.h
+++ b/source/slang/slang-ir-insts.h
@@ -1787,79 +1787,194 @@ struct IRConstantKey
struct SharedIRBuilder
{
+public:
SharedIRBuilder()
{}
- SharedIRBuilder(Session* session, IRModule* module)
- : session(session)
- , module(module)
- {}
-
explicit SharedIRBuilder(IRModule* module)
- : session(module->getSession())
- , module(module)
- {}
+ {
+ init(module);
+ }
- // The parent compilation session
- Session* session;
- Session* getSession()
+ void init(IRModule* module)
{
- return session;
+ m_module = module;
+ m_session = module->getSession();
+
+ m_globalValueNumberingMap.Clear();
+ m_constantMap.Clear();
}
- // The module that will own all of the IR
- IRModule* module;
+ IRModule* getModule()
+ {
+ return m_module;
+ }
- Dictionary<IRInstKey, IRInst*> globalValueNumberingMap;
- Dictionary<IRConstantKey, IRConstant*> constantMap;
+ Session* getSession()
+ {
+ return m_session;
+ }
void insertBlockAlongEdge(IREdge const& edge);
// Rebuilds `globalValueNumberingMap`. This is necessary if any existing
// keys are modified (thus its hash code is changed).
void deduplicateAndRebuildGlobalNumberingMap();
+
+ typedef Dictionary<IRInstKey, IRInst*> GlobalValueNumberingMap;
+ typedef Dictionary<IRConstantKey, IRConstant*> ConstantMap;
+
+ GlobalValueNumberingMap& getGlobalValueNumberingMap() { return m_globalValueNumberingMap; }
+ ConstantMap& getConstantMap() { return m_constantMap; }
+
+private:
+ // The module that will own all of the IR
+ IRModule* m_module;
+
+ // The parent compilation session
+ Session* m_session;
+
+ GlobalValueNumberingMap m_globalValueNumberingMap;
+ ConstantMap m_constantMap;
};
struct IRBuilderSourceLocRAII;
struct IRBuilder
{
+private:
+ /// Shared state for all IR builders working on the same module
+ SharedIRBuilder* m_sharedBuilder = nullptr;
+
+ /// Default location for inserting new instructions as they are emitted
+ IRInsertLoc m_insertLoc;
+
+ /// Information that controls how source locations are associatd with instructions that get emitted
+ IRBuilderSourceLocRAII* m_sourceLocInfo = nullptr;
+
+public:
IRBuilder()
{}
- IRBuilder(SharedIRBuilder* sharedBuilder)
- : sharedBuilder(sharedBuilder)
+ explicit IRBuilder(SharedIRBuilder* sharedBuilder)
+ : m_sharedBuilder(sharedBuilder)
{}
- // Shared state for all IR builders working on the same module
- SharedIRBuilder* sharedBuilder = nullptr;
+ explicit IRBuilder(SharedIRBuilder& sharedBuilder)
+ : m_sharedBuilder(&sharedBuilder)
+ {}
- Session* getSession()
+ void init(SharedIRBuilder* sharedBuilder)
{
- return sharedBuilder->getSession();
+ *this = IRBuilder(sharedBuilder);
}
- IRModule* getModule() { return sharedBuilder->module; }
+ void init(SharedIRBuilder& sharedBuilder)
+ {
+ *this = IRBuilder(sharedBuilder);
+ }
- // The current parent being inserted into (this might
- // be the global scope, a function, a block inside
- // a function, etc.)
- IRInst* insertIntoParent = nullptr;
- //
- // An instruction in the current parent that we should insert before
- IRInst* insertBeforeInst = nullptr;
+ SharedIRBuilder* getSharedBuilder() const
+ {
+ return m_sharedBuilder;
+ }
+
+ Session* getSession() const
+ {
+ return m_sharedBuilder->getSession();
+ }
+
+ IRModule* getModule() const
+ {
+ return m_sharedBuilder->getModule();
+ }
+
+ IRInsertLoc const& getInsertLoc() const { return m_insertLoc; }
+
+ void setInsertLoc(IRInsertLoc const& loc) { m_insertLoc = loc; }
// Get the current basic block we are inserting into (if any)
- IRBlock* getBlock();
+ IRBlock* getBlock() { return m_insertLoc.getBlock(); }
// Get the current function (or other value with code)
// that we are inserting into (if any).
- IRGlobalValueWithCode* getFunc();
+ IRGlobalValueWithCode* getFunc() { return m_insertLoc.getFunc(); }
+
+ void setInsertInto(IRInst* insertInto) { setInsertLoc(IRInsertLoc::atEnd(insertInto)); }
+ void setInsertBefore(IRInst* insertBefore) { setInsertLoc(IRInsertLoc::before(insertBefore)); }
+
+ void setInsertInto(IRModule* module) { setInsertInto(module->getModuleInst()); }
+
+ IRBuilderSourceLocRAII* getSourceLocInfo() const { return m_sourceLocInfo; }
+ void setSourceLocInfo(IRBuilderSourceLocRAII* sourceLocInfo) { m_sourceLocInfo = sourceLocInfo; }
+
+ //
+ // Low-level interface for instruction creation/insertion.
+ //
+
+ /// Either find or create an `IRConstant` that matches the value of `keyInst`.
+ ///
+ /// This operation will re-use an existing constant with the same type and
+ /// value if one can be found (currently identified through the `SharedIRBuilder`).
+ /// Otherwise it will create a new `IRConstant` with the given value and register it.
+ ///
+ IRConstant* _findOrEmitConstant(
+ IRConstant& keyInst);
+
+ /// Create a new instruction with the given `type` and `op`, with an allocated
+ /// size of at least `minSizeInBytes`, and with its operand list initialized
+ /// from the provided lists of "fixed" and "variable" operands.
+ ///
+ /// The `fixedArgs` array must contain `fixedArgCount` operands, and will be
+ /// the initial operands in the operand list of the instruction.
+ ///
+ /// After the fixed arguments, the instruction may have zero or more additional
+ /// lists of "variable" operands, which are all concatenated. The total number
+ /// of such additional lists is given by `varArgsListCount`. The number of
+ /// operands in list `i` is given by `listArgCounts[i]`, and the arguments in
+ /// list `i` are pointed to by `listArgs[i]`.
+ ///
+ /// The allocation for the instruction created will be at least `minSizeInBytes`,
+ /// but may be larger if the total number of operands provided implies a larger
+ /// size.
+ ///
+ /// Note: This is an extremely low-level operation and clients of an `IRBuilder`
+ /// should not be using it when other options are available.
+ ///
+ IRInst* _createInst(
+ size_t minSizeInBytes,
+ IRType* type,
+ IROp op,
+ Int fixedArgCount,
+ IRInst* const* fixedArgs,
+ Int varArgListCount,
+ Int const* listArgCounts,
+ IRInst* const* const* listArgs);
+
+
+
+ /// Create a new instruction with the given `type` and `op`, with an allocated
+ /// size of at least `minSizeInBytes`, and with zero operands.
+ ///
+ IRInst* _createInst(
+ size_t minSizeInBytes,
+ IRType* type,
+ IROp op)
+ {
+ return _createInst(minSizeInBytes, type, op, 0, nullptr, 0, nullptr, nullptr);
+ }
+
+ /// Attempt to attach a useful source location to `inst`.
+ ///
+ /// This operation looks at the source location information that has been
+ /// attached to the builder. If it finds a valid source location, it will
+ /// attach that location to `inst`.
+ ///
+ void _maybeSetSourceLoc(
+ IRInst* inst);
- void setInsertInto(IRInst* insertInto);
- void setInsertBefore(IRInst* insertBefore);
- IRBuilderSourceLocRAII* sourceLocInfo = nullptr;
+ //
void addInst(IRInst* inst);
@@ -2189,8 +2304,6 @@ struct IRBuilder
UInt operandCount,
IRInst* const* operands);
- IRModule* createModule();
-
IRFunc* createFunc();
IRGlobalVar* createGlobalVar(
IRType* valueType);
@@ -2716,14 +2829,14 @@ struct IRBuilderSourceLocRAII
, sourceLoc(sourceLoc)
, next(nullptr)
{
- next = builder->sourceLocInfo;
- builder->sourceLocInfo = this;
+ next = builder->getSourceLocInfo();
+ builder->setSourceLocInfo(this);
}
~IRBuilderSourceLocRAII()
{
- SLANG_ASSERT(builder->sourceLocInfo == this);
- builder->sourceLocInfo = next;
+ SLANG_ASSERT(builder->getSourceLocInfo() == this);
+ builder->setSourceLocInfo(next);
}
};
diff --git a/source/slang/slang-ir-layout.cpp b/source/slang/slang-ir-layout.cpp
index 126f710d8..c89d15808 100644
--- a/source/slang/slang-ir-layout.cpp
+++ b/source/slang/slang-ir-layout.cpp
@@ -153,12 +153,9 @@ static Result _calcNaturalSizeAndAlignment(
// cache the field offset on the IR field
// instruction.
//
- SharedIRBuilder sharedBuilder;
- sharedBuilder.module = module;
- sharedBuilder.session = module->getSession();
+ SharedIRBuilder sharedBuilder(module);
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ IRBuilder builder(sharedBuilder);
auto intType = builder.getIntType();
builder.addDecoration(
@@ -203,12 +200,8 @@ static Result _calcNaturalSizeAndAlignment(
auto matType = cast<IRMatrixType>(type);
auto rowCount = getIntegerValueFromInst(matType->getRowCount());
auto colCount = getIntegerValueFromInst(matType->getColumnCount());
- SharedIRBuilder sharedBuilder;
- sharedBuilder.module = type->getModule();
- sharedBuilder.session = sharedBuilder.module->getSession();
-
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ SharedIRBuilder sharedBuilder(type->getModule());
+ IRBuilder builder(sharedBuilder);
return _calcNaturalArraySizeAndAlignment(
target, matType->getElementType(),
@@ -254,12 +247,9 @@ Result getNaturalSizeAndAlignment(TargetRequest* target, IRType* type, IRSizeAnd
if( auto module = type->getModule() )
{
- SharedIRBuilder sharedBuilder;
- sharedBuilder.module = module;
- sharedBuilder.session = module->getSession();
+ SharedIRBuilder sharedBuilder(module);
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ IRBuilder builder(sharedBuilder);
auto intType = builder.getIntType();
builder.addDecoration(
diff --git a/source/slang/slang-ir-legalize-types.cpp b/source/slang/slang-ir-legalize-types.cpp
index 416df6c77..1b61e802e 100644
--- a/source/slang/slang-ir-legalize-types.cpp
+++ b/source/slang/slang-ir-legalize-types.cpp
@@ -99,11 +99,10 @@ IRTypeLegalizationContext::IRTypeLegalizationContext(
module = inModule;
auto sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->session = session;
- sharedBuilder->module = module;
+ sharedBuilder->init(module);
builder = &builderStorage;
- builder->sharedBuilder = sharedBuilder;
+ builder->init(sharedBuilder);
}
static void registerLegalizedValue(
diff --git a/source/slang/slang-ir-legalize-varying-params.cpp b/source/slang/slang-ir-legalize-varying-params.cpp
index 8025bb088..6fedc1f5f 100644
--- a/source/slang/slang-ir-legalize-varying-params.cpp
+++ b/source/slang/slang-ir-legalize-varying-params.cpp
@@ -203,9 +203,7 @@ public:
// shared builder to avoid unnecessary duplication of
// types/constants.
//
- SharedIRBuilder sharedBuilderStorage;
- sharedBuilderStorage.module = module;
- sharedBuilderStorage.session = module->getSession();
+ SharedIRBuilder sharedBuilderStorage(module);
m_sharedBuilder = &sharedBuilderStorage;
// Once the basic initialization is done, we will allow
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp
index 36985efd6..77998fba1 100644
--- a/source/slang/slang-ir-link.cpp
+++ b/source/slang/slang-ir-link.cpp
@@ -1279,24 +1279,24 @@ void insertGlobalValueSymbols(
void initializeSharedSpecContext(
IRSharedSpecContext* sharedContext,
Session* session,
- IRModule* module,
+ IRModule* inModule,
CodeGenTarget target,
TargetRequest* targetReq)
{
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = nullptr;
- sharedBuilder->session = session;
IRBuilder* builder = &sharedContext->builderStorage;
- builder->sharedBuilder = sharedBuilder;
+ RefPtr<IRModule> module = inModule;
if( !module )
{
- module = builder->createModule();
+ module = IRModule::create(session);
}
- sharedBuilder->module = module;
+ sharedBuilder->init(module);
+ builder->init(sharedBuilder);
+
sharedContext->module = module;
sharedContext->target = target;
sharedContext->targetReq = targetReq;
@@ -1399,7 +1399,7 @@ LinkedIR linkIR(
{
findGlobalHashedStringLiterals(irModule, pool);
}
- addGlobalHashedStringLiterals(pool, *builder.sharedBuilder);
+ addGlobalHashedStringLiterals(pool, *builder.getSharedBuilder());
}
// Set up shared and builder insert point
diff --git a/source/slang/slang-ir-lower-bit-cast.cpp b/source/slang/slang-ir-lower-bit-cast.cpp
index fdb8a6bdb..d895f1e28 100644
--- a/source/slang/slang-ir-lower-bit-cast.cpp
+++ b/source/slang/slang-ir-lower-bit-cast.cpp
@@ -43,8 +43,7 @@ struct BitCastLoweringContext
void processModule()
{
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = module;
- sharedBuilder->session = module->session;
+ sharedBuilder->init(module);
// Deduplicate equivalent types.
sharedBuilder->deduplicateAndRebuildGlobalNumberingMap();
@@ -239,8 +238,7 @@ struct BitCastLoweringContext
return;
}
// Enumerate all fields in to-type and obtain its value from operand object.
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
auto finalObject = readObject(builder, operand, toType, 0);
inst->replaceUsesWith(finalObject);
diff --git a/source/slang/slang-ir-lower-existential.cpp b/source/slang/slang-ir-lower-existential.cpp
index 7cbb1b372..ab948bc7a 100644
--- a/source/slang/slang-ir-lower-existential.cpp
+++ b/source/slang/slang-ir-lower-existential.cpp
@@ -16,9 +16,8 @@ namespace Slang
void processMakeExistential(IRMakeExistentialWithRTTI* inst)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(inst);
auto value = inst->getWrappedValue();
@@ -52,9 +51,8 @@ namespace Slang
// existential value.
void processCreateExistentialObject(IRCreateExistentialObject* inst)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(inst);
// The result type of this `createExistentialObject` inst should already
@@ -103,9 +101,8 @@ namespace Slang
void processExtractExistentialElement(IRInst* extractInst, UInt elementId)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(extractInst);
auto element = extractTupleElement(builder, extractInst->getOperand(0), elementId);
@@ -130,9 +127,8 @@ namespace Slang
void processGetValueFromBoundInterface(IRGetValueFromBoundInterface* inst)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(inst);
// A value of interface will lower as a tuple, and
@@ -212,8 +208,7 @@ namespace Slang
// generate along the way.
//
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
+ sharedBuilder->init(sharedContext->module);
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
diff --git a/source/slang/slang-ir-lower-generic-call.cpp b/source/slang/slang-ir-lower-generic-call.cpp
index 7669593c6..dc234bbbc 100644
--- a/source/slang/slang-ir-lower-generic-call.cpp
+++ b/source/slang/slang-ir-lower-generic-call.cpp
@@ -159,9 +159,8 @@ namespace Slang
for (UInt i = 0; i < funcType->getParamCount(); i++)
paramTypes.add(funcType->getParamType(i));
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(callInst);
// Process the argument list of the call.
@@ -285,9 +284,8 @@ namespace Slang
if (isBuiltin(interfaceType))
return;
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(callInst);
// Create interface dispatch method that bottlenecks the dispatch logic.
@@ -346,8 +344,7 @@ namespace Slang
// generate along the way.
//
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
+ sharedBuilder->init(sharedContext->module);
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
diff --git a/source/slang/slang-ir-lower-generic-function.cpp b/source/slang/slang-ir-lower-generic-function.cpp
index 8cd292e49..0bfc62fdb 100644
--- a/source/slang/slang-ir-lower-generic-function.cpp
+++ b/source/slang/slang-ir-lower-generic-function.cpp
@@ -45,8 +45,7 @@ namespace Slang
return genericValue;
}
IRCloneEnv cloneEnv;
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(genericParent);
auto loweredFunc = cast<IRFunc>(cloneInstAndOperands(&cloneEnv, &builder, func));
auto loweredGenericType =
@@ -155,8 +154,7 @@ namespace Slang
return interfaceType;
List<IRInterfaceRequirementEntry*> newEntries;
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(interfaceType);
// Translate IRFuncType in interface requirements.
@@ -214,9 +212,8 @@ namespace Slang
void lowerWitnessTable(IRWitnessTable* witnessTable)
{
auto interfaceType = maybeLowerInterfaceType(cast<IRInterfaceType>(witnessTable->getConformanceType()));
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(witnessTable);
if (interfaceType != witnessTable->getConformanceType())
{
@@ -322,8 +319,7 @@ namespace Slang
// generate along the way.
//
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
+ sharedBuilder->init(sharedContext->module);
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
diff --git a/source/slang/slang-ir-lower-generic-type.cpp b/source/slang/slang-ir-lower-generic-type.cpp
index 50c97c1f2..76233d155 100644
--- a/source/slang/slang-ir-lower-generic-type.cpp
+++ b/source/slang/slang-ir-lower-generic-type.cpp
@@ -29,9 +29,8 @@ namespace Slang
if (as<IRType>(inst))
return;
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(inst);
auto newType = sharedContext->lowerType(builder, inst->getFullType());
@@ -61,8 +60,7 @@ namespace Slang
// generate along the way.
//
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
+ sharedBuilder->init(sharedContext->module);
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
diff --git a/source/slang/slang-ir-lower-generics.cpp b/source/slang/slang-ir-lower-generics.cpp
index 95046787a..ea45ecfff 100644
--- a/source/slang/slang-ir-lower-generics.cpp
+++ b/source/slang/slang-ir-lower-generics.cpp
@@ -24,8 +24,7 @@ namespace Slang
uint32_t id = 0;
for (auto rtti : sharedContext->mapTypeToRTTIObject)
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(rtti.Value);
IRUse* nextUse = nullptr;
auto uint2Type = builder.getVectorType(
@@ -56,8 +55,7 @@ namespace Slang
case kIROp_WitnessTableIDType:
case kIROp_RTTIHandleType:
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(inst);
auto uint2Type = builder.getVectorType(
builder.getUIntType(), builder.getIntValue(builder.getIntType(), 2));
@@ -74,8 +72,7 @@ namespace Slang
// Remove all interface types from module.
void cleanUpInterfaceTypes(SharedGenericsLoweringContext* sharedContext)
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertInto(sharedContext->module->getModuleInst());
auto dummyInterfaceObj = builder.getIntValue(builder.getIntType(), 0);
List<IRInst*> interfaceInsts;
diff --git a/source/slang/slang-ir-lower-reinterpret.cpp b/source/slang/slang-ir-lower-reinterpret.cpp
index bfe430aff..b7c88e632 100644
--- a/source/slang/slang-ir-lower-reinterpret.cpp
+++ b/source/slang/slang-ir-lower-reinterpret.cpp
@@ -38,8 +38,7 @@ struct ReinterpretLoweringContext
void processModule()
{
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = module;
- sharedBuilder->session = module->session;
+ sharedBuilder->init(module);
// Deduplicate equivalent types.
sharedBuilder->deduplicateAndRebuildGlobalNumberingMap();
@@ -78,8 +77,7 @@ struct ReinterpretLoweringContext
}
SlangInt anyValueSize = Math::Max(fromTypeSize, toTypeSize);
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
auto anyValueType = builder.getAnyValueType(builder.getIntValue(builder.getUIntType(), anyValueSize));
auto packInst = builder.emitPackAnyValue(
diff --git a/source/slang/slang-ir-lower-tuple-types.cpp b/source/slang/slang-ir-lower-tuple-types.cpp
index 429058edf..49a6a9045 100644
--- a/source/slang/slang-ir-lower-tuple-types.cpp
+++ b/source/slang/slang-ir-lower-tuple-types.cpp
@@ -85,9 +85,8 @@ namespace Slang
void processMakeTuple(IRMakeTuple* inst)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(inst);
auto info = getLoweredTupleType(builder, inst->getDataType());
@@ -104,9 +103,8 @@ namespace Slang
void processGetTupleElement(IRGetTupleElement* inst)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(inst);
auto base = inst->getTuple();
@@ -123,9 +121,8 @@ namespace Slang
void processTupleType(IRTupleType* inst)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(inst);
auto loweredTupleInfo = getLoweredTupleType(builder, inst);
@@ -154,8 +151,7 @@ namespace Slang
void processModule()
{
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = module;
- sharedBuilder->session = module->session;
+ sharedBuilder->init(module);
// Deduplicate equivalent types.
sharedBuilder->deduplicateAndRebuildGlobalNumberingMap();
diff --git a/source/slang/slang-ir-restructure-scoping.cpp b/source/slang/slang-ir-restructure-scoping.cpp
index 0b8e37d31..0535483ec 100644
--- a/source/slang/slang-ir-restructure-scoping.cpp
+++ b/source/slang/slang-ir-restructure-scoping.cpp
@@ -254,12 +254,9 @@ static void fixValueScopingForInst(
//
IRModule* module = regionTree->irCode->getModule();
- SharedIRBuilder sharedBuilder;
- sharedBuilder.session = module->session;
- sharedBuilder.module = module;
+ SharedIRBuilder sharedBuilder(module);
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ IRBuilder builder(sharedBuilder);
// Because we will be changing some of the uses of `def`
// to use other values while we iterate the list, we
diff --git a/source/slang/slang-ir-sccp.cpp b/source/slang/slang-ir-sccp.cpp
index c54b5b8d9..159cf9abc 100644
--- a/source/slang/slang-ir-sccp.cpp
+++ b/source/slang/slang-ir-sccp.cpp
@@ -573,7 +573,7 @@ struct SCCPContext
{
// We start with the busy-work of setting up our IR builder.
//
- builderStorage.sharedBuilder = &shared->sharedBuilder;
+ builderStorage.init(shared->sharedBuilder);
// We expect the caller to have filtered out functions with
// no bodies, so there should always be at least one basic block.
@@ -940,8 +940,7 @@ void applySparseConditionalConstantPropagation(
{
SharedSCCPContext shared;
shared.module = module;
- shared.sharedBuilder.module = module;
- shared.sharedBuilder.session = module->getSession();
+ shared.sharedBuilder.init(module);
applySparseConditionalConstantPropagationRec(&shared, module->getModuleInst());
}
diff --git a/source/slang/slang-ir-specialize-dispatch.cpp b/source/slang/slang-ir-specialize-dispatch.cpp
index 640873140..eac5287e5 100644
--- a/source/slang/slang-ir-specialize-dispatch.cpp
+++ b/source/slang/slang-ir-specialize-dispatch.cpp
@@ -42,9 +42,8 @@ IRFunc* specializeDispatchFunction(SharedGenericsLoweringContext* sharedContext,
}
SLANG_ASSERT(callInst && lookupInst && returnInst);
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(dispatchFunc);
// Create a new dispatch func to replace the existing one.
@@ -209,8 +208,7 @@ void ensureWitnessTableSequentialIDs(SharedGenericsLoweringContext* sharedContex
}
// Add a decoration to the inst.
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(inst);
builder.addSequentialIDDecoration(inst, seqID);
}
@@ -232,8 +230,7 @@ void fixupDispatchFuncCall(SharedGenericsLoweringContext* sharedContext, IRFunc*
{
if (call->getCallee() != newDispatchFunc)
continue;
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(call);
List<IRInst*> args;
for (UInt i = 0; i < call->getArgCount(); i++)
diff --git a/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp b/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp
index 670202161..d37ac4fd2 100644
--- a/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp
+++ b/source/slang/slang-ir-specialize-dynamic-associatedtype-lookup.cpp
@@ -13,8 +13,7 @@ struct AssociatedTypeLookupSpecializationContext
IRFunc* createWitnessTableLookupFunc(IRInterfaceType* interfaceType, IRInst* key)
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(interfaceType);
auto inputWitnessTableIDType = builder.getWitnessTableIDType(interfaceType);
@@ -123,8 +122,7 @@ struct AssociatedTypeLookupSpecializationContext
// Ignore lookups for RTTI objects for now, since they are not used anywhere.
if (!as<IRWitnessTableType>(inst->getDataType()))
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(inst);
auto uint2Type = builder.getVectorType(
builder.getUIntType(), builder.getIntValue(builder.getIntType(), 2));
@@ -150,8 +148,7 @@ struct AssociatedTypeLookupSpecializationContext
func = createWitnessTableLookupFunc(interfaceType, key);
sharedContext->mapInterfaceRequirementKeyToDispatchMethods[key] = func;
}
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(inst);
auto witnessTableArg = inst->getWitnessTable();
if (witnessTableArg->getDataType()->getOp() == kIROp_WitnessTableType)
@@ -178,8 +175,7 @@ struct AssociatedTypeLookupSpecializationContext
// at this point, where the first element in the uint2 is the id of the
// witness table.
auto vectorType = inst->getRTTIOperand()->getDataType();
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(inst);
UInt index = 0;
auto id = builder.emitSwizzle(as<IRVectorType>(vectorType)->getElementType(), inst->getRTTIOperand(), 1, &index);
@@ -210,8 +206,7 @@ struct AssociatedTypeLookupSpecializationContext
for (auto use = inst->firstUse; use; )
{
auto nextUse = use->nextUse;
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(use->getUser());
auto uint2Type = builder.getVectorType(
builder.getUIntType(), builder.getIntValue(builder.getIntType(), 2));
@@ -231,8 +226,7 @@ struct AssociatedTypeLookupSpecializationContext
{
if (globalInst->getOp() == kIROp_WitnessTableType)
{
- IRBuilder builder;
- builder.sharedBuilder = &sharedContext->sharedBuilderStorage;
+ IRBuilder builder(sharedContext->sharedBuilderStorage);
builder.setInsertBefore(globalInst);
auto witnessTableIDType = builder.getWitnessTableIDType(
(IRType*)cast<IRWitnessTableType>(globalInst)->getConformanceType());
diff --git a/source/slang/slang-ir-specialize-function-call.cpp b/source/slang/slang-ir-specialize-function-call.cpp
index 0341438c5..ab77ec88e 100644
--- a/source/slang/slang-ir-specialize-function-call.cpp
+++ b/source/slang/slang-ir-specialize-function-call.cpp
@@ -104,9 +104,8 @@ struct FunctionParameterSpecializationContext
{
// We will start by initializing our IR building state.
//
- sharedBuilderStorage.module = module;
- sharedBuilderStorage.session = module->getSession();
- builderStorage.sharedBuilder = &sharedBuilderStorage;
+ sharedBuilderStorage.init(module);
+ builderStorage.init(sharedBuilderStorage);
// Next we will populate our initial work list by
// recursively finding every single call site in the module.
@@ -675,7 +674,19 @@ struct FunctionParameterSpecializationContext
// instructions if an insertion location
// is set.
//
- builder->setInsertInto(nullptr);
+ // TODO(tfoley): We should really question any cases where
+ // we are creating IR instructions but not inserting them into the
+ // hierarchy of the IR module anywhere. Ideally we would have an
+ // invariant that all IR instructions are always parented somewhere
+ // under their IR module, except during very brief interludes.
+ //
+ // A good fix here would be for a pass like this to create a transient
+ // IR block to serve as a "nursery" for the newly-created instructions,
+ // instead of using `newBodyInsts` to hold them. The new IR block could
+ // be placed directly under the IR module during the construction phase
+ // of things, and then inserted to a more permanent location later.
+ //
+ builder->setInsertLoc(IRInsertLoc());
auto newVal = builder->emitElementExtract(
oldArg->getFullType(),
newBase,
@@ -697,7 +708,7 @@ struct FunctionParameterSpecializationContext
auto newPtr = getSpecializedValueForArg(ioInfo, oldPtr);
auto builder = getBuilder();
- builder->setInsertInto(nullptr);
+ builder->setInsertLoc(IRInsertLoc());
auto newVal = builder->emitLoad(
oldArg->getFullType(),
newPtr);
@@ -782,7 +793,7 @@ struct FunctionParameterSpecializationContext
//
cloneInstDecorationsAndChildren(
&cloneEnv,
- builder->sharedBuilder,
+ builder->getSharedBuilder(),
oldFunc,
newFunc);
diff --git a/source/slang/slang-ir-specialize-resources.cpp b/source/slang/slang-ir-specialize-resources.cpp
index 09db3391f..1b3fc65f4 100644
--- a/source/slang/slang-ir-specialize-resources.cpp
+++ b/source/slang/slang-ir-specialize-resources.cpp
@@ -115,8 +115,7 @@ struct ResourceOutputSpecializationPass
{
// We start by setting up the shared IR building state.
//
- sharedBuilder.module = module;
- sharedBuilder.session = module->getSession();
+ sharedBuilder.init(module);
// The main logic consists of iterating over all functions
// (which must appear at the global level) and specializing
diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp
index b1da92ff1..9ceb4dbe7 100644
--- a/source/slang/slang-ir-specialize.cpp
+++ b/source/slang/slang-ir-specialize.cpp
@@ -635,8 +635,7 @@ struct SpecializationContext
// generate along the way.
//
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = module;
- sharedBuilder->session = module->session;
+ sharedBuilder->init(module);
// The unspecialized IR we receive as input will have
// `IRBindGlobalGenericParam` instructions that associate
@@ -785,8 +784,7 @@ struct SpecializationContext
{
auto oldSpecialize = cast<IRSpecialize>(oldSpecializedCallee);
SLANG_ASSERT(oldSpecialize->getArgCount() == 1);
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(oldSpecializedCallee);
auto calleeType = builder.getFuncType(1, &newContainerType, newElementType);
auto newSpecialize = builder.emitSpecializeInst(
@@ -816,8 +814,7 @@ struct SpecializationContext
auto resultType = inst->getFullType();
auto elementType = sbType->getElementType();
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
List<IRInst*> args;
@@ -1057,9 +1054,8 @@ struct SpecializationContext
// Now that we've built up our argument list, it is simple enough
// to construct a new `call` instruction.
//
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(inst);
auto newCall = builder->emitCallInst(
@@ -1214,9 +1210,8 @@ struct SpecializationContext
// We also need some IR building state, for any
// new instructions we will emit.
//
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
// We will start out by determining what the parameters
// of the specialized function should be, based on
@@ -1355,7 +1350,7 @@ struct SpecializationContext
//
cloneInstDecorationsAndChildren(
&cloneEnv,
- builder->sharedBuilder,
+ builder->getSharedBuilder(),
oldFunc,
newFunc);
@@ -1528,8 +1523,7 @@ struct SpecializationContext
//
auto resultType = inst->getFullType();
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
// We'd *like* to replace this instruction with
@@ -1626,8 +1620,7 @@ struct SpecializationContext
//
auto resultType = inst->getFullType();
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
// We'd *like* to replace this instruction with
@@ -1712,8 +1705,7 @@ struct SpecializationContext
//
auto resultType = inst->getFullType();
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
// We'd *like* to replace this instruction with
@@ -1798,8 +1790,7 @@ struct SpecializationContext
auto val = wrapInst->getWrappedValue();
auto resultType = inst->getFullType();
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
auto elementType = cast<IRArrayTypeBase>(val->getDataType())->getElementType();
@@ -1840,8 +1831,7 @@ struct SpecializationContext
auto resultType = inst->getFullType();
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(inst);
List<IRInst*> slotOperands;
@@ -1908,8 +1898,7 @@ struct SpecializationContext
auto baseType = type->getBaseType();
UInt slotOperandCount = type->getExistentialArgCount();
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilderStorage;
+ IRBuilder builder(sharedBuilderStorage);
builder.setInsertBefore(type);
if( auto baseInterfaceType = as<IRInterfaceType>(baseType) )
@@ -2153,13 +2142,9 @@ IRInst* specializeGenericImpl(
// into the global scope, at the same location
// as the original generic.
//
- SharedIRBuilder sharedBuilderStorage;
- sharedBuilderStorage.module = module;
- sharedBuilderStorage.session = module->getSession();
-
- IRBuilder builderStorage;
+ SharedIRBuilder sharedBuilderStorage(module);
+ IRBuilder builderStorage(sharedBuilderStorage);
IRBuilder* builder = &builderStorage;
- builder->sharedBuilder = &sharedBuilderStorage;
builder->setInsertBefore(genericVal);
// Now we will run through the body of the generic and
diff --git a/source/slang/slang-ir-spirv-legalize.cpp b/source/slang/slang-ir-spirv-legalize.cpp
index a75c26e86..9587fd205 100644
--- a/source/slang/slang-ir-spirv-legalize.cpp
+++ b/source/slang/slang-ir-spirv-legalize.cpp
@@ -70,8 +70,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
}
}
// Make a pointer type of storageClass.
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedContext->m_sharedIRBuilder;
+ IRBuilder builder(m_sharedContext->m_sharedIRBuilder);
builder.setInsertBefore(inst);
ptrType = builder.getPtrType(kIROp_PtrType, inst->getFullType(), storageClass);
inst->setFullType(ptrType);
@@ -141,8 +140,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
{
storageClass = SpvStorageClassWorkgroup;
}
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedContext->m_sharedIRBuilder;
+ IRBuilder builder(m_sharedContext->m_sharedIRBuilder);
builder.setInsertBefore(inst);
auto newPtrType =
builder.getPtrType(oldPtrType->getOp(), oldPtrType->getValueType(), storageClass);
@@ -165,8 +163,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
auto ptrType = as<IRPtrTypeBase>(inst->getDataType());
if (!ptrType)
return;
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedContext->m_sharedIRBuilder;
+ IRBuilder builder(m_sharedContext->m_sharedIRBuilder);
builder.setInsertBefore(inst);
auto qualPtrType = builder.getPtrType(
ptrType->getOp(), ptrType->getValueType(), snippet->resultStorageClass);
@@ -190,8 +187,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
auto oldResultType = as<IRPtrTypeBase>(inst->getDataType());
if (oldResultType->getAddressSpace() != ptrType->getAddressSpace())
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedContext->m_sharedIRBuilder;
+ IRBuilder builder(m_sharedContext->m_sharedIRBuilder);
builder.setInsertBefore(inst);
auto newPtrType = builder.getPtrType(
oldResultType->getOp(),
@@ -215,8 +211,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
auto oldResultType = as<IRPtrTypeBase>(inst->getDataType());
if (oldResultType->getAddressSpace() != ptrType->getAddressSpace())
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedContext->m_sharedIRBuilder;
+ IRBuilder builder(m_sharedContext->m_sharedIRBuilder);
builder.setInsertBefore(inst);
auto newPtrType = builder.getPtrType(
oldResultType->getOp(),
@@ -233,8 +228,7 @@ struct SPIRVLegalizationContext : public SourceEmitterBase
void processStructuredBufferType(IRHLSLStructuredBufferTypeBase* inst)
{
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedContext->m_sharedIRBuilder;
+ IRBuilder builder(m_sharedContext->m_sharedIRBuilder);
builder.setInsertBefore(inst);
auto arrayType = builder.getUnsizedArrayType(inst->getElementType());
auto structType = builder.createStructType();
diff --git a/source/slang/slang-ir-ssa.cpp b/source/slang/slang-ir-ssa.cpp
index 14198aa0a..1804664fb 100644
--- a/source/slang/slang-ir-ssa.cpp
+++ b/source/slang/slang-ir-ssa.cpp
@@ -921,8 +921,7 @@ void SharedIRBuilder::insertBlockAlongEdge(
auto succ = edge.getSuccessor();
auto edgeUse = edge.getUse();
- IRBuilder builder;
- builder.sharedBuilder = this;
+ IRBuilder builder(this);
builder.setInsertInto(pred);
// Create a new block that will sit "along" the edge
@@ -1065,7 +1064,7 @@ void constructSSA(ConstructSSAContext* context)
auto blockInfo = new SSABlockInfo();
blockInfo->block = bb;
- blockInfo->builder.sharedBuilder = &context->sharedBuilder;
+ blockInfo->builder.init(context->sharedBuilder);
blockInfo->builder.setInsertBefore(bb->getLastInst());
context->blockInfos.Add(bb, blockInfo);
@@ -1196,11 +1195,10 @@ void constructSSA(IRModule* module, IRGlobalValueWithCode* globalVal)
ConstructSSAContext context;
context.globalVal = globalVal;
- context.sharedBuilder.module = module;
- context.sharedBuilder.session = module->session;
+ context.sharedBuilder.init(module);
- context.builder.sharedBuilder = &context.sharedBuilder;
- context.builder.setInsertInto(module->moduleInst);
+ context.builder.init(context.sharedBuilder);
+ context.builder.setInsertInto(module);
constructSSA(&context);
}
diff --git a/source/slang/slang-ir-string-hash.cpp b/source/slang/slang-ir-string-hash.cpp
index 2d5d78d7e..8ff0ec756 100644
--- a/source/slang/slang-ir-string-hash.cpp
+++ b/source/slang/slang-ir-string-hash.cpp
@@ -44,8 +44,7 @@ void addGlobalHashedStringLiterals(const StringSlicePool& pool, SharedIRBuilder&
return;
}
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
+ IRBuilder builder(sharedBuilder);
//
IRModule* module = builder.getModule();
@@ -55,7 +54,16 @@ void addGlobalHashedStringLiterals(const StringSlicePool& pool, SharedIRBuilder&
const Index slicesCount = slices.getCount();
- IRInst* globalHashedInst = createEmptyInst(module, kIROp_GlobalHashedStringLiterals, int(slicesCount));
+ // Note: This pass is using the extremely low-level `_allocateInst` operation on `IRModule`
+ // as an optimization. By allocating the instruction here in an "empty" state and then filling
+ // its operands in in place, we can avoid allocating space for a temporary `List<IRInst*>` to
+ // hold the IR string values created in the loop below.
+ //
+ // TODO: We should probably either eliminate this micro-optimization and just use a `List<IRInst*>`
+ // here, *or* we should devise a more first-class system for doing in-place instruction creation
+ // like that that can be compatible with desirable features like automatic deduplication.
+ //
+ IRInst* globalHashedInst = module->_allocateInst(kIROp_GlobalHashedStringLiterals, int(slicesCount));
builder.addInst(globalHashedInst);
auto operands = globalHashedInst->getOperands();
diff --git a/source/slang/slang-ir-synthesize-active-mask.cpp b/source/slang/slang-ir-synthesize-active-mask.cpp
index 2ccfa2263..79d7df559 100644
--- a/source/slang/slang-ir-synthesize-active-mask.cpp
+++ b/source/slang/slang-ir-synthesize-active-mask.cpp
@@ -117,8 +117,7 @@ struct SynthesizeActiveMaskForModuleContext
// When asked to process an IR module, our pass first
// sets up the shared state.
//
- m_sharedBuilder.session = m_module->getSession();
- m_sharedBuilder.module = m_module;
+ m_sharedBuilder.init(m_module);
// We use the plain 32-bit `uint` type masks we
// generate here since it matches the current
@@ -129,8 +128,7 @@ struct SynthesizeActiveMaskForModuleContext
// so that the pass is compatible with all targets that
// support a wave mask.
//
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedBuilder;
+ IRBuilder builder(m_sharedBuilder);
m_maskType = builder.getBasicType(BaseType::UInt);
// With the setup out of the way, the job of the module
@@ -331,8 +329,7 @@ struct SynthesizeActiveMaskForModuleContext
// mask = waveGetActiveMask();
// callee(arg0, arg1, arg2, ..., m);
//
- IRBuilder builder;
- builder.sharedBuilder = &m_sharedBuilder;
+ IRBuilder builder(m_sharedBuilder);
builder.setInsertBefore(call);
// First we synthesize the mask to pass down by
@@ -734,8 +731,7 @@ struct SynthesizeActiveMaskForFunctionContext
//
// We will insert the code we generate at the start of the entry block.
//
- IRBuilder builder;
- builder.sharedBuilder = m_sharedBuilder;
+ IRBuilder builder(m_sharedBuilder);
builder.setInsertBefore(funcEntryBlock->getFirstOrdinaryInst());
//
// A naive approach would be to set the active mask to an all-ones
@@ -833,8 +829,7 @@ struct SynthesizeActiveMaskForFunctionContext
//
SLANG_ASSERT(doesBlockNeedActiveMask(block));
- IRBuilder builder;
- builder.sharedBuilder = m_sharedBuilder;
+ IRBuilder builder(m_sharedBuilder);
builder.setInsertBefore(block->getFirstOrdinaryInst());
auto activeMaskParam = builder.emitParam(m_maskType);
@@ -1226,8 +1221,7 @@ struct SynthesizeActiveMaskForFunctionContext
// code can take responsibility for computing the mask
// value to use for both `trueBlock` and `falseBlock`.
//
- IRBuilder builder;
- builder.sharedBuilder = m_sharedBuilder;
+ IRBuilder builder(m_sharedBuilder);
// To establish the mask value for `trueBlock` we will
// insert a `waveMaskBallot` before the branch:
@@ -1459,8 +1453,7 @@ struct SynthesizeActiveMaskForFunctionContext
// Next, we need to establish a mask value that will
// represent the active mask on entry to a given `case`.
//
- IRBuilder builder;
- builder.sharedBuilder = m_sharedBuilder;
+ IRBuilder builder(m_sharedBuilder);
builder.setInsertBefore(switchInst);
// For now we are computing a simple-but-inaccurate version
@@ -1693,8 +1686,7 @@ struct SynthesizeActiveMaskForFunctionContext
//
void transformUnconditionalEdge(RegionInfo* fromRegion, IRTerminatorInst* terminator, IRBlock* toBlock, IRInst* fromActiveMask)
{
- IRBuilder builder;
- builder.sharedBuilder = m_sharedBuilder;
+ IRBuilder builder(m_sharedBuilder);
builder.setInsertBefore(terminator);
// The context here is that the `terminator` instruction,
diff --git a/source/slang/slang-ir-type-set.cpp b/source/slang/slang-ir-type-set.cpp
index 4bebf658b..0cfe69e42 100644
--- a/source/slang/slang-ir-type-set.cpp
+++ b/source/slang/slang-ir-type-set.cpp
@@ -9,14 +9,10 @@ namespace Slang
IRTypeSet::IRTypeSet(Session* session)
{
- m_sharedBuilder.module = nullptr;
- m_sharedBuilder.session = session;
+ m_module = IRModule::create(session);
- m_builder.sharedBuilder = &m_sharedBuilder;
-
- m_module = m_builder.createModule();
-
- m_sharedBuilder.module = m_module;
+ m_sharedBuilder.init(m_module);
+ m_builder.init(m_sharedBuilder);
m_builder.setInsertInto(m_module->getModuleInst());
}
@@ -32,8 +28,11 @@ void IRTypeSet::clear()
m_cloneMap.Clear();
- m_module = m_builder.createModule();
- m_sharedBuilder.module = m_module;
+ m_module = IRModule::create(m_sharedBuilder.getSession());
+
+ m_sharedBuilder.init(m_module);
+ m_builder.init(m_sharedBuilder);
+
m_builder.setInsertInto(m_module->getModuleInst());
}
diff --git a/source/slang/slang-ir-union.cpp b/source/slang/slang-ir-union.cpp
index 216b0a81a..7a7271f23 100644
--- a/source/slang/slang-ir-union.cpp
+++ b/source/slang/slang-ir-union.cpp
@@ -39,9 +39,8 @@ struct DesugarUnionTypesContext
{
// We start by initializing our IR building state.
//
- sharedBuilderStorage.session = module->session;
- sharedBuilderStorage.module = module;
- builderStorage.sharedBuilder = &sharedBuilderStorage;
+ sharedBuilderStorage.init(module);
+ builderStorage.init(sharedBuilderStorage);
// Next, we will search for any instruction that create or use
// union types, and process them accordingingly (usually by
diff --git a/source/slang/slang-ir-validate.cpp b/source/slang/slang-ir-validate.cpp
index 94f0da047..ffadf33cf 100644
--- a/source/slang/slang-ir-validate.cpp
+++ b/source/slang/slang-ir-validate.cpp
@@ -216,14 +216,14 @@ namespace Slang
context->module = module;
context->sink = sink;
- auto moduleInst = module->moduleInst;
+ auto moduleInst = module->getModuleInst();
validate(context, moduleInst != nullptr, moduleInst, "module instruction");
validate(context, moduleInst->parent == nullptr, moduleInst, "module instruction parent");
validate(context, moduleInst->prev == nullptr, moduleInst, "module instruction prev");
validate(context, moduleInst->next == nullptr, moduleInst, "module instruction next");
- validateIRInst(context, module->moduleInst);
+ validateIRInst(context, moduleInst);
}
void validateIRModuleIfEnabled(
diff --git a/source/slang/slang-ir-witness-table-wrapper.cpp b/source/slang/slang-ir-witness-table-wrapper.cpp
index b3f37c7d1..e30ecc767 100644
--- a/source/slang/slang-ir-witness-table-wrapper.cpp
+++ b/source/slang/slang-ir-witness-table-wrapper.cpp
@@ -83,9 +83,8 @@ namespace Slang
IRStringLit* _getWitnessTableWrapperFuncName(IRFunc* func)
{
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(func);
if (auto linkageDecoration = func->findDecoration<IRLinkageDecoration>())
{
@@ -102,9 +101,8 @@ namespace Slang
{
auto funcTypeInInterface = cast<IRFuncType>(interfaceRequirementVal);
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedContext->sharedBuilderStorage);
auto builder = &builderStorage;
- builder->sharedBuilder = &sharedContext->sharedBuilderStorage;
builder->setInsertBefore(func);
auto wrapperFunc = builder->createFunc();
@@ -222,8 +220,7 @@ namespace Slang
// generate along the way.
//
SharedIRBuilder* sharedBuilder = &sharedContext->sharedBuilderStorage;
- sharedBuilder->module = sharedContext->module;
- sharedBuilder->session = sharedContext->module->session;
+ sharedBuilder->init(sharedContext->module);
sharedContext->addToWorkList(sharedContext->module->getModuleInst());
diff --git a/source/slang/slang-ir-wrap-structured-buffers.cpp b/source/slang/slang-ir-wrap-structured-buffers.cpp
index 089f43625..2ad09aa90 100644
--- a/source/slang/slang-ir-wrap-structured-buffers.cpp
+++ b/source/slang/slang-ir-wrap-structured-buffers.cpp
@@ -53,7 +53,7 @@ struct WrapStructuredBuffersContext
//
void processModule()
{
- processInstRec(m_module->moduleInst);
+ processInstRec(m_module->getModuleInst());
}
void processInstRec(IRInst* inst)
@@ -83,13 +83,10 @@ struct WrapStructuredBuffersContext
// Having found a `*StructuredBuffer<M>` we will now
// need an IR builder to help us construct the wrapper code.
//
- SharedIRBuilder sharedBuilderStorage;
+ SharedIRBuilder sharedBuilderStorage(m_module);
auto sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = m_module;
- sharedBuilder->session = m_module->getSession();
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilder);
auto builder = &builderStorage;
- builder->sharedBuilder = sharedBuilder;
// We begin by constructing a structure type that wraps
// our `matrixType`, into something like:
diff --git a/source/slang/slang-ir.cpp b/source/slang/slang-ir.cpp
index 81b554c3b..27eb1adfb 100644
--- a/source/slang/slang-ir.cpp
+++ b/source/slang/slang-ir.cpp
@@ -702,12 +702,8 @@ namespace Slang
auto irModule = func->getModule();
SLANG_ASSERT(irModule);
- SharedIRBuilder sharedBuilder;
- sharedBuilder.module = irModule;
-
- IRBuilder builder;
- builder.sharedBuilder = &sharedBuilder;
-
+ SharedIRBuilder sharedBuilder(irModule);
+ IRBuilder builder(sharedBuilder);
builder.setInsertBefore(func);
List<IRType*> paramTypes;
@@ -1121,16 +1117,33 @@ namespace Slang
//
- IRBlock* IRBuilder::getBlock()
+ IRInst* IRInsertLoc::getParent() const
+ {
+ auto inst = getInst();
+ switch(getMode())
+ {
+ default:
+ case Mode::None:
+ return nullptr;
+ case Mode::Before:
+ case Mode::After:
+ return inst->getParent();
+ case Mode::AtStart:
+ case Mode::AtEnd:
+ return inst;
+ }
+ }
+
+ IRBlock* IRInsertLoc::getBlock() const
{
- return as<IRBlock>(insertIntoParent);
+ return as<IRBlock>(getParent());
}
// Get the current function (or other value with code)
// that we are inserting into (if any).
- IRGlobalValueWithCode* IRBuilder::getFunc()
+ IRGlobalValueWithCode* IRInsertLoc::getFunc() const
{
- auto pp = insertIntoParent;
+ auto pp = getParent();
if (auto block = as<IRBlock>(pp))
{
pp = pp->getParent();
@@ -1138,37 +1151,11 @@ namespace Slang
return as<IRGlobalValueWithCode>(pp);
}
-
- void IRBuilder::setInsertInto(IRInst* insertInto)
- {
- insertIntoParent = insertInto;
- insertBeforeInst = nullptr;
- }
-
- void IRBuilder::setInsertBefore(IRInst* insertBefore)
- {
- SLANG_ASSERT(insertBefore);
- insertIntoParent = insertBefore->parent;
- insertBeforeInst = insertBefore;
- }
-
-
// Add an instruction into the current scope
void IRBuilder::addInst(
IRInst* inst)
{
- if(insertBeforeInst)
- {
- inst->insertBefore(insertBeforeInst);
- }
- else if (insertIntoParent)
- {
- inst->insertAtEnd(insertIntoParent);
- }
- else
- {
- // Don't append the instruction anywhere
- }
+ inst->insertAt(m_insertLoc);
}
// Given two parent instructions, pick the better one to use as as
@@ -1313,33 +1300,34 @@ namespace Slang
return parent;
}
- IRInst* createEmptyInst(
- IRModule* module,
- IROp op,
- int totalArgCount)
+ IRInst* IRModule::_allocateInst(
+ IROp op,
+ Int operandCount,
+ size_t minSizeInBytes)
{
- size_t size = sizeof(IRInst) + (totalArgCount) * sizeof(IRUse);
-
- SLANG_ASSERT(module);
- IRInst* inst = (IRInst*)module->memoryArena.allocateAndZero(size);
-
- inst->operandCount = uint32_t(totalArgCount);
- inst->m_op = op;
-
- return inst;
- }
+ // There are two basic cases for instructions that affect how we compute size:
+ //
+ // * The default case is that an instruction's state is fully defined by the fields
+ // in the `IRInst` base type, along with the trailing operand list (a tail-allocated
+ // array of `IRUse`s. Almost all instructions need space allocated this way.
+ //
+ // * A small number of cases (currently `IRConstant`s and the `IRModule` type) have
+ // *zero* operands but include additional state beyond the fields in `IRInst`.
+ // For these cases we want to ensure that at least `sizeof(T)` bytes are allocated,
+ // based on the specific leaf type `T`.
+ //
+ // We handle the combination of the two cases by just taking the maximum of the two
+ // different sizes.
+ //
+ size_t defaultSize = sizeof(IRInst) + (operandCount) * sizeof(IRUse);
+ size_t totalSize = minSizeInBytes > defaultSize ? minSizeInBytes : defaultSize;
- IRInst* createEmptyInstWithSize(
- IRModule* module,
- IROp op,
- size_t totalSizeInBytes)
- {
- SLANG_ASSERT(totalSizeInBytes >= sizeof(IRInst));
+ IRInst* inst = (IRInst*) m_memoryArena.allocateAndZero(totalSize);
- SLANG_ASSERT(module);
- IRInst* inst = (IRInst*)module->memoryArena.allocateAndZero(totalSizeInBytes);
+ // TODO: Is it actually important to run a constructor here?
+ new(inst) IRInst();
- inst->operandCount = 0;
+ inst->operandCount = uint32_t(operandCount);
inst->m_op = op;
return inst;
@@ -1561,14 +1549,10 @@ namespace Slang
}
}
- static void maybeSetSourceLoc(
- IRBuilder* builder,
- IRInst* value)
+ void IRBuilder::_maybeSetSourceLoc(
+ IRInst* inst)
{
- if(!builder)
- return;
-
- auto sourceLocInfo = builder->sourceLocInfo;
+ auto sourceLocInfo = getSourceLocInfo();
if(!sourceLocInfo)
return;
@@ -1584,7 +1568,7 @@ namespace Slang
sourceLocInfo = sourceLocInfo->next;
}
- value->sourceLoc = sourceLocInfo->sourceLoc;
+ inst->sourceLoc = sourceLocInfo->sourceLoc;
}
#if SLANG_ENABLE_IR_BREAK_ALLOC
@@ -1606,56 +1590,39 @@ namespace Slang
}
#endif
- // Create an IR instruction/value and initialize it.
- //
- // In this case `argCount` and `args` represent the
- // arguments *after* the type (which is a mandatory
- // argument for all instructions).
- template<typename T>
- static T* createInstImpl(
- IRModule* module,
- IRBuilder* builder,
- IROp op,
- IRType* type,
- UInt fixedArgCount,
- IRInst* const* fixedArgs,
- UInt varArgListCount,
- UInt const* listArgCounts,
+ IRInst* IRBuilder::_createInst(
+ size_t minSizeInBytes,
+ IRType* type,
+ IROp op,
+ Int fixedArgCount,
+ IRInst* const* fixedArgs,
+ Int varArgListCount,
+ Int const* listArgCounts,
IRInst* const* const* listArgs)
{
- UInt varArgCount = 0;
- for (UInt ii = 0; ii < varArgListCount; ++ii)
+ Int varArgCount = 0;
+ for (Int ii = 0; ii < varArgListCount; ++ii)
{
varArgCount += listArgCounts[ii];
}
- UInt size = sizeof(IRInst) + (fixedArgCount + varArgCount) * sizeof(IRUse);
- if (sizeof(T) > size)
- {
- size = sizeof(T);
- }
+ Int totalOperandCount = fixedArgCount + varArgCount;
+ auto module = getModule();
SLANG_ASSERT(module);
- T* inst = (T*)module->memoryArena.allocateAndZero(size);
-
- // TODO: Do we need to run ctor after zeroing?
- new(inst)T();
+ IRInst* inst = module->_allocateInst(op, totalOperandCount, minSizeInBytes);
#if SLANG_ENABLE_IR_BREAK_ALLOC
inst->_debugUID = _debugGetAndIncreaseInstCounter();
#endif
- inst->operandCount = (uint32_t)(fixedArgCount + varArgCount);
-
- inst->m_op = op;
-
inst->typeUse.init(inst, type);
- maybeSetSourceLoc(builder, inst);
+ _maybeSetSourceLoc(inst);
auto operand = inst->getOperands();
- for( UInt aa = 0; aa < fixedArgCount; ++aa )
+ for( Int aa = 0; aa < fixedArgCount; ++aa )
{
if (fixedArgs)
{
@@ -1668,10 +1635,10 @@ namespace Slang
operand++;
}
- for (UInt ii = 0; ii < varArgListCount; ++ii)
+ for (Int ii = 0; ii < varArgListCount; ++ii)
{
- UInt listArgCount = listArgCounts[ii];
- for (UInt jj = 0; jj < listArgCount; ++jj)
+ Int listArgCount = listArgCounts[ii];
+ for (Int jj = 0; jj < listArgCount; ++jj)
{
if (listArgs[ii])
{
@@ -1687,52 +1654,31 @@ namespace Slang
return inst;
}
- static IRInst* createInstWithSizeImpl(
- IRBuilder* builder,
- IROp op,
- IRType* type,
- size_t sizeInBytes)
- {
- auto module = builder->getModule();
- IRInst* inst = (IRInst*)module->memoryArena.allocate(sizeInBytes);
- // Zero only the 'type'
- memset(inst, 0, sizeof(IRInst));
- // TODO: Do we need to run ctor after zeroing?
- new (inst) IRInst;
-
-#if SLANG_ENABLE_IR_BREAK_ALLOC
- inst->_debugUID = _debugGetAndIncreaseInstCounter();
-#endif
-
- inst->m_op = op;
- if (type)
- {
- inst->typeUse.init(inst, type);
- }
- maybeSetSourceLoc(builder, inst);
- return inst;
- }
-
+ // Create an IR instruction/value and initialize it.
+ //
+ // In this case `argCount` and `args` represent the
+ // arguments *after* the type (which is a mandatory
+ // argument for all instructions).
template<typename T>
static T* createInstImpl(
- IRBuilder* builder,
- IROp op,
- IRType* type,
- UInt fixedArgCount,
- IRInst* const* fixedArgs,
- UInt varArgCount = 0,
- IRInst* const* varArgs = nullptr)
+ IRBuilder* builder,
+ IROp op,
+ IRType* type,
+ Int fixedArgCount,
+ IRInst* const* fixedArgs,
+ Int varArgListCount,
+ Int const* listArgCounts,
+ IRInst* const* const* listArgs)
{
- return createInstImpl<T>(
- builder->getModule(),
- builder,
- op,
+ return (T*) builder->_createInst(
+ sizeof(T),
type,
+ op,
fixedArgCount,
fixedArgs,
- 1,
- &varArgCount,
- &varArgs);
+ varArgListCount,
+ listArgCounts,
+ listArgs);
}
template<typename T>
@@ -1740,22 +1686,20 @@ namespace Slang
IRBuilder* builder,
IROp op,
IRType* type,
- UInt fixedArgCount,
+ Int fixedArgCount,
IRInst* const* fixedArgs,
- UInt varArgListCount,
- UInt const* listArgCount,
- IRInst* const* const* listArgs)
+ Int varArgCount = 0,
+ IRInst* const* varArgs = nullptr)
{
return createInstImpl<T>(
- builder->getModule(),
builder,
op,
type,
fixedArgCount,
fixedArgs,
- varArgListCount,
- listArgCount,
- listArgs);
+ 1,
+ &varArgCount,
+ &varArgs);
}
template<typename T>
@@ -1763,8 +1707,8 @@ namespace Slang
IRBuilder* builder,
IROp op,
IRType* type,
- UInt argCount,
- IRInst* const* args)
+ Int argCount,
+ IRInst* const* args)
{
return createInstImpl<T>(
builder,
@@ -1825,8 +1769,8 @@ namespace Slang
IRBuilder* builder,
IROp op,
IRType* type,
- UInt argCount,
- IRInst* const* args)
+ Int argCount,
+ IRInst* const* args)
{
return createInstImpl<T>(
builder,
@@ -1841,9 +1785,9 @@ namespace Slang
IRBuilder* builder,
IROp op,
IRType* type,
- UInt fixedArgCount,
+ Int fixedArgCount,
IRInst* const* fixedArgs,
- UInt varArgCount,
+ Int varArgCount,
IRInst* const* varArgs)
{
return createInstImpl<T>(
@@ -1862,7 +1806,7 @@ namespace Slang
IROp op,
IRType* type,
IRInst* arg1,
- UInt varArgCount,
+ Int varArgCount,
IRInst* const* varArgs)
{
IRInst* fixedArgs[] = { arg1 };
@@ -2038,8 +1982,7 @@ namespace Slang
}
}
- static IRConstant* findOrEmitConstant(
- IRBuilder* builder,
+ IRConstant* IRBuilder::_findOrEmitConstant(
IRConstant& keyInst)
{
// We now know where we want to insert, but there might
@@ -2054,7 +1997,7 @@ namespace Slang
key.inst = &keyInst;
IRConstant* irValue = nullptr;
- if( builder->sharedBuilder->constantMap.TryGetValue(key, irValue) )
+ if( getSharedBuilder()->getConstantMap().TryGetValue(key, irValue) )
{
// We found a match, so just use that.
return irValue;
@@ -2072,19 +2015,22 @@ namespace Slang
case kIROp_BoolLit:
case kIROp_IntLit:
{
- irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), prefixSize + sizeof(IRIntegerValue)));
+ const size_t instSize = prefixSize + sizeof(IRIntegerValue);
+ irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp()));
irValue->value.intVal = keyInst.value.intVal;
break;
}
case kIROp_FloatLit:
{
- irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), prefixSize + sizeof(IRFloatingPointValue)));
+ const size_t instSize = prefixSize + sizeof(IRFloatingPointValue);
+ irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp()));
irValue->value.floatVal = keyInst.value.floatVal;
break;
}
case kIROp_PtrLit:
{
- irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), prefixSize + sizeof(void*)));
+ const size_t instSize = prefixSize + sizeof(void*);
+ irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp()));
irValue->value.ptrVal = keyInst.value.ptrVal;
break;
}
@@ -2095,7 +2041,7 @@ namespace Slang
const size_t sliceSize = slice.getLength();
const size_t instSize = prefixSize + offsetof(IRConstant::StringValue, chars) + sliceSize;
- irValue = static_cast<IRConstant*>(createInstWithSizeImpl(builder, keyInst.getOp(), keyInst.getFullType(), instSize));
+ irValue = static_cast<IRConstant*>(_createInst(instSize, keyInst.getFullType(), keyInst.getOp()));
IRConstant::StringValue& dstString = irValue->value.stringVal;
@@ -2110,9 +2056,9 @@ namespace Slang
}
key.inst = irValue;
- builder->sharedBuilder->constantMap.Add(key, irValue);
+ getSharedBuilder()->getConstantMap().Add(key, irValue);
- addHoistableInst(builder, irValue);
+ addHoistableInst(this, irValue);
return irValue;
}
@@ -2126,7 +2072,7 @@ namespace Slang
keyInst.m_op = kIROp_BoolLit;
keyInst.typeUse.usedValue = getBoolType();
keyInst.value.intVal = IRIntegerValue(inValue);
- return findOrEmitConstant(this, keyInst);
+ return _findOrEmitConstant(keyInst);
}
IRInst* IRBuilder::getIntValue(IRType* type, IRIntegerValue inValue)
@@ -2136,7 +2082,7 @@ namespace Slang
keyInst.m_op = kIROp_IntLit;
keyInst.typeUse.usedValue = type;
keyInst.value.intVal = inValue;
- return findOrEmitConstant(this, keyInst);
+ return _findOrEmitConstant(keyInst);
}
IRInst* IRBuilder::getFloatValue(IRType* type, IRFloatingPointValue inValue)
@@ -2146,7 +2092,7 @@ namespace Slang
keyInst.m_op = kIROp_FloatLit;
keyInst.typeUse.usedValue = type;
keyInst.value.floatVal = inValue;
- return findOrEmitConstant(this, keyInst);
+ return _findOrEmitConstant(keyInst);
}
IRStringLit* IRBuilder::getStringValue(const UnownedStringSlice& inSlice)
@@ -2167,7 +2113,7 @@ namespace Slang
dstSlice.chars = const_cast<char*>(inSlice.begin());
dstSlice.numChars = uint32_t(inSlice.getLength());
- return static_cast<IRStringLit*>(findOrEmitConstant(this, keyInst));
+ return static_cast<IRStringLit*>(_findOrEmitConstant(keyInst));
}
IRPtrLit* IRBuilder::getPtrValue(void* value)
@@ -2179,7 +2125,7 @@ namespace Slang
keyInst.m_op = kIROp_PtrLit;
keyInst.typeUse.usedValue = type;
keyInst.value.ptrVal = value;
- return (IRPtrLit*) findOrEmitConstant(this, keyInst);
+ return (IRPtrLit*) _findOrEmitConstant(keyInst);
}
IRInst* IRBuilder::getCapabilityValue(CapabilitySet const& caps)
@@ -2226,7 +2172,7 @@ namespace Slang
operandCount += listOperandCounts[ii];
}
- auto& memoryArena = getModule()->memoryArena;
+ auto& memoryArena = getModule()->getMemoryArena();
void* cursor = memoryArena.getCursor();
// We are going to create a 'dummy' instruction on the memoryArena
@@ -2266,7 +2212,7 @@ namespace Slang
IRInstKey key = { inst };
// Ideally we would add if not found, else return if was found instead of testing & then adding.
- IRInst** found = sharedBuilder->globalValueNumberingMap.TryGetValueOrAdd(key, inst);
+ IRInst** found = getSharedBuilder()->getGlobalValueNumberingMap().TryGetValueOrAdd(key, inst);
SLANG_ASSERT(endCursor == memoryArena.getCursor());
// If it's found, just return, and throw away the instruction
if (found)
@@ -2285,7 +2231,7 @@ namespace Slang
inst->typeUse.init(inst, type);
}
- maybeSetSourceLoc(this, inst);
+ _maybeSetSourceLoc(inst);
IRUse*const operands = inst->getOperands();
for (UInt i = 0; i < operandCount; ++i)
@@ -2316,7 +2262,7 @@ namespace Slang
operandCount += listOperandCounts[ii];
}
- auto& memoryArena = getModule()->memoryArena;
+ auto& memoryArena = getModule()->getMemoryArena();
void* cursor = memoryArena.getCursor();
// We are going to create a 'dummy' instruction on the memoryArena
@@ -2356,7 +2302,7 @@ namespace Slang
IRInstKey key = { inst };
// Ideally we would add if not found, else return if was found instead of testing & then adding.
- IRInst** found = sharedBuilder->globalValueNumberingMap.TryGetValueOrAdd(key, inst);
+ IRInst** found = getSharedBuilder()->getGlobalValueNumberingMap().TryGetValueOrAdd(key, inst);
SLANG_ASSERT(endCursor == memoryArena.getCursor());
// If it's found, just return, and throw away the instruction
if (found)
@@ -2375,7 +2321,7 @@ namespace Slang
inst->typeUse.init(inst, type);
}
- maybeSetSourceLoc(this, inst);
+ _maybeSetSourceLoc(inst);
IRUse*const operands = inst->getOperands();
for (UInt i = 0; i < operandCount; ++i)
@@ -3216,22 +3162,13 @@ namespace Slang
return inst;
}
- IRModule* IRBuilder::createModule()
+ RefPtr<IRModule> IRModule::create(Session* session)
{
- auto module = new IRModule();
- module->session = getSession();
+ RefPtr<IRModule> module = new IRModule(session);
- auto moduleInst = createInstImpl<IRModuleInst>(
- module,
- this,
- kIROp_Module,
- nullptr,
- 0,
- nullptr,
- 0,
- nullptr,
- nullptr);
- module->moduleInst = moduleInst;
+ auto moduleInst = module->_allocateInst<IRModuleInst>(kIROp_Module, 0);
+
+ module->m_moduleInst = moduleInst;
moduleInst->module = module;
return module;
@@ -3248,7 +3185,9 @@ namespace Slang
// parent instruction for the builder, and
// possibly work our way up.
//
- auto parent = builder->insertIntoParent;
+ auto defaultInsertLoc = builder->getInsertLoc();
+ auto defaultParent = defaultInsertLoc.getParent();
+ auto parent = defaultParent;
while(parent)
{
// Inserting into the top level of a module?
@@ -3281,10 +3220,9 @@ namespace Slang
// current "insert into" parent for the builder, then
// we need to respect its "insert before" setting
// as well.
- if (parent == builder->insertIntoParent
- && builder->insertBeforeInst)
+ if (parent == defaultParent)
{
- value->insertBefore(builder->insertBeforeInst);
+ value->insertAt(defaultInsertLoc);
}
else
{
@@ -3298,7 +3236,7 @@ namespace Slang
this,
kIROp_Func,
nullptr);
- maybeSetSourceLoc(this, rsFunc);
+ _maybeSetSourceLoc(rsFunc);
addGlobalValue(this, rsFunc);
return rsFunc;
}
@@ -3311,7 +3249,7 @@ namespace Slang
this,
kIROp_GlobalVar,
ptrType);
- maybeSetSourceLoc(this, globalVar);
+ _maybeSetSourceLoc(globalVar);
addGlobalValue(this, globalVar);
return globalVar;
}
@@ -3323,7 +3261,7 @@ namespace Slang
this,
kIROp_GlobalParam,
valueType);
- maybeSetSourceLoc(this, inst);
+ _maybeSetSourceLoc(inst);
addGlobalValue(this, inst);
return inst;
}
@@ -5581,6 +5519,29 @@ namespace Slang
insertAtEnd(p);
}
+ void IRInst::insertAt(IRInsertLoc const& loc)
+ {
+ removeFromParent();
+ IRInst* other = loc.getInst();
+ switch(loc.getMode())
+ {
+ case IRInsertLoc::Mode::None:
+ break;
+ case IRInsertLoc::Mode::Before:
+ insertBefore(other);
+ break;
+ case IRInsertLoc::Mode::After:
+ insertAfter(other);
+ break;
+ case IRInsertLoc::Mode::AtStart:
+ insertAtStart(other);
+ break;
+ case IRInsertLoc::Mode::AtEnd:
+ insertAtEnd(other);
+ break;
+ }
+ }
+
// Remove this instruction from its parent block,
// and then destroy it (it had better have no uses!)
void IRInst::removeFromParent()
diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h
index 6006ce64c..4d1c153b4 100644
--- a/source/slang/slang-ir.h
+++ b/source/slang/slang-ir.h
@@ -305,6 +305,151 @@ public:
}
};
+ /// A marker for a place where IR instructions can be inserted
+ ///
+ /// An insertion location is defined relative to an existing IR
+ /// instruction, along with an enumeration that specifies where
+ /// new instructions should be inserted relative to the existing one.
+ ///
+ /// Available options are:
+ ///
+ /// * `None`, meaning the instruction is null/absent. This can either
+ /// represent an invalid/unitialized location, or an intention for
+ /// new instructions to be created without any parent.
+ ///
+ /// * `AtEnd`, meaning new instructions will be inserted as the last
+ /// child of the existing instruction. This is useful for filling
+ /// in the children of a basic block or other container for a sequence
+ /// of instructions. Note that since each new instruction will become
+ /// the last one in the parent, instructions emitted at such a location
+ /// will appear in the same order that they were emitted.
+ ///
+ /// * `Before`, meaning new instructions will be inserted before the existing
+ /// one. This is useful for inserting new instructions to compute a value
+ /// needed during optimization of an existing instruction (including when
+ /// the new instructions will *replace* the existing one). Because each
+ /// new instruction is inserted right before the existing one, the instructions
+ /// will appear in the same order that they were emitted.
+ ///
+ /// * `AtStart`, meaning new instructions will be inserted as the first
+ /// child of the existing instruction. This is useful for adding things
+ /// like decorations to an existing instruction (since decorations are
+ /// currently required to precede all other kinds of child instructions).
+ /// Note that if multiple new instructions are inserted in this mode they
+ /// will appear in the *reverse* of the order they were emitted.
+ ///
+ /// * `After`, meaning new instructions will be inserted as the next child
+ /// after the existing instruction.
+ /// Note that if multiple new instructions are inserted in this mode they
+ /// will appear in the *reverse* of the order they were emitted.
+ ///
+ /// An insertion location is usable and valid so long as the instruction it is
+ /// defined relative to is valid to insert into or next to. If the reference
+ /// instruction is moved, subsequent insertions will use its new location, but
+ /// already-inserted instructions will *not*.
+ ///
+ /// Note that at present there is no way to construct an `IRInsertLoc` that
+ /// can reliably be used to insert at certain locations that can be clearly
+ /// defined verbally (e.g., "at the end of the parameter list of this function").
+ /// Often a suitable approximation will work inside a specific pass (e.g., when
+ /// first constructing a function, the `AtEnd` mode could be used to insert
+ /// all parameters before any body instructions are inserted, and for an existing
+ /// function new parameters could be inserted `Before` the first existing body
+ /// instruction). Such approximations require knowing which kinds of IR modifications
+ /// will and will not be performed while the location is in use.
+ ///
+struct IRInsertLoc
+{
+public:
+ /// The different kinds of insertion locations.
+ enum class Mode
+ {
+ None, //< Don't insert new instructions at all; just create them
+ Before, //< Insert immediately before the existing instruction
+ After, //< Insert immediately after the existing instruction
+ AtStart, //< Insert at the start of the existing instruction's child list
+ AtEnd, //< Insert at the start of the existing instruction's child list
+ };
+
+ /// Construct a default insertion location in the `None` mode.
+ IRInsertLoc()
+ {}
+
+ /// Construct a location that inserts before `inst`
+ static IRInsertLoc before(IRInst* inst)
+ {
+ SLANG_ASSERT(inst);
+ return IRInsertLoc(Mode::Before, inst);
+ }
+
+ /// Construct a location that inserts after `inst`
+ ///
+ /// Note: instructions inserted at this location will appear in the opposite
+ /// of the order they were emitted.
+ static IRInsertLoc after(IRInst* inst)
+ {
+ SLANG_ASSERT(inst);
+ return IRInsertLoc(Mode::After, inst);
+ }
+
+ /// Construct a location that inserts at the start of the child list for `parent`
+ ///
+ /// Note: instructions inserted at this location will appear in the opposite
+ /// of the order they were emitted.
+ static IRInsertLoc atStart(IRInst* parent)
+ {
+ SLANG_ASSERT(parent);
+ return IRInsertLoc(Mode::AtStart, parent);
+ }
+
+ /// Construct a location that inserts at the end of the child list for `parent`
+ static IRInsertLoc atEnd(IRInst* parent)
+ {
+ SLANG_ASSERT(parent);
+ return IRInsertLoc(Mode::AtEnd, parent);
+ }
+
+ /// Get the insertion mode for this location
+ Mode getMode() const { return m_mode; }
+
+ /// Get the instruction that this location inserts relative to
+ IRInst* getInst() const { return m_inst; }
+
+ /// Get the parent instruction that new instructions will insert into.
+ ///
+ /// For the `AtStart` and `AtEnd` modes, this returns `getInst()`.
+ /// For the `Before` and `After` modes, this returns `getInst()->getParent()`
+ IRInst* getParent() const;
+
+ /// Get the parent basic block, if any, that new instructions will insert into.
+ ///
+ /// This returns the same instruction as `getParent()` if the parent is a basic block.
+ /// Otherwise, returns null.
+ IRBlock* getBlock() const;
+
+ /// Get the enclosing function (or other code-bearing value) that instructions are inserted into.
+ ///
+ /// This searches up the parent chain starting with `getParent()` looking for a code-bearing
+ /// value that things are being inserted into (could be a function, generic, etc.)
+ ///
+ IRGlobalValueWithCode* getFunc() const;
+
+private:
+ /// Internal constructor
+ IRInsertLoc(Mode mode, IRInst* inst)
+ : m_mode(mode)
+ , m_inst(inst)
+ {}
+
+ /// The insertion mode
+ Mode m_mode = Mode::None;
+
+ /// The instruction that insertions will be made relative to.
+ ///
+ /// Should always be null for the `None` mode and non-null for all other modes.
+ IRInst* m_inst = nullptr;
+};
+
// Every value in the IR is an instruction (even things
// like literal values).
//
@@ -475,6 +620,8 @@ struct IRInst
// that this value will now have no uses.
void replaceUsesWith(IRInst* other);
+ void insertAt(IRInsertLoc const& loc);
+
// Insert this instruction into the same basic block
// as `other`, right before/after it.
void insertBefore(IRInst* other);
@@ -1469,27 +1616,78 @@ struct IRModuleInst : IRInst
struct IRModule : RefObject
{
+public:
enum
{
kMemoryArenaBlockSize = 16 * 1024, ///< Use 16k block size for memory arena
};
- SLANG_FORCE_INLINE Session* getSession() const { return session; }
- SLANG_FORCE_INLINE IRModuleInst* getModuleInst() const { return moduleInst; }
+ static RefPtr<IRModule> create(Session* session);
+
+ SLANG_FORCE_INLINE Session* getSession() const { return m_session; }
+ SLANG_FORCE_INLINE IRModuleInst* getModuleInst() const { return m_moduleInst; }
+ SLANG_FORCE_INLINE MemoryArena& getMemoryArena() { return m_memoryArena; }
IRInstListBase getGlobalInsts() const { return getModuleInst()->getChildren(); }
+ /// Create an empty instruction with the `op` opcode and space for
+ /// a number of operands given by `operandCount`.
+ ///
+ /// The memory allocation will be *at least* `minSizeInBytes`, so
+ /// if `sizeof(T)` is passed in the reuslt is guaranteed to be big
+ /// enough for a `T` instance. It is safe to leave `minSizeInBytes` as zero
+ /// for instructions where the only additional space they require is
+ /// for their operands (which is most of them).
+ ///
+ /// The returned instruction is "empty" in thes sense that the `IRUse`s
+ /// for its type and operands are *not* initialized. The caller takes
+ /// full responsibility for initializing those uses as needed.
+ ///
+ /// This function does not (and cannot) perform any kind of deduplication
+ /// or simplification. Clients take responsibility for only using this
+ /// operation when they genuinely want a fresh instruction to be allocated.
+ ///
+ /// Note: the `_` prefix indicates that this is a low-level operation that
+ /// must cient code should not be invoking. When in doubt, plase try to
+ /// operations in `IRBuilder` to emit an instruction whenever possible.
+ ///
+ IRInst* _allocateInst(
+ IROp op,
+ Int operandCount,
+ size_t minSizeInBytes = 0);
+
+ template<typename T>
+ T* _allocateInst(
+ IROp op,
+ Int operandCount)
+ {
+ return (T*) _allocateInst(op, operandCount, sizeof(T));
+ }
+
+private:
+ IRModule() = delete;
+
/// Ctor
- IRModule():
- memoryArena(kMemoryArenaBlockSize)
+ IRModule(Session* session)
+ : m_session(session)
+ , m_memoryArena(kMemoryArenaBlockSize)
{
}
- MemoryArena memoryArena;
+ // The compilation session in use.
+ Session* m_session = nullptr;
+
+ /// The root IR instruction for the module.
+ ///
+ /// All other IR instructions that make up the state/contents of the module are
+ /// descendents of this instruction. Thus if we follow the chain of parent
+ /// instructions from an arbitrary IR instruction we expect to find the
+ /// `IRModuleInst` for the module the instruction belongs to, if any.
+ ///
+ IRModuleInst* m_moduleInst = nullptr;
- // The compilation session in use.
- Session* session;
- IRModuleInst* moduleInst;
+ /// The memory arena from which all IR instructions (and any associated state) in this module are allocated.
+ MemoryArena m_memoryArena;
};
@@ -1543,16 +1741,6 @@ void dumpIR(IRModule* module, const IRDumpOptions& options, SourceManager* sourc
void dumpIR(IRInst* globalVal, const IRDumpOptions& options, SourceManager* sourceManager, ISlangWriter* writer);
void dumpIR(IRModule* module, const IRDumpOptions& options, char const* label, SourceManager* sourceManager, ISlangWriter* writer);
-IRInst* createEmptyInst(
- IRModule* module,
- IROp op,
- int totalArgCount);
-
-IRInst* createEmptyInstWithSize(
- IRModule* module,
- IROp op,
- size_t totalSizeInBytes);
-
/// True if the op type can be handled 'nominally' meaning that pointer identity is applicable.
bool isNominalOp(IROp op);
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 3d686304a..40c88a0bc 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -1083,7 +1083,7 @@ IRStructKey* getInterfaceRequirementKey(
IRBuilder builderStorage = *context->irBuilder;
auto builder = &builderStorage;
- builder->setInsertInto(builder->sharedBuilder->module->getModuleInst());
+ builder->setInsertInto(builder->getModule());
// Construct a key to serve as the representation of
// this requirement in the IR, and to allow lookup
@@ -1259,9 +1259,8 @@ struct ValLoweringVisitor : ValVisitor<ValLoweringVisitor, LoweredValInfo, Lower
auto irFunc = getBuilder()->createFunc();
irSatisfyingVal = irFunc;
- IRBuilder subBuilderStorage;
+ IRBuilder subBuilderStorage(getBuilder()->getSharedBuilder());
auto subBuilder = &subBuilderStorage;
- subBuilder->sharedBuilder = getBuilder()->sharedBuilder;
subBuilder->setInsertInto(irFunc);
// We will start by setting up the function parameters,
@@ -5909,7 +5908,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// IR global variable under the parent of its containing
// function.
//
- auto parent = getBuilder()->insertIntoParent;
+ auto parent = getBuilder()->getInsertLoc().getParent();
if(auto block = as<IRBlock>(parent))
parent = block->getParent();
@@ -6695,8 +6694,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
// return f : ftype;
// }
// ```
- IRBuilder typeBuilder;
- typeBuilder.sharedBuilder = subBuilder->sharedBuilder;
+ IRBuilder typeBuilder(subBuilder->getSharedBuilder());
IRCloneEnv cloneEnv = {};
if (returnType)
{
@@ -7546,9 +7544,8 @@ LoweredValInfo ensureDecl(
env = env->outer;
}
- IRBuilder subIRBuilder;
- subIRBuilder.sharedBuilder = context->irBuilder->sharedBuilder;
- subIRBuilder.setInsertInto(subIRBuilder.sharedBuilder->module->getModuleInst());
+ IRBuilder subIRBuilder(context->irBuilder->getSharedBuilder());
+ subIRBuilder.setInsertInto(subIRBuilder.getModule());
IRGenEnv subEnv;
subEnv.outer = context->env;
@@ -7961,14 +7958,15 @@ static void ensureAllDeclsRec(
}
}
-IRModule* generateIRForTranslationUnit(
+RefPtr<IRModule> generateIRForTranslationUnit(
ASTBuilder* astBuilder,
TranslationUnitRequest* translationUnit)
{
+ auto session = translationUnit->getSession();
auto compileRequest = translationUnit->compileRequest;
SharedIRGenContext sharedContextStorage(
- translationUnit->getSession(),
+ session,
translationUnit->compileRequest->getSink(),
translationUnit->compileRequest->getLinkage()->m_obfuscateCode,
translationUnit->getModuleDecl());
@@ -7977,17 +7975,13 @@ IRModule* generateIRForTranslationUnit(
IRGenContext contextStorage(sharedContext, astBuilder);
IRGenContext* context = &contextStorage;
- SharedIRBuilder sharedBuilderStorage;
+ RefPtr<IRModule> module = IRModule::create(session);
+
+ SharedIRBuilder sharedBuilderStorage(module);
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = nullptr;
- sharedBuilder->session = compileRequest->getSession();
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilder);
IRBuilder* builder = &builderStorage;
- builder->sharedBuilder = sharedBuilder;
-
- IRModule* module = builder->createModule();
- sharedBuilder->module = module;
context->irBuilder = builder;
@@ -8181,19 +8175,15 @@ struct SpecializedComponentTypeIRGenContext : ComponentTypeVisitor
IRGenContext contextStorage(sharedContext, linkage->getASTBuilder());
context = &contextStorage;
- SharedIRBuilder sharedBuilderStorage;
+ RefPtr<IRModule> module = IRModule::create(session);
+
+ SharedIRBuilder sharedBuilderStorage(module);
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = nullptr;
- sharedBuilder->session = session;
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilder);
builder = &builderStorage;
- builder->sharedBuilder = sharedBuilder;
-
- RefPtr<IRModule> module = builder->createModule();
- sharedBuilder->module = module;
- builder->setInsertInto(module->getModuleInst());
+ builder->setInsertInto(module);
context->irBuilder = builder;
@@ -8315,19 +8305,15 @@ struct TypeConformanceIRGenContext
IRGenContext contextStorage(sharedContext, linkage->getASTBuilder());
context = &contextStorage;
- SharedIRBuilder sharedBuilderStorage;
+ RefPtr<IRModule> module = IRModule::create(session);
+
+ SharedIRBuilder sharedBuilderStorage(module);
SharedIRBuilder* sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = nullptr;
- sharedBuilder->session = session;
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilder);
builder = &builderStorage;
- builder->sharedBuilder = sharedBuilder;
-
- RefPtr<IRModule> module = builder->createModule();
- sharedBuilder->module = module;
- builder->setInsertInto(module->getModuleInst());
+ builder->setInsertInto(module);
context->irBuilder = builder;
@@ -8667,19 +8653,15 @@ RefPtr<IRModule> TargetProgram::createIRModuleForLayout(DiagnosticSink* sink)
IRLayoutGenContext contextStorage(sharedContext, astBuilder);
auto context = &contextStorage;
- SharedIRBuilder sharedBuilderStorage;
+ RefPtr<IRModule> irModule = IRModule::create(session);
+
+ SharedIRBuilder sharedBuilderStorage(irModule);
auto sharedBuilder = &sharedBuilderStorage;
- sharedBuilder->module = nullptr;
- sharedBuilder->session = session;
- IRBuilder builderStorage;
+ IRBuilder builderStorage(sharedBuilder);
auto builder = &builderStorage;
- builder->sharedBuilder = sharedBuilder;
-
- RefPtr<IRModule> irModule = builder->createModule();
- sharedBuilder->module = irModule;
- builder->setInsertInto(irModule->getModuleInst());
+ builder->setInsertInto(irModule);
context->irBuilder = builder;
diff --git a/source/slang/slang-lower-to-ir.h b/source/slang/slang-lower-to-ir.h
index ce7f9eaf0..859721beb 100644
--- a/source/slang/slang-lower-to-ir.h
+++ b/source/slang/slang-lower-to-ir.h
@@ -26,7 +26,7 @@ namespace Slang
/// module must be linked against other IR modules that define any symbols
/// that are imported before code generation can be performed.
///
- IRModule* generateIRForTranslationUnit(
+ RefPtr<IRModule> generateIRForTranslationUnit(
ASTBuilder* astBuilder,
TranslationUnitRequest* translationUnit);
diff --git a/source/slang/slang-serialize-ir.cpp b/source/slang/slang-serialize-ir.cpp
index 96818a130..0824bd68d 100644
--- a/source/slang/slang-serialize-ir.cpp
+++ b/source/slang/slang-serialize-ir.cpp
@@ -676,16 +676,47 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo
typedef Ser::Inst::PayloadType PayloadType;
m_serialData = &data;
-
- auto module = new IRModule();
+
+ auto module = IRModule::create(session);
outModule = module;
m_module = module;
- module->session = session;
-
// Convert m_stringTable into StringSlicePool.
SerialStringTableUtil::decodeStringTable(data.m_stringTable.getBuffer(), data.m_stringTable.getCount(), m_stringTable);
+ // Each IR instruction has:
+ //
+ // * An opcode
+ // * Zero or more operands
+ // * Zero or more children
+ //
+ // Most instructions are entirely defined by those properties.
+ //
+ // The instructions that represent simple constants (integers, strings, etc.) are
+ // unique in that they have "payload" data that holds their value, instead of having
+ // any operands.
+ //
+ // The deserialization logic here is set up to handle an arbitrary configuration
+ // of IR instructions, which means it can handle cases where:
+ //
+ // * An instruction earlier in the serialized stream might refer to an instruction
+ // later in the stream, as one of its operands or (transitive) children.
+ //
+ // * An instruction in the stream transitively depends on itself via operand
+ // and/or child relationships.
+ //
+ // In order to handle these cases, deserialization proceeds in multiple passes.
+ // In the first pass, `IRInst`s are allocated for each instruction in the stream,
+ // based on their memory requirements (number of operands in the ordinary case
+ // and payload size in the case of simple constants). Subsequent passes then
+ // fill in the operands and/or children.
+ //
+ // Note that as a result of the strategy used here, it is not possible for the
+ // deserialization logic to interact with any systems for deduplication or
+ // simplification of instructions. An alternative version of the deserializer that
+ // uses the `IRBuilder` interface instead might be possible, but would need a
+ // plan for how to handle forward and/or circular references in the IR module.
+
// Add all the instructions
List<IRInst*> insts;
@@ -704,10 +735,10 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo
SLANG_RELEASE_ASSERT(srcInst.m_op == kIROp_Module);
SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Empty);
- // Create the module inst
- auto moduleInst = static_cast<IRModuleInst*>(createEmptyInstWithSize(module, kIROp_Module, sizeof(IRModuleInst)));
- module->moduleInst = moduleInst;
- moduleInst->module = module;
+ // The root IR instruction for the module will already have
+ // been created as part of creating `module` above.
+ //
+ auto moduleInst = module->getModuleInst();
// Set the IRModuleInst
insts[1] = moduleInst;
@@ -726,34 +757,41 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo
// Calculate the minimum object size (ie not including the payload of value)
const size_t prefixSize = SLANG_OFFSET_OF(IRConstant, value);
+ // All IR constants have zero operands.
+ Int operandCount = 0;
+
IRConstant* irConst = nullptr;
switch (op)
{
case kIROp_BoolLit:
{
+ // TODO: Most of these cases could use the templated `_allocateInst<T>`
+ // *if* we had distinct `IRConstant` subtypes to represent these
+ // cases and their subtype-specific payloads.
+
SLANG_ASSERT(srcInst.m_payloadType == PayloadType::UInt32);
- irConst = static_cast<IRConstant*>(createEmptyInstWithSize(module, op, prefixSize + sizeof(IRIntegerValue)));
+ irConst = static_cast<IRConstant*>(module->_allocateInst(op, operandCount, prefixSize + sizeof(IRIntegerValue)));
irConst->value.intVal = srcInst.m_payload.m_uint32 != 0;
break;
}
case kIROp_IntLit:
{
SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Int64);
- irConst = static_cast<IRConstant*>(createEmptyInstWithSize(module, op, prefixSize + sizeof(IRIntegerValue)));
+ irConst = static_cast<IRConstant*>(module->_allocateInst(op, operandCount, prefixSize + sizeof(IRIntegerValue)));
irConst->value.intVal = srcInst.m_payload.m_int64;
break;
}
case kIROp_PtrLit:
{
SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Int64);
- irConst = static_cast<IRConstant*>(createEmptyInstWithSize(module, op, prefixSize + sizeof(void*)));
+ irConst = static_cast<IRConstant*>(module->_allocateInst(op, operandCount, prefixSize + sizeof(void*)));
irConst->value.ptrVal = (void*) (intptr_t) srcInst.m_payload.m_int64;
break;
}
case kIROp_FloatLit:
{
SLANG_ASSERT(srcInst.m_payloadType == PayloadType::Float64);
- irConst = static_cast<IRConstant*>(createEmptyInstWithSize(module, op, prefixSize + sizeof(IRFloatingPointValue)));
+ irConst = static_cast<IRConstant*>(module->_allocateInst(op, operandCount, prefixSize + sizeof(IRFloatingPointValue)));
irConst->value.floatVal = srcInst.m_payload.m_float64;
break;
}
@@ -766,7 +804,7 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo
const size_t sliceSize = slice.getLength();
const size_t instSize = prefixSize + SLANG_OFFSET_OF(IRConstant::StringValue, chars) + sliceSize;
- irConst = static_cast<IRConstant*>(createEmptyInstWithSize(module, op, instSize));
+ irConst = static_cast<IRConstant*>(module->_allocateInst(op, operandCount, instSize));
IRConstant::StringValue& dstString = irConst->value.stringVal;
@@ -788,7 +826,12 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo
}
else if (_isTextureTypeBase(op))
{
- IRTextureTypeBase* inst = static_cast<IRTextureTypeBase*>(createEmptyInst(module, op, 1));
+ // TODO: We should clean up the IR encoding of texture types so that
+ // they do not need to have special-case suport in the serialization layer.
+
+ // All IR texture types currently have a single operand
+ Int operandCount = 1;
+ IRTextureTypeBase* inst = module->_allocateInst<IRTextureTypeBase>(op, operandCount);
SLANG_ASSERT(srcInst.m_payloadType == PayloadType::OperandAndUInt32);
// Reintroduce the texture type bits into the the
@@ -800,7 +843,7 @@ Result IRSerialReader::read(const IRSerialData& data, Session* session, SerialSo
else
{
int numOperands = srcInst.getNumOperands();
- insts[i] = createEmptyInst(module, op, numOperands);
+ insts[i] = module->_allocateInst(op, numOperands);
}
}
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index bef6bd141..5fbc5b4bf 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -2040,7 +2040,7 @@ void FrontEndCompileRequest::generateIR()
// Verify debug information
if (SLANG_FAILED(SerialContainerUtil::verifyIRSerialize(irModule, getSession(), options)))
{
- getSink()->diagnose(irModule->moduleInst->sourceLoc, Diagnostics::serialDebugVerificationFailed);
+ getSink()->diagnose(irModule->getModuleInst()->sourceLoc, Diagnostics::serialDebugVerificationFailed);
}
}