97
includeThrowsAsExitNode: false,
98
});
99
const postDominatorFrontierCache = new Map<BlockId, Set<BlockId>>();
100
+
101
+ function isReactiveControlledBlock(id: BlockId): boolean {
102
+ let controlBlocks = postDominatorFrontierCache.get(id);
103
+ if (controlBlocks === undefined) {
104
+ controlBlocks = postDominatorFrontier(fn, postDominators, id);
105
+ postDominatorFrontierCache.set(id, controlBlocks);
106
+ }
107
+ for (const blockId of controlBlocks) {
108
+ const controlBlock = fn.body.blocks.get(blockId)!;
109
+ switch (controlBlock.terminal.kind) {
110
+ case "if":
111
+ case "branch": {
112
+ if (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
113
+ return true;
114
+ }
115
+ break;
116
+ }
117
+ case "switch": {
118
+ if (reactiveIdentifiers.isReactive(controlBlock.terminal.test)) {
119
+ return true;
120
+ }
121
+ for (const case_ of controlBlock.terminal.cases) {
122
+ if (
123
+ case_.test !== null &&
124
+ reactiveIdentifiers.isReactive(case_.test)
125
+ ) {
126
+ return true;
127
+ }
128
+ }
129
+ break;
130
+ }
131
+ }
132
+ }
133
+ return false;
134
+ }
135
+
136
const hasLoop = hasBackEdge(fn);
137
do {
138
const identifierMapping = new Map<Identifier, Identifier>();
139
for (const [, block] of fn.body.blocks) {
140
+ let hasReactiveControl = isReactiveControlledBlock(block.id);
141
+
142
for (const phi of block.phis) {
143
if (reactiveIdentifiers.isReactiveIdentifier(phi.id)) {
144
// Already marked reactive on a previous pass
154
if (isPhiReactive) {
155
reactiveIdentifiers.markReactiveIdentifier(phi.id);
156
} else {
119
- // check to see if it has a reactive control dependency
120
- for (const [pred, _operand] of phi.operands) {
121
- let controlBlocks = postDominatorFrontierCache.get(pred);
122
- if (controlBlocks === undefined) {
123
- controlBlocks = postDominatorFrontier(fn, postDominators, pred);
124
- postDominatorFrontierCache.set(pred, controlBlocks);
125
- }
126
- control: for (const blockId of controlBlocks) {
127
- const controlBlock = fn.body.blocks.get(blockId)!;
128
- switch (controlBlock.terminal.kind) {
129
- case "if":
130
- case "branch": {
131
- if (
132
- reactiveIdentifiers.isReactive(controlBlock.terminal.test)
133
- ) {
134
- // control dependency is reactive
135
- reactiveIdentifiers.markReactiveIdentifier(phi.id);
136
- break control;
137
- }
138
- break;
139
- }
140
- case "switch": {
141
- if (
142
- reactiveIdentifiers.isReactive(controlBlock.terminal.test)
143
- ) {
144
- // control dependency is reactive
145
- reactiveIdentifiers.markReactiveIdentifier(phi.id);
146
- break control;
147
- }
148
- for (const case_ of controlBlock.terminal.cases) {
149
- if (
150
- case_.test !== null &&
151
- reactiveIdentifiers.isReactive(case_.test)
152
- ) {
153
- // control dependency is reactive
154
- reactiveIdentifiers.markReactiveIdentifier(phi.id);
155
- break control;
156
- }
157
- }
158
- break;
159
- }
160
- }
157
+ for (const [pred] of phi.operands) {
158
+ if (isReactiveControlledBlock(pred)) {
159
+ reactiveIdentifiers.markReactiveIdentifier(phi.id);
160
+ break;
161
}
162
}
163
}
197
}
198
reactiveIdentifiers.markReactive(lvalue);
199
}
200
-
200
+ }
201
+ if (hasReactiveInput || hasReactiveControl) {
202
for (const operand of eachInstructionValueOperand(value)) {
203
switch (operand.effect) {
204
case Effect.Capture: