#pragma once #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" #endif //====- TargetFolder.h - Constant folding helper ---------------*- 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 the TargetFolder class, a helper for IRBuilder. // It provides IRBuilder with a set of methods for creating constants with // target dependent folding, in addition to the same target-independent // folding that the ConstantFolder class provides. For general constant // creation and folding, use ConstantExpr and the routines in // llvm/Analysis/ConstantFolding.h. // //===----------------------------------------------------------------------===// #ifndef LLVM_ANALYSIS_TARGETFOLDER_H #define LLVM_ANALYSIS_TARGETFOLDER_H #include "llvm/ADT/ArrayRef.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/IR/Constants.h" #include "llvm/IR/IRBuilderFolder.h" #include "llvm/IR/Operator.h" namespace llvm { class Constant; class DataLayout; class Type; /// TargetFolder - Create constants with target dependent folding. class TargetFolder final : public IRBuilderFolder { const DataLayout &DL; /// Fold - Fold the constant using target specific information. Constant *Fold(Constant *C) const { return ConstantFoldConstant(C, DL); } virtual void anchor(); public: explicit TargetFolder(const DataLayout &DL) : DL(DL) {} //===--------------------------------------------------------------------===// // Value-based folders. // // Return an existing value or a constant if the operation can be simplified. // Otherwise return nullptr. //===--------------------------------------------------------------------===// Value *FoldBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS) const override { auto *LC = dyn_cast(LHS); auto *RC = dyn_cast(RHS); if (LC && RC) { if (ConstantExpr::isDesirableBinOp(Opc)) return Fold(ConstantExpr::get(Opc, LC, RC)); return ConstantFoldBinaryOpOperands(Opc, LC, RC, DL); } return nullptr; } Value *FoldExactBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, bool IsExact) const override { auto *LC = dyn_cast(LHS); auto *RC = dyn_cast(RHS); if (LC && RC) { if (ConstantExpr::isDesirableBinOp(Opc)) return Fold(ConstantExpr::get( Opc, LC, RC, IsExact ? PossiblyExactOperator::IsExact : 0)); return ConstantFoldBinaryOpOperands(Opc, LC, RC, DL); } return nullptr; } Value *FoldNoWrapBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, bool HasNUW, bool HasNSW) const override { auto *LC = dyn_cast(LHS); auto *RC = dyn_cast(RHS); if (LC && RC) { if (ConstantExpr::isDesirableBinOp(Opc)) { unsigned Flags = 0; if (HasNUW) Flags |= OverflowingBinaryOperator::NoUnsignedWrap; if (HasNSW) Flags |= OverflowingBinaryOperator::NoSignedWrap; return Fold(ConstantExpr::get(Opc, LC, RC, Flags)); } return ConstantFoldBinaryOpOperands(Opc, LC, RC, DL); } return nullptr; } Value *FoldBinOpFMF(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, FastMathFlags FMF) const override { return FoldBinOp(Opc, LHS, RHS); } Value *FoldICmp(CmpInst::Predicate P, Value *LHS, Value *RHS) const override { auto *LC = dyn_cast(LHS); auto *RC = dyn_cast(RHS); if (LC && RC) return Fold(ConstantExpr::getCompare(P, LC, RC)); return nullptr; } Value *FoldUnOpFMF(Instruction::UnaryOps Opc, Value *V, FastMathFlags FMF) const override { if (Constant *C = dyn_cast(V)) return ConstantFoldUnaryOpOperand(Opc, C, DL); return nullptr; } Value *FoldGEP(Type *Ty, Value *Ptr, ArrayRef IdxList, bool IsInBounds = false) const override { if (auto *PC = dyn_cast(Ptr)) { // Every index must be constant. if (any_of(IdxList, [](Value *V) { return !isa(V); })) return nullptr; if (IsInBounds) return Fold(ConstantExpr::getInBoundsGetElementPtr(Ty, PC, IdxList)); else return Fold(ConstantExpr::getGetElementPtr(Ty, PC, IdxList)); } return nullptr; } Value *FoldSelect(Value *C, Value *True, Value *False) const override { auto *CC = dyn_cast(C); auto *TC = dyn_cast(True); auto *FC = dyn_cast(False); if (CC && TC && FC) return Fold(ConstantExpr::getSelect(CC, TC, FC)); return nullptr; } Value *FoldExtractValue(Value *Agg, ArrayRef IdxList) const override { if (auto *CAgg = dyn_cast(Agg)) return ConstantFoldExtractValueInstruction(CAgg, IdxList); return nullptr; }; Value *FoldInsertValue(Value *Agg, Value *Val, ArrayRef IdxList) const override { auto *CAgg = dyn_cast(Agg); auto *CVal = dyn_cast(Val); if (CAgg && CVal) return ConstantFoldInsertValueInstruction(CAgg, CVal, IdxList); return nullptr; } Value *FoldExtractElement(Value *Vec, Value *Idx) const override { auto *CVec = dyn_cast(Vec); auto *CIdx = dyn_cast(Idx); if (CVec && CIdx) return Fold(ConstantExpr::getExtractElement(CVec, CIdx)); return nullptr; } Value *FoldInsertElement(Value *Vec, Value *NewElt, Value *Idx) const override { auto *CVec = dyn_cast(Vec); auto *CNewElt = dyn_cast(NewElt); auto *CIdx = dyn_cast(Idx); if (CVec && CNewElt && CIdx) return Fold(ConstantExpr::getInsertElement(CVec, CNewElt, CIdx)); return nullptr; } Value *FoldShuffleVector(Value *V1, Value *V2, ArrayRef Mask) const override { auto *C1 = dyn_cast(V1); auto *C2 = dyn_cast(V2); if (C1 && C2) return Fold(ConstantExpr::getShuffleVector(C1, C2, Mask)); return nullptr; } //===--------------------------------------------------------------------===// // Cast/Conversion Operators //===--------------------------------------------------------------------===// Constant *CreateCast(Instruction::CastOps Op, Constant *C, Type *DestTy) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getCast(Op, C, DestTy)); } Constant *CreateIntCast(Constant *C, Type *DestTy, bool isSigned) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getIntegerCast(C, DestTy, isSigned)); } Constant *CreatePointerCast(Constant *C, Type *DestTy) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getPointerCast(C, DestTy)); } Constant *CreateFPCast(Constant *C, Type *DestTy) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getFPCast(C, DestTy)); } Constant *CreateBitCast(Constant *C, Type *DestTy) const override { return CreateCast(Instruction::BitCast, C, DestTy); } Constant *CreateIntToPtr(Constant *C, Type *DestTy) const override { return CreateCast(Instruction::IntToPtr, C, DestTy); } Constant *CreatePtrToInt(Constant *C, Type *DestTy) const override { return CreateCast(Instruction::PtrToInt, C, DestTy); } Constant *CreateZExtOrBitCast(Constant *C, Type *DestTy) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getZExtOrBitCast(C, DestTy)); } Constant *CreateSExtOrBitCast(Constant *C, Type *DestTy) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getSExtOrBitCast(C, DestTy)); } Constant *CreateTruncOrBitCast(Constant *C, Type *DestTy) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getTruncOrBitCast(C, DestTy)); } Constant *CreatePointerBitCastOrAddrSpaceCast(Constant *C, Type *DestTy) const override { if (C->getType() == DestTy) return C; // avoid calling Fold return Fold(ConstantExpr::getPointerBitCastOrAddrSpaceCast(C, DestTy)); } //===--------------------------------------------------------------------===// // Compare Instructions //===--------------------------------------------------------------------===// Constant *CreateFCmp(CmpInst::Predicate P, Constant *LHS, Constant *RHS) const override { return Fold(ConstantExpr::getCompare(P, LHS, RHS)); } }; } #endif #ifdef __GNUC__ #pragma GCC diagnostic pop #endif