3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-03-23 04:49:15 +00:00

rtlil: add remove2 unit test

This commit is contained in:
Emil J. Tywoniak 2026-03-18 17:03:51 +01:00
parent ea11453cef
commit 27737c6e2e

View file

@ -0,0 +1,333 @@
#include <gtest/gtest.h>
#include "kernel/rtlil.h"
YOSYS_NAMESPACE_BEGIN
// Test fixture with helper functions
class SigSpecRemove2Test : public ::testing::Test {
protected:
Design* d;
Module* m;
void SetUp() override {
d = new Design;
m = d->addModule("$test");
}
void TearDown() override {
delete d;
}
// Create n wires with given width
std::vector<Wire*> createWires(int count, int width = 4) {
std::vector<Wire*> wires;
for (int i = 0; i < count; i++) {
Wire* w = m->addWire(stringf("$w%d", i), width);
wires.push_back(w);
}
return wires;
}
// Append all wires to a SigSpec
SigSpec wiresAsSigSpec(const std::vector<Wire*>& wires) {
SigSpec sig;
for (auto w : wires)
sig.append(w);
return sig;
}
// Create a SigSpec of constants
SigSpec constsAsSigSpec(int count, int width = 4) {
SigSpec sig;
for (int i = 0; i < count; i++)
sig.append(Const(i, width));
return sig;
}
// Convert wires to pool of SigBits
pool<SigBit> wiresToPool(const std::vector<Wire*>& wires) {
pool<SigBit> pool;
for (auto w : wires)
for (auto &bit : SigSpec(w))
pool.insert(bit);
return pool;
}
// Convert wires to set of SigBits
std::set<SigBit> wiresToSet(const std::vector<Wire*>& wires) {
std::set<SigBit> set;
for (auto w : wires)
for (auto &bit : SigSpec(w))
set.insert(bit);
return set;
}
};
TEST_F(SigSpecRemove2Test, WithSigSpecPattern)
{
auto wires = createWires(4);
SigSpec sig = wiresAsSigSpec(wires);
SigSpec pattern(wires[1]); // Remove w2
SigSpec other = constsAsSigSpec(4);
EXPECT_EQ(sig.size(), 16);
sig.remove2(pattern, &other);
EXPECT_EQ(sig.size(), 12);
EXPECT_EQ(other.size(), 12);
// Verify correct wires remain (w1, w3, w4)
SigSpec expected;
expected.append(wires[0]);
expected.append(wires[2]);
expected.append(wires[3]);
EXPECT_EQ(sig, expected);
}
TEST_F(SigSpecRemove2Test, WithPoolPattern)
{
auto wires = createWires(3);
SigSpec sig = wiresAsSigSpec(wires);
auto pattern = wiresToPool({wires[1]});
SigSpec other = constsAsSigSpec(3);
EXPECT_EQ(sig.size(), 12);
sig.remove2(pattern, &other);
EXPECT_EQ(sig.size(), 8);
EXPECT_EQ(other.size(), 8);
// Verify correct wires remain (w0, w2)
SigSpec expected;
expected.append(wires[0]);
expected.append(wires[2]);
EXPECT_EQ(sig, expected);
}
TEST_F(SigSpecRemove2Test, WithSetPattern)
{
auto wires = createWires(3);
SigSpec sig = wiresAsSigSpec(wires);
auto pattern = wiresToSet({wires[1]});
SigSpec other = constsAsSigSpec(3);
EXPECT_EQ(sig.size(), 12);
sig.remove2(pattern, &other);
EXPECT_EQ(sig.size(), 8);
EXPECT_EQ(other.size(), 8);
// Verify correct wires remain (w0, w2)
SigSpec expected;
expected.append(wires[0]);
expected.append(wires[2]);
EXPECT_EQ(sig, expected);
}
TEST_F(SigSpecRemove2Test, ManyElements)
{
const int num_wires = 100;
auto wires = createWires(num_wires);
SigSpec sig = wiresAsSigSpec(wires);
// Remove every other wire
std::vector<Wire*> to_remove;
for (int i = 0; i < num_wires; i += 2)
to_remove.push_back(wires[i]);
auto pattern = wiresToPool(to_remove);
EXPECT_EQ(sig.size(), num_wires * 4);
sig.remove2(pattern, nullptr);
EXPECT_EQ(sig.size(), (num_wires / 2) * 4);
// Verify odd-indexed wires remain (w1, w3, w5, ..., w99)
SigSpec expected;
for (int i = 1; i < num_wires; i += 2)
expected.append(wires[i]);
EXPECT_EQ(sig, expected);
}
// Test remove2 with very large dataset to check scaling
TEST_F(SigSpecRemove2Test, VeryLargeScalingTest)
{
const int num_wires = 50000;
auto wires = createWires(num_wires);
SigSpec sig = wiresAsSigSpec(wires);
SigSpec other = constsAsSigSpec(num_wires);
// Create pattern with many chunks (one per wire)
SigSpec pattern;
for (int i = 0; i < num_wires; i += 2)
pattern.append(wires[i]);
EXPECT_EQ(sig.size(), num_wires * 4);
sig.remove2(pattern, &other);
EXPECT_EQ(sig.size(), (num_wires / 2) * 4);
EXPECT_EQ(other.size(), (num_wires / 2) * 4);
// Spot-check: odd-indexed wires should remain at expected positions
for (int i = 0; i < num_wires / 2; i++) {
EXPECT_EQ(sig[i * 4 + 0].wire, wires[i * 2 + 1]);
EXPECT_EQ(sig[i * 4 + 1].wire, wires[i * 2 + 1]);
EXPECT_EQ(sig[i * 4 + 2].wire, wires[i * 2 + 1]);
EXPECT_EQ(sig[i * 4 + 3].wire, wires[i * 2 + 1]);
}
}
// Test multiple sequential removals (simulates removeSignalFromCaseTree)
TEST_F(SigSpecRemove2Test, MultipleSequentialRemovals)
{
const int num_wires = 512;
auto wires = createWires(num_wires);
// Create many actions, each with one wire
std::vector<SigSpec> actions;
for (auto w : wires)
actions.push_back(SigSpec(w));
// Remove half the wires from all actions
for (int i = 0; i < num_wires / 2; i++) {
SigSpec pattern(wires[i]);
for (auto &action : actions)
if (action.size() > 0)
action.remove2(pattern, nullptr);
}
// Verify correct actions were cleared
for (int i = 0; i < num_wires; i++) {
EXPECT_EQ(actions[i].size(), i < num_wires / 2 ? 0 : 4);
}
// Verify remaining actions contain the correct wires
for (int i = num_wires / 2; i < num_wires; i++) {
SigSpec expected(wires[i]);
EXPECT_EQ(actions[i], expected);
}
}
// Test remove2 with very large dataset to check scaling
TEST_F(SigSpecRemove2Test, PoolOverloadLargeDataset)
{
const int num_wires = 50000;
auto wires = createWires(num_wires, 1);
SigSpec sig = wiresAsSigSpec(wires);
SigSpec other = constsAsSigSpec(num_wires, 1);
// Remove half
pool<SigBit> pattern;
for (int i = 0; i < num_wires; i += 2)
pattern.insert(SigBit(wires[i], 0));
EXPECT_EQ(sig.size(), num_wires);
sig.remove2(pattern, &other);
EXPECT_EQ(sig.size(), num_wires / 2);
EXPECT_EQ(other.size(), num_wires / 2);
// Spot-check: odd-indexed wires should remain
for (int i = 0; i < num_wires / 2; i++) {
EXPECT_EQ(sig[i].wire, wires[i * 2 + 1]);
}
}
// Test set overload (same perf characteristics as pool)
TEST_F(SigSpecRemove2Test, SetOverloadLargeDataset)
{
const int num_wires = 50000;
auto wires = createWires(num_wires, 1);
SigSpec sig = wiresAsSigSpec(wires);
SigSpec other = constsAsSigSpec(num_wires, 1);
// Remove half
std::set<SigBit> pattern;
for (int i = 0; i < num_wires; i += 2)
pattern.insert(SigBit(wires[i], 0));
EXPECT_EQ(sig.size(), num_wires);
sig.remove2(pattern, &other);
EXPECT_EQ(sig.size(), num_wires / 2);
EXPECT_EQ(other.size(), num_wires / 2);
// Spot-check: odd-indexed wires should remain
for (int i = 0; i < num_wires / 2; i++) {
EXPECT_EQ(sig[i].wire, wires[i * 2 + 1]);
}
}
// Worst case: remove almost all elements
TEST_F(SigSpecRemove2Test, RemoveAlmostAllElements)
{
const int num_wires = 10000;
auto wires = createWires(num_wires, 1);
SigSpec sig = wiresAsSigSpec(wires);
// Remove all but last
pool<SigBit> pattern;
for (int i = 0; i < num_wires - 1; i++)
pattern.insert(SigBit(wires[i], 0));
EXPECT_EQ(sig.size(), num_wires);
sig.remove2(pattern, nullptr);
EXPECT_EQ(sig.size(), 1);
EXPECT_EQ(sig[0].wire, wires[num_wires - 1]);
}
TEST_F(SigSpecRemove2Test, EmptyPattern)
{
auto wires = createWires(1);
SigSpec sig(wires[0]);
pool<SigBit> empty_pattern;
EXPECT_EQ(sig.size(), 4);
sig.remove2(empty_pattern, nullptr);
EXPECT_EQ(sig.size(), 4);
// Verify the wire is unchanged
SigSpec expected(wires[0]);
EXPECT_EQ(sig, expected);
}
// Test that NULL wire bits (constants) are not removed
TEST_F(SigSpecRemove2Test, NullWireBitsStay)
{
auto wires = createWires(1);
SigSpec sig;
sig.append(wires[0]);
sig.append(Const(15, 4));
// Try to remove the constants
pool<SigBit> pattern;
SigSpec const_spec(Const(15, 4));
for (auto &bit : const_spec)
pattern.insert(bit);
EXPECT_EQ(sig.size(), 8);
sig.remove2(pattern, nullptr);
EXPECT_EQ(sig.size(), 8); // Constants stay
// Verify original content is preserved
SigSpec expected;
expected.append(wires[0]);
expected.append(Const(15, 4));
EXPECT_EQ(sig, expected);
}
TEST_F(SigSpecRemove2Test, PartialBitRemoval)
{
Wire* w = m->addWire("$w1", 8);
SigSpec sig(w);
// Remove bits 2-5
pool<SigBit> pattern;
for (int i = 2; i < 6; i++)
pattern.insert(SigBit(w, i));
EXPECT_EQ(sig.size(), 8);
sig.remove2(pattern, nullptr);
EXPECT_EQ(sig.size(), 4);
// Verify only bits 0,1,6,7 remain
EXPECT_EQ(sig[0], SigBit(w, 0));
EXPECT_EQ(sig[1], SigBit(w, 1));
EXPECT_EQ(sig[2], SigBit(w, 6));
EXPECT_EQ(sig[3], SigBit(w, 7));
}
YOSYS_NAMESPACE_END