1c98f8835SCraig Topper //===-- Operator.cpp - Implement the LLVM operators -----------------------===//
2c98f8835SCraig Topper //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c98f8835SCraig Topper //
7c98f8835SCraig Topper //===----------------------------------------------------------------------===//
8c98f8835SCraig Topper //
9c98f8835SCraig Topper // This file implements the non-inline methods for the LLVM Operator classes.
10c98f8835SCraig Topper //
11c98f8835SCraig Topper //===----------------------------------------------------------------------===//
12c98f8835SCraig Topper 
1360310f27SDavid Blaikie #include "llvm/IR/Operator.h"
14b5c2bfa8SCraig Topper #include "llvm/IR/DataLayout.h"
156f0d5224SDavid Blaikie #include "llvm/IR/GetElementPtrTypeIterator.h"
1660310f27SDavid Blaikie #include "llvm/IR/Instructions.h"
1760310f27SDavid Blaikie 
1860310f27SDavid Blaikie #include "ConstantsContext.h"
1960310f27SDavid Blaikie 
2060310f27SDavid Blaikie namespace llvm {
hasPoisonGeneratingFlags() const21425cbbc6SPhilip Reames bool Operator::hasPoisonGeneratingFlags() const {
22425cbbc6SPhilip Reames   switch (getOpcode()) {
23425cbbc6SPhilip Reames   case Instruction::Add:
24425cbbc6SPhilip Reames   case Instruction::Sub:
25425cbbc6SPhilip Reames   case Instruction::Mul:
26425cbbc6SPhilip Reames   case Instruction::Shl: {
27425cbbc6SPhilip Reames     auto *OBO = cast<OverflowingBinaryOperator>(this);
28425cbbc6SPhilip Reames     return OBO->hasNoUnsignedWrap() || OBO->hasNoSignedWrap();
29425cbbc6SPhilip Reames   }
30425cbbc6SPhilip Reames   case Instruction::UDiv:
31425cbbc6SPhilip Reames   case Instruction::SDiv:
32425cbbc6SPhilip Reames   case Instruction::AShr:
33425cbbc6SPhilip Reames   case Instruction::LShr:
34425cbbc6SPhilip Reames     return cast<PossiblyExactOperator>(this)->isExact();
35425cbbc6SPhilip Reames   case Instruction::GetElementPtr: {
36425cbbc6SPhilip Reames     auto *GEP = cast<GEPOperator>(this);
37425cbbc6SPhilip Reames     // Note: inrange exists on constexpr only
38425cbbc6SPhilip Reames     return GEP->isInBounds() || GEP->getInRangeIndex() != None;
39425cbbc6SPhilip Reames   }
40425cbbc6SPhilip Reames   default:
41423f1968SPhilip Reames     if (const auto *FP = dyn_cast<FPMathOperator>(this))
42423f1968SPhilip Reames       return FP->hasNoNaNs() || FP->hasNoInfs();
43425cbbc6SPhilip Reames     return false;
44425cbbc6SPhilip Reames   }
45425cbbc6SPhilip Reames }
46425cbbc6SPhilip Reames 
getSourceElementType() const4760310f27SDavid Blaikie Type *GEPOperator::getSourceElementType() const {
4860310f27SDavid Blaikie   if (auto *I = dyn_cast<GetElementPtrInst>(this))
4960310f27SDavid Blaikie     return I->getSourceElementType();
5060310f27SDavid Blaikie   return cast<GetElementPtrConstantExpr>(this)->getSourceElementType();
5160310f27SDavid Blaikie }
526f0d5224SDavid Blaikie 
getResultElementType() const5319eb0310SEduard Burtescu Type *GEPOperator::getResultElementType() const {
5419eb0310SEduard Burtescu   if (auto *I = dyn_cast<GetElementPtrInst>(this))
5519eb0310SEduard Burtescu     return I->getResultElementType();
5619eb0310SEduard Burtescu   return cast<GetElementPtrConstantExpr>(this)->getResultElementType();
5719eb0310SEduard Burtescu }
5819eb0310SEduard Burtescu 
getMaxPreservedAlignment(const DataLayout & DL) const59b7338fb1STyker Align GEPOperator::getMaxPreservedAlignment(const DataLayout &DL) const {
60b7338fb1STyker   /// compute the worse possible offset for every level of the GEP et accumulate
61b7338fb1STyker   /// the minimum alignment into Result.
62b7338fb1STyker 
63b7338fb1STyker   Align Result = Align(llvm::Value::MaximumAlignment);
64b7338fb1STyker   for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this);
65b7338fb1STyker        GTI != GTE; ++GTI) {
66b7338fb1STyker     int64_t Offset = 1;
67b7338fb1STyker     ConstantInt *OpC = dyn_cast<ConstantInt>(GTI.getOperand());
68b7338fb1STyker 
69b7338fb1STyker     if (StructType *STy = GTI.getStructTypeOrNull()) {
70b7338fb1STyker       const StructLayout *SL = DL.getStructLayout(STy);
71b7338fb1STyker       Offset = SL->getElementOffset(OpC->getZExtValue());
72b7338fb1STyker     } else {
73b7338fb1STyker       assert(GTI.isSequential() && "should be sequencial");
74b7338fb1STyker       /// If the index isn't know we take 1 because it is the index that will
75b7338fb1STyker       /// give the worse alignment of the offset.
76b7338fb1STyker       int64_t ElemCount = 1;
77b7338fb1STyker       if (OpC)
78b7338fb1STyker         ElemCount = OpC->getZExtValue();
79b7338fb1STyker       Offset = DL.getTypeAllocSize(GTI.getIndexedType()) * ElemCount;
80b7338fb1STyker     }
81b7338fb1STyker     Result = Align(MinAlign(Offset, Result.value()));
82b7338fb1STyker   }
83b7338fb1STyker   return Result;
84b7338fb1STyker }
85b7338fb1STyker 
accumulateConstantOffset(const DataLayout & DL,APInt & Offset,function_ref<bool (Value &,APInt &)> ExternalAnalysis) const86e5780776SKuter Dinel bool GEPOperator::accumulateConstantOffset(
87e5780776SKuter Dinel     const DataLayout &DL, APInt &Offset,
88e5780776SKuter Dinel     function_ref<bool(Value &, APInt &)> ExternalAnalysis) const {
896f0d5224SDavid Blaikie   assert(Offset.getBitWidth() ==
90945b7e5aSElena Demikhovsky              DL.getIndexSizeInBits(getPointerAddressSpace()) &&
91945b7e5aSElena Demikhovsky          "The offset bit width does not match DL specification.");
92*500c4b68SKazu Hirata   SmallVector<const Value *> Index(llvm::drop_begin(operand_values()));
9340862b1aSWilliam S. Moses   return GEPOperator::accumulateConstantOffset(getSourceElementType(), Index,
9440862b1aSWilliam S. Moses                                                DL, Offset, ExternalAnalysis);
9540862b1aSWilliam S. Moses }
966f0d5224SDavid Blaikie 
accumulateConstantOffset(Type * SourceType,ArrayRef<const Value * > Index,const DataLayout & DL,APInt & Offset,function_ref<bool (Value &,APInt &)> ExternalAnalysis)9740862b1aSWilliam S. Moses bool GEPOperator::accumulateConstantOffset(
9840862b1aSWilliam S. Moses     Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL,
9940862b1aSWilliam S. Moses     APInt &Offset, function_ref<bool(Value &, APInt &)> ExternalAnalysis) {
100e5780776SKuter Dinel   bool UsedExternalAnalysis = false;
101e5780776SKuter Dinel   auto AccumulateOffset = [&](APInt Index, uint64_t Size) -> bool {
102e5780776SKuter Dinel     Index = Index.sextOrTrunc(Offset.getBitWidth());
103e5780776SKuter Dinel     APInt IndexedSize = APInt(Offset.getBitWidth(), Size);
104e5780776SKuter Dinel     // For array or vector indices, scale the index by the size of the type.
105e5780776SKuter Dinel     if (!UsedExternalAnalysis) {
106e5780776SKuter Dinel       Offset += Index * IndexedSize;
107e5780776SKuter Dinel     } else {
108e5780776SKuter Dinel       // External Analysis can return a result higher/lower than the value
109e5780776SKuter Dinel       // represents. We need to detect overflow/underflow.
110e5780776SKuter Dinel       bool Overflow = false;
111e5780776SKuter Dinel       APInt OffsetPlus = Index.smul_ov(IndexedSize, Overflow);
112e5780776SKuter Dinel       if (Overflow)
113e5780776SKuter Dinel         return false;
114e5780776SKuter Dinel       Offset = Offset.sadd_ov(OffsetPlus, Overflow);
115e5780776SKuter Dinel       if (Overflow)
116e5780776SKuter Dinel         return false;
117e5780776SKuter Dinel     }
118e5780776SKuter Dinel     return true;
119e5780776SKuter Dinel   };
12040862b1aSWilliam S. Moses   auto begin = generic_gep_type_iterator<decltype(Index.begin())>::begin(
12140862b1aSWilliam S. Moses       SourceType, Index.begin());
12240862b1aSWilliam S. Moses   auto end = generic_gep_type_iterator<decltype(Index.end())>::end(Index.end());
12340862b1aSWilliam S. Moses   for (auto GTI = begin, GTE = end; GTI != GTE; ++GTI) {
124e5780776SKuter Dinel     // Scalable vectors are multiplied by a runtime constant.
125e5780776SKuter Dinel     bool ScalableType = false;
1263ecced16SChristopher Tetreault     if (isa<ScalableVectorType>(GTI.getIndexedType()))
127e5780776SKuter Dinel       ScalableType = true;
128ef64ba83SSander de Smalen 
129e5780776SKuter Dinel     Value *V = GTI.getOperand();
130e5780776SKuter Dinel     StructType *STy = GTI.getStructTypeOrNull();
131e5780776SKuter Dinel     // Handle ConstantInt if possible.
132e5780776SKuter Dinel     if (auto ConstOffset = dyn_cast<ConstantInt>(V)) {
133e5780776SKuter Dinel       if (ConstOffset->isZero())
134e5780776SKuter Dinel         continue;
135e5780776SKuter Dinel       // if the type is scalable and the constant is not zero (vscale * n * 0 =
136e5780776SKuter Dinel       // 0) bailout.
137e5780776SKuter Dinel       if (ScalableType)
138e5780776SKuter Dinel         return false;
1396f0d5224SDavid Blaikie       // Handle a struct index, which adds its field offset to the pointer.
140e5780776SKuter Dinel       if (STy) {
141e5780776SKuter Dinel         unsigned ElementIdx = ConstOffset->getZExtValue();
1426f0d5224SDavid Blaikie         const StructLayout *SL = DL.getStructLayout(STy);
143e5780776SKuter Dinel         // Element offset is in bytes.
144e5780776SKuter Dinel         if (!AccumulateOffset(
145e5780776SKuter Dinel                 APInt(Offset.getBitWidth(), SL->getElementOffset(ElementIdx)),
146e5780776SKuter Dinel                 1))
147e5780776SKuter Dinel           return false;
148e5780776SKuter Dinel         continue;
149e5780776SKuter Dinel       }
150e5780776SKuter Dinel       if (!AccumulateOffset(ConstOffset->getValue(),
151e5780776SKuter Dinel                             DL.getTypeAllocSize(GTI.getIndexedType())))
152e5780776SKuter Dinel         return false;
1536f0d5224SDavid Blaikie       continue;
1546f0d5224SDavid Blaikie     }
1556f0d5224SDavid Blaikie 
156e5780776SKuter Dinel     // The operand is not constant, check if an external analysis was provided.
157e5780776SKuter Dinel     // External analsis is not applicable to a struct type.
158e5780776SKuter Dinel     if (!ExternalAnalysis || STy || ScalableType)
159e5780776SKuter Dinel       return false;
160e5780776SKuter Dinel     APInt AnalysisIndex;
161e5780776SKuter Dinel     if (!ExternalAnalysis(*V, AnalysisIndex))
162e5780776SKuter Dinel       return false;
163e5780776SKuter Dinel     UsedExternalAnalysis = true;
164e5780776SKuter Dinel     if (!AccumulateOffset(AnalysisIndex,
165e5780776SKuter Dinel                           DL.getTypeAllocSize(GTI.getIndexedType())))
166e5780776SKuter Dinel       return false;
1676f0d5224SDavid Blaikie   }
1686f0d5224SDavid Blaikie   return true;
1696f0d5224SDavid Blaikie }
170c7270567SStephen Tozer 
collectOffset(const DataLayout & DL,unsigned BitWidth,MapVector<Value *,APInt> & VariableOffsets,APInt & ConstantOffset) const171c7270567SStephen Tozer bool GEPOperator::collectOffset(
172c7270567SStephen Tozer     const DataLayout &DL, unsigned BitWidth,
173c7270567SStephen Tozer     MapVector<Value *, APInt> &VariableOffsets,
174c7270567SStephen Tozer     APInt &ConstantOffset) const {
175c7270567SStephen Tozer   assert(BitWidth == DL.getIndexSizeInBits(getPointerAddressSpace()) &&
176c7270567SStephen Tozer          "The offset bit width does not match DL specification.");
177c7270567SStephen Tozer 
178c7270567SStephen Tozer   auto CollectConstantOffset = [&](APInt Index, uint64_t Size) {
179c7270567SStephen Tozer     Index = Index.sextOrTrunc(BitWidth);
180c7270567SStephen Tozer     APInt IndexedSize = APInt(BitWidth, Size);
181c7270567SStephen Tozer     ConstantOffset += Index * IndexedSize;
182c7270567SStephen Tozer   };
183c7270567SStephen Tozer 
184c7270567SStephen Tozer   for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this);
185c7270567SStephen Tozer        GTI != GTE; ++GTI) {
186c7270567SStephen Tozer     // Scalable vectors are multiplied by a runtime constant.
187c7270567SStephen Tozer     bool ScalableType = isa<ScalableVectorType>(GTI.getIndexedType());
188c7270567SStephen Tozer 
189c7270567SStephen Tozer     Value *V = GTI.getOperand();
190c7270567SStephen Tozer     StructType *STy = GTI.getStructTypeOrNull();
191c7270567SStephen Tozer     // Handle ConstantInt if possible.
192c7270567SStephen Tozer     if (auto ConstOffset = dyn_cast<ConstantInt>(V)) {
193c7270567SStephen Tozer       if (ConstOffset->isZero())
194c7270567SStephen Tozer         continue;
195c7270567SStephen Tozer       // If the type is scalable and the constant is not zero (vscale * n * 0 =
196c7270567SStephen Tozer       // 0) bailout.
197c7270567SStephen Tozer       // TODO: If the runtime value is accessible at any point before DWARF
198c7270567SStephen Tozer       // emission, then we could potentially keep a forward reference to it
199c7270567SStephen Tozer       // in the debug value to be filled in later.
200c7270567SStephen Tozer       if (ScalableType)
201c7270567SStephen Tozer         return false;
202c7270567SStephen Tozer       // Handle a struct index, which adds its field offset to the pointer.
203c7270567SStephen Tozer       if (STy) {
204c7270567SStephen Tozer         unsigned ElementIdx = ConstOffset->getZExtValue();
205c7270567SStephen Tozer         const StructLayout *SL = DL.getStructLayout(STy);
206c7270567SStephen Tozer         // Element offset is in bytes.
207c7270567SStephen Tozer         CollectConstantOffset(APInt(BitWidth, SL->getElementOffset(ElementIdx)),
208c7270567SStephen Tozer                               1);
209c7270567SStephen Tozer         continue;
210c7270567SStephen Tozer       }
211c7270567SStephen Tozer       CollectConstantOffset(ConstOffset->getValue(),
212c7270567SStephen Tozer                             DL.getTypeAllocSize(GTI.getIndexedType()));
213c7270567SStephen Tozer       continue;
214c7270567SStephen Tozer     }
215c7270567SStephen Tozer 
216c7270567SStephen Tozer     if (STy || ScalableType)
217c7270567SStephen Tozer       return false;
218c7270567SStephen Tozer     APInt IndexedSize =
219c7270567SStephen Tozer         APInt(BitWidth, DL.getTypeAllocSize(GTI.getIndexedType()));
220b9ca73e1SStephen Tozer     // Insert an initial offset of 0 for V iff none exists already, then
221b9ca73e1SStephen Tozer     // increment the offset by IndexedSize.
222b9ca73e1SStephen Tozer     if (!IndexedSize.isZero()) {
223b9ca73e1SStephen Tozer       VariableOffsets.insert({V, APInt(BitWidth, 0)});
224c7270567SStephen Tozer       VariableOffsets[V] += IndexedSize;
225c7270567SStephen Tozer     }
226b9ca73e1SStephen Tozer   }
227c7270567SStephen Tozer   return true;
228c7270567SStephen Tozer }
22999107401SRosie Sumpter 
print(raw_ostream & O) const23099107401SRosie Sumpter void FastMathFlags::print(raw_ostream &O) const {
23199107401SRosie Sumpter   if (all())
23299107401SRosie Sumpter     O << " fast";
23399107401SRosie Sumpter   else {
23499107401SRosie Sumpter     if (allowReassoc())
23599107401SRosie Sumpter       O << " reassoc";
23699107401SRosie Sumpter     if (noNaNs())
23799107401SRosie Sumpter       O << " nnan";
23899107401SRosie Sumpter     if (noInfs())
23999107401SRosie Sumpter       O << " ninf";
24099107401SRosie Sumpter     if (noSignedZeros())
24199107401SRosie Sumpter       O << " nsz";
24299107401SRosie Sumpter     if (allowReciprocal())
24399107401SRosie Sumpter       O << " arcp";
24499107401SRosie Sumpter     if (allowContract())
24599107401SRosie Sumpter       O << " contract";
24699107401SRosie Sumpter     if (approxFunc())
24799107401SRosie Sumpter       O << " afn";
24899107401SRosie Sumpter   }
24999107401SRosie Sumpter }
2508b52037cSSimon Pilgrim } // namespace llvm
251