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