brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.4 KiB · c3e54a0 Raw
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