Skip to content

Commit f172920

Browse files
authored
StringLowering: Lower all remaining important string operations (#6283)
All those in the list from #6271 (comment)
1 parent 0724bab commit f172920

File tree

3 files changed

+267
-31
lines changed

3 files changed

+267
-31
lines changed

src/passes/StringLowering.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,20 @@ struct StringLowering : public StringGathering {
239239

240240
// Imported string functions.
241241
Name fromCharCodeArrayImport;
242+
Name intoCharCodeArrayImport;
242243
Name fromCodePointImport;
244+
Name equalsImport;
245+
Name compareImport;
246+
Name lengthImport;
247+
Name codePointAtImport;
248+
Name substringImport;
243249

244250
// The name of the module to import string functions from.
245251
Name WasmStringsModule = "wasm:js-string";
246252

247253
// Common types used in imports.
248254
Type nullArray16 = Type(Array(Field(Field::i16, Mutable)), Nullable);
255+
Type nullExt = Type(HeapType::ext, Nullable);
249256
Type nnExt = Type(HeapType::ext, NonNullable);
250257

251258
// Creates an imported string function, returning its name (which is equal to
@@ -269,6 +276,23 @@ struct StringLowering : public StringGathering {
269276
module, "fromCharCodeArray", {nullArray16, Type::i32, Type::i32}, nnExt);
270277
// string.fromCodePoint: codepoint -> ext
271278
fromCodePointImport = addImport(module, "fromCodePoint", Type::i32, nnExt);
279+
// string.intoCharCodeArray: string, array, start -> num written
280+
intoCharCodeArrayImport = addImport(module,
281+
"intoCharCodeArray",
282+
{nullExt, nullArray16, Type::i32},
283+
Type::i32);
284+
// string.equals: string, string -> i32
285+
equalsImport = addImport(module, "equals", {nullExt, nullExt}, Type::i32);
286+
// string.compare: string, string -> i32
287+
compareImport = addImport(module, "compare", {nullExt, nullExt}, Type::i32);
288+
// string.length: string -> i32
289+
lengthImport = addImport(module, "length", nullExt, Type::i32);
290+
// string.codePointAt: string, offset -> i32
291+
codePointAtImport =
292+
addImport(module, "codePointAt", {nullExt, Type::i32}, Type::i32);
293+
// string.substring: string, start, end -> string
294+
substringImport =
295+
addImport(module, "substring", {nullExt, Type::i32, Type::i32}, nnExt);
272296

273297
// Replace the string instructions in parallel.
274298
struct Replacer : public WalkerPass<PostWalker<Replacer>> {
@@ -304,6 +328,66 @@ struct StringLowering : public StringGathering {
304328
// strings: they are all just JS strings, so no conversion is needed.
305329
replaceCurrent(curr->ref);
306330
}
331+
332+
void visitStringEncode(StringEncode* curr) {
333+
Builder builder(*getModule());
334+
switch (curr->op) {
335+
case StringEncodeWTF16Array:
336+
replaceCurrent(builder.makeCall(lowering.intoCharCodeArrayImport,
337+
{curr->ref, curr->ptr, curr->start},
338+
Type::i32));
339+
return;
340+
default:
341+
WASM_UNREACHABLE("TODO: all of string.encode*");
342+
}
343+
}
344+
345+
void visitStringEq(StringEq* curr) {
346+
Builder builder(*getModule());
347+
switch (curr->op) {
348+
case StringEqEqual:
349+
replaceCurrent(builder.makeCall(
350+
lowering.equalsImport, {curr->left, curr->right}, Type::i32));
351+
return;
352+
case StringEqCompare:
353+
replaceCurrent(builder.makeCall(
354+
lowering.compareImport, {curr->left, curr->right}, Type::i32));
355+
return;
356+
default:
357+
WASM_UNREACHABLE("invalid string.eq*");
358+
}
359+
}
360+
361+
void visitStringMeasure(StringMeasure* curr) {
362+
Builder builder(*getModule());
363+
switch (curr->op) {
364+
case StringMeasureWTF16View:
365+
replaceCurrent(
366+
builder.makeCall(lowering.lengthImport, {curr->ref}, Type::i32));
367+
return;
368+
default:
369+
WASM_UNREACHABLE("invalid string.measure*");
370+
}
371+
}
372+
373+
void visitStringWTF16Get(StringWTF16Get* curr) {
374+
Builder builder(*getModule());
375+
replaceCurrent(builder.makeCall(
376+
lowering.codePointAtImport, {curr->ref, curr->pos}, Type::i32));
377+
}
378+
379+
void visitStringSliceWTF(StringSliceWTF* curr) {
380+
Builder builder(*getModule());
381+
switch (curr->op) {
382+
case StringSliceWTF16:
383+
replaceCurrent(builder.makeCall(lowering.substringImport,
384+
{curr->ref, curr->start, curr->end},
385+
lowering.nnExt));
386+
return;
387+
default:
388+
WASM_UNREACHABLE("TODO: all string.slice*");
389+
}
390+
}
307391
};
308392

309393
Replacer replacer(*this);

test/lit/passes/string-gathering.wast

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,21 +27,43 @@
2727
;; CHECK: (global $global2 stringref (global.get $string.const_bar))
2828
;; LOWER: (type $0 (func))
2929

30-
;; LOWER: (type $1 (array (mut i16)))
30+
;; LOWER: (type $1 (func (param externref externref) (result i32)))
3131

32-
;; LOWER: (type $2 (func (param (ref null $1) i32 i32) (result (ref extern))))
32+
;; LOWER: (type $2 (array (mut i16)))
3333

34-
;; LOWER: (type $3 (func (param i32) (result (ref extern))))
34+
;; LOWER: (type $3 (func (param (ref null $2) i32 i32) (result (ref extern))))
35+
36+
;; LOWER: (type $4 (func (param i32) (result (ref extern))))
37+
38+
;; LOWER: (type $5 (func (param externref (ref null $2) i32) (result i32)))
39+
40+
;; LOWER: (type $6 (func (param externref) (result i32)))
41+
42+
;; LOWER: (type $7 (func (param externref i32) (result i32)))
43+
44+
;; LOWER: (type $8 (func (param externref i32 i32) (result (ref extern))))
3545

3646
;; LOWER: (import "string.const" "0" (global $string.const_bar (ref extern)))
3747

3848
;; LOWER: (import "string.const" "1" (global $string.const_other (ref extern)))
3949

4050
;; LOWER: (import "string.const" "2" (global $global (ref extern)))
4151

42-
;; LOWER: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $2) (param (ref null $1) i32 i32) (result (ref extern))))
52+
;; LOWER: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $3) (param (ref null $2) i32 i32) (result (ref extern))))
4353

44-
;; LOWER: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint (type $3) (param i32) (result (ref extern))))
54+
;; LOWER: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint (type $4) (param i32) (result (ref extern))))
55+
56+
;; LOWER: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $5) (param externref (ref null $2) i32) (result i32)))
57+
58+
;; LOWER: (import "wasm:js-string" "equals" (func $equals (type $1) (param externref externref) (result i32)))
59+
60+
;; LOWER: (import "wasm:js-string" "compare" (func $compare (type $1) (param externref externref) (result i32)))
61+
62+
;; LOWER: (import "wasm:js-string" "length" (func $length (type $6) (param externref) (result i32)))
63+
64+
;; LOWER: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $7) (param externref i32) (result i32)))
65+
66+
;; LOWER: (import "wasm:js-string" "substring" (func $substring (type $8) (param externref i32 i32) (result (ref extern))))
4567

4668
;; LOWER: (global $global2 externref (global.get $string.const_bar))
4769
(global $global2 (ref null string) (string.const "bar"))
@@ -121,11 +143,21 @@
121143
;; Multiple possible reusable globals. Also test ignoring of imports.
122144
(module
123145
;; CHECK: (import "a" "b" (global $import (ref string)))
124-
;; LOWER: (type $0 (array (mut i16)))
146+
;; LOWER: (type $0 (func (param externref externref) (result i32)))
125147

126-
;; LOWER: (type $1 (func (param (ref null $0) i32 i32) (result (ref extern))))
148+
;; LOWER: (type $1 (array (mut i16)))
149+
150+
;; LOWER: (type $2 (func (param (ref null $1) i32 i32) (result (ref extern))))
151+
152+
;; LOWER: (type $3 (func (param i32) (result (ref extern))))
153+
154+
;; LOWER: (type $4 (func (param externref (ref null $1) i32) (result i32)))
155+
156+
;; LOWER: (type $5 (func (param externref) (result i32)))
157+
158+
;; LOWER: (type $6 (func (param externref i32) (result i32)))
127159

128-
;; LOWER: (type $2 (func (param i32) (result (ref extern))))
160+
;; LOWER: (type $7 (func (param externref i32 i32) (result (ref extern))))
129161

130162
;; LOWER: (import "a" "b" (global $import (ref extern)))
131163
(import "a" "b" (global $import (ref string)))
@@ -138,9 +170,21 @@
138170

139171
;; LOWER: (import "string.const" "1" (global $global4 (ref extern)))
140172

141-
;; LOWER: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $1) (param (ref null $0) i32 i32) (result (ref extern))))
173+
;; LOWER: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $2) (param (ref null $1) i32 i32) (result (ref extern))))
174+
175+
;; LOWER: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint (type $3) (param i32) (result (ref extern))))
176+
177+
;; LOWER: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $4) (param externref (ref null $1) i32) (result i32)))
178+
179+
;; LOWER: (import "wasm:js-string" "equals" (func $equals (type $0) (param externref externref) (result i32)))
180+
181+
;; LOWER: (import "wasm:js-string" "compare" (func $compare (type $0) (param externref externref) (result i32)))
182+
183+
;; LOWER: (import "wasm:js-string" "length" (func $length (type $5) (param externref) (result i32)))
184+
185+
;; LOWER: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $6) (param externref i32) (result i32)))
142186

143-
;; LOWER: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint (type $2) (param i32) (result (ref extern))))
187+
;; LOWER: (import "wasm:js-string" "substring" (func $substring (type $7) (param externref i32 i32) (result (ref extern))))
144188

145189
;; LOWER: (global $global2 (ref extern) (global.get $global1))
146190
(global $global2 (ref string) (string.const "foo"))

test/lit/passes/string-lowering-instructions.wast

Lines changed: 129 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,60 @@
33
;; RUN: foreach %s %t wasm-opt --string-lowering -all -S -o - | filecheck %s
44

55
(module
6-
;; CHECK: (type $0 (func))
7-
86
;; CHECK: (type $array16 (array (mut i16)))
97
(type $array16 (array (mut i16)))
108

9+
;; CHECK: (type $1 (func (param externref externref) (result i32)))
10+
1111
;; CHECK: (rec
12-
;; CHECK-NEXT: (type $2 (func (param (ref $array16))))
12+
;; CHECK-NEXT: (type $2 (func (param externref) (result externref)))
13+
14+
;; CHECK: (type $3 (func (param externref) (result i32)))
15+
16+
;; CHECK: (type $4 (func (param externref externref) (result i32)))
17+
18+
;; CHECK: (type $5 (func (param externref (ref $array16)) (result i32)))
19+
20+
;; CHECK: (type $6 (func (result externref)))
21+
22+
;; CHECK: (type $7 (func (param (ref $array16))))
1323

14-
;; CHECK: (type $3 (func (param externref externref externref externref)))
24+
;; CHECK: (type $8 (func (param externref externref externref externref)))
1525

16-
;; CHECK: (type $4 (func (param (ref null $array16) i32 i32) (result (ref extern))))
26+
;; CHECK: (type $9 (func))
1727

18-
;; CHECK: (type $5 (func (param i32) (result (ref extern))))
28+
;; CHECK: (type $10 (func (param (ref null $array16) i32 i32) (result (ref extern))))
1929

20-
;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $0)))
30+
;; CHECK: (type $11 (func (param i32) (result (ref extern))))
31+
32+
;; CHECK: (type $12 (func (param externref (ref null $array16) i32) (result i32)))
33+
34+
;; CHECK: (type $13 (func (param externref) (result i32)))
35+
36+
;; CHECK: (type $14 (func (param externref i32) (result i32)))
37+
38+
;; CHECK: (type $15 (func (param externref i32 i32) (result (ref extern))))
39+
40+
;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $9)))
2141
(import "colliding" "name" (func $fromCodePoint))
2242

23-
;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $4) (param (ref null $array16) i32 i32) (result (ref extern))))
43+
;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $10) (param (ref null $array16) i32 i32) (result (ref extern))))
44+
45+
;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_11 (type $11) (param i32) (result (ref extern))))
46+
47+
;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $12) (param externref (ref null $array16) i32) (result i32)))
2448

25-
;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_5 (type $5) (param i32) (result (ref extern))))
49+
;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $1) (param externref externref) (result i32)))
2650

27-
;; CHECK: (func $string.as (type $3) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
51+
;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $1) (param externref externref) (result i32)))
52+
53+
;; CHECK: (import "wasm:js-string" "length" (func $length (type $13) (param externref) (result i32)))
54+
55+
;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $14) (param externref i32) (result i32)))
56+
57+
;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $15) (param externref i32 i32) (result (ref extern))))
58+
59+
;; CHECK: (func $string.as (type $8) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
2860
;; CHECK-NEXT: (local.set $b
2961
;; CHECK-NEXT: (local.get $a)
3062
;; CHECK-NEXT: )
@@ -59,7 +91,7 @@
5991
)
6092
)
6193

62-
;; CHECK: (func $string.new.gc (type $2) (param $array16 (ref $array16))
94+
;; CHECK: (func $string.new.gc (type $7) (param $array16 (ref $array16))
6395
;; CHECK-NEXT: (drop
6496
;; CHECK-NEXT: (call $fromCharCodeArray
6597
;; CHECK-NEXT: (local.get $array16)
@@ -78,18 +110,94 @@
78110
)
79111
)
80112

81-
;; CHECK: (func $string.from_code_point (type $0)
82-
;; CHECK-NEXT: (drop
83-
;; CHECK-NEXT: (call $fromCodePoint_5
84-
;; CHECK-NEXT: (i32.const 1)
85-
;; CHECK-NEXT: )
113+
;; CHECK: (func $string.from_code_point (type $6) (result externref)
114+
;; CHECK-NEXT: (call $fromCodePoint_11
115+
;; CHECK-NEXT: (i32.const 1)
86116
;; CHECK-NEXT: )
87117
;; CHECK-NEXT: )
88-
(func $string.from_code_point
89-
(drop
90-
(string.from_code_point
91-
(i32.const 1)
92-
)
118+
(func $string.from_code_point (result stringref)
119+
(string.from_code_point
120+
(i32.const 1)
121+
)
122+
)
123+
124+
;; CHECK: (func $string.encode (type $5) (param $ref externref) (param $array16 (ref $array16)) (result i32)
125+
;; CHECK-NEXT: (call $intoCharCodeArray
126+
;; CHECK-NEXT: (local.get $ref)
127+
;; CHECK-NEXT: (local.get $array16)
128+
;; CHECK-NEXT: (i32.const 10)
129+
;; CHECK-NEXT: )
130+
;; CHECK-NEXT: )
131+
(func $string.encode (param $ref stringref) (param $array16 (ref $array16)) (result i32)
132+
(string.encode_wtf16_array
133+
(local.get $ref)
134+
(local.get $array16)
135+
(i32.const 10)
136+
)
137+
)
138+
139+
;; CHECK: (func $string.eq (type $4) (param $a externref) (param $b externref) (result i32)
140+
;; CHECK-NEXT: (call $equals
141+
;; CHECK-NEXT: (local.get $a)
142+
;; CHECK-NEXT: (local.get $b)
143+
;; CHECK-NEXT: )
144+
;; CHECK-NEXT: )
145+
(func $string.eq (param $a stringref) (param $b stringref) (result i32)
146+
(string.eq
147+
(local.get $a)
148+
(local.get $b)
149+
)
150+
)
151+
152+
;; CHECK: (func $string.compare (type $4) (param $a externref) (param $b externref) (result i32)
153+
;; CHECK-NEXT: (call $compare
154+
;; CHECK-NEXT: (local.get $a)
155+
;; CHECK-NEXT: (local.get $b)
156+
;; CHECK-NEXT: )
157+
;; CHECK-NEXT: )
158+
(func $string.compare (param $a stringref) (param $b stringref) (result i32)
159+
(string.compare
160+
(local.get $a)
161+
(local.get $b)
162+
)
163+
)
164+
165+
;; CHECK: (func $string.length (type $3) (param $ref externref) (result i32)
166+
;; CHECK-NEXT: (call $length
167+
;; CHECK-NEXT: (local.get $ref)
168+
;; CHECK-NEXT: )
169+
;; CHECK-NEXT: )
170+
(func $string.length (param $ref stringview_wtf16) (result i32)
171+
(stringview_wtf16.length
172+
(local.get $ref)
173+
)
174+
)
175+
176+
;; CHECK: (func $string.get_codeunit (type $3) (param $ref externref) (result i32)
177+
;; CHECK-NEXT: (call $codePointAt
178+
;; CHECK-NEXT: (local.get $ref)
179+
;; CHECK-NEXT: (i32.const 2)
180+
;; CHECK-NEXT: )
181+
;; CHECK-NEXT: )
182+
(func $string.get_codeunit (param $ref stringview_wtf16) (result i32)
183+
(stringview_wtf16.get_codeunit
184+
(local.get $ref)
185+
(i32.const 2)
186+
)
187+
)
188+
189+
;; CHECK: (func $string.slice (type $2) (param $ref externref) (result externref)
190+
;; CHECK-NEXT: (call $substring
191+
;; CHECK-NEXT: (local.get $ref)
192+
;; CHECK-NEXT: (i32.const 2)
193+
;; CHECK-NEXT: (i32.const 3)
194+
;; CHECK-NEXT: )
195+
;; CHECK-NEXT: )
196+
(func $string.slice (param $ref stringview_wtf16) (result stringref)
197+
(stringview_wtf16.slice
198+
(local.get $ref)
199+
(i32.const 2)
200+
(i32.const 3)
93201
)
94202
)
95203
)

0 commit comments

Comments
 (0)