Skip to content

Commit 590c1ba

Browse files
Anton Sidorenkoigcbot
authored andcommitted
Prepare VCBE to handle standalone stack calls
State before: The head of a function group is a kernel. Each function that is used in different function groups (kernels and theirs call graphs) must be copied. This rule must be applied even for stack calls. In other words, stack calls are kernel-dependent functions. Such an approach was OK until there was a need to compile standalone stack calls. How it is now reorganized: Each kernel is a head of a function group of type GROUP. Each stack call (or indirect function) is a head of function group of type SUBGROUP (legacy, we may consider removal of different types later). Stack calls won't be copied. Function group passes are run on each function group independently. This allows the creation of independent stack calls with no need in a kernel. So, each SUBGROUP is independent function group and compiles separately, but at the same time, its head may be referenced by others function groups of type GROUP of SUBGROUP.
1 parent 0696474 commit 590c1ba

19 files changed

+355
-153
lines changed

IGC/VectorCompiler/igcdeps/src/TranslationInterface.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ static void adjustTransformationsAndOptimizations(vc::CompileOptions &Opts) {
193193
Opts.ForceDisableNonOverlappingRegionOpt = true;
194194
if (IGC_IS_FLAG_ENABLED(VCPassDebugToFinalizer))
195195
Opts.ForcePassDebugToFinalizer = true;
196+
if (IGC_IS_FLAG_ENABLED(VCSaveStackCallLinkage))
197+
Opts.SaveStackCallLinkage = true;
196198
}
197199

198200
static void adjustDumpOptions(vc::CompileOptions &Opts) {

IGC/VectorCompiler/include/vc/Driver/Driver.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ struct CompileOptions {
9797

9898
// from IGC_XXX env
9999
FunctionControl FCtrl = FunctionControl::Default;
100+
bool SaveStackCallLinkage = false;
100101
};
101102

102103
struct ExternalData {

IGC/VectorCompiler/include/vc/Support/BackendConfig.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ struct GenXBackendOptions {
9999
// max private stateless memory size per thread
100100
unsigned StatelessPrivateMemSize;
101101

102+
// Historically stack calls linkage is changed to internal in CMABI. This
103+
// option allows saving the original linkage type for such functions. This is
104+
// required for linking (e.g. invoke_simd).
105+
bool SaveStackCallLinkage = false;
106+
102107
GenXBackendOptions();
103108
};
104109

@@ -217,6 +222,8 @@ class GenXBackendConfig : public ImmutablePass {
217222
}
218223

219224
bool useBindlessBuffers() const { return Options.UseBindlessBuffers; }
225+
226+
bool saveStackCallLinkage() const { return Options.SaveStackCallLinkage; }
220227
};
221228
} // namespace llvm
222229

IGC/VectorCompiler/lib/Driver/Driver.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@ static GenXBackendOptions createBackendOptions(const vc::CompileOptions &Opts) {
232232
BackendOpts.WATable = Opts.WATable;
233233
BackendOpts.IsLargeGRFMode = Opts.IsLargeGRFMode;
234234
BackendOpts.UseBindlessBuffers = Opts.UseBindlessBuffers;
235+
if (Opts.SaveStackCallLinkage)
236+
BackendOpts.SaveStackCallLinkage = true;
235237
return BackendOpts;
236238
}
237239

IGC/VectorCompiler/lib/GenXCodeGen/FunctionGroup.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ SPDX-License-Identifier: MIT
1818
//===----------------------------------------------------------------------===//
1919

2020
#include "FunctionGroup.h"
21+
#include "vc/GenXOpts/Utils/KernelInfo.h"
2122
#include "llvm/Analysis/LoopInfo.h"
2223
#include "llvm/GenXIntrinsics/GenXMetadata.h"
2324
#include "llvm/IR/Dominators.h"
@@ -83,6 +84,14 @@ FunctionGroup *FunctionGroupAnalysis::getSubGroup(const Function *F) const {
8384
return getGroup(F, FGType::SUBGROUP);
8485
}
8586

87+
FunctionGroup *FunctionGroupAnalysis::getAnyGroup(const Function *F) const {
88+
auto *Group = getGroup(F, FGType::SUBGROUP);
89+
if (!Group)
90+
Group = getGroup(F, FGType::GROUP);
91+
IGC_ASSERT_MESSAGE(Group, "Function isn't assigned to any function group");
92+
return Group;
93+
}
94+
8695
// getGroupForHead : get the FunctionGroup for which Function F is the
8796
// head, else 0
8897
FunctionGroup *FunctionGroupAnalysis::getGroupForHead(const Function *F) const {
@@ -98,7 +107,8 @@ FunctionGroup *FunctionGroupAnalysis::getGroupForHead(const Function *F) const {
98107
void FunctionGroupAnalysis::replaceFunction(Function *OldF, Function *NewF) {
99108
for (auto T : TypesToProcess) {
100109
auto OldFIt = GroupMap[T].find(OldF);
101-
IGC_ASSERT(OldFIt != GroupMap[T].end());
110+
if (OldFIt == GroupMap[T].end())
111+
continue;
102112
FunctionGroup *FG = OldFIt->second;
103113
GroupMap[T].erase(OldFIt);
104114
GroupMap[T][NewF] = FG;
@@ -166,8 +176,12 @@ bool FunctionGroupAnalysis::buildGroup(CallGraph &Callees, Function *F,
166176
LLVM_DEBUG(dbgs() << "process function " << F->getName() << " from " << curGr
167177
<< ", type = " << Type << "\n");
168178
if (Visited.count(F) > 0) {
169-
if (GroupMap[Type].count(F) > 0 && GroupMap[Type][F] != curGr &&
170-
!F->hasFnAttribute(TypeToAttr(Type))) {
179+
bool NeedCloning =
180+
std::any_of(std::begin(TypesToProcess), std::end(TypesToProcess),
181+
[&GM = GroupMap, curGr, F](FGType CurType) {
182+
return GM[CurType].count(F) && GM[CurType][F] != curGr;
183+
});
184+
if (NeedCloning && !F->hasFnAttribute(TypeToAttr(Type))) {
171185
ValueToValueMapTy VMap;
172186
Function *ClonedFunc = CloneFunction(F, VMap);
173187
LLVM_DEBUG(dbgs() << "Cloning: " << ClonedFunc->getName() << "\n");
@@ -181,16 +195,17 @@ bool FunctionGroupAnalysis::buildGroup(CallGraph &Callees, Function *F,
181195
if (GroupMap[Type][CI->getFunction()] == curGr)
182196
*u = ClonedFunc;
183197
}
184-
for (auto T : TypesToProcess) {
185-
if (T >= Type)
186-
break;
187-
addToFunctionGroup(getGroup(F, T), ClonedFunc, T);
188-
}
189198
addToFunctionGroup(curGr, ClonedFunc, Type);
190199

191200
for (auto &Callee : Callees[F]) {
192201
if (Callee == F)
193202
continue;
203+
if (genx::requiresStackCall(Callee)) {
204+
LLVM_DEBUG(dbgs()
205+
<< "\tDo not process next callee " << Callee->getName()
206+
<< " because it's a stack call\n");
207+
continue;
208+
}
194209
LLVM_DEBUG(dbgs() << "Next callee: " << Callee->getName() << "\n");
195210
result |= buildGroup(Callees, Callee, curGr, Type);
196211
}
@@ -209,6 +224,13 @@ bool FunctionGroupAnalysis::buildGroup(CallGraph &Callees, Function *F,
209224
addToFunctionGroup(curGr, F, Type);
210225
}
211226
for (auto &Callee : Callees[F]) {
227+
if (genx::requiresStackCall(Callee)) {
228+
LLVM_DEBUG(dbgs() << "\tDo not process next callee "
229+
<< Callee->getName()
230+
<< " because it's a stack call\n");
231+
continue;
232+
}
233+
212234
LLVM_DEBUG(dbgs() << "Next callee: " << Callee->getName() << "\n");
213235
result |= buildGroup(Callees, Callee, curGr, Type);
214236
}
@@ -418,7 +440,7 @@ bool FGPassManager::runFGPassSequence(unsigned &Pass) {
418440
bool Changed = false;
419441

420442
Changed |= doFGInitialization(BeginPass, Pass, FGA);
421-
for (auto *FG : FGA)
443+
for (auto *FG : FGA.AllGroups())
422444
Changed |= runPassesOnFunctionGroup(BeginPass, Pass, *FG);
423445
Changed |= doFGFinalization(BeginPass, Pass, FGA);
424446

IGC/VectorCompiler/lib/GenXCodeGen/FunctionGroup.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ SPDX-License-Identifier: MIT
2727
#ifndef FUNCTIONGROUP_H
2828
#define FUNCTIONGROUP_H
2929

30+
#include "vc/GenXOpts/Utils/KernelInfo.h"
31+
#include "llvm/ADT/SetVector.h"
3032
#include "llvm/ADT/SmallVector.h"
3133
#include "llvm/IR/Module.h"
3234
#include "llvm/IR/ValueHandle.h"
@@ -41,6 +43,18 @@ class FunctionGroupAnalysis;
4143
class LLVMContext;
4244
class PMStack;
4345

46+
namespace genx {
47+
namespace fg {
48+
inline bool isGroupHead(const Function &F) { return genx::isKernel(&F); }
49+
inline bool isSubGroupHead(const Function &F) {
50+
return genx::isReferencedIndirectly(&F) || genx::requiresStackCall(&F);
51+
}
52+
inline bool isHead(const Function &F) {
53+
return isGroupHead(F) || isSubGroupHead(F);
54+
}
55+
} // namespace fg
56+
} // namespace genx
57+
4458
//----------------------------------------------------------------------
4559
// FunctionGroup : a group of Functions
4660
//
@@ -50,6 +64,9 @@ class FunctionGroup {
5064
// Elements are asserting value handles, so we spot when a Function
5165
// in the group gets destroyed too early.
5266
SmallVector<AssertingVH<Function>, 8> Functions;
67+
// FunctionGroup can call the head function of another FunctionGroups with
68+
// SUBGROUP type.
69+
SetVector<const FunctionGroup *> Subgroups;
5370

5471
public:
5572
FunctionGroup(FunctionGroupAnalysis *FGA) : FGA(FGA) {}
@@ -83,6 +100,25 @@ class FunctionGroup {
83100
StringRef getName() { return getHead()->getName(); }
84101
LLVMContext &getContext() { return getHead()->getContext(); }
85102
Module *getModule() { return getHead()->getParent(); }
103+
void addSubgroup(FunctionGroup *FG) {
104+
IGC_ASSERT(FG);
105+
IGC_ASSERT(FG->getHead());
106+
IGC_ASSERT_MESSAGE(genx::fg::isSubGroupHead(*FG->getHead()),
107+
"Provided function group has incorrect type");
108+
Subgroups.insert(FG);
109+
}
110+
using subgroup_iterator = decltype(Subgroups)::iterator;
111+
using const_subgroup_iterator = decltype(Subgroups)::const_iterator;
112+
subgroup_iterator begin_subgroup() { return Subgroups.begin(); }
113+
subgroup_iterator end_subgroup() { return Subgroups.end(); }
114+
const_subgroup_iterator begin_subgroup() const { return Subgroups.begin(); }
115+
const_subgroup_iterator end_subgroup() const { return Subgroups.end(); }
116+
iterator_range<subgroup_iterator> subgroups() {
117+
return make_range(begin_subgroup(), end_subgroup());
118+
}
119+
iterator_range<const_subgroup_iterator> subgroups() const {
120+
return make_range(begin_subgroup(), end_subgroup());
121+
}
86122
};
87123

88124
//----------------------------------------------------------------------
@@ -153,6 +189,8 @@ class FunctionGroupAnalysis : public ModulePass {
153189
FunctionGroup *getGroup(const Function *F, FGType Type) const;
154190
FunctionGroup *getGroup(const Function *F) const;
155191
FunctionGroup *getSubGroup(const Function *F) const;
192+
// get group or subgroup depending on where the function is.
193+
FunctionGroup *getAnyGroup(const Function *F) const;
156194
// getGroupForHead : get the FunctionGroup for which Function F is the
157195
// head, else 0
158196
FunctionGroup *getGroupForHead(const Function *F) const;
@@ -161,10 +199,40 @@ class FunctionGroupAnalysis : public ModulePass {
161199
// iterator for FunctionGroups in the analysis
162200
typedef SmallVectorImpl<FunctionGroup *>::iterator iterator;
163201
typedef SmallVectorImpl<FunctionGroup *>::const_iterator const_iterator;
202+
using all_iterator = concat_iterator<FunctionGroup *, iterator, iterator>;
203+
using const_all_iterator =
204+
concat_iterator<FunctionGroup *const, const_iterator, const_iterator>;
164205
iterator begin() { return iterator(Groups.begin()); }
165206
iterator end() { return iterator(Groups.end()); }
166207
const_iterator begin() const { return const_iterator(Groups.begin()); }
167208
const_iterator end() const { return const_iterator(Groups.end()); }
209+
210+
iterator subgroup_begin() { return iterator(NonMainGroups.begin()); }
211+
iterator subgroup_end() { return iterator(NonMainGroups.end()); }
212+
const_iterator subgroup_begin() const {
213+
return const_iterator(NonMainGroups.begin());
214+
}
215+
const_iterator subgroup_end() const {
216+
return const_iterator(NonMainGroups.end());
217+
}
218+
iterator_range<iterator> subgroups() {
219+
return make_range(subgroup_begin(), subgroup_end());
220+
}
221+
iterator_range<const_iterator> subgroups() const {
222+
return make_range(subgroup_begin(), subgroup_end());
223+
}
224+
225+
iterator_range<all_iterator> AllGroups() {
226+
return concat<FunctionGroup *>(
227+
make_range(begin(), end()),
228+
make_range(subgroup_begin(), subgroup_end()));
229+
}
230+
iterator_range<const_all_iterator> AllGroups() const {
231+
return concat<FunctionGroup *const>(
232+
make_range(begin(), end()),
233+
make_range(subgroup_begin(), subgroup_end()));
234+
}
235+
168236
size_t size() const { return Groups.size(); }
169237
// addToFunctionGroup : add Function F to FunctionGroup FG
170238
// Using this (rather than calling push_back directly on the FunctionGroup)

IGC/VectorCompiler/lib/GenXCodeGen/GenXArgIndirection.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1095,9 +1095,14 @@ void SubroutineArg::gatherBalesToModify(Alignment Align)
10951095
auto User = cast<Instruction>(ui->getUser());
10961096
if (auto CI = dyn_cast<CallInst>(User)) {
10971097
Function *CF = CI->getCalledFunction();
1098-
if (!GenXIntrinsic::isAnyNonTrivialIntrinsic(CF)) {
1098+
if (!GenXIntrinsic::isAnyNonTrivialIntrinsic(CF) &&
1099+
!genx::requiresStackCall(CF)) {
10991100
// Non-intrinsic call. Ignore. (A call site using an arg being
11001101
// indirected gets handled differently.)
1102+
// Cannot indirect if there is a stack call. Do not ignore stack
1103+
// calls here and add them to BalesToModify. In checkIndirectBale
1104+
// report that such bale cannot be indirected. This method is
1105+
// confusing, must be improved.
11011106
continue;
11021107
}
11031108
} else {
@@ -1165,6 +1170,13 @@ bool GenXArgIndirection::checkIndirectBale(Bale *B, LiveRange *ArgLR,
11651170
<< "\n\tintrinsic with raw return value\n");
11661171
return false;
11671172
}
1173+
} else if (auto *CI = dyn_cast<CallInst>(MainInst->Inst)) {
1174+
auto *Callee = CI->getCalledFunction();
1175+
IGC_ASSERT_MESSAGE(genx::requiresStackCall(Callee),
1176+
"Expect a stack call to stop indirection. See "
1177+
"SubroutineArg::gatherBalesToModify");
1178+
LLVM_DEBUG(dbgs() << *CI << "\n\tcalls stack call function\n");
1179+
return false;
11681180
}
11691181
}
11701182
// Check the rdregion(s) and wrregion.

IGC/VectorCompiler/lib/GenXCodeGen/GenXCategory.cpp

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -800,13 +800,14 @@ CategoryAndAlignment GenXCategory::getCategoryAndAlignmentForDef(Value *V) const
800800
if (V->getType()->getScalarType()->getPrimitiveSizeInBits() == 1)
801801
return RegCategory::PREDICATE;
802802
if (Argument *Arg = dyn_cast<Argument>(V)) {
803+
auto *F = Arg->getParent();
803804
// This is a function Argument.
804805
if (!InFGHead) {
805806
// It is an arg in a subroutine. Get the category from the corresponding
806807
// arg at some call site. (We should not have disagreement among the
807808
// call sites and the function arg, since whichever one gets a category
808809
// first forces the category of all the others.)
809-
return getCategoryForCallArg(Arg->getParent(), Arg->getArgNo());
810+
return getCategoryForCallArg(F, Arg->getArgNo());
810811
}
811812
unsigned ArgNo = Arg->getArgNo();
812813
if (KM.getNumArgs() > ArgNo) {
@@ -819,7 +820,12 @@ CategoryAndAlignment GenXCategory::getCategoryAndAlignmentForDef(Value *V) const
819820
// determine the category. This is the fallback for compatibility with
820821
// hand coded LLVM IR from before this metadata was added. (If we only
821822
// had to cope with non-kernel functions, we could just return GENERAL.)
822-
return RegCategory::NONE;
823+
// FIXME: temporary fix for stack calls. We need to figure out how to
824+
// determine arguments category if it cannot be deduced from the arg uses.
825+
// * calls from another function groups might help (but we do not have
826+
// liveness -> category for them). What about standalone stack calls?
827+
IGC_ASSERT(genx::requiresStackCall(F));
828+
return getCategoryForCallArg(F, Arg->getArgNo());
823829
}
824830
// The def is a phi-instruction.
825831
if (PHINode *Phi = dyn_cast<PHINode>(V)) {
@@ -1070,22 +1076,19 @@ unsigned GenXCategory::getCategoryForCallArg(Function *Callee, unsigned ArgNo) c
10701076
return Cat;
10711077
}
10721078
// Then try the arg at each call site.
1073-
bool UseUndef = true;
10741079
for (auto *U: Callee->users()) {
10751080
if (auto *CI = checkFunctionCall(U, Callee)) {
10761081
auto ArgV = CI->getArgOperand(ArgNo);
1077-
if (!isa<UndefValue>(ArgV)) {
1078-
UseUndef = false;
10791082
if (auto LR = Liveness->getLiveRangeOrNull(ArgV)) {
10801083
unsigned Cat = LR->getCategory();
10811084
if (Cat != RegCategory::NONE)
10821085
return Cat;
10831086
}
1084-
}
10851087
}
10861088
}
1087-
// special case handling to break deadlock when all uses are undef,
1088-
// force the argument to be GENERAL
1089-
return(UseUndef ? RegCategory::GENERAL : RegCategory::NONE);
1089+
// special case handling to break deadlock when all uses are undef or stack
1090+
// call arg category cannot be deduced from the uses in the function, force
1091+
// the argument to be GENERAL
1092+
return EnforceCategoryPromotion ? RegCategory::GENERAL : RegCategory::NONE;
10901093
}
10911094

0 commit comments

Comments
 (0)