Exemplo n.º 1
0
 Block* optimize(Expression* curr, Expression*& child, Block* outer = nullptr, Expression** dependency1 = nullptr, Expression** dependency2 = nullptr) {
   if (!child) return outer;
   if (dependency1 && *dependency1 && EffectAnalyzer(*dependency1).hasSideEffects()) return outer;
   if (dependency2 && *dependency2 && EffectAnalyzer(*dependency2).hasSideEffects()) return outer;
   if (auto* block = child->dynCast<Block>()) {
     if (!block->name.is() && block->list.size() >= 2) {
       child = block->list.back();
       if (outer == nullptr) {
         // reuse the block, move it out
         block->list.back() = curr;
         block->finalize(); // last block element was our input, and is now our output, which may differ TODO optimize
         replaceCurrent(block);
         return block;
       } else {
         // append to an existing outer block
         assert(outer->list.back() == curr);
         outer->list.pop_back();
         for (Index i = 0; i < block->list.size() - 1; i++) {
           outer->list.push_back(block->list[i]);
         }
         outer->list.push_back(curr);
       }
     }
   }
   return outer;
 }
Exemplo n.º 2
0
 void visitFunction(Function* curr) {
   auto* optimized = optimize(curr->body, curr->result != none);
   if (optimized) {
     curr->body = optimized;
   } else {
     ExpressionManipulator::nop(curr->body);
   }
   if (curr->result == none && !EffectAnalyzer(getPassOptions(), curr->body).hasSideEffects()) {
     ExpressionManipulator::nop(curr->body);
   }
 }
Exemplo n.º 3
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);
     }
   }
 }
Exemplo n.º 4
0
 void visitCallIndirect(CallIndirect* curr) {
   auto* outer = optimize(curr, curr->target);
   if (EffectAnalyzer(curr->target).hasSideEffects()) return;
   handleCall(curr, outer);
 }
Exemplo n.º 5
0
 void handleCall(T* curr, Block* outer = nullptr) {
   for (Index i = 0; i < curr->operands.size(); i++) {
     outer = optimize(curr, curr->operands[i], outer);
     if (EffectAnalyzer(curr->operands[i]).hasSideEffects()) return;
   }
 }
Exemplo n.º 6
0
  // returns nullptr if curr is dead, curr if it must stay as is, or another node if it can be replaced
  Expression* optimize(Expression* curr, bool resultUsed) {
    while (1) {
      switch (curr->_id) {
        case Expression::Id::NopId: return nullptr; // never needed

        case Expression::Id::BlockId: return curr; // not always needed, but handled in visitBlock()
        case Expression::Id::IfId: return curr; // not always needed, but handled in visitIf()
        case Expression::Id::LoopId: return curr; // not always needed, but handled in visitLoop()
        case Expression::Id::DropId: return curr; // not always needed, but handled in visitDrop()

        case Expression::Id::BreakId:
        case Expression::Id::SwitchId:
        case Expression::Id::CallId:
        case Expression::Id::CallImportId:
        case Expression::Id::CallIndirectId:
        case Expression::Id::SetLocalId:
        case Expression::Id::StoreId:
        case Expression::Id::ReturnId:
        case Expression::Id::SetGlobalId:
        case Expression::Id::HostId:
        case Expression::Id::UnreachableId: return curr; // always needed

        case Expression::Id::LoadId: {
          if (!resultUsed) {
            return curr->cast<Load>()->ptr;
          }
          return curr;
        }
        case Expression::Id::ConstId:
        case Expression::Id::GetLocalId:
        case Expression::Id::GetGlobalId: {
          if (!resultUsed) return nullptr;
          return curr;
        }

        case Expression::Id::UnaryId:
        case Expression::Id::BinaryId:
        case Expression::Id::SelectId: {
          if (resultUsed) {
            return curr; // used, keep it
          }
          // for unary, binary, and select, we need to check their arguments for side effects
          if (auto* unary = curr->dynCast<Unary>()) {
            if (EffectAnalyzer(getPassOptions(), unary->value).hasSideEffects()) {
              curr = unary->value;
              continue;
            } else {
              return nullptr;
            }
          } else if (auto* binary = curr->dynCast<Binary>()) {
            if (EffectAnalyzer(getPassOptions(), binary->left).hasSideEffects()) {
              if (EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) {
                return curr; // leave them
              } else {
                curr = binary->left;
                continue;
              }
            } else {
              if (EffectAnalyzer(getPassOptions(), binary->right).hasSideEffects()) {
                curr = binary->right;
                continue;
              } else {
                return nullptr;
              }
            }
          } else {
            // TODO: if two have side effects, we could replace the select with say an add?
            auto* select = curr->cast<Select>();
            if (EffectAnalyzer(getPassOptions(), select->ifTrue).hasSideEffects()) {
              if (EffectAnalyzer(getPassOptions(), select->ifFalse).hasSideEffects()) {
                return curr; // leave them
              } else {
                if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) {
                  return curr; // leave them
                } else {
                  curr = select->ifTrue;
                  continue;
                }
              }
            } else {
              if (EffectAnalyzer(getPassOptions(), select->ifFalse).hasSideEffects()) {
                if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) {
                  return curr; // leave them
                } else {
                  curr = select->ifFalse;
                  continue;
                }
              } else {
                if (EffectAnalyzer(getPassOptions(), select->condition).hasSideEffects()) {
                  curr = select->condition;
                  continue;
                } else {
                  return nullptr;
                }
              }
            }
          }
        }

        default: WASM_UNREACHABLE();
      }
    }
  }