//===- OpenACCUtilsLoop.cpp - OpenACC Loop Utilities ----------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains utility functions for converting OpenACC loops to SCF.
//
//===----------------------------------------------------------------------===//

#include "mlir/Dialect/OpenACC/OpenACCUtilsLoop.h"

#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Arith/Utils/Utils.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/Dialect/SCF/Utils/Utils.h"
#include "mlir/IR/IRMapping.h"
#include "mlir/Transforms/RegionUtils.h"
#include "llvm/Support/ErrorHandling.h"

using namespace mlir;

namespace {

/// Calculate trip count for a loop: (ub - lb + step) / step
/// If inclusiveUpperbound is false, subtracts 1 from ub first.
static Value calculateTripCount(OpBuilder &b, Location loc, Value lb, Value ub,
                                Value step, bool inclusiveUpperbound) {
  Type type = b.getIndexType();

  // Convert original loop arguments to index type
  lb = getValueOrCreateCastToIndexLike(b, loc, type, lb);
  ub = getValueOrCreateCastToIndexLike(b, loc, type, ub);
  step = getValueOrCreateCastToIndexLike(b, loc, type, step);

  if (!inclusiveUpperbound) {
    Value one = arith::ConstantIndexOp::create(b, loc, 1);
    ub = b.createOrFold<arith::SubIOp>(loc, ub, one,
                                       arith::IntegerOverflowFlags::nsw);
  }

  Value sub = b.createOrFold<arith::SubIOp>(loc, ub, lb,
                                            arith::IntegerOverflowFlags::nsw);
  Value add = b.createOrFold<arith::AddIOp>(loc, sub, step,
                                            arith::IntegerOverflowFlags::nsw);
  return b.createOrFold<arith::DivSIOp>(loc, add, step);
}

/// Handle differing types between SCF (index) and ACC loops.
/// Creates casts from the new SCF IVs to the original ACC IV types and updates
/// the mapping. The newIVs should correspond 1:1 with the ACC loop's IVs.
static void mapACCLoopIVsToSCFIVs(acc::LoopOp accLoop, ValueRange newIVs,
                                  OpBuilder &b, IRMapping &mapping) {
  for (auto [origIV, newIV] :
       llvm::zip(accLoop.getBody().getArguments(), newIVs)) {
    Value replacementIV = getValueOrCreateCastToIndexLike(
        b, accLoop->getLoc(), origIV.getType(), newIV);
    mapping.map(origIV, replacementIV);
  }
}

/// Normalize IV uses after converting to normalized loop form.
/// For normalized loops (lb=0, step=1), we need to denormalize the IV:
/// original_iv = new_iv * orig_step + orig_lb
static void normalizeIVUses(OpBuilder &b, Location loc, Value iv, Value origLB,
                            Value origStep) {
  Type indexType = b.getIndexType();
  Value lb = getValueOrCreateCastToIndexLike(b, loc, indexType, origLB);
  Value step = getValueOrCreateCastToIndexLike(b, loc, indexType, origStep);

  // new_iv * step + lb
  Value scaled =
      arith::MulIOp::create(b, loc, iv, step, arith::IntegerOverflowFlags::nsw);
  Value denormalized = arith::AddIOp::create(b, loc, scaled, lb,
                                             arith::IntegerOverflowFlags::nsw);

  // Replace uses of iv with denormalized value, except for the ops that
  // compute the denormalized value itself (muli and addi)
  llvm::SmallPtrSet<Operation *, 2> exceptions;
  exceptions.insert(scaled.getDefiningOp());
  exceptions.insert(denormalized.getDefiningOp());
  iv.replaceAllUsesExcept(denormalized, exceptions);
}

/// Helper used by loop conversion: clone region and return insertion point
/// only.
static Block::iterator cloneACCRegionIntoForLoop(Region *src, Block *dest,
                                                 Block::iterator insertionPoint,
                                                 IRMapping &mapping,
                                                 RewriterBase &rewriter) {
  auto [replacements, ip] =
      acc::cloneACCRegionInto(src, dest, insertionPoint, mapping, ValueRange{});
  (void)replacements;
  return ip;
}

} // namespace

namespace mlir {
namespace acc {

std::pair<SmallVector<Value>, Block::iterator>
cloneACCRegionInto(Region *src, Block *dest, Block::iterator inlinePoint,
                   IRMapping &mapping, ValueRange resultsToReplace) {
  if (!src->hasOneBlock())
    llvm_unreachable("cloneACCRegionInto: multi-block region not supported "
                     "(requires scf.execute_region)");

  Region *insertRegion = dest->getParent();
  Block *postInsertBlock = dest->splitBlock(inlinePoint);
  src->cloneInto(insertRegion, postInsertBlock->getIterator(), mapping);

  SmallVector<Value> replacements;
  Block *lastNewBlock = &*std::prev(postInsertBlock->getIterator());

  Block::iterator ip;
  if (auto yieldOp = dyn_cast<acc::YieldOp>(lastNewBlock->getTerminator())) {
    for (auto [replacement, orig] :
         llvm::zip(yieldOp.getOperands(), resultsToReplace)) {
      replaceAllUsesInRegionWith(orig, replacement, *dest->getParent());
      replacements.push_back(replacement);
    }
    ip = std::prev(yieldOp->getIterator());
    yieldOp.erase();
  } else {
    auto terminatorOp =
        dyn_cast<acc::TerminatorOp>(lastNewBlock->getTerminator());
    if (!terminatorOp)
      llvm_unreachable(
          "cloneACCRegionInto: expected acc.yield or acc.terminator");
    ip = std::prev(terminatorOp->getIterator());
    terminatorOp.erase();
  }

  lastNewBlock->getOperations().splice(lastNewBlock->end(),
                                       postInsertBlock->getOperations());
  postInsertBlock->erase();

  Block *firstNewBlock = &*std::next(dest->getIterator());
  dest->getOperations().splice(dest->end(), firstNewBlock->getOperations());
  firstNewBlock->erase();
  return {replacements, ip};
}

/// Wrap a multi-block region with scf.execute_region.
scf::ExecuteRegionOp
wrapMultiBlockRegionWithSCFExecuteRegion(Region &region, IRMapping &mapping,
                                         Location loc, RewriterBase &rewriter) {
  SmallVector<Operation *> terminators;
  for (Block &block : region.getBlocks()) {
    if (block.empty())
      continue;
    Operation *term = block.getTerminator();
    if (term->getNumSuccessors() == 0)
      terminators.push_back(term);
  }
  SmallVector<Type> resultTypes;
  if (!terminators.empty())
    for (Value operand : terminators.front()->getOperands())
      resultTypes.push_back(operand.getType());

  auto exeRegionOp =
      scf::ExecuteRegionOp::create(rewriter, loc, TypeRange(resultTypes));

  rewriter.cloneRegionBefore(region, exeRegionOp.getRegion(),
                             exeRegionOp.getRegion().end(), mapping);

  for (Operation *term : terminators) {
    Operation *blockTerminator = mapping.lookup(term);
    assert(blockTerminator && "expected terminator to be in mapping");
    rewriter.setInsertionPoint(blockTerminator);
    (void)scf::YieldOp::create(rewriter, blockTerminator->getLoc(),
                               blockTerminator->getOperands());
    rewriter.eraseOp(blockTerminator);
  }

  return exeRegionOp;
}

scf::ForOp convertACCLoopToSCFFor(LoopOp loopOp, RewriterBase &rewriter,
                                  bool enableCollapse) {
  assert(!loopOp.getUnstructured() &&
         "use convertUnstructuredACCLoopToSCFExecuteRegion for unstructured "
         "loops");

  Location loc = loopOp->getLoc();

  IRMapping mapping;
  SmallVector<scf::ForOp> forOps;

  OpBuilder::InsertionGuard guard(rewriter);
  rewriter.setInsertionPoint(loopOp);

  // Normalize all loops: lb=0, step=1, ub=tripCount.
  // scf.for requires a positive step, but acc.loop may have arbitrary steps
  // (including negative). Normalizing unconditionally keeps this consistent
  // with convertACCLoopToSCFParallel and lets later passes fold constants.
  Value zero = arith::ConstantIndexOp::create(rewriter, loc, 0);
  Value one = arith::ConstantIndexOp::create(rewriter, loc, 1);

  SmallVector<Value> tripCounts;
  for (auto [idx, iv] : llvm::enumerate(loopOp.getBody().getArguments())) {
    bool inclusiveUpperbound = false;
    if (loopOp.getInclusiveUpperbound().has_value())
      inclusiveUpperbound =
          loopOp.getInclusiveUpperboundAttr().asArrayRef()[idx];

    Value tc = calculateTripCount(rewriter, loc, loopOp.getLowerbound()[idx],
                                  loopOp.getUpperbound()[idx],
                                  loopOp.getStep()[idx], inclusiveUpperbound);
    tripCounts.push_back(tc);
  }

  for (auto [idx, iv] : llvm::enumerate(loopOp.getBody().getArguments())) {
    // For nested loops, insert inside the previous loop's body
    if (idx > 0)
      rewriter.setInsertionPointToStart(forOps.back().getBody());

    scf::ForOp forOp =
        scf::ForOp::create(rewriter, loc, zero, tripCounts[idx], one);
    forOps.push_back(forOp);
    mapping.map(iv, forOp.getInductionVar());
  }

  // Set insertion point inside the innermost loop for IV casts and body cloning
  rewriter.setInsertionPointToStart(forOps.back().getBody());

  // Handle IV type conversion (index -> original type)
  SmallVector<Value> scfIVs;
  for (scf::ForOp forOp : forOps)
    scfIVs.push_back(forOp.getInductionVar());
  mapACCLoopIVsToSCFIVs(loopOp, scfIVs, rewriter, mapping);

  // Clone the loop body into the innermost scf.for
  cloneACCRegionIntoForLoop(&loopOp.getRegion(), forOps.back().getBody(),
                            rewriter.getInsertionPoint(), mapping, rewriter);

  // Denormalize IV uses: original_iv = normalized_iv * orig_step + orig_lb
  for (size_t idx = 0; idx < forOps.size(); ++idx) {
    Value iv = forOps[idx].getInductionVar();
    if (!iv.use_empty()) {
      rewriter.setInsertionPointToStart(forOps[idx].getBody());
      normalizeIVUses(rewriter, loc, iv, loopOp.getLowerbound()[idx],
                      loopOp.getStep()[idx]);
    }
  }

  // Optionally collapse nested loops
  if (enableCollapse && forOps.size() > 1) {
    unsigned numCollapsed = forOps.size();
    if (failed(coalesceLoops(rewriter, forOps)))
      loopOp.emitError("failed to collapse acc.loop");
    else
      setCollapseCountAttr(forOps.front(), numCollapsed);
  }

  return forOps.front();
}

scf::ParallelOp convertACCLoopToSCFParallel(LoopOp loopOp,
                                            RewriterBase &rewriter) {
  assert(!loopOp.getUnstructured() &&
         "use convertUnstructuredACCLoopToSCFExecuteRegion for unstructured "
         "loops");
  assert(
      rewriter.getInsertionBlock() &&
      !loopOp->isProperAncestor(rewriter.getInsertionBlock()->getParentOp()) &&
      "builder insertion point must not be inside the loop being converted");

  Location loc = loopOp->getLoc();

  SmallVector<Value> lowerBounds, upperBounds, steps;

  // Normalize all loops: lb=0, step=1, ub=tripCount
  Value lb = arith::ConstantIndexOp::create(rewriter, loc, 0);
  Value step = arith::ConstantIndexOp::create(rewriter, loc, 1);

  for (auto [idx, iv] : llvm::enumerate(loopOp.getBody().getArguments())) {
    bool inclusiveUpperbound = false;
    if (loopOp.getInclusiveUpperbound().has_value())
      inclusiveUpperbound = loopOp.getInclusiveUpperbound().value()[idx];

    Value ub = calculateTripCount(rewriter, loc, loopOp.getLowerbound()[idx],
                                  loopOp.getUpperbound()[idx],
                                  loopOp.getStep()[idx], inclusiveUpperbound);

    lowerBounds.push_back(lb);
    upperBounds.push_back(ub);
    steps.push_back(step);
  }

  auto parallelOp =
      scf::ParallelOp::create(rewriter, loc, lowerBounds, upperBounds, steps);

  // Create IV type conversions
  IRMapping mapping;
  rewriter.setInsertionPointToStart(parallelOp.getBody());
  mapACCLoopIVsToSCFIVs(loopOp, parallelOp.getInductionVars(), rewriter,
                        mapping);

  if (!loopOp.getRegion().hasOneBlock()) {
    auto exeRegion = wrapMultiBlockRegionWithSCFExecuteRegion(
        loopOp.getRegion(), mapping, loc, rewriter);
    if (!exeRegion) {
      rewriter.eraseOp(parallelOp);
      return nullptr;
    }
  } else {
    cloneACCRegionIntoForLoop(&loopOp.getRegion(), parallelOp.getBody(),
                              rewriter.getInsertionPoint(), mapping, rewriter);
  }

  // Denormalize IV uses
  rewriter.setInsertionPointToStart(parallelOp.getBody());
  for (auto [idx, iv] : llvm::enumerate(parallelOp.getBody()->getArguments()))
    if (!iv.use_empty())
      normalizeIVUses(rewriter, loc, iv, loopOp.getLowerbound()[idx],
                      loopOp.getStep()[idx]);

  setCollapseCountAttr(parallelOp, parallelOp.getNumLoops());
  return parallelOp;
}

scf::ExecuteRegionOp
convertUnstructuredACCLoopToSCFExecuteRegion(LoopOp loopOp,
                                             RewriterBase &rewriter) {
  assert(loopOp.getUnstructured() &&
         "use convertACCLoopToSCFFor for structured loops");
  assert(
      rewriter.getInsertionBlock() &&
      !loopOp->isProperAncestor(rewriter.getInsertionBlock()->getParentOp()) &&
      "builder insertion point must not be inside the loop being converted");

  IRMapping mapping;
  return wrapMultiBlockRegionWithSCFExecuteRegion(loopOp.getRegion(), mapping,
                                                  loopOp->getLoc(), rewriter);
}

void setCollapseCountAttr(Operation *op, uint64_t count) {
  op->setAttr(getCollapseCountAttrName(),
              IntegerAttr::get(IntegerType::get(op->getContext(), 64), count));
}

uint64_t getCollapseCount(Operation *op) {
  if (auto attr = op->getAttrOfType<IntegerAttr>(getCollapseCountAttrName()))
    return attr.getValue().getZExtValue();
  return 1;
}

} // namespace acc
} // namespace mlir
