diff --git a/xls/codegen/codegen_options.h b/xls/codegen/codegen_options.h index ca5b9321cf..aa17d09d69 100644 --- a/xls/codegen/codegen_options.h +++ b/xls/codegen/codegen_options.h @@ -16,6 +16,7 @@ #define XLS_CODEGEN_CODEGEN_OPTIONS_H_ #include +#include #include #include #include @@ -37,11 +38,32 @@ namespace xls::verilog { +class CodegenOptionExtension { + public: + virtual ~CodegenOptionExtension() = default; + virtual std::string_view extension_name() const = 0; +}; + // Options describing how codegen should be performed. class CodegenOptions { public: explicit CodegenOptions() = default; + template + const T* get_extension() const { + for (const auto& ext : extensions_) { + if (ext->extension_name() == T::kExtensionName) { + return static_cast(ext.get()); + } + } + return nullptr; + } + + CodegenOptions& add_extension(std::unique_ptr ext) { + extensions_.push_back(std::move(ext)); + return *this; + } + // Enum to describe which codegen version to use. enum class Version : uint8_t { kDefault = 0, @@ -461,6 +483,7 @@ class CodegenOptions { int64_t max_trace_verbosity_ = 0; RegisterMergeStrategy register_merge_strategy_ = RegisterMergeStrategy::kDefault; + SourceAnnotationStrategy source_annotation_strategy_ = SourceAnnotationStrategy::kNone; std::optional package_interface_; @@ -474,6 +497,8 @@ class CodegenOptions { std::vector randomize_order_seed_; std::optional residual_data_; std::optional ir_dump_path_; + + std::vector> extensions_; }; template diff --git a/xls/tools/BUILD b/xls/tools/BUILD index 200491d2c4..42b74891c0 100644 --- a/xls/tools/BUILD +++ b/xls/tools/BUILD @@ -725,6 +725,7 @@ cc_library( hdrs = ["codegen_flags.h"], deps = [ ":codegen_flags_cc_proto", + ":codegen_flags_handler_registry", "//xls/codegen:codegen_residual_data_cc_proto", "//xls/common/file:filesystem", "//xls/common/status:ret_check", @@ -765,12 +766,25 @@ cc_library( ], ) +cc_library( + name = "codegen_flags_handler_registry", + srcs = ["codegen_flags_handler_registry.cc"], + hdrs = ["codegen_flags_handler_registry.h"], + deps = [ + ":codegen_flags_cc_proto", + "//xls/codegen:codegen_options", + "//xls/common/status:status_macros", + "@com_google_absl//absl/status", + ], +) + cc_library( name = "codegen", srcs = ["codegen.cc"], hdrs = ["codegen.h"], deps = [ ":codegen_flags_cc_proto", + ":codegen_flags_handler_registry", ":schedule", ":scheduling_options_flags_cc_proto", "//xls/codegen:block_metrics", diff --git a/xls/tools/codegen.cc b/xls/tools/codegen.cc index 8a6b656c10..d96c74a69d 100644 --- a/xls/tools/codegen.cc +++ b/xls/tools/codegen.cc @@ -53,6 +53,7 @@ #include "xls/scheduling/scheduling_options.h" #include "xls/scheduling/scheduling_result.h" #include "xls/tools/codegen_flags.pb.h" +#include "xls/tools/codegen_flags_handler_registry.h" #include "xls/tools/schedule.h" #include "xls/tools/scheduling_options_flags.pb.h" @@ -455,6 +456,7 @@ absl::StatusOr CodegenOptionsFromProto( options.set_ir_dump_path(p.ir_dump_path()); } + XLS_RETURN_IF_ERROR(CodegenFlagsHandlerRegistry::Process(p, options)); return options; } diff --git a/xls/tools/codegen_flags.cc b/xls/tools/codegen_flags.cc index 2f16a6e914..129c1766f9 100644 --- a/xls/tools/codegen_flags.cc +++ b/xls/tools/codegen_flags.cc @@ -37,6 +37,7 @@ #include "xls/common/status/status_macros.h" #include "xls/ir/xls_ir_interface.pb.h" #include "xls/tools/codegen_flags.pb.h" +#include "xls/tools/codegen_flags_handler_registry.h" // LINT.IfChange ABSL_FLAG( @@ -438,6 +439,7 @@ static absl::StatusOr SetOptionsFromFlags(CodegenFlagsProto& proto) { POPULATE_FLAG(array_index_bounds_checking); POPULATE_FLAG(fifo_module); POPULATE_FLAG(nodata_fifo_module); + if (absl::GetFlag(FLAGS_materialize_internal_fifos)) { any_flags_set = true; if (!FLAGS_fifo_module.IsSpecifiedOnCommandLine()) { @@ -451,6 +453,7 @@ static absl::StatusOr SetOptionsFromFlags(CodegenFlagsProto& proto) { "--materialize_internal_fifos."; } } + XLS_ASSIGN_OR_RETURN( RegisterMergeStrategyProto merge_strategy, MergeStrategyFromString(absl::GetFlag(FLAGS_register_merge_strategy))); @@ -514,6 +517,7 @@ absl::StatusOr GetCodegenFlags() { XLS_RETURN_IF_ERROR(xls::ParseTextProtoFile( absl::GetFlag(FLAGS_codegen_options_proto), &proto)); } + XLS_RETURN_IF_ERROR(CodegenFlagsHandlerRegistry::ParseFlags(proto)); if (absl::GetFlag(FLAGS_codegen_options_used_textproto_file)) { XLS_RETURN_IF_ERROR(SetTextProtoFile( *absl::GetFlag(FLAGS_codegen_options_used_textproto_file), proto)); diff --git a/xls/tools/codegen_flags.proto b/xls/tools/codegen_flags.proto index cc561bc7ae..257d73be58 100644 --- a/xls/tools/codegen_flags.proto +++ b/xls/tools/codegen_flags.proto @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -syntax = "proto3"; +edition = "2023"; package xls; @@ -56,55 +56,55 @@ enum CodegenVersionProto { // // See codegen_flags.cc ABSL_FLAG() definitions for the meaning of these fields. message CodegenFlagsProto { - optional string top = 1; - optional GeneratorKind generator = 2; - optional string input_valid_signal = 3; - optional string output_valid_signal = 4; - optional string manual_load_enable_signal = 5; - optional bool flop_inputs = 6; - optional bool flop_outputs = 7; - optional IOKindProto flop_inputs_kind = 8; - optional IOKindProto flop_outputs_kind = 9; - optional bool flop_single_value_channels = 10; - optional bool add_idle_output = 11; - optional string module_name = 12; - optional string output_port_name = 13; - optional string reset = 14; - optional bool reset_active_low = 15; - optional bool reset_asynchronous = 16; - optional bool reset_data_path = 17; - optional bool use_system_verilog = 18; - optional bool separate_lines = 19; - optional int64 max_inline_depth = 35; - optional string gate_format = 20; - optional string assert_format = 21; - optional string smulp_format = 22; - optional string umulp_format = 23; - optional string streaming_channel_data_suffix = 24; - optional string streaming_channel_valid_suffix = 25; - optional string streaming_channel_ready_suffix = 26; + string top = 1; + GeneratorKind generator = 2; + string input_valid_signal = 3; + string output_valid_signal = 4; + string manual_load_enable_signal = 5; + bool flop_inputs = 6; + bool flop_outputs = 7; + IOKindProto flop_inputs_kind = 8; + IOKindProto flop_outputs_kind = 9; + bool flop_single_value_channels = 10; + bool add_idle_output = 11; + string module_name = 12; + string output_port_name = 13; + string reset = 14; + bool reset_active_low = 15; + bool reset_asynchronous = 16; + bool reset_data_path = 17; + bool use_system_verilog = 18; + bool separate_lines = 19; + int64 max_inline_depth = 35; + string gate_format = 20; + string assert_format = 21; + string smulp_format = 22; + string umulp_format = 23; + string streaming_channel_data_suffix = 24; + string streaming_channel_valid_suffix = 25; + string streaming_channel_ready_suffix = 26; repeated string ram_configurations = 27; - optional bool gate_recvs = 28; - optional bool array_index_bounds_checking = 29; - optional RegisterMergeStrategyProto register_merge_strategy = 30; - optional int64 max_trace_verbosity = 31; + bool gate_recvs = 28; + bool array_index_bounds_checking = 29; + RegisterMergeStrategyProto register_merge_strategy = 30; + int64 max_trace_verbosity = 31; // If present details about the interface requested. Eg specific sv types to // use for arguments etc. Only the 'top' and channels are interpreted. Unknown // interface elements are ignored. - optional PackageInterfaceProto package_interface = 32; + PackageInterfaceProto package_interface = 32; // Should annotated arguments be emitted with the sv_types they are annotated // with. - optional bool emit_sv_types = 33; + bool emit_sv_types = 33; - optional string simulation_macro_name = 34; + string simulation_macro_name = 34; repeated string assertion_macro_names = 39; - optional CodegenVersionProto codegen_version = 36; + CodegenVersionProto codegen_version = 36; // Which module to use for FIFOs. If empty, will materialize an internal // implementation. - optional string fifo_module = 40; - optional string nodata_fifo_module = 41; + string fifo_module = 40; + string nodata_fifo_module = 41; // If present, the seed used to randomize the order of lines in the output. If // empty, will use a default order. This can be useful for creating multiple @@ -113,14 +113,17 @@ message CodegenFlagsProto { // If false, runtime invariant assertions (e.g. one-hot selector checks) // are omitted from generated RTL. Default is true. - optional bool add_invariant_assertions = 42; + bool add_invariant_assertions = 42; // Parsed reference residual data. When present, codegen uses this to // influence emission order; preferred over reading from a path at runtime. - optional verilog.CodegenResidualData reference_residual_data = 43; + verilog.CodegenResidualData reference_residual_data = 43; - optional SourceAnnotationStrategyProto source_annotation_strategy = 44; + SourceAnnotationStrategyProto source_annotation_strategy = 44; // Debugging flag to cause the block conversion to dump its pass results. - optional string ir_dump_path = 45; + string ir_dump_path = 45; + + // Space for pass-specific configuration extensions. + extensions 20000 to max; } diff --git a/xls/tools/codegen_flags_handler_registry.cc b/xls/tools/codegen_flags_handler_registry.cc new file mode 100644 index 0000000000..5d3c5c5bad --- /dev/null +++ b/xls/tools/codegen_flags_handler_registry.cc @@ -0,0 +1,65 @@ +// Copyright 2026 The XLS Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "xls/tools/codegen_flags_handler_registry.h" + +#include +#include +#include + +#include "absl/status/status.h" +#include "xls/codegen/codegen_options.h" +#include "xls/common/status/status_macros.h" +#include "xls/tools/codegen_flags.pb.h" + +namespace xls { +namespace { + +struct RegisteredHandler { + std::string_view name; + CodegenFlagsHandler handler; + CodegenFlagsParser parser; +}; + +std::vector& GetRegistry() { + static auto* registry = new std::vector(); + return *registry; +} + +} // namespace + +void CodegenFlagsHandlerRegistry::Register(std::string_view name, + CodegenFlagsHandler handler, + CodegenFlagsParser parser) { + GetRegistry().push_back({name, std::move(handler), std::move(parser)}); +} + +absl::Status CodegenFlagsHandlerRegistry::ParseFlags(CodegenFlagsProto& proto) { + for (const auto& registered : GetRegistry()) { + if (registered.parser != nullptr) { + XLS_RETURN_IF_ERROR(registered.parser(proto)); + } + } + return absl::OkStatus(); +} + +absl::Status CodegenFlagsHandlerRegistry::Process( + const CodegenFlagsProto& proto, verilog::CodegenOptions& options) { + for (const auto& registered : GetRegistry()) { + XLS_RETURN_IF_ERROR(registered.handler(proto, options)); + } + return absl::OkStatus(); +} + +} // namespace xls diff --git a/xls/tools/codegen_flags_handler_registry.h b/xls/tools/codegen_flags_handler_registry.h new file mode 100644 index 0000000000..e54f3331eb --- /dev/null +++ b/xls/tools/codegen_flags_handler_registry.h @@ -0,0 +1,86 @@ +// Copyright 2026 The XLS Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef XLS_TOOLS_CODEGEN_FLAGS_HANDLER_REGISTRY_H_ +#define XLS_TOOLS_CODEGEN_FLAGS_HANDLER_REGISTRY_H_ + +#include +#include + +#include "absl/status/status.h" +#include "xls/codegen/codegen_options.h" +#include "xls/tools/codegen_flags.pb.h" + +namespace xls { + +using CodegenFlagsHandler = std::function; +using CodegenFlagsParser = std::function; + +// Registry to manage custom codegen option extensions. +// Enables downstream pass modules to register flag-parsing hooks and options +// handler callbacks. At runtime, the registry parses command-line flags into +// The CodegenFlagsProto (keeping them trackable/serializable) and then +// configures the C++ verilog::CodegenOptions container. +// +// Expected usage: +// 1. Declare proto extension fields on CodegenFlagsProto in a local proto file. +// 2. Define custom properties in a verilog::CodegenOptionExtension C++ struct. +// 3. Register your pass handlers using the registration macro helper. +// +// Example registration: +// ABSL_FLAG(std::string, my_pass_config, "none", "My pass setting"); +// +// absl::Status MyHandler(const CodegenFlagsProto& proto, +// verilog::CodegenOptions& options) { +// if (proto.HasExtension(my_extension_id)) { +// options.add_extension(std::make_unique(...)); +// } +// return absl::OkStatus(); +// } +// +// absl::Status MyParser(CodegenFlagsProto& proto) { +// std::string val = absl::GetFlag(FLAGS_my_pass_config); +// if (val != "none") { +// proto.SetExtension(my_extension_id, val); +// } +// return absl::OkStatus(); +// } +// +// XLS_REGISTER_CODEGEN_FLAGS_HANDLER("my_pass", MyHandler, MyParser); +class CodegenFlagsHandlerRegistry { + public: + static void Register(std::string_view name, CodegenFlagsHandler handler, + CodegenFlagsParser parser); + static absl::Status ParseFlags(CodegenFlagsProto& proto); + static absl::Status Process(const CodegenFlagsProto& proto, + verilog::CodegenOptions& options); +}; + +#define XLS_REGISTER_CODEGEN_FLAGS_HANDLER(name, handler, parser) \ + XLS_REGISTER_CODEGEN_FLAGS_HANDLER_UNIQHelper(__LINE__, name, handler, parser) + +#define XLS_REGISTER_CODEGEN_FLAGS_HANDLER_UNIQHelper(line, name, handler, \ + parser) \ + XLS_REGISTER_CODEGEN_FLAGS_HANDLER_UNIQ(line, name, handler, parser) + +#define XLS_REGISTER_CODEGEN_FLAGS_HANDLER_UNIQ(line, name, handler, parser) \ + static bool const registrator_##line = []() { \ + ::xls::CodegenFlagsHandlerRegistry::Register(name, handler, parser); \ + return true; \ + }(); + +} // namespace xls + +#endif // XLS_TOOLS_CODEGEN_FLAGS_HANDLER_REGISTRY_H_