1515#include " xls/dslx/type_system_v2/evaluator.h"
1616
1717#include < cstdint>
18+ #include < limits>
1819#include < memory>
1920#include < optional>
2021#include < string>
22+ #include < type_traits>
2123#include < utility>
2224#include < variant>
2325
2426#include " absl/container/flat_hash_map.h"
2527#include " absl/log/log.h"
28+ #include " absl/status/status.h"
2629#include " absl/status/statusor.h"
30+ #include " absl/strings/str_cat.h"
2731#include " xls/common/casts.h"
2832#include " xls/common/status/status_macros.h"
2933#include " xls/dslx/constexpr_evaluator.h"
4246namespace xls ::dslx {
4347namespace {
4448
49+ template <typename T>
50+ class ToSigned {
51+ public:
52+ typedef std::make_signed_t <T> type;
53+ };
54+
55+ template <>
56+ class ToSigned <bool > {
57+ public:
58+ typedef bool type;
59+ };
60+
4561class EvaluatorImpl : public Evaluator {
4662 public:
4763 EvaluatorImpl (InferenceTable& table, Module& module , ImportData& import_data,
@@ -57,43 +73,22 @@ class EvaluatorImpl : public Evaluator {
5773 absl::StatusOr<bool > EvaluateBoolOrExpr (
5874 std::optional<const ParametricContext*> parametric_context,
5975 std::variant<bool , const Expr*> value_or_expr) override {
60- if (std::holds_alternative<bool >(value_or_expr)) {
61- return std::get<bool >(value_or_expr);
62- }
63- const Expr* expr = std::get<const Expr*>(value_or_expr);
64- std::optional<InterpValue> value =
65- FastEvaluate (parametric_context, BuiltinType::kBool , expr);
66-
67- if (!value.has_value ()) {
68- XLS_RETURN_IF_ERROR (
69- converter_.ConvertSubtree (expr, std::nullopt , parametric_context));
70-
71- XLS_ASSIGN_OR_RETURN (
72- value,
73- Evaluate (ParametricContextScopedExpr (
74- parametric_context,
75- CreateBoolAnnotation (*expr->owner (), expr->span ()), expr)));
76-
77- if (expr->kind () == AstNodeKind::kNumber ) {
78- literal_cache_.emplace (
79- std::make_pair (BuiltinType::kBool , expr->ToString ()), *value);
80- }
81- }
82- return value->GetBitValueUnsigned ();
76+ return EvaluateValueOrExpr<bool , BuiltinType::kBool >(parametric_context,
77+ value_or_expr);
8378 }
8479
85- absl::StatusOr<int64_t > EvaluateU32OrExpr (
80+ absl::StatusOr<uint32_t > EvaluateU32OrExpr (
8681 std::optional<const ParametricContext*> parametric_context,
8782 std::variant<int64_t , const Expr*> value_or_expr) override {
88- return Evaluate32BitIntOrExpr (parametric_context, value_or_expr ,
89- /* is_signed= */ false );
83+ return EvaluateValueOrExpr< uint32_t , BuiltinType:: kU32 >(parametric_context ,
84+ value_or_expr );
9085 }
9186
92- absl::StatusOr<int64_t > EvaluateS32OrExpr (
87+ absl::StatusOr<int32_t > EvaluateS32OrExpr (
9388 std::optional<const ParametricContext*> parametric_context,
9489 std::variant<int64_t , const Expr*> value_or_expr) override {
95- return Evaluate32BitIntOrExpr (parametric_context, value_or_expr ,
96- /* is_signed= */ true );
90+ return EvaluateValueOrExpr< int32_t , BuiltinType:: kS32 >(parametric_context ,
91+ value_or_expr );
9792 }
9893
9994 absl::StatusOr<InterpValue> Evaluate (
@@ -156,17 +151,31 @@ class EvaluatorImpl : public Evaluator {
156151 }
157152
158153 private:
159- absl::StatusOr<int64_t > Evaluate32BitIntOrExpr (
154+ template <typename ResultT, typename ValueT>
155+ absl::StatusOr<ResultT> CheckedCast (ValueT value) {
156+ if (value >= static_cast <typename ToSigned<ResultT>::type>(
157+ std::numeric_limits<ResultT>::min ()) &&
158+ value <= std::numeric_limits<ResultT>::max ()) {
159+ return static_cast <ResultT>(value);
160+ }
161+ // We expect overflows from actual user code be detected at type
162+ // unification, so this is not supposed to be reachable.
163+ return absl::InternalError (
164+ absl::StrCat (" Evaluator overflow detected: `" , value,
165+ " ` cannot be represented in target type." ));
166+ }
167+
168+ template <typename ResultT, BuiltinType BuiltinT, typename ValueT>
169+ absl::StatusOr<ResultT> EvaluateValueOrExpr (
160170 std::optional<const ParametricContext*> parametric_context,
161- std::variant<int64_t , const Expr*> value_or_expr, bool is_signed ) {
162- if (std::holds_alternative< int64_t >( value_or_expr)) {
163- return std::get< int64_t >(value_or_expr );
171+ std::variant<ValueT , const Expr*> value_or_expr) {
172+ if (ValueT* value = std::get_if<ValueT>(& value_or_expr)) {
173+ return CheckedCast<ResultT>(*value );
164174 }
165175
166176 const Expr* expr = std::get<const Expr*>(value_or_expr);
167- const BuiltinType type = is_signed ? BuiltinType::kS32 : BuiltinType::kU32 ;
168177 std::optional<InterpValue> value =
169- FastEvaluate (parametric_context, type , expr);
178+ FastEvaluate (parametric_context, BuiltinT , expr);
170179
171180 if (!value.has_value ()) {
172181 XLS_RETURN_IF_ERROR (converter_.ConvertSubtree (
@@ -175,26 +184,28 @@ class EvaluatorImpl : public Evaluator {
175184 std::optional<const TypeAnnotation*> type_annotation =
176185 table_.GetTypeAnnotation (expr);
177186 if (!type_annotation.has_value ()) {
178- type_annotation =
179- is_signed ? CreateS32Annotation (* expr->owner (), expr-> span ())
180- : CreateU32Annotation (* expr->owner (), expr-> span ( ));
187+ type_annotation = expr-> owner ()-> Make <BuiltinTypeAnnotation>(
188+ expr->span (), BuiltinT,
189+ expr->owner ()-> GetOrCreateBuiltinNameDef (BuiltinT ));
181190 }
182191 XLS_ASSIGN_OR_RETURN (
183192 value, Evaluate (ParametricContextScopedExpr (parametric_context,
184193 *type_annotation, expr)));
185194
186195 if (expr->kind () == AstNodeKind::kNumber ) {
187- literal_cache_.emplace (std::make_pair (type, expr->ToString ()), *value);
196+ literal_cache_.emplace (std::make_pair (BuiltinT, expr->ToString ()),
197+ *value);
188198 }
189199 }
190200
191- int64_t result;
192- if (value->IsSigned ()) {
193- XLS_ASSIGN_OR_RETURN (result, value->GetBitValueSigned ());
201+ XLS_ASSIGN_OR_RETURN (bool signedness, GetBuiltinTypeSignedness (BuiltinT));
202+ if (signedness) {
203+ XLS_ASSIGN_OR_RETURN (int64_t result, value->GetBitValueSigned ());
204+ return CheckedCast<ResultT>(result);
194205 } else {
195- XLS_ASSIGN_OR_RETURN (result, value->GetBitValueUnsigned ());
206+ XLS_ASSIGN_OR_RETURN (uint64_t result, value->GetBitValueUnsigned ());
207+ return CheckedCast<ResultT>(result);
196208 }
197- return result;
198209 }
199210
200211 // Evaluates the given `Expr` if there is a faster way to do so than using
0 commit comments