xref: /src/contrib/llvm-project/llvm/lib/Analysis/Local.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1e3b55780SDimitry Andric //===- Local.cpp - Functions to perform local transformations -------------===//
2e3b55780SDimitry Andric //
3e3b55780SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e3b55780SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e3b55780SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e3b55780SDimitry Andric //
7e3b55780SDimitry Andric //===----------------------------------------------------------------------===//
8e3b55780SDimitry Andric //
9e3b55780SDimitry Andric // This family of functions perform various local transformations to the
10e3b55780SDimitry Andric // program.
11e3b55780SDimitry Andric //
12e3b55780SDimitry Andric //===----------------------------------------------------------------------===//
13e3b55780SDimitry Andric 
14e3b55780SDimitry Andric #include "llvm/Analysis/Utils/Local.h"
15e3b55780SDimitry Andric #include "llvm/ADT/Twine.h"
16e3b55780SDimitry Andric #include "llvm/IR/DataLayout.h"
17e3b55780SDimitry Andric #include "llvm/IR/GetElementPtrTypeIterator.h"
18e3b55780SDimitry Andric #include "llvm/IR/IRBuilder.h"
19e3b55780SDimitry Andric 
20e3b55780SDimitry Andric using namespace llvm;
21e3b55780SDimitry Andric 
emitGEPOffset(IRBuilderBase * Builder,const DataLayout & DL,User * GEP,bool NoAssumptions)22e3b55780SDimitry Andric Value *llvm::emitGEPOffset(IRBuilderBase *Builder, const DataLayout &DL,
23e3b55780SDimitry Andric                            User *GEP, bool NoAssumptions) {
24e3b55780SDimitry Andric   GEPOperator *GEPOp = cast<GEPOperator>(GEP);
25e3b55780SDimitry Andric   Type *IntIdxTy = DL.getIndexType(GEP->getType());
26e3b55780SDimitry Andric   Value *Result = nullptr;
27e3b55780SDimitry Andric 
28ac9a064cSDimitry Andric   // nusw implies nsw for the offset arithmetic.
29ac9a064cSDimitry Andric   bool NSW = GEPOp->hasNoUnsignedSignedWrap() && !NoAssumptions;
30ac9a064cSDimitry Andric   bool NUW = GEPOp->hasNoUnsignedWrap() && !NoAssumptions;
31b1c73532SDimitry Andric   auto AddOffset = [&](Value *Offset) {
32b1c73532SDimitry Andric     if (Result)
33b1c73532SDimitry Andric       Result = Builder->CreateAdd(Result, Offset, GEP->getName() + ".offs",
34ac9a064cSDimitry Andric                                   NUW, NSW);
35b1c73532SDimitry Andric     else
36b1c73532SDimitry Andric       Result = Offset;
37b1c73532SDimitry Andric   };
38e3b55780SDimitry Andric 
39e3b55780SDimitry Andric   gep_type_iterator GTI = gep_type_begin(GEP);
40e3b55780SDimitry Andric   for (User::op_iterator i = GEP->op_begin() + 1, e = GEP->op_end(); i != e;
41e3b55780SDimitry Andric        ++i, ++GTI) {
42e3b55780SDimitry Andric     Value *Op = *i;
43e3b55780SDimitry Andric     if (Constant *OpC = dyn_cast<Constant>(Op)) {
44e3b55780SDimitry Andric       if (OpC->isZeroValue())
45e3b55780SDimitry Andric         continue;
46e3b55780SDimitry Andric 
47e3b55780SDimitry Andric       // Handle a struct index, which adds its field offset to the pointer.
48e3b55780SDimitry Andric       if (StructType *STy = GTI.getStructTypeOrNull()) {
49e3b55780SDimitry Andric         uint64_t OpValue = OpC->getUniqueInteger().getZExtValue();
50b1c73532SDimitry Andric         uint64_t Size = DL.getStructLayout(STy)->getElementOffset(OpValue);
51e3b55780SDimitry Andric         if (!Size)
52e3b55780SDimitry Andric           continue;
53e3b55780SDimitry Andric 
54b1c73532SDimitry Andric         AddOffset(ConstantInt::get(IntIdxTy, Size));
55b1c73532SDimitry Andric         continue;
56e3b55780SDimitry Andric       }
57b1c73532SDimitry Andric     }
58b1c73532SDimitry Andric 
59e3b55780SDimitry Andric     // Splat the index if needed.
60e3b55780SDimitry Andric     if (IntIdxTy->isVectorTy() && !Op->getType()->isVectorTy())
61e3b55780SDimitry Andric       Op = Builder->CreateVectorSplat(
62b1c73532SDimitry Andric           cast<VectorType>(IntIdxTy)->getElementCount(), Op);
63e3b55780SDimitry Andric 
64e3b55780SDimitry Andric     // Convert to correct type.
65e3b55780SDimitry Andric     if (Op->getType() != IntIdxTy)
66e3b55780SDimitry Andric       Op = Builder->CreateIntCast(Op, IntIdxTy, true, Op->getName() + ".c");
67aca2e42cSDimitry Andric     TypeSize TSize = GTI.getSequentialElementStride(DL);
68b1c73532SDimitry Andric     if (TSize != TypeSize::getFixed(1)) {
69b1c73532SDimitry Andric       Value *Scale = Builder->CreateTypeSize(IntIdxTy->getScalarType(), TSize);
70b1c73532SDimitry Andric       if (IntIdxTy->isVectorTy())
71b1c73532SDimitry Andric         Scale = Builder->CreateVectorSplat(
72b1c73532SDimitry Andric             cast<VectorType>(IntIdxTy)->getElementCount(), Scale);
73e3b55780SDimitry Andric       // We'll let instcombine(mul) convert this to a shl if possible.
74ac9a064cSDimitry Andric       Op = Builder->CreateMul(Op, Scale, GEP->getName() + ".idx", NUW, NSW);
75e3b55780SDimitry Andric     }
76b1c73532SDimitry Andric     AddOffset(Op);
77e3b55780SDimitry Andric   }
78e3b55780SDimitry Andric   return Result ? Result : Constant::getNullValue(IntIdxTy);
79e3b55780SDimitry Andric }
80