@@ -40,6 +40,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40
40
#include " GenX.h"
41
41
#include " GenXBackendConfig.h"
42
42
43
+ #include < llvm/ADT/STLExtras.h>
43
44
#include < llvm/ADT/SmallPtrSet.h>
44
45
#include < llvm/Bitcode/BitcodeReader.h>
45
46
#include < llvm/IR/Attributes.h>
@@ -351,9 +352,9 @@ void BIConvert::runOnModule(Module &M) {
351
352
typedef std::vector<llvm::Function *> TFunctionsVec;
352
353
353
354
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 ())
357
358
return pFunc;
358
359
return nullptr ;
359
360
}
@@ -362,32 +363,6 @@ static bool materialized_use_empty(const Value *v) {
362
363
return v->materialized_use_begin () == v->use_end ();
363
364
}
364
365
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
-
391
366
static void removeFunctionBitcasts (llvm::Module &M) {
392
367
std::vector<Instruction *> list_delete;
393
368
DenseMap<Function *, std::vector<Function *>> bitcastFunctionMap;
@@ -505,43 +480,119 @@ static void InitializeBIFlags(llvm::Module &M) {
505
480
*reinterpret_cast <int *>(&profilingTimerResolution));
506
481
}
507
482
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
525
491
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});
539
525
}
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
+ }
541
539
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);
544
587
}
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);
545
596
546
597
// nuke the unused functions so we can materializeAll() quickly
547
598
auto CleanUnused = [](llvm::Module *Module) {
@@ -558,7 +609,11 @@ bool CMImportBiF(llvm::Module *MainModule,
558
609
CleanUnused (BiFModule.get ());
559
610
Linker ld (*MainModule);
560
611
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
+ });
562
617
IGC_ASSERT_MESSAGE (0 , " materializeAll failed for generic builtin module" );
563
618
}
564
619
@@ -614,15 +669,6 @@ void GenXImportBiF::getAnalysisUsage(AnalysisUsage &AU) const {
614
669
AU.addRequired <GenXBackendConfig>();
615
670
}
616
671
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
-
626
672
// Whether module has uresolved calls to OpenCL builtins.
627
673
static bool OCLBuiltinsRequired (const Module &M) {
628
674
return std::any_of (M.begin (), M.end (),
0 commit comments