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