Skip to content

Commit b9f0e22

Browse files
committed
Add test
1 parent e478497 commit b9f0e22

File tree

5 files changed

+630
-15
lines changed

5 files changed

+630
-15
lines changed

lib/Dialect/FIRRTL/Transforms/InferDomains.cpp

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ struct TermBase : Term {
211211
struct VariableTerm : public TermBase<TermKind::Variable> {
212212
VariableTerm() : leader(nullptr) {}
213213
VariableTerm(Term *leader) : leader(leader) {}
214-
Term *leader;
214+
Term *leader = nullptr;
215215
};
216216

217217
/// A concrete value defined in the IR.
@@ -246,12 +246,14 @@ Term *find(Term *x) {
246246
}
247247

248248
/// A helper for assigning low numeric IDs to variables for user-facing output.
249-
struct VariableIDTable {
249+
class VariableIDTable {
250+
public:
250251
size_t get(VariableTerm *term) {
251252
auto [it, inserted] = table.insert({term, table.size() + 1});
252253
return it->second;
253254
}
254255

256+
private:
255257
DenseMap<VariableTerm *, size_t> table;
256258
};
257259

@@ -303,13 +305,8 @@ raw_ostream &dump(raw_ostream &out, const ValueTerm *term) {
303305
// NOLINTNEXTLINE(misc-no-recursion)
304306
raw_ostream &dump(raw_ostream &out, const RowTerm *term) {
305307
out << "row@" << term << "{";
306-
bool first = true;
307-
for (auto *element : term->elements) {
308-
if (!first)
309-
out << ", ";
310-
dump(out, element);
311-
first = false;
312-
}
308+
llvm::interleaveComma(term->elements, out,
309+
[&](auto element) { dump(out, element); });
313310
out << "}";
314311
return out;
315312
}
@@ -708,6 +705,7 @@ template <typename T>
708705
LogicalResult processInstancePorts(const DomainInfo &info,
709706
TermAllocator &allocator, DomainTable &table,
710707
T op) {
708+
llvm::errs() << "ins=" << op << "\n";
711709
auto numDomainTypes = info.getNumDomains();
712710
DenseMap<unsigned, unsigned> domainPortTypeIDTable;
713711
auto domainInfo = op.getDomainInfoAttr();
@@ -966,7 +964,7 @@ void createModuleDomainPorts(const DomainInfo &info, TermAllocator &allocator,
966964
if (isPort(module, value))
967965
continue;
968966

969-
// The domain is defined internally. If there value is already exported,
967+
// The domain is defined internally. If the value is already exported,
970968
// or will be exported, we are done.
971969
if (exportTable.contains(value) || pendingExports.contains(value))
972970
continue;
@@ -1134,7 +1132,7 @@ LogicalResult updateModuleDomainInfo(const DomainInfo &info,
11341132
continue;
11351133
}
11361134

1137-
newModuleDomainInfo[i] = oldModuleDomainInfo[i];
1135+
newModuleDomainInfo[i] = ArrayAttr::get(context, {});
11381136
}
11391137

11401138
result = ArrayAttr::get(module.getContext(), newModuleDomainInfo);
@@ -1410,12 +1408,12 @@ LogicalResult checkAndInferModule(const DomainInfo &info,
14101408

14111409
LogicalResult runOnModuleLike(InferDomainsMode mode, const DomainInfo &info,
14121410
ModuleUpdateTable &updateTable, Operation *op) {
1413-
// llvm::errs() << "********\n";
1414-
// llvm::errs() << *op << "\n";
1415-
1416-
if (auto module = dyn_cast<FModuleOp>(op)) {
1411+
1412+
llvm::errs() << *op << "\n";
1413+
if (auto module = dyn_cast<FModuleOp>(op)) {
14171414
if (mode == InferDomainsMode::Check)
14181415
return checkModule(info, module);
1416+
14191417
if (mode == InferDomainsMode::InferAll || module.isPrivate())
14201418
return inferModule(info, updateTable, module);
14211419

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// RUN: circt-opt -pass-pipeline='builtin.module(firrtl.circuit(firrtl-infer-domains{mode=infer-all}))' %s --verify-diagnostics
2+
3+
// Port annotated with same domain type twice.
4+
firrtl.circuit "DomainCrossOnPort" {
5+
firrtl.domain @ClockDomain
6+
firrtl.module @DomainCrossOnPort(
7+
in %A: !firrtl.domain of @ClockDomain,
8+
in %B: !firrtl.domain of @ClockDomain,
9+
// expected-error @below {{illegal "ClockDomain" crossing in port "p"}}
10+
// expected-note @below {{1st instance: A}}
11+
// expected-note @below {{2nd instance: B}}
12+
in %p: !firrtl.uint<1> domains [%A, %B]
13+
) {}
14+
}
15+
16+
// Illegal domain crossing via connect op.
17+
firrtl.circuit "IllegalDomainCrossing" {
18+
firrtl.domain @ClockDomain
19+
firrtl.module @IllegalDomainCrossing(
20+
in %A: !firrtl.domain of @ClockDomain,
21+
in %B: !firrtl.domain of @ClockDomain,
22+
// expected-note @below {{2nd operand has domains: [ClockDomain: A]}}
23+
in %a: !firrtl.uint<1> domains [%A],
24+
// expected-note @below {{1st operand has domains: [ClockDomain: B]}}
25+
out %b: !firrtl.uint<1> domains [%B]
26+
) {
27+
// expected-error @below {{illegal domain crossing in operation}}
28+
firrtl.connect %b, %a : !firrtl.uint<1>
29+
}
30+
}
31+
32+
// Illegal domain crossing at matchingconnect op.
33+
firrtl.circuit "IllegalDomainCrossing" {
34+
firrtl.domain @ClockDomain
35+
firrtl.module @IllegalDomainCrossing(
36+
in %A: !firrtl.domain of @ClockDomain,
37+
in %B: !firrtl.domain of @ClockDomain,
38+
// expected-note @below {{2nd operand has domains: [ClockDomain: A]}}
39+
in %a: !firrtl.uint<1> domains [%A],
40+
// expected-note @below {{1st operand has domains: [ClockDomain: B]}}
41+
out %b: !firrtl.uint<1> domains [%B]
42+
) {
43+
// expected-error @below {{illegal domain crossing in operation}}
44+
firrtl.matchingconnect %b, %a : !firrtl.uint<1>
45+
}
46+
}
47+
48+
// Unable to infer domain of port, when port is driven by constant.
49+
firrtl.circuit "UnableToInferDomainOfPortDrivenByConstant" {
50+
firrtl.domain @ClockDomain
51+
firrtl.module @Foo(in %i: !firrtl.uint<1>) {}
52+
53+
firrtl.module @UnableToInferDomainOfPortDrivenByConstant() {
54+
%c0_ui1 = firrtl.constant 0 : !firrtl.uint<1>
55+
// expected-error @below {{unable to infer value for undriven domain port "ClockDomain"}}
56+
// expected-note @below {{associated with hardware port "i"}}
57+
%foo_i = firrtl.instance foo @Foo(in i: !firrtl.uint<1>)
58+
firrtl.matchingconnect %foo_i, %c0_ui1 : !firrtl.uint<1>
59+
}
60+
}
61+
62+
// Unable to infer domain of port, when port is driven by arithmetic on constant.
63+
firrtl.circuit "UnableToInferDomainOfPortDrivenByConstantExpr" {
64+
firrtl.domain @ClockDomain
65+
firrtl.module @Foo(in %i: !firrtl.uint<2>) {}
66+
67+
firrtl.module @UnableToInferDomainOfPortDrivenByConstantExpr() {
68+
%c0_ui1 = firrtl.constant 0 : !firrtl.uint<1>
69+
%0 = firrtl.add %c0_ui1, %c0_ui1 : (!firrtl.uint<1>, !firrtl.uint<1>) -> !firrtl.uint<2>
70+
// expected-error @below {{unable to infer value for undriven domain port "ClockDomain"}}
71+
// expected-note @below {{associated with hardware port "i"}}
72+
%foo_i = firrtl.instance foo @Foo(in i: !firrtl.uint<2>)
73+
firrtl.matchingconnect %foo_i, %0 : !firrtl.uint<2>
74+
}
75+
}
76+
77+
// Incomplete extmodule domain information.
78+
79+
firrtl.circuit "Top" {
80+
firrtl.domain @ClockDomain
81+
82+
// expected-error @below {{missing "ClockDomain" association for port "i"}}
83+
firrtl.extmodule @Top(in i: !firrtl.uint<1>)
84+
}
85+
86+
// Conflicting extmodule domain information.
87+
88+
firrtl.circuit "Top" {
89+
firrtl.domain @ClockDomain
90+
91+
firrtl.extmodule @Top(
92+
// expected-note @below {{associated with "ClockDomain" port "D1"}}
93+
in D1 : !firrtl.domain of @ClockDomain,
94+
// expected-note @below {{associated with "ClockDomain" port "D2"}}
95+
in D2 : !firrtl.domain of @ClockDomain,
96+
// expected-error @below {{ambiguous "ClockDomain" association for port "i"}}
97+
in i: !firrtl.uint<1> domains [D1, D2]
98+
)
99+
}
100+
101+
// -----
102+
103+
// Domain exported multiple times. Which do we choose?
104+
105+
firrtl.circuit "DoubleExportOfDomain" {
106+
firrtl.domain @ClockDomain
107+
108+
firrtl.module @DoubleExportOfDomain(
109+
// expected-note @below {{candidate association "DI"}}
110+
in %DI : !firrtl.domain of @ClockDomain,
111+
// expected-note @below {{candidate association "DO"}}
112+
out %DO : !firrtl.domain of @ClockDomain,
113+
in %i : !firrtl.uint<1> domains [%DO],
114+
// expected-error @below {{ambiguous "ClockDomain" association for port "o"}}
115+
out %o : !firrtl.uint<1> domains []
116+
) {
117+
// DI and DO are aliases
118+
firrtl.domain.define %DO, %DI
119+
120+
// o is on same domain as i
121+
firrtl.matchingconnect %o, %i : !firrtl.uint<1>
122+
}
123+
}
124+
125+
// Domain exported multiple times, this time with two outputs.
126+
127+
firrtl.circuit "DoubleExportOfDomain" {
128+
firrtl.domain @ClockDomain
129+
130+
firrtl.extmodule @Generator(out D: !firrtl.domain of @ClockDomain)
131+
132+
firrtl.module @DoubleExportOfDomain(
133+
// expected-note @below {{candidate association "D1"}}
134+
out %D1 : !firrtl.domain of @ClockDomain,
135+
// expected-note @below {{candidate association "D2"}}
136+
out %D2 : !firrtl.domain of @ClockDomain,
137+
in %i : !firrtl.uint<1> domains [%D1],
138+
// expected-error @below {{ambiguous "ClockDomain" association for port "o"}}
139+
out %o : !firrtl.uint<1> domains []
140+
) {
141+
%gen_D = firrtl.instance gen @Generator(out D: !firrtl.domain of @ClockDomain)
142+
// DI and DO are aliases
143+
firrtl.domain.define %D1, %gen_D
144+
firrtl.domain.define %D2, %gen_D
145+
146+
// o is on same domain as i
147+
firrtl.matchingconnect %o, %i : !firrtl.uint<1>
148+
}
149+
}
150+
151+
// CHECK-LABEL: UndrivenInstanceDomainPort
152+
firrtl.circuit "UndrivenInstanceDomainPort" {
153+
firrtl.domain @ClockDomain
154+
155+
firrtl.extmodule @Foo(in c : !firrtl.domain of @ClockDomain)
156+
157+
firrtl.module @UndrivenInstanceDomainPort() {
158+
// expected-error @below {{unable to infer value for undriven domain port "c"}}
159+
%foo_c = firrtl.instance foo @Foo(in c : !firrtl.domain of @ClockDomain)
160+
}
161+
}
162+
163+
// CHECK-LABEL: UndrivenInstanceChoiceDomainPort
164+
firrtl.circuit "UndrivenInstanceChoiceDomainPort" {
165+
firrtl.domain @ClockDomain
166+
167+
firrtl.option @Option {
168+
firrtl.option_case @X
169+
}
170+
171+
firrtl.extmodule @Foo(in c : !firrtl.domain of @ClockDomain)
172+
firrtl.extmodule @Bar(in c : !firrtl.domain of @ClockDomain)
173+
174+
firrtl.module @UndrivenInstanceChoiceDomainPort() {
175+
// expected-error @below {{unable to infer value for undriven domain port "c"}}
176+
%inst_c = firrtl.instance_choice inst @Foo alternatives @Option { @X -> @Bar } (in c : !firrtl.domain of @ClockDomain)
177+
}
178+
}
179+
180+
// InstanceChoice: Each module has different domains inferred.
181+
// TODO: this just relies on the op-verifier for instance choice ops.
182+
183+
firrtl.circuit "ConflictingInstanceChoiceDomains" {
184+
firrtl.domain @ClockDomain
185+
186+
firrtl.option @Option {
187+
firrtl.option_case @X
188+
firrtl.option_case @Y
189+
}
190+
191+
// Foo's "out" port takes on the domains of "in1".
192+
firrtl.module @Foo(in %in1: !firrtl.uint<1>, in %in2: !firrtl.uint<1>, out %out: !firrtl.uint<1>) {
193+
firrtl.connect %out, %in1 : !firrtl.uint<1>
194+
}
195+
196+
// Bar's "out" port takes on the domains of "in2".
197+
// expected-note @below {{original module declared here}}
198+
firrtl.module @Bar(in %in1: !firrtl.uint<1>, in %in2: !firrtl.uint<1>, out %out: !firrtl.uint<1>) {
199+
firrtl.connect %out, %in2 : !firrtl.uint<1>
200+
}
201+
202+
firrtl.module @ConflictingInstanceChoiceDomains(in %in1: !firrtl.uint<1>, in %in2: !firrtl.uint<1>) {
203+
// expected-error @below {{'firrtl.instance_choice' op domain info for "out" must be [2 : ui32], but got [0 : ui32]}}
204+
%inst_in1, %inst_in2, %inst_out = firrtl.instance_choice inst @Foo alternatives @Option { @X -> @Foo, @Y -> @Bar } (in in1: !firrtl.uint<1>, in in2: !firrtl.uint<1>, out out: !firrtl.uint<1>)
205+
firrtl.connect %inst_in1, %in1 : !firrtl.uint<1>, !firrtl.uint<1>
206+
firrtl.connect %inst_in2, %in2 : !firrtl.uint<1>, !firrtl.uint<1>
207+
}
208+
}

0 commit comments

Comments
 (0)