llvm/polly/include/polly/Support/ScopHelper.h

//===------ Support/ScopHelper.h -- Some Helper Functions for Scop. -------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Small functions that help with LLVM-IR.
//
//===----------------------------------------------------------------------===//

#ifndef POLLY_SUPPORT_IRHELPER_H
#define POLLY_SUPPORT_IRHELPER_H

#include "llvm/ADT/SetVector.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/ValueHandle.h"
#include "isl/isl-noexceptions.h"
#include <optional>

namespace llvm {
class LoopInfo;
class Loop;
class ScalarEvolution;
class SCEV;
class Region;
class Pass;
class DominatorTree;
class RegionInfo;
class RegionNode;
} // namespace llvm

namespace polly {
class Scop;
class ScopStmt;

/// Same as llvm/Analysis/ScalarEvolutionExpressions.h
LoopToScevMapT;

/// Enumeration of assumptions Polly can take.
enum AssumptionKind {};

/// Enum to distinguish between assumptions and restrictions.
enum AssumptionSign {};

/// Helper struct to remember assumptions.
struct Assumption {};

RecordedAssumptionsTy;

/// Record an assumption for later addition to the assumed context.
///
/// This function will add the assumption to the RecordedAssumptions. This
/// collection will be added (@see addAssumption) to the assumed context once
/// all paramaters are known and the context is fully built.
///
/// @param RecordedAssumption container which keeps all recorded assumptions.
/// @param Kind The assumption kind describing the underlying cause.
/// @param Set  The relations between parameters that are assumed to hold.
/// @param Loc  The location in the source that caused this assumption.
/// @param Sign Enum to indicate if the assumptions in @p Set are positive
///             (needed/assumptions) or negative (invalid/restrictions).
/// @param BB   The block in which this assumption was taken. If it is
///             set, the domain of that block will be used to simplify the
///             actual assumption in @p Set once it is added. This is useful
///             if the assumption was created prior to the domain.
/// @param RTC  Does the assumption require a runtime check?
void recordAssumption(RecordedAssumptionsTy *RecordedAssumptions,
                      AssumptionKind Kind, isl::set Set, llvm::DebugLoc Loc,
                      AssumptionSign Sign, llvm::BasicBlock *BB = nullptr,
                      bool RTC = true);

/// Type to remap values.
ValueMapT;

/// Type for a set of invariant loads.
InvariantLoadsSetTy;

/// Set type for parameters.
ParameterSetTy;

/// Set of loops (used to remember loops in non-affine subregions).
BoxedLoopsSetTy;

/// Utility proxy to wrap the common members of LoadInst and StoreInst.
///
/// This works like the LLVM utility class CallSite, ie. it forwards all calls
/// to either a LoadInst, StoreInst, MemIntrinsic or MemTransferInst.
/// It is similar to LLVM's utility classes IntrinsicInst, MemIntrinsic,
/// MemTransferInst, etc. in that it offers a common interface, but does not act
/// as a fake base class.
/// It is similar to StringRef and ArrayRef in that it holds a pointer to the
/// referenced object and should be passed by-value as it is small enough.
///
/// This proxy can either represent a LoadInst instance, a StoreInst instance,
/// a MemIntrinsic instance (memset, memmove, memcpy), a CallInst instance or a
/// nullptr (only creatable using the default constructor); never an Instruction
/// that is neither of the above mentioned. When representing a nullptr, only
/// the following methods are defined:
/// isNull(), isInstruction(), isLoad(), isStore(), ..., isMemTransferInst(),
/// operator bool(), operator!()
///
/// The functions isa, cast, cast_or_null, dyn_cast are modeled te resemble
/// those from llvm/Support/Casting.h. Partial template function specialization
/// is currently not supported in C++ such that those cannot be used directly.
/// (llvm::isa could, but then llvm:cast etc. would not have the expected
/// behavior)
class MemAccInst final {};
} // namespace polly

namespace llvm {
/// Specialize simplify_type for MemAccInst to enable dyn_cast and cast
///        from a MemAccInst object.
template <> struct simplify_type<polly::MemAccInst> {};
} // namespace llvm

namespace polly {

/// Simplify the region to have a single unconditional entry edge and a
/// single exit edge.
///
/// Although this function allows DT and RI to be null, regions only work
/// properly if the DominatorTree (for Region::contains) and RegionInfo are kept
/// up-to-date.
///
/// @param R  The region to be simplified
/// @param DT DominatorTree to be updated.
/// @param LI LoopInfo to be updated.
/// @param RI RegionInfo to be updated.
void simplifyRegion(llvm::Region *R, llvm::DominatorTree *DT,
                    llvm::LoopInfo *LI, llvm::RegionInfo *RI);

/// Split the entry block of a function to store the newly inserted
///        allocations outside of all Scops.
///
/// @param EntryBlock The entry block of the current function.
/// @param P          The pass that currently running.
///
void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock, llvm::Pass *P);

/// Split the entry block of a function to store the newly inserted
///        allocations outside of all Scops.
///
/// @param DT DominatorTree to be updated.
/// @param LI LoopInfo to be updated.
/// @param RI RegionInfo to be updated.
void splitEntryBlockForAlloca(llvm::BasicBlock *EntryBlock,
                              llvm::DominatorTree *DT, llvm::LoopInfo *LI,
                              llvm::RegionInfo *RI);

/// Wrapper for SCEVExpander extended to all Polly features.
///
/// This wrapper will internally call the SCEVExpander but also makes sure that
/// all additional features not represented in SCEV (e.g., SDiv/SRem are not
/// black boxes but can be part of the function) will be expanded correctly.
///
/// The parameters are the same as for the creation of a SCEVExpander as well
/// as the call to SCEVExpander::expandCodeFor:
///
/// @param S     The current Scop.
/// @param SE    The Scalar Evolution pass used by @p S.
/// @param GenFn The function to generate code in. Can be the same as @p SE.
/// @param GenSE The Scalar Evolution pass for @p GenFn.
/// @param DL    The module data layout.
/// @param Name  The suffix added to the new instruction names.
/// @param E     The expression for which code is actually generated.
/// @param Ty    The type of the resulting code.
/// @param IP    The insertion point for the new code.
/// @param VMap  A remapping of values used in @p E.
/// @param LoopMap A remapping of loops used in @p E.
/// @param RTCBB The last block of the RTC. Used to insert loop-invariant
///              instructions in rare cases.
llvm::Value *expandCodeFor(Scop &S, llvm::ScalarEvolution &SE,
                           llvm::Function *GenFn, llvm::ScalarEvolution &GenSE,
                           const llvm::DataLayout &DL, const char *Name,
                           const llvm::SCEV *E, llvm::Type *Ty,
                           llvm::Instruction *IP, ValueMapT *VMap,
                           LoopToScevMapT *LoopMap, llvm::BasicBlock *RTCBB);

/// Return the condition for the terminator @p TI.
///
/// For unconditional branches the "i1 true" condition will be returned.
///
/// @param TI The terminator to get the condition from.
///
/// @return The condition of @p TI and nullptr if none could be extracted.
llvm::Value *getConditionFromTerminator(llvm::Instruction *TI);

/// Get the smallest loop that contains @p S but is not in @p S.
llvm::Loop *getLoopSurroundingScop(Scop &S, llvm::LoopInfo &LI);

/// Get the number of blocks in @p L.
///
/// The number of blocks in a loop are the number of basic blocks actually
/// belonging to the loop, as well as all single basic blocks that the loop
/// exits to and which terminate in an unreachable instruction. We do not
/// allow such basic blocks in the exit of a scop, hence they belong to the
/// scop and represent run-time conditions which we want to model and
/// subsequently speculate away.
///
/// @see getRegionNodeLoop for additional details.
unsigned getNumBlocksInLoop(llvm::Loop *L);

/// Get the number of blocks in @p RN.
unsigned getNumBlocksInRegionNode(llvm::RegionNode *RN);

/// Return the smallest loop surrounding @p RN.
llvm::Loop *getRegionNodeLoop(llvm::RegionNode *RN, llvm::LoopInfo &LI);

/// Check if @p LInst can be hoisted in @p R.
///
/// @param LInst The load to check.
/// @param R     The analyzed region.
/// @param LI    The loop info.
/// @param SE    The scalar evolution analysis.
/// @param DT    The dominator tree of the function.
/// @param KnownInvariantLoads The invariant load set.
///
/// @return True if @p LInst can be hoisted in @p R.
bool isHoistableLoad(llvm::LoadInst *LInst, llvm::Region &R, llvm::LoopInfo &LI,
                     llvm::ScalarEvolution &SE, const llvm::DominatorTree &DT,
                     const InvariantLoadsSetTy &KnownInvariantLoads);

/// Return true iff @p V is an intrinsic that we ignore during code
///        generation.
bool isIgnoredIntrinsic(const llvm::Value *V);

/// Check whether a value an be synthesized by the code generator.
///
/// Some value will be recalculated only from information that is code generated
/// from the polyhedral representation. For such instructions we do not need to
/// ensure that their operands are available during code generation.
///
/// @param V The value to check.
/// @param S The current SCoP.
/// @param SE The scalar evolution database.
/// @param Scope Location where the value would by synthesized.
/// @return If the instruction I can be regenerated from its
///         scalar evolution representation, return true,
///         otherwise return false.
bool canSynthesize(const llvm::Value *V, const Scop &S,
                   llvm::ScalarEvolution *SE, llvm::Loop *Scope);

/// Return the block in which a value is used.
///
/// For normal instructions, this is the instruction's parent block. For PHI
/// nodes, this is the incoming block of that use, because this is where the
/// operand must be defined (i.e. its definition dominates this block).
/// Non-instructions do not use operands at a specific point such that in this
/// case this function returns nullptr.
llvm::BasicBlock *getUseBlock(const llvm::Use &U);

// If the loop is nonaffine/boxed, return the first non-boxed surrounding loop
// for Polly. If the loop is affine, return the loop itself.
//
// @param L             Pointer to the Loop object to analyze.
// @param LI            Reference to the LoopInfo.
// @param BoxedLoops    Set of Boxed Loops we get from the SCoP.
llvm::Loop *getFirstNonBoxedLoopFor(llvm::Loop *L, llvm::LoopInfo &LI,
                                    const BoxedLoopsSetTy &BoxedLoops);

// If the Basic Block belongs to a loop that is nonaffine/boxed, return the
// first non-boxed surrounding loop for Polly. If the loop is affine, return
// the loop itself.
//
// @param BB            Pointer to the Basic Block to analyze.
// @param LI            Reference to the LoopInfo.
// @param BoxedLoops    Set of Boxed Loops we get from the SCoP.
llvm::Loop *getFirstNonBoxedLoopFor(llvm::BasicBlock *BB, llvm::LoopInfo &LI,
                                    const BoxedLoopsSetTy &BoxedLoops);

/// Is the given instruction a call to a debug function?
///
/// A debug function can be used to insert output in Polly-optimized code which
/// normally does not allow function calls with side-effects. For instance, a
/// printf can be inserted to check whether a value still has the expected value
/// after Polly generated code:
///
///     int sum = 0;
///     for (int i = 0; i < 16; i+=1) {
///       sum += i;
///       printf("The value of sum at i=%d is %d\n", sum, i);
///     }
bool isDebugCall(llvm::Instruction *Inst);

/// Does the statement contain a call to a debug function?
///
/// Such a statement must not be removed, even if has no side-effects.
bool hasDebugCall(ScopStmt *Stmt);

/// Find a property value in a LoopID.
///
/// Generally, a property MDNode has the format
///
///   !{ !"Name", value }
///
/// In which case the value is returned.
///
/// If the property is just
///
///   !{ !"Name" }
///
/// Then `nullptr` is set to mark the property is existing, but does not carry
/// any value. If the property does not exist, `std::nullopt` is returned.
std::optional<llvm::Metadata *> findMetadataOperand(llvm::MDNode *LoopMD,
                                                    llvm::StringRef Name);

/// Find a boolean property value in a LoopID. The value not being defined is
/// interpreted as a false value.
bool getBooleanLoopAttribute(llvm::MDNode *LoopID, llvm::StringRef Name);

/// Find an integers property value in a LoopID.
std::optional<int> getOptionalIntLoopAttribute(llvm::MDNode *LoopID,
                                               llvm::StringRef Name);

/// Does the loop's LoopID contain a 'llvm.loop.disable_heuristics' property?
///
/// This is equivalent to llvm::hasDisableAllTransformsHint(Loop*), but
/// including the LoopUtils.h header indirectly also declares llvm::MemoryAccess
/// which clashes with polly::MemoryAccess. Declaring this alias here avoid
/// having to include LoopUtils.h in other files.
bool hasDisableAllTransformsHint(llvm::Loop *L);
bool hasDisableAllTransformsHint(llvm::MDNode *LoopID);

/// Represent the attributes of a loop.
struct BandAttr {};

/// Get an isl::id representing a loop.
///
/// This takes the ownership of the BandAttr and will be free'd when the
/// returned isl::Id is free'd.
isl::id getIslLoopAttr(isl::ctx Ctx, BandAttr *Attr);

/// Create an isl::id that identifies an original loop.
///
/// Return nullptr if the loop does not need a BandAttr (i.e. has no
/// properties);
///
/// This creates a BandAttr which must be unique per loop and therefore this
/// must not be called multiple times on the same loop as their id would be
/// different.
isl::id createIslLoopAttr(isl::ctx Ctx, llvm::Loop *L);

/// Is @p Id representing a loop?
///
/// Such ids contain a polly::BandAttr as its user pointer.
bool isLoopAttr(const isl::id &Id);

/// Return the BandAttr of a loop's isl::id.
BandAttr *getLoopAttr(const isl::id &Id);

} // namespace polly
#endif