Skip to content

Commit 3dccbad

Browse files
update calling conv only for imported from BiF funcs in VC (2nd edition) (#13)
Co-authored-by: Dmitry Ryabtsev <[email protected]>
1 parent 9a749ed commit 3dccbad

File tree

1 file changed

+118
-72
lines changed

1 file changed

+118
-72
lines changed

IGC/VectorCompiler/lib/GenXCodeGen/GenXImportBiF.cpp

Lines changed: 118 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4040
#include "GenX.h"
4141
#include "GenXBackendConfig.h"
4242

43+
#include <llvm/ADT/STLExtras.h>
4344
#include <llvm/ADT/SmallPtrSet.h>
4445
#include <llvm/Bitcode/BitcodeReader.h>
4546
#include <llvm/IR/Attributes.h>
@@ -351,9 +352,9 @@ void BIConvert::runOnModule(Module &M) {
351352
typedef std::vector<llvm::Function *> TFunctionsVec;
352353

353354
static Function *GetBuiltinFunction(llvm::StringRef funcName,
354-
llvm::Module *BiFModule) {
355-
Function *pFunc = nullptr;
356-
if ((pFunc = BiFModule->getFunction(funcName)) && !pFunc->isDeclaration())
355+
llvm::Module &BiFModule) {
356+
Function *pFunc = BiFModule.getFunction(funcName);
357+
if (pFunc && !pFunc->isDeclaration())
357358
return pFunc;
358359
return nullptr;
359360
}
@@ -362,32 +363,6 @@ static bool materialized_use_empty(const Value *v) {
362363
return v->materialized_use_begin() == v->use_end();
363364
}
364365

365-
static void GetCalledFunctions(const Function *pFunc,
366-
TFunctionsVec &calledFuncs) {
367-
SmallPtrSet<Function *, 8> visitedSet;
368-
// Iterate over function instructions and look for call instructions
369-
for (const_inst_iterator it = inst_begin(pFunc), e = inst_end(pFunc); it != e;
370-
++it) {
371-
const CallInst *pInstCall = dyn_cast<CallInst>(&*it);
372-
if (!pInstCall)
373-
continue;
374-
CallingConv::ID CCID = pFunc->getCallingConv();
375-
if (CCID != CallingConv::SPIR_KERNEL)
376-
((CallInst *)pInstCall)->setCallingConv(CCID);
377-
Function *pCalledFunc = pInstCall->getCalledFunction();
378-
if (!pCalledFunc) {
379-
// This case can occur only if CallInst is calling something other than
380-
// LLVM function. Thus, no need to handle this case - function casting is
381-
// not allowed (and not expected!)
382-
continue;
383-
}
384-
if (visitedSet.count(pCalledFunc))
385-
continue;
386-
visitedSet.insert(pCalledFunc);
387-
calledFuncs.push_back(pCalledFunc);
388-
}
389-
}
390-
391366
static void removeFunctionBitcasts(llvm::Module &M) {
392367
std::vector<Instruction *> list_delete;
393368
DenseMap<Function *, std::vector<Function *>> bitcastFunctionMap;
@@ -505,43 +480,119 @@ static void InitializeBIFlags(llvm::Module &M) {
505480
*reinterpret_cast<int *>(&profilingTimerResolution));
506481
}
507482

508-
bool CMImportBiF(llvm::Module *MainModule,
509-
std::unique_ptr<llvm::Module> BiFModule) {
510-
std::function<void(Function *)> Explore = [&](Function *pRoot) -> void {
511-
TFunctionsVec calledFuncs;
512-
GetCalledFunctions(pRoot, calledFuncs);
513-
514-
for (auto *pCallee : calledFuncs) {
515-
Function *pFunc = nullptr;
516-
if (pCallee->isDeclaration()) {
517-
auto funcName = pCallee->getName();
518-
Function *pSrcFunc = GetBuiltinFunction(funcName, BiFModule.get());
519-
if (!pSrcFunc)
520-
continue;
521-
pFunc = pSrcFunc;
522-
} else {
523-
pFunc = pCallee;
524-
}
483+
namespace {
484+
// Note: FuncDecl is a declaration of a function in the main module.
485+
// FuncImpl is a definition of this function in the BiF module.
486+
struct FuncAndItsImpl {
487+
Function *FuncDecl;
488+
Function *FuncImpl;
489+
};
490+
} // namespace
525491

526-
if (pFunc->isMaterializable()) {
527-
if (Error Err = pFunc->materialize()) {
528-
std::string Msg;
529-
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
530-
errs() << "===> Materialize Failure: " << EIB.message().c_str()
531-
<< '\n';
532-
});
533-
IGC_ASSERT_MESSAGE(0, "Failed to materialize Global Variables");
534-
} else {
535-
pFunc->setCallingConv(pRoot->getCallingConv());
536-
Explore(pFunc);
537-
}
538-
}
492+
static bool isOCLBuiltinDecl(const Function &F) {
493+
if (!F.isDeclaration())
494+
return false;
495+
if (F.isIntrinsic() || GenXIntrinsic::isGenXIntrinsic(&F))
496+
return false;
497+
// presuming that the only declarations left are from OCL header
498+
return true;
499+
}
500+
501+
static void fixCallingConv(Function &FuncDecl, CallingConv::ID Conv) {
502+
FuncDecl.setCallingConv(Conv);
503+
for (User *U : FuncDecl.users())
504+
cast<CallInst>(U)->setCallingConv(Conv);
505+
}
506+
507+
static void fixCallingConv(const std::vector<FuncAndItsImpl> &UsedBiFFuncs) {
508+
for (const auto &FuncLinkInfo : UsedBiFFuncs) {
509+
if (FuncLinkInfo.FuncDecl->getCallingConv() !=
510+
FuncLinkInfo.FuncImpl->getCallingConv())
511+
fixCallingConv(*FuncLinkInfo.FuncDecl,
512+
FuncLinkInfo.FuncImpl->getCallingConv());
513+
}
514+
}
515+
516+
static std::vector<FuncAndItsImpl> collectBiFFuncUses(Module &MainModule,
517+
Module &BiFModule) {
518+
std::vector<FuncAndItsImpl> FuncsFromBiF;
519+
for (auto &Func : MainModule)
520+
if (isOCLBuiltinDecl(Func)) {
521+
StringRef FuncName = Func.getName();
522+
Function *FuncBiFImpl = GetBuiltinFunction(FuncName, BiFModule);
523+
if (FuncBiFImpl)
524+
FuncsFromBiF.push_back({&Func, FuncBiFImpl});
539525
}
540-
};
526+
return std::move(FuncsFromBiF);
527+
}
528+
529+
static void materializeFuncIfRequired(Function &Func) {
530+
if (Func.isMaterializable()) {
531+
if (Error Err = Func.materialize()) {
532+
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
533+
errs() << "===> Materialize Failure: " << EIB.message().c_str() << '\n';
534+
});
535+
IGC_ASSERT_MESSAGE(0, "Failed to materialize Global Variables");
536+
}
537+
}
538+
}
541539

542-
for (auto &func : *MainModule) {
543-
Explore(&func);
540+
// Collects functions that are directly called from \p Parent function
541+
// (goes only one step in depth in the call graph).
542+
static std::vector<Function *> collectDirectSubroutines(Function &Parent) {
543+
std::vector<Function *> Subroutines;
544+
llvm::transform(
545+
make_filter_range(
546+
instructions(Parent),
547+
[](Instruction &Inst) {
548+
if (!isa<CallInst>(Inst))
549+
return false;
550+
auto *Subroutine = cast<CallInst>(Inst).getCalledFunction();
551+
IGC_ASSERT_MESSAGE(Subroutine,
552+
"indirect calls are unexpected in BiF module");
553+
IGC_ASSERT_MESSAGE(!GenXIntrinsic::isGenXIntrinsic(Subroutine),
554+
"genx intrinsics are unexpected in BiF module");
555+
return !Subroutine->isIntrinsic();
556+
}),
557+
std::back_inserter(Subroutines), [](Instruction &Inst) {
558+
auto *Subroutine = cast<CallInst>(Inst).getCalledFunction();
559+
IGC_ASSERT_MESSAGE(Subroutine,
560+
"indirect calls are unexpected in BiF module");
561+
IGC_ASSERT_MESSAGE(!Subroutine->isIntrinsic() &&
562+
!GenXIntrinsic::isGenXIntrinsic(Subroutine),
563+
"it should've been already checked");
564+
return Subroutine;
565+
});
566+
std::sort(Subroutines.begin(), Subroutines.end());
567+
Subroutines.erase(std::unique(Subroutines.begin(), Subroutines.end()),
568+
Subroutines.end());
569+
return std::move(Subroutines);
570+
}
571+
572+
// Recursively materialize \p Parent's subroutines and its subroutines too.
573+
static void materializeSubroutines(Function &Parent) {
574+
std::vector<Function *> Subroutines = collectDirectSubroutines(Parent);
575+
for (Function *Subroutine : Subroutines) {
576+
materializeFuncIfRequired(*Subroutine);
577+
materializeSubroutines(*Subroutine);
578+
}
579+
}
580+
581+
static void
582+
materializeUsedBiFFuncs(const std::vector<FuncAndItsImpl> &FuncsFromBiF) {
583+
for (auto &&[FuncDecl, FuncImpl] : FuncsFromBiF) {
584+
(void)FuncDecl;
585+
materializeFuncIfRequired(*FuncImpl);
586+
materializeSubroutines(*FuncImpl);
544587
}
588+
}
589+
590+
bool CMImportBiF(llvm::Module *MainModule,
591+
std::unique_ptr<llvm::Module> BiFModule) {
592+
std::vector<FuncAndItsImpl> FuncsFromBiF =
593+
collectBiFFuncUses(*MainModule, *BiFModule);
594+
materializeUsedBiFFuncs(FuncsFromBiF);
595+
fixCallingConv(FuncsFromBiF);
545596

546597
// nuke the unused functions so we can materializeAll() quickly
547598
auto CleanUnused = [](llvm::Module *Module) {
@@ -558,7 +609,11 @@ bool CMImportBiF(llvm::Module *MainModule,
558609
CleanUnused(BiFModule.get());
559610
Linker ld(*MainModule);
560611

561-
if (Error err = BiFModule->materializeAll()) {
612+
if (Error Err = BiFModule->materializeAll()) {
613+
handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
614+
errs() << "===> Materialize All Failure: " << EIB.message().c_str()
615+
<< '\n';
616+
});
562617
IGC_ASSERT_MESSAGE(0, "materializeAll failed for generic builtin module");
563618
}
564619

@@ -614,15 +669,6 @@ void GenXImportBiF::getAnalysisUsage(AnalysisUsage &AU) const {
614669
AU.addRequired<GenXBackendConfig>();
615670
}
616671

617-
static bool isOCLBuiltinDecl(const Function &F) {
618-
if (!F.isDeclaration())
619-
return false;
620-
if (F.isIntrinsic() || GenXIntrinsic::isGenXIntrinsic(&F))
621-
return false;
622-
// presuming that the only declarations left are from OCL header
623-
return true;
624-
}
625-
626672
// Whether module has uresolved calls to OpenCL builtins.
627673
static bool OCLBuiltinsRequired(const Module &M) {
628674
return std::any_of(M.begin(), M.end(),

0 commit comments

Comments
 (0)