Skip to content

Commit a5416d2

Browse files
authored
optimize dceing of blocks and known-to-exist children (#1015)
1 parent 9c6b8e0 commit a5416d2

File tree

1 file changed

+34
-57
lines changed

1 file changed

+34
-57
lines changed

src/passes/DeadCodeElimination.cpp

Lines changed: 34 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,16 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
7676
}
7777
}
7878

79-
// if a child is unreachable, we can replace ourselves with it
79+
// if a child exists and is unreachable, we can replace ourselves with it
8080
bool isDead(Expression* child) {
8181
return child && child->type == unreachable;
8282
}
8383

84+
// a similar check, assumes the child exists
85+
bool isUnreachable(Expression* child) {
86+
return child->type == unreachable;
87+
}
88+
8489
// things that stop control flow
8590

8691
void visitBreak(Break* curr) {
@@ -117,7 +122,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
117122
replaceCurrent(curr->value);
118123
return;
119124
}
120-
if (isDead(curr->condition)) {
125+
if (isUnreachable(curr->condition)) {
121126
if (curr->value) {
122127
auto* block = getModule()->allocator.alloc<Block>();
123128
block->list.resize(2);
@@ -149,45 +154,25 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
149154
reachable = false;
150155
}
151156

152-
// we maintain a stack for blocks, as we visit each item, and the parameter is the index
153-
154-
std::vector<Index> blockStack; // index in current block
155-
156-
static void doPreBlock(DeadCodeElimination* self, Expression** currp) {
157-
self->blockStack.push_back(0);
158-
}
159-
160-
static void doAfterBlockElement(DeadCodeElimination* self, Expression** currp) {
161-
auto* block = (*currp)->cast<Block>();
162-
Index i = self->blockStack.back();
163-
self->blockStack.back()++;
164-
if (!self->reachable) {
165-
// control flow ended in the middle of the block, so we can truncate the rest.
166-
// note that we still visit the rest, so if we already truncated, do not lengthen.
167-
// note that it is ok that we visit the others even though the list was shortened;
168-
// our arena vectors leave things as they are when shrinking.
169-
if (block->list.size() > i + 1) {
170-
// but note that it is not legal to truncate a block if it leaves a bad last element,
171-
// given the wasm type rules. For example, if the last element is a return, then
172-
// the block doesn't care about it for type checking purposes, but if removing
173-
// it would leave an element with type none as the last, that could be a problem,
174-
// see https://github.com/WebAssembly/spec/issues/355
175-
if (!(isConcreteWasmType(block->type) && block->list[i]->type == none)) {
176-
block->list.resize(i + 1);
177-
// note that we still walk the children, so typeUpdater will already
178-
// note they are being removed, and we don't need to do that here
157+
void visitBlock(Block* curr) {
158+
auto& list = curr->list;
159+
// if we are currently unreachable (before we take into account
160+
// breaks to the block) then a child may be unreachable, and we
161+
// can shorten
162+
if (!reachable && list.size() > 1) {
163+
// to do here: nothing to remove after it)
164+
for (Index i = 0; i < list.size() - 1; i++) {
165+
if (list[i]->type == unreachable) {
166+
list.resize(i + 1);
167+
break;
179168
}
180169
}
181170
}
182-
}
183-
184-
void visitBlock(Block* curr) {
185-
blockStack.pop_back();
186171
if (curr->name.is()) {
187172
reachable = reachable || reachableBreaks.count(curr->name);
188173
reachableBreaks.erase(curr->name);
189174
}
190-
if (curr->list.size() == 1 && isDead(curr->list[0])) {
175+
if (list.size() == 1 && isUnreachable(list[0])) {
191176
replaceCurrent(BlockUtils::simplifyToContentsWithPossibleTypeChange(curr, this));
192177
} else {
193178
// the block may have had a type, but can now be unreachable, which allows more reduction outside
@@ -199,7 +184,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
199184
if (curr->name.is()) {
200185
reachableBreaks.erase(curr->name);
201186
}
202-
if (isDead(curr->body) && !BreakSeeker::has(curr->body, curr->name)) {
187+
if (isUnreachable(curr->body) && !BreakSeeker::has(curr->body, curr->name)) {
203188
replaceCurrent(curr->body);
204189
return;
205190
}
@@ -225,7 +210,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
225210
// the ifStack has the branch that joins us, either from before if just an if, or the ifTrue if an if-else
226211
reachable = reachable || ifStack.back();
227212
ifStack.pop_back();
228-
if (isDead(curr->condition)) {
213+
if (isUnreachable(curr->condition)) {
229214
replaceCurrent(curr->condition);
230215
}
231216
// the if may have had a type, but can now be unreachable, which allows more reduction outside
@@ -280,14 +265,6 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
280265
self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->ifTrue);
281266
self->pushTask(DeadCodeElimination::doAfterIfCondition, currp);
282267
self->pushTask(DeadCodeElimination::scan, &curr->cast<If>()->condition);
283-
} else if (curr->is<Block>()) {
284-
self->pushTask(DeadCodeElimination::doVisitBlock, currp);
285-
auto& list = curr->cast<Block>()->list;
286-
for (int i = int(list.size()) - 1; i >= 0; i--) {
287-
self->pushTask(DeadCodeElimination::doAfterBlockElement, currp);
288-
self->pushTask(DeadCodeElimination::scan, &list[i]);
289-
}
290-
self->pushTask(DeadCodeElimination::doPreBlock, currp);
291268
} else {
292269
WalkerPass<PostWalker<DeadCodeElimination>>::scan(self, currp);
293270
}
@@ -304,7 +281,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
304281
template<typename T>
305282
Expression* handleCall(T* curr) {
306283
for (Index i = 0; i < curr->operands.size(); i++) {
307-
if (isDead(curr->operands[i])) {
284+
if (isUnreachable(curr->operands[i])) {
308285
if (i > 0) {
309286
auto* block = getModule()->allocator.alloc<Block>();
310287
Index newSize = i + 1;
@@ -333,7 +310,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
333310

334311
void visitCallIndirect(CallIndirect* curr) {
335312
if (handleCall(curr) != curr) return;
336-
if (isDead(curr->target)) {
313+
if (isUnreachable(curr->target)) {
337314
auto* block = getModule()->allocator.alloc<Block>();
338315
for (auto* operand : curr->operands) {
339316
block->list.push_back(drop(operand));
@@ -345,23 +322,23 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
345322
}
346323

347324
void visitSetLocal(SetLocal* curr) {
348-
if (isDead(curr->value)) {
325+
if (isUnreachable(curr->value)) {
349326
replaceCurrent(curr->value);
350327
}
351328
}
352329

353330
void visitLoad(Load* curr) {
354-
if (isDead(curr->ptr)) {
331+
if (isUnreachable(curr->ptr)) {
355332
replaceCurrent(curr->ptr);
356333
}
357334
}
358335

359336
void visitStore(Store* curr) {
360-
if (isDead(curr->ptr)) {
337+
if (isUnreachable(curr->ptr)) {
361338
replaceCurrent(curr->ptr);
362339
return;
363340
}
364-
if (isDead(curr->value)) {
341+
if (isUnreachable(curr->value)) {
365342
auto* block = getModule()->allocator.alloc<Block>();
366343
block->list.resize(2);
367344
block->list[0] = drop(curr->ptr);
@@ -372,17 +349,17 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
372349
}
373350

374351
void visitUnary(Unary* curr) {
375-
if (isDead(curr->value)) {
352+
if (isUnreachable(curr->value)) {
376353
replaceCurrent(curr->value);
377354
}
378355
}
379356

380357
void visitBinary(Binary* curr) {
381-
if (isDead(curr->left)) {
358+
if (isUnreachable(curr->left)) {
382359
replaceCurrent(curr->left);
383360
return;
384361
}
385-
if (isDead(curr->right)) {
362+
if (isUnreachable(curr->right)) {
386363
auto* block = getModule()->allocator.alloc<Block>();
387364
block->list.resize(2);
388365
block->list[0] = drop(curr->left);
@@ -393,11 +370,11 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
393370
}
394371

395372
void visitSelect(Select* curr) {
396-
if (isDead(curr->ifTrue)) {
373+
if (isUnreachable(curr->ifTrue)) {
397374
replaceCurrent(curr->ifTrue);
398375
return;
399376
}
400-
if (isDead(curr->ifFalse)) {
377+
if (isUnreachable(curr->ifFalse)) {
401378
auto* block = getModule()->allocator.alloc<Block>();
402379
block->list.resize(2);
403380
block->list[0] = drop(curr->ifTrue);
@@ -406,7 +383,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
406383
replaceCurrent(block);
407384
return;
408385
}
409-
if (isDead(curr->condition)) {
386+
if (isUnreachable(curr->condition)) {
410387
auto* block = getModule()->allocator.alloc<Block>();
411388
block->list.resize(3);
412389
block->list[0] = drop(curr->ifTrue);
@@ -419,7 +396,7 @@ struct DeadCodeElimination : public WalkerPass<PostWalker<DeadCodeElimination>>
419396
}
420397

421398
void visitDrop(Drop* curr) {
422-
if (isDead(curr->value)) {
399+
if (isUnreachable(curr->value)) {
423400
replaceCurrent(curr->value);
424401
}
425402
}

0 commit comments

Comments
 (0)