Author: Bruno Cardoso Lopes Date: 2026-10-08T13:54:00-07:00 New Revision: 986f4954120aae80201ff3187853c69db594d98c
URL: https://github.com/llvm/llvm-project/commit/986f4954120aae80201ff3187853c69db594d98c DIFF: https://github.com/llvm/llvm-project/commit/986f4954120aae80201ff3187853c69db594d98c.diff LOG: [CIR] Enable bytecode emission through the driver and cc1 (#229607) Teach the driver to serialize CIR directly to bytecode: new EmitCIRBC frontend action kind, `TY_CIRBC` (.cirbc) driver type, and EmitCIRBCAction writing the in-memory module with `mlir::writeBytecodeToFile` instead of printing text. `.cirbc` inputs map to the CIR language like .cir. Tests cover cc1 emission with magic-byte and read-back pins, .cir-input and .cirbc-input round trips, and driver forwarding, phase selection, default output name, and flag-implied pipeline selection. I started proper bytecode encoding support in #229586, so this is a step into using that through the driver. Added: clang/test/CIR/Driver/emit-cir-bc.c Modified: clang/include/clang/Basic/DiagnosticCodeGenKinds.td clang/include/clang/CIR/FrontendAction/CIRGenAction.h clang/include/clang/Driver/Types.def clang/include/clang/Frontend/FrontendOptions.h clang/include/clang/Options/Options.td clang/lib/CIR/FrontendAction/CIRGenAction.cpp clang/lib/CIR/FrontendAction/CMakeLists.txt clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Driver/Types.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/lib/Frontend/FrontendOptions.cpp clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp clang/test/CIR/emit-actions.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/DiagnosticCodeGenKinds.td b/clang/include/clang/Basic/DiagnosticCodeGenKinds.td index f135cc5df30574..c8b8bb38b20ea2 100644 --- a/clang/include/clang/Basic/DiagnosticCodeGenKinds.td +++ b/clang/include/clang/Basic/DiagnosticCodeGenKinds.td @@ -20,6 +20,9 @@ let Component = "CodeGen" in { def err_cir_to_cir_transform_failed : Error< "CIR-to-CIR transformation failed">, DefaultFatal; +def err_cir_bc_write_failed : Error< + "could not write ClangIR bytecode to output stream">, DefaultFatal; + def err_cir_verification_failed_pre_passes : Error< "CIR module verification error before running CIR-to-CIR passes">, DefaultFatal; diff --git a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h index f7ca27fa6b5a24..9f8bad248ea47e 100644 --- a/clang/include/clang/CIR/FrontendAction/CIRGenAction.h +++ b/clang/include/clang/CIR/FrontendAction/CIRGenAction.h @@ -33,6 +33,7 @@ class CIRGenAction : public clang::ASTFrontendAction { enum class OutputType { EmitAssembly, EmitCIR, + EmitCIRBC, EmitLLVM, EmitBC, EmitObj, @@ -74,6 +75,13 @@ class EmitCIRAction : public CIRGenAction { EmitCIRAction(mlir::MLIRContext *MLIRCtx = nullptr); }; +class EmitCIRBCAction : public CIRGenAction { + virtual void anchor(); + +public: + EmitCIRBCAction(mlir::MLIRContext *MLIRCtx = nullptr); +}; + class EmitLLVMAction : public CIRGenAction { virtual void anchor(); diff --git a/clang/include/clang/Driver/Types.def b/clang/include/clang/Driver/Types.def index 38ccdaaebe717e..dd9fe5053c8fa7 100644 --- a/clang/include/clang/Driver/Types.def +++ b/clang/include/clang/Driver/Types.def @@ -104,6 +104,7 @@ TYPE("lto-ir", LTO_IR, INVALID, "s", phases TYPE("lto-bc", LTO_BC, INVALID, "o", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("cir", CIR, INVALID, "cir", phases::Compile, phases::Backend, phases::Assemble, phases::Link) +TYPE("cir-bc", CIRBC, INVALID, "cirbc", phases::Compile, phases::Backend, phases::Assemble, phases::Link) // Misc. TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link) TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge) diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index cb32509aa09e2c..7e2b0936525662 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -68,6 +68,9 @@ enum ActionKind { /// Emit a .cir file EmitCIR, + /// Emit a .cirbc file (ClangIR bytecode). + EmitCIRBC, + /// Emit a .ll file. EmitLLVM, diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 2e6905a0d3065c..160c647286aac9 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3557,6 +3557,9 @@ defm clangir : BoolFOption<"clangir", BothFlags<[], [ClangOption, CC1Option], "">>; def emit_cir : Flag<["-"], "emit-cir">, Visibility<[ClangOption, CC1Option]>, Group<Action_Group>, HelpText<"Build ASTs and then lower to ClangIR">; +def emit_cir_bc : Flag<["-"], "emit-cir-bc">, + Visibility<[CC1Option]>, Group<Action_Group>, + HelpText<"Build ASTs and then emit ClangIR bytecode">; /// ClangIR-specific options - END def flto_EQ : Joined<["-"], "flto=">, diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp index 627e659f62ba8c..71a7a17146af3d 100644 --- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp +++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp @@ -8,6 +8,7 @@ #include "clang/CIR/FrontendAction/CIRGenAction.h" #include "CIRDiagnosticHandler.h" +#include "mlir/Bytecode/BytecodeWriter.h" #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/MLIRContext.h" #include "mlir/IR/OwningOpRef.h" @@ -48,6 +49,7 @@ static BackendAction getBackendActionFromOutputType(CIRGenAction::OutputType Action) { switch (Action) { case CIRGenAction::OutputType::EmitCIR: + case CIRGenAction::OutputType::EmitCIRBC: assert(false && "Unsupported output type for getBackendActionFromOutputType!"); break; // Unreachable, but fall through to report that @@ -194,6 +196,12 @@ class CIRGenConsumer : public clang::ASTConsumer { if (OutputStream && MlirModule) printCIRModule(MlirModule, *OutputStream); break; + case CIRGenAction::OutputType::EmitCIRBC: + if (OutputStream && MlirModule && + failed(mlir::writeBytecodeToFile(MlirModule, *OutputStream)) && + !CI.getDiagnostics().hasErrorOccurred()) + CI.getDiagnostics().Report(diag::err_cir_bc_write_failed); + break; case CIRGenAction::OutputType::EmitLLVM: case CIRGenAction::OutputType::EmitBC: case CIRGenAction::OutputType::EmitObj: @@ -433,6 +441,11 @@ void CIRGenAction::ExecuteAction() { // been through it, and its lowering passes are not idempotent. printCIRModule(*Module, *OS); break; + case OutputType::EmitCIRBC: + if (failed(mlir::writeBytecodeToFile(*Module, *OS)) && + !Diags.hasErrorOccurred()) + Diags.Report(diag::err_cir_bc_write_failed); + break; case OutputType::EmitLLVM: case OutputType::EmitBC: case OutputType::EmitObj: @@ -450,6 +463,8 @@ getOutputStream(CompilerInstance &CI, StringRef InFile, return CI.createDefaultOutputFile(false, InFile, "s"); case CIRGenAction::OutputType::EmitCIR: return CI.createDefaultOutputFile(false, InFile, "cir"); + case CIRGenAction::OutputType::EmitCIRBC: + return CI.createDefaultOutputFile(true, InFile, "cirbc"); case CIRGenAction::OutputType::EmitLLVM: return CI.createDefaultOutputFile(false, InFile, "ll"); case CIRGenAction::OutputType::EmitBC: @@ -481,6 +496,10 @@ void EmitCIRAction::anchor() {} EmitCIRAction::EmitCIRAction(mlir::MLIRContext *MLIRCtx) : CIRGenAction(OutputType::EmitCIR, MLIRCtx) {} +void EmitCIRBCAction::anchor() {} +EmitCIRBCAction::EmitCIRBCAction(mlir::MLIRContext *MLIRCtx) + : CIRGenAction(OutputType::EmitCIRBC, MLIRCtx) {} + void EmitLLVMAction::anchor() {} EmitLLVMAction::EmitLLVMAction(mlir::MLIRContext *MLIRCtx) : CIRGenAction(OutputType::EmitLLVM, MLIRCtx) {} diff --git a/clang/lib/CIR/FrontendAction/CMakeLists.txt b/clang/lib/CIR/FrontendAction/CMakeLists.txt index be46ce69659316..d19496939af60b 100644 --- a/clang/lib/CIR/FrontendAction/CMakeLists.txt +++ b/clang/lib/CIR/FrontendAction/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(clangCIRFrontendAction clangCodeGenUtils CIRRegisterAllDialects MLIRCIR + MLIRBytecodeWriter MLIRIR MLIRParser ) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 006c3d2f0044d2..a5bd672b8de478 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -4452,8 +4452,13 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<AnalyzeJobAction>(Input, types::TY_Plist); if (Args.hasArg(options::OPT_emit_ast)) return C.MakeAction<CompileJobAction>(Input, types::TY_AST); - if (Args.hasArg(options::OPT_emit_cir)) + if (Args.hasArg(options::OPT_emit_cir)) { + // Like -emit-llvm, -c selects the binary form; bare -emit-cir and + // -emit-cir -S keep emitting text. + if (Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S)) + return C.MakeAction<CompileJobAction>(Input, types::TY_CIRBC); return C.MakeAction<CompileJobAction>(Input, types::TY_CIR); + } if (Args.hasArg(options::OPT_module_file_info)) return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 2325e7cc552ef9..4c8530f01fd9a8 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -357,6 +357,9 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, case types::TY_PP_CXXModule: ClangType = "c++-cpp-output"; break; + case types::TY_CIRBC: + ClangType = "cir"; + break; default: ClangType = types::getTypeName(Input.getType()); break; @@ -5582,6 +5585,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, rewriteKind = RK_Fragile; } else if (JA.getType() == types::TY_CIR) { CmdArgs.push_back("-emit-cir"); + } else if (JA.getType() == types::TY_CIRBC) { + CmdArgs.push_back("-emit-cir-bc"); } else if (JA.getType() == types::TY_Image && IsAMDSPIRVForHIPDevice) { CmdArgs.push_back("-emit-obj"); } else { diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 4cca8acd515d7b..a3acdc97283084 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -171,6 +171,8 @@ bool types::isAcceptedByClang(ID Id) { case TY_PP_CXXStdModule: case TY_AST: case TY_ModuleFile: case TY_PCH: case TY_LLVM_IR: case TY_LLVM_BC: + case TY_CIR: + case TY_CIRBC: case TY_API_INFO: return true; } @@ -367,6 +369,8 @@ types::ID types::lookupTypeForExtension(llvm::StringRef Ext) { .Case("CPP", TY_CXX) .Case("c++", TY_CXX) .Case("C++", TY_CXX) + .Case("cir", TY_CIR) + .Case("cirbc", TY_CIRBC) .Case("cui", TY_PP_CUDA) .Case("cxx", TY_CXX) .Case("CXX", TY_CXX) diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 3d652a0304e21b..824b5d195098de 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2816,6 +2816,7 @@ static const auto &getFrontendActionTable() { {frontend::EmitAssembly, OPT_S}, {frontend::EmitBC, OPT_emit_llvm_bc}, {frontend::EmitCIR, OPT_emit_cir}, + {frontend::EmitCIRBC, OPT_emit_cir_bc}, {frontend::EmitHTML, OPT_emit_html}, {frontend::EmitLLVM, OPT_emit_llvm}, {frontend::EmitLLVMOnly, OPT_emit_llvm_only}, @@ -3179,7 +3180,7 @@ static bool ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, if (Opts.ProgramAction != frontend::GenerateModule && Opts.IsSystemModule) Diags.Report(diag::err_drv_argument_only_allowed_with) << "-fsystem-module" << "-emit-module"; - if (Args.hasArg(OPT_emit_cir)) + if (Args.hasArg(OPT_emit_cir, OPT_emit_cir_bc)) Opts.UseClangIRPipeline = true; #if CLANG_ENABLE_CIR @@ -4748,6 +4749,7 @@ static bool isStrictlyPreprocessorAction(frontend::ActionKind Action) { case frontend::EmitAssembly: case frontend::EmitBC: case frontend::EmitCIR: + case frontend::EmitCIRBC: case frontend::EmitHTML: case frontend::EmitLLVM: case frontend::EmitLLVMOnly: @@ -4789,6 +4791,7 @@ static bool isCodeGenAction(frontend::ActionKind Action) { case frontend::EmitAssembly: case frontend::EmitBC: case frontend::EmitCIR: + case frontend::EmitCIRBC: case frontend::EmitHTML: case frontend::EmitLLVM: case frontend::EmitLLVMOnly: diff --git a/clang/lib/Frontend/FrontendOptions.cpp b/clang/lib/Frontend/FrontendOptions.cpp index fb178b6b942e21..32db5306e35b51 100644 --- a/clang/lib/Frontend/FrontendOptions.cpp +++ b/clang/lib/Frontend/FrontendOptions.cpp @@ -35,6 +35,6 @@ InputKind FrontendOptions::getInputKindForExtension(StringRef Extension) { .Case("hip", Language::HIP) .Cases({"ll", "bc"}, Language::LLVM_IR) .Case("hlsl", Language::HLSL) - .Case("cir", Language::CIR) + .Cases({"cir", "cirbc"}, Language::CIR) .Default(Language::Unknown); } diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 24e699b42ca7fa..48d9e0acd3a781 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -56,10 +56,11 @@ CreateFrontendBaseAction(CompilerInstance &CI) { unsigned UseCIR = CI.getFrontendOpts().UseClangIRPipeline; frontend::ActionKind Act = CI.getFrontendOpts().ProgramAction; - bool EmitsCIR = Act == EmitCIR; + bool EmitsCIR = Act == EmitCIR || Act == EmitCIRBC; if (!UseCIR && EmitsCIR) - llvm::report_fatal_error("-emit-cir and only valid when using -fclangir"); + llvm::report_fatal_error( + "-emit-cir and -emit-cir-bc only valid when using -fclangir"); switch (CI.getFrontendOpts().ProgramAction) { case ASTDeclList: return std::make_unique<ASTDeclListAction>(); @@ -88,6 +89,13 @@ CreateFrontendBaseAction(CompilerInstance &CI) { #else CI.getDiagnostics().Report(diag::err_fe_cir_not_built); return nullptr; +#endif + case EmitCIRBC: +#if CLANG_ENABLE_CIR + return std::make_unique<cir::EmitCIRBCAction>(); +#else + CI.getDiagnostics().Report(diag::err_fe_cir_not_built); + return nullptr; #endif case EmitHTML: return std::make_unique<HTMLPrintAction>(); case EmitLLVM: { diff --git a/clang/test/CIR/Driver/emit-cir-bc.c b/clang/test/CIR/Driver/emit-cir-bc.c new file mode 100644 index 00000000000000..78bc4a3b9a6c14 --- /dev/null +++ b/clang/test/CIR/Driver/emit-cir-bc.c @@ -0,0 +1,28 @@ +// -emit-cir follows the -emit-llvm model: -c selects the binary form, +// bare -emit-cir and -emit-cir -S keep emitting text. -emit-cir-bc is +// cc1-only. + +// RUN: %clang -### -fclangir -emit-cir -c %s 2>&1 | FileCheck %s --check-prefix=BC +// BC: "-cc1" +// BC-SAME: "-emit-cir-bc" +// BC-SAME: "-o" "emit-cir-bc.cirbc" + +// RUN: %clang -ccc-print-phases -fclangir -emit-cir -c %s 2>&1 | FileCheck %s --check-prefix=PHASES +// PHASES: compiler, {{.*}}, cir-bc + +// RUN: %clang -### -fclangir -emit-cir %s 2>&1 | FileCheck %s --check-prefix=TEXT +// RUN: %clang -### -fclangir -emit-cir -S %s 2>&1 | FileCheck %s --check-prefix=TEXT +// TEXT: "-cc1" +// TEXT-SAME: "-emit-cir" +// TEXT-SAME: "-o" "emit-cir-bc.cir" + +// RUN: not %clang -fclangir -emit-cir-bc %s 2>&1 | FileCheck %s --check-prefix=REJECT +// REJECT: unknown argument '-emit-cir-bc' + +// The driver accepts .cirbc inputs, so bytecode round-trips through it. +// RUN: %clang -fclangir -emit-cir -c %s -o %t.cirbc +// RUN: %clang -fclangir -x cir-bc -emit-cir %t.cirbc -o - | FileCheck %s --check-prefix=ROUNDTRIP +// RUN: %clang -fclangir -emit-cir %t.cirbc -o - | FileCheck %s --check-prefix=ROUNDTRIP +// ROUNDTRIP: cir.func {{.*}}@foo() + +void foo() {} diff --git a/clang/test/CIR/emit-actions.cpp b/clang/test/CIR/emit-actions.cpp index 3cfb3d32e8e2c0..2e9e4d961dfabc 100644 --- a/clang/test/CIR/emit-actions.cpp +++ b/clang/test/CIR/emit-actions.cpp @@ -6,6 +6,17 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-obj %s -o %t.o // RUN: llvm-objdump -t %t.o | FileCheck %s -check-prefix=OBJ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir-bc %s -o %t.cirbc +// RUN: od -An -c -N4 %t.cirbc | FileCheck %s --check-prefix=CIRBC-MAGIC +// RUN: not grep -q "cir.global" %t.cirbc +// RUN: cir-opt %t.cirbc | FileCheck %s -check-prefix=CIRBC + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -x cir -emit-cir-bc %t.cir -o %t2.cirbc +// RUN: cir-opt %t2.cirbc | FileCheck %s --check-prefix=CIRBC + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %t.cirbc -o - | FileCheck %s --check-prefix=CIRBC + // TODO: Make this test target-independent // REQUIRES: x86-registered-target @@ -19,3 +30,7 @@ int x = 1; // OBJ: .data // OBJ-SAME: x + +// CIRBC-MAGIC: M L 357 R + +// CIRBC: cir.global {{.*}}@x = #cir.int<1> : !s32i _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
