Skip to content

Commit 7f8d7ac

Browse files
authored
CoalesceLocals: Use ValueNumbering (#4355)
This removes the old hardcoded value numbering in that pass and makes it use the new code that was split into helper code. The immediate benefit of this is to make the code aware of identical constants: if two locals have the same constant then they do not interfere. Future improvements to numbering will also automatically help here. This changes some constants in existing tests so that they keep testing what they were testing before, and adds new tests for the new benefit here. This implements a proposed TODO from #4314
1 parent 0bf6ff7 commit 7f8d7ac

File tree

4 files changed

+191
-46
lines changed

4 files changed

+191
-46
lines changed

src/passes/CoalesceLocals.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <unordered_set>
3131

3232
#include "cfg/liveness-traversal.h"
33+
#include "ir/numbering.h"
3334
#include "ir/utils.h"
3435
#include "pass.h"
3536
#include "support/learning.h"
@@ -155,6 +156,10 @@ void CoalesceLocals::calculateInterferences() {
155156
// loop.
156157
std::vector<Index> values(numLocals);
157158

159+
ValueNumbering valueNumbering;
160+
161+
auto* func = getFunction();
162+
158163
for (auto& curr : basicBlocks) {
159164
if (liveBlocks.count(curr.get()) == 0) {
160165
continue; // ignore dead blocks
@@ -196,29 +201,30 @@ void CoalesceLocals::calculateInterferences() {
196201
// around through copies between sets we can see when sets are guaranteed to
197202
// be equal.
198203

199-
// Give all default values the same value ID, regardless of their type. This
200-
// is valid since we only coalesce locals of the same type anyhow.
201-
auto zeroInit = 0;
202-
Index nextValue = 1;
203-
204204
if (curr.get() == entry) {
205205
// Each parameter is assumed to have a different value on entry.
206-
for (Index i = 0; i < getFunction()->getNumParams(); i++) {
207-
values[i] = nextValue++;
206+
for (Index i = 0; i < func->getNumParams(); i++) {
207+
values[i] = valueNumbering.getUniqueValue();
208208
}
209209

210-
for (Index i = getFunction()->getNumParams();
211-
i < getFunction()->getNumLocals();
212-
i++) {
213-
values[i] = zeroInit;
210+
for (Index i = func->getNumParams(); i < func->getNumLocals(); i++) {
211+
auto type = func->getLocalType(i);
212+
if (type.isNonNullable()) {
213+
// A non-nullable value cannot be used anyhow, but we must give it
214+
// some value. A unique one seems least likely to result in surprise
215+
// during debugging.
216+
values[i] = valueNumbering.getUniqueValue();
217+
} else {
218+
values[i] = valueNumbering.getValue(Literal::makeZeros(type));
219+
}
214220
}
215221
} else {
216222
// In any block but the entry, assume that each live local might have a
217223
// different value at the start.
218224
// TODO: Propagating value IDs across blocks could identify more copies,
219225
// however, it would also be nonlinear.
220226
for (auto index : curr->contents.start) {
221-
values[index] = nextValue++;
227+
values[index] = valueNumbering.getUniqueValue();
222228
}
223229
}
224230

@@ -246,8 +252,8 @@ void CoalesceLocals::calculateInterferences() {
246252
assert(i > 0 && set->value == *actions[i - 1].origin);
247253
newValue = values[actions[i - 1].index];
248254
} else {
249-
// This is not a copy; assign a new unique value.
250-
newValue = nextValue++;
255+
// This is not a copy.
256+
newValue = valueNumbering.getValue(set->value);
251257
}
252258
values[index] = newValue;
253259

test/lit/passes/coalesce-locals-learning.wast

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
;; CHECK-NEXT: (i32.const 0)
5858
;; CHECK-NEXT: )
5959
;; CHECK-NEXT: (local.set $1
60-
;; CHECK-NEXT: (i32.const 0)
60+
;; CHECK-NEXT: (i32.const 1)
6161
;; CHECK-NEXT: )
6262
;; CHECK-NEXT: (drop
6363
;; CHECK-NEXT: (local.get $0)
@@ -73,7 +73,7 @@
7373
(i32.const 0)
7474
)
7575
(local.set $y
76-
(i32.const 0)
76+
(i32.const 1)
7777
)
7878
(drop
7979
(local.get $x)
@@ -190,7 +190,7 @@
190190
;; CHECK-NEXT: )
191191
;; CHECK-NEXT: (block $block0
192192
;; CHECK-NEXT: (local.set $1
193-
;; CHECK-NEXT: (i32.const 0)
193+
;; CHECK-NEXT: (i32.const 1)
194194
;; CHECK-NEXT: )
195195
;; CHECK-NEXT: )
196196
;; CHECK-NEXT: (drop
@@ -208,7 +208,7 @@
208208
)
209209
(block $block0
210210
(local.set $y
211-
(i32.const 0)
211+
(i32.const 1)
212212
)
213213
)
214214
(drop
@@ -269,7 +269,7 @@
269269
;; CHECK-NEXT: )
270270
;; CHECK-NEXT: (block $block
271271
;; CHECK-NEXT: (local.set $1
272-
;; CHECK-NEXT: (i32.const 0)
272+
;; CHECK-NEXT: (i32.const 1)
273273
;; CHECK-NEXT: )
274274
;; CHECK-NEXT: (drop
275275
;; CHECK-NEXT: (local.get $1)
@@ -288,7 +288,7 @@
288288
)
289289
(block $block
290290
(local.set $y
291-
(i32.const 0)
291+
(i32.const 1)
292292
)
293293
(drop
294294
(local.get $y)
@@ -582,7 +582,7 @@
582582
;; CHECK-NEXT: (local $0 i32)
583583
;; CHECK-NEXT: (local $1 i32)
584584
;; CHECK-NEXT: (local.set $0
585-
;; CHECK-NEXT: (i32.const 0)
585+
;; CHECK-NEXT: (i32.const 1)
586586
;; CHECK-NEXT: )
587587
;; CHECK-NEXT: (if
588588
;; CHECK-NEXT: (i32.const 0)
@@ -600,7 +600,7 @@
600600
(local $x i32)
601601
(local $y i32)
602602
(local.set $x
603-
(i32.const 0)
603+
(i32.const 1)
604604
)
605605
(if
606606
(i32.const 0)
@@ -619,7 +619,7 @@
619619
;; CHECK-NEXT: (local $1 i32)
620620
;; CHECK-NEXT: (if
621621
;; CHECK-NEXT: (local.tee $0
622-
;; CHECK-NEXT: (i32.const 0)
622+
;; CHECK-NEXT: (i32.const 1)
623623
;; CHECK-NEXT: )
624624
;; CHECK-NEXT: (block $block1
625625
;; CHECK-NEXT: (drop
@@ -636,7 +636,7 @@
636636
(local $y i32)
637637
(if
638638
(local.tee $x
639-
(i32.const 0)
639+
(i32.const 1)
640640
)
641641
(block $block1
642642
(drop

test/lit/passes/coalesce-locals.wast

Lines changed: 152 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
;; CHECK-NEXT: (i32.const 0)
7575
;; CHECK-NEXT: )
7676
;; CHECK-NEXT: (local.set $1
77-
;; CHECK-NEXT: (i32.const 0)
77+
;; CHECK-NEXT: (i32.const 1)
7878
;; CHECK-NEXT: )
7979
;; CHECK-NEXT: (drop
8080
;; CHECK-NEXT: (local.get $0)
@@ -90,7 +90,7 @@
9090
(i32.const 0)
9191
)
9292
(local.set $y
93-
(i32.const 0)
93+
(i32.const 1)
9494
)
9595
(drop
9696
(local.get $x)
@@ -207,7 +207,7 @@
207207
;; CHECK-NEXT: )
208208
;; CHECK-NEXT: (block $block0
209209
;; CHECK-NEXT: (local.set $1
210-
;; CHECK-NEXT: (i32.const 0)
210+
;; CHECK-NEXT: (i32.const 1)
211211
;; CHECK-NEXT: )
212212
;; CHECK-NEXT: )
213213
;; CHECK-NEXT: (drop
@@ -225,7 +225,7 @@
225225
)
226226
(block $block0
227227
(local.set $y
228-
(i32.const 0)
228+
(i32.const 1)
229229
)
230230
)
231231
(drop
@@ -286,7 +286,7 @@
286286
;; CHECK-NEXT: )
287287
;; CHECK-NEXT: (block $block
288288
;; CHECK-NEXT: (local.set $1
289-
;; CHECK-NEXT: (i32.const 0)
289+
;; CHECK-NEXT: (i32.const 1)
290290
;; CHECK-NEXT: )
291291
;; CHECK-NEXT: (drop
292292
;; CHECK-NEXT: (local.get $1)
@@ -305,7 +305,7 @@
305305
)
306306
(block $block
307307
(local.set $y
308-
(i32.const 0)
308+
(i32.const 1)
309309
)
310310
(drop
311311
(local.get $y)
@@ -599,7 +599,7 @@
599599
;; CHECK-NEXT: (local $0 i32)
600600
;; CHECK-NEXT: (local $1 i32)
601601
;; CHECK-NEXT: (local.set $0
602-
;; CHECK-NEXT: (i32.const 0)
602+
;; CHECK-NEXT: (i32.const 1)
603603
;; CHECK-NEXT: )
604604
;; CHECK-NEXT: (if
605605
;; CHECK-NEXT: (i32.const 0)
@@ -617,7 +617,7 @@
617617
(local $x i32)
618618
(local $y i32)
619619
(local.set $x
620-
(i32.const 0)
620+
(i32.const 1)
621621
)
622622
(if
623623
(i32.const 0)
@@ -636,7 +636,7 @@
636636
;; CHECK-NEXT: (local $1 i32)
637637
;; CHECK-NEXT: (if
638638
;; CHECK-NEXT: (local.tee $0
639-
;; CHECK-NEXT: (i32.const 0)
639+
;; CHECK-NEXT: (i32.const 1)
640640
;; CHECK-NEXT: )
641641
;; CHECK-NEXT: (block $block1
642642
;; CHECK-NEXT: (drop
@@ -653,7 +653,7 @@
653653
(local $y i32)
654654
(if
655655
(local.tee $x
656-
(i32.const 0)
656+
(i32.const 1)
657657
)
658658
(block $block1
659659
(drop
@@ -2921,4 +2921,146 @@
29212921
)
29222922
(local.get $1)
29232923
)
2924+
2925+
;; CHECK: (func $equal-constants-zeroinit
2926+
;; CHECK-NEXT: (local $0 i32)
2927+
;; CHECK-NEXT: (drop
2928+
;; CHECK-NEXT: (local.get $0)
2929+
;; CHECK-NEXT: )
2930+
;; CHECK-NEXT: (drop
2931+
;; CHECK-NEXT: (local.get $0)
2932+
;; CHECK-NEXT: )
2933+
;; CHECK-NEXT: )
2934+
(func $equal-constants-zeroinit
2935+
(local $x i32)
2936+
(local $y i32)
2937+
;; $x and $y both have the zero init value, which is identical, and they do
2938+
;; not interfere.
2939+
(drop
2940+
(local.get $x)
2941+
)
2942+
(drop
2943+
(local.get $y)
2944+
)
2945+
)
2946+
2947+
;; CHECK: (func $equal-constants
2948+
;; CHECK-NEXT: (local $0 i32)
2949+
;; CHECK-NEXT: (local.set $0
2950+
;; CHECK-NEXT: (i32.const 0)
2951+
;; CHECK-NEXT: )
2952+
;; CHECK-NEXT: (drop
2953+
;; CHECK-NEXT: (local.get $0)
2954+
;; CHECK-NEXT: )
2955+
;; CHECK-NEXT: (drop
2956+
;; CHECK-NEXT: (local.get $0)
2957+
;; CHECK-NEXT: )
2958+
;; CHECK-NEXT: )
2959+
(func $equal-constants
2960+
(local $x i32)
2961+
(local $y i32)
2962+
;; $x is written the same value as $y, so they do not interfere.
2963+
(local.set $x
2964+
(i32.const 0)
2965+
)
2966+
(drop
2967+
(local.get $x)
2968+
)
2969+
(drop
2970+
(local.get $y)
2971+
)
2972+
)
2973+
2974+
;; CHECK: (func $different-constants
2975+
;; CHECK-NEXT: (local $0 i32)
2976+
;; CHECK-NEXT: (local $1 i32)
2977+
;; CHECK-NEXT: (local.set $0
2978+
;; CHECK-NEXT: (i32.const 1)
2979+
;; CHECK-NEXT: )
2980+
;; CHECK-NEXT: (drop
2981+
;; CHECK-NEXT: (local.get $0)
2982+
;; CHECK-NEXT: )
2983+
;; CHECK-NEXT: (drop
2984+
;; CHECK-NEXT: (local.get $1)
2985+
;; CHECK-NEXT: )
2986+
;; CHECK-NEXT: )
2987+
(func $different-constants
2988+
(local $x i32)
2989+
(local $y i32)
2990+
;; $x is written a different value, so they do interfere.
2991+
(local.set $x
2992+
(i32.const 1)
2993+
)
2994+
(drop
2995+
(local.get $x)
2996+
)
2997+
(drop
2998+
(local.get $y)
2999+
)
3000+
)
3001+
3002+
;; CHECK: (func $equal-constants-nonzero
3003+
;; CHECK-NEXT: (local $0 i32)
3004+
;; CHECK-NEXT: (local.set $0
3005+
;; CHECK-NEXT: (i32.const 42)
3006+
;; CHECK-NEXT: )
3007+
;; CHECK-NEXT: (local.set $0
3008+
;; CHECK-NEXT: (i32.const 42)
3009+
;; CHECK-NEXT: )
3010+
;; CHECK-NEXT: (drop
3011+
;; CHECK-NEXT: (local.get $0)
3012+
;; CHECK-NEXT: )
3013+
;; CHECK-NEXT: (drop
3014+
;; CHECK-NEXT: (local.get $0)
3015+
;; CHECK-NEXT: )
3016+
;; CHECK-NEXT: )
3017+
(func $equal-constants-nonzero
3018+
(local $x i32)
3019+
(local $y i32)
3020+
(local.set $x
3021+
(i32.const 42)
3022+
)
3023+
(local.set $y
3024+
(i32.const 42)
3025+
)
3026+
(drop
3027+
(local.get $x)
3028+
)
3029+
(drop
3030+
(local.get $y)
3031+
)
3032+
)
3033+
3034+
;; CHECK: (func $different-constants-nonzero
3035+
;; CHECK-NEXT: (local $0 i32)
3036+
;; CHECK-NEXT: (local $1 i32)
3037+
;; CHECK-NEXT: (local.set $0
3038+
;; CHECK-NEXT: (i32.const 42)
3039+
;; CHECK-NEXT: )
3040+
;; CHECK-NEXT: (local.set $1
3041+
;; CHECK-NEXT: (i32.const 1337)
3042+
;; CHECK-NEXT: )
3043+
;; CHECK-NEXT: (drop
3044+
;; CHECK-NEXT: (local.get $0)
3045+
;; CHECK-NEXT: )
3046+
;; CHECK-NEXT: (drop
3047+
;; CHECK-NEXT: (local.get $1)
3048+
;; CHECK-NEXT: )
3049+
;; CHECK-NEXT: )
3050+
(func $different-constants-nonzero
3051+
(local $x i32)
3052+
(local $y i32)
3053+
(local.set $x
3054+
(i32.const 42)
3055+
)
3056+
(local.set $y
3057+
(i32.const 1337)
3058+
)
3059+
(drop
3060+
(local.get $x)
3061+
)
3062+
(drop
3063+
(local.get $y)
3064+
)
3065+
)
29243066
)

0 commit comments

Comments
 (0)