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 | |
27 | namespace llvm { |
28 | |
29 | class Constant; |
30 | class DataLayout; |
31 | class Type; |
32 | |
33 | /// TargetFolder - Create constants with target dependent folding. |
34 | class 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 | |
44 | public: |
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>(Val: LHS); |
57 | auto *RC = dyn_cast<Constant>(Val: RHS); |
58 | if (LC && RC) { |
59 | if (ConstantExpr::isDesirableBinOp(Opcode: Opc)) |
60 | return Fold(C: ConstantExpr::get(Opcode: Opc, C1: LC, C2: RC)); |
61 | return ConstantFoldBinaryOpOperands(Opcode: Opc, LHS: LC, RHS: 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>(Val: LHS); |
69 | auto *RC = dyn_cast<Constant>(Val: RHS); |
70 | if (LC && RC) { |
71 | if (ConstantExpr::isDesirableBinOp(Opcode: Opc)) |
72 | return Fold(C: ConstantExpr::get( |
73 | Opcode: Opc, C1: LC, C2: RC, Flags: IsExact ? PossiblyExactOperator::IsExact : 0)); |
74 | return ConstantFoldBinaryOpOperands(Opcode: Opc, LHS: LC, RHS: 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>(Val: LHS); |
82 | auto *RC = dyn_cast<Constant>(Val: RHS); |
83 | if (LC && RC) { |
84 | if (ConstantExpr::isDesirableBinOp(Opcode: Opc)) { |
85 | unsigned Flags = 0; |
86 | if (HasNUW) |
87 | Flags |= OverflowingBinaryOperator::NoUnsignedWrap; |
88 | if (HasNSW) |
89 | Flags |= OverflowingBinaryOperator::NoSignedWrap; |
90 | return Fold(C: ConstantExpr::get(Opcode: Opc, C1: LC, C2: RC, Flags)); |
91 | } |
92 | return ConstantFoldBinaryOpOperands(Opcode: Opc, LHS: LC, RHS: 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>(Val: LHS); |
104 | auto *RC = dyn_cast<Constant>(Val: RHS); |
105 | if (LC && RC) |
106 | return Fold(C: ConstantExpr::getCompare(pred: P, C1: LC, C2: 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>(Val: V)) |
113 | return ConstantFoldUnaryOpOperand(Opcode: Opc, Op: 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(SrcElemTy: Ty)) |
120 | return nullptr; |
121 | |
122 | if (auto *PC = dyn_cast<Constant>(Val: Ptr)) { |
123 | // Every index must be constant. |
124 | if (any_of(Range&: IdxList, P: [](Value *V) { return !isa<Constant>(Val: V); })) |
125 | return nullptr; |
126 | if (IsInBounds) |
127 | return Fold(C: ConstantExpr::getInBoundsGetElementPtr(Ty, C: PC, IdxList)); |
128 | else |
129 | return Fold(C: ConstantExpr::getGetElementPtr(Ty, C: 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>(Val: C); |
136 | auto *TC = dyn_cast<Constant>(Val: True); |
137 | auto *FC = dyn_cast<Constant>(Val: False); |
138 | if (CC && TC && FC) |
139 | return ConstantFoldSelectInstruction(Cond: CC, V1: TC, V2: FC); |
140 | |
141 | return nullptr; |
142 | } |
143 | |
144 | Value *(Value *Agg, |
145 | ArrayRef<unsigned> IdxList) const override { |
146 | if (auto *CAgg = dyn_cast<Constant>(Val: Agg)) |
147 | return ConstantFoldExtractValueInstruction(Agg: CAgg, Idxs: 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>(Val: Agg); |
154 | auto *CVal = dyn_cast<Constant>(Val); |
155 | if (CAgg && CVal) |
156 | return ConstantFoldInsertValueInstruction(Agg: CAgg, Val: CVal, Idxs: IdxList); |
157 | return nullptr; |
158 | } |
159 | |
160 | Value *(Value *Vec, Value *Idx) const override { |
161 | auto *CVec = dyn_cast<Constant>(Val: Vec); |
162 | auto *CIdx = dyn_cast<Constant>(Val: Idx); |
163 | if (CVec && CIdx) |
164 | return Fold(C: ConstantExpr::getExtractElement(Vec: CVec, Idx: CIdx)); |
165 | return nullptr; |
166 | } |
167 | |
168 | Value *FoldInsertElement(Value *Vec, Value *NewElt, |
169 | Value *Idx) const override { |
170 | auto *CVec = dyn_cast<Constant>(Val: Vec); |
171 | auto *CNewElt = dyn_cast<Constant>(Val: NewElt); |
172 | auto *CIdx = dyn_cast<Constant>(Val: Idx); |
173 | if (CVec && CNewElt && CIdx) |
174 | return Fold(C: ConstantExpr::getInsertElement(Vec: CVec, Elt: CNewElt, Idx: 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>(Val: V1); |
181 | auto *C2 = dyn_cast<Constant>(Val: V2); |
182 | if (C1 && C2) |
183 | return Fold(C: ConstantExpr::getShuffleVector(V1: C1, V2: 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>(Val: V)) |
190 | return ConstantFoldCastOperand(Opcode: 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(C: ConstantExpr::getPointerCast(C, Ty: 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(C: ConstantExpr::getPointerBitCastOrAddrSpaceCast(C, Ty: 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(C: ConstantExpr::getCompare(pred: P, C1: LHS, C2: RHS)); |
218 | } |
219 | }; |
220 | |
221 | } |
222 | |
223 | #endif |
224 | |