sunshaoce created this revision.
sunshaoce added reviewers: rovka, kiranchandramohan, Leporacanthicus, 
awarzynski, sscalpone, liaolucy.
Herald added projects: Flang, All.
sunshaoce requested review of this revision.
Herald added subscribers: cfe-commits, jdoerfert, MaskRay.
Herald added a project: clang.

I'm trying to support `flang-new *.s`. Since I'm new to flang, I'm not sure if 
this is the right way to do it.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D143478

Files:
  clang/include/clang/Driver/Options.h
  clang/include/clang/Driver/Options.td
  clang/include/clang/Driver/ToolChain.h
  clang/lib/Driver/ToolChain.cpp
  clang/lib/Driver/ToolChains/Flang.cpp
  clang/lib/Driver/ToolChains/Flang.h
  flang/tools/flang-driver/CMakeLists.txt
  flang/tools/flang-driver/driver.cpp
  flang/tools/flang-driver/fc1as_main.cpp

Index: flang/tools/flang-driver/fc1as_main.cpp
===================================================================
--- /dev/null
+++ flang/tools/flang-driver/fc1as_main.cpp
@@ -0,0 +1,672 @@
+//===-- fc1as_main.cpp - Flang Assembler  ---------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the entry point to the flang -fc1as functionality, which implements
+// the direct interface to the LLVM MC based assembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/Driver/Options.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/MC/TargetRegistry.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/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <memory>
+#include <optional>
+#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 dwarf64 : 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 noTypeCheck : 1;
+  unsigned incrementalLinkerCompatible : 1;
+  unsigned embedBitcode : 1;
+
+  /// Whether to emit DWARF unwind info.
+  EmitDwarfUnwindType emitDwarfUnwind;
+
+  /// 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;
+
+  /// Darwin target variant triple, the variant of the deployment target
+  /// for which the code is being compiled.
+  std::optional<llvm::Triple> darwinTargetVariantTriple;
+
+  /// The version of the darwin target variant SDK which was used during the
+  /// compilation
+  llvm::VersionTuple darwinTargetVariantSdkVersion;
+
+  /// The name of a file to use with \c .secure_log_unique directives.
+  std::string asSecureLogFile;
+  /// @}
+
+public:
+  AssemblerInvocation() {
+    triple = "";
+    noInitialTextSection = 0;
+    inputFile = "-";
+    outputPath = "-";
+    outputType = FT_Asm;
+    outputAsmVariant = 0;
+    showInst = 0;
+    showEncoding = 0;
+    relaxAll = 0;
+    noExecStack = 0;
+    fatalWarnings = 0;
+    noWarn = 0;
+    noTypeCheck = 0;
+    incrementalLinkerCompatible = 0;
+    dwarf64 = 0;
+    dwarfVersion = 0;
+    embedBitcode = 0;
+    emitDwarfUnwind = EmitDwarfUnwindType::Default;
+  }
+
+  static bool createFromArgs(AssemblerInvocation &res,
+                             ArrayRef<const char *> argv,
+                             DiagnosticsEngine &diags);
+};
+
+} // namespace
+
+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::FC1AsOption;
+  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));
+  if (Arg *a = args.getLastArg(options::OPT_darwin_target_variant_triple))
+    opts.darwinTargetVariantTriple = llvm::Triple(a->getValue());
+  if (Arg *a = args.getLastArg(OPT_darwin_target_variant_sdk_version_EQ)) {
+    VersionTuple version;
+    if (version.tryParse(a->getValue()))
+      diags.Report(diag::err_drv_invalid_value)
+          << a->getAsString(args) << a->getValue();
+    else
+      opts.darwinTargetVariantSdkVersion = version;
+  }
+
+  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::Zlib)
+            .Case("zstd", llvm::DebugCompressionType::Zstd)
+            .Default(llvm::DebugCompressionType::None);
+  }
+
+  opts.relaxElfRelocations = !args.hasArg(OPT_mrelax_relocations_no);
+  if (auto *dwarfFormatArg = args.getLastArg(OPT_gdwarf64, OPT_gdwarf32))
+    opts.dwarf64 = dwarfFormatArg->getOption().matches(OPT_gdwarf64);
+  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));
+  if (const Arg *a = args.getLastArg(options::OPT_ffile_compilation_dir_EQ,
+                                     options::OPT_fdebug_compilation_dir_EQ))
+    opts.debugCompilationDir = a->getValue();
+  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.noTypeCheck = args.hasArg(OPT_mno_type_check);
+  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);
+  }
+
+  if (auto *a = args.getLastArg(OPT_femit_dwarf_unwind_EQ)) {
+    opts.emitDwarfUnwind =
+        llvm::StringSwitch<EmitDwarfUnwindType>(a->getValue())
+            .Case("always", EmitDwarfUnwindType::Always)
+            .Case("no-compact-unwind", EmitDwarfUnwindType::NoCompactUnwind)
+            .Case("default", EmitDwarfUnwindType::Default);
+  }
+
+  opts.asSecureLogFile = args.getLastArgValue(OPT_as_secure_log_file);
+
+  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_TextWithCRLF));
+  if (ec) {
+    diags.Report(diag::err_fe_unable_to_open_output) << path << ec.message();
+    return nullptr;
+  }
+
+  return out;
+}
+
+static bool executeAssemblerImpl(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, /*IsText=*/true);
+
+  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;
+  mcOptions.EmitDwarfUnwind = opts.emitDwarfUnwind;
+  mcOptions.AsSecureLogFile = opts.asSecureLogFile;
+
+  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);
+
+  // Build up the feature string from the target feature list.
+  std::string fs = llvm::join(opts.features, ",");
+
+  std::unique_ptr<MCSubtargetInfo> sti(
+      theTarget->createMCSubtargetInfo(opts.triple, opts.cpu, fs));
+  assert(sti && "Unable to create subtarget info!");
+
+  MCContext ctx(Triple(opts.triple), mai.get(), mri.get(), sti.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;
+  }
+
+  // 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(
+      theTarget->createMCObjectFileInfo(ctx, pic));
+  if (opts.darwinTargetVariantTriple)
+    mofi->setDarwinTargetVariantTriple(*opts.darwinTargetVariantTriple);
+  if (!opts.darwinTargetVariantSdkVersion.empty())
+    mofi->setDarwinTargetVariantSDKVersion(opts.darwinTargetVariantSdkVersion);
+  ctx.setObjectFileInfo(mofi.get());
+
+  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.setDwarfFormat(opts.dwarf64 ? dwarf::DWARF64 : dwarf::DWARF32);
+  ctx.setDwarfVersion(opts.dwarfVersion);
+  if (opts.genDwarfForAssembly)
+    ctx.setGenDwarfRootFile(opts.inputFile,
+                            srcMgr.getMemoryBuffer(bufferIndex)->getBuffer());
+
+  std::unique_ptr<MCStreamer> str;
+
+  std::unique_ptr<MCInstrInfo> mcii(theTarget->createMCInstrInfo());
+  assert(mcii && "Unable to create instruction info!");
+
+  raw_pwrite_stream *out = fdos.get();
+  std::unique_ptr<buffer_ostream> bos;
+
+  mcOptions.MCNoWarn = opts.noWarn;
+  mcOptions.MCFatalWarnings = opts.fatalWarnings;
+  mcOptions.MCNoTypeCheck = opts.noTypeCheck;
+  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, 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, 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, *sti);
+  }
+
+  // When -fembed-bitcode is passed to flang_as, a 1-byte marker
+  // is emitted in __LLVM,__asm section if the object file is MachO format.
+  if (opts.embedBitcode && ctx.getObjectFileType() == MCContext::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);
+  }
+
+  return failed;
+}
+
+static bool executeAssembler(AssemblerInvocation &opts,
+                             DiagnosticsEngine &diags) {
+  bool failed = executeAssemblerImpl(opts, diags);
+
+  // 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 char *message,
+                             bool genCrashDiag) {
+  DiagnosticsEngine &diags = *static_cast<DiagnosticsEngine *>(userData);
+
+  diags.Report(diag::err_fe_error_backend) << message;
+
+  // We cannot recover from llvm errors.
+  sys::Process::Exit(1);
+}
+
+int fc1as_main(ArrayRef<const char *> argv, const char *argv0) {
+  // Initialize targets and assembly printers/parsers.
+  InitializeAllTargetInfos();
+  InitializeAllTargetMCs();
+  InitializeAllAsmParsers();
+
+  // Construct our diagnostic client.
+  IntrusiveRefCntPtr<DiagnosticOptions> diagOpts = new DiagnosticOptions();
+  TextDiagnosticPrinter *diagClient =
+      new TextDiagnosticPrinter(errs(), &*diagOpts);
+  diagClient->setPrefix("flang -fc1as");
+  IntrusiveRefCntPtr<DiagnosticIDs> diagId(new DiagnosticIDs());
+  DiagnosticsEngine diags(diagId, &*diagOpts, diagClient);
+
+  // Set an error handler, so that any LLVM backend diagnostics go through our
+  // error handler.
+  ScopedFatalErrorHandler fatalErrorHandler(llvmErrorHandler,
+                                            static_cast<void *>(&diags));
+
+  // Parse the arguments.
+  AssemblerInvocation asmInv;
+  if (!AssemblerInvocation::createFromArgs(asmInv, argv, diags))
+    return 1;
+
+  if (asmInv.showHelp) {
+    getDriverOptTable().printHelp(
+        llvm::outs(), "flang -fc1as [options] file...",
+        "Flang Integrated Assembler",
+        /*Include=*/driver::options::FC1AsOption, /*Exclude=*/0,
+        /*ShowAllAliases=*/false);
+    return 0;
+  }
+
+  // Honor -version.
+  //
+  // FIXME: Use a better -version message?
+  if (asmInv.showVersion) {
+    llvm::cl::PrintVersionMessage();
+    return 0;
+  }
+
+  // Honor -mllvm.
+  //
+  // FIXME: Remove this, one day.
+  if (!asmInv.llvmArgs.empty()) {
+    unsigned numArgs = asmInv.llvmArgs.size();
+    auto args = std::make_unique<const char *[]>(numArgs + 2);
+    args[0] = "flang (LLVM option parsing)";
+    for (unsigned i = 0; i != numArgs; ++i)
+      args[i + 1] = asmInv.llvmArgs[i].c_str();
+    args[numArgs + 1] = nullptr;
+    llvm::cl::ParseCommandLineOptions(numArgs + 1, args.get());
+  }
+
+  // Execute the invocation, unless there were parsing errors.
+  bool failed = diags.hasErrorOccurred() || executeAssembler(asmInv, diags);
+
+  // If any timers were active but haven't been destroyed yet, print their
+  // results now.
+  TimerGroup::printAll(errs());
+  TimerGroup::clearAll();
+
+  return !!failed;
+}
Index: flang/tools/flang-driver/driver.cpp
===================================================================
--- flang/tools/flang-driver/driver.cpp
+++ flang/tools/flang-driver/driver.cpp
@@ -35,6 +35,8 @@
 // main frontend method. Lives inside fc1_main.cpp
 extern int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0);
 
+extern int fc1as_main(llvm::ArrayRef<const char *> argv, const char *argv0);
+
 std::string getExecutablePath(const char *argv0) {
   // This just needs to be some symbol in the binary
   void *p = (void *)(intptr_t)getExecutablePath;
@@ -64,6 +66,8 @@
   llvm::StringRef tool = argV[1];
   if (tool == "-fc1")
     return fc1_main(llvm::ArrayRef(argV).slice(2), argV[0]);
+  if (tool == "-fc1as")
+    return fc1as_main(llvm::ArrayRef(argV).slice(2), argV[0]);
 
   // Reject unknown tools.
   // ATM it only supports fc1. Any fc1[*] is rejected.
Index: flang/tools/flang-driver/CMakeLists.txt
===================================================================
--- flang/tools/flang-driver/CMakeLists.txt
+++ flang/tools/flang-driver/CMakeLists.txt
@@ -14,6 +14,7 @@
 add_flang_tool(flang-new
   driver.cpp
   fc1_main.cpp
+  fc1as_main.cpp
 
   DEPENDS
   # These libraries are used in the linker invocation generated by the driver
@@ -32,8 +33,12 @@
 
 clang_target_link_libraries(flang-new
   PRIVATE
-  clangDriver
   clangBasic
+  clangCodeGen
+  clangDriver
+  clangFrontend
+  clangFrontendTool
+  clangSerialization
 )
 
 option(FLANG_PLUGIN_SUPPORT "Build Flang with plugin support." ON)
Index: clang/lib/Driver/ToolChains/Flang.h
===================================================================
--- clang/lib/Driver/ToolChains/Flang.h
+++ clang/lib/Driver/ToolChains/Flang.h
@@ -79,6 +79,22 @@
                     const char *LinkingOutput) const override;
 };
 
+/// Flang integrated assembler tool.
+class LLVM_LIBRARY_VISIBILITY FlangAs : public Tool {
+public:
+  FlangAs(const ToolChain &TC)
+      : Tool("flang::as", "flang integrated assembler", TC) {}
+  void AddX86TargetArgs(const llvm::opt::ArgList &Args,
+                        llvm::opt::ArgStringList &CmdArgs) const;
+  bool hasIntegratedAssembler() const override { return false; }
+  bool hasIntegratedCPP() const override { return false; }
+
+  void ConstructJob(Compilation &C, const JobAction &JA,
+                    const InputInfo &Output, const InputInfoList &Inputs,
+                    const llvm::opt::ArgList &TCArgs,
+                    const char *LinkingOutput) const override;
+};
+
 } // end namespace tools
 
 } // end namespace driver
Index: clang/lib/Driver/ToolChains/Flang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Flang.cpp
+++ clang/lib/Driver/ToolChains/Flang.cpp
@@ -11,6 +11,7 @@
 #include "CommonArgs.h"
 
 #include "clang/Driver/Options.h"
+#include "llvm/Support/VirtualFileSystem.h"
 
 #include <cassert>
 
@@ -357,3 +358,143 @@
 Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {}
 
 Flang::~Flang() {}
+
+// Begin FlangAs
+
+void FlangAs::AddX86TargetArgs(const ArgList &Args,
+                               ArgStringList &CmdArgs) const {
+  addX86AlignBranchArgs(getToolChain().getDriver(), Args, CmdArgs,
+                        /*IsLTO=*/false);
+
+  if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) {
+    StringRef Value = A->getValue();
+    if (Value == "intel" || Value == "att") {
+      CmdArgs.push_back("-mllvm");
+      CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value));
+    } else {
+      getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument)
+          << A->getSpelling() << Value;
+    }
+  }
+}
+
+void FlangAs::ConstructJob(Compilation &C, const JobAction &JA,
+                           const InputInfo &Output, const InputInfoList &Inputs,
+                           const ArgList &Args,
+                           const char *LinkingOutput) const {
+  ArgStringList CmdArgs;
+
+  assert(Inputs.size() == 1 && "Unexpected number of inputs.");
+  const InputInfo &Input = Inputs[0];
+
+  const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
+  const std::string &TripleStr = Triple.getTriple();
+  const auto &D = getToolChain().getDriver();
+
+  // Don't warn about "clang -w -c foo.s"
+  Args.ClaimAllArgs(options::OPT_w);
+  // and "clang -emit-llvm -c foo.s"
+  Args.ClaimAllArgs(options::OPT_emit_llvm);
+
+  claimNoWarnArgs(Args);
+
+  // Invoke ourselves in -cc1as mode.
+  //
+  // FIXME: Implement custom jobs for internal actions.
+  CmdArgs.push_back("-fc1as");
+
+  // Add the "effective" target triple.
+  CmdArgs.push_back("-triple");
+  CmdArgs.push_back(Args.MakeArgString(TripleStr));
+
+  getToolChain().addClangCC1ASTargetOptions(Args, CmdArgs);
+
+  // Set the output mode, we currently only expect to be used as a real
+  // assembler.
+  CmdArgs.push_back("-filetype");
+  CmdArgs.push_back("obj");
+
+  // Add the target cpu
+  std::string CPU = getCPUName(D, Args, Triple, /*FromAs*/ true);
+  if (!CPU.empty()) {
+    CmdArgs.push_back("-target-cpu");
+    CmdArgs.push_back(Args.MakeArgString(CPU));
+  }
+
+  // Add the target features
+  getTargetFeatures(D, Triple, Args, CmdArgs, true);
+
+  // Ignore explicit -force_cpusubtype_ALL option.
+  (void)Args.hasArg(options::OPT_force__cpusubtype__ALL);
+
+  // Pass along any -I options so we get proper .include search paths.
+  Args.AddAllArgs(CmdArgs, options::OPT_I_Group);
+
+  // Handle -fPIC et al -- the relocation-model affects the assembler
+  // for some targets.
+  llvm::Reloc::Model RelocationModel;
+  unsigned PICLevel;
+  bool IsPIE;
+  std::tie(RelocationModel, PICLevel, IsPIE) =
+      ParsePICArgs(getToolChain(), Args);
+
+  const char *RMName = RelocationModelName(RelocationModel);
+  if (RMName) {
+    CmdArgs.push_back("-mrelocation-model");
+    CmdArgs.push_back(RMName);
+  }
+
+  // Add target specific flags.
+  switch (getToolChain().getArch()) {
+  default:
+    break;
+
+  case llvm::Triple::x86:
+  case llvm::Triple::x86_64:
+    AddX86TargetArgs(Args, CmdArgs);
+    break;
+
+  case llvm::Triple::arm:
+  case llvm::Triple::armeb:
+  case llvm::Triple::thumb:
+  case llvm::Triple::thumbeb:
+    // This isn't in AddARMTargetArgs because we want to do this for assembly
+    // only, not C/C++.
+    if (Args.hasFlag(options::OPT_mdefault_build_attributes,
+                     options::OPT_mno_default_build_attributes, true)) {
+      CmdArgs.push_back("-mllvm");
+      CmdArgs.push_back("-arm-add-build-attributes");
+    }
+    break;
+
+  case llvm::Triple::aarch64:
+  case llvm::Triple::aarch64_32:
+  case llvm::Triple::aarch64_be:
+    if (Args.hasArg(options::OPT_mmark_bti_property)) {
+      CmdArgs.push_back("-mllvm");
+      CmdArgs.push_back("-aarch64-mark-bti-property");
+    }
+    break;
+  }
+
+  Args.ClaimAllArgs(options::OPT_W_Group);
+
+  assert(Output.isFilename() && "Unexpected lipo output.");
+  CmdArgs.push_back("-o");
+  CmdArgs.push_back(Output.getFilename());
+
+  assert(Input.isFilename() && "Invalid input.");
+  CmdArgs.push_back(Input.getFilename());
+
+  const char *Exec = getToolChain().getDriver().getClangProgramPath();
+  if (D.CC1Main && !D.CCGenDiagnostics) {
+    // Invoke cc1as directly in this process.
+    C.addCommand(std::make_unique<CC1Command>(JA, *this,
+                                              ResponseFileSupport::AtFileUTF8(),
+                                              Exec, CmdArgs, Inputs, Output));
+  } else {
+    C.addCommand(std::make_unique<Command>(JA, *this,
+                                           ResponseFileSupport::AtFileUTF8(),
+                                           Exec, CmdArgs, Inputs, Output));
+  }
+}
Index: clang/lib/Driver/ToolChain.cpp
===================================================================
--- clang/lib/Driver/ToolChain.cpp
+++ clang/lib/Driver/ToolChain.cpp
@@ -363,6 +363,12 @@
   return Assemble.get();
 }
 
+Tool *ToolChain::getFlangAs() const {
+  if (!Assemble)
+    Assemble.reset(new tools::FlangAs(*this));
+  return Assemble.get();
+}
+
 Tool *ToolChain::getLink() const {
   if (!Link)
     Link.reset(buildLinker());
@@ -652,8 +658,12 @@
   if (D.IsFlangMode() && getDriver().ShouldUseFlangCompiler(JA)) return getFlang();
   if (getDriver().ShouldUseClangCompiler(JA)) return getClang();
   Action::ActionClass AC = JA.getKind();
-  if (AC == Action::AssembleJobClass && useIntegratedAs())
+  if (AC == Action::AssembleJobClass && useIntegratedAs()) {
+    if (D.IsFlangMode())
+      return getFlangAs();
     return getClangAs();
+  }
+
   return getTool(AC);
 }
 
Index: clang/include/clang/Driver/ToolChain.h
===================================================================
--- clang/include/clang/Driver/ToolChain.h
+++ clang/include/clang/Driver/ToolChain.h
@@ -166,6 +166,7 @@
   Tool *getStaticLibTool() const;
   Tool *getIfsMerge() const;
   Tool *getClangAs() const;
+  Tool *getFlangAs() const;
   Tool *getOffloadBundler() const;
   Tool *getOffloadPackager() const;
   Tool *getLinkerWrapper() const;
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -75,6 +75,9 @@
 // FC1Option - This option should be accepted by flang -fc1.
 def FC1Option : OptionFlag;
 
+// FC1AsOption - This option should be accepted by flang -fc1as.
+def FC1AsOption : OptionFlag;
+
 // A short name to show in documentation. The name will be interpreted as rST.
 class DocName<string name> { string DocName = name; }
 
@@ -696,7 +699,7 @@
     HelpText<"Restrict all prior -I flags to double-quoted inclusion and "
              "remove current directory from include path">;
 def I : JoinedOrSeparate<["-"], "I">, Group<I_Group>,
-    Flags<[CC1Option,CC1AsOption,FlangOption,FC1Option]>, MetaVarName<"<dir>">,
+    Flags<[CC1Option,CC1AsOption,FlangOption,FC1AsOption,FC1Option]>, MetaVarName<"<dir>">,
     HelpText<"Add directory to the end of the list of include search paths">,
     DocBrief<[{Add directory to include search path. For C++ inputs, if
 there are multiple -I options, these directories are searched
@@ -3300,7 +3303,7 @@
     Flags<[NoXarchOption]>,
     HelpText<"Restore the default behavior of not embedding source text in DWARF debug sections">;
 def headerpad__max__install__names : Joined<["-"], "headerpad_max_install_names">;
-def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption, FC1Option,
+def help : Flag<["-", "--"], "help">, Flags<[CC1Option,CC1AsOption, FC1Option, FC1AsOption,
     FlangOption]>, HelpText<"Display available options">,
     MarshallingInfoFlag<FrontendOpts<"ShowHelp">>;
 def ibuiltininc : Flag<["-"], "ibuiltininc">,
@@ -3475,7 +3478,7 @@
 def mkernel : Flag<["-"], "mkernel">, Group<m_Group>;
 def mlinker_version_EQ : Joined<["-"], "mlinker-version=">,
   Flags<[NoXarchOption]>;
-def mllvm : Separate<["-"], "mllvm">,Flags<[CC1Option,CC1AsOption,CoreOption,FC1Option,FlangOption]>,
+def mllvm : Separate<["-"], "mllvm">,Flags<[CC1Option,CC1AsOption,CoreOption,FC1Option,FC1AsOption,FlangOption]>,
   HelpText<"Additional arguments to forward to LLVM's option processing">,
   MarshallingInfoStringVector<FrontendOpts<"LLVMArgs">>;
 def : Joined<["-"], "mllvm=">, Flags<[CoreOption,FlangOption]>, Alias<mllvm>,
@@ -4127,7 +4130,7 @@
 def nostdlibxx : Flag<["-"], "nostdlib++">;
 def object : Flag<["-"], "object">;
 def o : JoinedOrSeparate<["-"], "o">, Flags<[NoXarchOption,
-  CC1Option, CC1AsOption, FC1Option, FlangOption]>,
+  CC1Option, CC1AsOption, FC1Option, FC1AsOption, FlangOption]>,
   HelpText<"Write output to <file>">, MetaVarName<"<file>">,
   MarshallingInfoString<FrontendOpts<"OutputFile">>;
 def object_file_name_EQ : Joined<["-"], "object-file-name=">, Flags<[CC1Option, CC1AsOption, CoreOption]>,
@@ -5166,7 +5169,7 @@
 // Target Options (cc1 + cc1as + fc1)
 //===----------------------------------------------------------------------===//
 
-let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption] in {
+let Flags = [CC1Option, CC1AsOption, FC1Option, FC1AsOption, NoDriverOption] in {
 
 def target_cpu : Separate<["-"], "target-cpu">,
   HelpText<"Target a specific cpu type">,
@@ -5179,7 +5182,7 @@
   MarshallingInfoString<TargetOpts<"Triple">, "llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple())">,
   AlwaysEmit, Normalizer<"normalizeTriple">;
 
-} // let Flags = [CC1Option, CC1ASOption, FC1Option, NoDriverOption]
+} // let Flags = [CC1Option, CC1ASOption, FC1Option, FC1AsOption, NoDriverOption]
 
 //===----------------------------------------------------------------------===//
 // Target Options (other)
@@ -5372,7 +5375,7 @@
 // CodeGen Options
 //===----------------------------------------------------------------------===//
 
-let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption] in {
+let Flags = [CC1Option, CC1AsOption, FC1Option, FC1AsOption, NoDriverOption] in {
 
 def mrelocation_model : Separate<["-"], "mrelocation-model">,
   HelpText<"The relocation model to use">, Values<"static,pic,ropi,rwpi,ropi-rwpi,dynamic-no-pic">,
@@ -5380,7 +5383,7 @@
   NormalizedValues<["Static", "PIC_", "ROPI", "RWPI", "ROPI_RWPI", "DynamicNoPIC"]>,
   MarshallingInfoEnum<CodeGenOpts<"RelocationModel">, "PIC_">;
 
-} // let Flags = [CC1Option, CC1AsOption, FC1Option, NoDriverOption]
+} // let Flags = [CC1Option, CC1AsOption, FC1Option, FC1AsOption, NoDriverOption]
 
 let Flags = [CC1Option, CC1AsOption, NoDriverOption] in {
 
@@ -6124,7 +6127,7 @@
 
 def version : Flag<["-"], "version">,
   HelpText<"Print the compiler version">,
-  Flags<[CC1Option, CC1AsOption, FC1Option, NoDriverOption]>,
+  Flags<[CC1Option, CC1AsOption, FC1Option, FC1AsOption, NoDriverOption]>,
   MarshallingInfoFlag<FrontendOpts<"ShowVersion">>;
 
 def main_file_name : Separate<["-"], "main-file-name">,
@@ -6511,7 +6514,7 @@
 // cc1as-only Options
 //===----------------------------------------------------------------------===//
 
-let Flags = [CC1AsOption, NoDriverOption] in {
+let Flags = [CC1AsOption, FC1AsOption, NoDriverOption] in {
 
 // Language Options
 def n : Flag<["-"], "n">,
@@ -6536,7 +6539,7 @@
 def defsym : Separate<["-"], "defsym">,
   HelpText<"Define a value for a symbol">;
 
-} // let Flags = [CC1AsOption]
+} // let Flags = [CC1AsOption, FC1AsOption, NoDriverOption]
 
 //===----------------------------------------------------------------------===//
 // clang-cl Options
Index: clang/include/clang/Driver/Options.h
===================================================================
--- clang/include/clang/Driver/Options.h
+++ clang/include/clang/Driver/Options.h
@@ -34,10 +34,11 @@
   LinkOption = (1 << 13),
   FlangOption = (1 << 14),
   FC1Option = (1 << 15),
-  FlangOnlyOption = (1 << 16),
-  DXCOption = (1 << 17),
-  CLDXCOption = (1 << 18),
-  Ignored = (1 << 19),
+  FC1AsOption = (1 << 16),
+  FlangOnlyOption = (1 << 17),
+  DXCOption = (1 << 18),
+  CLDXCOption = (1 << 19),
+  Ignored = (1 << 20),
 };
 
 enum ID {
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to