Example #1
0
 void visitBlock(Block *curr) {
   // compress out nops and other dead code
   int skip = 0;
   auto& list = curr->list;
   size_t size = list.size();
   bool needResize = false;
   for (size_t z = 0; z < size; z++) {
     auto* optimized = optimize(list[z], z == size - 1 && isConcreteWasmType(curr->type));
     if (!optimized) {
       skip++;
       needResize = true;
     } else {
       if (optimized != list[z]) {
         list[z] = optimized;
       }
       if (skip > 0) {
         list[z - skip] = list[z];
       }
       // if this is an unconditional br, the rest is dead code
       Break* br = list[z - skip]->dynCast<Break>();
       Switch* sw = list[z - skip]->dynCast<Switch>();
       if ((br && !br->condition) || sw) {
         auto* last = list.back();
         list.resize(z - skip + 1);
         // if we removed the last one, and it was a return value, it must be returned
         if (list.back() != last && isConcreteWasmType(last->type)) {
           list.push_back(last);
         }
         needResize = false;
         break;
       }
     }
   }
   if (needResize) {
     list.resize(size - skip);
   }
   if (!curr->name.is()) {
     if (list.size() == 1) {
       // just one element. replace the block, either with it or with a nop if it's not needed
       if (isConcreteWasmType(curr->type) || EffectAnalyzer(getPassOptions(), list[0]).hasSideEffects()) {
         replaceCurrent(list[0]);
       } else {
         if (curr->type == unreachable) {
           ExpressionManipulator::convert<Block, Unreachable>(curr);
         } else {
           ExpressionManipulator::nop(curr);
         }
       }
     } else if (list.size() == 0) {
       ExpressionManipulator::nop(curr);
     }
   }
 }
Example #2
0
 void visitExpression(Expression* curr) {
   if (curr->is<Const>()) return;
   // try to evaluate this into a const
   Flow flow;
   try {
     flow = StandaloneExpressionRunner().visit(curr);
   } catch (StandaloneExpressionRunner::NonstandaloneException& e) {
     return;
   }
   if (flow.breaking()) return; // TODO: can create a break as a replacement in some cases (not NONSTANDALONE)
   if (isConcreteWasmType(flow.value.type)) {
     replaceCurrent(Builder(*getModule()).makeConst(flow.value));
   }
 }
Example #3
0
 void visitDrop(Drop* curr) {
   // optimize the dropped value, maybe leaving nothing
   curr->value = optimize(curr->value, false);
   if (curr->value == nullptr) {
     ExpressionManipulator::nop(curr);
     return;
   }
   // a drop of a tee is a set
   if (auto* set = curr->value->dynCast<SetLocal>()) {
     assert(set->isTee());
     set->setTee(false);
     replaceCurrent(set);
     return;
   }
   // if we are dropping a block's return value, we might be able to remove it entirely
   if (auto* block = curr->value->dynCast<Block>()) {
     auto* last = block->list.back();
     if (isConcreteWasmType(last->type)) {
       assert(block->type == last->type);
       last = optimize(last, false);
       if (!last) {
         // we may be able to remove this, if there are no brs
         bool canPop = true;
         if (block->name.is()) {
           BreakSeeker breakSeeker(block->name);
           Expression* temp = block;
           breakSeeker.walk(temp);
           if (breakSeeker.found && breakSeeker.valueType != none) {
             canPop = false;
           }
         }
         if (canPop) {
           block->list.back() = last;
           block->list.pop_back();
           block->type = none;
           // we don't need the drop anymore, let's see what we have left in the block
           if (block->list.size() > 1) {
             replaceCurrent(block);
           } else if (block->list.size() == 1) {
             replaceCurrent(block->list[0]);
           } else {
             ExpressionManipulator::nop(curr);
           }
           return;
         }
       }
     }
   }
   // sink a drop into an arm of an if-else if the other arm ends in an unreachable, as it if is a branch, this can make that branch optimizable and more vaccuming possible
   auto* iff = curr->value->dynCast<If>();
   if (iff && iff->ifFalse && isConcreteWasmType(iff->type)) {
     // reuse the drop in both cases
     if (iff->ifTrue->type == unreachable) {
       assert(isConcreteWasmType(iff->ifFalse->type));
       curr->value = iff->ifFalse;
       iff->ifFalse = curr;
       iff->type = none;
       replaceCurrent(iff);
     } else if (iff->ifFalse->type == unreachable) {
       assert(isConcreteWasmType(iff->ifTrue->type));
       curr->value = iff->ifTrue;
       iff->ifTrue = curr;
       iff->type = none;
       replaceCurrent(iff);
     }
   }
 }