10b57cec5SDimitry Andric //===-- Operator.cpp - Implement the LLVM operators -----------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the non-inline methods for the LLVM Operator classes. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/IR/Operator.h" 140b57cec5SDimitry Andric #include "llvm/IR/DataLayout.h" 150b57cec5SDimitry Andric #include "llvm/IR/GetElementPtrTypeIterator.h" 160b57cec5SDimitry Andric #include "llvm/IR/Instructions.h" 170b57cec5SDimitry Andric #include "llvm/IR/Type.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #include "ConstantsContext.h" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric namespace llvm { 220b57cec5SDimitry Andric Type *GEPOperator::getSourceElementType() const { 230b57cec5SDimitry Andric if (auto *I = dyn_cast<GetElementPtrInst>(this)) 240b57cec5SDimitry Andric return I->getSourceElementType(); 250b57cec5SDimitry Andric return cast<GetElementPtrConstantExpr>(this)->getSourceElementType(); 260b57cec5SDimitry Andric } 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric Type *GEPOperator::getResultElementType() const { 290b57cec5SDimitry Andric if (auto *I = dyn_cast<GetElementPtrInst>(this)) 300b57cec5SDimitry Andric return I->getResultElementType(); 310b57cec5SDimitry Andric return cast<GetElementPtrConstantExpr>(this)->getResultElementType(); 320b57cec5SDimitry Andric } 330b57cec5SDimitry Andric 345ffd83dbSDimitry Andric Align GEPOperator::getMaxPreservedAlignment(const DataLayout &DL) const { 355ffd83dbSDimitry Andric /// compute the worse possible offset for every level of the GEP et accumulate 365ffd83dbSDimitry Andric /// the minimum alignment into Result. 375ffd83dbSDimitry Andric 385ffd83dbSDimitry Andric Align Result = Align(llvm::Value::MaximumAlignment); 395ffd83dbSDimitry Andric for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this); 405ffd83dbSDimitry Andric GTI != GTE; ++GTI) { 415ffd83dbSDimitry Andric int64_t Offset = 1; 425ffd83dbSDimitry Andric ConstantInt *OpC = dyn_cast<ConstantInt>(GTI.getOperand()); 435ffd83dbSDimitry Andric 445ffd83dbSDimitry Andric if (StructType *STy = GTI.getStructTypeOrNull()) { 455ffd83dbSDimitry Andric const StructLayout *SL = DL.getStructLayout(STy); 465ffd83dbSDimitry Andric Offset = SL->getElementOffset(OpC->getZExtValue()); 475ffd83dbSDimitry Andric } else { 485ffd83dbSDimitry Andric assert(GTI.isSequential() && "should be sequencial"); 495ffd83dbSDimitry Andric /// If the index isn't know we take 1 because it is the index that will 505ffd83dbSDimitry Andric /// give the worse alignment of the offset. 515ffd83dbSDimitry Andric int64_t ElemCount = 1; 525ffd83dbSDimitry Andric if (OpC) 535ffd83dbSDimitry Andric ElemCount = OpC->getZExtValue(); 545ffd83dbSDimitry Andric Offset = DL.getTypeAllocSize(GTI.getIndexedType()) * ElemCount; 555ffd83dbSDimitry Andric } 565ffd83dbSDimitry Andric Result = Align(MinAlign(Offset, Result.value())); 575ffd83dbSDimitry Andric } 585ffd83dbSDimitry Andric return Result; 595ffd83dbSDimitry Andric } 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric bool GEPOperator::accumulateConstantOffset( 625ffd83dbSDimitry Andric const DataLayout &DL, APInt &Offset, 635ffd83dbSDimitry Andric function_ref<bool(Value &, APInt &)> ExternalAnalysis) const { 640b57cec5SDimitry Andric assert(Offset.getBitWidth() == 650b57cec5SDimitry Andric DL.getIndexSizeInBits(getPointerAddressSpace()) && 660b57cec5SDimitry Andric "The offset bit width does not match DL specification."); 67d409305fSDimitry Andric SmallVector<const Value *> Index(value_op_begin() + 1, value_op_end()); 68d409305fSDimitry Andric return GEPOperator::accumulateConstantOffset(getSourceElementType(), Index, 69d409305fSDimitry Andric DL, Offset, ExternalAnalysis); 70d409305fSDimitry Andric } 710b57cec5SDimitry Andric 72d409305fSDimitry Andric bool GEPOperator::accumulateConstantOffset( 73d409305fSDimitry Andric Type *SourceType, ArrayRef<const Value *> Index, const DataLayout &DL, 74d409305fSDimitry Andric APInt &Offset, function_ref<bool(Value &, APInt &)> ExternalAnalysis) { 755ffd83dbSDimitry Andric bool UsedExternalAnalysis = false; 765ffd83dbSDimitry Andric auto AccumulateOffset = [&](APInt Index, uint64_t Size) -> bool { 775ffd83dbSDimitry Andric Index = Index.sextOrTrunc(Offset.getBitWidth()); 785ffd83dbSDimitry Andric APInt IndexedSize = APInt(Offset.getBitWidth(), Size); 795ffd83dbSDimitry Andric // For array or vector indices, scale the index by the size of the type. 805ffd83dbSDimitry Andric if (!UsedExternalAnalysis) { 815ffd83dbSDimitry Andric Offset += Index * IndexedSize; 825ffd83dbSDimitry Andric } else { 835ffd83dbSDimitry Andric // External Analysis can return a result higher/lower than the value 845ffd83dbSDimitry Andric // represents. We need to detect overflow/underflow. 855ffd83dbSDimitry Andric bool Overflow = false; 865ffd83dbSDimitry Andric APInt OffsetPlus = Index.smul_ov(IndexedSize, Overflow); 875ffd83dbSDimitry Andric if (Overflow) 885ffd83dbSDimitry Andric return false; 895ffd83dbSDimitry Andric Offset = Offset.sadd_ov(OffsetPlus, Overflow); 905ffd83dbSDimitry Andric if (Overflow) 915ffd83dbSDimitry Andric return false; 925ffd83dbSDimitry Andric } 935ffd83dbSDimitry Andric return true; 945ffd83dbSDimitry Andric }; 95d409305fSDimitry Andric auto begin = generic_gep_type_iterator<decltype(Index.begin())>::begin( 96d409305fSDimitry Andric SourceType, Index.begin()); 97d409305fSDimitry Andric auto end = generic_gep_type_iterator<decltype(Index.end())>::end(Index.end()); 98d409305fSDimitry Andric for (auto GTI = begin, GTE = end; GTI != GTE; ++GTI) { 995ffd83dbSDimitry Andric // Scalable vectors are multiplied by a runtime constant. 1005ffd83dbSDimitry Andric bool ScalableType = false; 1015ffd83dbSDimitry Andric if (isa<ScalableVectorType>(GTI.getIndexedType())) 1025ffd83dbSDimitry Andric ScalableType = true; 1030b57cec5SDimitry Andric 1045ffd83dbSDimitry Andric Value *V = GTI.getOperand(); 1055ffd83dbSDimitry Andric StructType *STy = GTI.getStructTypeOrNull(); 1065ffd83dbSDimitry Andric // Handle ConstantInt if possible. 1075ffd83dbSDimitry Andric if (auto ConstOffset = dyn_cast<ConstantInt>(V)) { 1085ffd83dbSDimitry Andric if (ConstOffset->isZero()) 1095ffd83dbSDimitry Andric continue; 1105ffd83dbSDimitry Andric // if the type is scalable and the constant is not zero (vscale * n * 0 = 1115ffd83dbSDimitry Andric // 0) bailout. 1125ffd83dbSDimitry Andric if (ScalableType) 1135ffd83dbSDimitry Andric return false; 1140b57cec5SDimitry Andric // Handle a struct index, which adds its field offset to the pointer. 1155ffd83dbSDimitry Andric if (STy) { 1165ffd83dbSDimitry Andric unsigned ElementIdx = ConstOffset->getZExtValue(); 1170b57cec5SDimitry Andric const StructLayout *SL = DL.getStructLayout(STy); 1185ffd83dbSDimitry Andric // Element offset is in bytes. 1195ffd83dbSDimitry Andric if (!AccumulateOffset( 1205ffd83dbSDimitry Andric APInt(Offset.getBitWidth(), SL->getElementOffset(ElementIdx)), 1215ffd83dbSDimitry Andric 1)) 1225ffd83dbSDimitry Andric return false; 1235ffd83dbSDimitry Andric continue; 1245ffd83dbSDimitry Andric } 1255ffd83dbSDimitry Andric if (!AccumulateOffset(ConstOffset->getValue(), 1265ffd83dbSDimitry Andric DL.getTypeAllocSize(GTI.getIndexedType()))) 1275ffd83dbSDimitry Andric return false; 1280b57cec5SDimitry Andric continue; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1315ffd83dbSDimitry Andric // The operand is not constant, check if an external analysis was provided. 1325ffd83dbSDimitry Andric // External analsis is not applicable to a struct type. 1335ffd83dbSDimitry Andric if (!ExternalAnalysis || STy || ScalableType) 1345ffd83dbSDimitry Andric return false; 1355ffd83dbSDimitry Andric APInt AnalysisIndex; 1365ffd83dbSDimitry Andric if (!ExternalAnalysis(*V, AnalysisIndex)) 1375ffd83dbSDimitry Andric return false; 1385ffd83dbSDimitry Andric UsedExternalAnalysis = true; 1395ffd83dbSDimitry Andric if (!AccumulateOffset(AnalysisIndex, 1405ffd83dbSDimitry Andric DL.getTypeAllocSize(GTI.getIndexedType()))) 1415ffd83dbSDimitry Andric return false; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric return true; 1440b57cec5SDimitry Andric } 145fe6060f1SDimitry Andric 146fe6060f1SDimitry Andric bool GEPOperator::collectOffset( 147fe6060f1SDimitry Andric const DataLayout &DL, unsigned BitWidth, 148fe6060f1SDimitry Andric MapVector<Value *, APInt> &VariableOffsets, 149fe6060f1SDimitry Andric APInt &ConstantOffset) const { 150fe6060f1SDimitry Andric assert(BitWidth == DL.getIndexSizeInBits(getPointerAddressSpace()) && 151fe6060f1SDimitry Andric "The offset bit width does not match DL specification."); 152fe6060f1SDimitry Andric 153fe6060f1SDimitry Andric auto CollectConstantOffset = [&](APInt Index, uint64_t Size) { 154fe6060f1SDimitry Andric Index = Index.sextOrTrunc(BitWidth); 155fe6060f1SDimitry Andric APInt IndexedSize = APInt(BitWidth, Size); 156fe6060f1SDimitry Andric ConstantOffset += Index * IndexedSize; 157fe6060f1SDimitry Andric }; 158fe6060f1SDimitry Andric 159fe6060f1SDimitry Andric for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this); 160fe6060f1SDimitry Andric GTI != GTE; ++GTI) { 161fe6060f1SDimitry Andric // Scalable vectors are multiplied by a runtime constant. 162fe6060f1SDimitry Andric bool ScalableType = isa<ScalableVectorType>(GTI.getIndexedType()); 163fe6060f1SDimitry Andric 164fe6060f1SDimitry Andric Value *V = GTI.getOperand(); 165fe6060f1SDimitry Andric StructType *STy = GTI.getStructTypeOrNull(); 166fe6060f1SDimitry Andric // Handle ConstantInt if possible. 167fe6060f1SDimitry Andric if (auto ConstOffset = dyn_cast<ConstantInt>(V)) { 168fe6060f1SDimitry Andric if (ConstOffset->isZero()) 169fe6060f1SDimitry Andric continue; 170fe6060f1SDimitry Andric // If the type is scalable and the constant is not zero (vscale * n * 0 = 171fe6060f1SDimitry Andric // 0) bailout. 172fe6060f1SDimitry Andric // TODO: If the runtime value is accessible at any point before DWARF 173fe6060f1SDimitry Andric // emission, then we could potentially keep a forward reference to it 174fe6060f1SDimitry Andric // in the debug value to be filled in later. 175fe6060f1SDimitry Andric if (ScalableType) 176fe6060f1SDimitry Andric return false; 177fe6060f1SDimitry Andric // Handle a struct index, which adds its field offset to the pointer. 178fe6060f1SDimitry Andric if (STy) { 179fe6060f1SDimitry Andric unsigned ElementIdx = ConstOffset->getZExtValue(); 180fe6060f1SDimitry Andric const StructLayout *SL = DL.getStructLayout(STy); 181fe6060f1SDimitry Andric // Element offset is in bytes. 182fe6060f1SDimitry Andric CollectConstantOffset(APInt(BitWidth, SL->getElementOffset(ElementIdx)), 183fe6060f1SDimitry Andric 1); 184fe6060f1SDimitry Andric continue; 185fe6060f1SDimitry Andric } 186fe6060f1SDimitry Andric CollectConstantOffset(ConstOffset->getValue(), 187fe6060f1SDimitry Andric DL.getTypeAllocSize(GTI.getIndexedType())); 188fe6060f1SDimitry Andric continue; 189fe6060f1SDimitry Andric } 190fe6060f1SDimitry Andric 191fe6060f1SDimitry Andric if (STy || ScalableType) 192fe6060f1SDimitry Andric return false; 193fe6060f1SDimitry Andric APInt IndexedSize = 194fe6060f1SDimitry Andric APInt(BitWidth, DL.getTypeAllocSize(GTI.getIndexedType())); 195*1b3bef43SDimitry Andric // Insert an initial offset of 0 for V iff none exists already, then 196*1b3bef43SDimitry Andric // increment the offset by IndexedSize. 197*1b3bef43SDimitry Andric if (!IndexedSize.isZero()) { 198*1b3bef43SDimitry Andric VariableOffsets.insert({V, APInt(BitWidth, 0)}); 199fe6060f1SDimitry Andric VariableOffsets[V] += IndexedSize; 200fe6060f1SDimitry Andric } 201*1b3bef43SDimitry Andric } 202fe6060f1SDimitry Andric return true; 203fe6060f1SDimitry Andric } 2045ffd83dbSDimitry Andric } // namespace llvm 205