diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index e66ab3a32c567..562af7e0d23c1 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -48,7 +48,7 @@ enum class ExportSource { ModuleDefinition, }; -enum class EmitKind { Obj, LLVM }; +enum class EmitKind { Obj, LLVM, ASM }; // Represents an /export option. struct Export { diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 75ac6d965eba6..554db5969ea13 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -1859,6 +1859,8 @@ void LinkerDriver::linkerMain(ArrayRef argsArr) { config->emit = EmitKind::Obj; else if (s == "llvm") config->emit = EmitKind::LLVM; + else if (s == "asm") + config->emit = EmitKind::ASM; else error("/lldemit: unknown option: " + s); } diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index 6e835d055479c..09d722849c382 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -94,6 +94,9 @@ lto::Config BitcodeCompiler::createConfig() { WriteBitcodeToFile(m, *os, false); return false; }; + } else if (ctx.config.emit == EmitKind::ASM) { + c.CGFileType = CodeGenFileType::AssemblyFile; + c.Options.MCOptions.AsmVerbose = true; } if (ctx.config.saveTemps) @@ -213,6 +216,8 @@ std::vector BitcodeCompiler::compile() { pruneCache(ctx.config.ltoCache, ctx.config.ltoCachePolicy, files); std::vector ret; + bool emitASM = ctx.config.emit == EmitKind::ASM; + const char *Ext = emitASM ? ".s" : ".obj"; for (unsigned i = 0; i != maxTasks; ++i) { StringRef bitcodeFilePath; // Get the native object contents either from the cache or from memory. Do @@ -235,20 +240,21 @@ std::vector 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 || emitASM) saveBuffer(buf[i].second, ltoObjName); - ret.push_back(make(ctx, MemoryBufferRef(objBuf, ltoObjName))); + if (!emitASM) + ret.push_back(make(ctx, MemoryBufferRef(objBuf, ltoObjName))); } return ret; diff --git a/lld/test/COFF/lto-emit-asm.ll b/lld/test/COFF/lto-emit-asm.ll new file mode 100644 index 0000000000000..bb32a7d8a7270 --- /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 /lldemit:asm /dll /noentry /include:f1 /include:f2 %t.obj /opt:lldltopartitions=1 /out:%t.1p /lldsavetemps +; RUN: cat %t.1p.lto.s | FileCheck %s +; RUN: llvm-dis %t.1p.0.4.opt.bc -o - | FileCheck --check-prefix=OPT %s + +; RUN: lld-link /lldemit:asm /dll /noentry /include:f1 /include:f2 %t.obj /opt:lldltopartitions=2 /out:%t.2p +; RUN: cat %t.2p.lto.s %t.2p.lto.1.s | 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; /lldemit:asm 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/pdb-thinlto.ll b/lld/test/COFF/pdb-thinlto.ll index 6ea0f28e1ef1e..10559e2191650 100644 --- a/lld/test/COFF/pdb-thinlto.ll +++ b/lld/test/COFF/pdb-thinlto.ll @@ -29,8 +29,8 @@ declare void @foo() ; CHECK: Modules ; CHECK: ============================================================ -; CHECK: Mod 0000 | `{{.*}}main.exe.lto.main.bc`: -; CHECK: Obj: `{{.*}}main.exe.lto.main.bc`: -; CHECK: Mod 0001 | `{{.*}}main.exe.lto.foo.bc`: -; CHECK: Obj: `{{.*}}main.exe.lto.foo.bc`: +; CHECK: Mod 0000 | `{{.*}}main.exe.lto.main.obj`: +; CHECK: Obj: `{{.*}}main.exe.lto.main.obj`: +; CHECK: Mod 0001 | `{{.*}}main.exe.lto.foo.obj`: +; CHECK: Obj: `{{.*}}main.exe.lto.foo.obj`: ; CHECK: Mod 0002 | `* Linker *`: