github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/builder/cc1as.cpp (about)

     1  //go:build byollvm
     2  
     3  // Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
     4  // This file needs to be updated each LLVM release.
     5  // There are a few small modifications to make, like:
     6  //   * ExecuteAssembler is made non-static.
     7  //   * The struct AssemblerImplementation is moved to cc1as.h so it can be
     8  //     included elsewhere.
     9  
    10  //===-- cc1as.cpp - Clang Assembler  --------------------------------------===//
    11  //
    12  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
    13  // See https://llvm.org/LICENSE.txt for license information.
    14  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
    15  //
    16  //===----------------------------------------------------------------------===//
    17  //
    18  // This is the entry point to the clang -cc1as functionality, which implements
    19  // the direct interface to the LLVM MC based assembler.
    20  //
    21  //===----------------------------------------------------------------------===//
    22  
    23  #include "clang/Basic/Diagnostic.h"
    24  #include "clang/Basic/DiagnosticOptions.h"
    25  #include "clang/Driver/DriverDiagnostic.h"
    26  #include "clang/Driver/Options.h"
    27  #include "clang/Frontend/FrontendDiagnostic.h"
    28  #include "clang/Frontend/TextDiagnosticPrinter.h"
    29  #include "clang/Frontend/Utils.h"
    30  #include "llvm/ADT/STLExtras.h"
    31  #include "llvm/ADT/StringExtras.h"
    32  #include "llvm/ADT/StringSwitch.h"
    33  #include "llvm/IR/DataLayout.h"
    34  #include "llvm/MC/MCAsmBackend.h"
    35  #include "llvm/MC/MCAsmInfo.h"
    36  #include "llvm/MC/MCCodeEmitter.h"
    37  #include "llvm/MC/MCContext.h"
    38  #include "llvm/MC/MCInstrInfo.h"
    39  #include "llvm/MC/MCObjectFileInfo.h"
    40  #include "llvm/MC/MCObjectWriter.h"
    41  #include "llvm/MC/MCParser/MCAsmParser.h"
    42  #include "llvm/MC/MCParser/MCTargetAsmParser.h"
    43  #include "llvm/MC/MCRegisterInfo.h"
    44  #include "llvm/MC/MCSectionMachO.h"
    45  #include "llvm/MC/MCStreamer.h"
    46  #include "llvm/MC/MCSubtargetInfo.h"
    47  #include "llvm/MC/MCTargetOptions.h"
    48  #include "llvm/MC/TargetRegistry.h"
    49  #include "llvm/Option/Arg.h"
    50  #include "llvm/Option/ArgList.h"
    51  #include "llvm/Option/OptTable.h"
    52  #include "llvm/Support/CommandLine.h"
    53  #include "llvm/Support/ErrorHandling.h"
    54  #include "llvm/Support/FileSystem.h"
    55  #include "llvm/Support/FormattedStream.h"
    56  #include "llvm/Support/MemoryBuffer.h"
    57  #include "llvm/Support/Path.h"
    58  #include "llvm/Support/Process.h"
    59  #include "llvm/Support/Signals.h"
    60  #include "llvm/Support/SourceMgr.h"
    61  #include "llvm/Support/TargetSelect.h"
    62  #include "llvm/Support/Timer.h"
    63  #include "llvm/Support/raw_ostream.h"
    64  #include "llvm/TargetParser/Host.h"
    65  #include "llvm/TargetParser/Triple.h"
    66  #include <memory>
    67  #include <optional>
    68  #include <system_error>
    69  using namespace clang;
    70  using namespace clang::driver;
    71  using namespace clang::driver::options;
    72  using namespace llvm;
    73  using namespace llvm::opt;
    74  
    75  #include "cc1as.h"
    76  
    77  bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
    78                                           ArrayRef<const char *> Argv,
    79                                           DiagnosticsEngine &Diags) {
    80    bool Success = true;
    81  
    82    // Parse the arguments.
    83    const OptTable &OptTbl = getDriverOptTable();
    84  
    85    const unsigned IncludedFlagsBitmask = options::CC1AsOption;
    86    unsigned MissingArgIndex, MissingArgCount;
    87    InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
    88                                         IncludedFlagsBitmask);
    89  
    90    // Check for missing argument error.
    91    if (MissingArgCount) {
    92      Diags.Report(diag::err_drv_missing_argument)
    93          << Args.getArgString(MissingArgIndex) << MissingArgCount;
    94      Success = false;
    95    }
    96  
    97    // Issue errors on unknown arguments.
    98    for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
    99      auto ArgString = A->getAsString(Args);
   100      std::string Nearest;
   101      if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
   102        Diags.Report(diag::err_drv_unknown_argument) << ArgString;
   103      else
   104        Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
   105            << ArgString << Nearest;
   106      Success = false;
   107    }
   108  
   109    // Construct the invocation.
   110  
   111    // Target Options
   112    Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
   113    if (Arg *A = Args.getLastArg(options::OPT_darwin_target_variant_triple))
   114      Opts.DarwinTargetVariantTriple = llvm::Triple(A->getValue());
   115    if (Arg *A = Args.getLastArg(OPT_darwin_target_variant_sdk_version_EQ)) {
   116      VersionTuple Version;
   117      if (Version.tryParse(A->getValue()))
   118        Diags.Report(diag::err_drv_invalid_value)
   119            << A->getAsString(Args) << A->getValue();
   120      else
   121        Opts.DarwinTargetVariantSDKVersion = Version;
   122    }
   123  
   124    Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
   125    Opts.Features = Args.getAllArgValues(OPT_target_feature);
   126  
   127    // Use the default target triple if unspecified.
   128    if (Opts.Triple.empty())
   129      Opts.Triple = llvm::sys::getDefaultTargetTriple();
   130  
   131    // Language Options
   132    Opts.IncludePaths = Args.getAllArgValues(OPT_I);
   133    Opts.NoInitialTextSection = Args.hasArg(OPT_n);
   134    Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
   135    // Any DebugInfoKind implies GenDwarfForAssembly.
   136    Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
   137  
   138    if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
   139      Opts.CompressDebugSections =
   140          llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
   141              .Case("none", llvm::DebugCompressionType::None)
   142              .Case("zlib", llvm::DebugCompressionType::Zlib)
   143              .Case("zstd", llvm::DebugCompressionType::Zstd)
   144              .Default(llvm::DebugCompressionType::None);
   145    }
   146  
   147    Opts.RelaxELFRelocations = !Args.hasArg(OPT_mrelax_relocations_no);
   148    if (auto *DwarfFormatArg = Args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
   149      Opts.Dwarf64 = DwarfFormatArg->getOption().matches(OPT_gdwarf64);
   150    Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
   151    Opts.DwarfDebugFlags =
   152        std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
   153    Opts.DwarfDebugProducer =
   154        std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
   155    if (const Arg *A = Args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
   156                                       options::OPT_fdebug_compilation_dir_EQ))
   157      Opts.DebugCompilationDir = A->getValue();
   158    Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
   159  
   160    for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
   161      auto Split = StringRef(Arg).split('=');
   162      Opts.DebugPrefixMap.emplace_back(Split.first, Split.second);
   163    }
   164  
   165    // Frontend Options
   166    if (Args.hasArg(OPT_INPUT)) {
   167      bool First = true;
   168      for (const Arg *A : Args.filtered(OPT_INPUT)) {
   169        if (First) {
   170          Opts.InputFile = A->getValue();
   171          First = false;
   172        } else {
   173          Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
   174          Success = false;
   175        }
   176      }
   177    }
   178    Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
   179    Opts.OutputPath = std::string(Args.getLastArgValue(OPT_o));
   180    Opts.SplitDwarfOutput =
   181        std::string(Args.getLastArgValue(OPT_split_dwarf_output));
   182    if (Arg *A = Args.getLastArg(OPT_filetype)) {
   183      StringRef Name = A->getValue();
   184      unsigned OutputType = StringSwitch<unsigned>(Name)
   185        .Case("asm", FT_Asm)
   186        .Case("null", FT_Null)
   187        .Case("obj", FT_Obj)
   188        .Default(~0U);
   189      if (OutputType == ~0U) {
   190        Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
   191        Success = false;
   192      } else
   193        Opts.OutputType = FileType(OutputType);
   194    }
   195    Opts.ShowHelp = Args.hasArg(OPT_help);
   196    Opts.ShowVersion = Args.hasArg(OPT_version);
   197  
   198    // Transliterate Options
   199    Opts.OutputAsmVariant =
   200        getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
   201    Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
   202    Opts.ShowInst = Args.hasArg(OPT_show_inst);
   203  
   204    // Assemble Options
   205    Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
   206    Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
   207    Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
   208    Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
   209    Opts.NoTypeCheck = Args.hasArg(OPT_mno_type_check);
   210    Opts.RelocationModel =
   211        std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic"));
   212    Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
   213    Opts.IncrementalLinkerCompatible =
   214        Args.hasArg(OPT_mincremental_linker_compatible);
   215    Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
   216  
   217    // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag.
   218    // EmbedBitcode behaves the same for all embed options for assembly files.
   219    if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) {
   220      Opts.EmbedBitcode = llvm::StringSwitch<unsigned>(A->getValue())
   221                              .Case("all", 1)
   222                              .Case("bitcode", 1)
   223                              .Case("marker", 1)
   224                              .Default(0);
   225    }
   226  
   227    if (auto *A = Args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
   228      Opts.EmitDwarfUnwind =
   229          llvm::StringSwitch<EmitDwarfUnwindType>(A->getValue())
   230              .Case("always", EmitDwarfUnwindType::Always)
   231              .Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
   232              .Case("default", EmitDwarfUnwindType::Default);
   233    }
   234  
   235    Opts.EmitCompactUnwindNonCanonical =
   236        Args.hasArg(OPT_femit_compact_unwind_non_canonical);
   237  
   238    Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
   239  
   240    return Success;
   241  }
   242  
   243  static std::unique_ptr<raw_fd_ostream>
   244  getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
   245    // Make sure that the Out file gets unlinked from the disk if we get a
   246    // SIGINT.
   247    if (Path != "-")
   248      sys::RemoveFileOnSignal(Path);
   249  
   250    std::error_code EC;
   251    auto Out = std::make_unique<raw_fd_ostream>(
   252        Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_TextWithCRLF));
   253    if (EC) {
   254      Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
   255      return nullptr;
   256    }
   257  
   258    return Out;
   259  }
   260  
   261  static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
   262                                   DiagnosticsEngine &Diags) {
   263    // Get the target specific parser.
   264    std::string Error;
   265    const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
   266    if (!TheTarget)
   267      return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
   268  
   269    ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
   270        MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
   271  
   272    if (std::error_code EC = Buffer.getError()) {
   273      return Diags.Report(diag::err_fe_error_reading)
   274             << Opts.InputFile << EC.message();
   275    }
   276  
   277    SourceMgr SrcMgr;
   278  
   279    // Tell SrcMgr about this buffer, which is what the parser will pick up.
   280    unsigned BufferIndex = SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
   281  
   282    // Record the location of the include directories so that the lexer can find
   283    // it later.
   284    SrcMgr.setIncludeDirs(Opts.IncludePaths);
   285  
   286    std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
   287    assert(MRI && "Unable to create target register info!");
   288  
   289    MCTargetOptions MCOptions;
   290    MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
   291    MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
   292    MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
   293  
   294    std::unique_ptr<MCAsmInfo> MAI(
   295        TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
   296    assert(MAI && "Unable to create target asm info!");
   297  
   298    // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
   299    // may be created with a combination of default and explicit settings.
   300    MAI->setCompressDebugSections(Opts.CompressDebugSections);
   301  
   302    MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
   303  
   304    bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
   305    if (Opts.OutputPath.empty())
   306      Opts.OutputPath = "-";
   307    std::unique_ptr<raw_fd_ostream> FDOS =
   308        getOutputStream(Opts.OutputPath, Diags, IsBinary);
   309    if (!FDOS)
   310      return true;
   311    std::unique_ptr<raw_fd_ostream> DwoOS;
   312    if (!Opts.SplitDwarfOutput.empty())
   313      DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
   314  
   315    // Build up the feature string from the target feature list.
   316    std::string FS = llvm::join(Opts.Features, ",");
   317  
   318    std::unique_ptr<MCSubtargetInfo> STI(
   319        TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
   320    assert(STI && "Unable to create subtarget info!");
   321  
   322    MCContext Ctx(Triple(Opts.Triple), MAI.get(), MRI.get(), STI.get(), &SrcMgr,
   323                  &MCOptions);
   324  
   325    bool PIC = false;
   326    if (Opts.RelocationModel == "static") {
   327      PIC = false;
   328    } else if (Opts.RelocationModel == "pic") {
   329      PIC = true;
   330    } else {
   331      assert(Opts.RelocationModel == "dynamic-no-pic" &&
   332             "Invalid PIC model!");
   333      PIC = false;
   334    }
   335  
   336    // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
   337    // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
   338    std::unique_ptr<MCObjectFileInfo> MOFI(
   339        TheTarget->createMCObjectFileInfo(Ctx, PIC));
   340    if (Opts.DarwinTargetVariantTriple)
   341      MOFI->setDarwinTargetVariantTriple(*Opts.DarwinTargetVariantTriple);
   342    if (!Opts.DarwinTargetVariantSDKVersion.empty())
   343      MOFI->setDarwinTargetVariantSDKVersion(Opts.DarwinTargetVariantSDKVersion);
   344    Ctx.setObjectFileInfo(MOFI.get());
   345  
   346    if (Opts.SaveTemporaryLabels)
   347      Ctx.setAllowTemporaryLabels(false);
   348    if (Opts.GenDwarfForAssembly)
   349      Ctx.setGenDwarfForAssembly(true);
   350    if (!Opts.DwarfDebugFlags.empty())
   351      Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
   352    if (!Opts.DwarfDebugProducer.empty())
   353      Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
   354    if (!Opts.DebugCompilationDir.empty())
   355      Ctx.setCompilationDir(Opts.DebugCompilationDir);
   356    else {
   357      // If no compilation dir is set, try to use the current directory.
   358      SmallString<128> CWD;
   359      if (!sys::fs::current_path(CWD))
   360        Ctx.setCompilationDir(CWD);
   361    }
   362    if (!Opts.DebugPrefixMap.empty())
   363      for (const auto &KV : Opts.DebugPrefixMap)
   364        Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
   365    if (!Opts.MainFileName.empty())
   366      Ctx.setMainFileName(StringRef(Opts.MainFileName));
   367    Ctx.setDwarfFormat(Opts.Dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
   368    Ctx.setDwarfVersion(Opts.DwarfVersion);
   369    if (Opts.GenDwarfForAssembly)
   370      Ctx.setGenDwarfRootFile(Opts.InputFile,
   371                              SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
   372  
   373    std::unique_ptr<MCStreamer> Str;
   374  
   375    std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
   376    assert(MCII && "Unable to create instruction info!");
   377  
   378    raw_pwrite_stream *Out = FDOS.get();
   379    std::unique_ptr<buffer_ostream> BOS;
   380  
   381    MCOptions.MCNoWarn = Opts.NoWarn;
   382    MCOptions.MCFatalWarnings = Opts.FatalWarnings;
   383    MCOptions.MCNoTypeCheck = Opts.NoTypeCheck;
   384    MCOptions.ABIName = Opts.TargetABI;
   385  
   386    // FIXME: There is a bit of code duplication with addPassesToEmitFile.
   387    if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
   388      MCInstPrinter *IP = TheTarget->createMCInstPrinter(
   389          llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
   390  
   391      std::unique_ptr<MCCodeEmitter> CE;
   392      if (Opts.ShowEncoding)
   393        CE.reset(TheTarget->createMCCodeEmitter(*MCII, Ctx));
   394      std::unique_ptr<MCAsmBackend> MAB(
   395          TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
   396  
   397      auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
   398      Str.reset(TheTarget->createAsmStreamer(
   399          Ctx, std::move(FOut), /*asmverbose*/ true,
   400          /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
   401          Opts.ShowInst));
   402    } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
   403      Str.reset(createNullStreamer(Ctx));
   404    } else {
   405      assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
   406             "Invalid file type!");
   407      if (!FDOS->supportsSeeking()) {
   408        BOS = std::make_unique<buffer_ostream>(*FDOS);
   409        Out = BOS.get();
   410      }
   411  
   412      std::unique_ptr<MCCodeEmitter> CE(
   413          TheTarget->createMCCodeEmitter(*MCII, Ctx));
   414      std::unique_ptr<MCAsmBackend> MAB(
   415          TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
   416      assert(MAB && "Unable to create asm backend!");
   417  
   418      std::unique_ptr<MCObjectWriter> OW =
   419          DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
   420                : MAB->createObjectWriter(*Out);
   421  
   422      Triple T(Opts.Triple);
   423      Str.reset(TheTarget->createMCObjectStreamer(
   424          T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
   425          Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
   426          /*DWARFMustBeAtTheEnd*/ true));
   427      Str.get()->initSections(Opts.NoExecStack, *STI);
   428    }
   429  
   430    // When -fembed-bitcode is passed to clang_as, a 1-byte marker
   431    // is emitted in __LLVM,__asm section if the object file is MachO format.
   432    if (Opts.EmbedBitcode && Ctx.getObjectFileType() == MCContext::IsMachO) {
   433      MCSection *AsmLabel = Ctx.getMachOSection(
   434          "__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
   435      Str.get()->switchSection(AsmLabel);
   436      Str.get()->emitZeros(1);
   437    }
   438  
   439    // Assembly to object compilation should leverage assembly info.
   440    Str->setUseAssemblerInfoForParsing(true);
   441  
   442    bool Failed = false;
   443  
   444    std::unique_ptr<MCAsmParser> Parser(
   445        createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
   446  
   447    // FIXME: init MCTargetOptions from sanitizer flags here.
   448    std::unique_ptr<MCTargetAsmParser> TAP(
   449        TheTarget->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
   450    if (!TAP)
   451      Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
   452  
   453    // Set values for symbols, if any.
   454    for (auto &S : Opts.SymbolDefs) {
   455      auto Pair = StringRef(S).split('=');
   456      auto Sym = Pair.first;
   457      auto Val = Pair.second;
   458      int64_t Value;
   459      // We have already error checked this in the driver.
   460      Val.getAsInteger(0, Value);
   461      Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
   462    }
   463  
   464    if (!Failed) {
   465      Parser->setTargetParser(*TAP.get());
   466      Failed = Parser->Run(Opts.NoInitialTextSection);
   467    }
   468  
   469    return Failed;
   470  }
   471  
   472  bool ExecuteAssembler(AssemblerInvocation &Opts,
   473                               DiagnosticsEngine &Diags) {
   474    bool Failed = ExecuteAssemblerImpl(Opts, Diags);
   475  
   476    // Delete output file if there were errors.
   477    if (Failed) {
   478      if (Opts.OutputPath != "-")
   479        sys::fs::remove(Opts.OutputPath);
   480      if (!Opts.SplitDwarfOutput.empty() && Opts.SplitDwarfOutput != "-")
   481        sys::fs::remove(Opts.SplitDwarfOutput);
   482    }
   483  
   484    return Failed;
   485  }
   486  
   487  static void LLVMErrorHandler(void *UserData, const char *Message,
   488                               bool GenCrashDiag) {
   489    DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
   490  
   491    Diags.Report(diag::err_fe_error_backend) << Message;
   492  
   493    // We cannot recover from llvm errors.
   494    sys::Process::Exit(1);
   495  }
   496  
   497  int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   498    // Initialize targets and assembly printers/parsers.
   499    InitializeAllTargetInfos();
   500    InitializeAllTargetMCs();
   501    InitializeAllAsmParsers();
   502  
   503    // Construct our diagnostic client.
   504    IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
   505    TextDiagnosticPrinter *DiagClient
   506      = new TextDiagnosticPrinter(errs(), &*DiagOpts);
   507    DiagClient->setPrefix("clang -cc1as");
   508    IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
   509    DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
   510  
   511    // Set an error handler, so that any LLVM backend diagnostics go through our
   512    // error handler.
   513    ScopedFatalErrorHandler FatalErrorHandler
   514      (LLVMErrorHandler, static_cast<void*>(&Diags));
   515  
   516    // Parse the arguments.
   517    AssemblerInvocation Asm;
   518    if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags))
   519      return 1;
   520  
   521    if (Asm.ShowHelp) {
   522      getDriverOptTable().printHelp(
   523          llvm::outs(), "clang -cc1as [options] file...",
   524          "Clang Integrated Assembler",
   525          /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,
   526          /*ShowAllAliases=*/false);
   527      return 0;
   528    }
   529  
   530    // Honor -version.
   531    //
   532    // FIXME: Use a better -version message?
   533    if (Asm.ShowVersion) {
   534      llvm::cl::PrintVersionMessage();
   535      return 0;
   536    }
   537  
   538    // Honor -mllvm.
   539    //
   540    // FIXME: Remove this, one day.
   541    if (!Asm.LLVMArgs.empty()) {
   542      unsigned NumArgs = Asm.LLVMArgs.size();
   543      auto Args = std::make_unique<const char*[]>(NumArgs + 2);
   544      Args[0] = "clang (LLVM option parsing)";
   545      for (unsigned i = 0; i != NumArgs; ++i)
   546        Args[i + 1] = Asm.LLVMArgs[i].c_str();
   547      Args[NumArgs + 1] = nullptr;
   548      llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
   549    }
   550  
   551    // Execute the invocation, unless there were parsing errors.
   552    bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags);
   553  
   554    // If any timers were active but haven't been destroyed yet, print their
   555    // results now.
   556    TimerGroup::printAll(errs());
   557    TimerGroup::clearAll();
   558  
   559    return !!Failed;
   560  }