Skip to content

Commit 4cda64f

Browse files
committed
Fix properties propagation
1 parent 4dd50e5 commit 4cda64f

File tree

4 files changed

+95
-85
lines changed

4 files changed

+95
-85
lines changed

llvm/test/tools/sycl-post-link/sycl-esimd/sycl-esimd-double-grf.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
; RUN: FileCheck %s -input-file=%t_esimd_x2grf_0.sym --check-prefixes CHECK-ESIMD-2xGRF-SYM
1717

1818
; CHECK: [Code|Properties|Symbols]
19-
; CHECK: {{.*}}esimd_0.ll|{{.*}}esimd_0.prop|{{.*}}esimd_0.sym
2019
; CHECK: {{.*}}esimd_x2grf_0.ll|{{.*}}esimd_x2grf_0.prop|{{.*}}esimd_x2grf_0.sym
2120
; CHECK: {{.*}}_0.ll|{{.*}}_0.prop|{{.*}}_0.sym
21+
; CHECK: {{.*}}esimd_0.ll|{{.*}}esimd_0.prop|{{.*}}esimd_0.sym
2222

2323
; CHECK-ESIMD-2xGRF-PROP: isEsimdImage=1|1
2424
; CHECK-ESIMD-2xGRF-PROP: isDoubleGRFEsimdImage=1|1

llvm/tools/sycl-post-link/ModuleSplitter.cpp

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,8 @@ bool isESIMDFunction(const Function &F) {
136136
// This function makes one or two groups depending on kernel types (SYCL, ESIMD)
137137
EntryPointGroupVec
138138
groupEntryPointsByKernelType(const Module &M, bool EmitOnlyKernelsAsEntryPoints,
139-
EntryPointVec *AllowedEntriesVec) {
139+
EntryPointVec *AllowedEntriesVec,
140+
EntryPointGroup::Properties BlueprintProps) {
140141
SmallPtrSet<const Function *, 32> AllowedEntries;
141142

142143
if (AllowedEntriesVec) {
@@ -161,7 +162,8 @@ groupEntryPointsByKernelType(const Module &M, bool EmitOnlyKernelsAsEntryPoints,
161162

162163
if (!EntryPointMap.empty()) {
163164
for (auto& EPG : EntryPointMap) {
164-
EntryPointGroups.push_back({ EPG.first, std::move(EPG.second) });
165+
EntryPointGroups.emplace_back(
166+
EntryPointGroup{EPG.first, std::move(EPG.second), BlueprintProps});
165167
EntryPointGroup& G = EntryPointGroups.back();
166168

167169
if (G.GroupId == ESIMD_SCOPE_NAME) {
@@ -185,9 +187,10 @@ groupEntryPointsByKernelType(const Module &M, bool EmitOnlyKernelsAsEntryPoints,
185187
// which contains pairs of group id and entry points for that group. Each such
186188
// group along with IR it depends on (globals, functions from its call graph,
187189
// ...) will constitute a separate module.
188-
EntryPointGroupVec groupEntryPointsByScope(const Module &M,
189-
EntryPointsGroupScope EntryScope,
190-
bool EmitOnlyKernelsAsEntryPoints) {
190+
EntryPointGroupVec
191+
groupEntryPointsByScope(const Module &M, EntryPointsGroupScope EntryScope,
192+
bool EmitOnlyKernelsAsEntryPoints,
193+
EntryPointGroup::Properties BlueprintProps) {
191194
EntryPointGroupVec EntryPointGroups{};
192195
// Use MapVector for deterministic order of traversal (helps tests).
193196
MapVector<StringRef, EntryPointVec> EntryPointMap;
@@ -227,7 +230,8 @@ EntryPointGroupVec groupEntryPointsByScope(const Module &M,
227230
if (!EntryPointMap.empty()) {
228231
EntryPointGroups.reserve(EntryPointMap.size());
229232
for (auto& EPG : EntryPointMap) {
230-
EntryPointGroups.push_back({ EPG.first, std::move(EPG.second) });
233+
EntryPointGroups.emplace_back(
234+
EntryPointGroup{EPG.first, std::move(EPG.second), BlueprintProps});
231235
EntryPointGroup& G = EntryPointGroups.back();
232236
G.Props.Scope = EntryScope;
233237
}
@@ -239,10 +243,9 @@ EntryPointGroupVec groupEntryPointsByScope(const Module &M,
239243
}
240244

241245
template <class EntryPoinGroupFunc>
242-
EntryPointGroupVec
243-
groupEntryPointsByAttribute(const Module &M, StringRef AttrName,
244-
bool EmitOnlyKernelsAsEntryPoints,
245-
EntryPoinGroupFunc F) {
246+
EntryPointGroupVec groupEntryPointsByAttribute(
247+
const Module &M, StringRef AttrName, bool EmitOnlyKernelsAsEntryPoints,
248+
EntryPoinGroupFunc F, EntryPointGroup::Properties BlueprintProps) {
246249
EntryPointGroupVec EntryPointGroups{};
247250
std::map<StringRef, EntryPointVec> EntryPointMap;
248251

@@ -260,7 +263,8 @@ groupEntryPointsByAttribute(const Module &M, StringRef AttrName,
260263
if (!EntryPointMap.empty()) {
261264
EntryPointGroups.reserve(EntryPointMap.size());
262265
for (auto& EPG : EntryPointMap) {
263-
EntryPointGroups.push_back({ EPG.first, std::move(EPG.second) });
266+
EntryPointGroups.emplace_back(
267+
EntryPointGroup{EPG.first, std::move(EPG.second), BlueprintProps});
264268
F(EntryPointGroups.back());
265269
}
266270
} else {
@@ -271,11 +275,9 @@ groupEntryPointsByAttribute(const Module &M, StringRef AttrName,
271275
return EntryPointGroups;
272276
}
273277

274-
// Records a use graph between functions in a module. Nodes are functions, edges
275-
// are "uses" relation. One function "uses" another if any of its instructions
276-
// use the other function. Typical use is a call, another example of use is
277-
// storing
278-
class FunctionUseGraph {
278+
// Represents a call graph between functions in a module. Nodes are functions,
279+
// edges are "calls" relation.
280+
class CallGraph {
279281
public:
280282
using FunctionSet = SmallPtrSet<const Function*, 16>;
281283

@@ -284,11 +286,11 @@ class FunctionUseGraph {
284286
SmallPtrSet<const Function*, 1> EmptySet;
285287

286288
public:
287-
FunctionUseGraph(const Module& M, bool AllUsesAreGraphEdges = false) {
289+
CallGraph(const Module &M) {
288290
for (const auto& F : M) {
289291
for (const Value* U : F.users()) {
290-
if (const Instruction* I = dyn_cast<Instruction>(U)) {
291-
if (AllUsesAreGraphEdges || dyn_cast<const CallInst>(I)) {
292+
if (const auto *I = dyn_cast<CallInst>(U)) {
293+
if (I->getCalledFunction() == &F) {
292294
const Function* F1 = I->getFunction();
293295
Graph[F1].insert(&F);
294296
}
@@ -305,7 +307,7 @@ class FunctionUseGraph {
305307

306308
void collectFunctionsToExtract(SetVector<const GlobalValue *> &GVs,
307309
const EntryPointGroup &ModuleEntryPoints,
308-
const FunctionUseGraph &Deps) {
310+
const CallGraph &Deps) {
309311
for (const auto *F : ModuleEntryPoints.Functions)
310312
GVs.insert(F);
311313

@@ -336,9 +338,10 @@ void collectGlobalVarsToExtract(SetVector<const GlobalValue *> &GVs,
336338
GVs.insert(&G);
337339
}
338340

339-
ModuleDesc extractSubModule(const Module &M,
341+
ModuleDesc extractSubModule(const ModuleDesc &MD,
340342
const SetVector<const GlobalValue *> GVs,
341343
EntryPointGroup &&ModuleEntryPoints) {
344+
const Module &M = MD.getModule();
342345
// For each group of entry points collect all dependencies.
343346
ValueToValueMapTy VMap;
344347
// Clone definitions only for needed globals. Others will be added as
@@ -353,7 +356,7 @@ ModuleDesc extractSubModule(const Module &M,
353356
EPs.cbegin(), EPs.cend(), std::inserter(NewEPs, NewEPs.end()),
354357
[&VMap](const Function *F) { return cast<Function>(VMap[F]); });
355358
ModuleEntryPoints.Functions = std::move(NewEPs);
356-
return ModuleDesc{std::move(SubM), std::move(ModuleEntryPoints)};
359+
return ModuleDesc{std::move(SubM), std::move(ModuleEntryPoints), MD.Props};
357360
}
358361

359362
// TODO: try to move including all passes (cleanup, spec consts, compile time
@@ -371,14 +374,13 @@ void cleanupSplitModule(Module &SplitM) {
371374

372375
// The function produces a copy of input LLVM IR module M with only those entry
373376
// points that are specified in ModuleEntryPoints vector.
374-
ModuleDesc extractCallGraph(const Module &M,
375-
EntryPointGroup &&ModuleEntryPoints,
376-
bool AllUsesAreCallGraphEdges = false) {
377+
ModuleDesc extractCallGraph(const ModuleDesc &MD,
378+
EntryPointGroup &&ModuleEntryPoints) {
377379
SetVector<const GlobalValue *> GVs;
378-
collectFunctionsToExtract(GVs, ModuleEntryPoints, FunctionUseGraph{M, AllUsesAreCallGraphEdges});
379-
collectGlobalVarsToExtract(GVs, M);
380+
collectFunctionsToExtract(GVs, ModuleEntryPoints, CallGraph{MD.getModule()});
381+
collectGlobalVarsToExtract(GVs, MD.getModule());
380382

381-
ModuleDesc SplitM = extractSubModule(M, GVs, std::move(ModuleEntryPoints));
383+
ModuleDesc SplitM = extractSubModule(MD, GVs, std::move(ModuleEntryPoints));
382384
cleanupSplitModule(SplitM.getModule());
383385

384386
return SplitM;
@@ -389,19 +391,17 @@ class ModuleCopier : public ModuleSplitterBase {
389391
using ModuleSplitterBase::ModuleSplitterBase; // to inherit base constructors
390392

391393
ModuleDesc nextSplit() override {
392-
return {releaseInputModule(), nextGroup()};
394+
return ModuleDesc{releaseInputModule(), nextGroup(), Input.Props};
393395
}
394396
};
395397

396398
class ModuleSplitter : public ModuleSplitterBase {
397-
bool AllUsesAreCallGraphEdges;
398-
399399
public:
400-
401-
ModuleSplitter(std::unique_ptr<Module> M, EntryPointGroupVec&& GroupVec, bool AllUsesAreCallGraphEdges = false) : ModuleSplitterBase(std::move(M), std::move(GroupVec)), AllUsesAreCallGraphEdges(AllUsesAreCallGraphEdges) {}
400+
ModuleSplitter(ModuleDesc &&MD, EntryPointGroupVec &&GroupVec)
401+
: ModuleSplitterBase(std::move(MD), std::move(GroupVec)) {}
402402

403403
ModuleDesc nextSplit() override {
404-
return extractCallGraph(getInputModule(), nextGroup(), AllUsesAreCallGraphEdges);
404+
return extractCallGraph(Input, nextGroup());
405405
}
406406
};
407407

@@ -411,39 +411,40 @@ namespace llvm {
411411
namespace module_split {
412412

413413
std::unique_ptr<ModuleSplitterBase>
414-
getSplitterByKernelType(std::unique_ptr<Module> M,
415-
bool EmitOnlyKernelsAsEntryPoints,
414+
getSplitterByKernelType(ModuleDesc &&MD, bool EmitOnlyKernelsAsEntryPoints,
416415
EntryPointVec *AllowedEntries) {
417416
EntryPointGroupVec Groups = groupEntryPointsByKernelType(
418-
*M, EmitOnlyKernelsAsEntryPoints, AllowedEntries);
417+
MD.getModule(), EmitOnlyKernelsAsEntryPoints, AllowedEntries,
418+
MD.getEntryPointGroup().Props);
419419
bool DoSplit = (Groups.size() > 1);
420420

421421
if (DoSplit)
422-
return std::make_unique<ModuleSplitter>(std::move(M), std::move(Groups));
422+
return std::make_unique<ModuleSplitter>(std::move(MD), std::move(Groups));
423423
else
424-
return std::make_unique<ModuleCopier>(std::move(M), std::move(Groups));
424+
return std::make_unique<ModuleCopier>(std::move(MD), std::move(Groups));
425425
}
426426

427427
std::unique_ptr<ModuleSplitterBase>
428-
getSplitterByMode(std::unique_ptr<Module> M, IRSplitMode Mode,
428+
getSplitterByMode(ModuleDesc &&MD, IRSplitMode Mode,
429429
bool AutoSplitIsGlobalScope,
430430
bool EmitOnlyKernelsAsEntryPoints) {
431431
EntryPointsGroupScope Scope =
432-
selectDeviceCodeGroupScope(*M, Mode, AutoSplitIsGlobalScope);
433-
EntryPointGroupVec Groups =
434-
groupEntryPointsByScope(*M, Scope, EmitOnlyKernelsAsEntryPoints);
432+
selectDeviceCodeGroupScope(MD.getModule(), Mode, AutoSplitIsGlobalScope);
433+
EntryPointGroupVec Groups = groupEntryPointsByScope(
434+
MD.getModule(), Scope, EmitOnlyKernelsAsEntryPoints,
435+
MD.getEntryPointGroup().Props);
435436
assert(!Groups.empty() && "At least one group is expected");
436437
bool DoSplit = (Mode != SPLIT_NONE &&
437438
(Groups.size() > 1 || !Groups.cbegin()->Functions.empty()));
438439

439440
if (DoSplit)
440-
return std::make_unique<ModuleSplitter>(std::move(M), std::move(Groups));
441+
return std::make_unique<ModuleSplitter>(std::move(MD), std::move(Groups));
441442
else
442-
return std::make_unique<ModuleCopier>(std::move(M), std::move(Groups));
443+
return std::make_unique<ModuleCopier>(std::move(MD), std::move(Groups));
443444
}
444445

445446
void ModuleSplitterBase::verifyNoCrossModuleDeviceGlobalUsage() {
446-
const Module &M = *InputModule;
447+
const Module &M = getInputModule();
447448
// Early exit if there is only one group
448449
if (Groups.size() < 2)
449450
return;
@@ -669,21 +670,22 @@ void EntryPointGroup::rebuild(const Module &M) {
669670
}
670671

671672
std::unique_ptr<ModuleSplitterBase>
672-
getESIMDDoubleGRFSplitter(std::unique_ptr<Module> M,
673-
bool EmitOnlyKernelsAsEntryPoints) {
673+
getESIMDDoubleGRFSplitter(ModuleDesc &&MD, bool EmitOnlyKernelsAsEntryPoints) {
674674
EntryPointGroupVec Groups = groupEntryPointsByAttribute(
675-
*M, ATTR_DOUBLE_GRF, EmitOnlyKernelsAsEntryPoints, [](EntryPointGroup& G) {
676-
if (G.GroupId == ATTR_DOUBLE_GRF) {
677-
G.Props.UsesDoubleGRF = true;
678-
}
679-
});
675+
MD.getModule(), ATTR_DOUBLE_GRF, EmitOnlyKernelsAsEntryPoints,
676+
[](EntryPointGroup &G) {
677+
if (G.GroupId == ATTR_DOUBLE_GRF) {
678+
G.Props.UsesDoubleGRF = true;
679+
}
680+
},
681+
MD.getEntryPointGroup().Props);
680682
assert(!Groups.empty() && "At least one group is expected");
681683
assert(Groups.size() <= 2 && "At most 2 groups are expected");
682684

683685
if (Groups.size() > 1)
684-
return std::make_unique<ModuleSplitter>(std::move(M), std::move(Groups));
686+
return std::make_unique<ModuleSplitter>(std::move(MD), std::move(Groups));
685687
else
686-
return std::make_unique<ModuleCopier>(std::move(M), std::move(Groups));
688+
return std::make_unique<ModuleCopier>(std::move(MD), std::move(Groups));
687689
}
688690

689691
} // namespace module_split

llvm/tools/sycl-post-link/ModuleSplitter.h

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ struct EntryPointGroup {
7575
EntryPointGroup(StringRef GroupId = "") : GroupId(GroupId) {}
7676
EntryPointGroup(StringRef GroupId, EntryPointVec &&Functions)
7777
: GroupId(GroupId), Functions(std::move(Functions)) {}
78+
EntryPointGroup(StringRef GroupId, EntryPointVec &&Functions,
79+
const Properties &Props)
80+
: GroupId(GroupId), Functions(std::move(Functions)), Props(Props) {}
7881

7982
// Tells if this group has only ESIMD entry points (based on GroupId).
8083
bool isEsimd() const { return Props.HasESIMD == SyclEsimdSplitStatus::ESIMD_ONLY; }
@@ -101,8 +104,15 @@ class ModuleDesc {
101104
std::string Name = "";
102105
Properties Props;
103106

104-
ModuleDesc(std::unique_ptr<Module> &&M, EntryPointGroup &&EntryPoints)
105-
: M(std::move(M)), EntryPoints(std::move(EntryPoints)) {
107+
ModuleDesc() { Name = "EMPTY"; }
108+
109+
ModuleDesc(std::unique_ptr<Module> &&M) : M(std::move(M)) {
110+
Name = "TOP-LEVEL";
111+
}
112+
113+
ModuleDesc(std::unique_ptr<Module> &&M, EntryPointGroup &&EntryPoints,
114+
const Properties &Props)
115+
: M(std::move(M)), EntryPoints(std::move(EntryPoints)), Props(Props) {
106116
Name = this->EntryPoints.GroupId.str();
107117
}
108118

@@ -118,6 +128,7 @@ class ModuleDesc {
118128
bool isDoubleGRF() const { return EntryPoints.isDoubleGRF(); }
119129

120130
const EntryPointVec &entries() const { return EntryPoints.Functions; }
131+
const EntryPointGroup &getEntryPointGroup() const { return EntryPoints; }
121132
EntryPointVec &entries() { return EntryPoints.Functions; }
122133
Module &getModule() { return *M; }
123134
const Module &getModule() const { return *M; }
@@ -150,11 +161,12 @@ class ModuleDesc {
150161
};
151162

152163
// Module split support interface.
153-
// It gets a module and a collection of entry points groups. Each group
154-
// specifies subset entry points from input module that should be included in
155-
// a split module.
164+
// It gets a module (in a form of module descriptor, to get additional info) and
165+
// a collection of entry points groups. Each group specifies subset entry points
166+
// from input module that should be included in a split module.
156167
class ModuleSplitterBase {
157-
std::unique_ptr<Module> InputModule{nullptr};
168+
protected:
169+
ModuleDesc Input;
158170
EntryPointGroupVec Groups;
159171

160172
protected:
@@ -165,19 +177,15 @@ class ModuleSplitterBase {
165177
return Res;
166178
}
167179

168-
Module &getInputModule() {
169-
assert(InputModule && "No module to access to.");
170-
return *InputModule;
171-
}
180+
Module &getInputModule() { return Input.getModule(); }
181+
172182
std::unique_ptr<Module> releaseInputModule() {
173-
assert(InputModule && "No module to release.");
174-
return std::move(InputModule);
183+
return std::move(Input.releaseModulePtr());
175184
}
176185

177186
public:
178-
ModuleSplitterBase(std::unique_ptr<Module> M, EntryPointGroupVec &&GroupVec)
179-
: InputModule(std::move(M)), Groups(std::move(GroupVec)) {
180-
assert(InputModule && "Module is absent.");
187+
ModuleSplitterBase(ModuleDesc &&MD, EntryPointGroupVec &&GroupVec)
188+
: Input(std::move(MD)), Groups(std::move(GroupVec)) {
181189
assert(!Groups.empty() && "Entry points groups collection is empty!");
182190
}
183191

@@ -200,18 +208,16 @@ class ModuleSplitterBase {
200208
};
201209

202210
std::unique_ptr<ModuleSplitterBase>
203-
getSplitterByKernelType(std::unique_ptr<Module> M,
204-
bool EmitOnlyKernelsAsEntryPoints,
211+
getSplitterByKernelType(ModuleDesc &&MD, bool EmitOnlyKernelsAsEntryPoints,
205212
EntryPointVec *AllowedEntries = nullptr);
206213

207214
std::unique_ptr<ModuleSplitterBase>
208-
getSplitterByMode(std::unique_ptr<Module> M, IRSplitMode Mode,
215+
getSplitterByMode(ModuleDesc &&MD, IRSplitMode Mode,
209216
bool AutoSplitIsGlobalScope,
210217
bool EmitOnlyKernelsAsEntryPoints);
211218

212219
std::unique_ptr<ModuleSplitterBase>
213-
getESIMDDoubleGRFSplitter(std::unique_ptr<Module> M,
214-
bool EmitOnlyKernelsAsEntryPoints);
220+
getESIMDDoubleGRFSplitter(ModuleDesc &&MD, bool EmitOnlyKernelsAsEntryPoints);
215221

216222
#ifndef _NDEBUG
217223
void dumpEntryPoints(const EntryPointVec &C, const char *msg = "", int Tab = 0);

0 commit comments

Comments
 (0)