/*
 * Copyright 2016 WebAssembly Community Group participants
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// Removes obviously unneeded code
//

#include <ir/block-utils.h>
#include <ir/effects.h>
#include <ir/literal-utils.h>
#include <ir/type-updating.h>
#include <ir/utils.h>
#include <pass.h>
#include <wasm-builder.h>
#include <wasm.h>

namespace wasm {

struct Vacuum : public WalkerPass<ExpressionStackWalker<Vacuum>> {
  bool isFunctionParallel() override { return true; }

  Pass* create() override { return new Vacuum; }

  TypeUpdater typeUpdater;

  Expression* replaceCurrent(Expression* expression) {
    auto* old = getCurrent();
    super::replaceCurrent(expression);
    // also update the type updater
    typeUpdater.noteReplacement(old, expression);
    return expression;
  }

  void doWalkFunction(Function* func) {
    typeUpdater.walk(func->body);
    walk(func->body);
  }

  // Returns nullptr if curr is dead, curr if it must stay as is, or another
  // node if it can be replaced. Takes into account:
  //  * The result may be used or unused.
  //  * The type may or may not matter (a drop can drop anything, for example).
  Expression* optimize(Expression* curr, bool resultUsed, bool typeMatters) {
    FeatureSet features = getModule()->features;
    auto type = curr->type;
    // An unreachable node must not be changed.
    if (type == Type::unreachable) {
      return curr;
    }
    // We iterate on possible replacements. If a replacement changes the type,
    // stop and go back.
    auto* prev = curr;
    while (1) {
      if (typeMatters && curr->type != type) {
        return prev;
      }
      prev = curr;
      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::TryId:
          return curr; // not always needed, but handled in visitTry()

        case Expression::Id::BreakId:
        case Expression::Id::SwitchId:
        case Expression::Id::BrOnExnId:
        case Expression::Id::CallId:
        case Expression::Id::CallIndirectId:
        case Expression::Id::LocalSetId:
        case Expression::Id::StoreId:
        case Expression::Id::ReturnId:
        case Expression::Id::GlobalSetId:
        case Expression::Id::HostId:
        case Expression::Id::UnreachableId:
          return curr; // always needed

        case Expression::Id::LoadId: {
          // it is ok to remove a load if the result is not used, and it has no
          // side effects (the load itself may trap, if we are not ignoring such
          // things)
          auto* load = curr->cast<Load>();
          if (!resultUsed && !EffectAnalyzer(getPassOptions(), features, curr)
                                .hasSideEffects()) {
            if (!typeMatters || load->ptr->type == type) {
              return load->ptr;
            }
          }
          return curr;
        }
        case Expression::Id::ConstId:
        case Expression::Id::LocalGetId:
        case Expression::Id::GlobalGetId: {
          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, as well as the node itself, as some unaries and
          // binaries have implicit traps
          if (auto* unary = curr->dynCast<Unary>()) {
            EffectAnalyzer tester(getPassOptions(), features);
            tester.visitUnary(unary);
            if (tester.hasSideEffects()) {
              return curr;
            }
            if (EffectAnalyzer(getPassOptions(), features, unary->value)
                  .hasSideEffects()) {
              curr = unary->value;
              continue;
            } else {
              return nullptr;
            }
          } else if (auto* binary = curr->dynCast<Binary>()) {
            EffectAnalyzer tester(getPassOptions(), features);
            tester.visitBinary(binary);
            if (tester.hasSideEffects()) {
              return curr;
            }
            if (EffectAnalyzer(getPassOptions(), features, binary->left)
                  .hasSideEffects()) {
              if (EffectAnalyzer(getPassOptions(), features, binary->right)
                    .hasSideEffects()) {
                return curr; // leave them
              } else {
                curr = binary->left;
                continue;
              }
            } else {
              if (EffectAnalyzer(getPassOptions(), features, 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(), features, select->ifTrue)
                  .hasSideEffects()) {
              if (EffectAnalyzer(getPassOptions(), features, select->ifFalse)
                    .hasSideEffects()) {
                return curr; // leave them
              } else {
                if (EffectAnalyzer(
                      getPassOptions(), features, select->condition)
                      .hasSideEffects()) {
                  return curr; // leave them
                } else {
                  curr = select->ifTrue;
                  continue;
                }
              }
            } else {
              if (EffectAnalyzer(getPassOptions(), features, select->ifFalse)
                    .hasSideEffects()) {
                if (EffectAnalyzer(
                      getPassOptions(), features, select->condition)
                      .hasSideEffects()) {
                  return curr; // leave them
                } else {
                  curr = select->ifFalse;
                  continue;
                }
              } else {
                if (EffectAnalyzer(
                      getPassOptions(), features, select->condition)
                      .hasSideEffects()) {
                  curr = select->condition;
                  continue;
                } else {
                  return nullptr;
                }
              }
            }
          }
        }

        default:
          return curr; // assume needed
      }
    }
  }

  void visitBlock(Block* curr) {
    // compress out nops and other dead code
    int skip = 0;
    auto& list = curr->list;
    size_t size = list.size();
    for (size_t z = 0; z < size; z++) {
      auto* child = list[z];
      // The last element may be used.
      bool used =
        z == size - 1 && curr->type.isConcrete() &&
        ExpressionAnalyzer::isResultUsed(expressionStack, getFunction());
      auto* optimized = optimize(child, used, true);
      if (!optimized) {
        if (child->type.isConcrete()) {
          // We can't just skip a final concrete element, even if it isn't used.
          // Instead, replace it with something that's easy to optimize out (for
          // example, code-folding can merge out identical zeros at the end of
          // if arms).
          optimized = LiteralUtils::makeZero(child->type, *getModule());
        } else if (child->type == Type::unreachable) {
          // Don't try to optimize out an unreachable child (dce can do that
          // properly).
          optimized = child;
        }
      }
      if (!optimized) {
        typeUpdater.noteRecursiveRemoval(child);
        skip++;
      } else {
        if (optimized != child) {
          typeUpdater.noteReplacement(child, optimized);
          list[z] = optimized;
        }
        if (skip > 0) {
          list[z - skip] = list[z];
          list[z] = nullptr;
        }
        // if this is unreachable, the rest is dead code
        if (list[z - skip]->type == Type::unreachable && z < size - 1) {
          for (Index i = z - skip + 1; i < list.size(); i++) {
            auto* remove = list[i];
            if (remove) {
              typeUpdater.noteRecursiveRemoval(remove);
            }
          }
          list.resize(z - skip + 1);
          typeUpdater.maybeUpdateTypeToUnreachable(curr);
          skip = 0; // nothing more to do on the list
          break;
        }
      }
    }
    if (skip > 0) {
      list.resize(size - skip);
      typeUpdater.maybeUpdateTypeToUnreachable(curr);
    }
    // the block may now be a trivial one that we can get rid of and just leave
    // its contents
    replaceCurrent(BlockUtils::simplifyToContents(curr, this));
  }

  void visitIf(If* curr) {
    // if the condition is a constant, just apply it
    // we can just return the ifTrue or ifFalse.
    if (auto* value = curr->condition->dynCast<Const>()) {
      Expression* child;
      if (value->value.getInteger()) {
        child = curr->ifTrue;
        if (curr->ifFalse) {
          typeUpdater.noteRecursiveRemoval(curr->ifFalse);
        }
      } else {
        if (curr->ifFalse) {
          child = curr->ifFalse;
          typeUpdater.noteRecursiveRemoval(curr->ifTrue);
        } else {
          typeUpdater.noteRecursiveRemoval(curr);
          ExpressionManipulator::nop(curr);
          return;
        }
      }
      replaceCurrent(child);
      return;
    }
    // if the condition is unreachable, just return it
    if (curr->condition->type == Type::unreachable) {
      typeUpdater.noteRecursiveRemoval(curr->ifTrue);
      if (curr->ifFalse) {
        typeUpdater.noteRecursiveRemoval(curr->ifFalse);
      }
      replaceCurrent(curr->condition);
      return;
    }
    // from here on, we can assume the condition executed
    if (curr->ifFalse) {
      if (curr->ifFalse->is<Nop>()) {
        curr->ifFalse = nullptr;
      } else if (curr->ifTrue->is<Nop>()) {
        curr->ifTrue = curr->ifFalse;
        curr->ifFalse = nullptr;
        curr->condition =
          Builder(*getModule()).makeUnary(EqZInt32, curr->condition);
      } else if (curr->ifTrue->is<Drop>() && curr->ifFalse->is<Drop>()) {
        // instead of dropping both sides, drop the if, if they are the same
        // type
        auto* left = curr->ifTrue->cast<Drop>()->value;
        auto* right = curr->ifFalse->cast<Drop>()->value;
        if (left->type == right->type) {
          curr->ifTrue = left;
          curr->ifFalse = right;
          curr->finalize();
          replaceCurrent(Builder(*getModule()).makeDrop(curr));
        }
      }
    } else {
      // no else
      if (curr->ifTrue->is<Nop>()) {
        // no nothing
        replaceCurrent(Builder(*getModule()).makeDrop(curr->condition));
      }
    }
  }

  void visitLoop(Loop* curr) {
    if (curr->body->is<Nop>()) {
      ExpressionManipulator::nop(curr);
    }
  }

  void visitDrop(Drop* curr) {
    // optimize the dropped value, maybe leaving nothing
    curr->value = optimize(curr->value, false, false);
    if (curr->value == nullptr) {
      ExpressionManipulator::nop(curr);
      return;
    }
    // a drop of a tee is a set
    if (auto* set = curr->value->dynCast<LocalSet>()) {
      assert(set->isTee());
      set->makeSet();
      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();
      // note that the last element may be concrete but not the block, if the
      // block has an unreachable element in the middle, making the block
      // unreachable despite later elements and in particular the last
      if (last->type.isConcrete() && block->type == last->type) {
        last = optimize(last, false, false);
        if (!last) {
          // we may be able to remove this, if there are no brs
          bool canPop = true;
          if (block->name.is()) {
            BranchUtils::BranchSeeker seeker(block->name);
            Expression* temp = block;
            seeker.walk(temp);
            if (seeker.found && seeker.valueType != Type::none) {
              canPop = false;
            }
          }
          if (canPop) {
            block->list.back() = last;
            block->list.pop_back();
            block->type = 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 && iff->type.isConcrete()) {
      // reuse the drop in both cases
      if (iff->ifTrue->type == Type::unreachable &&
          iff->ifFalse->type.isConcrete()) {
        curr->value = iff->ifFalse;
        iff->ifFalse = curr;
        iff->type = Type::none;
        replaceCurrent(iff);
      } else if (iff->ifFalse->type == Type::unreachable &&
                 iff->ifTrue->type.isConcrete()) {
        curr->value = iff->ifTrue;
        iff->ifTrue = curr;
        iff->type = Type::none;
        replaceCurrent(iff);
      }
    }
  }

  void visitTry(Try* curr) {
    // If try's body does not throw, the whole try-catch can be replaced with
    // the try's body.
    if (!EffectAnalyzer(getPassOptions(), getModule()->features, curr->body)
           .throws) {
      replaceCurrent(curr->body);
    }
  }

  void visitFunction(Function* curr) {
    auto* optimized =
      optimize(curr->body, curr->sig.results != Type::none, true);
    if (optimized) {
      curr->body = optimized;
    } else {
      ExpressionManipulator::nop(curr->body);
    }
    if (curr->sig.results == Type::none &&
        !EffectAnalyzer(getPassOptions(), getModule()->features, curr->body)
           .hasSideEffects()) {
      ExpressionManipulator::nop(curr->body);
    }
  }
};

Pass* createVacuumPass() { return new Vacuum(); }

} // namespace wasm
