#ifndef LLVM_TRANSFORMS_LOOPCHAINOUTLINEUTILS_H
#define LLVM_TRANSFORMS_LOOPCHAINOUTLINEUTILS_H



#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
namespace llvm {

class LoopChainOutlineUtils{
  public:
     /**
  * @brief Creates a runtime guard to conditionally execute one of two function variants
  *
  * This function transforms a call instruction into a conditional execution pattern 
  * that chooses between two function implementations at runtime:
  * - The if-branch calls the original function (F)
  * - The else-branch calls the specialized/cloned function (FCloned)
  *
  * The condition is determined by an LLVM intrinsic (specified by IntrinsicID).
  * If the function returns a value, a PHI node is created to properly handle
  * results from either execution path.
  * 
  * This transformation enables runtime decisions about which implementation
  * to use, especially for loop chain specialized code paths.
  *
  * @param F The original outlined function
  * @param FCloned The specialized clone of the outlined function
  * @param CI The call instruction to be guarded
  * @param DT The dominator tree for CFG updates
  * @param PDT The post-dominator tree for CFG updates
  * @param LI Loop information for the function
  * @param IntrinsicID The intrinsic ID used as the condition
  * @param BBName Optional name prefix for created basic blocks
  * @return Instruction* The guard instruction created by this transformation
  */
  static Instruction* conditionalFunctionExecutor(
    Function *F, Function *FCloned, Instruction *CI,
    DominatorTree &DT, PostDominatorTree &PDT, LoopInfo &LI, Intrinsic::ID IntrsicID,
    const Twine &BBName = "");

  /**  
  * @brief Replaces all function call instructions within a function with calls to 
  * suffixed versions of the original callees.
  *
  * @param F The function in which to replace call instructions
  * @param Suffix The string suffix to append to callee function names
  * @param FnAttribute The attribute to add to the new function calls
  *
  * This function locates all call instructions within the given function F,
  * and transforms them to call versions of their original callees with the
  * provided suffix appended to the name. Additionally, the specified function
  * attribute is added to these transformed calls.
  */
  static void replaceAllFunctionCallsInFunction(Function *F,
                                                const std::string &Suffix,
                                                const std::string &FnAttribute);

  /** \brief Preserves a function from being deleted by optimizations.
  *
  * This function adds the specified function to the "llvm.used" global array,
  * which prevents it from being eliminated during dead code elimination or
  * other optimization passes. It ensures that the function remains in the
  * final output even if it appears to be unused.
  *
  * \param F The function to preserve. If this is nullptr, the function returns
  *          without making any changes.
  */
  static void preserveFunction(Function *F);

  /// Remove the given function from the llvm.used global variable.
  /// This allows the function to be removed during optimization passes if it is
  /// no longer needed.
  ///
  /// \param F The function to be removed.
  static void removeFunctionsFromUsed(std::vector<Function *> FuncToDelete);


  static std::vector<BasicBlock *>
  orderBlocks(Function &F, LoopInfo &LI,
                                  PostDominatorTree &PDT,
                                  DominatorTree &DT);
                                  
  /**
  * @brief Reorders the basic blocks of a function to match a specified order
  *
  * This function rearranges the basic blocks within a function according to the order
  * provided in the OrderedBBs vector. It validates that the vector contains
  * exactly the same blocks as the function before performing the reordering,
  * ensuring safety of the transformation.
  *
  * The reordering is done by moving each basic block to the end of the function's
  * basic block list in the specified order, maintaining all internal references
  * without creating new blocks or copying content.
  *
  * @param F The function whose basic blocks should be reordered
  * @param OrderedBBs Vector of BasicBlocks in the desired order
  * @return true if reordering was successful, false otherwise
  */
  static bool reorderFunctionBlocks(Function &F, 
                                    const std::vector<BasicBlock*> &OrderedBBs);

};

} // namespace llvm
#endif // LLVM_TRANSFORMS_LOOPCHAINOUTLINE_H