From 0720f010b256b750df0d6e02c70fb372aa1bbf4b Mon Sep 17 00:00:00 2001
From: David Plass
Date: Thu, 23 Apr 2026 09:15:03 -0700
Subject: [PATCH] [DSLX Fuzz Testing] Update Function::AttributeIrStrings to
properly serialize the attributes.
PiperOrigin-RevId: 904489338
---
xls/ir/BUILD | 5 ++++-
xls/ir/function.cc | 30 ++++++++++++++++++++++++++++--
xls/ir/function_test.cc | 21 +++++++++++++++++++++
xls/ir/xls_ir_interface.proto | 30 ++++++++++++++++++++++++++++++
4 files changed, 83 insertions(+), 3 deletions(-)
diff --git a/xls/ir/BUILD b/xls/ir/BUILD
index 3acf6fea70..af0a43dcb2 100644
--- a/xls/ir/BUILD
+++ b/xls/ir/BUILD
@@ -1570,7 +1570,10 @@ py_proto_library(
proto_library(
name = "xls_ir_interface_proto",
srcs = ["xls_ir_interface.proto"],
- deps = [":xls_type_proto"],
+ deps = [
+ ":xls_type_proto",
+ ":xls_value_proto",
+ ],
)
cc_proto_library(
diff --git a/xls/ir/function.cc b/xls/ir/function.cc
index c99e0e4389..45157be200 100644
--- a/xls/ir/function.cc
+++ b/xls/ir/function.cc
@@ -32,9 +32,11 @@
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/types/span.h"
+#include "absl/types/variant.h"
#include "xls/common/attribute_data.h"
#include "xls/common/status/ret_check.h"
#include "xls/common/status/status_macros.h"
+#include "xls/common/visitor.h"
#include "xls/ir/change_listener.h"
#include "xls/ir/function_base.h"
#include "xls/ir/ir_annotator.h"
@@ -348,8 +350,32 @@ std::vector Function::AttributeIrStrings() const {
attribute_strings.push_back("non_synth");
}
for (const auto& attr : attributes_) {
- // TODO - davidplass: Properly serialize AttributeData arguments.
- attribute_strings.push_back(AttributeKindToString(attr.kind()));
+ std::string attr_str = AttributeKindToString(attr.kind());
+ if (!attr.args().empty()) {
+ std::vector arg_strings;
+ for (const auto& arg : attr.args()) {
+ std::string arg_str = absl::visit(
+ Visitor{
+ [](const std::string& s) { return s; },
+ [](const AttributeData::StringLiteralArgument& s) {
+ return absl::StrCat("\"", s.text, "\"");
+ },
+ [](const AttributeData::StringKeyValueArgument& s) {
+ if (s.is_backticked) {
+ return absl::StrCat(s.first, "=`", s.second, "`");
+ }
+ return absl::StrCat(s.first, "=\"", s.second, "\"");
+ },
+ [](const AttributeData::IntKeyValueArgument& s) {
+ return absl::StrCat(s.first, "=", s.second);
+ },
+ },
+ arg);
+ arg_strings.push_back(arg_str);
+ }
+ absl::StrAppend(&attr_str, "(", absl::StrJoin(arg_strings, ", "), ")");
+ }
+ attribute_strings.push_back(attr_str);
}
return attribute_strings;
}
diff --git a/xls/ir/function_test.cc b/xls/ir/function_test.cc
index 1f11e09183..1615c2ad8b 100644
--- a/xls/ir/function_test.cc
+++ b/xls/ir/function_test.cc
@@ -642,5 +642,26 @@ TEST_F(FunctionTest, AttributeDataTest) {
EXPECT_THAT(f->DumpIr(), HasSubstr("#[fuzz_test]"));
}
+TEST_F(FunctionTest, AttributeSerializationWithArgumentsTest) {
+ auto p = CreatePackage();
+ FunctionBuilder b("f", p.get());
+ b.Param("x", p->GetBitsType(32));
+ XLS_ASSERT_OK_AND_ASSIGN(Function * f, b.BuildWithReturnValue(b.Tuple({})));
+
+ std::vector args;
+ args.push_back("ident");
+ args.push_back(AttributeData::StringLiteralArgument{.text = "literal"});
+ args.push_back(AttributeData::StringKeyValueArgument{
+ .first = "key", .second = "backticked", .is_backticked = true});
+ args.push_back(AttributeData::IntKeyValueArgument{"int_key", 42});
+
+ f->AddAttribute(AttributeData(AttributeKind::kFuzzTest, args));
+
+ EXPECT_THAT(
+ f->DumpIr(),
+ HasSubstr(
+ "#[fuzz_test(ident, \"literal\", key=`backticked`, int_key=42)]"));
+}
+
} // namespace
} // namespace xls
diff --git a/xls/ir/xls_ir_interface.proto b/xls/ir/xls_ir_interface.proto
index 34e734a476..91e5be5d5a 100644
--- a/xls/ir/xls_ir_interface.proto
+++ b/xls/ir/xls_ir_interface.proto
@@ -17,6 +17,7 @@ syntax = "proto3";
package xls;
import "xls/ir/xls_type.proto";
+import "xls/ir/xls_value.proto";
message PackageInterfaceProto {
// A generic thing with a name and a type.
@@ -59,6 +60,10 @@ message PackageInterfaceProto {
optional TypeProto result_type = 3;
// If present the corresponding sv type for the result of this function.
optional string sv_result_type = 4;
+
+ // The structured fuzzing domains for this function. There may be
+ // either zero domains, or exactly one domain per parameter.
+ repeated FuzzTestDomain parameter_domains = 5;
}
message Proc {
@@ -87,6 +92,31 @@ message PackageInterfaceProto {
repeated NamedValue output_ports = 4;
}
+ message FuzzTestDomain {
+ message Range {
+ optional ValueProto min = 1;
+ optional ValueProto max = 2;
+ }
+ message ElementOf {
+ repeated ValueProto values = 1;
+ }
+ message Tuple {
+ repeated FuzzTestDomain elements = 1;
+ }
+ message Array {
+ optional FuzzTestDomain element_domain = 1;
+ optional int64 size = 2;
+ }
+
+ oneof domain_kind {
+ bool arbitrary = 1;
+ Range range = 2;
+ ElementOf element_of = 3;
+ Tuple tuple = 4;
+ Array array = 5;
+ }
+ }
+
// Name of the overall package.
optional string name = 1;