diff options
Diffstat (limited to 'source/slang/slang-ir-link.cpp')
| -rw-r--r-- | source/slang/slang-ir-link.cpp | 189 |
1 files changed, 118 insertions, 71 deletions
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 7e2ac1f98..56b06a499 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -8,14 +8,13 @@ namespace Slang { -// Needed for lookup up entry-point layouts. -// -// TODO: maybe arrange so that codegen is driven from the layout layer -// instead of the input/request layer. + /// Find a suitable layout for `entryPoint` in `programLayout`. + /// + /// TODO: This function should be eliminated. See its body + /// for an explanation of the problems. EntryPointLayout* findEntryPointLayout( ProgramLayout* programLayout, - EntryPoint* entryPoint, - EntryPointGroupLayout** outEntryPointGroupLayout); + EntryPoint* entryPoint); struct IRSpecSymbol : RefObject { @@ -339,9 +338,10 @@ IRType* cloneType( } void cloneGlobalValueWithCodeCommon( - IRSpecContextBase* context, - IRGlobalValueWithCode* clonedValue, - IRGlobalValueWithCode* originalValue); + IRSpecContextBase* context, + IRGlobalValueWithCode* clonedValue, + IRGlobalValueWithCode* originalValue, + IROriginalValuesForClone const& originalValues); IRRate* cloneRate( IRSpecContextBase* context, @@ -382,11 +382,58 @@ IRGlobalVar* cloneGlobalVarImpl( cloneGlobalValueWithCodeCommon( context, clonedVar, - originalVar); + originalVar, + originalValues); return clonedVar; } + /// Clone certain special decorations for `clonedInst` from its (potentially multiple) definitions. + /// + /// In most cases, once we've decided on the "best" definition to use for an IR instruction, + /// we only want the linking process to use the decorations from the single best definition. + /// In some casses, though, the canonical best definition might not have all the information. + /// + /// A concrete example is the `[bindExistentialsSlots(...)]` decorations for global shader + /// parameters and entry points. These decorations are only generated as part of the IR + /// associated with a specialization of a program, and not the original IR for the modules + /// of the program. + /// + /// This function scans through all the `originalValues` that were considered for `clonedInst`, + /// and copies over any decorations that are allowed to come from a non-"best" definition. + /// For a given decoration opcode, only one such decoration will ever be copied, and nothing + /// will be copied if the instruction already has a matching decoration (that was cloned + /// from the "best" definition). + /// +static void cloneExtraDecorations( + IRSpecContextBase* context, + IRInst* clonedInst, + IROriginalValuesForClone const& originalValues) +{ + IRBuilder builderStorage = *context->builder; + IRBuilder* builder = &builderStorage; + builder->setInsertInto(clonedInst); + + for(auto sym = originalValues.sym; sym; sym = sym->nextWithSameName) + { + for(auto decoration : sym->irGlobalValue->getDecorations()) + { + switch(decoration->op) + { + default: + break; + + case kIROp_BindExistentialSlotsDecoration: + if(!clonedInst->findDecorationImpl(decoration->op)) + { + cloneInst(context, builder, decoration); + } + break; + } + } + } +} + void cloneSimpleGlobalValueImpl( IRSpecContextBase* context, IRInst* originalInst, @@ -407,6 +454,12 @@ void cloneSimpleGlobalValueImpl( { cloneInst(context, builder, child); } + + // Also clone certain decorations if they appear on *any* + // definition of the symbol (not necessarily the one + // we picked as the primary/best). + // + cloneExtraDecorations(context, clonedInst, originalValues); } IRGlobalParam* cloneGlobalParamImpl( @@ -469,7 +522,8 @@ IRGeneric* cloneGenericImpl( cloneGlobalValueWithCodeCommon( context, clonedVal, - originalVal); + originalVal, + originalValues); return clonedVal; } @@ -545,7 +599,8 @@ IRInterfaceType* cloneInterfaceTypeImpl( void cloneGlobalValueWithCodeCommon( IRSpecContextBase* context, IRGlobalValueWithCode* clonedValue, - IRGlobalValueWithCode* originalValue) + IRGlobalValueWithCode* originalValue, + IROriginalValuesForClone const& originalValues) { // Next we are going to clone the actual code. IRBuilder builderStorage = *context->builder; @@ -553,6 +608,7 @@ void cloneGlobalValueWithCodeCommon( builder->setInsertInto(clonedValue); cloneDecorations(context, clonedValue, originalValue); + cloneExtraDecorations(context, clonedValue, originalValues); // We will walk through the blocks of the function, and clone each of them. // @@ -629,10 +685,11 @@ void checkIRDuplicate(IRInst* inst, IRInst* moduleInst, UnownedStringSlice const } void cloneFunctionCommon( - IRSpecContextBase* context, - IRFunc* clonedFunc, - IRFunc* originalFunc, - bool checkDuplicate = true) + IRSpecContextBase* context, + IRFunc* clonedFunc, + IRFunc* originalFunc, + IROriginalValuesForClone const& originalValues, + bool checkDuplicate = true) { // First clone all the simple properties. clonedFunc->setFullType(cloneType(context, originalFunc->getFullType())); @@ -640,7 +697,8 @@ void cloneFunctionCommon( cloneGlobalValueWithCodeCommon( context, clonedFunc, - originalFunc); + originalFunc, + originalValues); // Shuffle the function to the end of the list, because // it needs to follow its dependencies. @@ -667,7 +725,6 @@ IRInst* specializeGeneric( IRFunc* specializeIRForEntryPoint( IRSpecContext* context, - EntryPoint* entryPoint, EntryPointLayout* entryPointLayout) { // We start by looking up the IR symbol that @@ -679,7 +736,7 @@ IRFunc* specializeIRForEntryPoint( // so that the mangled name of the decl-ref is // not the same as the mangled name of the decl. // - auto mangledName = getMangledName(entryPoint->getFuncDeclRef()); + auto mangledName = getMangledName(entryPointLayout->getFuncDeclRef()); RefPtr<IRSpecSymbol> sym; if (!context->getSymbols().TryGetValue(mangledName, sym)) { @@ -947,7 +1004,7 @@ IRFunc* cloneFuncImpl( { auto clonedFunc = builder->createFunc(); registerClonedValue(context, clonedFunc, originalValues); - cloneFunctionCommon(context, clonedFunc, originalFunc); + cloneFunctionCommon(context, clonedFunc, originalFunc, originalValues); return clonedFunc; } @@ -1227,7 +1284,9 @@ LinkedIR linkIR( CodeGenTarget target, TargetRequest* targetReq) { - auto sink = compileRequest->getSink(); + // TODO: We need to make sure that the program we are being asked + // to compile has been "resolved" so that it has no outstanding + // unsatisfied requirements. IRSpecializationState stateStorage; auto state = &stateStorage; @@ -1252,12 +1311,11 @@ LinkedIR linkIR( // accelerate lookup, we will create a symbol table for looking // up IR definitions by their mangled name. // - auto originalProgramIRModule = program->getOrCreateIRModule(sink); - insertGlobalValueSymbols(sharedContext, originalProgramIRModule); - for (auto module : program->getModuleDependencies()) + program->enumerateIRModules([&](IRModule* irModule) { - insertGlobalValueSymbols(sharedContext, module->getIRModule()); - } + insertGlobalValueSymbols(sharedContext, irModule); + }); + auto context = state->getContext(); context->shared = sharedContext; @@ -1282,32 +1340,9 @@ LinkedIR linkIR( context->globalVarLayouts.AddIfNotExists(mangledName, globalVarLayout); } - EntryPointGroupLayout* entryPointGroupLayout = nullptr; - auto entryPointLayout = findEntryPointLayout(programLayout, entryPoint, &entryPointGroupLayout); - - auto offsetEntryPointLayout = entryPointLayout->getAbsoluteLayout(entryPointGroupLayout); + auto entryPointLayout = findEntryPointLayout(programLayout, entryPoint); - // Note: when we are doing the compatibility approach for Falcor, we - // can have global-scope symbols that are actually part of the - // local root signature (entry point group), so we need to make - // sure to apply those layouts appropriately. - auto entryPointGroupStructLayout = getScopeStructLayout(entryPointGroupLayout); - for(auto entry : entryPointGroupStructLayout->mapVarToLayout) - { - if(!entry.Key) - continue; - - auto mangledName = getMangledName(entry.Key); - auto groupVarLayout = entry.Value; - - // We need to "adjust" the layout that was computed for the parameter - // because it will be relative to the start of the entry-point group, - // rather than absolute. - // - auto absoluteVarLayout = groupVarLayout->getAbsoluteLayout(entryPointGroupLayout->parametersLayout); - - context->globalVarLayouts.AddIfNotExists(mangledName, absoluteVarLayout); - } + auto offsetEntryPointLayout = entryPointLayout; context->builder->setInsertInto(context->getModule()->getModuleInst()); @@ -1316,7 +1351,7 @@ LinkedIR linkIR( // TODO: This step should *not* be needed with the current IR // specialization approach, so we should consider removing it. // - for (auto sym :context->getSymbols()) + for (auto sym : context->getSymbols()) { if (sym.Value->irGlobalValue->op == kIROp_WitnessTable) cloneGlobalValue(context, (IRWitnessTable*)sym.Value->irGlobalValue); @@ -1327,28 +1362,31 @@ LinkedIR linkIR( // the entry point function itself, and rely on // this step to recursively copy over anything else // it might reference. - auto irEntryPoint = specializeIRForEntryPoint(context, entryPoint, offsetEntryPointLayout); + auto irEntryPoint = specializeIRForEntryPoint(context, offsetEntryPointLayout); - // HACK: right now the bindings for global generic parameters are coming in - // as part of the original IR module, and we need to make sure these get - // copied over, even if they aren't referenced. + // Bindings for global generic parameters are currently represented + // as stand-alone global-scope instructions in the IR module for + // `SpecializedComponentType`s. These instructions are required for + // correct codegen, and so we must make sure to copy them all over, + // even though they are not directly referenced. // - for(auto inst : originalProgramIRModule->getGlobalInsts()) - { - auto bindInst = as<IRBindGlobalGenericParam>(inst); - if(!bindInst) - continue; - - cloneValue(context, bindInst); - } - - for(auto inst : originalProgramIRModule->getGlobalInsts()) + // TODO: We should change these to decorations, akin to how + // `[bindExistentialSlots(...)]` works, so that they can be attached + // to the relevant parameters and cloned via `cloneExtraDecorations`. + // In the long run we do not want to *ever* iterate over all the + // instructions in all the input modules. + // + program->enumerateIRModules([&](IRModule* irModule) { - if(inst->op != kIROp_BindGlobalExistentialSlots) - continue; + for(auto inst : irModule->getGlobalInsts()) + { + auto bindInst = as<IRBindGlobalGenericParam>(inst); + if(!bindInst) + continue; - cloneValue(context, inst); - } + cloneValue(context, bindInst); + } + }); // HACK: we need to ensure that any tagged union types // in the IR module have layout information copied over to them. @@ -1357,7 +1395,7 @@ LinkedIR linkIR( // instructions, since we expected the tagged union type(s) to // be referenced by them. // - for( auto taggedUnionTypeLayout : entryPointLayout->taggedUnionTypeLayouts ) + for( auto taggedUnionTypeLayout : programLayout->taggedUnionTypeLayouts ) { auto taggedUnionType = taggedUnionTypeLayout->getType(); auto mangledName = getMangledTypeName(taggedUnionType); @@ -1377,6 +1415,15 @@ LinkedIR linkIR( // we have global variables with initializers, since // these should get run whether or not the entry point // references them. + // + // Or alternatively we can define by fiat that the initializers + // on global variables get run at an unspecified time between + // program startup and the first access to a given global. + // Such a definition gives us the freedom to eliminate globals + // that are never accessed, while still doing "eager" + // initialization for globals that are referenced (instead of + // having to add the overhead of lazy initialization a la + // function-`static` variables). // Now that we've cloned the entry point and everything // it refers to, we can package up the data we return |
