10b57cec5SDimitry Andric //===--- llvm-as.cpp - The low-level LLVM assembler -----------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This utility may be invoked in the following manner: 100b57cec5SDimitry Andric // llvm-as --help - Output information about command line switches 110b57cec5SDimitry Andric // llvm-as [options] - Read LLVM asm from stdin, write bitcode to stdout 120b57cec5SDimitry Andric // llvm-as [options] x.ll - Read LLVM asm from the x.ll file, write bitcode 130b57cec5SDimitry Andric // to the x.bc file. 140b57cec5SDimitry Andric // 150b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include "llvm/AsmParser/Parser.h" 180b57cec5SDimitry Andric #include "llvm/Bitcode/BitcodeWriter.h" 190b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h" 200b57cec5SDimitry Andric #include "llvm/IR/Module.h" 210b57cec5SDimitry Andric #include "llvm/IR/ModuleSummaryIndex.h" 220b57cec5SDimitry Andric #include "llvm/IR/Verifier.h" 230b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 240b57cec5SDimitry Andric #include "llvm/Support/FileSystem.h" 250b57cec5SDimitry Andric #include "llvm/Support/InitLLVM.h" 260b57cec5SDimitry Andric #include "llvm/Support/SourceMgr.h" 270b57cec5SDimitry Andric #include "llvm/Support/SystemUtils.h" 280b57cec5SDimitry Andric #include "llvm/Support/ToolOutputFile.h" 290b57cec5SDimitry Andric #include <memory> 30bdd1243dSDimitry Andric #include <optional> 310b57cec5SDimitry Andric using namespace llvm; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric cl::OptionCategory AsCat("llvm-as Options"); 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric static cl::opt<std::string> InputFilename(cl::Positional, 360b57cec5SDimitry Andric cl::desc("<input .llvm file>"), 370b57cec5SDimitry Andric cl::init("-")); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric static cl::opt<std::string> OutputFilename("o", 400b57cec5SDimitry Andric cl::desc("Override output filename"), 410b57cec5SDimitry Andric cl::value_desc("filename"), 420b57cec5SDimitry Andric cl::cat(AsCat)); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric static cl::opt<bool> Force("f", cl::desc("Enable binary output on terminals"), 450b57cec5SDimitry Andric cl::cat(AsCat)); 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric static cl::opt<bool> DisableOutput("disable-output", cl::desc("Disable output"), 480b57cec5SDimitry Andric cl::init(false), cl::cat(AsCat)); 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric static cl::opt<bool> EmitModuleHash("module-hash", cl::desc("Emit module hash"), 510b57cec5SDimitry Andric cl::init(false), cl::cat(AsCat)); 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric static cl::opt<bool> DumpAsm("d", cl::desc("Print assembly as parsed"), 540b57cec5SDimitry Andric cl::Hidden, cl::cat(AsCat)); 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric static cl::opt<bool> 570b57cec5SDimitry Andric DisableVerify("disable-verify", cl::Hidden, 580b57cec5SDimitry Andric cl::desc("Do not run verifier on input LLVM (dangerous!)"), 590b57cec5SDimitry Andric cl::cat(AsCat)); 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric static cl::opt<bool> PreserveBitcodeUseListOrder( 620b57cec5SDimitry Andric "preserve-bc-uselistorder", 630b57cec5SDimitry Andric cl::desc("Preserve use-list order when writing LLVM bitcode."), 640b57cec5SDimitry Andric cl::init(true), cl::Hidden, cl::cat(AsCat)); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric static cl::opt<std::string> ClDataLayout("data-layout", 670b57cec5SDimitry Andric cl::desc("data layout string to use"), 680b57cec5SDimitry Andric cl::value_desc("layout-string"), 690b57cec5SDimitry Andric cl::init(""), cl::cat(AsCat)); 70*0fca6ea1SDimitry Andric extern cl::opt<bool> UseNewDbgInfoFormat; 71*0fca6ea1SDimitry Andric extern bool WriteNewDbgInfoFormatToBitcode; 720b57cec5SDimitry Andric 730b57cec5SDimitry Andric static void WriteOutputFile(const Module *M, const ModuleSummaryIndex *Index) { 740b57cec5SDimitry Andric // Infer the output filename if needed. 750b57cec5SDimitry Andric if (OutputFilename.empty()) { 760b57cec5SDimitry Andric if (InputFilename == "-") { 770b57cec5SDimitry Andric OutputFilename = "-"; 780b57cec5SDimitry Andric } else { 790b57cec5SDimitry Andric StringRef IFN = InputFilename; 805f757f3fSDimitry Andric OutputFilename = (IFN.ends_with(".ll") ? IFN.drop_back(3) : IFN).str(); 810b57cec5SDimitry Andric OutputFilename += ".bc"; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric std::error_code EC; 860b57cec5SDimitry Andric std::unique_ptr<ToolOutputFile> Out( 878bcb0991SDimitry Andric new ToolOutputFile(OutputFilename, EC, sys::fs::OF_None)); 880b57cec5SDimitry Andric if (EC) { 890b57cec5SDimitry Andric errs() << EC.message() << '\n'; 900b57cec5SDimitry Andric exit(1); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric 935ffd83dbSDimitry Andric if (Force || !CheckBitcodeOutputToConsole(Out->os())) { 940b57cec5SDimitry Andric const ModuleSummaryIndex *IndexToWrite = nullptr; 955ffd83dbSDimitry Andric // Don't attempt to write a summary index unless it contains any entries or 965ffd83dbSDimitry Andric // has non-zero flags. The latter is used to assemble dummy index files for 975ffd83dbSDimitry Andric // skipping modules by distributed ThinLTO backends. Otherwise we get an empty 985ffd83dbSDimitry Andric // summary section. 995ffd83dbSDimitry Andric if (Index && (Index->begin() != Index->end() || Index->getFlags())) 1000b57cec5SDimitry Andric IndexToWrite = Index; 1010b57cec5SDimitry Andric if (!IndexToWrite || (M && (!M->empty() || !M->global_empty()))) 1020b57cec5SDimitry Andric // If we have a non-empty Module, then we write the Module plus 1030b57cec5SDimitry Andric // any non-null Index along with it as a per-module Index. 1040b57cec5SDimitry Andric // If both are empty, this will give an empty module block, which is 1050b57cec5SDimitry Andric // the expected behavior. 1060b57cec5SDimitry Andric WriteBitcodeToFile(*M, Out->os(), PreserveBitcodeUseListOrder, 1070b57cec5SDimitry Andric IndexToWrite, EmitModuleHash); 1080b57cec5SDimitry Andric else 1090b57cec5SDimitry Andric // Otherwise, with an empty Module but non-empty Index, we write a 1100b57cec5SDimitry Andric // combined index. 1111fd87a68SDimitry Andric writeIndexToFile(*IndexToWrite, Out->os()); 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric // Declare success. 1150b57cec5SDimitry Andric Out->keep(); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric int main(int argc, char **argv) { 1190b57cec5SDimitry Andric InitLLVM X(argc, argv); 1200b57cec5SDimitry Andric cl::HideUnrelatedOptions(AsCat); 1210b57cec5SDimitry Andric cl::ParseCommandLineOptions(argc, argv, "llvm .ll -> .bc assembler\n"); 122fe6060f1SDimitry Andric LLVMContext Context; 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric // Parse the file now... 1250b57cec5SDimitry Andric SMDiagnostic Err; 126bdd1243dSDimitry Andric auto SetDataLayout = [](StringRef, StringRef) -> std::optional<std::string> { 1275ffd83dbSDimitry Andric if (ClDataLayout.empty()) 128bdd1243dSDimitry Andric return std::nullopt; 1295ffd83dbSDimitry Andric return ClDataLayout; 1305ffd83dbSDimitry Andric }; 1315ffd83dbSDimitry Andric ParsedModuleAndIndex ModuleAndIndex; 1325ffd83dbSDimitry Andric if (DisableVerify) { 1335ffd83dbSDimitry Andric ModuleAndIndex = parseAssemblyFileWithIndexNoUpgradeDebugInfo( 1345ffd83dbSDimitry Andric InputFilename, Err, Context, nullptr, SetDataLayout); 1355ffd83dbSDimitry Andric } else { 1365ffd83dbSDimitry Andric ModuleAndIndex = parseAssemblyFileWithIndex(InputFilename, Err, Context, 1375ffd83dbSDimitry Andric nullptr, SetDataLayout); 1385ffd83dbSDimitry Andric } 1390b57cec5SDimitry Andric std::unique_ptr<Module> M = std::move(ModuleAndIndex.Mod); 140*0fca6ea1SDimitry Andric if (!M) { 1410b57cec5SDimitry Andric Err.print(argv[0], errs()); 1420b57cec5SDimitry Andric return 1; 1430b57cec5SDimitry Andric } 144*0fca6ea1SDimitry Andric 145*0fca6ea1SDimitry Andric // Convert to new debug format if requested. 146*0fca6ea1SDimitry Andric M->setIsNewDbgInfoFormat(UseNewDbgInfoFormat && 147*0fca6ea1SDimitry Andric WriteNewDbgInfoFormatToBitcode); 148*0fca6ea1SDimitry Andric if (M->IsNewDbgInfoFormat) 149*0fca6ea1SDimitry Andric M->removeDebugIntrinsicDeclarations(); 150*0fca6ea1SDimitry Andric 1510b57cec5SDimitry Andric std::unique_ptr<ModuleSummaryIndex> Index = std::move(ModuleAndIndex.Index); 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric if (!DisableVerify) { 1540b57cec5SDimitry Andric std::string ErrorStr; 1550b57cec5SDimitry Andric raw_string_ostream OS(ErrorStr); 156*0fca6ea1SDimitry Andric if (verifyModule(*M, &OS)) { 1570b57cec5SDimitry Andric errs() << argv[0] 1580b57cec5SDimitry Andric << ": assembly parsed, but does not verify as correct!\n"; 1590b57cec5SDimitry Andric errs() << OS.str(); 1600b57cec5SDimitry Andric return 1; 1610b57cec5SDimitry Andric } 1620b57cec5SDimitry Andric // TODO: Implement and call summary index verifier. 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric if (DumpAsm) { 166*0fca6ea1SDimitry Andric errs() << "Here's the assembly:\n" << *M; 1670b57cec5SDimitry Andric if (Index.get() && Index->begin() != Index->end()) 1680b57cec5SDimitry Andric Index->print(errs()); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric if (!DisableOutput) 1720b57cec5SDimitry Andric WriteOutputFile(M.get(), Index.get()); 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric return 0; 1750b57cec5SDimitry Andric } 176