[lld] [lld][COFF][LTO] Implement /opt:emitasm option (PR #67079)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 21 18:04:15 PDT 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld-elf
<details>
<summary>Changes</summary>
Stacked on top of https://github.com/llvm/llvm-project/pull/66964
Disregard first and second commits.
---
Full diff: https://github.com/llvm/llvm-project/pull/67079.diff
9 Files Affected:
- (modified) lld/COFF/Config.h (+2)
- (modified) lld/COFF/Driver.cpp (+6-1)
- (modified) lld/COFF/LTO.cpp (+22-17)
- (modified) lld/Common/Filesystem.cpp (+26)
- (modified) lld/ELF/LTO.cpp (+1-26)
- (modified) lld/MachO/LTO.cpp (+1-13)
- (modified) lld/include/lld/Common/Filesystem.h (+4)
- (added) lld/test/COFF/lto-emit-asm.ll (+28)
- (added) lld/test/COFF/lto-emit-llvm.ll (+14)
``````````diff
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 4ade2c953c73e40..c80df08cfcf09aa 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -311,6 +311,8 @@ struct Configuration {
bool pseudoRelocs = false;
bool stdcallFixup = false;
bool writeCheckSum = false;
+ bool emitLLVM = false;
+ bool emitASM = false;
};
} // namespace lld::coff
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 61a04a74aa60278..304344512cf61a0 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -1823,6 +1823,10 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
ltoDebugPM = true;
} else if (s == "noltodebugpassmanager") {
ltoDebugPM = false;
+ } else if (s == "emitllvm") {
+ config->emitLLVM = true;
+ } else if (s == "emitasm") {
+ config->emitASM = true;
} else if (s.consume_front("lldlto=")) {
if (s.getAsInteger(10, config->ltoo) || config->ltoo > 3)
error("/opt:lldlto: invalid optimization level: " + s);
@@ -2395,7 +2399,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// If -thinlto-index-only is given, we should create only "index
// files" and not object files. Index file creation is already done
// in addCombinedLTOObject, so we are done if that's the case.
- if (config->thinLTOIndexOnly)
+ // Likewise, for /opt:emitllvm and /opt:emitasm we only emit bitcode / asm.
+ if (config->emitLLVM || config->emitASM || config->thinLTOIndexOnly)
return;
// If we generated native object files from bitcode files, this resolves
diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index c185da5370fa3dd..ae207abc801437d 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -13,6 +13,7 @@
#include "Symbols.h"
#include "lld/Common/Args.h"
#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/Filesystem.h"
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/ADT/STLExtras.h"
@@ -42,18 +43,6 @@ using namespace llvm::object;
using namespace lld;
using namespace lld::coff;
-// Creates an empty file to and returns a raw_fd_ostream to write to it.
-static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) {
- std::error_code ec;
- auto ret =
- std::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::OF_None);
- if (ec) {
- error("cannot open " + file + ": " + ec.message());
- return nullptr;
- }
- return ret;
-}
-
std::string BitcodeCompiler::getThinLTOOutputFile(StringRef path) {
return lto::getThinLTOOutputFile(path, ctx.config.thinLTOPrefixReplaceOld,
ctx.config.thinLTOPrefixReplaceNew);
@@ -98,6 +87,20 @@ lto::Config BitcodeCompiler::createConfig() {
c.RunCSIRInstr = ctx.config.ltoCSProfileGenerate;
c.PGOWarnMismatch = ctx.config.ltoPGOWarnMismatch;
+ if (ctx.config.emitLLVM) {
+ c.PostInternalizeModuleHook = [this](size_t task, const Module &m) {
+ if (std::unique_ptr<raw_fd_ostream> os =
+ openLTOOutputFile(ctx.config.outputFile))
+ WriteBitcodeToFile(m, *os, false);
+ return false;
+ };
+ }
+
+ if (ctx.config.emitASM) {
+ c.CGFileType = CodeGenFileType::AssemblyFile;
+ c.Options.MCOptions.AsmVerbose = true;
+ }
+
if (ctx.config.saveTemps)
checkError(c.addSaveTemps(std::string(ctx.config.outputFile) + ".",
/*UseInputModulePath*/ true));
@@ -215,6 +218,7 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
pruneCache(ctx.config.ltoCache, ctx.config.ltoCachePolicy, files);
std::vector<InputFile *> ret;
+ const char *Ext = ctx.config.emitASM ? ".asm" : ".obj";
for (unsigned i = 0; i != maxTasks; ++i) {
StringRef bitcodeFilePath;
// Get the native object contents either from the cache or from memory. Do
@@ -237,20 +241,21 @@ std::vector<InputFile *> BitcodeCompiler::compile() {
if (bitcodeFilePath == "ld-temp.o") {
ltoObjName =
saver().save(Twine(ctx.config.outputFile) + ".lto" +
- (i == 0 ? Twine("") : Twine('.') + Twine(i)) + ".obj");
+ (i == 0 ? Twine("") : Twine('.') + Twine(i)) + Ext);
} else {
StringRef directory = sys::path::parent_path(bitcodeFilePath);
- StringRef baseName = sys::path::filename(bitcodeFilePath);
+ StringRef baseName = sys::path::stem(bitcodeFilePath);
StringRef outputFileBaseName = sys::path::filename(ctx.config.outputFile);
SmallString<64> path;
sys::path::append(path, directory,
- outputFileBaseName + ".lto." + baseName);
+ outputFileBaseName + ".lto." + baseName + Ext);
sys::path::remove_dots(path, true);
ltoObjName = saver().save(path.str());
}
- if (ctx.config.saveTemps)
+ if (ctx.config.saveTemps || ctx.config.emitASM)
saveBuffer(buf[i].second, ltoObjName);
- ret.push_back(make<ObjFile>(ctx, MemoryBufferRef(objBuf, ltoObjName)));
+ if (!ctx.config.emitASM)
+ ret.push_back(make<ObjFile>(ctx, MemoryBufferRef(objBuf, ltoObjName)));
}
return ret;
diff --git a/lld/Common/Filesystem.cpp b/lld/Common/Filesystem.cpp
index c93353f2d292ce2..1fc19ef02788603 100644
--- a/lld/Common/Filesystem.cpp
+++ b/lld/Common/Filesystem.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "lld/Common/Filesystem.h"
+#include "lld/Common/ErrorHandler.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/FileSystem.h"
@@ -127,3 +128,28 @@ std::error_code lld::tryCreateFile(StringRef path) {
return std::error_code();
return errorToErrorCode(FileOutputBuffer::create(path, 1).takeError());
}
+
+// Creates an empty file to and returns a raw_fd_ostream to write to it.
+std::unique_ptr<raw_fd_ostream> lld::openFile(StringRef file) {
+ std::error_code ec;
+ auto ret =
+ std::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::OF_None);
+ if (ec) {
+ error("cannot open " + file + ": " + ec.message());
+ return nullptr;
+ }
+ return ret;
+}
+
+// The merged bitcode after LTO is large. Try opening a file stream that
+// supports reading, seeking and writing. Such a file allows BitcodeWriter to
+// flush buffered data to reduce memory consumption. If this fails, open a file
+// stream that supports only write.
+std::unique_ptr<raw_fd_ostream> lld::openLTOOutputFile(StringRef file) {
+ std::error_code ec;
+ std::unique_ptr<raw_fd_ostream> fs =
+ std::make_unique<raw_fd_stream>(file, ec);
+ if (!ec)
+ return fs;
+ return openFile(file);
+}
diff --git a/lld/ELF/LTO.cpp b/lld/ELF/LTO.cpp
index eb8f8d7f829a6f0..504c12aac6c5696 100644
--- a/lld/ELF/LTO.cpp
+++ b/lld/ELF/LTO.cpp
@@ -13,6 +13,7 @@
#include "Symbols.h"
#include "lld/Common/Args.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Filesystem.h"
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/ADT/SmallString.h"
@@ -40,32 +41,6 @@ using namespace llvm::ELF;
using namespace lld;
using namespace lld::elf;
-// Creates an empty file to store a list of object files for final
-// linking of distributed ThinLTO.
-static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) {
- std::error_code ec;
- auto ret =
- std::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::OF_None);
- if (ec) {
- error("cannot open " + file + ": " + ec.message());
- return nullptr;
- }
- return ret;
-}
-
-// The merged bitcode after LTO is large. Try opening a file stream that
-// supports reading, seeking and writing. Such a file allows BitcodeWriter to
-// flush buffered data to reduce memory consumption. If this fails, open a file
-// stream that supports only write.
-static std::unique_ptr<raw_fd_ostream> openLTOOutputFile(StringRef file) {
- std::error_code ec;
- std::unique_ptr<raw_fd_ostream> fs =
- std::make_unique<raw_fd_stream>(file, ec);
- if (!ec)
- return fs;
- return openFile(file);
-}
-
static std::string getThinLTOOutputFile(StringRef modulePath) {
return lto::getThinLTOOutputFile(modulePath, config->thinLTOPrefixReplaceOld,
config->thinLTOPrefixReplaceNew);
diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp
index a5b0f4d3d2a746d..7a9a9223a03227f 100644
--- a/lld/MachO/LTO.cpp
+++ b/lld/MachO/LTO.cpp
@@ -15,6 +15,7 @@
#include "lld/Common/Args.h"
#include "lld/Common/CommonLinkerContext.h"
+#include "lld/Common/Filesystem.h"
#include "lld/Common/Strings.h"
#include "lld/Common/TargetOptionsCommandFlags.h"
#include "llvm/Bitcode/BitcodeWriter.h"
@@ -32,19 +33,6 @@ using namespace llvm;
using namespace llvm::MachO;
using namespace llvm::sys;
-// Creates an empty file to store a list of object files for final
-// linking of distributed ThinLTO.
-static std::unique_ptr<raw_fd_ostream> openFile(StringRef file) {
- std::error_code ec;
- auto ret =
- std::make_unique<raw_fd_ostream>(file, ec, sys::fs::OpenFlags::OF_None);
- if (ec) {
- error("cannot open " + file + ": " + ec.message());
- return nullptr;
- }
- return ret;
-}
-
static std::string getThinLTOOutputFile(StringRef modulePath) {
return lto::getThinLTOOutputFile(modulePath, config->thinLTOPrefixReplaceOld,
config->thinLTOPrefixReplaceNew);
diff --git a/lld/include/lld/Common/Filesystem.h b/lld/include/lld/Common/Filesystem.h
index 63a0f554a06c57f..61b32eec2ee7d7d 100644
--- a/lld/include/lld/Common/Filesystem.h
+++ b/lld/include/lld/Common/Filesystem.h
@@ -10,11 +10,15 @@
#define LLD_FILESYSTEM_H
#include "lld/Common/LLVM.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
#include <system_error>
namespace lld {
void unlinkAsync(StringRef path);
std::error_code tryCreateFile(StringRef path);
+std::unique_ptr<llvm::raw_fd_ostream> openFile(StringRef file);
+std::unique_ptr<llvm::raw_fd_ostream> openLTOOutputFile(StringRef file);
} // namespace lld
#endif
diff --git a/lld/test/COFF/lto-emit-asm.ll b/lld/test/COFF/lto-emit-asm.ll
new file mode 100644
index 000000000000000..52199ebe3a569c6
--- /dev/null
+++ b/lld/test/COFF/lto-emit-asm.ll
@@ -0,0 +1,28 @@
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.obj
+
+; RUN: lld-link /opt:emitasm /dll /noentry /include:f1 /include:f2 %t.obj /opt:lldltopartitions=1 /out:%t.1p /lldsavetemps
+; RUN: cat %t.1p.lto.asm | FileCheck %s
+; RUN: llvm-dis %t.1p.0.4.opt.bc -o - | FileCheck --check-prefix=OPT %s
+
+; RUN: lld-link /opt:emitasm /dll /noentry /include:f1 /include:f2 %t.obj /opt:lldltopartitions=2 /out:%t.2p
+; RUN: cat %t.2p.lto.asm %t.2p.lto.1.asm | FileCheck %s
+
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+;; Note: we also check for the presence of comments; /opt:emitasm output should be verbose.
+
+; CHECK-DAG: # -- Begin function f1
+; CHECK-DAG: f1:
+; OPT: define void @f1()
+define void @f1() {
+ ret void
+}
+
+; CHECK-DAG: # -- Begin function f2
+; CHECK-DAG: f2:
+; OPT: define void @f2()
+define void @f2() {
+ ret void
+}
diff --git a/lld/test/COFF/lto-emit-llvm.ll b/lld/test/COFF/lto-emit-llvm.ll
new file mode 100644
index 000000000000000..d7ab61d043a0099
--- /dev/null
+++ b/lld/test/COFF/lto-emit-llvm.ll
@@ -0,0 +1,14 @@
+; REQUIRES: x86
+; RUN: llvm-as -o %T/lto.obj %s
+
+; RUN: lld-link /opt:emitllvm /out:%T/lto.bc /entry:main /subsystem:console %T/lto.obj
+; RUN: llvm-dis %T/lto.bc -o - | FileCheck %s
+
+; CHECK: define void @main()
+
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @main() {
+ ret void
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/67079
More information about the llvm-commits
mailing list