15
15
#include " xls/dslx/type_system_v2/evaluator.h"
16
16
17
17
#include < cstdint>
18
+ #include < limits>
18
19
#include < memory>
19
20
#include < optional>
20
21
#include < string>
22
+ #include < type_traits>
21
23
#include < utility>
22
24
#include < variant>
23
25
24
26
#include " absl/container/flat_hash_map.h"
25
27
#include " absl/log/log.h"
28
+ #include " absl/status/status.h"
26
29
#include " absl/status/statusor.h"
30
+ #include " absl/strings/str_cat.h"
27
31
#include " xls/common/casts.h"
28
32
#include " xls/common/status/status_macros.h"
29
33
#include " xls/dslx/constexpr_evaluator.h"
42
46
namespace xls ::dslx {
43
47
namespace {
44
48
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
+
45
61
class EvaluatorImpl : public Evaluator {
46
62
public:
47
63
EvaluatorImpl (InferenceTable& table, Module& module , ImportData& import_data,
@@ -57,43 +73,22 @@ class EvaluatorImpl : public Evaluator {
57
73
absl::StatusOr<bool > EvaluateBoolOrExpr (
58
74
std::optional<const ParametricContext*> parametric_context,
59
75
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);
83
78
}
84
79
85
- absl::StatusOr<int64_t > EvaluateU32OrExpr (
80
+ absl::StatusOr<uint32_t > EvaluateU32OrExpr (
86
81
std::optional<const ParametricContext*> parametric_context,
87
82
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 );
90
85
}
91
86
92
- absl::StatusOr<int64_t > EvaluateS32OrExpr (
87
+ absl::StatusOr<int32_t > EvaluateS32OrExpr (
93
88
std::optional<const ParametricContext*> parametric_context,
94
89
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 );
97
92
}
98
93
99
94
absl::StatusOr<InterpValue> Evaluate (
@@ -156,17 +151,31 @@ class EvaluatorImpl : public Evaluator {
156
151
}
157
152
158
153
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 (
160
170
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 );
164
174
}
165
175
166
176
const Expr* expr = std::get<const Expr*>(value_or_expr);
167
- const BuiltinType type = is_signed ? BuiltinType::kS32 : BuiltinType::kU32 ;
168
177
std::optional<InterpValue> value =
169
- FastEvaluate (parametric_context, type , expr);
178
+ FastEvaluate (parametric_context, BuiltinT , expr);
170
179
171
180
if (!value.has_value ()) {
172
181
XLS_RETURN_IF_ERROR (converter_.ConvertSubtree (
@@ -175,26 +184,28 @@ class EvaluatorImpl : public Evaluator {
175
184
std::optional<const TypeAnnotation*> type_annotation =
176
185
table_.GetTypeAnnotation (expr);
177
186
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 ));
181
190
}
182
191
XLS_ASSIGN_OR_RETURN (
183
192
value, Evaluate (ParametricContextScopedExpr (parametric_context,
184
193
*type_annotation, expr)));
185
194
186
195
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);
188
198
}
189
199
}
190
200
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);
194
205
} else {
195
- XLS_ASSIGN_OR_RETURN (result, value->GetBitValueUnsigned ());
206
+ XLS_ASSIGN_OR_RETURN (uint64_t result, value->GetBitValueUnsigned ());
207
+ return CheckedCast<ResultT>(result);
196
208
}
197
- return result;
198
209
}
199
210
200
211
// Evaluates the given `Expr` if there is a faster way to do so than using
0 commit comments