Skip to content

Commit 7cc7ac6

Browse files
committed
Fix SPIR-V function ordering violation in linker
SPIR-V specification requires all function declarations to appear before any function definitions. However, LLVM's linker was producing modules where declarations appeared after definitions, causing SPIR-V validation failures and compilation errors. Problem: - Function declarations (declare) were scattered throughout the module - Some declarations appeared after function definitions (define) - This violates SPIR-V spec section 2.4 which mandates declaration-before-definition ordering - Resulted in invalid SPIR-V modules that failed validation Solution: - Added SPIR-V target detection in ModuleLinker::run() - Implemented reorderFunctionsForSPIRV() to enforce proper ordering - Only activates for SPIR-V targets (spirv, spirv32, spirv64) - Reorders functions: all declarations first, then all definitions - Preserves function references and module integrity
1 parent 376b714 commit 7cc7ac6

File tree

1 file changed

+60
-0
lines changed

1 file changed

+60
-0
lines changed

llvm/lib/Linker/LinkModules.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/IR/Module.h"
2020
#include "llvm/Linker/Linker.h"
2121
#include "llvm/Support/Error.h"
22+
#include "llvm/TargetParser/Triple.h"
2223
using namespace llvm;
2324

2425
namespace {
@@ -105,6 +106,10 @@ class ModuleLinker {
105106
const DenseSet<const Comdat *> &ReplacedDstComdats);
106107

107108
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);
108113

109114
public:
110115
ModuleLinker(IRMover &Mover, std::unique_ptr<Module> SrcM, unsigned Flags,
@@ -615,9 +620,64 @@ bool ModuleLinker::run() {
615620
if (InternalizeCallback)
616621
InternalizeCallback(DstM, Internalize);
617622

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+
618630
return false;
619631
}
620632

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+
621681
Linker::Linker(Module &M) : Mover(M) {}
622682

623683
bool Linker::linkInModule(

0 commit comments

Comments
 (0)