1//====- TargetFolder.h - Constant folding helper ---------------*- C++ -*-====//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines the TargetFolder class, a helper for IRBuilder.
10// It provides IRBuilder with a set of methods for creating constants with
11// target dependent folding, in addition to the same target-independent
12// folding that the ConstantFolder class provides.  For general constant
13// creation and folding, use ConstantExpr and the routines in
14// llvm/Analysis/ConstantFolding.h.
15//
16//===----------------------------------------------------------------------===//
17
18#ifndef LLVM_ANALYSIS_TARGETFOLDER_H
19#define LLVM_ANALYSIS_TARGETFOLDER_H
20
21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/Analysis/ConstantFolding.h"
23#include "llvm/IR/Constants.h"
24#include "llvm/IR/IRBuilderFolder.h"
25#include "llvm/IR/Operator.h"
26
27namespace llvm {
28
29class Constant;
30class DataLayout;
31class Type;
32
33/// TargetFolder - Create constants with target dependent folding.
34class TargetFolder final : public IRBuilderFolder {
35  const DataLayout &DL;
36
37  /// Fold - Fold the constant using target specific information.
38  Constant *Fold(Constant *C) const {
39    return ConstantFoldConstant(C, DL);
40  }
41
42  virtual void anchor();
43
44public:
45  explicit TargetFolder(const DataLayout &DL) : DL(DL) {}
46
47  //===--------------------------------------------------------------------===//
48  // Value-based folders.
49  //
50  // Return an existing value or a constant if the operation can be simplified.
51  // Otherwise return nullptr.
52  //===--------------------------------------------------------------------===//
53
54  Value *FoldBinOp(Instruction::BinaryOps Opc, Value *LHS,
55                   Value *RHS) const override {
56    auto *LC = dyn_cast<Constant>(LHS);
57    auto *RC = dyn_cast<Constant>(RHS);
58    if (LC && RC) {
59      if (ConstantExpr::isDesirableBinOp(Opc))
60        return Fold(ConstantExpr::get(Opc, LC, RC));
61      return ConstantFoldBinaryOpOperands(Opc, LC, RC, DL);
62    }
63    return nullptr;
64  }
65
66  Value *FoldExactBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS,
67                        bool IsExact) const override {
68    auto *LC = dyn_cast<Constant>(LHS);
69    auto *RC = dyn_cast<Constant>(RHS);
70    if (LC && RC) {
71      if (ConstantExpr::isDesirableBinOp(Opc))
72        return Fold(ConstantExpr::get(
73            Opc, LC, RC, IsExact ? PossiblyExactOperator::IsExact : 0));
74      return ConstantFoldBinaryOpOperands(Opc, LC, RC, DL);
75    }
76    return nullptr;
77  }
78
79  Value *FoldNoWrapBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS,
80                         bool HasNUW, bool HasNSW) const override {
81    auto *LC = dyn_cast<Constant>(LHS);
82    auto *RC = dyn_cast<Constant>(RHS);
83    if (LC && RC) {
84      if (ConstantExpr::isDesirableBinOp(Opc)) {
85        unsigned Flags = 0;
86        if (HasNUW)
87          Flags |= OverflowingBinaryOperator::NoUnsignedWrap;
88        if (HasNSW)
89          Flags |= OverflowingBinaryOperator::NoSignedWrap;
90        return Fold(ConstantExpr::get(Opc, LC, RC, Flags));
91      }
92      return ConstantFoldBinaryOpOperands(Opc, LC, RC, DL);
93    }
94    return nullptr;
95  }
96
97  Value *FoldBinOpFMF(Instruction::BinaryOps Opc, Value *LHS, Value *RHS,
98                      FastMathFlags FMF) const override {
99    return FoldBinOp(Opc, LHS, RHS);
100  }
101
102  Value *FoldICmp(CmpInst::Predicate P, Value *LHS, Value *RHS) const override {
103    auto *LC = dyn_cast<Constant>(LHS);
104    auto *RC = dyn_cast<Constant>(RHS);
105    if (LC && RC)
106      return Fold(ConstantExpr::getCompare(P, LC, RC));
107    return nullptr;
108  }
109
110  Value *FoldUnOpFMF(Instruction::UnaryOps Opc, Value *V,
111                      FastMathFlags FMF) const override {
112    if (Constant *C = dyn_cast<Constant>(V))
113      return ConstantFoldUnaryOpOperand(Opc, C, DL);
114    return nullptr;
115  }
116
117  Value *FoldGEP(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
118                 bool IsInBounds = false) const override {
119    if (auto *PC = dyn_cast<Constant>(Ptr)) {
120      // Every index must be constant.
121      if (any_of(IdxList, [](Value *V) { return !isa<Constant>(V); }))
122        return nullptr;
123      if (IsInBounds)
124        return Fold(ConstantExpr::getInBoundsGetElementPtr(Ty, PC, IdxList));
125      else
126        return Fold(ConstantExpr::getGetElementPtr(Ty, PC, IdxList));
127    }
128    return nullptr;
129  }
130
131  Value *FoldSelect(Value *C, Value *True, Value *False) const override {
132    auto *CC = dyn_cast<Constant>(C);
133    auto *TC = dyn_cast<Constant>(True);
134    auto *FC = dyn_cast<Constant>(False);
135    if (CC && TC && FC)
136      return Fold(ConstantExpr::getSelect(CC, TC, FC));
137
138    return nullptr;
139  }
140
141  Value *FoldExtractValue(Value *Agg,
142                          ArrayRef<unsigned> IdxList) const override {
143    if (auto *CAgg = dyn_cast<Constant>(Agg))
144      return ConstantFoldExtractValueInstruction(CAgg, IdxList);
145    return nullptr;
146  };
147
148  Value *FoldInsertValue(Value *Agg, Value *Val,
149                         ArrayRef<unsigned> IdxList) const override {
150    auto *CAgg = dyn_cast<Constant>(Agg);
151    auto *CVal = dyn_cast<Constant>(Val);
152    if (CAgg && CVal)
153      return ConstantFoldInsertValueInstruction(CAgg, CVal, IdxList);
154    return nullptr;
155  }
156
157  Value *FoldExtractElement(Value *Vec, Value *Idx) const override {
158    auto *CVec = dyn_cast<Constant>(Vec);
159    auto *CIdx = dyn_cast<Constant>(Idx);
160    if (CVec && CIdx)
161      return Fold(ConstantExpr::getExtractElement(CVec, CIdx));
162    return nullptr;
163  }
164
165  Value *FoldInsertElement(Value *Vec, Value *NewElt,
166                           Value *Idx) const override {
167    auto *CVec = dyn_cast<Constant>(Vec);
168    auto *CNewElt = dyn_cast<Constant>(NewElt);
169    auto *CIdx = dyn_cast<Constant>(Idx);
170    if (CVec && CNewElt && CIdx)
171      return Fold(ConstantExpr::getInsertElement(CVec, CNewElt, CIdx));
172    return nullptr;
173  }
174
175  Value *FoldShuffleVector(Value *V1, Value *V2,
176                           ArrayRef<int> Mask) const override {
177    auto *C1 = dyn_cast<Constant>(V1);
178    auto *C2 = dyn_cast<Constant>(V2);
179    if (C1 && C2)
180      return Fold(ConstantExpr::getShuffleVector(C1, C2, Mask));
181    return nullptr;
182  }
183
184  //===--------------------------------------------------------------------===//
185  // Cast/Conversion Operators
186  //===--------------------------------------------------------------------===//
187
188  Constant *CreateCast(Instruction::CastOps Op, Constant *C,
189                       Type *DestTy) const override {
190    if (C->getType() == DestTy)
191      return C; // avoid calling Fold
192    return Fold(ConstantExpr::getCast(Op, C, DestTy));
193  }
194  Constant *CreateIntCast(Constant *C, Type *DestTy,
195                          bool isSigned) const override {
196    if (C->getType() == DestTy)
197      return C; // avoid calling Fold
198    return Fold(ConstantExpr::getIntegerCast(C, DestTy, isSigned));
199  }
200  Constant *CreatePointerCast(Constant *C, Type *DestTy) const override {
201    if (C->getType() == DestTy)
202      return C; // avoid calling Fold
203    return Fold(ConstantExpr::getPointerCast(C, DestTy));
204  }
205  Constant *CreateFPCast(Constant *C, Type *DestTy) const override {
206    if (C->getType() == DestTy)
207      return C; // avoid calling Fold
208    return Fold(ConstantExpr::getFPCast(C, DestTy));
209  }
210  Constant *CreateBitCast(Constant *C, Type *DestTy) const override {
211    return CreateCast(Instruction::BitCast, C, DestTy);
212  }
213  Constant *CreateIntToPtr(Constant *C, Type *DestTy) const override {
214    return CreateCast(Instruction::IntToPtr, C, DestTy);
215  }
216  Constant *CreatePtrToInt(Constant *C, Type *DestTy) const override {
217    return CreateCast(Instruction::PtrToInt, C, DestTy);
218  }
219  Constant *CreateZExtOrBitCast(Constant *C, Type *DestTy) const override {
220    if (C->getType() == DestTy)
221      return C; // avoid calling Fold
222    return Fold(ConstantExpr::getZExtOrBitCast(C, DestTy));
223  }
224  Constant *CreateSExtOrBitCast(Constant *C, Type *DestTy) const override {
225    if (C->getType() == DestTy)
226      return C; // avoid calling Fold
227    return Fold(ConstantExpr::getSExtOrBitCast(C, DestTy));
228  }
229  Constant *CreateTruncOrBitCast(Constant *C, Type *DestTy) const override {
230    if (C->getType() == DestTy)
231      return C; // avoid calling Fold
232    return Fold(ConstantExpr::getTruncOrBitCast(C, DestTy));
233  }
234
235  Constant *CreatePointerBitCastOrAddrSpaceCast(Constant *C,
236                                                Type *DestTy) const override {
237    if (C->getType() == DestTy)
238      return C; // avoid calling Fold
239    return Fold(ConstantExpr::getPointerBitCastOrAddrSpaceCast(C, DestTy));
240  }
241
242  //===--------------------------------------------------------------------===//
243  // Compare Instructions
244  //===--------------------------------------------------------------------===//
245
246  Constant *CreateFCmp(CmpInst::Predicate P, Constant *LHS,
247                       Constant *RHS) const override {
248    return Fold(ConstantExpr::getCompare(P, LHS, RHS));
249  }
250};
251
252}
253
254#endif
255