Skip to content

Conversation

kripken
Copy link
Member

@kripken kripken commented Jun 20, 2024

If we have

(global $g (struct.new $S (i32.const 1) (struct.new $T ..) (ref.func $f) ))

then before this PR if we wanted to read the middle field we'd stop, as it is non-constant.
However, we can un-nest it, making it constant:

(global $g.unnested (struct.new $T ..)) (global $g (struct.new $S (i32.const 1) (global.get $g.unnested) (ref.func $f) ))

Now the field is a global.get of an immutable global, which is constant. Using this
technique we can handle anything in a struct field, constant or not. The cost of adding
a global is likely offset by the benefit of being able to refer to it directly, as that opens
up more opportunities later.

Concretely, this replaces the constant values we look for in GSI with a variant over
constants or expressions (we do still want to group constants, as multiple globals
with the same constant field can be treated as a whole). And we note cases where we
need to un-nest, and handle those at the end.

@kripken kripken requested a review from tlively June 20, 2024 17:52

std::unique_ptr<Pass> create() override {
return std::make_unique<FunctionOptimizer>(parent);
const PossibleConstantValues& getConstant() const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have this return a pointer, then you can avoid the need for a separate isConstant and you can use it conveniently in if (assignment) expressions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yeah, that might be a little less code here. But I'm not sure if it would be more clear (as working with pointers is less nice). Also, this is parallel to other existing APIs:

bool isConstant() const {
return !std::get_if<None>(&value) && !std::get_if<Many>(&value);
}
bool isConstantLiteral() const { return std::get_if<Literal>(&value); }
bool isConstantGlobal() const { return std::get_if<Name>(&value); }
bool isNull() const {
return isConstantLiteral() && getConstantLiteral().isNull();
}
// Returns the single constant value.
Literal getConstantLiteral() const {
assert(isConstant());
return std::get<Literal>(value);
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we have divergent styles here. All of the variant-using code I've written uses the pointer approach :)

// See if it matches anything we've seen before.
bool grouped = false;
if (value.isConstant()) {
for (auto& oldValue : values) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be worth mapping constants to Values to avoid this linear lookup?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, since we have a limit on 2 values (so that we can do a single comparison to pick between them).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, right, that makes sense, too.

@kripken kripken merged commit c3089b3 into WebAssembly:main Jun 20, 2024
@kripken kripken deleted the gsi.unnest branch June 20, 2024 22:24
@gkdn gkdn mentioned this pull request Aug 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants