Skip to content

Commit 154650e

Browse files
committed
[SYCL][NFCI] Restore commit ccd73ee
Commit > ccd73ee > [LinkerWrapper] Remove in-house handling of LTO (llvm/llvm-project#113715) Removed a lot of dead code from `clang-linker-wrapper`. However, it has been preserved in our fork by: > d7c2a0f > Merge from 'main' to 'sycl-web' (69 commits) Due to the way we have handled a divergence from the upstream it isn't really clear if something is our code or not, so it wasn't that hard to make a conflict resolution mistake. This commit removes all that dead code to make it closer to the upstream.
1 parent 41d4f25 commit 154650e

File tree

1 file changed

+3
-351
lines changed

1 file changed

+3
-351
lines changed

clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp

Lines changed: 3 additions & 351 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,6 @@ static std::list<SmallString<128>> TempFiles;
147147
/// Codegen flags for LTO backend.
148148
static codegen::RegisterCodeGenFlags CodeGenFlags;
149149

150-
/// Global flag to indicate that the LTO pipeline threw an error.
151-
static std::atomic<bool> LTOError;
152-
153150
static std::optional<llvm::module_split::IRSplitMode> SYCLModuleSplitMode;
154151

155152
static bool UseSYCLPostLinkTool;
@@ -1706,338 +1703,6 @@ void diagnosticHandler(const DiagnosticInfo &DI) {
17061703
}
17071704
}
17081705

1709-
// Get the list of target features from the input file and unify them such that
1710-
// if there are multiple +xxx or -xxx features we only keep the last one.
1711-
std::vector<std::string> getTargetFeatures(ArrayRef<OffloadFile> InputFiles) {
1712-
SmallVector<StringRef> Features;
1713-
for (const OffloadFile &File : InputFiles) {
1714-
for (auto &Arg : llvm::split(File.getBinary()->getString("feature"), ","))
1715-
Features.emplace_back(Arg);
1716-
}
1717-
1718-
// Only add a feature if it hasn't been seen before starting from the end.
1719-
std::vector<std::string> UnifiedFeatures;
1720-
DenseSet<StringRef> UsedFeatures;
1721-
for (StringRef Feature : llvm::reverse(Features)) {
1722-
if (UsedFeatures.insert(Feature.drop_front()).second)
1723-
UnifiedFeatures.push_back(Feature.str());
1724-
}
1725-
1726-
return UnifiedFeatures;
1727-
}
1728-
1729-
template <typename ModuleHook = function_ref<bool(size_t, const Module &)>>
1730-
std::unique_ptr<lto::LTO> createLTO(
1731-
const ArgList &Args, const std::vector<std::string> &Features,
1732-
ModuleHook Hook = [](size_t, const Module &) { return true; }) {
1733-
const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
1734-
// We need to remove AMD's target-id from the processor if present.
1735-
StringRef TargetID = Args.getLastArgValue(OPT_arch_EQ);
1736-
StringRef Arch = clang::getProcessorFromTargetID(Triple, TargetID);
1737-
lto::Config Conf;
1738-
lto::ThinBackend Backend;
1739-
// TODO: Handle index-only thin-LTO
1740-
Backend =
1741-
lto::createInProcessThinBackend(llvm::heavyweight_hardware_concurrency());
1742-
1743-
Conf.CPU = Arch.str();
1744-
Conf.Options = codegen::InitTargetOptionsFromCodeGenFlags(Triple);
1745-
1746-
Conf.RemarksFilename = RemarksFilename;
1747-
Conf.RemarksPasses = RemarksPasses;
1748-
Conf.RemarksWithHotness = RemarksWithHotness;
1749-
Conf.RemarksHotnessThreshold = RemarksHotnessThreshold;
1750-
Conf.RemarksFormat = RemarksFormat;
1751-
1752-
StringRef OptLevel = Args.getLastArgValue(OPT_opt_level, "O2");
1753-
Conf.MAttrs = Features;
1754-
std::optional<CodeGenOptLevel> CGOptLevelOrNone =
1755-
CodeGenOpt::parseLevel(OptLevel[1]);
1756-
assert(CGOptLevelOrNone && "Invalid optimization level");
1757-
Conf.CGOptLevel = *CGOptLevelOrNone;
1758-
Conf.OptLevel = OptLevel[1] - '0';
1759-
Conf.DefaultTriple = Triple.getTriple();
1760-
1761-
// TODO: Should we complain about combining --opt-level and -passes, as opt
1762-
// does? That might be too limiting in clang-linker-wrapper, so for now we
1763-
// just warn in the help entry for -passes that the default<O?> corresponding
1764-
// to --opt-level=O? should be included there. The problem is that
1765-
// --opt-level produces effects in clang-linker-wrapper beyond what -passes
1766-
// appears to be able to achieve, so rejecting the combination of --opt-level
1767-
// and -passes would apparently make it impossible to combine those effects
1768-
// with a custom pass pipeline.
1769-
Conf.OptPipeline = PassPipeline;
1770-
Conf.PassPlugins = PassPlugins;
1771-
1772-
LTOError = false;
1773-
Conf.DiagHandler = diagnosticHandler;
1774-
1775-
Conf.PTO.LoopVectorization = Conf.OptLevel > 1;
1776-
Conf.PTO.SLPVectorization = Conf.OptLevel > 1;
1777-
1778-
if (SaveTemps) {
1779-
std::string TempName = (sys::path::filename(ExecutableName) + "." +
1780-
Triple.getTriple() + "." + TargetID)
1781-
.str();
1782-
Conf.PostInternalizeModuleHook = [=](size_t Task, const Module &M) {
1783-
std::string File =
1784-
!Task ? TempName + ".postlink.bc"
1785-
: TempName + "." + std::to_string(Task) + ".postlink.bc";
1786-
error_code EC;
1787-
raw_fd_ostream LinkedBitcode(File, EC, sys::fs::OF_None);
1788-
if (EC)
1789-
reportError(errorCodeToError(EC));
1790-
WriteBitcodeToFile(M, LinkedBitcode);
1791-
return true;
1792-
};
1793-
Conf.PreCodeGenModuleHook = [=](size_t Task, const Module &M) {
1794-
std::string File =
1795-
!Task ? TempName + ".postopt.bc"
1796-
: TempName + "." + std::to_string(Task) + ".postopt.bc";
1797-
error_code EC;
1798-
raw_fd_ostream LinkedBitcode(File, EC, sys::fs::OF_None);
1799-
if (EC)
1800-
reportError(errorCodeToError(EC));
1801-
WriteBitcodeToFile(M, LinkedBitcode);
1802-
return true;
1803-
};
1804-
}
1805-
Conf.PostOptModuleHook = Hook;
1806-
Conf.CGFileType = (Triple.isNVPTX() || SaveTemps)
1807-
? CodeGenFileType::AssemblyFile
1808-
: CodeGenFileType::ObjectFile;
1809-
1810-
// TODO: Handle remark files
1811-
Conf.HasWholeProgramVisibility = Args.hasArg(OPT_whole_program);
1812-
1813-
return std::make_unique<lto::LTO>(std::move(Conf), Backend);
1814-
}
1815-
1816-
// Returns true if \p S is valid as a C language identifier and will be given
1817-
// `__start_` and `__stop_` symbols.
1818-
bool isValidCIdentifier(StringRef S) {
1819-
return !S.empty() && (isAlpha(S[0]) || S[0] == '_') &&
1820-
llvm::all_of(llvm::drop_begin(S),
1821-
[](char C) { return C == '_' || isAlnum(C); });
1822-
}
1823-
1824-
Error linkBitcodeFiles(SmallVectorImpl<OffloadFile> &InputFiles,
1825-
SmallVectorImpl<StringRef> &OutputFiles,
1826-
const ArgList &Args) {
1827-
llvm::TimeTraceScope TimeScope("Link bitcode files");
1828-
const llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ));
1829-
StringRef Arch = Args.getLastArgValue(OPT_arch_EQ);
1830-
1831-
// Early exit for SPIR targets
1832-
if (Triple.isSPIROrSPIRV())
1833-
return Error::success();
1834-
1835-
SmallVector<OffloadFile, 4> BitcodeInputFiles;
1836-
DenseSet<StringRef> StrongResolutions;
1837-
DenseSet<StringRef> UsedInRegularObj;
1838-
DenseSet<StringRef> UsedInSharedLib;
1839-
BumpPtrAllocator Alloc;
1840-
StringSaver Saver(Alloc);
1841-
1842-
// Search for bitcode files in the input and create an LTO input file. If
1843-
// it is not a bitcode file, scan its symbol table for symbols we need to
1844-
// save.
1845-
for (OffloadFile &File : InputFiles) {
1846-
MemoryBufferRef Buffer = MemoryBufferRef(File.getBinary()->getImage(), "");
1847-
1848-
file_magic Type = identify_magic(Buffer.getBuffer());
1849-
switch (Type) {
1850-
case file_magic::bitcode: {
1851-
Expected<IRSymtabFile> IRSymtabOrErr = readIRSymtab(Buffer);
1852-
if (!IRSymtabOrErr)
1853-
return IRSymtabOrErr.takeError();
1854-
1855-
// Check for any strong resolutions we need to preserve.
1856-
for (unsigned I = 0; I != IRSymtabOrErr->Mods.size(); ++I) {
1857-
for (const auto &Sym : IRSymtabOrErr->TheReader.module_symbols(I)) {
1858-
if (!Sym.isFormatSpecific() && Sym.isGlobal() && !Sym.isWeak() &&
1859-
!Sym.isUndefined())
1860-
StrongResolutions.insert(Saver.save(Sym.Name));
1861-
}
1862-
}
1863-
BitcodeInputFiles.emplace_back(std::move(File));
1864-
continue;
1865-
}
1866-
case file_magic::elf_relocatable:
1867-
case file_magic::elf_shared_object: {
1868-
Expected<std::unique_ptr<ObjectFile>> ObjFile =
1869-
ObjectFile::createObjectFile(Buffer);
1870-
if (!ObjFile)
1871-
continue;
1872-
1873-
for (SymbolRef Sym : (*ObjFile)->symbols()) {
1874-
Expected<StringRef> Name = Sym.getName();
1875-
if (!Name)
1876-
return Name.takeError();
1877-
1878-
// Record if we've seen these symbols in any object or shared
1879-
// libraries.
1880-
if ((*ObjFile)->isRelocatableObject())
1881-
UsedInRegularObj.insert(Saver.save(*Name));
1882-
else
1883-
UsedInSharedLib.insert(Saver.save(*Name));
1884-
}
1885-
continue;
1886-
}
1887-
default:
1888-
continue;
1889-
}
1890-
}
1891-
1892-
if (BitcodeInputFiles.empty())
1893-
return Error::success();
1894-
1895-
// Remove all the bitcode files that we moved from the original input.
1896-
llvm::erase_if(InputFiles, [](OffloadFile &F) { return !F.getBinary(); });
1897-
1898-
// LTO Module hook to output bitcode without running the backend.
1899-
SmallVector<StringRef> BitcodeOutput;
1900-
auto OutputBitcode = [&](size_t, const Module &M) {
1901-
auto TempFileOrErr = createOutputFile(sys::path::filename(ExecutableName) +
1902-
"-jit-" + Triple.getTriple(),
1903-
"bc");
1904-
if (!TempFileOrErr)
1905-
reportError(TempFileOrErr.takeError());
1906-
1907-
std::error_code EC;
1908-
raw_fd_ostream LinkedBitcode(*TempFileOrErr, EC, sys::fs::OF_None);
1909-
if (EC)
1910-
reportError(errorCodeToError(EC));
1911-
WriteBitcodeToFile(M, LinkedBitcode);
1912-
BitcodeOutput.push_back(*TempFileOrErr);
1913-
return false;
1914-
};
1915-
1916-
// We assume visibility of the whole program if every input file was
1917-
// bitcode.
1918-
auto Features = getTargetFeatures(BitcodeInputFiles);
1919-
auto LTOBackend = Args.hasArg(OPT_embed_bitcode) ||
1920-
Args.hasArg(OPT_builtin_bitcode_EQ) ||
1921-
Args.hasArg(OPT_clang_backend)
1922-
? createLTO(Args, Features, OutputBitcode)
1923-
: createLTO(Args, Features);
1924-
1925-
// We need to resolve the symbols so the LTO backend knows which symbols
1926-
// need to be kept or can be internalized. This is a simplified symbol
1927-
// resolution scheme to approximate the full resolution a linker would do.
1928-
uint64_t Idx = 0;
1929-
DenseSet<StringRef> PrevailingSymbols;
1930-
for (auto &BitcodeInput : BitcodeInputFiles) {
1931-
// Get a semi-unique buffer identifier for Thin-LTO.
1932-
StringRef Identifier = Saver.save(
1933-
std::to_string(Idx++) + "." +
1934-
BitcodeInput.getBinary()->getMemoryBufferRef().getBufferIdentifier());
1935-
MemoryBufferRef Buffer =
1936-
MemoryBufferRef(BitcodeInput.getBinary()->getImage(), Identifier);
1937-
Expected<std::unique_ptr<lto::InputFile>> BitcodeFileOrErr =
1938-
llvm::lto::InputFile::create(Buffer);
1939-
if (!BitcodeFileOrErr)
1940-
return BitcodeFileOrErr.takeError();
1941-
1942-
// Save the input file and the buffer associated with its memory.
1943-
const auto Symbols = (*BitcodeFileOrErr)->symbols();
1944-
SmallVector<lto::SymbolResolution, 16> Resolutions(Symbols.size());
1945-
size_t Idx = 0;
1946-
for (auto &Sym : Symbols) {
1947-
lto::SymbolResolution &Res = Resolutions[Idx++];
1948-
1949-
// We will use this as the prevailing symbol definition in LTO unless
1950-
// it is undefined or another definition has already been used.
1951-
Res.Prevailing =
1952-
!Sym.isUndefined() &&
1953-
!(Sym.isWeak() && StrongResolutions.contains(Sym.getName())) &&
1954-
PrevailingSymbols.insert(Saver.save(Sym.getName())).second;
1955-
1956-
// We need LTO to preseve the following global symbols:
1957-
// 1) Symbols used in regular objects.
1958-
// 2) Sections that will be given a __start/__stop symbol.
1959-
// 3) Prevailing symbols that are needed visible to external
1960-
// libraries.
1961-
Res.VisibleToRegularObj =
1962-
UsedInRegularObj.contains(Sym.getName()) ||
1963-
isValidCIdentifier(Sym.getSectionName()) ||
1964-
(Res.Prevailing &&
1965-
(Sym.getVisibility() != GlobalValue::HiddenVisibility &&
1966-
!Sym.canBeOmittedFromSymbolTable()));
1967-
1968-
// Identify symbols that must be exported dynamically and can be
1969-
// referenced by other files.
1970-
Res.ExportDynamic =
1971-
Sym.getVisibility() != GlobalValue::HiddenVisibility &&
1972-
(UsedInSharedLib.contains(Sym.getName()) ||
1973-
!Sym.canBeOmittedFromSymbolTable());
1974-
1975-
// The final definition will reside in this linkage unit if the symbol
1976-
// is defined and local to the module. This only checks for bitcode
1977-
// files, full assertion will require complete symbol resolution.
1978-
Res.FinalDefinitionInLinkageUnit =
1979-
Sym.getVisibility() != GlobalValue::DefaultVisibility &&
1980-
(!Sym.isUndefined() && !Sym.isCommon());
1981-
1982-
// We do not support linker redefined symbols (e.g. --wrap) for device
1983-
// image linking, so the symbols will not be changed after LTO.
1984-
Res.LinkerRedefined = false;
1985-
}
1986-
1987-
// Add the bitcode file with its resolved symbols to the LTO job.
1988-
if (Error Err = LTOBackend->add(std::move(*BitcodeFileOrErr), Resolutions))
1989-
return Err;
1990-
}
1991-
1992-
// Run the LTO job to compile the bitcode.
1993-
size_t MaxTasks = LTOBackend->getMaxTasks();
1994-
SmallVector<StringRef> Files(MaxTasks);
1995-
auto AddStream =
1996-
[&](size_t Task,
1997-
const Twine &ModuleName) -> std::unique_ptr<CachedFileStream> {
1998-
int FD = -1;
1999-
auto &TempFile = Files[Task];
2000-
StringRef Extension = (Triple.isNVPTX() || SaveTemps) ? "s" : "o";
2001-
std::string TaskStr = Task ? "." + std::to_string(Task) : "";
2002-
auto TempFileOrErr =
2003-
createOutputFile(sys::path::filename(ExecutableName) + "." +
2004-
Triple.getTriple() + "." + Arch + TaskStr,
2005-
Extension);
2006-
if (!TempFileOrErr)
2007-
reportError(TempFileOrErr.takeError());
2008-
TempFile = *TempFileOrErr;
2009-
if (std::error_code EC = sys::fs::openFileForWrite(TempFile, FD))
2010-
reportError(errorCodeToError(EC));
2011-
return std::make_unique<CachedFileStream>(
2012-
std::make_unique<llvm::raw_fd_ostream>(FD, true));
2013-
};
2014-
2015-
if (Error Err = LTOBackend->run(AddStream))
2016-
return Err;
2017-
2018-
if (LTOError)
2019-
return createStringError("Errors encountered inside the LTO pipeline.");
2020-
2021-
// If we are embedding bitcode we only need the intermediate output.
2022-
bool SingleOutput = Files.size() == 1;
2023-
if (Args.hasArg(OPT_embed_bitcode)) {
2024-
if (BitcodeOutput.size() != 1 || !SingleOutput)
2025-
return createStringError("Cannot embed bitcode with multiple files.");
2026-
OutputFiles.push_back(Args.MakeArgString(BitcodeOutput.front()));
2027-
return Error::success();
2028-
}
2029-
2030-
// Append the new inputs to the device linker input. If the user requested
2031-
// an internalizing link we need to pass the bitcode to clang.
2032-
for (StringRef File :
2033-
Args.hasArg(OPT_clang_backend) || Args.hasArg(OPT_builtin_bitcode_EQ)
2034-
? BitcodeOutput
2035-
: Files)
2036-
OutputFiles.push_back(File);
2037-
2038-
return Error::success();
2039-
}
2040-
20411706
// Compile the module to an object file using the appropriate target machine for
20421707
// the host triple.
20431708
Expected<StringRef> compileModule(Module &M, OffloadKind Kind) {
@@ -2370,15 +2035,8 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
23702035
return FileNameOrErr.takeError();
23712036
InputFiles.emplace_back(*FileNameOrErr);
23722037
}
2038+
23732039
if (HasSYCLOffloadKind) {
2374-
SmallVector<StringRef> InputFiles;
2375-
// Write device inputs to an output file for the linker.
2376-
for (const OffloadFile &File : Input) {
2377-
auto FileNameOrErr = writeOffloadFile(File);
2378-
if (!FileNameOrErr)
2379-
return FileNameOrErr.takeError();
2380-
InputFiles.emplace_back(*FileNameOrErr);
2381-
}
23822040
// Link the input device files using the device linker for SYCL
23832041
// offload.
23842042
auto TmpOutputOrErr = sycl::linkDevice(InputFiles, LinkerArgs);
@@ -2458,12 +2116,8 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
24582116
std::scoped_lock Guard(ImageMtx);
24592117
WrappedOutput.push_back(*OutputFile);
24602118
}
2461-
if (HasNonSYCLOffloadKinds) {
2462-
// First link and remove all the input files containing bitcode.
2463-
SmallVector<StringRef> InputFiles;
2464-
if (Error Err = linkBitcodeFiles(Input, InputFiles, LinkerArgs))
2465-
return Err;
24662119

2120+
if (HasNonSYCLOffloadKinds) {
24672121
// Write any remaining device inputs to an output file for the linker.
24682122
for (const OffloadFile &File : Input) {
24692123
auto FileNameOrErr = writeOffloadFile(File);
@@ -2473,9 +2127,7 @@ Expected<SmallVector<StringRef>> linkAndWrapDeviceFiles(
24732127
}
24742128

24752129
// Link the remaining device files using the device linker.
2476-
auto OutputOrErr = !Args.hasArg(OPT_embed_bitcode)
2477-
? linkDevice(InputFiles, LinkerArgs)
2478-
: InputFiles.front();
2130+
auto OutputOrErr = linkDevice(InputFiles, LinkerArgs);
24792131
if (!OutputOrErr)
24802132
return OutputOrErr.takeError();
24812133
// Store the offloading image for each linked output file.

0 commit comments

Comments
 (0)