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/InstrTypes.h"
25 #include "llvm/IR/IRBuilderFolder.h"
26 
27 namespace llvm {
28 
29 class DataLayout;
30 
31 /// TargetFolder - Create constants with target dependent folding.
32 class TargetFolder final : public IRBuilderFolder {
33   const DataLayout &DL;
34 
35   /// Fold - Fold the constant using target specific information.
36   Constant *Fold(Constant *C) const {
37     return ConstantFoldConstant(C, DL);
38   }
39 
40   virtual void anchor();
41 
42 public:
43   explicit TargetFolder(const DataLayout &DL) : DL(DL) {}
44 
45   //===--------------------------------------------------------------------===//
46   // Value-based folders.
47   //
48   // Return an existing value or a constant if the operation can be simplified.
49   // Otherwise return nullptr.
50   //===--------------------------------------------------------------------===//
51   Value *FoldAdd(Value *LHS, Value *RHS, bool HasNUW = false,
52                  bool HasNSW = false) const override {
53     auto *LC = dyn_cast<Constant>(LHS);
54     auto *RC = dyn_cast<Constant>(RHS);
55     if (LC && RC)
56       return Fold(ConstantExpr::getAdd(LC, RC, HasNUW, HasNSW));
57     return nullptr;
58   }
59 
60   Value *FoldAnd(Value *LHS, Value *RHS) const override {
61     auto *LC = dyn_cast<Constant>(LHS);
62     auto *RC = dyn_cast<Constant>(RHS);
63     if (LC && RC)
64       return Fold(ConstantExpr::getAnd(LC, RC));
65     return nullptr;
66   }
67 
68   Value *FoldOr(Value *LHS, Value *RHS) const override {
69     auto *LC = dyn_cast<Constant>(LHS);
70     auto *RC = dyn_cast<Constant>(RHS);
71     if (LC && RC)
72       return Fold(ConstantExpr::getOr(LC, RC));
73     return nullptr;
74   }
75 
76   Value *FoldICmp(CmpInst::Predicate P, Value *LHS, Value *RHS) const override {
77     auto *LC = dyn_cast<Constant>(LHS);
78     auto *RC = dyn_cast<Constant>(RHS);
79     if (LC && RC)
80       return ConstantExpr::getCompare(P, LC, RC);
81     return nullptr;
82   }
83 
84   Value *FoldGEP(Type *Ty, Value *Ptr, ArrayRef<Value *> IdxList,
85                  bool IsInBounds = false) const override {
86     if (auto *PC = dyn_cast<Constant>(Ptr)) {
87       // Every index must be constant.
88       if (any_of(IdxList, [](Value *V) { return !isa<Constant>(V); }))
89         return nullptr;
90       if (IsInBounds)
91         return Fold(ConstantExpr::getInBoundsGetElementPtr(Ty, PC, IdxList));
92       else
93         return Fold(ConstantExpr::getGetElementPtr(Ty, PC, IdxList));
94     }
95     return nullptr;
96   }
97 
98   Value *FoldSelect(Value *C, Value *True, Value *False) const override {
99     auto *CC = dyn_cast<Constant>(C);
100     auto *TC = dyn_cast<Constant>(True);
101     auto *FC = dyn_cast<Constant>(False);
102     if (CC && TC && FC)
103       return Fold(ConstantExpr::getSelect(CC, TC, FC));
104 
105     return nullptr;
106   }
107 
108   //===--------------------------------------------------------------------===//
109   // Binary Operators
110   //===--------------------------------------------------------------------===//
111 
112   Constant *CreateFAdd(Constant *LHS, Constant *RHS) const override {
113     return Fold(ConstantExpr::getFAdd(LHS, RHS));
114   }
115   Constant *CreateSub(Constant *LHS, Constant *RHS,
116                       bool HasNUW = false, bool HasNSW = false) const override {
117     return Fold(ConstantExpr::getSub(LHS, RHS, HasNUW, HasNSW));
118   }
119   Constant *CreateFSub(Constant *LHS, Constant *RHS) const override {
120     return Fold(ConstantExpr::getFSub(LHS, RHS));
121   }
122   Constant *CreateMul(Constant *LHS, Constant *RHS,
123                       bool HasNUW = false, bool HasNSW = false) const override {
124     return Fold(ConstantExpr::getMul(LHS, RHS, HasNUW, HasNSW));
125   }
126   Constant *CreateFMul(Constant *LHS, Constant *RHS) const override {
127     return Fold(ConstantExpr::getFMul(LHS, RHS));
128   }
129   Constant *CreateUDiv(Constant *LHS, Constant *RHS,
130                        bool isExact = false) const override {
131     return Fold(ConstantExpr::getUDiv(LHS, RHS, isExact));
132   }
133   Constant *CreateSDiv(Constant *LHS, Constant *RHS,
134                        bool isExact = false) const override {
135     return Fold(ConstantExpr::getSDiv(LHS, RHS, isExact));
136   }
137   Constant *CreateFDiv(Constant *LHS, Constant *RHS) const override {
138     return Fold(ConstantExpr::getFDiv(LHS, RHS));
139   }
140   Constant *CreateURem(Constant *LHS, Constant *RHS) const override {
141     return Fold(ConstantExpr::getURem(LHS, RHS));
142   }
143   Constant *CreateSRem(Constant *LHS, Constant *RHS) const override {
144     return Fold(ConstantExpr::getSRem(LHS, RHS));
145   }
146   Constant *CreateFRem(Constant *LHS, Constant *RHS) const override {
147     return Fold(ConstantExpr::getFRem(LHS, RHS));
148   }
149   Constant *CreateShl(Constant *LHS, Constant *RHS,
150                       bool HasNUW = false, bool HasNSW = false) const override {
151     return Fold(ConstantExpr::getShl(LHS, RHS, HasNUW, HasNSW));
152   }
153   Constant *CreateLShr(Constant *LHS, Constant *RHS,
154                        bool isExact = false) const override {
155     return Fold(ConstantExpr::getLShr(LHS, RHS, isExact));
156   }
157   Constant *CreateAShr(Constant *LHS, Constant *RHS,
158                        bool isExact = false) const override {
159     return Fold(ConstantExpr::getAShr(LHS, RHS, isExact));
160   }
161   Constant *CreateXor(Constant *LHS, Constant *RHS) const override {
162     return Fold(ConstantExpr::getXor(LHS, RHS));
163   }
164 
165   Constant *CreateBinOp(Instruction::BinaryOps Opc,
166                         Constant *LHS, Constant *RHS) const override {
167     return Fold(ConstantExpr::get(Opc, LHS, RHS));
168   }
169 
170   //===--------------------------------------------------------------------===//
171   // Unary Operators
172   //===--------------------------------------------------------------------===//
173 
174   Constant *CreateNeg(Constant *C,
175                       bool HasNUW = false, bool HasNSW = false) const override {
176     return Fold(ConstantExpr::getNeg(C, HasNUW, HasNSW));
177   }
178   Constant *CreateFNeg(Constant *C) const override {
179     return Fold(ConstantExpr::getFNeg(C));
180   }
181   Constant *CreateNot(Constant *C) const override {
182     return Fold(ConstantExpr::getNot(C));
183   }
184 
185   Constant *CreateUnOp(Instruction::UnaryOps Opc, Constant *C) const override {
186     return Fold(ConstantExpr::get(Opc, C));
187   }
188 
189   //===--------------------------------------------------------------------===//
190   // Cast/Conversion Operators
191   //===--------------------------------------------------------------------===//
192 
193   Constant *CreateCast(Instruction::CastOps Op, Constant *C,
194                        Type *DestTy) const override {
195     if (C->getType() == DestTy)
196       return C; // avoid calling Fold
197     return Fold(ConstantExpr::getCast(Op, C, DestTy));
198   }
199   Constant *CreateIntCast(Constant *C, Type *DestTy,
200                           bool isSigned) const override {
201     if (C->getType() == DestTy)
202       return C; // avoid calling Fold
203     return Fold(ConstantExpr::getIntegerCast(C, DestTy, isSigned));
204   }
205   Constant *CreatePointerCast(Constant *C, Type *DestTy) const override {
206     if (C->getType() == DestTy)
207       return C; // avoid calling Fold
208     return Fold(ConstantExpr::getPointerCast(C, DestTy));
209   }
210   Constant *CreateFPCast(Constant *C, Type *DestTy) const override {
211     if (C->getType() == DestTy)
212       return C; // avoid calling Fold
213     return Fold(ConstantExpr::getFPCast(C, DestTy));
214   }
215   Constant *CreateBitCast(Constant *C, Type *DestTy) const override {
216     return CreateCast(Instruction::BitCast, C, DestTy);
217   }
218   Constant *CreateIntToPtr(Constant *C, Type *DestTy) const override {
219     return CreateCast(Instruction::IntToPtr, C, DestTy);
220   }
221   Constant *CreatePtrToInt(Constant *C, Type *DestTy) const override {
222     return CreateCast(Instruction::PtrToInt, C, DestTy);
223   }
224   Constant *CreateZExtOrBitCast(Constant *C, Type *DestTy) const override {
225     if (C->getType() == DestTy)
226       return C; // avoid calling Fold
227     return Fold(ConstantExpr::getZExtOrBitCast(C, DestTy));
228   }
229   Constant *CreateSExtOrBitCast(Constant *C, Type *DestTy) const override {
230     if (C->getType() == DestTy)
231       return C; // avoid calling Fold
232     return Fold(ConstantExpr::getSExtOrBitCast(C, DestTy));
233   }
234   Constant *CreateTruncOrBitCast(Constant *C, Type *DestTy) const override {
235     if (C->getType() == DestTy)
236       return C; // avoid calling Fold
237     return Fold(ConstantExpr::getTruncOrBitCast(C, DestTy));
238   }
239 
240   Constant *CreatePointerBitCastOrAddrSpaceCast(Constant *C,
241                                                 Type *DestTy) const override {
242     if (C->getType() == DestTy)
243       return C; // avoid calling Fold
244     return Fold(ConstantExpr::getPointerBitCastOrAddrSpaceCast(C, DestTy));
245   }
246 
247   //===--------------------------------------------------------------------===//
248   // Compare Instructions
249   //===--------------------------------------------------------------------===//
250 
251   Constant *CreateFCmp(CmpInst::Predicate P, Constant *LHS,
252                        Constant *RHS) const override {
253     return Fold(ConstantExpr::getCompare(P, LHS, RHS));
254   }
255 
256   //===--------------------------------------------------------------------===//
257   // Other Instructions
258   //===--------------------------------------------------------------------===//
259 
260   Constant *CreateExtractElement(Constant *Vec, Constant *Idx) const override {
261     return Fold(ConstantExpr::getExtractElement(Vec, Idx));
262   }
263 
264   Constant *CreateInsertElement(Constant *Vec, Constant *NewElt,
265                                 Constant *Idx) const override {
266     return Fold(ConstantExpr::getInsertElement(Vec, NewElt, Idx));
267   }
268 
269   Constant *CreateShuffleVector(Constant *V1, Constant *V2,
270                                 ArrayRef<int> Mask) const override {
271     return Fold(ConstantExpr::getShuffleVector(V1, V2, Mask));
272   }
273 
274   Constant *CreateExtractValue(Constant *Agg,
275                                ArrayRef<unsigned> IdxList) const override {
276     return Fold(ConstantExpr::getExtractValue(Agg, IdxList));
277   }
278 
279   Constant *CreateInsertValue(Constant *Agg, Constant *Val,
280                               ArrayRef<unsigned> IdxList) const override {
281     return Fold(ConstantExpr::getInsertValue(Agg, Val, IdxList));
282   }
283 };
284 
285 }
286 
287 #endif
288