mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
This also tries to restructure the command line interface to the toolchain a bit to make it start operating more like a compiler that could be integrated into a build system rather than primarily as a testing tool. 1) This switches form a `dump` subcommand to a `compile` subcommand which has "dump" actions that can be enabled within it. 2) A distinct set of compile _phases_ that match the toolchain structure: - `lex` to run the lexer - `parse` to run the parser - `check` to fully check that the code is valid - `lower` to lower to LLVM's IR - `codegen` to generate executable code 3) The codegen phase has two output formats: textual assembly and a binary object. These outputs can be configured, with a default for an object when writing to a file and more firm default for textual assembly when writing to stdout. 4) Select and expose the use of the LLVM host detection to compute a default code generation target in the driver so that the command line interface can reflect this. For example, the `help` output will include the default target. 5) The `//toolchain/codegen` library APIs have been restructured a bit to make the code flow a bit more naturally when implementing the new command line structure. No real changes to the logic though. There are also some minor tweaks to the command line interface based on trying to use the shortest names for things that still seem likely to be learnable for users: - Switched `target-triple` to just `target`: the "triple" component to this name is historical and can be confusing. For example, almost all "triple" strings have more than three components today. - Switched to just `--output` as now the fact that it is a file can be configured in the documentation -- it will render as `--output=FILE`. This also adds support for two custom output filename modes. First, when no output is specified, we now compute one in the conventional way for compilers by removing the file extension of the input file and replacing it with `.o` for an object file output or `.s` for an assembly file output. This matches the behavior of Clang and GCC for example. Second, output to stdout is enabled with the special output file name of `-` since it is no longer the default. This also follows the convention of most compilers and many other command line tools to use `-` as a file name to signify using standard in/out pipes. There are still some rough edges here that I suspect could be improved, but this seems like a good start of switching over to a complete argument parser. --------- Co-authored-by: Jon Ross-Perkins <jperkins@google.com> Co-authored-by: Lucile Rose Nihlen <luci.the.rose@gmail.com> Co-authored-by: Richard Smith <richard@metafoo.co.uk>
76 lines
2.3 KiB
C++
76 lines
2.3 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#include "toolchain/codegen/codegen.h"
|
|
|
|
#include <cstdio>
|
|
#include <memory>
|
|
|
|
#include "llvm/IR/LegacyPassManager.h"
|
|
#include "llvm/MC/TargetRegistry.h"
|
|
#include "llvm/Support/TargetSelect.h"
|
|
#include "llvm/Target/TargetOptions.h"
|
|
#include "llvm/TargetParser/Host.h"
|
|
|
|
namespace Carbon {
|
|
|
|
auto CodeGen::Create(llvm::Module& module, llvm::StringRef target_triple,
|
|
llvm::raw_pwrite_stream& errors)
|
|
-> std::optional<CodeGen> {
|
|
// Initialize the target registry etc.
|
|
llvm::InitializeAllTargetInfos();
|
|
llvm::InitializeAllTargets();
|
|
llvm::InitializeAllTargetMCs();
|
|
llvm::InitializeAllAsmParsers();
|
|
llvm::InitializeAllAsmPrinters();
|
|
|
|
std::string error;
|
|
const llvm::Target* target =
|
|
llvm::TargetRegistry::lookupTarget(target_triple, error);
|
|
|
|
if (!target) {
|
|
errors << "ERROR: Invalid target: " << error << "\n";
|
|
return {};
|
|
}
|
|
module.setTargetTriple(target_triple);
|
|
|
|
constexpr llvm::StringLiteral CPU = "generic";
|
|
constexpr llvm::StringLiteral Features = "";
|
|
|
|
llvm::TargetOptions target_opts;
|
|
std::optional<llvm::Reloc::Model> reloc_model;
|
|
CodeGen codegen(module, errors);
|
|
codegen.target_machine_.reset(target->createTargetMachine(
|
|
target_triple, CPU, Features, target_opts, reloc_model));
|
|
return codegen;
|
|
}
|
|
|
|
auto CodeGen::EmitAssembly(llvm::raw_pwrite_stream& out) -> bool {
|
|
return EmitCode(out, llvm::CodeGenFileType::CGFT_AssemblyFile);
|
|
}
|
|
|
|
auto CodeGen::EmitObject(llvm::raw_pwrite_stream& out) -> bool {
|
|
return EmitCode(out, llvm::CodeGenFileType::CGFT_ObjectFile);
|
|
}
|
|
|
|
auto CodeGen::EmitCode(llvm::raw_pwrite_stream& out,
|
|
llvm::CodeGenFileType file_type) -> bool {
|
|
module_.setDataLayout(target_machine_->createDataLayout());
|
|
|
|
// Using the legacy PM to generate the assembly since the new PM
|
|
// does not work with this yet.
|
|
// TODO: make the new PM work with the codegen pipeline.
|
|
llvm::legacy::PassManager pass;
|
|
// Note that this returns true on an error.
|
|
if (target_machine_->addPassesToEmitFile(pass, out, nullptr, file_type)) {
|
|
errors_ << "ERROR: Unable to emit to this file.\n";
|
|
return false;
|
|
}
|
|
|
|
pass.run(module_);
|
|
return true;
|
|
}
|
|
|
|
} // namespace Carbon
|