Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions xls/common/attribute_data.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ std::string AttributeKindToString(AttributeKind kind) {
return "channel_strictness";
case AttributeKind::kFuzzTest:
return "fuzz_test";
case AttributeKind::kFuzzDomain:
return "fuzz_domain";
}
}

Expand Down
1 change: 1 addition & 0 deletions xls/common/attribute_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ enum class AttributeKind : uint8_t {
kQuickcheck,
kChannelStrictness,
kFuzzTest,
kFuzzDomain,
};

// Converts an AttributeKind to a string, e.g., "fuzz_test"
Expand Down
18 changes: 1 addition & 17 deletions xls/dslx/bytecode/builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,23 +156,7 @@ absl::Status BuiltinRangeInternal(InterpreterStack& stack) {
const InterpValue& end) -> absl::StatusOr<InterpValue> {
XLS_RET_CHECK(start.IsBits());
XLS_RET_CHECK(end.IsBits());
XLS_ASSIGN_OR_RETURN(InterpValue start_ge_end, start.Ge(end));
if (start_ge_end.IsTrue()) {
return InterpValue::MakeRange({});
}

std::vector<InterpValue> elements;
InterpValue cur = start;
XLS_ASSIGN_OR_RETURN(InterpValue done, cur.Ge(end));
XLS_ASSIGN_OR_RETURN(int64_t cur_bits, cur.GetBitCount());
InterpValue one(cur.IsSigned() ? InterpValue::MakeSBits(cur_bits, 1)
: InterpValue::MakeUBits(cur_bits, 1));
while (done.IsFalse()) {
elements.push_back(cur);
XLS_ASSIGN_OR_RETURN(cur, cur.Add(one));
XLS_ASSIGN_OR_RETURN(done, cur.Ge(end));
}
return InterpValue::MakeRange(elements);
return InterpValue::MakeSymbolicRange(start, end);
},
stack);
}
Expand Down
20 changes: 20 additions & 0 deletions xls/dslx/bytecode/bytecode_interpreter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2880,5 +2880,25 @@ fn main() -> u32[3] {
InterpValue::MakeU32(15)}));
}

TEST_F(BytecodeInterpreterTest, SymbolicRangeHuge) {
if (kDefaultTypeInferenceVersion == TypeInferenceVersion::kVersion2) {
// The range() builtin is deprecated and no longer supported in TIv2.
return;
}
constexpr std::string_view kProgram = R"(
fn main() -> u32[4294967295] {
range(u32:0, u32:4294967295)
}
)";
XLS_ASSERT_OK_AND_ASSIGN(InterpValue value, Interpret(kProgram, "main"));
EXPECT_TRUE(value.is_range());
XLS_ASSERT_OK_AND_ASSIGN(int64_t len, value.GetLength());
EXPECT_EQ(len, 4294967295LL);

XLS_ASSERT_OK_AND_ASSIGN(InterpValue elem, value.Index(123456789));
XLS_ASSERT_OK_AND_ASSIGN(uint64_t val, elem.GetBitValueUnsigned());
EXPECT_EQ(val, 123456789);
}

} // namespace
} // namespace xls::dslx
18 changes: 18 additions & 0 deletions xls/dslx/frontend/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -3334,6 +3334,11 @@ class StructDefBase : public AstNode {

const std::vector<StructMemberNode*>& members() const { return members_; }
std::vector<StructMember>& mutable_members() { return struct_members_; }
void AddMember(StructMemberNode* member) {
members_.push_back(member);
struct_members_.push_back(member->ToStructMemberStruct());
members_by_name_[member->name()] = member;
}

bool is_public() const { return public_; }
const Span& span() const { return span_; }
Expand Down Expand Up @@ -3417,9 +3422,22 @@ class StructDef : public StructDefBase {
return extern_type_name_;
}

void set_is_domain_struct(bool v) { is_domain_struct_ = v; }
bool is_domain_struct() const { return is_domain_struct_; }

void set_is_populated(bool v) { is_populated_ = v; }
bool is_populated() const { return is_populated_; }

void set_original_struct(StructDef* s) { original_struct_ = s; }
StructDef* original_struct() const { return original_struct_; }

private:
// The external verilog type name
std::optional<std::string> extern_type_name_;

bool is_domain_struct_ = false;
bool is_populated_ = false;
StructDef* original_struct_ = nullptr;
};

// Represents a proc declared with struct-like syntax, with the functions in an
Expand Down
52 changes: 48 additions & 4 deletions xls/dslx/frontend/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include <variant>
#include <vector>
Expand Down Expand Up @@ -225,6 +226,7 @@ absl::StatusOr<AttributeKind> ParseAttributeKind(Token token,
{"test_proc", AttributeKind::kTestProc},
{"quickcheck", AttributeKind::kQuickcheck},
{"fuzz_test", AttributeKind::kFuzzTest},
{"fuzz_domain", AttributeKind::kFuzzDomain},
{"channel_strictness", AttributeKind::kChannelStrictness}};

const auto it = map->find(token.GetStringValue());
Expand Down Expand Up @@ -605,7 +607,7 @@ absl::StatusOr<std::unique_ptr<Module>> Parser::ParseModule(
TypeAlias * type_alias,
ParseTypeAlias(*module_member_start_pos, is_public, *bindings));
XLS_RETURN_IF_ERROR(
ApplyTypeAttributes(type_alias, pending_attributes));
ApplyTypeAttributes(type_alias, pending_attributes, *bindings));
XLS_RETURN_IF_ERROR(module_->AddTop(type_alias, make_collision_error));
break;
}
Expand All @@ -614,15 +616,16 @@ absl::StatusOr<std::unique_ptr<Module>> Parser::ParseModule(
StructDef * struct_def,
ParseStruct(*module_member_start_pos, is_public, *bindings));
XLS_RETURN_IF_ERROR(
ApplyTypeAttributes(struct_def, pending_attributes));
ApplyTypeAttributes(struct_def, pending_attributes, *bindings));
XLS_RETURN_IF_ERROR(module_->AddTop(struct_def, make_collision_error));
break;
}
case Keyword::kEnum: {
XLS_ASSIGN_OR_RETURN(
EnumDef * enum_def,
ParseEnumDef(*module_member_start_pos, is_public, *bindings));
XLS_RETURN_IF_ERROR(ApplyTypeAttributes(enum_def, pending_attributes));
XLS_RETURN_IF_ERROR(
ApplyTypeAttributes(enum_def, pending_attributes, *bindings));
XLS_RETURN_IF_ERROR(module_->AddTop(enum_def, make_collision_error));
break;
}
Expand Down Expand Up @@ -949,6 +952,7 @@ absl::Status Parser::UnsupportedAttributeError(const Attribute& attribute) {
Span span = *attribute.GetSpan();
switch (attribute.attribute_kind()) {
case AttributeKind::kDerive:
case AttributeKind::kFuzzDomain:
return ParseErrorStatus(
span,
absl::StrCat(attribute.ToString(), " is only valid on a struct."));
Expand Down Expand Up @@ -1143,7 +1147,8 @@ absl::StatusOr<XlsTuple*> Parser::ParseFuzzTestDomains(

template <typename T>
absl::Status Parser::ApplyTypeAttributes(T* node,
std::vector<Attribute*> attributes) {
std::vector<Attribute*> attributes,
Bindings& bindings) {
for (Attribute* next : attributes) {
switch (next->attribute_kind()) {
case AttributeKind::kDerive: {
Expand Down Expand Up @@ -1180,6 +1185,45 @@ absl::Status Parser::ApplyTypeAttributes(T* node,
break;
}

case AttributeKind::kFuzzDomain: {
if constexpr (!std::is_same_v<T, StructDef>) {
return UnsupportedAttributeError(*next);
} else {
if (next->args().size() != 1 ||
!std::holds_alternative<AttributeData::StringLiteralArgument>(
next->args()[0])) {
return ParseErrorStatus(
*next->GetSpan(),
"fuzz_domain attribute requires a string argument.");
}
std::string domain_name =
std::get<AttributeData::StringLiteralArgument>(next->args()[0])
.text;

StructDef* struct_def = node;
Span span = *next->GetSpan();
NameDef* domain_name_def =
module_->Make<NameDef>(span, domain_name, /*definer=*/nullptr);
std::vector<ParametricBinding*> parametric_bindings;
std::vector<StructMemberNode*> members;
StructDef* domain_struct = module_->Make<StructDef>(
span, domain_name_def, std::move(parametric_bindings),
std::move(members), struct_def->is_public());
domain_name_def->set_definer(domain_struct);

domain_struct->set_is_domain_struct(true);
domain_struct->set_original_struct(struct_def);

bindings.Add(domain_name, domain_struct);

auto make_collision_error =
absl::bind_front(&MakeModuleTopCollisionError, file_table());
XLS_RETURN_IF_ERROR(
module_->AddTop(domain_struct, make_collision_error));
}
break;
}

default:
return UnsupportedAttributeError(*next);
}
Expand Down
3 changes: 2 additions & 1 deletion xls/dslx/frontend/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,8 @@ class Parser : public TokenParser {
const std::vector<Attribute*>& attributes);

template <typename T>
absl::Status ApplyTypeAttributes(T* node, std::vector<Attribute*> attributes);
absl::Status ApplyTypeAttributes(T* node, std::vector<Attribute*> attributes,
Bindings& bindings);

absl::StatusOr<QuickCheckTestCases> GetQuickCheckTestCases(
const Attribute& attribute);
Expand Down
23 changes: 23 additions & 0 deletions xls/dslx/frontend/parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4964,4 +4964,27 @@ fn f(x: u32, y: u8) {}
EXPECT_TRUE(second_member_tuple->members().empty());
}

TEST_F(ParserTest, FuzzDomainAttribute) {
std::string_view program = R"(
#[fuzz_domain("MyDomain")]
struct MyStruct {
x: u32,
}
)";
auto module = ExpectParsesSuccessfully(program);
ASSERT_NE(module, nullptr);

// Verify MyStruct exists.
XLS_ASSERT_OK_AND_ASSIGN(StructDef * my_struct,
module->GetMemberOrError<StructDef>("MyStruct"));
EXPECT_FALSE(my_struct->is_domain_struct());

// Verify MyDomain exists and is linked.
XLS_ASSERT_OK_AND_ASSIGN(StructDef * my_domain,
module->GetMemberOrError<StructDef>("MyDomain"));
EXPECT_TRUE(my_domain->is_domain_struct());
EXPECT_FALSE(my_domain->is_populated());
EXPECT_EQ(my_domain->original_struct(), my_struct);
}

} // namespace xls::dslx
Loading
Loading