llvm/llvm/lib/Analysis/ConstantFolding.cpp

//===-- ConstantFolding.cpp - Fold instructions into constants ------------===//
//
// 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 routines for folding instructions into constants.
//
// Also, to supplement the basic IR ConstantExpr simplifications,
// this file defines some additional folding routines that can make use of
// DataLayout information. These functions cannot go in IR due to library
// dependency issues.
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/TargetFolder.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Analysis/VectorUtils.h"
#include "llvm/Config/config.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/ConstantFold.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsAArch64.h"
#include "llvm/IR/IntrinsicsAMDGPU.h"
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/IntrinsicsWebAssembly.h"
#include "llvm/IR/IntrinsicsX86.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/MathExtras.h"
#include <cassert>
#include <cerrno>
#include <cfenv>
#include <cmath>
#include <cstdint>

usingnamespacellvm;

namespace {

//===----------------------------------------------------------------------===//
// Constant Folding internal helper functions
//===----------------------------------------------------------------------===//

static Constant *foldConstVectorToAPInt(APInt &Result, Type *DestTy,
                                        Constant *C, Type *SrcEltTy,
                                        unsigned NumSrcElts,
                                        const DataLayout &DL) {}

/// Constant fold bitcast, symbolically evaluating it with DataLayout.
/// This always returns a non-null constant, but it may be a
/// ConstantExpr if unfoldable.
Constant *FoldBitCast(Constant *C, Type *DestTy, const DataLayout &DL) {}

} // end anonymous namespace

/// If this constant is a constant offset from a global, return the global and
/// the constant. Because of constantexprs, this function is recursive.
bool llvm::IsConstantOffsetFromGlobal(Constant *C, GlobalValue *&GV,
                                      APInt &Offset, const DataLayout &DL,
                                      DSOLocalEquivalent **DSOEquiv) {}

Constant *llvm::ConstantFoldLoadThroughBitcast(Constant *C, Type *DestTy,
                                               const DataLayout &DL) {}

namespace {

/// Recursive helper to read bits out of global. C is the constant being copied
/// out of. ByteOffset is an offset into C. CurPtr is the pointer to copy
/// results into and BytesLeft is the number of bytes left in
/// the CurPtr buffer. DL is the DataLayout.
bool ReadDataFromGlobal(Constant *C, uint64_t ByteOffset, unsigned char *CurPtr,
                        unsigned BytesLeft, const DataLayout &DL) {}

Constant *FoldReinterpretLoadFromConst(Constant *C, Type *LoadTy,
                                       int64_t Offset, const DataLayout &DL) {}

} // anonymous namespace

// If GV is a constant with an initializer read its representation starting
// at Offset and return it as a constant array of unsigned char.  Otherwise
// return null.
Constant *llvm::ReadByteArrayFromGlobal(const GlobalVariable *GV,
                                        uint64_t Offset) {}

/// If this Offset points exactly to the start of an aggregate element, return
/// that element, otherwise return nullptr.
Constant *getConstantAtOffset(Constant *Base, APInt Offset,
                              const DataLayout &DL) {}

Constant *llvm::ConstantFoldLoadFromConst(Constant *C, Type *Ty,
                                          const APInt &Offset,
                                          const DataLayout &DL) {}

Constant *llvm::ConstantFoldLoadFromConst(Constant *C, Type *Ty,
                                          const DataLayout &DL) {}

Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
                                             APInt Offset,
                                             const DataLayout &DL) {}

Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
                                             const DataLayout &DL) {}

Constant *llvm::ConstantFoldLoadFromUniformValue(Constant *C, Type *Ty,
                                                 const DataLayout &DL) {}

namespace {

/// One of Op0/Op1 is a constant expression.
/// Attempt to symbolically evaluate the result of a binary operator merging
/// these together.  If target data info is available, it is provided as DL,
/// otherwise DL is null.
Constant *SymbolicallyEvaluateBinop(unsigned Opc, Constant *Op0, Constant *Op1,
                                    const DataLayout &DL) {}

/// If array indices are not pointer-sized integers, explicitly cast them so
/// that they aren't implicitly casted by the getelementptr.
Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops,
                         Type *ResultTy, GEPNoWrapFlags NW,
                         std::optional<ConstantRange> InRange,
                         const DataLayout &DL, const TargetLibraryInfo *TLI) {}

/// If we can symbolically evaluate the GEP constant expression, do so.
Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
                                  ArrayRef<Constant *> Ops,
                                  const DataLayout &DL,
                                  const TargetLibraryInfo *TLI) {}

/// Attempt to constant fold an instruction with the
/// specified opcode and operands.  If successful, the constant result is
/// returned, if not, null is returned.  Note that this function can fail when
/// attempting to fold instructions like loads and stores, which have no
/// constant expression form.
Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
                                       ArrayRef<Constant *> Ops,
                                       const DataLayout &DL,
                                       const TargetLibraryInfo *TLI,
                                       bool AllowNonDeterministic) {}

} // end anonymous namespace

//===----------------------------------------------------------------------===//
// Constant Folding public APIs
//===----------------------------------------------------------------------===//

namespace {

Constant *
ConstantFoldConstantImpl(const Constant *C, const DataLayout &DL,
                         const TargetLibraryInfo *TLI,
                         SmallDenseMap<Constant *, Constant *> &FoldedOps) {}

} // end anonymous namespace

Constant *llvm::ConstantFoldInstruction(Instruction *I, const DataLayout &DL,
                                        const TargetLibraryInfo *TLI) {}

Constant *llvm::ConstantFoldConstant(const Constant *C, const DataLayout &DL,
                                     const TargetLibraryInfo *TLI) {}

Constant *llvm::ConstantFoldInstOperands(Instruction *I,
                                         ArrayRef<Constant *> Ops,
                                         const DataLayout &DL,
                                         const TargetLibraryInfo *TLI,
                                         bool AllowNonDeterministic) {}

Constant *llvm::ConstantFoldCompareInstOperands(
    unsigned IntPredicate, Constant *Ops0, Constant *Ops1, const DataLayout &DL,
    const TargetLibraryInfo *TLI, const Instruction *I) {}

Constant *llvm::ConstantFoldUnaryOpOperand(unsigned Opcode, Constant *Op,
                                           const DataLayout &DL) {}

Constant *llvm::ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
                                             Constant *RHS,
                                             const DataLayout &DL) {}

Constant *llvm::FlushFPConstant(Constant *Operand, const Instruction *I,
                                bool IsOutput) {}

Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
                                           Constant *RHS, const DataLayout &DL,
                                           const Instruction *I,
                                           bool AllowNonDeterministic) {}

Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
                                        Type *DestTy, const DataLayout &DL) {}

Constant *llvm::ConstantFoldIntegerCast(Constant *C, Type *DestTy,
                                        bool IsSigned, const DataLayout &DL) {}

//===----------------------------------------------------------------------===//
//  Constant Folding for Calls
//

bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {}

namespace {

Constant *GetConstantFoldFPValue(double V, Type *Ty) {}

#if defined(HAS_IEE754_FLOAT128) && defined(HAS_LOGF128)
Constant *GetConstantFoldFPValue128(float128 V, Type *Ty) {
  if (Ty->isFP128Ty())
    return ConstantFP::get(Ty, V);
  llvm_unreachable("Can only constant fold fp128");
}
#endif

/// Clear the floating-point exception state.
inline void llvm_fenv_clearexcept() {}

/// Test if a floating-point exception was raised.
inline bool llvm_fenv_testexcept() {}

Constant *ConstantFoldFP(double (*NativeFP)(double), const APFloat &V,
                         Type *Ty) {}

#if defined(HAS_IEE754_FLOAT128) && defined(HAS_LOGF128)
Constant *ConstantFoldFP128(float128 (*NativeFP)(float128), const APFloat &V,
                            Type *Ty) {
  llvm_fenv_clearexcept();
  float128 Result = NativeFP(V.convertToQuad());
  if (llvm_fenv_testexcept()) {
    llvm_fenv_clearexcept();
    return nullptr;
  }

  return GetConstantFoldFPValue128(Result, Ty);
}
#endif

Constant *ConstantFoldBinaryFP(double (*NativeFP)(double, double),
                               const APFloat &V, const APFloat &W, Type *Ty) {}

Constant *constantFoldVectorReduce(Intrinsic::ID IID, Constant *Op) {}

/// Attempt to fold an SSE floating point to integer conversion of a constant
/// floating point. If roundTowardZero is false, the default IEEE rounding is
/// used (toward nearest, ties to even). This matches the behavior of the
/// non-truncating SSE instructions in the default rounding mode. The desired
/// integer type Ty is used to select how many bits are available for the
/// result. Returns null if the conversion cannot be performed, otherwise
/// returns the Constant value resulting from the conversion.
Constant *ConstantFoldSSEConvertToInt(const APFloat &Val, bool roundTowardZero,
                                      Type *Ty, bool IsSigned) {}

double getValueAsDouble(ConstantFP *Op) {}

static bool getConstIntOrUndef(Value *Op, const APInt *&C) {}

/// Checks if the given intrinsic call, which evaluates to constant, is allowed
/// to be folded.
///
/// \param CI Constrained intrinsic call.
/// \param St Exception flags raised during constant evaluation.
static bool mayFoldConstrained(ConstrainedFPIntrinsic *CI,
                               APFloat::opStatus St) {}

/// Returns the rounding mode that should be used for constant evaluation.
static RoundingMode
getEvaluationRoundingMode(const ConstrainedFPIntrinsic *CI) {}

/// Try to constant fold llvm.canonicalize for the given caller and value.
static Constant *constantFoldCanonicalize(const Type *Ty, const CallBase *CI,
                                          const APFloat &Src) {}

static Constant *ConstantFoldScalarCall1(StringRef Name,
                                         Intrinsic::ID IntrinsicID,
                                         Type *Ty,
                                         ArrayRef<Constant *> Operands,
                                         const TargetLibraryInfo *TLI,
                                         const CallBase *Call) {}

static Constant *evaluateCompare(const APFloat &Op1, const APFloat &Op2,
                                 const ConstrainedFPIntrinsic *Call) {}

static Constant *ConstantFoldLibCall2(StringRef Name, Type *Ty,
                                      ArrayRef<Constant *> Operands,
                                      const TargetLibraryInfo *TLI) {}

static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
                                            ArrayRef<Constant *> Operands,
                                            const CallBase *Call) {}

static APFloat ConstantFoldAMDGCNCubeIntrinsic(Intrinsic::ID IntrinsicID,
                                               const APFloat &S0,
                                               const APFloat &S1,
                                               const APFloat &S2) {}

static Constant *ConstantFoldAMDGCNPermIntrinsic(ArrayRef<Constant *> Operands,
                                                 Type *Ty) {}

static Constant *ConstantFoldScalarCall3(StringRef Name,
                                         Intrinsic::ID IntrinsicID,
                                         Type *Ty,
                                         ArrayRef<Constant *> Operands,
                                         const TargetLibraryInfo *TLI,
                                         const CallBase *Call) {}

static Constant *ConstantFoldScalarCall(StringRef Name,
                                        Intrinsic::ID IntrinsicID,
                                        Type *Ty,
                                        ArrayRef<Constant *> Operands,
                                        const TargetLibraryInfo *TLI,
                                        const CallBase *Call) {}

static Constant *ConstantFoldFixedVectorCall(
    StringRef Name, Intrinsic::ID IntrinsicID, FixedVectorType *FVTy,
    ArrayRef<Constant *> Operands, const DataLayout &DL,
    const TargetLibraryInfo *TLI, const CallBase *Call) {}

static Constant *ConstantFoldScalableVectorCall(
    StringRef Name, Intrinsic::ID IntrinsicID, ScalableVectorType *SVTy,
    ArrayRef<Constant *> Operands, const DataLayout &DL,
    const TargetLibraryInfo *TLI, const CallBase *Call) {}

static std::pair<Constant *, Constant *>
ConstantFoldScalarFrexpCall(Constant *Op, Type *IntTy) {}

/// Handle intrinsics that return tuples, which may be tuples of vectors.
static Constant *
ConstantFoldStructCall(StringRef Name, Intrinsic::ID IntrinsicID,
                       StructType *StTy, ArrayRef<Constant *> Operands,
                       const DataLayout &DL, const TargetLibraryInfo *TLI,
                       const CallBase *Call) {}

} // end anonymous namespace

Constant *llvm::ConstantFoldBinaryIntrinsic(Intrinsic::ID ID, Constant *LHS,
                                            Constant *RHS, Type *Ty,
                                            Instruction *FMFSource) {}

Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F,
                                 ArrayRef<Constant *> Operands,
                                 const TargetLibraryInfo *TLI,
                                 bool AllowNonDeterministic) {}

bool llvm::isMathLibCallNoop(const CallBase *Call,
                             const TargetLibraryInfo *TLI) {}

void TargetFolder::anchor() {}