//===- ABIRewriteContext.h - Dialect-specific ABI rewriting -----*- C++ -*-===//
//
// 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 defines ABIRewriteContext, the abstract interface for dialect-
// specific ABI lowering rewrites.  Each MLIR dialect that wants ABI lowering
// (CIR, FIR, etc.) provides a concrete subclass.
//
// ABIRewriteContext consumes ABI classification results and drives the
// creation of lowered function signatures, argument coercions, and call
// site rewrites using dialect-specific operations.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_ABI_ABIREWRITECONTEXT_H
#define MLIR_ABI_ABIREWRITECONTEXT_H

#include "mlir/IR/Builders.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/Types.h"
#include "mlir/IR/Value.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "llvm/Support/Alignment.h"

namespace mlir {
namespace abi {

/// Classification of how a single argument or return value should be
/// passed at the ABI level.
///
/// This is a dialect-agnostic representation.  It mirrors the kinds
/// found in the LLVM ABI library and in CIR's ABIArgInfo, but does
/// not depend on either.
enum class ArgKind : uint8_t {
  /// Pass directly in registers, possibly coerced to a different type.
  Direct,

  /// Like Direct, but with a sign/zero extension attribute.
  Extend,

  /// Pass indirectly via a pointer (sret for returns, byval for args).
  Indirect,

  /// Ignore (void return, empty struct).
  Ignore,

  /// Expand an aggregate into its constituent scalar fields.
  Expand,
};

/// Describes how a single argument or return value is passed after ABI
/// lowering.
struct ArgClassification {
  ArgKind kind = ArgKind::Direct;

  /// The ABI-coerced type, if different from the original.  Null means
  /// use the original type.
  Type coercedType = nullptr;

  /// For Indirect: alignment of the pointed-to object.
  llvm::Align indirectAlign = llvm::Align(1);

  /// For Extend: whether to sign-extend (true) or zero-extend (false).
  bool signExtend = false;

  /// For Direct: whether a struct coercion can be flattened into
  /// individual register-width arguments.
  bool canFlatten = true;

  /// For Indirect: whether the callee gets ownership (byval).
  bool byVal = false;

  static ArgClassification getDirect(Type coerced = nullptr) {
    ArgClassification c;
    c.kind = ArgKind::Direct;
    c.coercedType = coerced;
    return c;
  }

  static ArgClassification getIgnore() {
    ArgClassification c;
    c.kind = ArgKind::Ignore;
    return c;
  }

  static ArgClassification getIndirect(llvm::Align align, bool byVal = true) {
    ArgClassification c;
    c.kind = ArgKind::Indirect;
    c.indirectAlign = align;
    c.byVal = byVal;
    return c;
  }

  static ArgClassification getExtend(Type coerced, bool signExt) {
    ArgClassification c;
    c.kind = ArgKind::Extend;
    c.coercedType = coerced;
    c.signExtend = signExt;
    return c;
  }
};

/// Holds the full ABI classification for a function: return type and
/// all arguments.
struct FunctionClassification {
  ArgClassification returnInfo;
  SmallVector<ArgClassification> argInfos;
};

/// ABIRewriteContext is the abstract interface that each dialect
/// implements to perform ABI-specific rewrites on its operations.
///
/// The pass orchestrator calls these methods after ABI classification
/// to rewrite function definitions and call sites.
class ABIRewriteContext {
public:
  virtual ~ABIRewriteContext() = default;

  /// Rewrite a function definition to use ABI-lowered types.
  ///
  /// This creates a new function with the lowered signature, rewrites
  /// the function body to adapt between the ABI types and the
  /// original high-level types, and replaces the original function.
  ///
  /// \param funcOp  The function to rewrite (via FunctionOpInterface).
  /// \param fc      The ABI classification for this function.
  /// \param builder  The OpBuilder to use for modifications.
  /// \returns success() if the function was rewritten.
  virtual LogicalResult
  rewriteFunctionDefinition(FunctionOpInterface funcOp,
                            const FunctionClassification &fc,
                            OpBuilder &builder) = 0;

  /// Rewrite a call operation to match the callee's ABI-lowered
  /// signature.
  ///
  /// This coerces arguments, handles indirect returns (sret), and
  /// adapts the call result back to the original high-level type.
  ///
  /// \param callOp  The call operation to rewrite.
  /// \param fc      The ABI classification for the callee.
  /// \param builder  The OpBuilder to use for modifications.
  /// \returns success() if the call was rewritten.
  virtual LogicalResult rewriteCallSite(Operation *callOp,
                                        const FunctionClassification &fc,
                                        OpBuilder &builder) = 0;

  /// Return the dialect namespace this context handles (e.g. "cir").
  virtual StringRef getDialectNamespace() const = 0;
};

} // namespace abi
} // namespace mlir

#endif // MLIR_ABI_ABIREWRITECONTEXT_H
