1 | //===-- Operator.cpp - Implement the LLVM operators -----------------------===// |
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 implements the non-inline methods for the LLVM Operator classes. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/IR/Operator.h" |
14 | #include "llvm/IR/DataLayout.h" |
15 | #include "llvm/IR/GetElementPtrTypeIterator.h" |
16 | #include "llvm/IR/Instructions.h" |
17 | |
18 | #include "ConstantsContext.h" |
19 | |
20 | namespace llvm { |
21 | bool Operator::hasPoisonGeneratingFlags() const { |
22 | switch (getOpcode()) { |
23 | case Instruction::Add: |
24 | case Instruction::Sub: |
25 | case Instruction::Mul: |
26 | case Instruction::Shl: { |
27 | auto *OBO = cast<OverflowingBinaryOperator>(Val: this); |
28 | return OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap(); |
29 | } |
30 | case Instruction::Trunc: { |
31 | if (auto *TI = dyn_cast<TruncInst>(Val: this)) |
32 | return TI->hasNoUnsignedWrap() || TI->hasNoSignedWrap(); |
33 | return false; |
34 | } |
35 | case Instruction::UDiv: |
36 | case Instruction::SDiv: |
37 | case Instruction::AShr: |
38 | case Instruction::LShr: |
39 | return cast<PossiblyExactOperator>(Val: this)->isExact(); |
40 | case Instruction::Or: |
41 | return cast<PossiblyDisjointInst>(Val: this)->isDisjoint(); |
42 | case Instruction::GetElementPtr: { |
43 | auto *GEP = cast<GEPOperator>(Val: this); |
44 | // Note: inrange exists on constexpr only |
45 | return GEP->isInBounds() || GEP->getInRange() != std::nullopt; |
46 | } |
47 | case Instruction::UIToFP: |
48 | case Instruction::ZExt: |
49 | if (auto *NNI = dyn_cast<PossiblyNonNegInst>(Val: this)) |
50 | return NNI->hasNonNeg(); |
51 | return false; |
52 | default: |
53 | if (const auto *FP = dyn_cast<FPMathOperator>(Val: this)) |
54 | return FP->hasNoNaNs() || FP->hasNoInfs(); |
55 | return false; |
56 | } |
57 | } |
58 | |
59 | bool Operator::hasPoisonGeneratingAnnotations() const { |
60 | if (hasPoisonGeneratingFlags()) |
61 | return true; |
62 | auto *I = dyn_cast<Instruction>(Val: this); |
63 | return I && (I->hasPoisonGeneratingReturnAttributes() || |
64 | I->hasPoisonGeneratingMetadata()); |
65 | } |
66 | |
67 | Type *GEPOperator::getSourceElementType() const { |
68 | if (auto *I = dyn_cast<GetElementPtrInst>(Val: this)) |
69 | return I->getSourceElementType(); |
70 | return cast<GetElementPtrConstantExpr>(Val: this)->getSourceElementType(); |
71 | } |
72 | |
73 | Type *GEPOperator::getResultElementType() const { |
74 | if (auto *I = dyn_cast<GetElementPtrInst>(Val: this)) |
75 | return I->getResultElementType(); |
76 | return cast<GetElementPtrConstantExpr>(Val: this)->getResultElementType(); |
77 | } |
78 | |
79 | std::optional<ConstantRange> GEPOperator::getInRange() const { |
80 | if (auto *CE = dyn_cast<GetElementPtrConstantExpr>(Val: this)) |
81 | return CE->getInRange(); |
82 | return std::nullopt; |
83 | } |
84 | |
85 | Align GEPOperator::getMaxPreservedAlignment(const DataLayout &DL) const { |
86 | /// compute the worse possible offset for every level of the GEP et accumulate |
87 | /// the minimum alignment into Result. |
88 | |
89 | Align Result = Align(llvm::Value::MaximumAlignment); |
90 | for (gep_type_iterator GTI = gep_type_begin(GEP: this), GTE = gep_type_end(GEP: this); |
91 | GTI != GTE; ++GTI) { |
92 | uint64_t Offset; |
93 | ConstantInt *OpC = dyn_cast<ConstantInt>(Val: GTI.getOperand()); |
94 | |
95 | if (StructType *STy = GTI.getStructTypeOrNull()) { |
96 | const StructLayout *SL = DL.getStructLayout(Ty: STy); |
97 | Offset = SL->getElementOffset(Idx: OpC->getZExtValue()); |
98 | } else { |
99 | assert(GTI.isSequential() && "should be sequencial" ); |
100 | /// If the index isn't known, we take 1 because it is the index that will |
101 | /// give the worse alignment of the offset. |
102 | const uint64_t ElemCount = OpC ? OpC->getZExtValue() : 1; |
103 | Offset = GTI.getSequentialElementStride(DL) * ElemCount; |
104 | } |
105 | Result = Align(MinAlign(A: Offset, B: Result.value())); |
106 | } |
107 | return Result; |
108 | } |
109 | |
110 | bool GEPOperator::accumulateConstantOffset( |
111 | const DataLayout &DL, APInt &Offset, |
112 | function_ref<bool(Value &, APInt &)> ExternalAnalysis) const { |
113 | assert(Offset.getBitWidth() == |
114 | DL.getIndexSizeInBits(getPointerAddressSpace()) && |
115 | "The offset bit width does not match DL specification." ); |
116 | SmallVector<const Value *> Index(llvm::drop_begin(RangeOrContainer: operand_values())); |
117 | return GEPOperator::accumulateConstantOffset(SourceType: getSourceElementType(), Index, |
118 | DL, Offset, ExternalAnalysis); |
119 | } |
120 | |
121 | bool GEPOperator::accumulateConstantOffset( |
122 | Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL, |
123 | APInt &Offset, function_ref<bool(Value &, APInt &)> ExternalAnalysis) { |
124 | // Fast path for canonical getelementptr i8 form. |
125 | if (SourceType->isIntegerTy(Bitwidth: 8) && !ExternalAnalysis) { |
126 | if (auto *CI = dyn_cast<ConstantInt>(Val: Index.front())) { |
127 | Offset += CI->getValue().sextOrTrunc(width: Offset.getBitWidth()); |
128 | return true; |
129 | } |
130 | return false; |
131 | } |
132 | |
133 | bool UsedExternalAnalysis = false; |
134 | auto AccumulateOffset = [&](APInt Index, uint64_t Size) -> bool { |
135 | Index = Index.sextOrTrunc(width: Offset.getBitWidth()); |
136 | APInt IndexedSize = APInt(Offset.getBitWidth(), Size); |
137 | // For array or vector indices, scale the index by the size of the type. |
138 | if (!UsedExternalAnalysis) { |
139 | Offset += Index * IndexedSize; |
140 | } else { |
141 | // External Analysis can return a result higher/lower than the value |
142 | // represents. We need to detect overflow/underflow. |
143 | bool Overflow = false; |
144 | APInt OffsetPlus = Index.smul_ov(RHS: IndexedSize, Overflow); |
145 | if (Overflow) |
146 | return false; |
147 | Offset = Offset.sadd_ov(RHS: OffsetPlus, Overflow); |
148 | if (Overflow) |
149 | return false; |
150 | } |
151 | return true; |
152 | }; |
153 | auto begin = generic_gep_type_iterator<decltype(Index.begin())>::begin( |
154 | Ty: SourceType, It: Index.begin()); |
155 | auto end = generic_gep_type_iterator<decltype(Index.end())>::end(It: Index.end()); |
156 | for (auto GTI = begin, GTE = end; GTI != GTE; ++GTI) { |
157 | // Scalable vectors are multiplied by a runtime constant. |
158 | bool ScalableType = GTI.getIndexedType()->isScalableTy(); |
159 | |
160 | Value *V = GTI.getOperand(); |
161 | StructType *STy = GTI.getStructTypeOrNull(); |
162 | // Handle ConstantInt if possible. |
163 | if (auto ConstOffset = dyn_cast<ConstantInt>(Val: V)) { |
164 | if (ConstOffset->isZero()) |
165 | continue; |
166 | // if the type is scalable and the constant is not zero (vscale * n * 0 = |
167 | // 0) bailout. |
168 | if (ScalableType) |
169 | return false; |
170 | // Handle a struct index, which adds its field offset to the pointer. |
171 | if (STy) { |
172 | unsigned ElementIdx = ConstOffset->getZExtValue(); |
173 | const StructLayout *SL = DL.getStructLayout(Ty: STy); |
174 | // Element offset is in bytes. |
175 | if (!AccumulateOffset( |
176 | APInt(Offset.getBitWidth(), SL->getElementOffset(Idx: ElementIdx)), |
177 | 1)) |
178 | return false; |
179 | continue; |
180 | } |
181 | if (!AccumulateOffset(ConstOffset->getValue(), |
182 | GTI.getSequentialElementStride(DL))) |
183 | return false; |
184 | continue; |
185 | } |
186 | |
187 | // The operand is not constant, check if an external analysis was provided. |
188 | // External analsis is not applicable to a struct type. |
189 | if (!ExternalAnalysis || STy || ScalableType) |
190 | return false; |
191 | APInt AnalysisIndex; |
192 | if (!ExternalAnalysis(*V, AnalysisIndex)) |
193 | return false; |
194 | UsedExternalAnalysis = true; |
195 | if (!AccumulateOffset(AnalysisIndex, GTI.getSequentialElementStride(DL))) |
196 | return false; |
197 | } |
198 | return true; |
199 | } |
200 | |
201 | bool GEPOperator::collectOffset( |
202 | const DataLayout &DL, unsigned BitWidth, |
203 | MapVector<Value *, APInt> &VariableOffsets, |
204 | APInt &ConstantOffset) const { |
205 | assert(BitWidth == DL.getIndexSizeInBits(getPointerAddressSpace()) && |
206 | "The offset bit width does not match DL specification." ); |
207 | |
208 | auto CollectConstantOffset = [&](APInt Index, uint64_t Size) { |
209 | Index = Index.sextOrTrunc(width: BitWidth); |
210 | APInt IndexedSize = APInt(BitWidth, Size); |
211 | ConstantOffset += Index * IndexedSize; |
212 | }; |
213 | |
214 | for (gep_type_iterator GTI = gep_type_begin(GEP: this), GTE = gep_type_end(GEP: this); |
215 | GTI != GTE; ++GTI) { |
216 | // Scalable vectors are multiplied by a runtime constant. |
217 | bool ScalableType = GTI.getIndexedType()->isScalableTy(); |
218 | |
219 | Value *V = GTI.getOperand(); |
220 | StructType *STy = GTI.getStructTypeOrNull(); |
221 | // Handle ConstantInt if possible. |
222 | if (auto ConstOffset = dyn_cast<ConstantInt>(Val: V)) { |
223 | if (ConstOffset->isZero()) |
224 | continue; |
225 | // If the type is scalable and the constant is not zero (vscale * n * 0 = |
226 | // 0) bailout. |
227 | // TODO: If the runtime value is accessible at any point before DWARF |
228 | // emission, then we could potentially keep a forward reference to it |
229 | // in the debug value to be filled in later. |
230 | if (ScalableType) |
231 | return false; |
232 | // Handle a struct index, which adds its field offset to the pointer. |
233 | if (STy) { |
234 | unsigned ElementIdx = ConstOffset->getZExtValue(); |
235 | const StructLayout *SL = DL.getStructLayout(Ty: STy); |
236 | // Element offset is in bytes. |
237 | CollectConstantOffset(APInt(BitWidth, SL->getElementOffset(Idx: ElementIdx)), |
238 | 1); |
239 | continue; |
240 | } |
241 | CollectConstantOffset(ConstOffset->getValue(), |
242 | GTI.getSequentialElementStride(DL)); |
243 | continue; |
244 | } |
245 | |
246 | if (STy || ScalableType) |
247 | return false; |
248 | APInt IndexedSize = APInt(BitWidth, GTI.getSequentialElementStride(DL)); |
249 | // Insert an initial offset of 0 for V iff none exists already, then |
250 | // increment the offset by IndexedSize. |
251 | if (!IndexedSize.isZero()) { |
252 | auto *It = VariableOffsets.insert(KV: {V, APInt(BitWidth, 0)}).first; |
253 | It->second += IndexedSize; |
254 | } |
255 | } |
256 | return true; |
257 | } |
258 | |
259 | void FastMathFlags::print(raw_ostream &O) const { |
260 | if (all()) |
261 | O << " fast" ; |
262 | else { |
263 | if (allowReassoc()) |
264 | O << " reassoc" ; |
265 | if (noNaNs()) |
266 | O << " nnan" ; |
267 | if (noInfs()) |
268 | O << " ninf" ; |
269 | if (noSignedZeros()) |
270 | O << " nsz" ; |
271 | if (allowReciprocal()) |
272 | O << " arcp" ; |
273 | if (allowContract()) |
274 | O << " contract" ; |
275 | if (approxFunc()) |
276 | O << " afn" ; |
277 | } |
278 | } |
279 | } // namespace llvm |
280 | |