From 4fcec8425f4e402b48770ea8d9c30583bbee5f8b Mon Sep 17 00:00:00 2001 From: XLS Team Date: Wed, 13 May 2026 14:23:31 -0700 Subject: [PATCH] Internal only change PiperOrigin-RevId: 915057233 --- xls/build_rules/BUILD | 23 +++ xls/build_rules/xls_dslx_common.bzl | 70 +++++++++ xls/build_rules/xls_dslx_rules.bzl | 230 +--------------------------- xls/build_rules/xls_dslx_test.bzl | 208 +++++++++++++++++++++++++ xls/build_rules/xls_ir_rules.bzl | 3 +- xls/build_rules/xls_rules.bzl | 2 +- 6 files changed, 308 insertions(+), 228 deletions(-) create mode 100644 xls/build_rules/xls_dslx_common.bzl create mode 100644 xls/build_rules/xls_dslx_test.bzl diff --git a/xls/build_rules/BUILD b/xls/build_rules/BUILD index 9d0fa1c254..2193e52b5a 100644 --- a/xls/build_rules/BUILD +++ b/xls/build_rules/BUILD @@ -111,6 +111,8 @@ bzl_library( deps = [ ":xls_common_rules_bzl", ":xls_config_rules_bzl", + ":xls_dslx_common_bzl", + ":xls_dslx_test_bzl", ":xls_providers_bzl", ":xls_toolchains_bzl", "@bazel_skylib//lib:dicts", @@ -124,6 +126,7 @@ bzl_library( deps = [ ":xls_common_rules_bzl", ":xls_config_rules_bzl", + ":xls_dslx_common_bzl", ":xls_dslx_rules_bzl", ":xls_providers_bzl", ":xls_toolchains_bzl", @@ -209,6 +212,7 @@ bzl_library( ":xls_common_rules_bzl", ":xls_config_rules_bzl", ":xls_dslx_rules_bzl", + ":xls_dslx_test_bzl", ":xls_ir_rules_bzl", ":xls_providers_bzl", ":xls_toolchains_bzl", @@ -345,6 +349,25 @@ bzl_library( ], ) +bzl_library( + name = "xls_dslx_test_bzl", + srcs = ["xls_dslx_test.bzl"], + visibility = ["//visibility:private"], + deps = [ + ":xls_common_rules_bzl", + ":xls_dslx_common_bzl", + ":xls_toolchains_bzl", + "@bazel_skylib//lib:dicts", + ], +) + +bzl_library( + name = "xls_dslx_common_bzl", + srcs = ["xls_dslx_common.bzl"], + visibility = ["//visibility:private"], + deps = [":xls_providers_bzl"], +) + xls_toolchain( name = "default_xls_toolchain", visibility = ["//xls:xls_public"], diff --git a/xls/build_rules/xls_dslx_common.bzl b/xls/build_rules/xls_dslx_common.bzl new file mode 100644 index 0000000000..07ff9925dd --- /dev/null +++ b/xls/build_rules/xls_dslx_common.bzl @@ -0,0 +1,70 @@ +# 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. + +"""This module contains common functions for DSLX build rules for XLS.""" + +load( + "//xls/build_rules:xls_providers.bzl", + "DslxInfo", +) + +visibility(["//xls/build_rules/..."]) + +xls_dslx_library_as_input_attrs = { + "library": attr.label( + doc = "A DSLX library target where the direct (non-transitive) " + + "files of the target are tested. This attribute is mutually " + + "exclusive with the 'srcs' and 'deps' attribute.", + providers = [DslxInfo], + ), + "srcs": attr.label_list( + doc = "Source files for the rule. The files must have a '.x' " + + "extension. This attribute is mutually exclusive with the " + + "'library' attribute.", + allow_files = [".x"], + ), + "deps": attr.label_list( + doc = "Dependency targets for the files in the 'srcs' attribute. " + + "This attribute is mutually exclusive with the 'library' " + + "attribute.", + providers = [DslxInfo], + ), +} + +def get_src_files_from_dslx_library_as_input(ctx): + """Returns the DSLX source files of rules using 'xls_dslx_library_as_input_attrs'. + + Args: + ctx: The current rule's context object. + + Returns: + Returns the DSLX source files of rules using 'xls_dslx_library_as_input_attrs'. + """ + dslx_src_files = [] + count = 0 + + if ctx.attr.library: + dslx_info = ctx.attr.library[DslxInfo] + dslx_src_files = dslx_info.target_dslx_source_files + count += 1 + if ctx.attr.srcs or ctx.attr.deps: + if not ctx.attr.srcs: + fail("'srcs' must be defined when 'deps' is defined.") + dslx_src_files = ctx.files.srcs + count += 1 + + if count != 1: + fail("One of: 'library' or ['srcs', 'deps'] must be assigned.") + + return dslx_src_files diff --git a/xls/build_rules/xls_dslx_rules.bzl b/xls/build_rules/xls_dslx_rules.bzl index 2d6df85362..315a03a439 100644 --- a/xls/build_rules/xls_dslx_rules.bzl +++ b/xls/build_rules/xls_dslx_rules.bzl @@ -19,13 +19,12 @@ load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") load( "//xls/build_rules:xls_common_rules.bzl", "append_cmd_line_args_to", - "append_default_to_args", "args_to_string", "get_runfiles_for_xls", "get_transitive_built_files_for_xls", - "is_args_valid", ) load("//xls/build_rules:xls_config_rules.bzl", "CONFIG") +load("//xls/build_rules:xls_dslx_common.bzl", "get_src_files_from_dslx_library_as_input", "xls_dslx_library_as_input_attrs") load( "//xls/build_rules:xls_providers.bzl", "DslxInfo", @@ -34,15 +33,15 @@ load( "//xls/build_rules:xls_toolchains.bzl", "xls_toolchain_attrs", ) +load( + ":xls_dslx_test.bzl", + _xls_dslx_test = "xls_dslx_test", +) _H_FILE_EXTENSION = ".h" _CC_FILE_EXTENSION = ".cc" _SV_FILE_EXTENSION = ".sv" -_DEFAULT_DSLX_TEST_ARGS = { - "compare": "none", -} - def get_transitive_dslx_srcs_files_depset(srcs, deps): """Returns a depset representing the transitive DSLX source files. @@ -81,79 +80,6 @@ def get_transitive_dslx_placeholder_files_depset(srcs, deps): transitive = [dep[DslxInfo].dslx_placeholder_files for dep in deps], ) -def _get_dslx_test_cmdline(ctx, src, all_srcs, append_cmd_line_args = True): - """Returns the command that executes in the xls_dslx_test rule. - - Args: - ctx: The current rule's context object. - src: The file to test. - all_srcs: All dslx sources, including dependencies as part of the test. - append_cmd_line_args: Flag controlling appending the command-line - arguments invoking the command generated by this function. When set to - True, the command-line arguments invoking the command are appended. - Otherwise, the command-line arguments are not appended. - - Returns: - The command that executes in the xls_dslx_test rule. - """ - dslx_interpreter_tool = ctx.executable._xls_dslx_interpreter_tool - _dslx_test_args = append_default_to_args( - ctx.attr.dslx_test_args, - _DEFAULT_DSLX_TEST_ARGS, - ) - - DSLX_TEST_FLAGS = ( - "compare", - "dslx_path", - "warnings_as_errors", - "disable_warnings", - "enable_warnings", - "max_ticks", - "format_preference", - "configured_values", - "lower_to_proc_scoped_channels", - "lower_to_ir", - "convert_tests", - ) - - dslx_test_args = dict(_dslx_test_args) - - # With runs outside a monorepo, the execution root for the workspace of - # the binary can be different with the execroot, requiring to change - # the dslx stdlib search path accordingly. - # e.g., Label("@repo//pkg/xls:binary").workspace_root == "external/repo" - wsroot = ctx.attr._xls_dslx_interpreter_tool.label.workspace_root - wsroot_dslx_path = ":{}".format(wsroot) if wsroot != "" else "" - dslx_srcs_wsroot = ":".join([s.owner.workspace_root for s in all_srcs] + - [ctx.genfiles_dir.path + "/" + s.owner.workspace_root for s in all_srcs]) - dslx_srcs_wsroot_path = ":{}".format(dslx_srcs_wsroot) if dslx_srcs_wsroot != "" else "" - - dslx_test_args["dslx_path"] = ( - dslx_test_args.get("dslx_path", "") + ":${PWD}:" + - ctx.genfiles_dir.path + ":" + ctx.bin_dir.path + - dslx_srcs_wsroot_path + wsroot_dslx_path - ) - if ctx.attr.configured_values: - formatted_values = [] - for k, v in ctx.attr.configured_values.items(): - formatted_values.append("{}:{}".format(k, v)) - dslx_test_args["configured_values"] = ",".join(formatted_values) - is_args_valid(dslx_test_args, DSLX_TEST_FLAGS) - dslx_test_args["evaluator"] = ctx.attr.evaluator - my_args = args_to_string(dslx_test_args) - - cmd = "{} {} {}".format( - dslx_interpreter_tool.short_path, - src.short_path, - my_args, - ) - - # Append command-line arguments. - if append_cmd_line_args: - cmd = append_cmd_line_args_to(cmd) - - return cmd - def _get_dslx_prove_quickcheck_test_cmdline(ctx, src, all_srcs, append_cmd_line_args = True): """Returns the command that executes in the xls_dslx_prove_quickcheck_test rule. @@ -204,33 +130,6 @@ def _get_dslx_prove_quickcheck_test_cmdline(ctx, src, all_srcs, append_cmd_line_ return cmd -def get_src_files_from_dslx_library_as_input(ctx): - """Returns the DSLX source files of rules using 'xls_dslx_library_as_input_attrs'. - - Args: - ctx: The current rule's context object. - - Returns: - Returns the DSLX source files of rules using 'xls_dslx_library_as_input_attrs'. - """ - dslx_src_files = [] - count = 0 - - if ctx.attr.library: - dslx_info = ctx.attr.library[DslxInfo] - dslx_src_files = dslx_info.target_dslx_source_files - count += 1 - if ctx.attr.srcs or ctx.attr.deps: - if not ctx.attr.srcs: - fail("'srcs' must be defined when 'deps' is defined.") - dslx_src_files = ctx.files.srcs - count += 1 - - if count != 1: - fail("One of: 'library' or ['srcs', 'deps'] must be assigned.") - - return dslx_src_files - def get_DslxInfo_from_dslx_library_as_input(ctx): """Returns the DslxInfo provider of rules using 'xls_dslx_library_as_input_attrs'. @@ -283,50 +182,6 @@ _xls_dslx_library_attrs = { ), } -xls_dslx_library_as_input_attrs = { - "library": attr.label( - doc = "A DSLX library target where the direct (non-transitive) " + - "files of the target are tested. This attribute is mutually " + - "exclusive with the 'srcs' and 'deps' attribute.", - providers = [DslxInfo], - ), - "srcs": attr.label_list( - doc = "Source files for the rule. The files must have a '.x' " + - "extension. This attribute is mutually exclusive with the " + - "'library' attribute.", - allow_files = [".x"], - ), - "deps": attr.label_list( - doc = "Dependency targets for the files in the 'srcs' attribute. " + - "This attribute is mutually exclusive with the 'library' " + - "attribute.", - providers = [DslxInfo], - ), -} - -# Common attributes for DSLX testing. -xls_dslx_test_common_attrs = { - "configured_values": attr.string_dict( - doc = "Dictionary of overrides to use for overridable constants " + - "in DSLX processing. Format is \"key\":\"value\" pairs.", - ), - "dslx_test_args": attr.string_dict( - doc = "Arguments of the DSLX interpreter executable. For details " + - "on the arguments, refer to the interpreter_main " + - "application at " + - "//xls/dslx/interpreter_main.cc.", - ), - "evaluator": attr.string( - default = "dslx-interpreter", - values = ["dslx-interpreter", "ir-jit", "ir-interpreter"], - doc = "What type of evaluator to use. 'ir-jit' will execute the tests faster " + - "but has higher startup time and less helpful failure messages. Options: " + - '["dslx-interpreter" (default), "ir-jit", "ir-interpreter"]. Note: The ' + - "'compare' dslx_test_arg is only available with the default 'dslx-interpreter' " + - "evaluator.", - ), -} - # Common attributes for DSLX proof-based quickcheck testing. xls_dslx_prove_quickcheck_test_common_attrs = { "test_filter": attr.string(doc = "Regex to select quickcheck tests to run."), @@ -473,71 +328,6 @@ Examples: ), ) -def get_dslx_test_cmd(ctx, src_files_to_test): - """Returns the runfiles and commands to execute the sources files. - - Args: - ctx: The current rule's context object. - src_files_to_test: A list of source files to test. - - Returns: - A tuple with the following elements in the order presented: - 1. The runfiles to execute the commands. - 1. A list of commands. - """ - - # Get runfiles. - dslx_interpreter_tool_runfiles = ( - ctx.attr._xls_dslx_interpreter_tool[DefaultInfo].default_runfiles - ) - runfiles = get_runfiles_for_xls( - ctx, - [dslx_interpreter_tool_runfiles], - src_files_to_test, - ) - - cmds = [] - for src in src_files_to_test: - cmds.append(_get_dslx_test_cmdline(ctx, src, src_files_to_test)) - return runfiles, cmds - -def _xls_dslx_test_impl(ctx): - """The implementation of the 'xls_dslx_test' rule. - - Executes the tests and quick checks of a DSLX source file. - - Args: - ctx: The current rule's context object. - - Returns: - DefaultInfo provider - """ - src_files_to_test = get_src_files_from_dslx_library_as_input(ctx) - - runfiles, cmds = get_dslx_test_cmd(ctx, src_files_to_test) - - executable_file = ctx.actions.declare_file(ctx.label.name + ".sh") - ctx.actions.write( - output = executable_file, - content = "\n".join([ - "#!/usr/bin/env bash", - "set -e", - "\n".join(cmds), - "exit 0", - ]), - is_executable = True, - ) - return [ - DefaultInfo( - runfiles = runfiles, - files = depset( - direct = [executable_file], - transitive = get_transitive_built_files_for_xls(ctx), - ), - executable = executable_file, - ), - ] - def get_dslx_prove_quickcheck_test_cmd(ctx, src_files_to_test): """Returns the runfiles and commands to execute the proof solver against DSLX source files. @@ -603,16 +393,6 @@ def _xls_dslx_prove_quickcheck_test_impl(ctx): ), ] -_xls_dslx_test = rule( - implementation = _xls_dslx_test_impl, - attrs = dicts.add( - xls_dslx_library_as_input_attrs, - xls_dslx_test_common_attrs, - dicts.pick(xls_toolchain_attrs, ["_xls_dslx_interpreter_tool"]), - ), - test = True, -) - def xls_dslx_test(**kwargs): """A dslx test executes the tests and quick checks of a DSLX source file. diff --git a/xls/build_rules/xls_dslx_test.bzl b/xls/build_rules/xls_dslx_test.bzl new file mode 100644 index 0000000000..403ae6b48a --- /dev/null +++ b/xls/build_rules/xls_dslx_test.bzl @@ -0,0 +1,208 @@ +# 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. + +"""This module contains the DSLX-related test build rules for XLS.""" + +load("@bazel_skylib//lib:dicts.bzl", "dicts") +load( + "//xls/build_rules:xls_common_rules.bzl", + "append_cmd_line_args_to", + "append_default_to_args", + "args_to_string", + "get_runfiles_for_xls", + "get_transitive_built_files_for_xls", + "is_args_valid", +) +load("//xls/build_rules:xls_dslx_common.bzl", "get_src_files_from_dslx_library_as_input", "xls_dslx_library_as_input_attrs") +load( + "//xls/build_rules:xls_toolchains.bzl", + "xls_toolchain_attrs", +) + +visibility(["//xls/build_rules/..."]) + +_DEFAULT_DSLX_TEST_ARGS = { + "compare": "none", +} + +# Common attributes for DSLX testing. +xls_dslx_test_common_attrs = { + "configured_values": attr.string_dict( + doc = "Dictionary of overrides to use for overridable constants " + + "in DSLX processing. Format is \"key\":\"value\" pairs.", + ), + "dslx_test_args": attr.string_dict( + doc = "Arguments of the DSLX interpreter executable. For details " + + "on the arguments, refer to the interpreter_main " + + "application at " + + "//xls/dslx/interpreter_main.cc.", + ), + "evaluator": attr.string( + default = "dslx-interpreter", + values = ["dslx-interpreter", "ir-jit", "ir-interpreter"], + doc = "What type of evaluator to use. 'ir-jit' will execute the tests faster " + + "but has higher startup time and less helpful failure messages. Options: " + + '["dslx-interpreter" (default), "ir-jit", "ir-interpreter"]. Note: The ' + + "'compare' dslx_test_arg is only available with the default 'dslx-interpreter' " + + "evaluator.", + ), +} + +def get_dslx_test_cmd(ctx, src_files_to_test): + """Returns the runfiles and commands to execute the sources files. + + Args: + ctx: The current rule's context object. + src_files_to_test: A list of source files to test. + + Returns: + A tuple with the following elements in the order presented: + 1. The runfiles to execute the commands. + 1. A list of commands. + """ + + # Get runfiles. + dslx_interpreter_tool_runfiles = ( + ctx.attr._xls_dslx_interpreter_tool[DefaultInfo].default_runfiles + ) + runfiles = get_runfiles_for_xls( + ctx, + [dslx_interpreter_tool_runfiles], + src_files_to_test, + ) + + cmds = [] + for src in src_files_to_test: + cmds.append(_get_dslx_test_cmdline(ctx, src, src_files_to_test)) + return runfiles, cmds + +def _get_dslx_test_cmdline(ctx, src, all_srcs, append_cmd_line_args = True): + """Returns the command that executes in the xls_dslx_test rule. + + Args: + ctx: The current rule's context object. + src: The file to test. + all_srcs: All dslx sources, including dependencies as part of the test. + append_cmd_line_args: Flag controlling appending the command-line + arguments invoking the command generated by this function. When set to + True, the command-line arguments invoking the command are appended. + Otherwise, the command-line arguments are not appended. + + Returns: + The command that executes in the xls_dslx_test rule. + """ + dslx_interpreter_tool = ctx.executable._xls_dslx_interpreter_tool + _dslx_test_args = append_default_to_args( + ctx.attr.dslx_test_args, + _DEFAULT_DSLX_TEST_ARGS, + ) + + DSLX_TEST_FLAGS = ( + "compare", + "dslx_path", + "warnings_as_errors", + "disable_warnings", + "enable_warnings", + "max_ticks", + "format_preference", + "configured_values", + "lower_to_proc_scoped_channels", + "lower_to_ir", + "convert_tests", + ) + + dslx_test_args = dict(_dslx_test_args) + + # With runs outside a monorepo, the execution root for the workspace of + # the binary can be different with the execroot, requiring to change + # the dslx stdlib search path accordingly. + # e.g., Label("@repo//pkg/xls:binary").workspace_root == "external/repo" + wsroot = ctx.attr._xls_dslx_interpreter_tool.label.workspace_root + wsroot_dslx_path = ":{}".format(wsroot) if wsroot != "" else "" + dslx_srcs_wsroot = ":".join([s.owner.workspace_root for s in all_srcs] + + [ctx.genfiles_dir.path + "/" + s.owner.workspace_root for s in all_srcs]) + dslx_srcs_wsroot_path = ":{}".format(dslx_srcs_wsroot) if dslx_srcs_wsroot != "" else "" + + dslx_test_args["dslx_path"] = ( + dslx_test_args.get("dslx_path", "") + ":${PWD}:" + + ctx.genfiles_dir.path + ":" + ctx.bin_dir.path + + dslx_srcs_wsroot_path + wsroot_dslx_path + ) + if ctx.attr.configured_values: + formatted_values = [] + for k, v in ctx.attr.configured_values.items(): + formatted_values.append("{}:{}".format(k, v)) + dslx_test_args["configured_values"] = ",".join(formatted_values) + is_args_valid(dslx_test_args, DSLX_TEST_FLAGS) + dslx_test_args["evaluator"] = ctx.attr.evaluator + my_args = args_to_string(dslx_test_args) + + cmd = "{} {} {}".format( + dslx_interpreter_tool.short_path, + src.short_path, + my_args, + ) + + # Append command-line arguments. + if append_cmd_line_args: + cmd = append_cmd_line_args_to(cmd) + + return cmd + +def _xls_dslx_test_impl(ctx): + """The implementation of the 'xls_dslx_test' rule. + + Executes the tests and quick checks of a DSLX source file. + + Args: + ctx: The current rule's context object. + + Returns: + DefaultInfo provider + """ + src_files_to_test = get_src_files_from_dslx_library_as_input(ctx) + + runfiles, cmds = get_dslx_test_cmd(ctx, src_files_to_test) + + executable_file = ctx.actions.declare_file(ctx.label.name + ".sh") + ctx.actions.write( + output = executable_file, + content = "\n".join([ + "#!/usr/bin/env bash", + "set -e", + "\n".join(cmds), + "exit 0", + ]), + is_executable = True, + ) + return [ + DefaultInfo( + runfiles = runfiles, + files = depset( + direct = [executable_file], + transitive = get_transitive_built_files_for_xls(ctx), + ), + executable = executable_file, + ), + ] + +xls_dslx_test = rule( + implementation = _xls_dslx_test_impl, + attrs = dicts.add( + xls_dslx_library_as_input_attrs, + xls_dslx_test_common_attrs, + dicts.pick(xls_toolchain_attrs, ["_xls_dslx_interpreter_tool"]), + ), + test = True, +) diff --git a/xls/build_rules/xls_ir_rules.bzl b/xls/build_rules/xls_ir_rules.bzl index a37c68879f..daa3734197 100644 --- a/xls/build_rules/xls_ir_rules.bzl +++ b/xls/build_rules/xls_ir_rules.bzl @@ -36,11 +36,10 @@ load( "CONFIG", "DEFAULT_BENCHMARK_SYNTH_DELAY_MODEL", ) +load("//xls/build_rules:xls_dslx_common.bzl", "get_src_files_from_dslx_library_as_input", "xls_dslx_library_as_input_attrs") load( "//xls/build_rules:xls_dslx_rules.bzl", "get_DslxInfo_from_dslx_library_as_input", - "get_src_files_from_dslx_library_as_input", - "xls_dslx_library_as_input_attrs", ) load( "//xls/build_rules:xls_providers.bzl", diff --git a/xls/build_rules/xls_rules.bzl b/xls/build_rules/xls_rules.bzl index ad6437f8f6..a738bfca93 100644 --- a/xls/build_rules/xls_rules.bzl +++ b/xls/build_rules/xls_rules.bzl @@ -29,7 +29,7 @@ load( ) load("//xls/build_rules:xls_config_rules.bzl", "CONFIG") load( - "//xls/build_rules:xls_dslx_rules.bzl", + "//xls/build_rules:xls_dslx_test.bzl", "get_dslx_test_cmd", "xls_dslx_test_common_attrs", )