Skip to content

Commit

Permalink
Merge pull request #1720 from xlsynth:cdleary/2024-11-14-vast-constructs
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 697635694
  • Loading branch information
copybara-github committed Nov 18, 2024
2 parents d7aeef5 + e56d590 commit 133967a
Show file tree
Hide file tree
Showing 4 changed files with 339 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ endmodule


module my_block(
input pkg::small_arr_t x,
input pkg::small_arr_t y,
output pkg::big_arr_t out
input pkg::small_arr_t x,
input pkg::small_arr_t y,
output pkg::big_arr_t out
);
wire [159:0] x_flattened;
assign x_flattened = x;
Expand Down
95 changes: 79 additions & 16 deletions xls/codegen/vast/vast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,40 @@ std::string EmitNothing(const VastNode* node, LineInfo* line_info) {
return "";
}

// Helper for validating that there is not leading/trailing whitespace that can
// be stripped from string view `s` -- this helps us maintain our invariants
// that our Emit() calls generally do not return things with leading or
// trailing whitespace, so callers uniformly know what to expect in terms of
// spacing.
//
// This routine is made without performing string copies or performing a strcmp
// so should be usable in CHECKs instead of resorting to DCHECKs everywhere.
//
// i.e. callers are expected to call `CHECK(CannotStripWhitespace(s));`
bool CannotStripWhitespace(std::string_view s) {
std::string_view stripped = absl::StripAsciiWhitespace(s);
return stripped.size() == s.size();
}

// Helper that combines DataKind and DataType strings -- since either of these
// can be empty under certain circumstances we consolidate the handling of
// inserting spaces appropriately in this routine.
std::string CombineKindAndDataType(std::string_view kind_str,
std::string_view data_type_str) {
CHECK(CannotStripWhitespace(kind_str));
CHECK(CannotStripWhitespace(data_type_str));

std::string result;
if (kind_str.empty()) {
result = data_type_str;
} else if (data_type_str.empty()) {
result = kind_str;
} else {
result = absl::StrCat(kind_str, " ", data_type_str);
}
return result;
}

} // namespace

int Precedence(OperatorKind kind) {
Expand Down Expand Up @@ -301,14 +335,24 @@ std::string ToString(Direction direction) {
}
}

std::string DataType::EmitWithIdentifier(LineInfo* line_info,
std::string_view identifier) const {
std::string base = Emit(line_info);
if (base.empty()) {
return std::string{identifier};
}
CHECK(CannotStripWhitespace(base));
return absl::StrCat(base, " ", identifier);
}

std::string ScalarType::Emit(LineInfo* line_info) const {
// The `DataKind` preceding the type is enough.
if (!is_signed_) {
return EmitNothing(this, line_info);
}
LineInfoStart(line_info, this);
LineInfoEnd(line_info, this);
return " signed";
return "signed";
}

std::string IntegerType::Emit(LineInfo* line_info) const {
Expand All @@ -319,7 +363,7 @@ std::string IntegerType::Emit(LineInfo* line_info) const {
}
LineInfoStart(line_info, this);
LineInfoEnd(line_info, this);
return " unsigned";
return "unsigned";
}

std::string MacroRef::Emit(LineInfo* line_info) const {
Expand Down Expand Up @@ -500,17 +544,21 @@ LogicRef* VerilogFunction::return_value_ref() {

std::string VerilogFunction::Emit(LineInfo* line_info) const {
LineInfoStart(line_info, this);

// Construct the return type for the function, sometimes we want to put
// "logic" in front when in SV mode.
std::string return_type =
return_value_def_->data_type()->EmitWithIdentifier(line_info, name());
if (!absl::StartsWith(return_type, " ")) {
return_type = absl::StrCat(" ", return_type);
}
if (return_value_def_->data_type()->IsScalar() &&
file()->use_system_verilog()) {
// Preface the return type with "logic", so there's always a type provided.
return_type =
absl::StrCat(" ", DataKindToString(DataKind::kLogic), return_type);
absl::StrCat(DataKindToString(DataKind::kLogic), " ", return_type);
}
if (!return_type.empty()) {
return_type = absl::StrCat(" ", return_type);
}

std::string parameters =
absl::StrJoin(argument_defs_, ", ", [=](std::string* out, Def* d) {
absl::StrAppend(out, "input ", d->EmitNoSemi(line_info));
Expand Down Expand Up @@ -757,10 +805,11 @@ absl::StatusOr<int64_t> BitVectorType::FlatBitCountAsInt64() const {

std::string BitVectorType::Emit(LineInfo* line_info) const {
LineInfoStart(line_info, this);
std::string result =
absl::StrFormat("%s [%s:0]", is_signed_ ? " signed" : "",
size_expr_is_max_ ? size_expr_->Emit(line_info)
: WidthToLimit(line_info, size_expr_));
std::string result = is_signed_ ? "signed " : "";
absl::StrAppendFormat(&result, "[%s:0]",
size_expr_is_max_
? size_expr_->Emit(line_info)
: WidthToLimit(line_info, size_expr_));
LineInfoEnd(line_info, this);
return result;
}
Expand Down Expand Up @@ -891,8 +940,10 @@ std::string Def::Emit(LineInfo* line_info) const {
std::string Def::EmitNoSemi(LineInfo* line_info) const {
LineInfoStart(line_info, this);
std::string kind_str = DataKindToString(data_kind());
std::string result = absl::StrCat(
kind_str, data_type()->EmitWithIdentifier(line_info, GetName()));
std::string data_type_str =
data_type()->EmitWithIdentifier(line_info, GetName());
std::string result = CombineKindAndDataType(kind_str, data_type_str);

LineInfoEnd(line_info, this);
return result;
}
Expand Down Expand Up @@ -1106,8 +1157,10 @@ std::string Module::Emit(LineInfo* line_info) const {
absl::StrAppend(
&result,
absl::StrJoin(ports_, ",\n ", [=](std::string* out, const Port& port) {
std::string wire_str = port.wire->EmitNoSemi(line_info);
CHECK(CannotStripWhitespace(wire_str));
absl::StrAppendFormat(out, "%s %s", ToString(port.direction),
port.wire->EmitNoSemi(line_info));
wire_str);
LineInfoIncrease(line_info, 1);
}));
absl::StrAppend(&result, "\n);\n");
Expand Down Expand Up @@ -1302,7 +1355,14 @@ std::string TypedefType::Emit(LineInfo* line_info) const {

std::string ExternType::Emit(LineInfo* line_info) const {
LineInfoStart(line_info, this);
std::string result = absl::StrCat(" ", name_);
std::string result = name_;
LineInfoEnd(line_info, this);
return result;
}

std::string ExternPackageType::Emit(LineInfo* line_info) const {
LineInfoStart(line_info, this);
std::string result = absl::StrCat(package_name_, "::", type_name_);
LineInfoEnd(line_info, this);
return result;
}
Expand All @@ -1311,8 +1371,11 @@ std::string Enum::Emit(LineInfo* line_info) const {
LineInfoStart(line_info, this);
std::string result = "enum {\n";
if (kind_ != DataKind::kUntypedEnum) {
result = absl::StrFormat("enum %s%s {\n", DataKindToString(kind_),
BaseType()->Emit(line_info));
std::string kind_str = DataKindToString(kind_);
std::string data_type_str = BaseType()->Emit(line_info);
std::string underlying_type_str =
CombineKindAndDataType(kind_str, data_type_str);
result = absl::StrFormat("enum %s {\n", underlying_type_str);
}
LineInfoIncrease(line_info, 1);
for (int i = 0; i < members_.size(); i++) {
Expand Down
52 changes: 43 additions & 9 deletions xls/codegen/vast/vast.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,8 @@ class DataType : public VastNode {
// Returns whether this is a scalar signal type (for example, "wire foo").
virtual bool IsScalar() const { return false; }

// Returns whether this type represents to a typedef, struct, enum, or an
// array of a user-defined type.
// Returns whether this type represents a typedef, struct, enum, or an array
// of a user-defined type.
virtual bool IsUserDefined() const { return false; }

// Returns the width of the def (not counting packed or unpacked dimensions)
Expand Down Expand Up @@ -233,9 +233,7 @@ class DataType : public VastNode {
// This method is required rather than simply Emit because an identifier
// string is nested within the string describing the type.
virtual std::string EmitWithIdentifier(LineInfo* line_info,
std::string_view identifier) const {
return absl::StrFormat("%s %s", Emit(line_info), identifier);
}
std::string_view identifier) const;
};

// Represents a scalar type. Example:
Expand Down Expand Up @@ -507,7 +505,7 @@ class UserDefinedDef final : public Def {
: Def(name, DataKind::kUser, data_type, init, file, loc) {}
};

// Register variable definition.Example:
// Register variable definition. Example:
// reg [41:0] foo;
class RegDef final : public Def {
public:
Expand All @@ -519,7 +517,7 @@ class RegDef final : public Def {
: Def(name, DataKind::kReg, data_type, init, file, loc) {}
};

// Logic variable definition.Example:
// Logic variable definition. Example:
// logic [41:0] foo;
class LogicDef final : public Def {
public:
Expand All @@ -543,7 +541,7 @@ class UserDef final : public Def {
: Def(name, DataKind::kUser, data_type, init, file, loc) {}
};

// Integer variable definition.Example:
// Integer variable definition. Example:
// integer foo;
class IntegerDef final : public Def {
public:
Expand Down Expand Up @@ -1163,6 +1161,37 @@ class Typedef final : public VastNode {
Def* def_;
};

// A type that is defined in an external package, where we may not know the
// underlying bit vector count as we request in `ExternType`.
class ExternPackageType : public DataType {
public:
explicit ExternPackageType(std::string_view package_name,
std::string_view type_name, VerilogFile* file,
const SourceInfo& loc)
: DataType(file, loc),
package_name_(package_name),
type_name_(type_name) {}

std::string Emit(LineInfo* line_info) const final;

bool IsScalar() const final { return false; }
bool IsUserDefined() const final { return true; }
absl::StatusOr<int64_t> WidthAsInt64() const final {
return absl::UnimplementedError(
"WidthAsInt64 is not implemented for ExternPackageType.");
}
absl::StatusOr<int64_t> FlatBitCountAsInt64() const final {
return absl::UnimplementedError(
"FlatBitCountAsInt64 is not implemented for ExternPackageType.");
}
std::optional<Expression*> width() const final { return std::nullopt; }
bool is_signed() const final { return false; }

private:
std::string package_name_;
std::string type_name_;
};

// The type of an entity when its type is a typedef. This emits just the name of
// the typedef.
class TypedefType final : public UserDefinedAliasType {
Expand Down Expand Up @@ -2299,7 +2328,12 @@ class VerilogPackageSection final : public VastNode {
std::vector<VerilogPackageMember> members_;
};

// Represents a package definition.
// Represents a package definition. Emits as:
// ```
// package ${name};
// .. content ..
// endpackage
// ```
class VerilogPackage final : public VastNode {
public:
VerilogPackage(std::string_view name, VerilogFile* file,
Expand Down
Loading

0 comments on commit 133967a

Please sign in to comment.