summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/StringLowering.cpp52
-rw-r--r--test/lit/passes/string-lowering-instructions.wast105
2 files changed, 111 insertions, 46 deletions
diff --git a/src/passes/StringLowering.cpp b/src/passes/StringLowering.cpp
index d0487f602..a0002fcf6 100644
--- a/src/passes/StringLowering.cpp
+++ b/src/passes/StringLowering.cpp
@@ -423,24 +423,44 @@ struct StringLowering : public StringGathering {
}
}
- // Additional hacks.
+ // Additional hacks: We fix up a none that should be noext. Before the
+ // lowering we can use none for stringref, but after we must use noext as
+ // the two do not share a bottom type.
+ //
+ // The code here and in the visitors below is course wildly insufficient
+ // (we need selects and blocks and all other joins, and not just nulls,
+ // etc.) but in practice this is enough for now. TODO extend as needed
+ void ensureNullIsExt(Expression* curr) {
+ if (auto* null = curr->dynCast<RefNull>()) {
+ null->finalize(HeapType::noext);
+ }
+ }
+
+ bool isExt(Type type) {
+ return type.isRef() && type.getHeapType() == HeapType::ext;
+ }
void visitIf(If* curr) {
- // Before the lowering we could have one arm be a ref.null none and the
- // other a stringref; after the lowering that is invalid, because the
- // string is now extern, which has no shared ancestor with none. Fix
- // that up manually in the simple case of an if arm with a null by
- // correcting the null's type. This is of course wildly insufficient (we
- // need selects and blocks and all other joins) but in practice this is
- // enough for now. TODO extend as needed
- if (curr->type.isRef() && curr->type.getHeapType() == HeapType::ext) {
- auto fixArm = [](Expression* arm) {
- if (auto* null = arm->dynCast<RefNull>()) {
- null->finalize(HeapType::noext);
- }
- };
- fixArm(curr->ifTrue);
- fixArm(curr->ifFalse);
+ // If the if outputs an ext, fix up the arms to contain proper nulls for
+ // that type.
+ if (isExt(curr->type)) {
+ ensureNullIsExt(curr->ifTrue);
+ ensureNullIsExt(curr->ifFalse);
+ }
+ }
+
+ void visitStructNew(StructNew* curr) {
+ if (curr->type == Type::unreachable || curr->operands.empty()) {
+ return;
+ }
+
+ // If we write a none into an ext field, fix that.
+ auto& fields = curr->type.getHeapType().getStruct().fields;
+ assert(curr->operands.size() == fields.size());
+ for (Index i = 0; i < fields.size(); i++) {
+ if (isExt(fields[i].type)) {
+ ensureNullIsExt(curr->operands[i]);
+ }
}
}
};
diff --git a/test/lit/passes/string-lowering-instructions.wast b/test/lit/passes/string-lowering-instructions.wast
index 2feedcb39..458cf4f91 100644
--- a/test/lit/passes/string-lowering-instructions.wast
+++ b/test/lit/passes/string-lowering-instructions.wast
@@ -15,6 +15,9 @@
;; CHECK: (type $4 (func (result externref)))
+ ;; CHECK: (type $struct-of-string (struct (field externref) (field i32) (field anyref)))
+ (type $struct-of-string (struct (field stringref) (field i32) (field anyref)))
+
;; CHECK: (type $struct-of-array (struct (field (ref $0))))
(type $struct-of-array (struct (field (ref $array16))))
@@ -34,58 +37,60 @@
(type $array16 (array (mut i16)))
)
- ;; CHECK: (type $11 (func (param externref) (result externref)))
-
;; CHECK: (type $12 (func (param externref) (result externref)))
- ;; CHECK: (type $13 (func (param externref) (result i32)))
+ ;; CHECK: (type $13 (func (param externref) (result externref)))
- ;; CHECK: (type $14 (func (param externref externref) (result i32)))
+ ;; CHECK: (type $14 (func (param externref) (result i32)))
- ;; CHECK: (type $15 (func (param externref (ref $0)) (result i32)))
+ ;; CHECK: (type $15 (func (param externref externref) (result i32)))
- ;; CHECK: (type $16 (func (param (ref $0))))
+ ;; CHECK: (type $16 (func (param externref (ref $0)) (result i32)))
- ;; CHECK: (type $17 (func (param externref externref externref externref)))
+ ;; CHECK: (type $17 (func (param (ref $0))))
- ;; CHECK: (type $18 (func (param (ref null $0) i32 i32) (result (ref extern))))
+ ;; CHECK: (type $18 (func (param externref externref externref externref)))
- ;; CHECK: (type $19 (func (param i32) (result (ref extern))))
+ ;; CHECK: (type $19 (func (param (ref null $0) i32 i32) (result (ref extern))))
- ;; CHECK: (type $20 (func (param externref (ref null $0) i32) (result i32)))
+ ;; CHECK: (type $20 (func (param i32) (result (ref extern))))
- ;; CHECK: (type $21 (func (param externref) (result i32)))
+ ;; CHECK: (type $21 (func (param externref (ref null $0) i32) (result i32)))
- ;; CHECK: (type $22 (func (param externref i32) (result i32)))
+ ;; CHECK: (type $22 (func (param externref) (result i32)))
- ;; CHECK: (type $23 (func (param externref i32 i32) (result (ref extern))))
+ ;; CHECK: (type $23 (func (param externref i32) (result i32)))
+
+ ;; CHECK: (type $24 (func (param externref i32 i32) (result (ref extern))))
;; CHECK: (import "string.const" "0" (global $string.const_exported (ref extern)))
+ ;; CHECK: (import "string.const" "1" (global $string.const_value (ref extern)))
+
;; CHECK: (import "colliding" "name" (func $fromCodePoint (type $1)))
(import "colliding" "name" (func $fromCodePoint))
- ;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $18) (param (ref null $0) i32 i32) (result (ref extern))))
+ ;; CHECK: (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (type $19) (param (ref null $0) i32 i32) (result (ref extern))))
- ;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_16 (type $19) (param i32) (result (ref extern))))
+ ;; CHECK: (import "wasm:js-string" "fromCodePoint" (func $fromCodePoint_17 (type $20) (param i32) (result (ref extern))))
- ;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $20) (param externref (ref null $0) i32) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "intoCharCodeArray" (func $intoCharCodeArray (type $21) (param externref (ref null $0) i32) (result i32)))
;; CHECK: (import "wasm:js-string" "equals" (func $equals (type $2) (param externref externref) (result i32)))
;; CHECK: (import "wasm:js-string" "compare" (func $compare (type $2) (param externref externref) (result i32)))
- ;; CHECK: (import "wasm:js-string" "length" (func $length (type $21) (param externref) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "length" (func $length (type $22) (param externref) (result i32)))
- ;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $22) (param externref i32) (result i32)))
+ ;; CHECK: (import "wasm:js-string" "codePointAt" (func $codePointAt (type $23) (param externref i32) (result i32)))
- ;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $23) (param externref i32 i32) (result (ref extern))))
+ ;; CHECK: (import "wasm:js-string" "substring" (func $substring (type $24) (param externref i32 i32) (result (ref extern))))
;; CHECK: (export "export.1" (func $exported-string-returner))
;; CHECK: (export "export.2" (func $exported-string-receiver))
- ;; CHECK: (func $string.as (type $17) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
+ ;; CHECK: (func $string.as (type $18) (param $a externref) (param $b externref) (param $c externref) (param $d externref)
;; CHECK-NEXT: (local.set $b
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: )
@@ -120,7 +125,7 @@
)
)
- ;; CHECK: (func $string.new.gc (type $16) (param $array16 (ref $0))
+ ;; CHECK: (func $string.new.gc (type $17) (param $array16 (ref $0))
;; CHECK-NEXT: (drop
;; CHECK-NEXT: (call $fromCharCodeArray
;; CHECK-NEXT: (local.get $array16)
@@ -140,7 +145,7 @@
)
;; CHECK: (func $string.from_code_point (type $4) (result externref)
- ;; CHECK-NEXT: (call $fromCodePoint_16
+ ;; CHECK-NEXT: (call $fromCodePoint_17
;; CHECK-NEXT: (i32.const 1)
;; CHECK-NEXT: )
;; CHECK-NEXT: )
@@ -150,7 +155,7 @@
)
)
- ;; CHECK: (func $string.encode (type $15) (param $ref externref) (param $array16 (ref $0)) (result i32)
+ ;; CHECK: (func $string.encode (type $16) (param $ref externref) (param $array16 (ref $0)) (result i32)
;; CHECK-NEXT: (call $intoCharCodeArray
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: (local.get $array16)
@@ -165,7 +170,7 @@
)
)
- ;; CHECK: (func $string.eq (type $14) (param $a externref) (param $b externref) (result i32)
+ ;; CHECK: (func $string.eq (type $15) (param $a externref) (param $b externref) (result i32)
;; CHECK-NEXT: (call $equals
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (local.get $b)
@@ -178,7 +183,7 @@
)
)
- ;; CHECK: (func $string.compare (type $14) (param $a externref) (param $b externref) (result i32)
+ ;; CHECK: (func $string.compare (type $15) (param $a externref) (param $b externref) (result i32)
;; CHECK-NEXT: (call $compare
;; CHECK-NEXT: (local.get $a)
;; CHECK-NEXT: (local.get $b)
@@ -191,7 +196,7 @@
)
)
- ;; CHECK: (func $string.length (type $13) (param $ref externref) (result i32)
+ ;; CHECK: (func $string.length (type $14) (param $ref externref) (result i32)
;; CHECK-NEXT: (call $length
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: )
@@ -202,7 +207,7 @@
)
)
- ;; CHECK: (func $string.get_codeunit (type $13) (param $ref externref) (result i32)
+ ;; CHECK: (func $string.get_codeunit (type $14) (param $ref externref) (result i32)
;; CHECK-NEXT: (call $codePointAt
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: (i32.const 2)
@@ -215,7 +220,7 @@
)
)
- ;; CHECK: (func $string.slice (type $12) (param $ref externref) (result externref)
+ ;; CHECK: (func $string.slice (type $13) (param $ref externref) (result externref)
;; CHECK-NEXT: (call $substring
;; CHECK-NEXT: (local.get $ref)
;; CHECK-NEXT: (i32.const 2)
@@ -230,7 +235,7 @@
)
)
- ;; CHECK: (func $if.string (type $11) (param $ref externref) (result externref)
+ ;; CHECK: (func $if.string (type $12) (param $ref externref) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (then
@@ -253,7 +258,7 @@
)
)
- ;; CHECK: (func $if.string.flip (type $11) (param $ref externref) (result externref)
+ ;; CHECK: (func $if.string.flip (type $12) (param $ref externref) (result externref)
;; CHECK-NEXT: (if (result externref)
;; CHECK-NEXT: (i32.const 0)
;; CHECK-NEXT: (then
@@ -366,4 +371,44 @@
)
)
)
+
+ ;; CHECK: (func $struct-of-string (type $1)
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new $struct-of-string
+ ;; CHECK-NEXT: (ref.null noextern)
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new $struct-of-string
+ ;; CHECK-NEXT: (global.get $string.const_value)
+ ;; CHECK-NEXT: (i32.const 10)
+ ;; CHECK-NEXT: (ref.null none)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (struct.new_default $struct-of-string)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $struct-of-string
+ ;; Test lowering of struct fields from stringref to externref.
+ (drop
+ (struct.new $struct-of-string
+ (ref.null none) ;; This null must be fixed to be ext.
+ (i32.const 10)
+ (ref.null none) ;; Nothing to do here (field remains anyref).
+ )
+ )
+ (drop
+ (struct.new $struct-of-string
+ (string.const "value") ;; Nothing to do besides change to a global.
+ (i32.const 10)
+ (ref.null none)
+ )
+ )
+ (drop
+ (struct.new_default $struct-of-string) ;; Nothing to do here.
+ )
+ )
)