[llvm] [AMDGPU] Add object linking support for LDS and named barrier lowering in the middle end (PR #191645)
Stanislav Mekhanoshin via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 13 11:57:07 PDT 2026
================
@@ -910,7 +911,170 @@ class AMDGPULowerModuleLDS {
return KernelToCreatedDynamicLDS;
}
+ // Per-TU mode for link-time LDS resolution. Instead of computing a global
+ // layout, create per-function LDS struct declarations so the linker can
+ // assign offsets across TUs.
+ bool runOnModuleLinkTime(Module &M) {
+ bool Changed = superAlignLDSGlobals(M);
+ Changed |= eliminateConstantExprUsesOfLDSFromAllInstructions(M);
+
+ CallGraph CG(M);
+ FunctionVariableMap KernelLDSUses, FunctionLDSUses;
+ getUsesOfLDSByFunction(CG, M, KernelLDSUses, FunctionLDSUses);
+
+ if (KernelLDSUses.empty() && FunctionLDSUses.empty())
+ return Changed;
+
+ FunctionVariableMap AllLDSUses;
+ for (auto &[F, Vars] : KernelLDSUses)
+ AllLDSUses[F].insert(Vars.begin(), Vars.end());
+ for (auto &[F, Vars] : FunctionLDSUses)
+ AllLDSUses[F].insert(Vars.begin(), Vars.end());
+
+ // Named barriers are handled by AMDGPULowerExecSync; filter them out.
+ for (auto &[F, Vars] : AllLDSUses) {
+ SmallVector<GlobalVariable *> Barriers;
+ for (GlobalVariable *V : Vars)
+ if (AMDGPU::isNamedBarrier(*V))
+ Barriers.push_back(V);
+ for (GlobalVariable *V : Barriers)
+ Vars.erase(V);
+ }
+
+ // Build reverse map: LDS variable -> functions that use it.
+ DenseMap<GlobalVariable *, SmallVector<Function *, 4>> VarToFuncs;
+ for (auto &[F, Vars] : AllLDSUses) {
+ for (GlobalVariable *V : Vars)
+ VarToFuncs[V].push_back(F);
+ }
+
+ // A variable is function-scope iff it has local linkage and exactly one
+ // user function. Everything else is global-scope and must remain as a
+ // standalone external declaration so the linker can assign a single shared
+ // offset.
+ DenseSet<GlobalVariable *> GlobalScopeVars;
+ DenseSet<GlobalVariable *> InternalMultiUserVars;
+ for (auto &[V, Funcs] : VarToFuncs) {
+ if (!V->hasLocalLinkage() || Funcs.size() > 1) {
+ GlobalScopeVars.insert(V);
+ if (V->hasLocalLinkage())
+ InternalMultiUserVars.insert(V);
+ }
+ }
+
+ // Wrap function-scope LDS into per-function structs (unchanged logic,
+ // but global-scope variables are excluded from the set).
+ SmallVector<std::pair<Function *, GlobalVariable *>, 4> FuncToLdsStruct;
+ DenseSet<GlobalVariable *> AllReplacedVars;
+ for (auto &KV : AllLDSUses) {
+ Function *F = KV.first;
+ DenseSet<GlobalVariable *> FuncScopeVars;
+ for (GlobalVariable *V : KV.second)
+ if (!GlobalScopeVars.count(V))
+ FuncScopeVars.insert(V);
+
+ if (FuncScopeVars.empty())
+ continue;
+
+ std::string StructName = ("__amdgpu_lds." + F->getName()).str();
+ LDSVariableReplacement Replacement =
+ createLDSVariableReplacement(M, StructName, FuncScopeVars);
+
+ GlobalVariable *SGV = Replacement.SGV;
+ SGV->setLinkage(GlobalValue::ExternalLinkage);
+ SGV->setInitializer(nullptr);
+ FuncToLdsStruct.push_back({F, SGV});
+
+ replaceLDSVariablesWithStruct(
+ M, FuncScopeVars, Replacement, [F](const Use &U) {
+ auto *I = dyn_cast<Instruction>(U.getUser());
+ return I && I->getFunction() == F;
+ });
+
+ AllReplacedVars.insert(FuncScopeVars.begin(), FuncScopeVars.end());
+ }
+
+ // Internal-linkage LDS variables used by multiple functions would collide
+ // across TUs if promoted individually to external linkage (same name in
+ // different TUs). Pack them into a single per-module struct with a
+ // module-unique name so the linker treats them as one allocation unit.
+ if (!InternalMultiUserVars.empty()) {
+ SmallString<256> ModSuffix(M.getSourceFileName());
+ std::replace_if(
+ ModSuffix.begin(), ModSuffix.end(),
+ [](char Ch) { return !isAlnum(Ch); }, '_');
----------------
rampitec wrote:
> > I'd expect many modules will have duplicated strings that way, mostly empty.
>
> Well, not really. The reason we have empty string in the past is our final module is one created by the linker. Now these modules are directly from the front end, so they will have their corresponding name.
I am thinking about multiple MLIR generators in particular.
https://github.com/llvm/llvm-project/pull/191645
More information about the llvm-commits
mailing list