diff --git a/src/frontend/cxx/frontend.cc b/src/frontend/cxx/frontend.cc index 0c258139..ea0b0ec5 100644 --- a/src/frontend/cxx/frontend.cc +++ b/src/frontend/cxx/frontend.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +44,12 @@ #include #include #include +#include #include +#include +#include +#include +#include #endif #include @@ -81,6 +87,10 @@ struct Frontend::Private { return cli.opt_emit_ir || cli.opt_emit_llvm || cli.opt_S || cli.opt_c; } + [[nodiscard]] auto needsLLVMIR() const -> bool { + return cli.opt_emit_llvm || cli.opt_S || cli.opt_c; + } + void prepare(); void preparePreprocessor(); void preprocess(); @@ -94,6 +104,8 @@ struct Frontend::Private { void generateIR(); void emitIR(); void emitLLVMIR(); + void emitCode(); + void emitObjectFile(); void printPreprocessedText(); void dumpMacros(std::ostream& out); @@ -109,7 +121,7 @@ struct Frontend::Private { #ifdef CXX_WITH_MLIR void withRawOutputStream( const std::optional& extension, - const std::function& action); + const std::function& action); #endif }; @@ -169,6 +181,7 @@ Frontend::Private::Private(Frontend& frontend, const CLI& cli, actions_.emplace_back([this]() { generateIR(); }); actions_.emplace_back([this]() { emitIR(); }); actions_.emplace_back([this]() { emitLLVMIR(); }); + actions_.emplace_back([this]() { emitCode(); }); } Frontend::Private::~Private() {} @@ -196,7 +209,7 @@ void Frontend::Private::withOutputStream( #ifdef CXX_WITH_MLIR void Frontend::Private::withRawOutputStream( const std::optional& extension, - const std::function& action) { + const std::function& action) { auto explicitOutput = cli.getSingle("-o"); if (explicitOutput == "-" || (!explicitOutput.has_value() && @@ -507,7 +520,7 @@ void Frontend::Private::emitIR() { } void Frontend::Private::emitLLVMIR() { - if (!cli.opt_emit_llvm) return; + if (!needsLLVMIR()) return; #ifdef CXX_WITH_MLIR if (!module_) return; @@ -522,9 +535,76 @@ void Frontend::Private::emitLLVMIR() { return; } + if (!cli.opt_emit_llvm) return; + shouldExit_ = true; + withRawOutputStream( ".ll", [&](llvm::raw_ostream& out) { llvmModule_->print(out, nullptr); }); + +#endif +} + +void Frontend::Private::emitCode() { + if (!cli.opt_S && !cli.opt_c) return; +#ifdef CXX_WITH_MLIR + llvm::InitializeAllAsmPrinters(); + + auto triple = toolchain_->memoryLayout()->triple(); + + std::string error; + auto target = llvm::TargetRegistry::lookupTarget(triple, error); + + if (!target) { + std::cerr << std::format("cxx: cannot find target for triple '{}': {}\n", + triple, error); + shouldExit_ = true; + exitStatus_ = EXIT_FAILURE; + return; + } + + llvm::TargetOptions opt; + + auto RM = std::optional(); + + auto targetMachine = + target->createTargetMachine(triple, "generic", "", opt, RM); + + if (!targetMachine) { + std::cerr << std::format("cxx: cannot create target machine for '{}': {}\n", + triple, error); + shouldExit_ = true; + exitStatus_ = EXIT_FAILURE; + return; + } + + std::string extension; + if (cli.opt_S) { + extension = ".s"; + } else if (cli.opt_c) { + extension = ".o"; + } + + withRawOutputStream(extension, [&](llvm::raw_pwrite_stream& out) { + llvm::legacy::PassManager pm; + + llvm::CodeGenFileType fileType; + if (cli.opt_S) { + fileType = llvm::CodeGenFileType::AssemblyFile; + } else { + fileType = llvm::CodeGenFileType::ObjectFile; + } + + if (targetMachine->addPassesToEmitFile(pm, out, nullptr, fileType)) { + std::cerr << "cxx: target machine cannot emit assembly\n"; + shouldExit_ = true; + exitStatus_ = EXIT_FAILURE; + return; + } + + pm.run(*llvmModule_); + out.flush(); + }); #endif } diff --git a/src/mlir/cxx/mlir/CMakeLists.txt b/src/mlir/cxx/mlir/CMakeLists.txt index 37a59f12..2a79fcfd 100644 --- a/src/mlir/cxx/mlir/CMakeLists.txt +++ b/src/mlir/cxx/mlir/CMakeLists.txt @@ -37,9 +37,14 @@ target_link_libraries(cxx-mlir PUBLIC MLIRLLVMToLLVMIRTranslation MLIRPass MLIRTargetLLVMIRExport + MLIRTargetLLVMIRImport MLIRTransforms ) +if (EMSCRIPTEN) + target_link_libraries(cxx-mlir PUBLIC LLVMWebAssemblyCodeGen) +endif() + target_compile_definitions(cxx-mlir PUBLIC CXX_WITH_MLIR) add_dependencies(cxx-mlir MLIRCxxOpsIncGen) diff --git a/src/mlir/cxx/mlir/CxxOps.td b/src/mlir/cxx/mlir/CxxOps.td index 27a311ce..bf704d59 100644 --- a/src/mlir/cxx/mlir/CxxOps.td +++ b/src/mlir/cxx/mlir/CxxOps.td @@ -30,7 +30,7 @@ def Cxx_Dialect : Dialect { let name = "cxx"; let cppNamespace = "mlir::cxx"; let useDefaultTypePrinterParser = 1; - let dependentDialects = ["mlir::cf::ControlFlowDialect" ]; + let dependentDialects = ["mlir::cf::ControlFlowDialect", "mlir::DLTIDialect", "mlir::LLVM::LLVMDialect"]; } class Cxx_Type traits = []> @@ -405,4 +405,4 @@ def Cxx_TodoStmtOp : Cxx_Op<"todo.stmt"> { let arguments = (ins StringProp:$message); let results = (outs); let assemblyFormat = "$message attr-dict"; -} \ No newline at end of file +} diff --git a/src/mlir/cxx/mlir/codegen_units.cc b/src/mlir/cxx/mlir/codegen_units.cc index 0a55ab3d..06955445 100644 --- a/src/mlir/cxx/mlir/codegen_units.cc +++ b/src/mlir/cxx/mlir/codegen_units.cc @@ -23,8 +23,21 @@ // cxx #include #include +#include +#include #include +// mlir +#include +#include +#include +#include +#include +#include +#include + +#include + namespace cxx { namespace { @@ -57,11 +70,44 @@ auto Codegen::operator()(UnitAST* ast) -> UnitResult { } auto Codegen::UnitVisitor::operator()(TranslationUnitAST* ast) -> UnitResult { + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + auto loc = gen.builder_.getUnknownLoc(); auto name = gen.unit_->fileName(); auto module = gen.builder_.create(loc, name); gen.builder_.setInsertionPointToStart(module.getBody()); + auto memoryLayout = gen.control()->memoryLayout(); + + auto triple = gen.control()->memoryLayout()->triple(); + + std::string error; + auto target = llvm::TargetRegistry::lookupTarget(triple, error); + + if (!target) { + cxx_runtime_error(std::format("failed to find target for triple '{}': {}", + triple, error)); + } + + llvm::TargetOptions opt; + + auto RM = std::optional(); + + auto targetMachine = + target->createTargetMachine(triple, "generic", "", opt, RM); + + auto llvmDataLayout = targetMachine->createDataLayout(); + + auto dataLayout = + mlir::translateDataLayout(llvmDataLayout, module->getContext()); + + module->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dataLayout); + + module->setAttr("cxx.triple", mlir::StringAttr::get(module->getContext(), + memoryLayout->triple())); + std::swap(gen.module_, module); ForEachExternalDefinition forEachExternalDefinition; diff --git a/src/mlir/cxx/mlir/cxx_dialect.cc b/src/mlir/cxx/mlir/cxx_dialect.cc index 899ae6e8..e0b4b026 100644 --- a/src/mlir/cxx/mlir/cxx_dialect.cc +++ b/src/mlir/cxx/mlir/cxx_dialect.cc @@ -23,7 +23,9 @@ // mlir #include #include +#include #include +#include #include #include #include diff --git a/src/mlir/cxx/mlir/cxx_dialect_conversions.cc b/src/mlir/cxx/mlir/cxx_dialect_conversions.cc index 0c9b8a52..b34b71c0 100644 --- a/src/mlir/cxx/mlir/cxx_dialect_conversions.cc +++ b/src/mlir/cxx/mlir/cxx_dialect_conversions.cc @@ -24,10 +24,13 @@ #include // mlir +#include #include +#include #include #include #include +#include #include #include #include @@ -1085,6 +1088,7 @@ class CxxToLLVMLoweringPass auto getArgument() const -> StringRef override { return "cxx-to-llvm"; } void getDependentDialects(DialectRegistry ®istry) const override { + registry.insert(); registry.insert(); } @@ -1097,9 +1101,6 @@ void CxxToLLVMLoweringPass::runOnOperation() { auto context = &getContext(); auto module = getOperation(); - // set up the data layout - DataLayout dataLayout(module); - // set up the type converter LLVMTypeConverter typeConverter{context}; diff --git a/src/parser/cxx/gcc_linux_toolchain.cc b/src/parser/cxx/gcc_linux_toolchain.cc index 6c472da3..822d25cc 100644 --- a/src/parser/cxx/gcc_linux_toolchain.cc +++ b/src/parser/cxx/gcc_linux_toolchain.cc @@ -32,8 +32,10 @@ GCCLinuxToolchain::GCCLinuxToolchain(Preprocessor* preprocessor, : Toolchain(preprocessor), arch_(std::move(arch)) { if (arch_ == "aarch64") { memoryLayout()->setSizeOfLongDouble(8); + memoryLayout()->setTriple("aarch64-linux"); } else if (arch_ == "x86_64") { memoryLayout()->setSizeOfLongDouble(16); + memoryLayout()->setTriple("x86_64-linux"); } else { cxx_runtime_error(std::format("Unsupported architecture: {}", arch_)); } diff --git a/src/parser/cxx/macos_toolchain.cc b/src/parser/cxx/macos_toolchain.cc index e1e8d1a9..f3f7bdc2 100644 --- a/src/parser/cxx/macos_toolchain.cc +++ b/src/parser/cxx/macos_toolchain.cc @@ -42,8 +42,10 @@ MacOSToolchain::MacOSToolchain(Preprocessor* preprocessor, std::string arch) if (arch_ == "aarch64") { memoryLayout()->setSizeOfLongDouble(8); + memoryLayout()->setTriple("aarch64-darwin"); } else if (arch_ == "x86_64") { memoryLayout()->setSizeOfLongDouble(16); + memoryLayout()->setTriple("x86_64-apple-darwin24.6.0"); } else { cxx_runtime_error(std::format("Unsupported architecture: {}", arch_)); } diff --git a/src/parser/cxx/memory_layout.cc b/src/parser/cxx/memory_layout.cc index 9417372b..6f32854e 100644 --- a/src/parser/cxx/memory_layout.cc +++ b/src/parser/cxx/memory_layout.cc @@ -326,4 +326,10 @@ auto MemoryLayout::alignmentOf(const Type* type) const return visit(AlignmentOf{*this}, type); } +auto MemoryLayout::triple() const -> const std::string& { return triple_; } + +void MemoryLayout::setTriple(std::string triple) { + triple_ = std::move(triple); +} + } // namespace cxx \ No newline at end of file diff --git a/src/parser/cxx/memory_layout.h b/src/parser/cxx/memory_layout.h index 9d53639d..78813258 100644 --- a/src/parser/cxx/memory_layout.h +++ b/src/parser/cxx/memory_layout.h @@ -50,12 +50,16 @@ class MemoryLayout { [[nodiscard]] auto alignmentOf(const Type* type) const -> std::optional; + [[nodiscard]] auto triple() const -> const std::string&; + void setTriple(std::string triple); + private: std::size_t bits_ = 0; std::size_t sizeOfPointer_ = 0; std::size_t sizeOfLong_ = 0; std::size_t sizeOfLongLong_ = 0; std::size_t sizeOfLongDouble_ = 0; + std::string triple_; }; #undef DECLARE_METHOD diff --git a/src/parser/cxx/wasm32_wasi_toolchain.cc b/src/parser/cxx/wasm32_wasi_toolchain.cc index 654d3176..e7f7cc74 100644 --- a/src/parser/cxx/wasm32_wasi_toolchain.cc +++ b/src/parser/cxx/wasm32_wasi_toolchain.cc @@ -34,6 +34,7 @@ Wasm32WasiToolchain::Wasm32WasiToolchain(Preprocessor* preprocessor) setMemoryLayout(std::make_unique(32)); memoryLayout()->setSizeOfLongDouble(16); memoryLayout()->setSizeOfLongLong(8); + memoryLayout()->setTriple("wasm32"); } auto Wasm32WasiToolchain::appdir() const -> const std::string& { diff --git a/src/parser/cxx/windows_toolchain.cc b/src/parser/cxx/windows_toolchain.cc index 723f8b8a..29042570 100644 --- a/src/parser/cxx/windows_toolchain.cc +++ b/src/parser/cxx/windows_toolchain.cc @@ -37,6 +37,14 @@ WindowsToolchain::WindowsToolchain(Preprocessor *preprocessor, memoryLayout()->setSizeOfLongLong(8); memoryLayout()->setSizeOfLongDouble(8); memoryLayout()->setSizeOfPointer(8); + + if (arch_ == "aarch64") { + memoryLayout()->setTriple("aarch64-windows"); + } else if (arch_ == "x86_64") { + memoryLayout()->setTriple("x86_64-windows"); + } else { + cxx_runtime_error(std::format("Unsupported architecture: {}", arch_)); + } } void WindowsToolchain::setVctoolsdir(std::string path) {