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 (!ConstantExpr::isSupportedGetElementPtr(Ty))
120      return nullptr;
121
122    if (auto *PC = dyn_cast<Constant>(Ptr)) {
123      // Every index must be constant.
124      if (any_of(IdxList, [](Value *V) { return !isa<Constant>(V); }))
125        return nullptr;
126      if (IsInBounds)
127        return Fold(ConstantExpr::getInBoundsGetElementPtr(Ty, PC, IdxList));
128      else
129        return Fold(ConstantExpr::getGetElementPtr(Ty, PC, IdxList));
130    }
131    return nullptr;
132  }
133
134  Value *FoldSelect(Value *C, Value *True, Value *False) const override {
135    auto *CC = dyn_cast<Constant>(C);
136    auto *TC = dyn_cast<Constant>(True);
137    auto *FC = dyn_cast<Constant>(False);
138    if (CC && TC && FC)
139      return ConstantFoldSelectInstruction(CC, TC, FC);
140
141    return nullptr;
142  }
143
144  Value *FoldExtractValue(Value *Agg,
145                          ArrayRef<unsigned> IdxList) const override {
146    if (auto *CAgg = dyn_cast<Constant>(Agg))
147      return ConstantFoldExtractValueInstruction(CAgg, IdxList);
148    return nullptr;
149  };
150
151  Value *FoldInsertValue(Value *Agg, Value *Val,
152                         ArrayRef<unsigned> IdxList) const override {
153    auto *CAgg = dyn_cast<Constant>(Agg);
154    auto *CVal = dyn_cast<Constant>(Val);
155    if (CAgg && CVal)
156      return ConstantFoldInsertValueInstruction(CAgg, CVal, IdxList);
157    return nullptr;
158  }
159
160  Value *FoldExtractElement(Value *Vec, Value *Idx) const override {
161    auto *CVec = dyn_cast<Constant>(Vec);
162    auto *CIdx = dyn_cast<Constant>(Idx);
163    if (CVec && CIdx)
164      return Fold(ConstantExpr::getExtractElement(CVec, CIdx));
165    return nullptr;
166  }
167
168  Value *FoldInsertElement(Value *Vec, Value *NewElt,
169                           Value *Idx) const override {
170    auto *CVec = dyn_cast<Constant>(Vec);
171    auto *CNewElt = dyn_cast<Constant>(NewElt);
172    auto *CIdx = dyn_cast<Constant>(Idx);
173    if (CVec && CNewElt && CIdx)
174      return Fold(ConstantExpr::getInsertElement(CVec, CNewElt, CIdx));
175    return nullptr;
176  }
177
178  Value *FoldShuffleVector(Value *V1, Value *V2,
179                           ArrayRef<int> Mask) const override {
180    auto *C1 = dyn_cast<Constant>(V1);
181    auto *C2 = dyn_cast<Constant>(V2);
182    if (C1 && C2)
183      return Fold(ConstantExpr::getShuffleVector(C1, C2, Mask));
184    return nullptr;
185  }
186
187  Value *FoldCast(Instruction::CastOps Op, Value *V,
188                  Type *DestTy) const override {
189    if (auto *C = dyn_cast<Constant>(V))
190      return ConstantFoldCastOperand(Op, C, DestTy, DL);
191    return nullptr;
192  }
193
194  //===--------------------------------------------------------------------===//
195  // Cast/Conversion Operators
196  //===--------------------------------------------------------------------===//
197
198  Constant *CreatePointerCast(Constant *C, Type *DestTy) const override {
199    if (C->getType() == DestTy)
200      return C; // avoid calling Fold
201    return Fold(ConstantExpr::getPointerCast(C, DestTy));
202  }
203
204  Constant *CreatePointerBitCastOrAddrSpaceCast(Constant *C,
205                                                Type *DestTy) const override {
206    if (C->getType() == DestTy)
207      return C; // avoid calling Fold
208    return Fold(ConstantExpr::getPointerBitCastOrAddrSpaceCast(C, DestTy));
209  }
210
211  //===--------------------------------------------------------------------===//
212  // Compare Instructions
213  //===--------------------------------------------------------------------===//
214
215  Constant *CreateFCmp(CmpInst::Predicate P, Constant *LHS,
216                       Constant *RHS) const override {
217    return Fold(ConstantExpr::getCompare(P, LHS, RHS));
218  }
219};
220
221}
222
223#endif
224