Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions src/passes/GlobalStructInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -300,24 +300,23 @@ 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.
auto fieldType = field.type;
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.
Expand Down Expand Up @@ -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);
Expand All @@ -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) {
Expand Down
51 changes: 51 additions & 0 deletions test/lit/passes/gsi.wast
Original file line number Diff line number Diff line change
Expand Up @@ -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)
)
)
)
)