summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/passes/GlobalStructInference.cpp21
-rw-r--r--test/lit/passes/gsi.wast51
2 files changed, 61 insertions, 11 deletions
diff --git a/src/passes/GlobalStructInference.cpp b/src/passes/GlobalStructInference.cpp
index 9fc906971..c0b92e3bb 100644
--- a/src/passes/GlobalStructInference.cpp
+++ b/src/passes/GlobalStructInference.cpp
@@ -50,7 +50,7 @@
#include "ir/find_all.h"
#include "ir/module-utils.h"
-#include "ir/properties.h"
+#include "ir/possible-constant.h"
#include "ir/subtypes.h"
#include "ir/utils.h"
#include "pass.h"
@@ -300,7 +300,7 @@ struct GlobalStructInference : public Pass {
// Find the constant values and which globals correspond to them.
// TODO: SmallVectors?
- std::vector<Literal> values;
+ std::vector<PossibleConstantValues> values;
std::vector<std::vector<Name>> globalsForValue;
// Check if the relevant fields contain constants.
@@ -308,16 +308,15 @@ struct GlobalStructInference : public Pass {
for (Index i = 0; i < globals.size(); i++) {
Name global = globals[i];
auto* structNew = wasm.getGlobal(global)->init->cast<StructNew>();
- Literal value;
+ PossibleConstantValues value;
if (structNew->isWithDefault()) {
- value = Literal::makeZero(fieldType);
+ value.note(Literal::makeZero(fieldType));
} else {
- auto* init = structNew->operands[fieldIndex];
- if (!Properties::isConstantExpression(init)) {
- // Non-constant; give up entirely.
+ value.note(structNew->operands[fieldIndex], wasm);
+ if (!value.isConstant()) {
+ // Give up entirely.
return;
}
- value = Properties::getLiteral(init);
}
// Process the current value, comparing it against the previous.
@@ -346,7 +345,7 @@ struct GlobalStructInference : public Pass {
// otherwise return the value.
replaceCurrent(builder.makeSequence(
builder.makeDrop(builder.makeRefAs(RefAsNonNull, curr->ref)),
- builder.makeConstantExpression(values[0])));
+ values[0].makeExpression(wasm)));
return;
}
assert(values.size() == 2);
@@ -373,8 +372,8 @@ struct GlobalStructInference : public Pass {
builder.makeRefEq(builder.makeRefAs(RefAsNonNull, curr->ref),
builder.makeGlobalGet(
checkGlobal, wasm.getGlobal(checkGlobal)->type)),
- builder.makeConstantExpression(values[0]),
- builder.makeConstantExpression(values[1])));
+ values[0].makeExpression(wasm),
+ values[1].makeExpression(wasm)));
}
void visitFunction(Function* func) {
diff --git a/test/lit/passes/gsi.wast b/test/lit/passes/gsi.wast
index f60e911c7..15afea5ed 100644
--- a/test/lit/passes/gsi.wast
+++ b/test/lit/passes/gsi.wast
@@ -1437,3 +1437,54 @@
)
)
)
+
+;; Test that we can optimize global.get operations on immutable globals.
+(module
+ ;; CHECK: (type $struct (struct (field i32)))
+ (type $struct (struct i32))
+
+ ;; CHECK: (type $1 (func (param (ref null $struct))))
+
+ ;; CHECK: (global $one i32 (i32.const 1))
+ (global $one i32 (i32.const 1))
+
+ ;; CHECK: (global $two i32 (i32.const 2))
+ (global $two i32 (i32.const 2))
+
+ ;; CHECK: (global $global1 (ref $struct) (struct.new $struct
+ ;; CHECK-NEXT: (global.get $one)
+ ;; CHECK-NEXT: ))
+ (global $global1 (ref $struct) (struct.new $struct
+ (global.get $one)
+ ))
+
+ ;; CHECK: (global $global2 (ref $struct) (struct.new $struct
+ ;; CHECK-NEXT: (global.get $two)
+ ;; CHECK-NEXT: ))
+ (global $global2 (ref $struct) (struct.new $struct
+ (global.get $two)
+ ))
+
+ ;; CHECK: (func $test (type $1) (param $struct (ref null $struct))
+ ;; CHECK-NEXT: (drop
+ ;; CHECK-NEXT: (select
+ ;; CHECK-NEXT: (global.get $one)
+ ;; CHECK-NEXT: (global.get $two)
+ ;; CHECK-NEXT: (ref.eq
+ ;; CHECK-NEXT: (ref.as_non_null
+ ;; CHECK-NEXT: (local.get $struct)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: (global.get $global1)
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ ;; CHECK-NEXT: )
+ (func $test (param $struct (ref null $struct))
+ ;; The get here will read one of the two globals, so we can use a select.
+ (drop
+ (struct.get $struct 0
+ (local.get $struct)
+ )
+ )
+ )
+)