Skip to content

Commit

Permalink
[SignExt] OptimizeInstructions: Remove signexts of already-extended v…
Browse files Browse the repository at this point in the history
…alues (WebAssembly#7072)
  • Loading branch information
kripken authored Nov 14, 2024
1 parent 9002cc6 commit 74a910b
Show file tree
Hide file tree
Showing 2 changed files with 404 additions and 15 deletions.
52 changes: 37 additions & 15 deletions src/passes/OptimizeInstructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ static bool isSignedOp(BinaryOp op) {
struct LocalInfo {
static const Index kUnknown = Index(-1);

Index maxBits;
Index signExtedBits;
Index maxBits = -1;
Index signExtBits = 0;
};

struct LocalScanner : PostWalker<LocalScanner> {
Expand All @@ -99,18 +99,18 @@ struct LocalScanner : PostWalker<LocalScanner> {
auto& info = localInfo[i];
if (func->isParam(i)) {
info.maxBits = getBitsForType(func->getLocalType(i)); // worst-case
info.signExtedBits = LocalInfo::kUnknown; // we will never know anything
info.signExtBits = LocalInfo::kUnknown; // we will never know anything
} else {
info.maxBits = info.signExtedBits = 0; // we are open to learning
info.maxBits = info.signExtBits = 0; // we are open to learning
}
}
// walk
PostWalker<LocalScanner>::doWalkFunction(func);
// finalize
for (Index i = 0; i < func->getNumLocals(); i++) {
auto& info = localInfo[i];
if (info.signExtedBits == LocalInfo::kUnknown) {
info.signExtedBits = 0;
if (info.signExtBits == LocalInfo::kUnknown) {
info.signExtBits = 0;
}
}
}
Expand All @@ -137,11 +137,11 @@ struct LocalScanner : PostWalker<LocalScanner> {
signExtBits = load->bytes * 8;
}
}
if (info.signExtedBits == 0) {
info.signExtedBits = signExtBits; // first info we see
} else if (info.signExtedBits != signExtBits) {
if (info.signExtBits == 0) {
info.signExtBits = signExtBits; // first info we see
} else if (info.signExtBits != signExtBits) {
// contradictory information, give up
info.signExtedBits = LocalInfo::kUnknown;
info.signExtBits = LocalInfo::kUnknown;
}
}

Expand Down Expand Up @@ -1006,6 +1006,22 @@ struct OptimizeInstructions
}
}

// Simple sign extends can be removed if the value is already sign-extended.
auto signExtBits = getSignExtBits(curr->value);
if (signExtBits > 0) {
// Note that we can handle the case of |curr| having a larger sign-extend:
// if we have an 8-bit value in 32-bit, then there are 24 sign bits, and
// doing a sign-extend to 16 will only affect 16 of those 24, and the
// effect is to leave them as they are.
if ((curr->op == ExtendS8Int32 && signExtBits <= 8) ||
(curr->op == ExtendS16Int32 && signExtBits <= 16) ||
(curr->op == ExtendS8Int64 && signExtBits <= 8) ||
(curr->op == ExtendS16Int64 && signExtBits <= 16) ||
(curr->op == ExtendS32Int64 && signExtBits <= 32)) {
return replaceCurrent(curr->value);
}
}

if (Abstract::hasAnyReinterpret(curr->op)) {
// i32.reinterpret_f32(f32.reinterpret_i32(x)) => x
// i64.reinterpret_f64(f64.reinterpret_i64(x)) => x
Expand Down Expand Up @@ -3611,16 +3627,22 @@ struct OptimizeInstructions
return inner;
}

// check if an expression is already sign-extended
// Check if an expression is already sign-extended to an exact number of bits.
bool isSignExted(Expression* curr, Index bits) {
return getSignExtBits(curr) == bits;
}

// Returns the number of bits an expression is sign-extended (or 0 if it is
// not).
Index getSignExtBits(Expression* curr) {
if (Properties::getSignExtValue(curr)) {
return Properties::getSignExtBits(curr) == bits;
return Properties::getSignExtBits(curr);
}
if (auto* get = curr->dynCast<LocalGet>()) {
// check what we know about the local
return localInfo[get->index].signExtedBits == bits;
// Check what we know about the local.
return localInfo[get->index].signExtBits;
}
return false;
return 0;
}

// optimize trivial math operations, given that the right side of a binary
Expand Down
Loading

0 comments on commit 74a910b

Please sign in to comment.