[llvm-branch-commits] [clang] 2325157 - [Clang] Move assembler into a separate file

Ayke van Laethem via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Sat Jan 23 05:42:28 PST 2021


Author: Ayke van Laethem
Date: 2021-01-23T14:34:23+01:00
New Revision: 2325157c0568ffd16f3318ad54f947e4e2109ef6

URL: https://github.com/llvm/llvm-project/commit/2325157c0568ffd16f3318ad54f947e4e2109ef6
DIFF: https://github.com/llvm/llvm-project/commit/2325157c0568ffd16f3318ad54f947e4e2109ef6.diff

LOG: [Clang] Move assembler into a separate file

This change adds an AssemblerInvocation class, similar to the
CompilerInvocation class. It can be used to invoke cc1as directly.

The project I'm working on wants to compile Clang and use it as a static
library. For that to work, there must be a way to invoke the assembler
programmatically, using the same arguments as you would otherwise pass
to cc1as.

Differential Revision: https://reviews.llvm.org/D63852

Added: 
    clang/include/clang/Frontend/AssemblerInvocation.h
    clang/lib/Frontend/AssemblerInvocation.cpp

Modified: 
    clang/lib/Frontend/CMakeLists.txt
    clang/tools/driver/cc1as_main.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Frontend/AssemblerInvocation.h b/clang/include/clang/Frontend/AssemblerInvocation.h
new file mode 100644
index 000000000000..8644f6c14228
--- /dev/null
+++ b/clang/include/clang/Frontend/AssemblerInvocation.h
@@ -0,0 +1,126 @@
+//===- AssemblerInvocation.h - Assembler Invocation Helper Data -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_ASSEMBLERINVOCATION_H
+#define LLVM_CLANG_FRONTEND_ASSEMBLERINVOCATION_H
+
+#include "llvm/MC/MCTargetOptions.h"
+
+namespace clang {
+
+/// Helper class for representing a single invocation of the assembler.
+struct AssemblerInvocation {
+  /// @name Target Options
+  /// @{
+
+  /// The name of the target triple to assemble for.
+  std::string Triple;
+
+  /// If given, the name of the target CPU to determine which instructions
+  /// are legal.
+  std::string CPU;
+
+  /// The list of target specific features to enable or disable -- this should
+  /// be a list of strings starting with '+' or '-'.
+  std::vector<std::string> Features;
+
+  /// The list of symbol definitions.
+  std::vector<std::string> SymbolDefs;
+
+  /// @}
+  /// @name Language Options
+  /// @{
+
+  std::vector<std::string> IncludePaths;
+  unsigned NoInitialTextSection : 1;
+  unsigned SaveTemporaryLabels : 1;
+  unsigned GenDwarfForAssembly : 1;
+  unsigned RelaxELFRelocations : 1;
+  unsigned DwarfVersion;
+  std::string DwarfDebugFlags;
+  std::string DwarfDebugProducer;
+  std::string DebugCompilationDir;
+  std::map<const std::string, const std::string> DebugPrefixMap;
+  llvm::DebugCompressionType CompressDebugSections =
+      llvm::DebugCompressionType::None;
+  std::string MainFileName;
+  std::string SplitDwarfOutput;
+
+  /// @}
+  /// @name Frontend Options
+  /// @{
+
+  std::string InputFile;
+  std::vector<std::string> LLVMArgs;
+  std::string OutputPath;
+  enum FileType {
+    FT_Asm,  ///< Assembly (.s) output, transliterate mode.
+    FT_Null, ///< No output, for timing purposes.
+    FT_Obj   ///< Object file output.
+  };
+  FileType OutputType;
+  unsigned ShowHelp : 1;
+  unsigned ShowVersion : 1;
+
+  /// @}
+  /// @name Transliterate Options
+  /// @{
+
+  unsigned OutputAsmVariant;
+  unsigned ShowEncoding : 1;
+  unsigned ShowInst : 1;
+
+  /// @}
+  /// @name Assembler Options
+  /// @{
+
+  unsigned RelaxAll : 1;
+  unsigned NoExecStack : 1;
+  unsigned FatalWarnings : 1;
+  unsigned NoWarn : 1;
+  unsigned IncrementalLinkerCompatible : 1;
+  unsigned EmbedBitcode : 1;
+
+  /// The name of the relocation model to use.
+  std::string RelocationModel;
+
+  /// The ABI targeted by the backend. Specified using -target-abi. Empty
+  /// otherwise.
+  std::string TargetABI;
+
+  /// @}
+
+public:
+  AssemblerInvocation() {
+    Triple = "";
+    NoInitialTextSection = 0;
+    InputFile = "-";
+    OutputPath = "-";
+    OutputType = FT_Asm;
+    OutputAsmVariant = 0;
+    ShowInst = 0;
+    ShowEncoding = 0;
+    RelaxAll = 0;
+    NoExecStack = 0;
+    FatalWarnings = 0;
+    NoWarn = 0;
+    IncrementalLinkerCompatible = 0;
+    DwarfVersion = 0;
+    EmbedBitcode = 0;
+  }
+
+  static bool CreateFromArgs(AssemblerInvocation &Res,
+                             ArrayRef<const char *> Argv,
+                             DiagnosticsEngine &Diags);
+};
+
+bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags);
+
+} // namespace clang
+
+#endif // LLVM_CLANG_FRONTEND_ASSEMBLERINVOCATION_H

diff  --git a/clang/lib/Frontend/AssemblerInvocation.cpp b/clang/lib/Frontend/AssemblerInvocation.cpp
new file mode 100644
index 000000000000..7f6944c60379
--- /dev/null
+++ b/clang/lib/Frontend/AssemblerInvocation.cpp
@@ -0,0 +1,432 @@
+//===- AssemblerInvocation.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/AssemblerInvocation.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Frontend/Utils.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptTable.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <system_error>
+using namespace clang;
+using namespace clang::driver;
+using namespace clang::driver::options;
+using namespace llvm;
+using namespace llvm::opt;
+
+namespace clang {
+
+bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
+                                         ArrayRef<const char *> Argv,
+                                         DiagnosticsEngine &Diags) {
+  bool Success = true;
+
+  // Parse the arguments.
+  const OptTable &OptTbl = getDriverOptTable();
+
+  const unsigned IncludedFlagsBitmask = options::CC1AsOption;
+  unsigned MissingArgIndex, MissingArgCount;
+  InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
+                                       IncludedFlagsBitmask);
+
+  // Check for missing argument error.
+  if (MissingArgCount) {
+    Diags.Report(diag::err_drv_missing_argument)
+        << Args.getArgString(MissingArgIndex) << MissingArgCount;
+    Success = false;
+  }
+
+  // Issue errors on unknown arguments.
+  for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
+    auto ArgString = A->getAsString(Args);
+    std::string Nearest;
+    if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
+      Diags.Report(diag::err_drv_unknown_argument) << ArgString;
+    else
+      Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
+          << ArgString << Nearest;
+    Success = false;
+  }
+
+  // Construct the invocation.
+
+  // Target Options
+  Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
+  Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
+  Opts.Features = Args.getAllArgValues(OPT_target_feature);
+
+  // Use the default target triple if unspecified.
+  if (Opts.Triple.empty())
+    Opts.Triple = llvm::sys::getDefaultTargetTriple();
+
+  // Language Options
+  Opts.IncludePaths = Args.getAllArgValues(OPT_I);
+  Opts.NoInitialTextSection = Args.hasArg(OPT_n);
+  Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
+  // Any DebugInfoKind implies GenDwarfForAssembly.
+  Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
+
+  if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
+    Opts.CompressDebugSections =
+        llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
+            .Case("none", llvm::DebugCompressionType::None)
+            .Case("zlib", llvm::DebugCompressionType::Z)
+            .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
+            .Default(llvm::DebugCompressionType::None);
+  }
+
+  Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
+  Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
+  Opts.DwarfDebugFlags =
+      std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
+  Opts.DwarfDebugProducer =
+      std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
+  Opts.DebugCompilationDir =
+      std::string(Args.getLastArgValue(OPT_fdebug_compilation_dir));
+  Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
+
+  for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
+    auto Split = StringRef(Arg).split('=');
+    Opts.DebugPrefixMap.insert(
+        {std::string(Split.first), std::string(Split.second)});
+  }
+
+  // Frontend Options
+  if (Args.hasArg(OPT_INPUT)) {
+    bool First = true;
+    for (const Arg *A : Args.filtered(OPT_INPUT)) {
+      if (First) {
+        Opts.InputFile = A->getValue();
+        First = false;
+      } else {
+        Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
+        Success = false;
+      }
+    }
+  }
+  Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
+  Opts.OutputPath = std::string(Args.getLastArgValue(OPT_o));
+  Opts.SplitDwarfOutput =
+      std::string(Args.getLastArgValue(OPT_split_dwarf_output));
+  if (Arg *A = Args.getLastArg(OPT_filetype)) {
+    StringRef Name = A->getValue();
+    unsigned OutputType = StringSwitch<unsigned>(Name)
+      .Case("asm", FT_Asm)
+      .Case("null", FT_Null)
+      .Case("obj", FT_Obj)
+      .Default(~0U);
+    if (OutputType == ~0U) {
+      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
+      Success = false;
+    } else
+      Opts.OutputType = FileType(OutputType);
+  }
+  Opts.ShowHelp = Args.hasArg(OPT_help);
+  Opts.ShowVersion = Args.hasArg(OPT_version);
+
+  // Transliterate Options
+  Opts.OutputAsmVariant =
+      getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
+  Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
+  Opts.ShowInst = Args.hasArg(OPT_show_inst);
+
+  // Assemble Options
+  Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
+  Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
+  Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
+  Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
+  Opts.RelocationModel =
+      std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic"));
+  Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
+  Opts.IncrementalLinkerCompatible =
+      Args.hasArg(OPT_mincremental_linker_compatible);
+  Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
+
+  // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag.
+  // EmbedBitcode behaves the same for all embed options for assembly files.
+  if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) {
+    Opts.EmbedBitcode = llvm::StringSwitch<unsigned>(A->getValue())
+                            .Case("all", 1)
+                            .Case("bitcode", 1)
+                            .Case("marker", 1)
+                            .Default(0);
+  }
+
+  return Success;
+}
+
+static std::unique_ptr<raw_fd_ostream>
+getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
+  // Make sure that the Out file gets unlinked from the disk if we get a
+  // SIGINT.
+  if (Path != "-")
+    sys::RemoveFileOnSignal(Path);
+
+  std::error_code EC;
+  auto Out = std::make_unique<raw_fd_ostream>(
+      Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
+  if (EC) {
+    Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
+    return nullptr;
+  }
+
+  return Out;
+}
+
+bool ExecuteAssembler(AssemblerInvocation &Opts, DiagnosticsEngine &Diags) {
+  // Get the target specific parser.
+  std::string Error;
+  const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
+  if (!TheTarget)
+    return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+
+  ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
+      MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
+
+  if (std::error_code EC = Buffer.getError()) {
+    Error = EC.message();
+    return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
+  }
+
+  SourceMgr SrcMgr;
+
+  // Tell SrcMgr about this buffer, which is what the parser will pick up.
+  unsigned BufferIndex = SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
+
+  // Record the location of the include directories so that the lexer can find
+  // it later.
+  SrcMgr.setIncludeDirs(Opts.IncludePaths);
+
+  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
+  assert(MRI && "Unable to create target register info!");
+
+  MCTargetOptions MCOptions;
+  std::unique_ptr<MCAsmInfo> MAI(
+      TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
+  assert(MAI && "Unable to create target asm info!");
+
+  // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
+  // may be created with a combination of default and explicit settings.
+  MAI->setCompressDebugSections(Opts.CompressDebugSections);
+
+  MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
+
+  bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
+  if (Opts.OutputPath.empty())
+    Opts.OutputPath = "-";
+  std::unique_ptr<raw_fd_ostream> FDOS =
+      getOutputStream(Opts.OutputPath, Diags, IsBinary);
+  if (!FDOS)
+    return true;
+  std::unique_ptr<raw_fd_ostream> DwoOS;
+  if (!Opts.SplitDwarfOutput.empty())
+    DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
+
+  // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
+  // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
+  std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
+
+  MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
+
+  bool PIC = false;
+  if (Opts.RelocationModel == "static") {
+    PIC = false;
+  } else if (Opts.RelocationModel == "pic") {
+    PIC = true;
+  } else {
+    assert(Opts.RelocationModel == "dynamic-no-pic" &&
+           "Invalid PIC model!");
+    PIC = false;
+  }
+
+  MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
+  if (Opts.SaveTemporaryLabels)
+    Ctx.setAllowTemporaryLabels(false);
+  if (Opts.GenDwarfForAssembly)
+    Ctx.setGenDwarfForAssembly(true);
+  if (!Opts.DwarfDebugFlags.empty())
+    Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
+  if (!Opts.DwarfDebugProducer.empty())
+    Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
+  if (!Opts.DebugCompilationDir.empty())
+    Ctx.setCompilationDir(Opts.DebugCompilationDir);
+  else {
+    // If no compilation dir is set, try to use the current directory.
+    SmallString<128> CWD;
+    if (!sys::fs::current_path(CWD))
+      Ctx.setCompilationDir(CWD);
+  }
+  if (!Opts.DebugPrefixMap.empty())
+    for (const auto &KV : Opts.DebugPrefixMap)
+      Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
+  if (!Opts.MainFileName.empty())
+    Ctx.setMainFileName(StringRef(Opts.MainFileName));
+  Ctx.setDwarfVersion(Opts.DwarfVersion);
+  if (Opts.GenDwarfForAssembly)
+    Ctx.setGenDwarfRootFile(Opts.InputFile,
+                            SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
+
+  // Build up the feature string from the target feature list.
+  std::string FS = llvm::join(Opts.Features, ",");
+
+  std::unique_ptr<MCStreamer> Str;
+
+  std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
+  assert(MCII && "Unable to create instruction info!");
+
+  std::unique_ptr<MCSubtargetInfo> STI(
+      TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
+  assert(STI && "Unable to create subtarget info!");
+
+  raw_pwrite_stream *Out = FDOS.get();
+  std::unique_ptr<buffer_ostream> BOS;
+
+  MCOptions.MCNoWarn = Opts.NoWarn;
+  MCOptions.MCFatalWarnings = Opts.FatalWarnings;
+  MCOptions.ABIName = Opts.TargetABI;
+
+  // FIXME: There is a bit of code duplication with addPassesToEmitFile.
+  if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
+    MCInstPrinter *IP = TheTarget->createMCInstPrinter(
+        llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
+
+    std::unique_ptr<MCCodeEmitter> CE;
+    if (Opts.ShowEncoding)
+      CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+    std::unique_ptr<MCAsmBackend> MAB(
+        TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
+
+    auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
+    Str.reset(TheTarget->createAsmStreamer(
+        Ctx, std::move(FOut), /*asmverbose*/ true,
+        /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
+        Opts.ShowInst));
+  } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
+    Str.reset(createNullStreamer(Ctx));
+  } else {
+    assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
+           "Invalid file type!");
+    if (!FDOS->supportsSeeking()) {
+      BOS = std::make_unique<buffer_ostream>(*FDOS);
+      Out = BOS.get();
+    }
+
+    std::unique_ptr<MCCodeEmitter> CE(
+        TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
+    std::unique_ptr<MCAsmBackend> MAB(
+        TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
+    assert(MAB && "Unable to create asm backend!");
+
+    std::unique_ptr<MCObjectWriter> OW =
+        DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
+              : MAB->createObjectWriter(*Out);
+
+    Triple T(Opts.Triple);
+    Str.reset(TheTarget->createMCObjectStreamer(
+        T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
+        Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
+        /*DWARFMustBeAtTheEnd*/ true));
+    Str.get()->InitSections(Opts.NoExecStack);
+  }
+
+  // When -fembed-bitcode is passed to clang_as, a 1-byte marker
+  // is emitted in __LLVM,__asm section if the object file is MachO format.
+  if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() ==
+                               MCObjectFileInfo::IsMachO) {
+    MCSection *AsmLabel = Ctx.getMachOSection(
+        "__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
+    Str.get()->SwitchSection(AsmLabel);
+    Str.get()->emitZeros(1);
+  }
+
+  // Assembly to object compilation should leverage assembly info.
+  Str->setUseAssemblerInfoForParsing(true);
+
+  bool Failed = false;
+
+  std::unique_ptr<MCAsmParser> Parser(
+      createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
+
+  // FIXME: init MCTargetOptions from sanitizer flags here.
+  std::unique_ptr<MCTargetAsmParser> TAP(
+      TheTarget->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
+  if (!TAP)
+    Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
+
+  // Set values for symbols, if any.
+  for (auto &S : Opts.SymbolDefs) {
+    auto Pair = StringRef(S).split('=');
+    auto Sym = Pair.first;
+    auto Val = Pair.second;
+    int64_t Value;
+    // We have already error checked this in the driver.
+    Val.getAsInteger(0, Value);
+    Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
+  }
+
+  if (!Failed) {
+    Parser->setTargetParser(*TAP.get());
+    Failed = Parser->Run(Opts.NoInitialTextSection);
+  }
+
+  // Parser has a reference to the output stream (Str), so close Parser first.
+  Parser.reset();
+  Str.reset();
+  // Close the output stream early.
+  BOS.reset();
+  FDOS.reset();
+
+  // Delete output file if there were errors.
+  if (Failed) {
+    if (Opts.OutputPath != "-")
+      sys::fs::remove(Opts.OutputPath);
+    if (!Opts.SplitDwarfOutput.empty() && Opts.SplitDwarfOutput != "-")
+      sys::fs::remove(Opts.SplitDwarfOutput);
+  }
+
+  return Failed;
+}
+
+} // namespace clang

diff  --git a/clang/lib/Frontend/CMakeLists.txt b/clang/lib/Frontend/CMakeLists.txt
index 90422855bd05..511e4e5e55e1 100644
--- a/clang/lib/Frontend/CMakeLists.txt
+++ b/clang/lib/Frontend/CMakeLists.txt
@@ -9,6 +9,7 @@ set(LLVM_LINK_COMPONENTS
   )
 
 add_clang_library(clangFrontend
+  AssemblerInvocation.cpp
   ASTConsumers.cpp
   ASTMerge.cpp
   ASTUnit.cpp

diff  --git a/clang/tools/driver/cc1as_main.cpp b/clang/tools/driver/cc1as_main.cpp
index de71026fbffe..5568af07b79b 100644
--- a/clang/tools/driver/cc1as_main.cpp
+++ b/clang/tools/driver/cc1as_main.cpp
@@ -15,6 +15,7 @@
 #include "clang/Basic/DiagnosticOptions.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/Options.h"
+#include "clang/Frontend/AssemblerInvocation.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Frontend/Utils.h"
@@ -56,493 +57,9 @@
 #include <memory>
 #include <system_error>
 using namespace clang;
-using namespace clang::driver;
-using namespace clang::driver::options;
 using namespace llvm;
 using namespace llvm::opt;
 
-namespace {
-
-/// Helper class for representing a single invocation of the assembler.
-struct AssemblerInvocation {
-  /// @name Target Options
-  /// @{
-
-  /// The name of the target triple to assemble for.
-  std::string Triple;
-
-  /// If given, the name of the target CPU to determine which instructions
-  /// are legal.
-  std::string CPU;
-
-  /// The list of target specific features to enable or disable -- this should
-  /// be a list of strings starting with '+' or '-'.
-  std::vector<std::string> Features;
-
-  /// The list of symbol definitions.
-  std::vector<std::string> SymbolDefs;
-
-  /// @}
-  /// @name Language Options
-  /// @{
-
-  std::vector<std::string> IncludePaths;
-  unsigned NoInitialTextSection : 1;
-  unsigned SaveTemporaryLabels : 1;
-  unsigned GenDwarfForAssembly : 1;
-  unsigned RelaxELFRelocations : 1;
-  unsigned DwarfVersion;
-  std::string DwarfDebugFlags;
-  std::string DwarfDebugProducer;
-  std::string DebugCompilationDir;
-  std::map<const std::string, const std::string> DebugPrefixMap;
-  llvm::DebugCompressionType CompressDebugSections =
-      llvm::DebugCompressionType::None;
-  std::string MainFileName;
-  std::string SplitDwarfOutput;
-
-  /// @}
-  /// @name Frontend Options
-  /// @{
-
-  std::string InputFile;
-  std::vector<std::string> LLVMArgs;
-  std::string OutputPath;
-  enum FileType {
-    FT_Asm,  ///< Assembly (.s) output, transliterate mode.
-    FT_Null, ///< No output, for timing purposes.
-    FT_Obj   ///< Object file output.
-  };
-  FileType OutputType;
-  unsigned ShowHelp : 1;
-  unsigned ShowVersion : 1;
-
-  /// @}
-  /// @name Transliterate Options
-  /// @{
-
-  unsigned OutputAsmVariant;
-  unsigned ShowEncoding : 1;
-  unsigned ShowInst : 1;
-
-  /// @}
-  /// @name Assembler Options
-  /// @{
-
-  unsigned RelaxAll : 1;
-  unsigned NoExecStack : 1;
-  unsigned FatalWarnings : 1;
-  unsigned NoWarn : 1;
-  unsigned IncrementalLinkerCompatible : 1;
-  unsigned EmbedBitcode : 1;
-
-  /// The name of the relocation model to use.
-  std::string RelocationModel;
-
-  /// The ABI targeted by the backend. Specified using -target-abi. Empty
-  /// otherwise.
-  std::string TargetABI;
-
-  /// @}
-
-public:
-  AssemblerInvocation() {
-    Triple = "";
-    NoInitialTextSection = 0;
-    InputFile = "-";
-    OutputPath = "-";
-    OutputType = FT_Asm;
-    OutputAsmVariant = 0;
-    ShowInst = 0;
-    ShowEncoding = 0;
-    RelaxAll = 0;
-    NoExecStack = 0;
-    FatalWarnings = 0;
-    NoWarn = 0;
-    IncrementalLinkerCompatible = 0;
-    DwarfVersion = 0;
-    EmbedBitcode = 0;
-  }
-
-  static bool CreateFromArgs(AssemblerInvocation &Res,
-                             ArrayRef<const char *> Argv,
-                             DiagnosticsEngine &Diags);
-};
-
-}
-
-bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
-                                         ArrayRef<const char *> Argv,
-                                         DiagnosticsEngine &Diags) {
-  bool Success = true;
-
-  // Parse the arguments.
-  const OptTable &OptTbl = getDriverOptTable();
-
-  const unsigned IncludedFlagsBitmask = options::CC1AsOption;
-  unsigned MissingArgIndex, MissingArgCount;
-  InputArgList Args = OptTbl.ParseArgs(Argv, MissingArgIndex, MissingArgCount,
-                                       IncludedFlagsBitmask);
-
-  // Check for missing argument error.
-  if (MissingArgCount) {
-    Diags.Report(diag::err_drv_missing_argument)
-        << Args.getArgString(MissingArgIndex) << MissingArgCount;
-    Success = false;
-  }
-
-  // Issue errors on unknown arguments.
-  for (const Arg *A : Args.filtered(OPT_UNKNOWN)) {
-    auto ArgString = A->getAsString(Args);
-    std::string Nearest;
-    if (OptTbl.findNearest(ArgString, Nearest, IncludedFlagsBitmask) > 1)
-      Diags.Report(diag::err_drv_unknown_argument) << ArgString;
-    else
-      Diags.Report(diag::err_drv_unknown_argument_with_suggestion)
-          << ArgString << Nearest;
-    Success = false;
-  }
-
-  // Construct the invocation.
-
-  // Target Options
-  Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple));
-  Opts.CPU = std::string(Args.getLastArgValue(OPT_target_cpu));
-  Opts.Features = Args.getAllArgValues(OPT_target_feature);
-
-  // Use the default target triple if unspecified.
-  if (Opts.Triple.empty())
-    Opts.Triple = llvm::sys::getDefaultTargetTriple();
-
-  // Language Options
-  Opts.IncludePaths = Args.getAllArgValues(OPT_I);
-  Opts.NoInitialTextSection = Args.hasArg(OPT_n);
-  Opts.SaveTemporaryLabels = Args.hasArg(OPT_msave_temp_labels);
-  // Any DebugInfoKind implies GenDwarfForAssembly.
-  Opts.GenDwarfForAssembly = Args.hasArg(OPT_debug_info_kind_EQ);
-
-  if (const Arg *A = Args.getLastArg(OPT_compress_debug_sections_EQ)) {
-    Opts.CompressDebugSections =
-        llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
-            .Case("none", llvm::DebugCompressionType::None)
-            .Case("zlib", llvm::DebugCompressionType::Z)
-            .Case("zlib-gnu", llvm::DebugCompressionType::GNU)
-            .Default(llvm::DebugCompressionType::None);
-  }
-
-  Opts.RelaxELFRelocations = Args.hasArg(OPT_mrelax_relocations);
-  Opts.DwarfVersion = getLastArgIntValue(Args, OPT_dwarf_version_EQ, 2, Diags);
-  Opts.DwarfDebugFlags =
-      std::string(Args.getLastArgValue(OPT_dwarf_debug_flags));
-  Opts.DwarfDebugProducer =
-      std::string(Args.getLastArgValue(OPT_dwarf_debug_producer));
-  Opts.DebugCompilationDir =
-      std::string(Args.getLastArgValue(OPT_fdebug_compilation_dir));
-  Opts.MainFileName = std::string(Args.getLastArgValue(OPT_main_file_name));
-
-  for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
-    auto Split = StringRef(Arg).split('=');
-    Opts.DebugPrefixMap.insert(
-        {std::string(Split.first), std::string(Split.second)});
-  }
-
-  // Frontend Options
-  if (Args.hasArg(OPT_INPUT)) {
-    bool First = true;
-    for (const Arg *A : Args.filtered(OPT_INPUT)) {
-      if (First) {
-        Opts.InputFile = A->getValue();
-        First = false;
-      } else {
-        Diags.Report(diag::err_drv_unknown_argument) << A->getAsString(Args);
-        Success = false;
-      }
-    }
-  }
-  Opts.LLVMArgs = Args.getAllArgValues(OPT_mllvm);
-  Opts.OutputPath = std::string(Args.getLastArgValue(OPT_o));
-  Opts.SplitDwarfOutput =
-      std::string(Args.getLastArgValue(OPT_split_dwarf_output));
-  if (Arg *A = Args.getLastArg(OPT_filetype)) {
-    StringRef Name = A->getValue();
-    unsigned OutputType = StringSwitch<unsigned>(Name)
-      .Case("asm", FT_Asm)
-      .Case("null", FT_Null)
-      .Case("obj", FT_Obj)
-      .Default(~0U);
-    if (OutputType == ~0U) {
-      Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name;
-      Success = false;
-    } else
-      Opts.OutputType = FileType(OutputType);
-  }
-  Opts.ShowHelp = Args.hasArg(OPT_help);
-  Opts.ShowVersion = Args.hasArg(OPT_version);
-
-  // Transliterate Options
-  Opts.OutputAsmVariant =
-      getLastArgIntValue(Args, OPT_output_asm_variant, 0, Diags);
-  Opts.ShowEncoding = Args.hasArg(OPT_show_encoding);
-  Opts.ShowInst = Args.hasArg(OPT_show_inst);
-
-  // Assemble Options
-  Opts.RelaxAll = Args.hasArg(OPT_mrelax_all);
-  Opts.NoExecStack = Args.hasArg(OPT_mno_exec_stack);
-  Opts.FatalWarnings = Args.hasArg(OPT_massembler_fatal_warnings);
-  Opts.NoWarn = Args.hasArg(OPT_massembler_no_warn);
-  Opts.RelocationModel =
-      std::string(Args.getLastArgValue(OPT_mrelocation_model, "pic"));
-  Opts.TargetABI = std::string(Args.getLastArgValue(OPT_target_abi));
-  Opts.IncrementalLinkerCompatible =
-      Args.hasArg(OPT_mincremental_linker_compatible);
-  Opts.SymbolDefs = Args.getAllArgValues(OPT_defsym);
-
-  // EmbedBitcode Option. If -fembed-bitcode is enabled, set the flag.
-  // EmbedBitcode behaves the same for all embed options for assembly files.
-  if (auto *A = Args.getLastArg(OPT_fembed_bitcode_EQ)) {
-    Opts.EmbedBitcode = llvm::StringSwitch<unsigned>(A->getValue())
-                            .Case("all", 1)
-                            .Case("bitcode", 1)
-                            .Case("marker", 1)
-                            .Default(0);
-  }
-
-  return Success;
-}
-
-static std::unique_ptr<raw_fd_ostream>
-getOutputStream(StringRef Path, DiagnosticsEngine &Diags, bool Binary) {
-  // Make sure that the Out file gets unlinked from the disk if we get a
-  // SIGINT.
-  if (Path != "-")
-    sys::RemoveFileOnSignal(Path);
-
-  std::error_code EC;
-  auto Out = std::make_unique<raw_fd_ostream>(
-      Path, EC, (Binary ? sys::fs::OF_None : sys::fs::OF_Text));
-  if (EC) {
-    Diags.Report(diag::err_fe_unable_to_open_output) << Path << EC.message();
-    return nullptr;
-  }
-
-  return Out;
-}
-
-static bool ExecuteAssembler(AssemblerInvocation &Opts,
-                             DiagnosticsEngine &Diags) {
-  // Get the target specific parser.
-  std::string Error;
-  const Target *TheTarget = TargetRegistry::lookupTarget(Opts.Triple, Error);
-  if (!TheTarget)
-    return Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
-
-  ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
-      MemoryBuffer::getFileOrSTDIN(Opts.InputFile);
-
-  if (std::error_code EC = Buffer.getError()) {
-    Error = EC.message();
-    return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
-  }
-
-  SourceMgr SrcMgr;
-
-  // Tell SrcMgr about this buffer, which is what the parser will pick up.
-  unsigned BufferIndex = SrcMgr.AddNewSourceBuffer(std::move(*Buffer), SMLoc());
-
-  // Record the location of the include directories so that the lexer can find
-  // it later.
-  SrcMgr.setIncludeDirs(Opts.IncludePaths);
-
-  std::unique_ptr<MCRegisterInfo> MRI(TheTarget->createMCRegInfo(Opts.Triple));
-  assert(MRI && "Unable to create target register info!");
-
-  MCTargetOptions MCOptions;
-  std::unique_ptr<MCAsmInfo> MAI(
-      TheTarget->createMCAsmInfo(*MRI, Opts.Triple, MCOptions));
-  assert(MAI && "Unable to create target asm info!");
-
-  // Ensure MCAsmInfo initialization occurs before any use, otherwise sections
-  // may be created with a combination of default and explicit settings.
-  MAI->setCompressDebugSections(Opts.CompressDebugSections);
-
-  MAI->setRelaxELFRelocations(Opts.RelaxELFRelocations);
-
-  bool IsBinary = Opts.OutputType == AssemblerInvocation::FT_Obj;
-  if (Opts.OutputPath.empty())
-    Opts.OutputPath = "-";
-  std::unique_ptr<raw_fd_ostream> FDOS =
-      getOutputStream(Opts.OutputPath, Diags, IsBinary);
-  if (!FDOS)
-    return true;
-  std::unique_ptr<raw_fd_ostream> DwoOS;
-  if (!Opts.SplitDwarfOutput.empty())
-    DwoOS = getOutputStream(Opts.SplitDwarfOutput, Diags, IsBinary);
-
-  // FIXME: This is not pretty. MCContext has a ptr to MCObjectFileInfo and
-  // MCObjectFileInfo needs a MCContext reference in order to initialize itself.
-  std::unique_ptr<MCObjectFileInfo> MOFI(new MCObjectFileInfo());
-
-  MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr, &MCOptions);
-
-  bool PIC = false;
-  if (Opts.RelocationModel == "static") {
-    PIC = false;
-  } else if (Opts.RelocationModel == "pic") {
-    PIC = true;
-  } else {
-    assert(Opts.RelocationModel == "dynamic-no-pic" &&
-           "Invalid PIC model!");
-    PIC = false;
-  }
-
-  MOFI->InitMCObjectFileInfo(Triple(Opts.Triple), PIC, Ctx);
-  if (Opts.SaveTemporaryLabels)
-    Ctx.setAllowTemporaryLabels(false);
-  if (Opts.GenDwarfForAssembly)
-    Ctx.setGenDwarfForAssembly(true);
-  if (!Opts.DwarfDebugFlags.empty())
-    Ctx.setDwarfDebugFlags(StringRef(Opts.DwarfDebugFlags));
-  if (!Opts.DwarfDebugProducer.empty())
-    Ctx.setDwarfDebugProducer(StringRef(Opts.DwarfDebugProducer));
-  if (!Opts.DebugCompilationDir.empty())
-    Ctx.setCompilationDir(Opts.DebugCompilationDir);
-  else {
-    // If no compilation dir is set, try to use the current directory.
-    SmallString<128> CWD;
-    if (!sys::fs::current_path(CWD))
-      Ctx.setCompilationDir(CWD);
-  }
-  if (!Opts.DebugPrefixMap.empty())
-    for (const auto &KV : Opts.DebugPrefixMap)
-      Ctx.addDebugPrefixMapEntry(KV.first, KV.second);
-  if (!Opts.MainFileName.empty())
-    Ctx.setMainFileName(StringRef(Opts.MainFileName));
-  Ctx.setDwarfVersion(Opts.DwarfVersion);
-  if (Opts.GenDwarfForAssembly)
-    Ctx.setGenDwarfRootFile(Opts.InputFile,
-                            SrcMgr.getMemoryBuffer(BufferIndex)->getBuffer());
-
-  // Build up the feature string from the target feature list.
-  std::string FS = llvm::join(Opts.Features, ",");
-
-  std::unique_ptr<MCStreamer> Str;
-
-  std::unique_ptr<MCInstrInfo> MCII(TheTarget->createMCInstrInfo());
-  assert(MCII && "Unable to create instruction info!");
-
-  std::unique_ptr<MCSubtargetInfo> STI(
-      TheTarget->createMCSubtargetInfo(Opts.Triple, Opts.CPU, FS));
-  assert(STI && "Unable to create subtarget info!");
-
-  raw_pwrite_stream *Out = FDOS.get();
-  std::unique_ptr<buffer_ostream> BOS;
-
-  MCOptions.MCNoWarn = Opts.NoWarn;
-  MCOptions.MCFatalWarnings = Opts.FatalWarnings;
-  MCOptions.ABIName = Opts.TargetABI;
-
-  // FIXME: There is a bit of code duplication with addPassesToEmitFile.
-  if (Opts.OutputType == AssemblerInvocation::FT_Asm) {
-    MCInstPrinter *IP = TheTarget->createMCInstPrinter(
-        llvm::Triple(Opts.Triple), Opts.OutputAsmVariant, *MAI, *MCII, *MRI);
-
-    std::unique_ptr<MCCodeEmitter> CE;
-    if (Opts.ShowEncoding)
-      CE.reset(TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
-    std::unique_ptr<MCAsmBackend> MAB(
-        TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
-
-    auto FOut = std::make_unique<formatted_raw_ostream>(*Out);
-    Str.reset(TheTarget->createAsmStreamer(
-        Ctx, std::move(FOut), /*asmverbose*/ true,
-        /*useDwarfDirectory*/ true, IP, std::move(CE), std::move(MAB),
-        Opts.ShowInst));
-  } else if (Opts.OutputType == AssemblerInvocation::FT_Null) {
-    Str.reset(createNullStreamer(Ctx));
-  } else {
-    assert(Opts.OutputType == AssemblerInvocation::FT_Obj &&
-           "Invalid file type!");
-    if (!FDOS->supportsSeeking()) {
-      BOS = std::make_unique<buffer_ostream>(*FDOS);
-      Out = BOS.get();
-    }
-
-    std::unique_ptr<MCCodeEmitter> CE(
-        TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx));
-    std::unique_ptr<MCAsmBackend> MAB(
-        TheTarget->createMCAsmBackend(*STI, *MRI, MCOptions));
-    assert(MAB && "Unable to create asm backend!");
-
-    std::unique_ptr<MCObjectWriter> OW =
-        DwoOS ? MAB->createDwoObjectWriter(*Out, *DwoOS)
-              : MAB->createObjectWriter(*Out);
-
-    Triple T(Opts.Triple);
-    Str.reset(TheTarget->createMCObjectStreamer(
-        T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
-        Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
-        /*DWARFMustBeAtTheEnd*/ true));
-    Str.get()->InitSections(Opts.NoExecStack);
-  }
-
-  // When -fembed-bitcode is passed to clang_as, a 1-byte marker
-  // is emitted in __LLVM,__asm section if the object file is MachO format.
-  if (Opts.EmbedBitcode && Ctx.getObjectFileInfo()->getObjectFileType() ==
-                               MCObjectFileInfo::IsMachO) {
-    MCSection *AsmLabel = Ctx.getMachOSection(
-        "__LLVM", "__asm", MachO::S_REGULAR, 4, SectionKind::getReadOnly());
-    Str.get()->SwitchSection(AsmLabel);
-    Str.get()->emitZeros(1);
-  }
-
-  // Assembly to object compilation should leverage assembly info.
-  Str->setUseAssemblerInfoForParsing(true);
-
-  bool Failed = false;
-
-  std::unique_ptr<MCAsmParser> Parser(
-      createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI));
-
-  // FIXME: init MCTargetOptions from sanitizer flags here.
-  std::unique_ptr<MCTargetAsmParser> TAP(
-      TheTarget->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
-  if (!TAP)
-    Failed = Diags.Report(diag::err_target_unknown_triple) << Opts.Triple;
-
-  // Set values for symbols, if any.
-  for (auto &S : Opts.SymbolDefs) {
-    auto Pair = StringRef(S).split('=');
-    auto Sym = Pair.first;
-    auto Val = Pair.second;
-    int64_t Value;
-    // We have already error checked this in the driver.
-    Val.getAsInteger(0, Value);
-    Ctx.setSymbolValue(Parser->getStreamer(), Sym, Value);
-  }
-
-  if (!Failed) {
-    Parser->setTargetParser(*TAP.get());
-    Failed = Parser->Run(Opts.NoInitialTextSection);
-  }
-
-  // Parser has a reference to the output stream (Str), so close Parser first.
-  Parser.reset();
-  Str.reset();
-  // Close the output stream early.
-  BOS.reset();
-  FDOS.reset();
-
-  // Delete output file if there were errors.
-  if (Failed) {
-    if (Opts.OutputPath != "-")
-      sys::fs::remove(Opts.OutputPath);
-    if (!Opts.SplitDwarfOutput.empty() && Opts.SplitDwarfOutput != "-")
-      sys::fs::remove(Opts.SplitDwarfOutput);
-  }
-
-  return Failed;
-}
-
 static void LLVMErrorHandler(void *UserData, const std::string &Message,
                              bool GenCrashDiag) {
   DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
@@ -578,7 +95,7 @@ int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
     return 1;
 
   if (Asm.ShowHelp) {
-    getDriverOptTable().PrintHelp(
+    clang::driver::getDriverOptTable().PrintHelp(
         llvm::outs(), "clang -cc1as [options] file...",
         "Clang Integrated Assembler",
         /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0,


        


More information about the llvm-branch-commits mailing list