summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-ir-link.cpp
diff options
context:
space:
mode:
authorYong He <yonghe@outlook.com>2024-02-26 17:00:31 -0800
committerGitHub <noreply@github.com>2024-02-26 17:00:31 -0800
commit39522159c245e32a99cfdc47f03236f7028f5c61 (patch)
tree4ae93fb32f267f7caa5ce55a6a52aac9f1f33bdd /source/slang/slang-ir-link.cpp
parent1d8e93cd434f0c7acbb6db747b32c3a3720c5c2e (diff)
Allow default values for `extern` symbols. (#3632)
* Allow default values for `extern` symbols. * Fix. * Fix test.
Diffstat (limited to 'source/slang/slang-ir-link.cpp')
-rw-r--r--source/slang/slang-ir-link.cpp100
1 files changed, 100 insertions, 0 deletions
diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp
index be0b87b60..e81eddab7 100644
--- a/source/slang/slang-ir-link.cpp
+++ b/source/slang/slang-ir-link.cpp
@@ -1425,6 +1425,100 @@ static bool _isHLSLExported(IRInst* inst)
return false;
}
+static bool doesFuncHaveDefinition(IRFunc* func)
+{
+ if (func->getFirstBlock() != nullptr)
+ return true;
+ for (auto decor : func->getDecorations())
+ {
+ switch (decor->getOp())
+ {
+ case kIROp_IntrinsicOpDecoration:
+ case kIROp_TargetIntrinsicDecoration:
+ return true;
+ default:
+ continue;
+ }
+ }
+ return false;
+}
+
+static bool doesWitnessTableHaveDefinition(IRWitnessTable* wt)
+{
+ auto interfaceType = as<IRInterfaceType>(wt->getConformanceType());
+ if (!interfaceType)
+ return true;
+ auto interfaceRequirementCount = interfaceType->getRequirementCount();
+ if (interfaceRequirementCount == 0)
+ return true;
+ for (auto entry : wt->getChildren())
+ {
+ if (as<IRWitnessTableEntry>(entry))
+ return true;
+ }
+ return false;
+}
+
+static bool doesTargetAllowUnresolvedFuncSymbol(TargetRequest* req)
+{
+ switch (req->getTarget())
+ {
+ case CodeGenTarget::HLSL:
+ case CodeGenTarget::DXIL:
+ case CodeGenTarget::DXILAssembly:
+ case CodeGenTarget::HostCPPSource:
+ case CodeGenTarget::PyTorchCppBinding:
+ case CodeGenTarget::ShaderHostCallable:
+ case CodeGenTarget::ShaderSharedLibrary:
+ case CodeGenTarget::HostHostCallable:
+ case CodeGenTarget::CPPSource:
+ case CodeGenTarget::CUDASource:
+ case CodeGenTarget::SPIRV:
+ if (req->getOptionSet().getBoolOption(CompilerOptionName::IncompleteLibrary))
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void diagnoseUnresolvedSymbols(TargetRequest* req, DiagnosticSink* sink, IRModule* module)
+{
+ for (auto globalSym : module->getGlobalInsts())
+ {
+ if (globalSym->findDecoration<IRImportDecoration>())
+ {
+ for (;;)
+ {
+ if (auto constant = as<IRGlobalConstant>(globalSym))
+ {
+ if (constant->getOperandCount() == 0)
+ sink->diagnose(globalSym->sourceLoc, Diagnostics::unresolvedSymbol, globalSym);
+ }
+ else if (auto genericSym = as<IRGeneric>(globalSym))
+ {
+ globalSym = findGenericReturnVal(genericSym);
+ continue;
+ }
+ else if (auto funcSym = as<IRFunc>(globalSym))
+ {
+ if (!doesFuncHaveDefinition(funcSym) && !doesTargetAllowUnresolvedFuncSymbol(req))
+ sink->diagnose(globalSym->sourceLoc, Diagnostics::unresolvedSymbol, globalSym);
+ }
+ else if (auto witnessSym = as<IRWitnessTable>(globalSym))
+ {
+ if (!doesWitnessTableHaveDefinition(witnessSym))
+ {
+ sink->diagnose(globalSym->sourceLoc, Diagnostics::unresolvedSymbol, witnessSym);
+ if (auto concreteType = witnessSym->getConcreteType())
+ sink->diagnose(concreteType->sourceLoc, Diagnostics::seeDeclarationOf, concreteType);
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
LinkedIR linkIR(
CodeGenContext* codeGenContext)
{
@@ -1627,6 +1721,12 @@ LinkedIR linkIR(
// Specialize target_switch branches to use the best branch for the target.
specializeTargetSwitch(targetReq, state->irModule);
+ // Diagnose on unresolved symbols if we are compiling into a target that does
+ // not allow incomplete symbols.
+ // At this point, we should not see any [import] symbols that does not have a
+ // definition.
+ diagnoseUnresolvedSymbols(targetReq, codeGenContext->getSink(), state->irModule);
+
// TODO: *technically* we should consider the case where
// we have global variables with initializers, since
// these should get run whether or not the entry point