diff --git a/include/vast/Frontend/Action.hpp b/include/vast/Frontend/Action.hpp index f01d831eec..81ed11eada 100644 --- a/include/vast/Frontend/Action.hpp +++ b/include/vast/Frontend/Action.hpp @@ -9,9 +9,9 @@ VAST_RELAX_WARNINGS VAST_UNRELAX_WARNINGS #include "vast/Util/Common.hpp" -#include "vast/Frontend/FrontendAction.hpp" #include "vast/Frontend/CompilerInstance.hpp" -#include "vast/CodeGen/Generator.hpp" +#include "vast/Frontend/FrontendAction.hpp" +#include "vast/Frontend/Options.hpp" namespace llvm { class LLVMIRContext; @@ -25,37 +25,17 @@ namespace mlir { namespace vast::cc { - namespace opt { - constexpr string_ref emit_llvm = "emit-llvm"; - constexpr string_ref emit_obj = "emit-obj"; - constexpr string_ref emit_asm = "emit-asm"; - - constexpr string_ref emit_mlir = "emit-mlir"; - - constexpr string_ref emit_locs = "emit-locs"; - - constexpr string_ref opt_pipeline = "pipeline"; - - constexpr string_ref disable_vast_verifier = "disable-vast-verifier"; - constexpr string_ref vast_verify_diags = "verify-diags"; - constexpr string_ref disable_emit_cxx_default = "disable-emit-cxx-default"; - - bool emit_only_mlir(const vast_args &vargs); - bool emit_only_llvm(const vast_args &vargs); - - } // namespace opt - - struct vast_gen_consumer; + struct vast_consumer; - struct vast_gen_action : frontend_action { - virtual ~vast_gen_action() = default; + struct vast_action : frontend_action { + virtual ~vast_action() = default; - vast_gen_consumer *consumer; + vast_consumer *consumer; output_type action; protected: - vast_gen_action(output_type action, const vast_args &vargs); + vast_action(output_type action, const vast_args &vargs); std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(compiler_instance &ci, string_ref input) override; @@ -65,7 +45,7 @@ namespace vast::cc { void EndSourceFileAction() override; private: - friend struct vast_gen_consumer; + friend struct vast_consumer; owning_module_ref mlir_module; @@ -79,7 +59,7 @@ namespace vast::cc { // // Emit assembly // - struct emit_assembly_action : vast_gen_action { + struct emit_assembly_action : vast_action { explicit emit_assembly_action(const vast_args &vargs); private: virtual void anchor(); @@ -88,7 +68,7 @@ namespace vast::cc { // // Emit LLVM // - struct emit_llvm_action : vast_gen_action { + struct emit_llvm_action : vast_action { explicit emit_llvm_action(const vast_args &vargs); private: virtual void anchor(); @@ -97,7 +77,7 @@ namespace vast::cc { // // Emit MLIR // - struct emit_mlir_action : vast_gen_action { + struct emit_mlir_action : vast_action { explicit emit_mlir_action(const vast_args &vargs); private: virtual void anchor(); @@ -106,7 +86,7 @@ namespace vast::cc { // // Emit obj // - struct emit_obj_action : vast_gen_action { + struct emit_obj_action : vast_action { explicit emit_obj_action(const vast_args &vargs); private: virtual void anchor(); diff --git a/include/vast/Frontend/Consumer.hpp b/include/vast/Frontend/Consumer.hpp new file mode 100644 index 0000000000..6f8dc480f5 --- /dev/null +++ b/include/vast/Frontend/Consumer.hpp @@ -0,0 +1,113 @@ +// Copyright (c) 2023-present, Trail of Bits, Inc. + +#pragma once + +#include "vast/Util/Warnings.hpp" + +VAST_RELAX_WARNINGS +#include +#include +VAST_UNRELAX_WARNINGS + +#include "vast/CodeGen/Generator.hpp" +#include "vast/Frontend/Diagnostics.hpp" +#include "vast/Frontend/FrontendAction.hpp" +#include "vast/Frontend/Options.hpp" + +namespace vast::cc { + + using virtual_file_system_ptr = llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem >; + + using output_stream_ptr = std::unique_ptr< llvm::raw_pwrite_stream >; + + using clang_ast_consumer = clang::ASTConsumer; + + // TODO: Introduce helper wrapper on top of `vast_args`? + enum class target_dialect { high_level, low_level, llvm }; + + using backend = clang::BackendAction; + + struct vast_consumer : clang_ast_consumer + { + using vast_generator_ptr = std::unique_ptr< cg::vast_generator >; + + vast_consumer( + output_type act, diagnostics_engine &diags, virtual_file_system_ptr vfs, + header_search_options &hopts, codegen_options &copts, target_options &topts, + language_options &lopts, + // frontend_options &fopts, + const vast_args &vargs, output_stream_ptr os + ) + : action(act) + , diags(diags) + , vfs(vfs) + , header_search_opts(hopts) + , codegen_opts(copts) + , target_opts(topts) + , lang_opts(lopts) + // , frontend_opts(fopts) + , vargs(vargs) + , output_stream(std::move(os)) + , generator(std::make_unique< cg::vast_generator >(diags, codegen_opts, lang_opts) + ) {} + + void Initialize(acontext_t &ctx) override; + + bool HandleTopLevelDecl(clang::DeclGroupRef decls) override; + + void HandleCXXStaticMemberVarInstantiation(clang::VarDecl * /* decl */) override; + + void HandleInlineFunctionDefinition(clang::FunctionDecl * /* decl */) override; + + void HandleInterestingDecl(clang::DeclGroupRef /* decl */) override; + + void HandleTranslationUnit(acontext_t &acontext) override; + + void HandleTagDeclDefinition(clang::TagDecl *decl) override; + + // void HandleTagDeclRequiredDefinition(clang::TagDecl */* decl */) override { + // VAST_UNIMPLEMENTED; + // } + + void CompleteTentativeDefinition(clang::VarDecl *decl) override; + + void CompleteExternalDeclaration(clang::VarDecl * /* decl */) override; + + void AssignInheritanceModel(clang::CXXRecordDecl * /* decl */) override; + + void HandleVTable(clang::CXXRecordDecl * /* decl */) override; + + private: + + void emit_backend_output( + backend backend_action, owning_module_ref mlir_module, mcontext_t *mctx + ); + + void emit_mlir_output(target_dialect target, owning_module_ref mod, mcontext_t *mctx); + + void compile_via_vast(vast_module mod, mcontext_t *mctx); + + virtual void anchor() {} + + output_type action; + + diagnostics_engine &diags; + + virtual_file_system_ptr vfs; + + // options + const header_search_options &header_search_opts; + const codegen_options &codegen_opts; + const target_options &target_opts; + const language_options &lang_opts; + // const frontend_options &frontend_opts; + + const vast_args &vargs; + + output_stream_ptr output_stream; + + acontext_t *acontext = nullptr; + + vast_generator_ptr generator; + }; +} // namespace vast::cc diff --git a/include/vast/Frontend/Options.hpp b/include/vast/Frontend/Options.hpp index 96569c3ba0..944331e82e 100644 --- a/include/vast/Frontend/Options.hpp +++ b/include/vast/Frontend/Options.hpp @@ -53,4 +53,23 @@ namespace vast::cc std::pair< vast_args, argv_storage > filter_args(const argv_storage_base &args); + namespace opt { + constexpr string_ref emit_llvm = "emit-llvm"; + constexpr string_ref emit_obj = "emit-obj"; + constexpr string_ref emit_asm = "emit-asm"; + + constexpr string_ref emit_mlir = "emit-mlir"; + + constexpr string_ref emit_locs = "emit-locs"; + + constexpr string_ref opt_pipeline = "pipeline"; + + constexpr string_ref disable_vast_verifier = "disable-vast-verifier"; + constexpr string_ref vast_verify_diags = "verify-diags"; + constexpr string_ref disable_emit_cxx_default = "disable-emit-cxx-default"; + + bool emit_only_mlir(const vast_args &vargs); + bool emit_only_llvm(const vast_args &vargs); + } // namespace opt + } // namespace vast::cc diff --git a/lib/vast/Frontend/Action.cpp b/lib/vast/Frontend/Action.cpp index cc6475f9ef..ec0a16cb73 100644 --- a/lib/vast/Frontend/Action.cpp +++ b/lib/vast/Frontend/Action.cpp @@ -1,23 +1,9 @@ // Copyright (c) 2023-present, Trail of Bits, Inc. #include "vast/Frontend/Action.hpp" -#include "vast/Util/Warnings.hpp" - -VAST_RELAX_WARNINGS -#include - -#include - -#include -#include -VAST_UNRELAX_WARNINGS #include "vast/Util/Common.hpp" -#include "vast/Frontend/Options.hpp" -#include "vast/Frontend/Diagnostics.hpp" -#include "vast/CodeGen/Passes.hpp" - -#include "vast/Target/LLVMIR/Convert.hpp" +#include "vast/Frontend/Consumer.hpp" namespace clang { class CXXRecordDecl; @@ -30,39 +16,39 @@ namespace clang { namespace vast::cc { namespace opt { - bool emit_only_mlir(const vast_args &vargs) { - for (auto arg : {emit_mlir}) { - if (vargs.has_option(arg)) + for (auto arg : { emit_mlir }) { + if (vargs.has_option(arg)) { return true; + } } return false; } - bool emit_only_llvm(const vast_args &vargs) { - return vargs.has_option(emit_llvm); - } + bool emit_only_llvm(const vast_args &vargs) { return vargs.has_option(emit_llvm); } } // namespace opt - using output_stream_ptr = std::unique_ptr< llvm::raw_pwrite_stream >; - static std::string get_output_stream_suffix(output_type act) { switch (act) { - case output_type::emit_assembly: return "s"; - case output_type::emit_mlir: return "mlir"; - case output_type::emit_llvm: return "ll"; - case output_type::emit_obj: return "o"; - case output_type::none: break; + case output_type::emit_assembly: + return "s"; + case output_type::emit_mlir: + return "mlir"; + case output_type::emit_llvm: + return "ll"; + case output_type::emit_obj: + return "o"; + case output_type::none: + break; } VAST_UNREACHABLE("unsupported action type"); } static auto get_output_stream(compiler_instance &ci, string_ref in, output_type act) - -> output_stream_ptr - { + -> output_stream_ptr { if (act == output_type::none) { return nullptr; } @@ -70,355 +56,36 @@ namespace vast::cc { return ci.createDefaultOutputFile(false, in, get_output_stream_suffix(act)); } - using virtual_file_system_ptr = llvm::IntrusiveRefCntPtr< llvm::vfs::FileSystem >; - - struct vast_gen_consumer : cg::clang_ast_consumer { - - using vast_generator_ptr = std::unique_ptr< cg::vast_generator >; - - vast_gen_consumer( - output_type act, - diagnostics_engine &diags, - virtual_file_system_ptr vfs, - header_search_options &hopts, - codegen_options &copts, - target_options &topts, - language_options &lopts, - // frontend_options &fopts, - const vast_args &vargs, - output_stream_ptr os - ) - : action(act) - , diags(diags) - , vfs(vfs) - , header_search_opts(hopts) - , codegen_opts(copts) - , target_opts(topts) - , lang_opts(lopts) - // , frontend_opts(fopts) - , vargs(vargs) - , output_stream(std::move(os)) - , generator(std::make_unique< cg::vast_generator >(diags, codegen_opts, lang_opts)) - {} - - void Initialize(acontext_t &ctx) override { - VAST_CHECK(!acontext, "initialized multiple times"); - acontext = &ctx; - generator->Initialize(ctx); - } - - bool HandleTopLevelDecl(clang::DeclGroupRef decls) override { - clang::PrettyStackTraceDecl crash_info( - *decls.begin(), clang::SourceLocation(), acontext->getSourceManager(), - "LLVM IR generation of declaration" - ); - return generator->HandleTopLevelDecl(decls); - } - - void HandleCXXStaticMemberVarInstantiation(clang::VarDecl * /* decl */) override { - VAST_UNIMPLEMENTED; - } - - void HandleInlineFunctionDefinition(clang::FunctionDecl * /* decl */) override { - VAST_UNIMPLEMENTED; - } - - void HandleInterestingDecl(clang::DeclGroupRef /* decl */) override { - VAST_UNIMPLEMENTED; - } - void emit_backend_output(clang::BackendAction backend_action, - owning_module_ref mlir_module, mcontext_t *mctx) - { - - llvm::LLVMContext llvm_context; - target::llvmir::register_vast_to_llvm_ir(*mctx); - auto pipeline = parse_pipeline(vargs.get_options_list(opt::opt_pipeline)); - target::llvmir::lower_hl_module(mlir_module.get(), pipeline); - - auto mod = target::llvmir::translate(mlir_module.get(), llvm_context, "tmp"); - - clang::EmitBackendOutput( - diags - , header_search_opts - , codegen_opts - , target_opts - , lang_opts - , acontext->getTargetInfo().getDataLayoutString() - , mod.get() - , backend_action - , vfs - , std::move(output_stream) - ); - } - - // TODO: Introduce helper wrapper on top of `vast_args`? - enum class target_dialect { - high_level - , low_level - , llvm - }; - - target_dialect parse_target_dialect(const vast_args::maybe_option_list &list) - { - if (!list) - return target_dialect::high_level; - - if (list->size() != 1) - VAST_UNREACHABLE("Can emit only one dialect."); - - return parse_target_dialect(list->front()); - } - - target::llvmir::pipeline parse_pipeline(const vast_args::maybe_option_list &list) - { - if (!list) - return target::llvmir::default_pipeline(); - - if (list->size() != 1) - VAST_UNREACHABLE("Cannot use more than one pipeline!"); - - return parse_pipeline(list->front()); - } - - target::llvmir::pipeline parse_pipeline(llvm::StringRef from) - { - auto trg = from.lower(); - if (trg == "with-abi") - return target::llvmir::pipeline::with_abi; - if (trg == "baseline") - return target::llvmir::pipeline::baseline; - - VAST_UNREACHABLE("Unknown option of pipeline to use: {0}", trg); - } - - target_dialect parse_target_dialect(llvm::StringRef from) - { - auto trg = from.lower(); - if (trg == "hl" || trg == "high_level") - return target_dialect::high_level; - if (trg == "ll" || trg == "low_level") - return target_dialect::low_level; - if (trg == "llvm") - return target_dialect::llvm; - VAST_UNREACHABLE("Unknown option of target dialect: {0}", trg); - } - - [[nodiscard]] static inline std::string to_string(target_dialect target) - { - switch (target) - { - case target_dialect::high_level: return "high_level"; - case target_dialect::low_level: return "low_level"; - case target_dialect::llvm: return "llvm"; - } - } - - void compile_via_vast(auto mod, mcontext_t *mctx) - { - const bool enable_vast_verifier = !vargs.has_option(opt::disable_vast_verifier); - auto pass = cg::emit_high_level_pass(mod, mctx, - acontext, enable_vast_verifier); - if (pass.failed()) - VAST_UNREACHABLE("codegen: MLIR pass manager fails when running vast passes"); - - } - - void emit_mlir_output(target_dialect target, owning_module_ref mod, mcontext_t *mctx) { - if (!output_stream || !mod) { - return; - } - - auto setup_pipeline_and_execute = [&] - { - switch (target) - { - case target_dialect::high_level: - break; - case target_dialect::llvm: - { - // TODO: These should probably be moved outside of `target::llvmir`. - target::llvmir::register_vast_to_llvm_ir(*mctx); - target::llvmir::lower_hl_module(mod.get()); - break; - } - default: - VAST_UNREACHABLE("Cannot emit {0}, missing support", to_string(target)); - } - }; - - - // Handle source manager properly given that lifetime analysis - // might emit warnings and remarks. - auto &src_mgr = acontext->getSourceManager(); - auto main_file_id = src_mgr.getMainFileID(); - - auto file_buff = llvm::MemoryBuffer::getMemBuffer( - src_mgr.getBufferOrFake(main_file_id) - ); - - llvm::SourceMgr mlir_src_mgr; - mlir_src_mgr.AddNewSourceBuffer(std::move(file_buff), llvm::SMLoc()); - - if (vargs.has_option(opt::vast_verify_diags)) { - mlir::SourceMgrDiagnosticVerifierHandler src_mgr_handler(mlir_src_mgr, mctx); - mctx->printOpOnDiagnostic(false); - setup_pipeline_and_execute(); - - // Verify the diagnostic handler to make sure that each of the - // diagnostics matched. - if (src_mgr_handler.verify().failed()) { - llvm::sys::RunInterruptHandlers(); - VAST_UNREACHABLE("failed mlir codegen"); - } - } else { - mlir::SourceMgrDiagnosticHandler src_mgr_handler(mlir_src_mgr, mctx); - setup_pipeline_and_execute(); - } - - // Emit remaining defaulted C++ methods - // if (!vargs.has_option(opt::disable_emit_cxx_default)) { - // generator->build_default_methods(); - // } - - // FIXME: we cannot roundtrip prettyForm=true right now. - mlir::OpPrintingFlags flags; - flags.enableDebugInfo( - vargs.has_option(opt::emit_locs), /* prettyForm */ true - ); - - mod->print(*output_stream, flags); - } - - void HandleTranslationUnit(acontext_t &acontext) override { - // Note that this method is called after `HandleTopLevelDecl` has already - // ran all over the top level decls. Here clang mostly wraps defered and - // global codegen, followed by running vast passes. - generator->HandleTranslationUnit(acontext); - - if (!vargs.has_option(opt::disable_vast_verifier)) { - if (!generator->verify_module()) { - VAST_UNREACHABLE("codegen: module verification error before running vast passes"); - } - } - - auto mod = generator->freeze(); - auto mctx = generator->take_context(); - - compile_via_vast(mod.get(), mctx.get()); - - switch (action) - { - case output_type::emit_assembly: - return emit_backend_output(clang::BackendAction::Backend_EmitAssembly, - std::move(mod), mctx.get()); - case output_type::emit_mlir: - { - auto trg = parse_target_dialect(vargs.get_options_list(opt::emit_mlir)); - return emit_mlir_output(trg, std::move(mod), mctx.get()); - } - case output_type::emit_llvm: - return emit_backend_output(clang::BackendAction::Backend_EmitLL, - std::move(mod), mctx.get()); - case output_type::emit_obj: - return emit_backend_output(clang::BackendAction::Backend_EmitObj, - std::move(mod), mctx.get()); - case output_type::none: break; - } - } + vast_action::vast_action(output_type act, const vast_args &vargs) + : action(act), vargs(vargs) {} - void HandleTagDeclDefinition(clang::TagDecl *decl) override { - clang::PrettyStackTraceDecl crash_info( - decl, clang::SourceLocation(), acontext->getSourceManager(), - "vast generation of declaration" - ); - - generator->HandleTagDeclDefinition(decl); - } - - // void HandleTagDeclRequiredDefinition(clang::TagDecl */* decl */) override { - // VAST_UNIMPLEMENTED; - // } - - void CompleteTentativeDefinition(clang::VarDecl *decl) override { - generator->CompleteTentativeDefinition(decl); - } - - void CompleteExternalDeclaration(clang::VarDecl */* decl */) override { - VAST_UNIMPLEMENTED; - } - - void AssignInheritanceModel(clang::CXXRecordDecl */* decl */) override { - VAST_UNIMPLEMENTED; - } - - void HandleVTable(clang::CXXRecordDecl */* decl */) override { - VAST_UNIMPLEMENTED; - } - - private: - virtual void anchor() {} - - output_type action; - - diagnostics_engine &diags; - - virtual_file_system_ptr vfs; - - // options - const header_search_options &header_search_opts; - const codegen_options &codegen_opts; - const target_options &target_opts; - const language_options &lang_opts; - // const frontend_options &frontend_opts; - - const vast_args &vargs; - - output_stream_ptr output_stream; - - acontext_t *acontext = nullptr; - - vast_generator_ptr generator; - }; - - vast_gen_action::vast_gen_action(output_type act, const vast_args &vargs) - : action(act), vargs(vargs) - {} - - owning_module_ref vast_gen_action::load_module(llvm::MemoryBufferRef /* mref */) { + owning_module_ref vast_action::load_module(llvm::MemoryBufferRef /* mref */) { VAST_UNIMPLEMENTED; } - void vast_gen_action::ExecuteAction() { + void vast_action::ExecuteAction() { // FIXME: if (getCurrentFileKind().getLanguage() != Language::CIR) this->ASTFrontendAction::ExecuteAction(); } - auto vast_gen_action::CreateASTConsumer(compiler_instance &ci, string_ref input) - -> std::unique_ptr< clang::ASTConsumer > - { + auto vast_action::CreateASTConsumer(compiler_instance &ci, string_ref input) + -> std::unique_ptr< clang::ASTConsumer > { auto out = ci.takeOutputStream(); if (!out) { out = get_output_stream(ci, input, action); } - auto result = std::make_unique< vast_gen_consumer >( - action - , ci.getDiagnostics() - , &ci.getVirtualFileSystem() - , ci.getHeaderSearchOpts() - , ci.getCodeGenOpts() - , ci.getTargetOpts() - , ci.getLangOpts() - // , ci.getFrontendOpts() - , vargs - , std::move(out) + auto result = std::make_unique< vast_consumer >( + action, ci.getDiagnostics(), &ci.getVirtualFileSystem(), ci.getHeaderSearchOpts(), + ci.getCodeGenOpts(), ci.getTargetOpts(), ci.getLangOpts(), // ci.getFrontendOpts() + vargs, std::move(out) ); consumer = result.get(); // Enable generating macro debug info only when debug info is not disabled and // also macrod ebug info is enabled - auto &cgo = ci.getCodeGenOpts(); + auto &cgo = ci.getCodeGenOpts(); auto nodebuginfo = llvm::codegenoptions::NoDebugInfo; if (cgo.getDebugInfo() != nodebuginfo && cgo.MacroDebugInfo) { VAST_UNIMPLEMENTED_MSG("Macro debug info not implemented"); @@ -427,10 +94,11 @@ namespace vast::cc { return result; } - void vast_gen_action::EndSourceFileAction() { + void vast_action::EndSourceFileAction() { // If the consumer creation failed, do nothing. - if (!getCompilerInstance().hasASTConsumer()) + if (!getCompilerInstance().hasASTConsumer()) { return; + } // TODO: pass the module around } @@ -439,28 +107,24 @@ namespace vast::cc { void emit_assembly_action::anchor() {} emit_assembly_action::emit_assembly_action(const vast_args &vargs) - : vast_gen_action(output_type::emit_assembly, vargs) - {} + : vast_action(output_type::emit_assembly, vargs) {} // emit_llvm void emit_llvm_action::anchor() {} emit_llvm_action::emit_llvm_action(const vast_args &vargs) - : vast_gen_action(output_type::emit_llvm, vargs) - {} + : vast_action(output_type::emit_llvm, vargs) {} // emit_mlir void emit_mlir_action::anchor() {} emit_mlir_action::emit_mlir_action(const vast_args &vargs) - : vast_gen_action(output_type::emit_mlir, vargs) - {} + : vast_action(output_type::emit_mlir, vargs) {} // emit_obj void emit_obj_action::anchor() {} emit_obj_action::emit_obj_action(const vast_args &vargs) - : vast_gen_action(output_type::emit_obj, vargs) - {} + : vast_action(output_type::emit_obj, vargs) {} } // namespace vast::cc diff --git a/lib/vast/Frontend/CMakeLists.txt b/lib/vast/Frontend/CMakeLists.txt index 75df062be0..a864b40b88 100644 --- a/lib/vast/Frontend/CMakeLists.txt +++ b/lib/vast/Frontend/CMakeLists.txt @@ -2,6 +2,7 @@ add_vast_library(Frontend Action.cpp + Consumer.cpp Options.cpp LINK_LIBS PUBLIC diff --git a/lib/vast/Frontend/Consumer.cpp b/lib/vast/Frontend/Consumer.cpp new file mode 100644 index 0000000000..b481619279 --- /dev/null +++ b/lib/vast/Frontend/Consumer.cpp @@ -0,0 +1,273 @@ +// Copyright (c) 2023-present, Trail of Bits, Inc. + +#include "vast/Frontend/Consumer.hpp" + +VAST_RELAX_WARNINGS +#include + +#include +#include +VAST_UNRELAX_WARNINGS + +#include "vast/CodeGen/Passes.hpp" +#include "vast/Target/LLVMIR/Convert.hpp" + +namespace vast::cc { + + namespace llvmir = target::llvmir; + + using pipeline = llvmir::pipeline; + + [[nodiscard]] target_dialect parse_target_dialect(const vast_args::maybe_option_list &list); + + [[nodiscard]] pipeline parse_pipeline(const vast_args::maybe_option_list &list); + + [[nodiscard]] pipeline parse_pipeline(string_ref from); + + [[nodiscard]] target_dialect parse_target_dialect(string_ref from); + + [[nodiscard]] std::string to_string(target_dialect target); + + void emit_mlir_output(target_dialect target, owning_module_ref mod, mcontext_t *mctx); + + void vast_consumer::Initialize(acontext_t &ctx) { + VAST_CHECK(!acontext, "initialized multiple times"); + acontext = &ctx; + generator->Initialize(ctx); + } + + bool vast_consumer::HandleTopLevelDecl(clang::DeclGroupRef decls) { + clang::PrettyStackTraceDecl crash_info( + *decls.begin(), clang::SourceLocation(), acontext->getSourceManager(), + "LLVM IR generation of declaration" + ); + return generator->HandleTopLevelDecl(decls); + } + + void vast_consumer::HandleCXXStaticMemberVarInstantiation(clang::VarDecl * /* decl */) { + VAST_UNIMPLEMENTED; + } + + void vast_consumer::HandleInlineFunctionDefinition(clang::FunctionDecl * /* decl */) { + VAST_UNIMPLEMENTED; + } + + void vast_consumer::HandleInterestingDecl(clang::DeclGroupRef /* decl */) { + VAST_UNIMPLEMENTED; + } + + void vast_consumer::HandleTranslationUnit(acontext_t &acontext) { + // Note that this method is called after `HandleTopLevelDecl` has already + // ran all over the top level decls. Here clang mostly wraps defered and + // global codegen, followed by running vast passes. + generator->HandleTranslationUnit(acontext); + + if (!vargs.has_option(opt::disable_vast_verifier)) { + if (!generator->verify_module()) { + VAST_UNREACHABLE("codegen: module verification error before running vast passes" + ); + } + } + + auto mod = generator->freeze(); + auto mctx = generator->take_context(); + + compile_via_vast(mod.get(), mctx.get()); + + switch (action) { + case output_type::emit_assembly: + return emit_backend_output( + backend::Backend_EmitAssembly, std::move(mod), mctx.get() + ); + case output_type::emit_mlir: { + auto trg = parse_target_dialect(vargs.get_options_list(opt::emit_mlir)); + return emit_mlir_output(trg, std::move(mod), mctx.get()); + } + case output_type::emit_llvm: + return emit_backend_output( + backend::Backend_EmitLL, std::move(mod), mctx.get() + ); + case output_type::emit_obj: + return emit_backend_output( + backend::Backend_EmitObj, std::move(mod), mctx.get() + ); + case output_type::none: + break; + } + } + + void vast_consumer::HandleTagDeclDefinition(clang::TagDecl *decl) { + clang::PrettyStackTraceDecl crash_info( + decl, clang::SourceLocation(), acontext->getSourceManager(), + "vast generation of declaration" + ); + + generator->HandleTagDeclDefinition(decl); + } + + // void vast_consumer::HandleTagDeclRequiredDefinition(clang::TagDecl */* decl */) { + // VAST_UNIMPLEMENTED; + // } + + void vast_consumer::CompleteTentativeDefinition(clang::VarDecl *decl) { + generator->CompleteTentativeDefinition(decl); + } + + void vast_consumer::CompleteExternalDeclaration(clang::VarDecl * /* decl */) { + VAST_UNIMPLEMENTED; + } + + void vast_consumer::AssignInheritanceModel(clang::CXXRecordDecl * /* decl */) { + VAST_UNIMPLEMENTED; + } + + void vast_consumer::HandleVTable(clang::CXXRecordDecl * /* decl */) { VAST_UNIMPLEMENTED; } + + void vast_consumer::emit_backend_output( + backend backend_action, owning_module_ref mlir_module, mcontext_t *mctx + ) { + llvm::LLVMContext llvm_context; + llvmir::register_vast_to_llvm_ir(*mctx); + auto pipeline = parse_pipeline(vargs.get_options_list(opt::opt_pipeline)); + llvmir::lower_hl_module(mlir_module.get(), pipeline); + + auto mod = llvmir::translate(mlir_module.get(), llvm_context, "tmp"); + + clang::EmitBackendOutput( + diags, header_search_opts, codegen_opts, target_opts, lang_opts, + acontext->getTargetInfo().getDataLayoutString(), mod.get(), backend_action, vfs, + std::move(output_stream) + ); + } + + void vast_consumer::emit_mlir_output( + target_dialect target, owning_module_ref mod, mcontext_t *mctx + ) { + if (!output_stream || !mod) { + return; + } + + auto setup_pipeline_and_execute = [&] { + switch (target) { + case target_dialect::high_level: + break; + case target_dialect::llvm: { + // TODO: These should probably be moved outside of `target::llvmir`. + llvmir::register_vast_to_llvm_ir(*mctx); + llvmir::lower_hl_module(mod.get()); + break; + } + default: + VAST_UNREACHABLE("Cannot emit {0}, missing support", to_string(target)); + } + }; + + // Handle source manager properly given that lifetime analysis + // might emit warnings and remarks. + auto &src_mgr = acontext->getSourceManager(); + auto main_file_id = src_mgr.getMainFileID(); + + auto file_buff = + llvm::MemoryBuffer::getMemBuffer(src_mgr.getBufferOrFake(main_file_id)); + + llvm::SourceMgr mlir_src_mgr; + mlir_src_mgr.AddNewSourceBuffer(std::move(file_buff), llvm::SMLoc()); + + if (vargs.has_option(opt::vast_verify_diags)) { + mlir::SourceMgrDiagnosticVerifierHandler src_mgr_handler(mlir_src_mgr, mctx); + mctx->printOpOnDiagnostic(false); + setup_pipeline_and_execute(); + + // Verify the diagnostic handler to make sure that each of the + // diagnostics matched. + if (src_mgr_handler.verify().failed()) { + llvm::sys::RunInterruptHandlers(); + VAST_UNREACHABLE("failed mlir codegen"); + } + } else { + mlir::SourceMgrDiagnosticHandler src_mgr_handler(mlir_src_mgr, mctx); + setup_pipeline_and_execute(); + } + + // Emit remaining defaulted C++ methods + // if (!vargs.has_option(opt::disable_emit_cxx_default)) { + // generator->build_default_methods(); + // } + + // FIXME: we cannot roundtrip prettyForm=true right now. + mlir::OpPrintingFlags flags; + flags.enableDebugInfo(vargs.has_option(opt::emit_locs), /* prettyForm */ true); + + mod->print(*output_stream, flags); + } + + void vast_consumer::compile_via_vast(vast_module mod, mcontext_t *mctx) { + const bool enable_vast_verifier = !vargs.has_option(opt::disable_vast_verifier); + auto pass = cg::emit_high_level_pass(mod, mctx, acontext, enable_vast_verifier); + if (pass.failed()) { + VAST_UNREACHABLE("codegen: MLIR pass manager fails when running vast passes"); + } + } + + target_dialect parse_target_dialect(const vast_args::maybe_option_list &list) { + if (!list) { + return target_dialect::high_level; + } + + if (list->size() != 1) { + VAST_UNREACHABLE("Can emit only one dialect."); + } + + return parse_target_dialect(list->front()); + } + + pipeline parse_pipeline(const vast_args::maybe_option_list &list) { + if (!list) { + return llvmir::default_pipeline(); + } + + if (list->size() != 1) { + VAST_UNREACHABLE("Cannot use more than one pipeline!"); + } + + return parse_pipeline(list->front()); + } + + pipeline parse_pipeline(string_ref from) { + auto trg = from.lower(); + if (trg == "with-abi") { + return pipeline::with_abi; + } + if (trg == "baseline") { + return pipeline::baseline; + } + + VAST_UNREACHABLE("Unknown option of pipeline to use: {0}", trg); + } + + target_dialect parse_target_dialect(string_ref from) { + auto trg = from.lower(); + if (trg == "hl" || trg == "high_level") { + return target_dialect::high_level; + } + if (trg == "ll" || trg == "low_level") { + return target_dialect::low_level; + } + if (trg == "llvm") { + return target_dialect::llvm; + } + VAST_UNREACHABLE("Unknown option of target dialect: {0}", trg); + } + + std::string to_string(target_dialect target) { + switch (target) { + case target_dialect::high_level: + return "high_level"; + case target_dialect::low_level: + return "low_level"; + case target_dialect::llvm: + return "llvm"; + } + } + +} // namespace vast::cc