diff --git a/xls/dslx/bytecode/builtins.cc b/xls/dslx/bytecode/builtins.cc index e3956d1d2d..66e9fbd73f 100644 --- a/xls/dslx/bytecode/builtins.cc +++ b/xls/dslx/bytecode/builtins.cc @@ -158,7 +158,7 @@ absl::Status BuiltinRangeInternal(InterpreterStack& stack) { XLS_RET_CHECK(end.IsBits()); XLS_ASSIGN_OR_RETURN(InterpValue start_ge_end, start.Ge(end)); if (start_ge_end.IsTrue()) { - return InterpValue::MakeArray({}); + return InterpValue::MakeRange({}); } std::vector elements; @@ -172,7 +172,7 @@ absl::Status BuiltinRangeInternal(InterpreterStack& stack) { XLS_ASSIGN_OR_RETURN(cur, cur.Add(one)); XLS_ASSIGN_OR_RETURN(done, cur.Ge(end)); } - return InterpValue::MakeArray(elements); + return InterpValue::MakeRange(elements); }, stack); } diff --git a/xls/dslx/bytecode/bytecode_interpreter_test.cc b/xls/dslx/bytecode/bytecode_interpreter_test.cc index 3997afc73c..494e1d5e54 100644 --- a/xls/dslx/bytecode/bytecode_interpreter_test.cc +++ b/xls/dslx/bytecode/bytecode_interpreter_test.cc @@ -2002,6 +2002,18 @@ fn main() -> u32[8] { } } +TEST_F(BytecodeInterpreterTest, RangeExprEmpty) { + constexpr std::string_view kProgram = R"( +fn main() -> u32[0] { + u32:100..u32:100 +})"; + + XLS_ASSERT_OK_AND_ASSIGN(InterpValue value, Interpret(kProgram, "main")); + XLS_ASSERT_OK_AND_ASSIGN(const std::vector* elements, + value.GetValues()); + EXPECT_EQ(elements->size(), 0); +} + TEST_F(BytecodeInterpreterTest, TypeMaxExprU7) { constexpr std::string_view kProgram = R"( fn main() -> u7 { diff --git a/xls/dslx/interp_value.cc b/xls/dslx/interp_value.cc index 4b85c515b7..f3c6c7d540 100644 --- a/xls/dslx/interp_value.cc +++ b/xls/dslx/interp_value.cc @@ -87,6 +87,12 @@ std::string TagToString(InterpValueTag tag) { return InterpValue{InterpValueTag::kArray, std::move(elements)}; } +/* static */ absl::StatusOr InterpValue::MakeRange( + std::vector elements) { + return InterpValue{InterpValueTag::kArray, std::move(elements), + /*is_range=*/true}; +} + /* static */ InterpValue InterpValue::MakeUBits(int64_t bit_count, int64_t value) { return InterpValue{InterpValueTag::kUBits, @@ -975,7 +981,11 @@ absl::StatusOr InterpValue::Concat( for (const InterpValue& o : other.GetValuesOrDie()) { result.push_back(o); } - return InterpValue(InterpValueTag::kArray, std::move(result)); + // We don't propagate is_range_ from either operand, because the resulting + // concatenated array may or may not represent a contiguous range of + // values anymore. + return InterpValue(InterpValueTag::kArray, std::move(result), + /*is_range=*/false); } case InterpValueTag::kUBits: return InterpValue( diff --git a/xls/dslx/interp_value.h b/xls/dslx/interp_value.h index 0ba7eee2dd..2957847ea9 100644 --- a/xls/dslx/interp_value.h +++ b/xls/dslx/interp_value.h @@ -249,6 +249,8 @@ class InterpValue { static InterpValue MakeBool(bool value) { return MakeUBits(1, value ? 1 : 0); } + static absl::StatusOr MakeRange( + std::vector elements); static absl::StatusOr MakeBits(InterpValueTag tag, Bits bits) { if (tag != InterpValueTag::kUBits && tag != InterpValueTag::kSBits) { @@ -541,6 +543,8 @@ class InterpValue { bool operator<(const InterpValue& rhs) const; bool operator>=(const InterpValue& rhs) const; + bool is_range() const { return is_range_; } + private: friend struct InterpValuePickler; @@ -576,8 +580,8 @@ class InterpValue { std::shared_ptr, ChannelReference, TypeReference, std::shared_ptr>; - InterpValue(InterpValueTag tag, Payload payload) - : tag_(tag), payload_(std::move(payload)) {} + InterpValue(InterpValueTag tag, Payload payload, bool is_range = false) + : tag_(tag), payload_(std::move(payload)), is_range_(is_range) {} using CompareF = bool (*)(const Bits& lhs, const Bits& rhs); @@ -588,6 +592,7 @@ class InterpValue { InterpValueTag tag_; Payload payload_; + bool is_range_; }; template diff --git a/xls/dslx/interp_value_test.cc b/xls/dslx/interp_value_test.cc index 61b17fbed1..98cd271328 100644 --- a/xls/dslx/interp_value_test.cc +++ b/xls/dslx/interp_value_test.cc @@ -94,6 +94,22 @@ TEST(InterpValueTest, FlattenArrayOfBits) { EXPECT_THAT(o->GetBitValueUnsigned(), IsOkAndHolds(0xf00ba5)); } +TEST(InterpValueTest, ConcatRange) { + auto a = InterpValue::MakeUBits(/*bit_count=*/4, 1); + auto b = InterpValue::MakeUBits(/*bit_count=*/4, 2); + XLS_ASSERT_OK_AND_ASSIGN(InterpValue range_a, InterpValue::MakeRange({a})); + XLS_ASSERT_OK_AND_ASSIGN(InterpValue array_b, InterpValue::MakeArray({b})); + + XLS_ASSERT_OK_AND_ASSIGN(InterpValue concat, range_a.Concat(array_b)); + // Concatenating ranges don't produce a range, it produces an array. + EXPECT_FALSE(concat.is_range()); + EXPECT_TRUE(concat.IsArray()); + + XLS_ASSERT_OK_AND_ASSIGN(InterpValue concat2, array_b.Concat(range_a)); + EXPECT_FALSE(concat2.is_range()); + EXPECT_TRUE(concat2.IsArray()); +} + TEST(InterpValueTest, BitwiseNegateAllBitsSet) { auto v = InterpValue::MakeUBits(/*bit_count=*/3, 0x7); auto expected = InterpValue::MakeUBits(/*bit_count=*/3, 0);