[ssa] Potential improvements to ssa construction
Redo of #711 Note that one test (switch.js) is failing, i'm working on a fix.
Joseph Savona committed
Oct 27, 2022 at 13:20 UTC
fc1320552b0c36ce0bdbe985941398afcc43989a
14 files changed
+168
-126
compiler/forget/src/HIR/SSAify.ts
+43
-16
@@ -22,11 +22,10 @@ type State = {
22
incompletePhis: IncompletePhi[];
23
};
24
25
-const unsealedPreds: Map<BasicBlock, number> = new Map();
26
-
25
class SSABuilder {
26
#states: Map<BasicBlock, State> = new Map();
27
#current: BasicBlock | null = null;
28
+ unsealedPreds: Map<BasicBlock, number> = new Map();
29
#env: Environment;
30
31
constructor(env: Environment) {
@@ -73,13 +72,13 @@ class SSABuilder {
72
73
if (block.preds.size == 0) {
74
// We're at the entry block and haven't found our defintion yet.
76
- console.log(
77
- `Unable to find "${printIdentifier(oldId)}", assuming it's a global`
78
- );
75
+ // console.log(
76
+ // `Unable to find "${printIdentifier(oldId)}", assuming it's a global`
77
+ // );
78
return oldId;
79
}
80
82
- if (unsealedPreds.get(block)! > 0) {
81
+ if (this.unsealedPreds.get(block)! > 0) {
82
// We haven't visited all our predecessors, let's place an incomplete phi
83
// for now.
84
const newId = { ...oldId, id: this.nextIdentifierId };
@@ -96,17 +95,45 @@ class SSABuilder {
95
return newId;
96
}
97
99
- // There are multiple predecessors, we need a phi.
100
- const newId = { ...oldId, id: this.nextIdentifierId };
98
+ // There are multiple predecessors, we may need a phi.
99
+ return this.maybeAddPhi(block, oldId, state);
100
+ }
101
+
102
+ maybeAddPhi(block: BasicBlock, oldId: Identifier, state: State): Identifier {
103
// Adding a phi may loop back to our block if there is a loop in the CFG. We
104
// update our defs before adding the phi to terminate the recursion rather than
105
// looping infinitely.
106
+ const newId = { ...oldId, id: this.nextIdentifierId };
107
state.defs.set(oldId, newId);
105
- this.addPhi(block, oldId, newId);
108
107
- // TODO(gsn): Can we just return `newPlace` rather than looking it up?
108
- // `addPhi` _can_ mutate it, but _will_ it?
109
- return state.defs.get(oldId)!;
109
+ const predDefs: Map<BasicBlock, Identifier> = new Map();
110
+ const predIds: Set<Identifier> = new Set();
111
+ for (const predBlock of block.preds) {
112
+ const predId = this.getIdAt(oldId, predBlock);
113
+ predDefs.set(predBlock, predId);
114
+ predIds.add(predId);
115
+ }
116
+
117
+ // if all predecessors have the same id, then there is no need for a phi node.
118
+ // note that in the case of a loop there are guaranteed to be multiple values,
119
+ // since we have already updated this block with a new identifier to terminate
120
+ // the recursion
121
+ if (predIds.size === 1) {
122
+ // there was only a single incoming id so we don't need a phi node,
123
+ // replace with that incoming id instead
124
+ const predId = [...predIds][0]!;
125
+ state.defs.set(oldId, predId);
126
+ return predId;
127
+ }
128
+
129
+ const phi: Phi = {
130
+ kind: "Phi",
131
+ id: newId,
132
+ operands: predDefs,
133
+ };
134
+
135
+ block.phis.add(phi);
136
+ return newId;
137
}
138
139
addPhi(block: BasicBlock, oldId: Identifier, newId: Identifier) {
@@ -197,14 +224,14 @@ export default function buildSSA(func: HIRFunction, env: Environment) {
224
const outputBlocks = outputs.map((id) => func.body.blocks.get(id)!);
225
for (const output of outputBlocks) {
226
let count;
200
- if (unsealedPreds.has(output)) {
201
- count = unsealedPreds.get(output)! - 1;
227
+ if (builder.unsealedPreds.has(output)) {
228
+ count = builder.unsealedPreds.get(output)! - 1;
229
} else {
230
count = output.preds.size - 1;
231
}
205
- unsealedPreds.set(output, count);
232
+ builder.unsealedPreds.set(output, count);
233
207
- if (count == 0 && visitedBlocks.has(output)) {
234
+ if (count === 0 && visitedBlocks.has(output)) {
235
builder.fixIncompletePhis(output);
236
}
237
}
compiler/forget/src/__tests__/fixtures/hir/component.expect.md
+11
-17
@@ -44,11 +44,11 @@ bb0:
44
Goto bb1
45
bb1:
46
predecessor blocks: bb0 bb4 bb7
47
- items$33: phi(bb0: items$27, bb4: items$50, bb7: items$50)
48
- item$35: phi(bb0: item$10, bb4: item$42, bb7: item$42)
49
- seen$38: phi(bb0: seen$30, bb4: seen$41, bb7: seen$41)
50
- renderedItems$46: phi(bb0: renderedItems$29, bb4: renderedItems$45, bb7: renderedItems$45)
51
- max$48: phi(bb0: max$32, bb4: max$47, bb7: max$47)
47
+ items$33: phi(bb0: items$27, bb4: items$33, bb7: items$33)
48
+ item$35: phi(bb0: item$10, bb4: item$35, bb7: item$35)
49
+ seen$38: phi(bb0: seen$30, bb4: seen$38, bb7: seen$38)
50
+ renderedItems$46: phi(bb0: renderedItems$29, bb4: renderedItems$46, bb7: renderedItems$46)
51
+ max$48: phi(bb0: max$32, bb4: max$48, bb7: max$48)
52
If (read items$33) then:bb3 else:bb2
53
bb3:
54
predecessor blocks: bb1
@@ -66,24 +66,18 @@ bb9:
66
bb7:
67
predecessor blocks: bb9 bb8
68
$40: phi(bb9: $39, bb8: $37)
69
- seen$41: phi(bb9: seen$38, bb8: seen$38)
70
- item$42: phi(bb9: item$35, bb8: item$35)
71
- renderedItems$45: phi(bb9: renderedItems$46, bb8: renderedItems$46)
72
- max$47: phi(bb9: max$48, bb8: max$48)
73
- items$50: phi(bb9: items$33, bb8: items$33)
69
If (read $40) then:bb1 else:bb4
70
bb4:
71
predecessor blocks: bb7
77
- Call mutate seen$41.add(mutate item$42)
72
+ Call mutate seen$38.add(mutate item$35)
73
Const mutate $43 = "div"
79
- Const mutate $44 = JSX <read $43>{read item$42}</read $43>
80
- Call mutate renderedItems$45.push(read $44)
81
- Const mutate $49 = Binary read renderedItems$45.length >= read max$47
74
+ Const mutate $44 = JSX <read $43>{read item$35}</read $43>
75
+ Call mutate renderedItems$46.push(read $44)
76
+ Const mutate $49 = Binary read renderedItems$46.length >= read max$48
77
If (read $49) then:bb2 else:bb1
78
bb2:
79
predecessor blocks: bb1 bb4
85
- renderedItems$51: phi(bb1: renderedItems$46, bb4: renderedItems$45)
86
- Const mutate count$52 = read renderedItems$51.length
80
+ Const mutate count$52 = read renderedItems$46.length
81
Const mutate $53 = "div"
82
Const mutate $54 = "\n "
83
Const mutate $55 = "h1"
@@ -91,7 +85,7 @@ bb2:
85
Const mutate $57 = JSX <read $55>{freeze count$52}{read $56}</read $55>
86
Const mutate $58 = "\n "
87
Const mutate $59 = "\n "
94
- Const mutate $60 = JSX <read $53>{read $54}{read $57}{read $58}{freeze renderedItems$51}{read $59}</read $53>
88
+ Const mutate $60 = JSX <read $53>{read $54}{read $57}{read $58}{freeze renderedItems$46}{read $59}</read $53>
89
Return read $60
90
```
91
compiler/forget/src/__tests__/fixtures/hir/conditional-break.expect.md
+8
-12
@@ -119,10 +119,8 @@ bb2:
119
Goto bb1
120
bb1:
121
predecessor blocks: bb0 bb2
122
- a$5: phi(bb0: a$4, bb2: a$4)
123
- props$6: phi(bb0: props$3, bb2: props$3)
124
- Call mutate a$5.push(read props$6.d)
125
- Return freeze a$5
122
+ Call mutate a$4.push(read props$3.d)
123
+ Return freeze a$4
124
```
125
126
## Code
@@ -136,8 +134,8 @@ function Component$0(props$3) {
134
("<<TODO: handle complex control flow in codegen>>");
135
}
136
139
- a$5.push(props$6.d);
140
- return a$5;
137
+ a$4.push(props$3.d);
138
+ return a$4;
139
}
140
141
```
@@ -221,10 +219,8 @@ bb2:
219
Goto bb1
220
bb1:
221
predecessor blocks: bb2 bb0
224
- a$5: phi(bb2: a$4, bb0: a$4)
225
- props$6: phi(bb2: props$3, bb0: props$3)
226
- Call mutate a$5.push(read props$6.d)
227
- Return freeze a$5
222
+ Call mutate a$4.push(read props$3.d)
223
+ Return freeze a$4
224
```
225
226
## Code
@@ -234,8 +230,8 @@ function Component$0(props$3) {
230
const a$4 = [];
231
a$4.push(props$3.a);
232
if (props$3.b) {
237
- a$5.push(props$6.d);
238
- return a$5;
233
+ a$4.push(props$3.d);
234
+ return a$4;
235
}
236
237
a$4.push(props$3.c);
compiler/forget/src/__tests__/fixtures/hir/conditional-on-mutable.expect.md
+12
-26
@@ -76,21 +76,14 @@ bb2:
76
Goto bb1
77
bb1:
78
predecessor blocks: bb0 bb2
79
- props$9: phi(bb0: props$6, bb2: props$6)
80
- b$10: phi(bb0: b$8, bb2: b$8)
81
- Foo$12: phi(bb0: Foo$4, bb2: Foo$4)
82
- a$14: phi(bb0: a$7, bb2: a$7)
83
- If (read props$9.p1) then:bb4 else:bb3
79
+ If (read props$6.p1) then:bb4 else:bb3
80
bb4:
81
predecessor blocks: bb1
86
- Call mutate b$10.push(read props$9.p2)
82
+ Call mutate b$8.push(read props$6.p2)
83
Goto bb3
84
bb3:
85
predecessor blocks: bb1 bb4
90
- Foo$11: phi(bb1: Foo$12, bb4: Foo$12)
91
- a$13: phi(bb1: a$14, bb4: a$14)
92
- b$15: phi(bb1: b$10, bb4: b$10)
93
- Const mutate $16 = JSX <read Foo$11 a={freeze a$13} b={freeze b$15} ></read Foo$11>
86
+ Const mutate $16 = JSX <read Foo$4 a={freeze a$7} b={freeze b$8} ></read Foo$4>
87
Return read $16
88
```
89
@@ -105,12 +98,12 @@ function Component$0(props$6) {
98
("<<TODO: handle complex control flow in codegen>>");
99
}
100
108
- if (props$9.p1) {
109
- b$10.push(props$9.p2);
101
+ if (props$6.p1) {
102
+ b$8.push(props$6.p2);
103
("<<TODO: handle complex control flow in codegen>>");
104
}
105
113
- return <Foo$11 a={a$13} b={b$15}></Foo$11>;
106
+ return <Foo$4 a={a$7} b={b$8}></Foo$4>;
107
}
108
109
```
@@ -128,21 +121,14 @@ bb2:
121
Goto bb1
122
bb1:
123
predecessor blocks: bb0 bb2
131
- props$12: phi(bb0: props$8, bb2: props$8)
132
- b$13: phi(bb0: b$10, bb2: b$10)
133
- Foo$15: phi(bb0: Foo$6, bb2: Foo$6)
134
- a$17: phi(bb0: a$9, bb2: a$9)
135
- If (read props$12.p1) then:bb4 else:bb3
124
+ If (read props$8.p1) then:bb4 else:bb3
125
bb4:
126
predecessor blocks: bb1
138
- Call mutate b$13.push(read props$12.p2)
127
+ Call mutate b$10.push(read props$8.p2)
128
Goto bb3
129
bb3:
130
predecessor blocks: bb1 bb4
142
- Foo$14: phi(bb1: Foo$15, bb4: Foo$15)
143
- a$16: phi(bb1: a$17, bb4: a$17)
144
- b$18: phi(bb1: b$13, bb4: b$13)
145
- Const mutate $19 = JSX <read Foo$14 a={freeze a$16} b={freeze b$18} ></read Foo$14>
131
+ Const mutate $19 = JSX <read Foo$6 a={freeze a$9} b={freeze b$10} ></read Foo$6>
132
Return read $19
133
```
134
@@ -157,12 +143,12 @@ function Component$0(props$8) {
143
("<<TODO: handle complex control flow in codegen>>");
144
}
145
160
- if (props$12.p1) {
161
- b$13.push(props$12.p2);
146
+ if (props$8.p1) {
147
+ b$10.push(props$8.p2);
148
("<<TODO: handle complex control flow in codegen>>");
149
}
150
165
- return <Foo$14 a={a$16} b={b$18}></Foo$14>;
151
+ return <Foo$6 a={a$9} b={b$10}></Foo$6>;
152
}
153
154
```
compiler/forget/src/__tests__/fixtures/hir/hooks-freeze-possibly-mutable-arguments.expect.md
+6
-8
@@ -40,12 +40,10 @@ bb3:
40
Goto bb1
41
bb1:
42
predecessor blocks: bb3 bb2
43
- useFreeze$13: phi(bb3: useFreeze$5, bb2: useFreeze$5)
43
a$14: phi(bb3: a$12, bb2: a$11)
45
- call$15: phi(bb3: call$6, bb2: call$6)
46
- Call read useFreeze$13(freeze a$14)
47
- Call read useFreeze$13(read a$14)
48
- Call mutate call$15(read a$14)
44
+ Call read useFreeze$5(freeze a$14)
45
+ Call read useFreeze$5(read a$14)
46
+ Call mutate call$6(read a$14)
47
Return read a$14
48
```
49
@@ -64,9 +62,9 @@ function Component$0(props$7) {
62
("<<TODO: handle complex control flow in codegen>>");
63
}
64
67
- useFreeze$13(a$14);
68
- useFreeze$13(a$14);
69
- call$15(a$14);
65
+ useFreeze$5(a$14);
66
+ useFreeze$5(a$14);
67
+ call$6(a$14);
68
return a$14;
69
}
70
compiler/forget/src/__tests__/fixtures/hir/independent-across-if.expect.md
+2
-5
@@ -107,10 +107,7 @@ bb2:
107
Goto bb1
108
bb1:
109
predecessor blocks: bb0 bb2
110
- Foo$11: phi(bb0: Foo$6, bb2: Foo$6)
111
- a$12: phi(bb0: a$9, bb2: a$9)
112
- b$13: phi(bb0: b$10, bb2: b$10)
113
- Const mutate $14 = JSX <read Foo$11 a={freeze a$12} b={freeze b$13} ></read Foo$11>
110
+ Const mutate $14 = JSX <read Foo$6 a={freeze a$9} b={freeze b$10} ></read Foo$6>
111
Return read $14
112
```
113
@@ -126,7 +123,7 @@ function Component$0(props$8) {
123
("<<TODO: handle complex control flow in codegen>>");
124
}
125
129
- return <Foo$11 a={a$12} b={b$13}></Foo$11>;
126
+ return <Foo$6 a={a$9} b={b$10}></Foo$6>;
127
}
128
129
```
compiler/forget/src/__tests__/fixtures/hir/interdependent-across-if.expect.md
+2
-5
@@ -85,10 +85,7 @@ bb2:
85
Goto bb1
86
bb1:
87
predecessor blocks: bb0 bb2
88
- Foo$11: phi(bb0: Foo$6, bb2: Foo$6)
89
- a$12: phi(bb0: a$9, bb2: a$9)
90
- b$13: phi(bb0: b$10, bb2: b$10)
91
- Const mutate $14 = JSX <read Foo$11 a={freeze a$12} b={freeze b$13} ></read Foo$11>
88
+ Const mutate $14 = JSX <read Foo$6 a={freeze a$9} b={freeze b$10} ></read Foo$6>
89
Return read $14
90
```
91
@@ -103,7 +100,7 @@ function Component$0(props$8) {
100
("<<TODO: handle complex control flow in codegen>>");
101
}
102
106
- return <Foo$11 a={a$12} b={b$13}></Foo$11>;
103
+ return <Foo$6 a={a$9} b={b$10}></Foo$6>;
104
}
105
106
```
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md
+1
-2
@@ -104,7 +104,6 @@ bb2:
104
b$31: phi(bb1: b$20, bb3: b$23)
105
c$32: phi(bb1: c$22, bb3: c$25)
106
d$33: phi(bb1: d$24, bb3: d$26)
107
- mutate$35: phi(bb1: mutate$27, bb3: mutate$27)
107
If (read a$30) then:bb7 else:bb7
108
bb7:
109
predecessor blocks: bb2
@@ -118,7 +117,7 @@ bb11:
117
bb13:
118
predecessor blocks: bb11
119
Const mutate $34 = null
121
- Call mutate mutate$35(mutate d$33, read $34)
120
+ Call mutate mutate$27(mutate d$33, read $34)
121
Return
122
```
123
compiler/forget/src/__tests__/fixtures/hir/reassignment-conditional.expect.md
+6
-9
@@ -33,13 +33,10 @@ bb2:
33
Goto bb1
34
bb1:
35
predecessor blocks: bb0 bb2
36
- Component$10: phi(bb0: Component$0, bb2: Component$0)
36
x$11: phi(bb0: x$7, bb2: x$9)
38
- y$13: phi(bb0: y$8, bb2: y$8)
39
- props$14: phi(bb0: props$6, bb2: props$6)
40
- Let mutate _$12 = JSX <read Component$10 x={freeze x$11} ></read Component$10>
41
- Call read y$13.push(read props$14.p2)
42
- Const mutate $15 = JSX <read Component$10 x={read x$11} y={read y$13} ></read Component$10>
37
+ Let mutate _$12 = JSX <read Component$0 x={freeze x$11} ></read Component$0>
38
+ Call read y$8.push(read props$6.p2)
39
+ Const mutate $15 = JSX <read Component$0 x={read x$11} y={read y$8} ></read Component$0>
40
Return read $15
41
```
42
@@ -55,10 +52,10 @@ function Component$0(props$6) {
52
("<<TODO: handle complex control flow in codegen>>");
53
}
54
58
- let _$12 = <Component$10 x={x$11}></Component$10>;
55
+ let _$12 = <Component$0 x={x$11}></Component$0>;
56
60
- y$13.push(props$14.p2);
61
- return <Component$10 x={x$11} y={y$13}></Component$10>;
57
+ y$8.push(props$6.p2);
58
+ return <Component$0 x={x$11} y={y$8}></Component$0>;
59
}
60
61
```
compiler/forget/src/__tests__/fixtures/hir/ssa-complex-multiple-if.expect.md
+2
-3
@@ -32,10 +32,9 @@ bb2:
32
Goto bb1
33
bb1:
34
predecessor blocks: bb0 bb2
35
- y$13: phi(bb0: y$8, bb2: y$8)
35
x$17: phi(bb0: x$7, bb2: x$11)
36
Const mutate $12 = 3
38
- Const mutate $14 = Binary read y$13 === read $12
37
+ Const mutate $14 = Binary read y$8 === read $12
38
If (read $14) then:bb4 else:bb3
39
bb4:
40
predecessor blocks: bb1
@@ -59,7 +58,7 @@ function foo$0() {
58
("<<TODO: handle complex control flow in codegen>>");
59
}
60
62
- if (y$13 === 3) {
61
+ if (y$8 === 3) {
62
x$15 = 5;
63
("<<TODO: handle complex control flow in codegen>>");
64
}
compiler/forget/src/__tests__/fixtures/hir/ssa-for-of.expect.md
new
+51
@@ -0,0 +1,51 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+function foo(cond) {
6
+ let items = [];
7
+ for (const item of items) {
8
+ let y = 0;
9
+ if (cond) {
10
+ y = 1;
11
+ }
12
+ }
13
+ return items;
14
+}
15
+
16
+```
17
+
18
+## HIR
19
+
20
+```
21
+bb0:
22
+ Let mutate items$5 = Array []
23
+ Goto bb1
24
+bb1:
25
+ predecessor blocks: bb0 bb3 bb5
26
+ items$6: phi(bb0: items$5, bb3: items$6, bb5: items$6)
27
+ cond$8: phi(bb0: cond$4, bb3: cond$8, bb5: cond$8)
28
+ If (read items$6) then:bb3 else:bb2
29
+bb3:
30
+ predecessor blocks: bb1
31
+ Let mutate y$7 = 0
32
+ If (read cond$8) then:bb5 else:bb1
33
+bb5:
34
+ predecessor blocks: bb3
35
+ Reassign mutate y$9 = 1
36
+ Goto bb1
37
+bb2:
38
+ predecessor blocks: bb1
39
+ Return freeze items$6
40
+```
41
+
42
+## Code
43
+
44
+```javascript
45
+function foo$0(cond$4) {
46
+ let items$5 = [];
47
+ ("<<TODO: handle complex control flow in codegen>>");
48
+}
49
+
50
+```
51
+
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-for-of.js
new
+10
@@ -0,0 +1,10 @@
1
+function foo(cond) {
2
+ let items = [];
3
+ for (const item of items) {
4
+ let y = 0;
5
+ if (cond) {
6
+ y = 1;
7
+ }
8
+ }
9
+ return items;
10
+}
compiler/forget/src/__tests__/fixtures/hir/switch-non-final-default.expect.md
+6
-9
@@ -53,13 +53,10 @@ bb2:
53
Goto bb1
54
bb1:
55
predecessor blocks: bb0 bb6 bb2
56
- Component$17: phi(bb0: Component$0, bb6: Component$0, bb2: Component$0)
57
- x$18: phi(bb0: x$10, bb6: x$10, bb2: x$10)
56
y$20: phi(bb0: y$11, bb6: y$15, bb2: y$16)
59
- props$21: phi(bb0: props$9, bb6: props$9, bb2: props$9)
60
- Const mutate child$19 = JSX <read Component$17 data={freeze x$18} ></read Component$17>
61
- Call read y$20.push(read props$21.p4)
62
- Const mutate $22 = JSX <read Component$17 data={freeze y$20} >{read child$19}</read Component$17>
57
+ Const mutate child$19 = JSX <read Component$0 data={freeze x$10} ></read Component$0>
58
+ Call read y$20.push(read props$9.p4)
59
+ Const mutate $22 = JSX <read Component$0 data={freeze y$20} >{read child$19}</read Component$0>
60
Return read $22
61
```
62
@@ -88,9 +85,9 @@ function Component$0(props$9) {
85
}
86
}
87
91
- const child$19 = <Component$17 data={x$18}></Component$17>;
92
- y$20.push(props$21.p4);
93
- return <Component$17 data={y$20}>{child$19}</Component$17>;
88
+ const child$19 = <Component$0 data={x$10}></Component$0>;
89
+ y$20.push(props$9.p4);
90
+ return <Component$0 data={y$20}>{child$19}</Component$0>;
91
}
92
93
```
compiler/forget/src/__tests__/fixtures/hir/switch.expect.md
+8
-14
@@ -44,20 +44,14 @@ bb4:
44
Goto bb2
45
bb2:
46
predecessor blocks: bb4 bb0
47
- x$14: phi(bb4: x$9, bb0: x$9)
48
- Component$17: phi(bb4: Component$0, bb0: Component$0)
49
- props$22: phi(bb4: props$8, bb0: props$8)
50
- Reassign mutate y$15 = read x$14
47
+ Reassign mutate y$15 = read x$9
48
Goto bb1
49
bb1:
50
predecessor blocks: bb2 bb0
54
- Component$16: phi(bb2: Component$17, bb0: Component$0)
55
- x$18: phi(bb2: x$14, bb0: x$9)
51
y$20: phi(bb2: y$15, bb0: y$10)
57
- props$21: phi(bb2: props$22, bb0: props$8)
58
- Const mutate child$19 = JSX <read Component$16 data={freeze x$18} ></read Component$16>
59
- Call read y$20.push(read props$21.p4)
60
- Const mutate $23 = JSX <read Component$16 data={read y$20} >{read child$19}</read Component$16>
52
+ Const mutate child$19 = JSX <read Component$0 data={freeze x$9} ></read Component$0>
53
+ Call read y$20.push(read props$8.p4)
54
+ Const mutate $23 = JSX <read Component$0 data={read y$20} >{read child$19}</read Component$0>
55
Return read $23
56
```
57
@@ -76,14 +70,14 @@ function Component$0(props$8) {
70
}
71
72
case false: {
79
- y$15 = x$14;
73
+ y$15 = x$9;
74
("<<TODO: handle complex control flow in codegen>>");
75
}
76
}
77
84
- const child$19 = <Component$16 data={x$18}></Component$16>;
85
- y$20.push(props$21.p4);
86
- return <Component$16 data={y$20}>{child$19}</Component$16>;
78
+ const child$19 = <Component$0 data={x$9}></Component$0>;
79
+ y$20.push(props$8.p4);
80
+ return <Component$0 data={y$20}>{child$19}</Component$0>;
81
}
82
83
```