diff options
Diffstat (limited to 'source/slang')
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); } } |
