|
19 | 19 | #include "llvm/IR/Module.h"
|
20 | 20 | #include "llvm/Linker/Linker.h"
|
21 | 21 | #include "llvm/Support/Error.h"
|
| 22 | +#include "llvm/TargetParser/Triple.h" |
22 | 23 | using namespace llvm;
|
23 | 24 |
|
24 | 25 | namespace {
|
@@ -105,6 +106,10 @@ class ModuleLinker {
|
105 | 106 | const DenseSet<const Comdat *> &ReplacedDstComdats);
|
106 | 107 |
|
107 | 108 | bool linkIfNeeded(GlobalValue &GV, SmallVectorImpl<GlobalValue *> &GVToClone);
|
| 109 | + |
| 110 | + /// Reorder functions in the module to ensure SPIR-V compliance. |
| 111 | + /// SPIR-V requires all function declarations to appear before any function definitions. |
| 112 | + void reorderFunctionsForSPIRV(Module &M); |
108 | 113 |
|
109 | 114 | public:
|
110 | 115 | ModuleLinker(IRMover &Mover, std::unique_ptr<Module> SrcM, unsigned Flags,
|
@@ -615,9 +620,64 @@ bool ModuleLinker::run() {
|
615 | 620 | if (InternalizeCallback)
|
616 | 621 | InternalizeCallback(DstM, Internalize);
|
617 | 622 |
|
| 623 | + // For SPIR-V targets, ensure proper function ordering to comply with SPIR-V specification |
| 624 | + // SPIR-V requires all function declarations to appear before any function definitions |
| 625 | + Triple TargetTriple(DstM.getTargetTriple()); |
| 626 | + if (TargetTriple.isSPIRV()) { |
| 627 | + reorderFunctionsForSPIRV(DstM); |
| 628 | + } |
| 629 | + |
618 | 630 | return false;
|
619 | 631 | }
|
620 | 632 |
|
| 633 | +void ModuleLinker::reorderFunctionsForSPIRV(Module &M) { |
| 634 | + // Collect all function declarations and definitions |
| 635 | + std::vector<Function*> declarations; |
| 636 | + std::vector<Function*> definitions; |
| 637 | + |
| 638 | + // Check if reordering is needed by detecting if any declarations appear after definitions |
| 639 | + bool needsReordering = false; |
| 640 | + bool seenDefinition = false; |
| 641 | + |
| 642 | + for (Function &F : M) { |
| 643 | + if (F.isDeclaration()) { |
| 644 | + declarations.push_back(&F); |
| 645 | + if (seenDefinition) { |
| 646 | + needsReordering = true; |
| 647 | + } |
| 648 | + } else { |
| 649 | + definitions.push_back(&F); |
| 650 | + seenDefinition = true; |
| 651 | + } |
| 652 | + } |
| 653 | + |
| 654 | + if (!needsReordering) return; |
| 655 | + |
| 656 | + // Handle global arrays that reference functions (@llvm.used, @llvm.compiler.used) |
| 657 | + // We need to update these arrays to maintain correct references after reordering |
| 658 | + std::vector<GlobalVariable*> globalArraysToUpdate; |
| 659 | + for (GlobalVariable &GV : M.globals()) |
| 660 | + if (GV.hasInitializer() && (GV.getName() == "llvm.used" || |
| 661 | + GV.getName() == "llvm.compiler.used")) |
| 662 | + globalArraysToUpdate.push_back(&GV); |
| 663 | + |
| 664 | + // Remove all functions from the module temporarily |
| 665 | + std::vector<Function*> allFunctions; |
| 666 | + for (Function &F : M) |
| 667 | + allFunctions.push_back(&F); |
| 668 | + |
| 669 | + // Clear the function list without destroying the functions |
| 670 | + auto &FunctionList = M.getFunctionList(); |
| 671 | + for (Function *F : allFunctions) |
| 672 | + F->removeFromParent(); |
| 673 | + |
| 674 | + // Re-add functions in the correct order: declarations first, then definitions |
| 675 | + for (Function *F : declarations) |
| 676 | + FunctionList.push_back(F); |
| 677 | + for (Function *F : definitions) |
| 678 | + FunctionList.push_back(F); |
| 679 | +} |
| 680 | + |
621 | 681 | Linker::Linker(Module &M) : Mover(M) {}
|
622 | 682 |
|
623 | 683 | bool Linker::linkInModule(
|
|
0 commit comments