summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
authorTheresa Foley <tfoleyNV@users.noreply.github.com>2021-12-17 09:35:23 -0800
committerGitHub <noreply@github.com>2021-12-17 09:35:23 -0800
commitcc709e6532e2dc5da3dd19595bc635856d5fd33b (patch)
tree61a00dc975ef0b9db612cf10aa6a31eb2080d882 /source
parentac88374136ae0c9e83d3350ca3113f4bce893911 (diff)
Cleanup refactoring work around the IR builder (#2061)
* Cleanup refactoring work around the IR builder We have some long-term goals for the IR that require a more centralized and disciplined set of rules for how IR instructions get created/emitted. I had been working on trying to set things up so that all IR instruction creation goes through a single bottleneck point, but the non-trivial work in that branch was getting drowned out by the sheer volume of cleanup and refactoring changes. This change tries to pull together several of the more important cleanups. The big pieces are: * `IRBuilder` and `SharedIRBuilder` now protect their data members and rely on users to initialize them more directly via constructor of an `init()` method. This change affects a *bunch* of sites where `IRBuilder`s were created. I changed use sites to use the constructors whenever possible, and to use `init()` in cases where we had longer-lived builders that needed to be initialized multiple times. * The insertion location for the `IRBuilder` now uses an encapsulated type called `IRInsertLoc`. This new type can replace what used to be just two `IRInst*` fields in the builder, and also covers some new functionality (if we ever want to take advantage of it). Very little client code cares about this change, but it is still a nice cleanup in terms of making things more explicit. * The creation of an `IRModule` has been moded *out* of `IRBuilder`, because in practice we `IRBuilder` always wants to be associated with a pre-existing `IRModule` at creation time (via its `SharedIRBuilder`). There is now an `IRModule::create()` operation instead. This required changing the sequencing at many `IRModule` creation sites, since most had been contriving to make an `IRBuilder` first. There were also several cleanups because code had been carelessly using non-reference-counted pointers for `IRModule`s in ways that broke now that `IRModule::create()` always returns a `RefPtr`. * The core operations to actually allocate memory for IR instructions were moved into `IRModule` (since they interact with the memory pool that the module owns). These *were* called `createEmptyInst()` but have been renamed into `_allocateInst()`. In principle these seem like they should only be needed to be called by the `IRBuilder`, but in practice they are also needed by the IR deserialization logic. * A few core operations for emitting IR instructions that were associted with `IRBuilder` were moved to actually be methods on `IRBuilder`. First is `_findOrEmitConstant` which is the primary bottleneck for creating simple scalar constant values. Another is `_createInst` (formerly part of the templated `createInstImpl` along with `createInstWithSizeImpl`) which is the main bottleneck for allocation and initialization of any instruction other than a constant (well, the `IRModuleInst` is the other exception...). Finally, there is also `_maybeSetSourceLoc()`, which is obvious to scope inside the `IRBuilder` once it is protecting the source-location info. Notes: * The `minSizeInBytes` parameter to `_createInst()` might not actually be needed at all. At this point any `IRInst` subtypes that need data allocated for things other than their operands already get created manually via `_allocateInst` or `_findOrEmitConstant`, so I *think* we could remove that part. I will handle that in a subsequent cleanup if it turns out to be the case. * There is one IR pass (`slang-ir-string-hash.cpp`) that is using manual `_allocateInst()` instead of going through an `IRBuilder`. It could be easily cleaned up to not do so (and I will probably make that change down the line), but for now I wanted to avoid doing anything that wasn't close to pure refactoring if I could. * At this point in our design an `IRBuilder` is a very lightweight thing - it basically just owns the insertion location plus a source location to write into instructions. A lot of our code currently treats `IRBuilder`s like they are expensive and/or need to be re-used (which leads to them being used in more mutable/stateful ways). It is quite likely that as we clean up other aspects of the implementation of IR creation/emission we can make `IRBuilder` use feel more lightweight in ways that can streamline and simplify code. * The next step for this work is to identify the different paths that eventually lead to `_createInst()` being called, and unify them at a single bottleneck operation that can own the decisions around when to create an instruction vs. when to re-use an existing one (rather than those decisions being baked into the various `IRBuilder` subroutines that create instructions of the various subtypes). * fixup: gcc/clang C++ spec details
Diffstat (limited to 'source')
-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);
}
}