1d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar/*
2d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * Copyright 2016, The Android Open Source Project
3d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar *
4d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * Licensed under the Apache License, Version 2.0 (the "License");
5d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * you may not use this file except in compliance with the License.
6d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * You may obtain a copy of the License at
7d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar *
8d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar *     http://www.apache.org/licenses/LICENSE-2.0
9d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar *
10d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * Unless required by applicable law or agreed to in writing, software
11d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * distributed under the License is distributed on an "AS IS" BASIS,
12d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * See the License for the specific language governing permissions and
14d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * limitations under the License.
15d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar */
16d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
17a2dd52f0710c214e00c1a13e25116e1af5eec77aJean-Luc Brouillet#include "bcc/Config.h"
18a2dd52f0710c214e00c1a13e25116e1af5eec77aJean-Luc Brouillet#include "Assert.h"
19a2dd52f0710c214e00c1a13e25116e1af5eec77aJean-Luc Brouillet#include "Log.h"
20a2dd52f0710c214e00c1a13e25116e1af5eec77aJean-Luc Brouillet#include "RSTransforms.h"
21d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
22d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar#include <cstdlib>
23d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
24d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar#include <llvm/IR/Function.h>
25d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar#include <llvm/IR/Instructions.h>
26d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar#include <llvm/IR/Module.h>
27d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar#include <llvm/Pass.h>
28d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar#include <llvm/IR/GetElementPtrTypeIterator.h>
29d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
30d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainarnamespace { // anonymous namespace
31d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
32d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar/* This pass translates GEPs that index into structs or arrays of structs to
33d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * GEPs with an int8* operand and a byte offset.  This translation is done to
34d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * enforce on x86 the ARM alignment rule that 64-bit scalars be 8-byte aligned
35d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar * for structs with such scalars.
36d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar */
37d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainarclass RSX86TranslateGEPPass : public llvm::FunctionPass {
38d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainarprivate:
39d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  static char ID;
40d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  llvm::LLVMContext *Context;
41d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  const llvm::DataLayout DL;
42d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
43d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // Walk a GEP instruction and return true if any type indexed is a struct.
44d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  bool GEPIndexesStructType(const llvm::GetElementPtrInst *GEP) {
45d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    for (llvm::gep_type_iterator GTI = gep_type_begin(GEP),
46d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                 GTE = gep_type_end(GEP);
47d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar         GTI != GTE; ++GTI) {
48d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      if (llvm::dyn_cast<llvm::StructType>(*GTI)) {
49d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        return true;
50d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      }
51d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    }
52d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    return false;
53d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
54d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
55d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // Helper method to add two llvm::Value parameters
56d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  llvm::Value *incrementOffset(llvm::Value *accum, llvm::Value *incr,
57d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                               llvm::Instruction *InsertBefore) {
58d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    if (accum == nullptr)
59d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      return incr;
60d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    return llvm::BinaryOperator::CreateAdd(accum, incr, "", InsertBefore);
61d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
62d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
63d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // Compute the byte offset for a GEP from the GEP's base pointer operand.
64d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // Based on visitGetElementPtrInst in llvm/lib/Transforms/Scalar/SROA.cpp.
65d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // The difference is that this function handles non-constant array indices and
66d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // constructs a sequence of instructions to calculate the offset.  These
67d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // instructions might not be the most efficient way to calculate this offset,
68d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  // but we rely on subsequent optimizations to do necessary fold/combine.
69d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  llvm::Value *computeGEPOffset(llvm::GetElementPtrInst *GEP) {
70d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    llvm::Value *Offset = nullptr;
71d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
72d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    for (llvm::gep_type_iterator GTI = gep_type_begin(GEP),
73d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                 GTE = gep_type_end(GEP);
74d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar         GTI != GTE; ++GTI) {
75d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      if (llvm::StructType *STy = llvm::dyn_cast<llvm::StructType>(*GTI)) {
76d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        llvm::ConstantInt *OpC = llvm::dyn_cast<llvm::ConstantInt>(GTI.getOperand());
77d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        if (!OpC) {
78d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar          ALOGE("Operand for struct type is not constant!");
79d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar          bccAssert(false);
80d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        }
81d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
82d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        // Offset = Offset + EltOffset for index into a struct
83d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        const llvm::StructLayout *SL = DL.getStructLayout(STy);
84d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        unsigned EltOffset = SL->getElementOffset(OpC->getZExtValue());
85d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        llvm::Value *Incr = llvm::ConstantInt::get(
86d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                llvm::Type::getInt32Ty(*Context), EltOffset);
87d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        Offset = incrementOffset(Offset, Incr, GEP);
88d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      } else {
89d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        // Offset = Offset + Index * EltSize for index into an array or a vector
90d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        llvm::Value *EltSize = llvm::ConstantInt::get(
91d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                 llvm::Type::getInt32Ty(*Context),
92d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                 DL.getTypeAllocSize(GTI.getIndexedType()));
93d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        llvm::Value *Incr = llvm::BinaryOperator::CreateMul(
94d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                GTI.getOperand() /* Index */,
95d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                EltSize, "", GEP);
96d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        Offset = incrementOffset(Offset, Incr, GEP);
97d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      }
98d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    }
99d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
100d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    return Offset;
101d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
102d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
103d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  void translateGEP(llvm::GetElementPtrInst *GEP) {
104d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // cast GEP pointer operand to int8*
105d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    llvm::CastInst *Int8Ptr = llvm::CastInst::CreatePointerCast(
106d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                  GEP->getPointerOperand(),
107d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                  llvm::Type::getInt8PtrTy(*Context),
108d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                  "to.int8ptr",
109d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar                                  GEP);
110d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    llvm::Value *Indices[1] = {computeGEPOffset(GEP)};
111d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
112d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // index into the int8* based on the byte offset
113d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    llvm::GetElementPtrInst *Int8PtrGEP = llvm::GetElementPtrInst::Create(
114d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        llvm::Type::getInt8Ty(*Context), Int8Ptr, llvm::makeArrayRef(Indices),
115d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        "int8ptr.indexed", GEP);
116d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    Int8PtrGEP->setIsInBounds(GEP->isInBounds());
117d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
118d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // cast the indexed int8* back to the type of the original GEP
119d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    llvm::CastInst *OutCast = llvm::CastInst::CreatePointerCast(
120d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        Int8PtrGEP, GEP->getType(), "to.orig.geptype", GEP);
121d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
122d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    GEP->replaceAllUsesWith(OutCast);
123d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
124d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
125d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainarpublic:
126d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  RSX86TranslateGEPPass()
127d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    : FunctionPass (ID), DL(X86_CUSTOM_DL_STRING) {
128d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
129d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
130d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
131d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // This pass is run in isolation in a separate pass manager.  So setting
132d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // AnalysisUsage is unnecessary.  Set just for completeness.
133d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    AU.setPreservesCFG();
134d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
135d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
136d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  virtual bool runOnFunction(llvm::Function &F) override {
137d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    bool changed = false;
138d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    Context = &F.getParent()->getContext();
139d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
140d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // To avoid updating/deleting instructions while walking a BasicBlock's instructions,
141d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // collect the GEPs that need to be translated and process them
142d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    // subsequently.
143d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    std::vector<llvm::GetElementPtrInst *> GEPsToHandle;
144d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
145d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    for (auto &BB: F) {
146d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      for (auto &I: BB) {
147d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        if (auto *GEP = llvm::dyn_cast<llvm::GetElementPtrInst>(&I)) {
148d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar          if (GEPIndexesStructType(GEP)) {
149d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar            GEPsToHandle.push_back(GEP);
150d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar          }
151d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar        }
152d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      }
153d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    }
154d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
155d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    for (auto *GEP: GEPsToHandle) {
156d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      // Translate GEPs and erase them
157d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      translateGEP(GEP);
158d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      changed = true;
159d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar      GEP->eraseFromParent();
160d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    }
161d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
162d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    return changed;
163d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
164d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
165d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  virtual const char *getPassName() const override {
166d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar    return "Translate GEPs on structs, intended for x86 target";
167d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  }
168d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar};
169d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
170d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar}
171d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
172d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainarchar RSX86TranslateGEPPass::ID = 0;
173d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
174d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainarnamespace bcc {
175d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
176d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainarllvm::FunctionPass *
177d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga NainarcreateRSX86TranslateGEPPass() {
178d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar  return new RSX86TranslateGEPPass();
179d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar}
180d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar
181d2d5ee3893220cec256c829a4740a718232f84acPirama Arumuga Nainar}
182