|
| 1 | +// UNSUPPORTED: system-windows |
| 2 | +// See https://github.com/llvm/circt/issues/4129 |
| 3 | +// RUN: circt-reduce --test /usr/bin/env --test-arg true --include firrtl-module-swapper --max-chunks=1 %s | FileCheck %s |
| 4 | + |
| 5 | +// Test that the ModuleSwapper reducer can replace instances of larger modules |
| 6 | +// with instances of smaller modules that have the same port signature. |
| 7 | + |
| 8 | +// CHECK-LABEL: firrtl.circuit "ModuleSwapperTest" |
| 9 | +firrtl.circuit "ModuleSwapperTest" { |
| 10 | + // CHECK: firrtl.module private @SmallModule |
| 11 | + firrtl.module private @SmallModule(in %a: !firrtl.uint<1>, out %b: !firrtl.uint<1>) { |
| 12 | + // Small module with minimal implementation |
| 13 | + firrtl.connect %b, %a : !firrtl.uint<1>, !firrtl.uint<1> |
| 14 | + } |
| 15 | + |
| 16 | + // CHECK: firrtl.module private @LargeModule |
| 17 | + firrtl.module private @LargeModule(in %a: !firrtl.uint<1>, out %b: !firrtl.uint<1>) { |
| 18 | + // Large module with more complex implementation (same interface as SmallModule) |
| 19 | + %wire1 = firrtl.wire : !firrtl.uint<1> |
| 20 | + %wire2 = firrtl.wire : !firrtl.uint<1> |
| 21 | + %wire3 = firrtl.wire : !firrtl.uint<1> |
| 22 | + firrtl.connect %wire1, %a : !firrtl.uint<1>, !firrtl.uint<1> |
| 23 | + firrtl.connect %wire2, %wire1 : !firrtl.uint<1>, !firrtl.uint<1> |
| 24 | + firrtl.connect %wire3, %wire2 : !firrtl.uint<1>, !firrtl.uint<1> |
| 25 | + firrtl.connect %b, %wire3 : !firrtl.uint<1>, !firrtl.uint<1> |
| 26 | + } |
| 27 | + |
| 28 | + // CHECK: firrtl.module private @AnotherLargeModule |
| 29 | + firrtl.module private @AnotherLargeModule(in %a: !firrtl.uint<1>, out %b: !firrtl.uint<1>) { |
| 30 | + // Another large module with same interface but different implementation |
| 31 | + %wire1 = firrtl.wire : !firrtl.uint<1> |
| 32 | + %wire2 = firrtl.wire : !firrtl.uint<1> |
| 33 | + %wire3 = firrtl.wire : !firrtl.uint<1> |
| 34 | + %wire4 = firrtl.wire : !firrtl.uint<1> |
| 35 | + firrtl.connect %wire1, %a : !firrtl.uint<1>, !firrtl.uint<1> |
| 36 | + firrtl.connect %wire2, %wire1 : !firrtl.uint<1>, !firrtl.uint<1> |
| 37 | + firrtl.connect %wire3, %wire2 : !firrtl.uint<1>, !firrtl.uint<1> |
| 38 | + firrtl.connect %wire4, %wire3 : !firrtl.uint<1>, !firrtl.uint<1> |
| 39 | + firrtl.connect %b, %wire4 : !firrtl.uint<1>, !firrtl.uint<1> |
| 40 | + } |
| 41 | + |
| 42 | + // Module with different interface - should not be affected |
| 43 | + // CHECK: firrtl.module private @DifferentInterface |
| 44 | + firrtl.module private @DifferentInterface(in %x: !firrtl.uint<2>, out %y: !firrtl.uint<2>) { |
| 45 | + %wire = firrtl.wire : !firrtl.uint<2> |
| 46 | + firrtl.connect %wire, %x : !firrtl.uint<2>, !firrtl.uint<2> |
| 47 | + firrtl.connect %y, %wire : !firrtl.uint<2>, !firrtl.uint<2> |
| 48 | + } |
| 49 | + |
| 50 | + // CHECK: firrtl.module @ModuleSwapperTest |
| 51 | + firrtl.module @ModuleSwapperTest(in %clk: !firrtl.clock, in %input: !firrtl.uint<1>, out %output1: !firrtl.uint<1>, out %output2: !firrtl.uint<1>, out %output3: !firrtl.uint<1>, out %output4: !firrtl.uint<2>) { |
| 52 | + // CHECK: firrtl.instance small @SmallModule |
| 53 | + %small_a, %small_b = firrtl.instance small @SmallModule(in a: !firrtl.uint<1>, out b: !firrtl.uint<1>) |
| 54 | + |
| 55 | + // CHECK: firrtl.instance large @SmallModule |
| 56 | + %large_a, %large_b = firrtl.instance large @LargeModule(in a: !firrtl.uint<1>, out b: !firrtl.uint<1>) |
| 57 | + |
| 58 | + // CHECK: firrtl.instance another @SmallModule |
| 59 | + %another_a, %another_b = firrtl.instance another @AnotherLargeModule(in a: !firrtl.uint<1>, out b: !firrtl.uint<1>) |
| 60 | + |
| 61 | + // This should remain unchanged as it has a different interface |
| 62 | + // CHECK: firrtl.instance diff @DifferentInterface |
| 63 | + %diff_x, %diff_y = firrtl.instance diff @DifferentInterface(in x: !firrtl.uint<2>, out y: !firrtl.uint<2>) |
| 64 | + |
| 65 | + // Connect inputs |
| 66 | + firrtl.connect %small_a, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 67 | + firrtl.connect %large_a, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 68 | + firrtl.connect %another_a, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 69 | + |
| 70 | + %input_ext = firrtl.pad %input, 2 : (!firrtl.uint<1>) -> !firrtl.uint<2> |
| 71 | + firrtl.connect %diff_x, %input_ext : !firrtl.uint<2>, !firrtl.uint<2> |
| 72 | + |
| 73 | + // Connect outputs |
| 74 | + firrtl.connect %output1, %small_b : !firrtl.uint<1>, !firrtl.uint<1> |
| 75 | + firrtl.connect %output2, %large_b : !firrtl.uint<1>, !firrtl.uint<1> |
| 76 | + firrtl.connect %output3, %another_b : !firrtl.uint<1>, !firrtl.uint<1> |
| 77 | + firrtl.connect %output4, %diff_y : !firrtl.uint<2>, !firrtl.uint<2> |
| 78 | + } |
| 79 | +} |
| 80 | + |
| 81 | +// Test with modules that have different port directions but same types |
| 82 | +// CHECK-LABEL: firrtl.circuit "DirectionTest" |
| 83 | +firrtl.circuit "DirectionTest" { |
| 84 | + // CHECK: firrtl.module private @SimpleInOut |
| 85 | + firrtl.module private @SimpleInOut(in %in: !firrtl.uint<1>, out %out: !firrtl.uint<1>) { |
| 86 | + firrtl.connect %out, %in : !firrtl.uint<1>, !firrtl.uint<1> |
| 87 | + } |
| 88 | + |
| 89 | + // CHECK: firrtl.module private @ComplexInOut |
| 90 | + firrtl.module private @ComplexInOut(in %in: !firrtl.uint<1>, out %out: !firrtl.uint<1>) { |
| 91 | + %w1 = firrtl.wire : !firrtl.uint<1> |
| 92 | + %w2 = firrtl.wire : !firrtl.uint<1> |
| 93 | + %w3 = firrtl.wire : !firrtl.uint<1> |
| 94 | + firrtl.connect %w1, %in : !firrtl.uint<1>, !firrtl.uint<1> |
| 95 | + firrtl.connect %w2, %w1 : !firrtl.uint<1>, !firrtl.uint<1> |
| 96 | + firrtl.connect %w3, %w2 : !firrtl.uint<1>, !firrtl.uint<1> |
| 97 | + firrtl.connect %out, %w3 : !firrtl.uint<1>, !firrtl.uint<1> |
| 98 | + } |
| 99 | + |
| 100 | + // Different direction - should not be grouped with above modules |
| 101 | + // CHECK: firrtl.module private @OutIn |
| 102 | + firrtl.module private @OutIn(out %out: !firrtl.uint<1>, in %in: !firrtl.uint<1>) { |
| 103 | + %wire = firrtl.wire : !firrtl.uint<1> |
| 104 | + firrtl.connect %wire, %in : !firrtl.uint<1>, !firrtl.uint<1> |
| 105 | + firrtl.connect %out, %wire : !firrtl.uint<1>, !firrtl.uint<1> |
| 106 | + } |
| 107 | + |
| 108 | + // CHECK: firrtl.module @DirectionTest |
| 109 | + firrtl.module @DirectionTest(in %input: !firrtl.uint<1>, out %output1: !firrtl.uint<1>, out %output2: !firrtl.uint<1>, out %output3: !firrtl.uint<1>) { |
| 110 | + // CHECK: firrtl.instance simple @SimpleInOut |
| 111 | + %simple_in, %simple_out = firrtl.instance simple @SimpleInOut(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) |
| 112 | + |
| 113 | + // CHECK: firrtl.instance complex @SimpleInOut |
| 114 | + %complex_in, %complex_out = firrtl.instance complex @ComplexInOut(in in: !firrtl.uint<1>, out out: !firrtl.uint<1>) |
| 115 | + |
| 116 | + // This should remain unchanged due to different port order |
| 117 | + // CHECK: firrtl.instance outIn @OutIn |
| 118 | + %outIn_out, %outIn_in = firrtl.instance outIn @OutIn(out out: !firrtl.uint<1>, in in: !firrtl.uint<1>) |
| 119 | + |
| 120 | + firrtl.connect %simple_in, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 121 | + firrtl.connect %complex_in, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 122 | + firrtl.connect %outIn_in, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 123 | + |
| 124 | + firrtl.connect %output1, %simple_out : !firrtl.uint<1>, !firrtl.uint<1> |
| 125 | + firrtl.connect %output2, %complex_out : !firrtl.uint<1>, !firrtl.uint<1> |
| 126 | + firrtl.connect %output3, %outIn_out : !firrtl.uint<1>, !firrtl.uint<1> |
| 127 | + } |
| 128 | +} |
| 129 | + |
| 130 | +// Test that instances participating in NLAs are not swapped |
| 131 | +// CHECK-LABEL: firrtl.circuit "NLATest" |
| 132 | +firrtl.circuit "NLATest" { |
| 133 | + // NLA that references an instance |
| 134 | + // CHECK: hw.hierpath private @nla [@NLATest::@large, @LargeNLA] |
| 135 | + hw.hierpath private @nla [@NLATest::@large, @LargeNLA] |
| 136 | + |
| 137 | + // CHECK: firrtl.module private @SmallNLA |
| 138 | + firrtl.module private @SmallNLA(in %a: !firrtl.uint<1>, out %b: !firrtl.uint<1>) { |
| 139 | + // Small simple module |
| 140 | + firrtl.connect %b, %a : !firrtl.uint<1>, !firrtl.uint<1> |
| 141 | + } |
| 142 | + |
| 143 | + // CHECK: firrtl.module private @LargeNLA |
| 144 | + firrtl.module private @LargeNLA(in %a: !firrtl.uint<1>, out %b: !firrtl.uint<1>) { |
| 145 | + // Large module with same interface as SmallNLA |
| 146 | + %wire1 = firrtl.wire : !firrtl.uint<1> |
| 147 | + %wire2 = firrtl.wire : !firrtl.uint<1> |
| 148 | + %wire3 = firrtl.wire : !firrtl.uint<1> |
| 149 | + %wire4 = firrtl.wire : !firrtl.uint<1> |
| 150 | + firrtl.connect %wire1, %a : !firrtl.uint<1>, !firrtl.uint<1> |
| 151 | + firrtl.connect %wire2, %wire1 : !firrtl.uint<1>, !firrtl.uint<1> |
| 152 | + firrtl.connect %wire3, %wire2 : !firrtl.uint<1>, !firrtl.uint<1> |
| 153 | + firrtl.connect %wire4, %wire3 : !firrtl.uint<1>, !firrtl.uint<1> |
| 154 | + firrtl.connect %b, %wire4 : !firrtl.uint<1>, !firrtl.uint<1> |
| 155 | + } |
| 156 | + |
| 157 | + // CHECK: firrtl.module @NLATest |
| 158 | + firrtl.module @NLATest(in %input: !firrtl.uint<1>, out %output1: !firrtl.uint<1>, out %output2: !firrtl.uint<1>, out %output3: !firrtl.uint<1>, out %output4: !firrtl.uint<1>) { |
| 159 | + // This instance should remain as SmallNLA (already the smallest) |
| 160 | + // CHECK: firrtl.instance small @SmallNLA |
| 161 | + %small_a, %small_b = firrtl.instance small @SmallNLA(in a: !firrtl.uint<1>, out b: !firrtl.uint<1>) |
| 162 | + |
| 163 | + // This instance should NOT be swapped because it participates in an NLA |
| 164 | + // CHECK: firrtl.instance large sym @large {annotations = [{circt.nonlocal = @nla, class = "test"}]} @LargeNLA |
| 165 | + %large_a, %large_b = firrtl.instance large sym @large {annotations = [{circt.nonlocal = @nla, class = "test"}]} @LargeNLA(in a: !firrtl.uint<1>, out b: !firrtl.uint<1>) |
| 166 | + |
| 167 | + // This instance should be swapped because it does not participate in an NLA |
| 168 | + // CHECK: firrtl.instance another @SmallNLA |
| 169 | + %another_a, %another_b = firrtl.instance another @LargeNLA(in a: !firrtl.uint<1>, out b: !firrtl.uint<1>) |
| 170 | + |
| 171 | + firrtl.connect %small_a, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 172 | + firrtl.connect %large_a, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 173 | + firrtl.connect %another_a, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 174 | + firrtl.connect %output1, %small_b : !firrtl.uint<1>, !firrtl.uint<1> |
| 175 | + firrtl.connect %output2, %large_b : !firrtl.uint<1>, !firrtl.uint<1> |
| 176 | + firrtl.connect %output3, %another_b : !firrtl.uint<1>, !firrtl.uint<1> |
| 177 | + } |
| 178 | +} |
| 179 | + |
| 180 | +// Test that modules with different port names but same types are swapped |
| 181 | +// CHECK-LABEL: firrtl.circuit "PortNameTest" |
| 182 | +firrtl.circuit "PortNameTest" { |
| 183 | + // CHECK: firrtl.module private @SmallPortNames |
| 184 | + firrtl.module private @SmallPortNames(in %input: !firrtl.uint<1>, out %output: !firrtl.uint<1>) { |
| 185 | + // Small module with simple port names |
| 186 | + firrtl.connect %output, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 187 | + } |
| 188 | + |
| 189 | + // CHECK: firrtl.module private @LargePortNames |
| 190 | + firrtl.module private @LargePortNames(in %data_in: !firrtl.uint<1>, out %data_out: !firrtl.uint<1>) { |
| 191 | + // Large module with different port names but same types |
| 192 | + %wire1 = firrtl.wire : !firrtl.uint<1> |
| 193 | + %wire2 = firrtl.wire : !firrtl.uint<1> |
| 194 | + %wire3 = firrtl.wire : !firrtl.uint<1> |
| 195 | + firrtl.connect %wire1, %data_in : !firrtl.uint<1>, !firrtl.uint<1> |
| 196 | + firrtl.connect %wire2, %wire1 : !firrtl.uint<1>, !firrtl.uint<1> |
| 197 | + firrtl.connect %wire3, %wire2 : !firrtl.uint<1>, !firrtl.uint<1> |
| 198 | + firrtl.connect %data_out, %wire3 : !firrtl.uint<1>, !firrtl.uint<1> |
| 199 | + } |
| 200 | + |
| 201 | + // CHECK: firrtl.module @PortNameTest |
| 202 | + firrtl.module @PortNameTest(in %clk: !firrtl.clock, in %input: !firrtl.uint<1>, out %output1: !firrtl.uint<1>, out %output2: !firrtl.uint<1>) { |
| 203 | + // CHECK: firrtl.instance small @SmallPortNames |
| 204 | + %small_input, %small_output = firrtl.instance small @SmallPortNames(in input: !firrtl.uint<1>, out output: !firrtl.uint<1>) |
| 205 | + |
| 206 | + // This should be swapped to SmallPortNames and port names should be updated |
| 207 | + // CHECK: firrtl.instance large @SmallPortNames(in input: !firrtl.uint<1>, out output: !firrtl.uint<1>) |
| 208 | + %large_data_in, %large_data_out = firrtl.instance large @LargePortNames(in data_in: !firrtl.uint<1>, out data_out: !firrtl.uint<1>) |
| 209 | + |
| 210 | + // Connect inputs |
| 211 | + firrtl.connect %small_input, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 212 | + firrtl.connect %large_data_in, %input : !firrtl.uint<1>, !firrtl.uint<1> |
| 213 | + |
| 214 | + // Connect outputs |
| 215 | + firrtl.connect %output1, %small_output : !firrtl.uint<1>, !firrtl.uint<1> |
| 216 | + firrtl.connect %output2, %large_data_out : !firrtl.uint<1>, !firrtl.uint<1> |
| 217 | + } |
| 218 | +} |
0 commit comments