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 #include "llvm/IR/Type.h"
18 
19 #include "ConstantsContext.h"
20 
21 namespace llvm {
22 Type *GEPOperator::getSourceElementType() const {
23   if (auto *I = dyn_cast<GetElementPtrInst>(this))
24     return I->getSourceElementType();
25   return cast<GetElementPtrConstantExpr>(this)->getSourceElementType();
26 }
27 
28 Type *GEPOperator::getResultElementType() const {
29   if (auto *I = dyn_cast<GetElementPtrInst>(this))
30     return I->getResultElementType();
31   return cast<GetElementPtrConstantExpr>(this)->getResultElementType();
32 }
33 
34 bool GEPOperator::accumulateConstantOffset(
35     const DataLayout &DL, APInt &Offset,
36     function_ref<bool(Value &, APInt &)> ExternalAnalysis) const {
37    assert(Offset.getBitWidth() ==
38               DL.getIndexSizeInBits(getPointerAddressSpace()) &&
39           "The offset bit width does not match DL specification.");
40 
41   bool UsedExternalAnalysis = false;
42   auto AccumulateOffset = [&](APInt Index, uint64_t Size) -> bool {
43     Index = Index.sextOrTrunc(Offset.getBitWidth());
44     APInt IndexedSize = APInt(Offset.getBitWidth(), Size);
45     // For array or vector indices, scale the index by the size of the type.
46     if (!UsedExternalAnalysis) {
47       Offset += Index * IndexedSize;
48     } else {
49       // External Analysis can return a result higher/lower than the value
50       // represents. We need to detect overflow/underflow.
51       bool Overflow = false;
52       APInt OffsetPlus = Index.smul_ov(IndexedSize, Overflow);
53       if (Overflow)
54         return false;
55       Offset = Offset.sadd_ov(OffsetPlus, Overflow);
56       if (Overflow)
57         return false;
58     }
59     return true;
60   };
61 
62   for (gep_type_iterator GTI = gep_type_begin(this), GTE = gep_type_end(this);
63        GTI != GTE; ++GTI) {
64     // Scalable vectors are multiplied by a runtime constant.
65     bool ScalableType = false;
66     if (isa<ScalableVectorType>(GTI.getIndexedType()))
67       ScalableType = true;
68 
69     Value *V = GTI.getOperand();
70     StructType *STy = GTI.getStructTypeOrNull();
71     // Handle ConstantInt if possible.
72     if (auto ConstOffset = dyn_cast<ConstantInt>(V)) {
73       if (ConstOffset->isZero())
74         continue;
75       // if the type is scalable and the constant is not zero (vscale * n * 0 =
76       // 0) bailout.
77       if (ScalableType)
78         return false;
79       // Handle a struct index, which adds its field offset to the pointer.
80       if (STy) {
81         unsigned ElementIdx = ConstOffset->getZExtValue();
82         const StructLayout *SL = DL.getStructLayout(STy);
83         // Element offset is in bytes.
84         if (!AccumulateOffset(
85                 APInt(Offset.getBitWidth(), SL->getElementOffset(ElementIdx)),
86                 1))
87           return false;
88         continue;
89       }
90       if (!AccumulateOffset(ConstOffset->getValue(),
91                             DL.getTypeAllocSize(GTI.getIndexedType())))
92         return false;
93       continue;
94     }
95 
96     // The operand is not constant, check if an external analysis was provided.
97     // External analsis is not applicable to a struct type.
98     if (!ExternalAnalysis || STy || ScalableType)
99       return false;
100     APInt AnalysisIndex;
101     if (!ExternalAnalysis(*V, AnalysisIndex))
102       return false;
103     UsedExternalAnalysis = true;
104     if (!AccumulateOffset(AnalysisIndex,
105                           DL.getTypeAllocSize(GTI.getIndexedType())))
106       return false;
107   }
108   return true;
109 }
110 }
111