/*
 * Copyright 2020 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.
 */

#include "stack-utils.h"
#include "ir/iteration.h"
#include "ir/properties.h"

namespace wasm {

namespace StackUtils {

void removeNops(Block* block) {
  size_t newIndex = 0;
  for (size_t i = 0, size = block->list.size(); i < size; ++i) {
    if (!block->list[i]->is<Nop>()) {
      block->list[newIndex++] = block->list[i];
    }
  }
  block->list.resize(newIndex);
}

bool mayBeUnreachable(Expression* expr) {
  if (Properties::isControlFlowStructure(expr)) {
    return true;
  }
  switch (expr->_id) {
    case Expression::Id::BreakId:
      return expr->cast<Break>()->condition == nullptr;
    case Expression::Id::CallId:
      return expr->cast<Call>()->isReturn;
    case Expression::Id::CallIndirectId:
      return expr->cast<CallIndirect>()->isReturn;
    case Expression::Id::ReturnId:
    case Expression::Id::SwitchId:
    case Expression::Id::UnreachableId:
    case Expression::Id::ThrowId:
    case Expression::Id::RethrowId:
      return true;
    default:
      return false;
  }
}

} // namespace StackUtils

StackSignature::StackSignature(Expression* expr) {
  std::vector<Type> inputs;
  for (auto* child : ValueChildIterator(expr)) {
    assert(child->type.isConcrete());
    // Children might be tuple pops, so expand their types
    inputs.insert(inputs.end(), child->type.begin(), child->type.end());
  }
  params = Type(inputs);
  if (expr->type == Type::unreachable) {
    unreachable = true;
    results = Type::none;
  } else {
    unreachable = false;
    results = expr->type;
  }
}

bool StackSignature::composes(const StackSignature& next) const {
  auto checked = std::min(results.size(), next.params.size());
  return std::equal(results.end() - checked,
                    results.end(),
                    next.params.end() - checked,
                    [](const Type& produced, const Type& consumed) {
                      return Type::isSubType(produced, consumed);
                    });
}

StackSignature& StackSignature::operator+=(const StackSignature& next) {
  assert(composes(next));
  std::vector<Type> stack(results.begin(), results.end());
  size_t required = next.params.size();
  // Consume stack values according to next's parameters
  if (stack.size() >= required) {
    stack.resize(stack.size() - required);
  } else {
    if (!unreachable) {
      // Prepend the unsatisfied params of `next` to the current params
      size_t unsatisfied = required - stack.size();
      std::vector<Type> newParams(next.params.begin(),
                                  next.params.begin() + unsatisfied);
      newParams.insert(newParams.end(), params.begin(), params.end());
      params = Type(newParams);
    }
    stack.clear();
  }
  // Add stack values according to next's results
  if (next.unreachable) {
    results = next.results;
    unreachable = true;
  } else {
    stack.insert(stack.end(), next.results.begin(), next.results.end());
    results = Type(stack);
  }
  return *this;
}

StackSignature StackSignature::operator+(const StackSignature& next) const {
  StackSignature sig = *this;
  sig += next;
  return sig;
}

bool StackSignature::isSubType(StackSignature a, StackSignature b) {
  if (a.params.size() > b.params.size() ||
      a.results.size() > b.results.size()) {
    // `a` consumes or produces more values than `b` can provides or expects.
    return false;
  }
  if (b.unreachable && !a.unreachable) {
    // Non-polymorphic sequences cannot be typed as being polymorphic.
    return false;
  }
  bool paramSuffixMatches =
    std::equal(a.params.begin(),
               a.params.end(),
               b.params.end() - a.params.size(),
               [](const Type& consumed, const Type& provided) {
                 return Type::isSubType(provided, consumed);
               });
  if (!paramSuffixMatches) {
    return false;
  }
  bool resultSuffixMatches =
    std::equal(a.results.begin(),
               a.results.end(),
               b.results.end() - a.results.size(),
               [](const Type& produced, const Type& expected) {
                 return Type::isSubType(produced, expected);
               });
  if (!resultSuffixMatches) {
    return false;
  }
  if (a.unreachable) {
    // The unreachable can consume any additional provided params and produce
    // any additional expected results, so we are done.
    return true;
  }
  // Any additional provided params will pass through untouched, so they must be
  // compatible with the additional produced results.
  return std::equal(b.params.begin(),
                    b.params.end() - a.params.size(),
                    b.results.begin(),
                    b.results.end() - a.results.size(),
                    [](const Type& provided, const Type& expected) {
                      return Type::isSubType(provided, expected);
                    });
}

bool StackSignature::haveLeastUpperBound(StackSignature a, StackSignature b) {
  // If a signature is unreachable, the LUB could extend its params and results
  // arbitrarily. Otherwise, the LUB must extend its params and results
  // uniformly so that each additional param is a subtype of the corresponding
  // additional result.
  auto extensionCompatible = [](auto self, auto other) -> bool {
    if (self.unreachable) {
      return true;
    }
    // If no extension, then no problem.
    if (self.params.size() >= other.params.size() &&
        self.results.size() >= other.results.size()) {
      return true;
    }
    auto extSize = other.params.size() - self.params.size();
    if (extSize != other.results.size() - self.results.size()) {
      return false;
    }
    return std::equal(other.params.begin(),
                      other.params.begin() + extSize,
                      other.results.begin(),
                      other.results.begin() + extSize,
                      [](const Type& param, const Type& result) {
                        return Type::isSubType(param, result);
                      });
  };
  if (!extensionCompatible(a, b) || !extensionCompatible(b, a)) {
    return false;
  }

  auto valsCompatible = [](auto as, auto bs, auto compatible) -> bool {
    // Canonicalize so the as are shorter and any unshared prefix is on bs.
    if (bs.size() < as.size()) {
      std::swap(as, bs);
    }
    // Check that shared values after the unshared prefix have are compatible.
    size_t diff = bs.size() - as.size();
    for (size_t i = 0, shared = as.size(); i < shared; ++i) {
      if (!compatible(as[i], bs[i + diff])) {
        return false;
      }
    }
    return true;
  };

  bool paramsOk = valsCompatible(a.params, b.params, [](Type a, Type b) {
    assert(a == b && "TODO: calculate greatest lower bound to handle "
                     "contravariance correctly");
    return true;
  });
  bool resultsOk = valsCompatible(a.results, b.results, [](Type a, Type b) {
    return Type::getLeastUpperBound(a, b) != Type::none;
  });
  return paramsOk && resultsOk;
}

StackSignature StackSignature::getLeastUpperBound(StackSignature a,
                                                  StackSignature b) {
  assert(haveLeastUpperBound(a, b));

  auto combineVals = [](auto as, auto bs, auto combine) -> std::vector<Type> {
    // Canonicalize so the as are shorter and any unshared prefix is on bs.
    if (bs.size() < as.size()) {
      std::swap(as, bs);
    }
    // Combine shared values after the unshared prefix.
    size_t diff = bs.size() - as.size();
    std::vector<Type> vals(bs.begin(), bs.begin() + diff);
    for (size_t i = 0, shared = as.size(); i < shared; ++i) {
      vals.push_back(combine(as[i], bs[i + diff]));
    }
    return vals;
  };

  auto params = combineVals(a.params, b.params, [&](Type a, Type b) {
    assert(a == b && "TODO: calculate greatest lower bound to handle "
                     "contravariance correctly");
    return a;
  });

  auto results = combineVals(a.results, b.results, [&](Type a, Type b) {
    return Type::getLeastUpperBound(a, b);
  });

  return StackSignature{
    Type(params), Type(results), a.unreachable && b.unreachable};
}

StackFlow::StackFlow(Block* block) {
  // Encapsulates the logic for treating the block and its children
  // uniformly. The end of the block is treated as if it consumed values
  // corresponding to the its result type and produced no values, which is why
  // the block's result type is used as the params of its processed stack
  // signature.
  auto processBlock = [&block](auto process) {
    // TODO: Once we support block parameters, set up the stack by calling
    // `process` before iterating through the block.
    for (auto* expr : block->list) {
      process(expr, StackSignature(expr));
    }
    bool unreachable = block->type == Type::unreachable;
    Type params = unreachable ? Type::none : block->type;
    process(block, StackSignature(params, Type::none, unreachable));
  };

  // We need to make an initial pass through the block to figure out how many
  // values each unreachable instruction produces.
  std::unordered_map<Expression*, size_t> producedByUnreachable;
  {
    size_t stackSize = 0;
    size_t produced = 0;
    Expression* lastUnreachable = nullptr;
    processBlock([&](Expression* expr, const StackSignature sig) {
      // Consume params
      if (sig.params.size() > stackSize) {
        // We need more values than are available, so they must come from the
        // last unreachable.
        assert(lastUnreachable);
        produced += sig.params.size() - stackSize;
        stackSize = 0;
      } else {
        stackSize -= sig.params.size();
      }

      // Handle unreachable or produce results
      if (sig.unreachable) {
        if (lastUnreachable) {
          producedByUnreachable[lastUnreachable] = produced;
          produced = 0;
        }
        assert(produced == 0);
        lastUnreachable = expr;
        stackSize = 0;
      } else {
        stackSize += sig.results.size();
      }
    });

    // Finish record for final unreachable
    if (lastUnreachable) {
      producedByUnreachable[lastUnreachable] = produced;
    }
  }

  // Take another pass through the block, recording srcs and dests.
  std::vector<Location> values;
  Expression* lastUnreachable = nullptr;
  processBlock([&](Expression* expr, const StackSignature sig) {
    assert((sig.params.size() <= values.size() || lastUnreachable) &&
           "Block inputs not yet supported");

    // Unreachable instructions consume all available values
    size_t consumed = sig.unreachable
                        ? std::max(values.size(), sig.params.size())
                        : sig.params.size();

    // We previously calculated how many values unreachable instructions produce
    size_t produced =
      sig.unreachable ? producedByUnreachable[expr] : sig.results.size();

    srcs[expr] = std::vector<Location>(consumed);
    dests[expr] = std::vector<Location>(produced);

    // Figure out what kind of unreachable values we have
    assert(sig.params.size() <= consumed);
    size_t unreachableBeyondStack = 0;
    size_t unreachableFromStack = 0;
    if (consumed > values.size()) {
      assert(consumed == sig.params.size());
      unreachableBeyondStack = consumed - values.size();
    } else if (consumed > sig.params.size()) {
      assert(consumed == values.size());
      unreachableFromStack = consumed - sig.params.size();
    }

    // Consume values
    for (Index i = 0; i < consumed; ++i) {
      if (i < unreachableBeyondStack) {
        // This value comes from the polymorphic stack of the last unreachable
        // because the stack did not have enough values to satisfy this
        // instruction.
        assert(lastUnreachable);
        assert(producedByUnreachable[lastUnreachable] >=
               unreachableBeyondStack);
        Index destIndex =
          producedByUnreachable[lastUnreachable] - unreachableBeyondStack + i;
        Type type = sig.params[i];
        srcs[expr][i] = {lastUnreachable, destIndex, type, true};
        dests[lastUnreachable][destIndex] = {expr, i, type, false};
      } else {
        // A normal value from the value stack
        bool unreachable = i < unreachableFromStack;
        auto& src = values[values.size() + i - consumed];
        srcs[expr][i] = src;
        dests[src.expr][src.index] = {expr, i, src.type, unreachable};
      }
    }

    // Update available values
    if (unreachableBeyondStack) {
      producedByUnreachable[lastUnreachable] -= unreachableBeyondStack;
      values.resize(0);
    } else {
      values.resize(values.size() - consumed);
    }

    // Produce values
    for (Index i = 0; i < sig.results.size(); ++i) {
      values.push_back({expr, i, sig.results[i], false});
    }

    // Update the last unreachable instruction
    if (sig.unreachable) {
      assert(producedByUnreachable[lastUnreachable] == 0);
      lastUnreachable = expr;
    }
  });
}

StackSignature StackFlow::getSignature(Expression* expr) {
  auto exprSrcs = srcs.find(expr);
  auto exprDests = dests.find(expr);
  assert(exprSrcs != srcs.end() && exprDests != dests.end());
  std::vector<Type> params, results;
  for (auto& src : exprSrcs->second) {
    params.push_back(src.type);
  }
  for (auto& dest : exprDests->second) {
    results.push_back(dest.type);
  }
  bool unreachable = expr->type == Type::unreachable;
  return StackSignature(Type(params), Type(results), unreachable);
}

} // namespace wasm
