summaryrefslogtreecommitdiff
path: root/source/slang/slang-lower-to-ir.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2025-07-17 16:04:20 -0700
committerGitHub <noreply@github.com>2025-07-17 23:04:20 +0000
commit094d1ba7cd1eb5f09be05b2e57b5fbd3041cca38 (patch)
treef9768d9608ae27ac56aef641fbf9c1cac651711a /source/slang/slang-lower-to-ir.cpp
parented1a0b8b53c7556fbf0ccab4f3496078eea4c8a2 (diff)
Prelink ForceInlined functions during lowering. (#7812)
* Prelink ForceInlined functions during lowering. * Fixes and cleanups. * Fix warning. * Fix crash.
Diffstat (limited to 'source/slang/slang-lower-to-ir.cpp')
-rw-r--r--source/slang/slang-lower-to-ir.cpp61
1 files changed, 34 insertions, 27 deletions
diff --git a/source/slang/slang-lower-to-ir.cpp b/source/slang/slang-lower-to-ir.cpp
index 1f5909e94..ab9f85b21 100644
--- a/source/slang/slang-lower-to-ir.cpp
+++ b/source/slang/slang-lower-to-ir.cpp
@@ -18,6 +18,7 @@
#include "slang-ir-inline.h"
#include "slang-ir-insert-debug-value-store.h"
#include "slang-ir-insts.h"
+#include "slang-ir-link.h"
#include "slang-ir-loop-inversion.h"
#include "slang-ir-lower-defer.h"
#include "slang-ir-lower-error-handling.h"
@@ -494,6 +495,10 @@ struct SharedIRGenContext
Dictionary<IntVal*, IRInst*> mapSpecConstValToIRInst;
+ // External (imported) unsafeForceInline functions that need to
+ // prelink into the current module after lowering.
+ List<IRInst*> externalSymbolsToPrelink;
+
void setGlobalValue(Decl* decl, LoweredValInfo value)
{
globalEnv.mapDeclToValue[decl] = value;
@@ -10636,6 +10641,30 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
FunctionDeclBase* decl,
bool emitBody = true)
{
+ bool isFromDifferentModule = isDeclInDifferentModule(context, decl);
+ if (isFromDifferentModule && isForceInlineEarly(decl))
+ {
+ // If a function is imported from another module then
+ // we usually don't want to emit it as a definition, and
+ // will instead only emit a declaration for it with an
+ // appropriate `[import(...)]` linkage decoration.
+ //
+ // However, if the function is marked with `[__unsafeForceInlineEarly]`
+ // then we need to make sure the IR for its definition is available
+ // to the mandatory optimization passes.
+ //
+ // We do so by finding the IR function from the imported module, and clone
+ // the body of the IRFunc from the imported module to the current module.
+ //
+ auto importedModule = getModule(decl);
+ auto irModule = importedModule->getIRModule();
+ SLANG_ASSERT(irModule && "Module containing imported decl does not have an IRModule.");
+ String mangledName = getMangledName(context->astBuilder, decl);
+ auto importedFunc = irModule->findSymbolByMangledName(mangledName);
+ SLANG_ASSERT(importedFunc.getCount() > 0);
+ subContext->shared->externalSymbolsToPrelink.add(importedFunc[0]);
+ }
+
IRGeneric* outerGeneric = nullptr;
subContext->funcDecl = decl;
@@ -10726,32 +10755,7 @@ struct DeclLoweringVisitor : DeclVisitor<DeclLoweringVisitor, LoweredValInfo>
subBuilder->setInsertInto(irFunc);
- // If a function is imported from another module then
- // we usually don't want to emit it as a definition, and
- // will instead only emit a declaration for it with an
- // appropriate `[import(...)]` linkage decoration.
- //
- // However, if the function is marked with `[__unsafeForceInlineEarly]`
- // then we need to make sure the IR for its definition is available
- // to the mandatory optimization passes.
- //
- // TODO: The design here means that we will re-emit the inline
- // function from its AST in every module that uses it. We should
- // instead have logic to clone the target function in from the
- // pre-generated IR for the module that defines it (or do some kind
- // of minimal linking to bring in the inline functions).
- //
- if (!decl->body)
- {
- // This is a function declaration without a body.
- // In Slang we currently try not to support forward declarations
- // (although we might have to give in eventually), so
- // this case should really only occur for builtin declarations.
- }
- else if (isDeclInDifferentModule(context, decl) && !isForceInlineEarly(decl))
- {
- }
- else if (emitBody)
+ if (emitBody && decl->body && !isFromDifferentModule)
{
// This is a function definition, so we need to actually
// construct IR for the body...
@@ -12103,7 +12107,6 @@ RefPtr<IRModule> generateIRForTranslationUnit(
validateIRModuleIfEnabled(compileRequest, module);
-
// We will perform certain "mandatory" optimization passes now.
// These passes serve two purposes:
//
@@ -12122,6 +12125,10 @@ RefPtr<IRModule> generateIRForTranslationUnit(
// dumpIR(module);
+ // Before we can do any validation, we need to prelink [unsafeForceInlineEarly]
+ // functions.
+ prelinkIR(translationUnit->module, module, context->shared->externalSymbolsToPrelink);
+
// First, lower error handling logic into normal control flow.
// This includes lowering throwing functions into functions that
// returns a `Result<T,E>` value, translating `tryCall` into