Skip to content

Commit 1b8c225

Browse files
committed
Reinstate llvm.compiler.used removal at SPL
For spirv remove the llvm.compiler.used symbol at sycl-post-link. This is because we use llvm-spirv for lowering, not the SPIR-V backend.
1 parent 3f9ae01 commit 1b8c225

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

llvm/tools/sycl-post-link/sycl-post-link.cpp

+71
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,70 @@ static bool removeSYCLKernelsConstRefArray(Module &M) {
572572
return true;
573573
}
574574

575+
// Removes all device_global variables from the llvm.compiler.used global
576+
// variable. A device_global with internal linkage will be in llvm.compiler.used
577+
// to avoid the compiler wrongfully removing it during optimizations. However,
578+
// as an effect the device_global variables will also be distributed across
579+
// binaries, even if llvm.compiler.used has served its purpose. To avoid
580+
// polluting other binaries with unused device_global variables, we remove them
581+
// from llvm.compiler.used and erase them if they have no further uses.
582+
static bool removeDeviceGlobalFromCompilerUsed(Module &M) {
583+
GlobalVariable *GV = M.getGlobalVariable("llvm.compiler.used");
584+
if (!GV)
585+
return false;
586+
587+
// Erase the old llvm.compiler.used. A new one will be created at the end if
588+
// there are other values in it (other than device_global).
589+
assert(GV->user_empty() && "Unexpected llvm.compiler.used users");
590+
Constant *Initializer = GV->getInitializer();
591+
const auto *VAT = cast<ArrayType>(GV->getValueType());
592+
GV->setInitializer(nullptr);
593+
GV->eraseFromParent();
594+
595+
// Destroy the initializer. Keep the operands so we keep the ones we need.
596+
SmallVector<Constant *, 8> IOperands;
597+
for (auto It = Initializer->op_begin(); It != Initializer->op_end(); It++)
598+
IOperands.push_back(cast<Constant>(*It));
599+
assert(llvm::isSafeToDestroyConstant(Initializer) &&
600+
"Cannot remove initializer of llvm.compiler.used global");
601+
Initializer->destroyConstant();
602+
603+
// Iterate through all operands. If they are device_global then we drop them
604+
// and erase them if they have no uses afterwards. All other values are kept.
605+
SmallVector<Constant *, 8> NewOperands;
606+
for (auto It = IOperands.begin(); It != IOperands.end(); It++) {
607+
Constant *Op = *It;
608+
auto *DG = dyn_cast<GlobalVariable>(Op->stripPointerCasts());
609+
610+
// If it is not a device_global we keep it.
611+
if (!DG || !isDeviceGlobalVariable(*DG)) {
612+
NewOperands.push_back(Op);
613+
continue;
614+
}
615+
616+
// Destroy the device_global operand.
617+
if (llvm::isSafeToDestroyConstant(Op))
618+
Op->destroyConstant();
619+
620+
// Remove device_global if it no longer has any uses.
621+
if (!DG->isConstantUsed())
622+
DG->eraseFromParent();
623+
}
624+
625+
// If we have any operands left from the original llvm.compiler.used we create
626+
// a new one with the new size.
627+
if (!NewOperands.empty()) {
628+
ArrayType *ATy = ArrayType::get(VAT->getElementType(), NewOperands.size());
629+
GlobalVariable *NGV =
630+
new GlobalVariable(M, ATy, false, GlobalValue::AppendingLinkage,
631+
ConstantArray::get(ATy, NewOperands), "");
632+
NGV->setName("llvm.compiler.used");
633+
NGV->setSection("llvm.metadata");
634+
}
635+
636+
return true;
637+
}
638+
575639
SmallVector<module_split::ModuleDesc, 2>
576640
handleESIMD(module_split::ModuleDesc &&MDesc, bool &Modified,
577641
bool &SplitOccurred) {
@@ -719,6 +783,13 @@ processInputModule(std::unique_ptr<Module> M) {
719783
// actions.
720784
Modified |= removeSYCLKernelsConstRefArray(*M.get());
721785

786+
// There may be device_global variables kept alive in "llvm.compiler.used"
787+
// to keep the optimizer from wrongfully removing them. llvm.compiler.used
788+
// symbols are usually removed at backend lowering, but this is handled here
789+
// for SPIR-V since SYCL compilation uses llvm-spirv, not the SPIR-V backend.
790+
if (auto Triple = M->getTargetTriple().find("spir") != std::string::npos)
791+
Modified |= removeDeviceGlobalFromCompilerUsed(*M.get());
792+
722793
// Instrument each image scope device globals if the module has been
723794
// instrumented by sanitizer pass.
724795
if (isModuleUsingAsan(*M))

0 commit comments

Comments
 (0)