19e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar/*
29e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * Copyright 2016, The Android Open Source Project
39e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar *
49e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * Licensed under the Apache License, Version 2.0 (the "License");
59e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * you may not use this file except in compliance with the License.
69e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * You may obtain a copy of the License at
79e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar *
89e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar *     http://www.apache.org/licenses/LICENSE-2.0
99e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar *
109e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * Unless required by applicable law or agreed to in writing, software
119e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * distributed under the License is distributed on an "AS IS" BASIS,
129e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * See the License for the specific language governing permissions and
149e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * limitations under the License.
159e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar */
169e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
179e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include "bcc/Assert.h"
189e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include "bcc/Config/Config.h"
199e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include "bcc/Support/Log.h"
209e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include "bcc/Renderscript/RSTransforms.h"
219e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
229e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include <cstdlib>
239e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
249e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include <llvm/IR/Function.h>
259e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include <llvm/IR/Instructions.h>
269e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include <llvm/IR/Module.h>
279e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include <llvm/Pass.h>
289e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar#include <llvm/IR/GetElementPtrTypeIterator.h>
299e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
309e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainarnamespace { // anonymous namespace
319e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
329e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar/* This pass translates GEPs that index into structs or arrays of structs to
339e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * GEPs with an int8* operand and a byte offset.  This translation is done to
349e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * enforce on x86 the ARM alignment rule that 64-bit scalars be 8-byte aligned
359e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar * for structs with such scalars.
369e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar */
379e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainarclass RSX86TranslateGEPPass : public llvm::FunctionPass {
389e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainarprivate:
399e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  static char ID;
409e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  llvm::LLVMContext *Context;
419e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  const llvm::DataLayout DL;
429e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
439e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // Walk a GEP instruction and return true if any type indexed is a struct.
449e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  bool GEPIndexesStructType(const llvm::GetElementPtrInst *GEP) {
459e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    for (llvm::gep_type_iterator GTI = gep_type_begin(GEP),
469e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                 GTE = gep_type_end(GEP);
479e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar         GTI != GTE; ++GTI) {
489e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      if (llvm::dyn_cast<llvm::StructType>(*GTI)) {
499e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        return true;
509e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      }
519e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    }
529e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    return false;
539e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
549e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
559e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // Helper method to add two llvm::Value parameters
569e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  llvm::Value *incrementOffset(llvm::Value *accum, llvm::Value *incr,
579e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                               llvm::Instruction *InsertBefore) {
589e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    if (accum == nullptr)
599e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      return incr;
609e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    return llvm::BinaryOperator::CreateAdd(accum, incr, "", InsertBefore);
619e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
629e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
639e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // Compute the byte offset for a GEP from the GEP's base pointer operand.
649e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // Based on visitGetElementPtrInst in llvm/lib/Transforms/Scalar/SROA.cpp.
659e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // The difference is that this function handles non-constant array indices and
669e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // constructs a sequence of instructions to calculate the offset.  These
679e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // instructions might not be the most efficient way to calculate this offset,
689e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  // but we rely on subsequent optimizations to do necessary fold/combine.
699e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  llvm::Value *computeGEPOffset(llvm::GetElementPtrInst *GEP) {
709e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    llvm::Value *Offset = nullptr;
719e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
729e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    for (llvm::gep_type_iterator GTI = gep_type_begin(GEP),
739e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                 GTE = gep_type_end(GEP);
749e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar         GTI != GTE; ++GTI) {
759e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      if (llvm::StructType *STy = llvm::dyn_cast<llvm::StructType>(*GTI)) {
769e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        llvm::ConstantInt *OpC = llvm::dyn_cast<llvm::ConstantInt>(GTI.getOperand());
779e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        if (!OpC) {
789e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar          ALOGE("Operand for struct type is not constant!");
799e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar          bccAssert(false);
809e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        }
819e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
829e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        // Offset = Offset + EltOffset for index into a struct
839e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        const llvm::StructLayout *SL = DL.getStructLayout(STy);
849e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        unsigned EltOffset = SL->getElementOffset(OpC->getZExtValue());
859e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        llvm::Value *Incr = llvm::ConstantInt::get(
869e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                llvm::Type::getInt32Ty(*Context), EltOffset);
879e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        Offset = incrementOffset(Offset, Incr, GEP);
889e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      } else {
899e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        // Offset = Offset + Index * EltSize for index into an array or a vector
909e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        llvm::Value *EltSize = llvm::ConstantInt::get(
919e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                 llvm::Type::getInt32Ty(*Context),
929e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                 DL.getTypeAllocSize(GTI.getIndexedType()));
939e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        llvm::Value *Incr = llvm::BinaryOperator::CreateMul(
949e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                GTI.getOperand() /* Index */,
959e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                EltSize, "", GEP);
969e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        Offset = incrementOffset(Offset, Incr, GEP);
979e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      }
989e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    }
999e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1009e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    return Offset;
1019e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
1029e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1039e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  void translateGEP(llvm::GetElementPtrInst *GEP) {
1049e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // cast GEP pointer operand to int8*
1059e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    llvm::CastInst *Int8Ptr = llvm::CastInst::CreatePointerCast(
1069e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                  GEP->getPointerOperand(),
1079e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                  llvm::Type::getInt8PtrTy(*Context),
1089e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                  "to.int8ptr",
1099e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar                                  GEP);
1109e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    llvm::Value *Indices[1] = {computeGEPOffset(GEP)};
1119e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1129e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // index into the int8* based on the byte offset
1139e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    llvm::GetElementPtrInst *Int8PtrGEP = llvm::GetElementPtrInst::Create(
1149e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        llvm::Type::getInt8Ty(*Context), Int8Ptr, llvm::makeArrayRef(Indices),
1159e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        "int8ptr.indexed", GEP);
1169e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    Int8PtrGEP->setIsInBounds(GEP->isInBounds());
1179e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1189e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // cast the indexed int8* back to the type of the original GEP
1199e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    llvm::CastInst *OutCast = llvm::CastInst::CreatePointerCast(
1209e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        Int8PtrGEP, GEP->getType(), "to.orig.geptype", GEP);
1219e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1229e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    GEP->replaceAllUsesWith(OutCast);
1239e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
1249e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1259e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainarpublic:
1269e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  RSX86TranslateGEPPass()
1279e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    : FunctionPass (ID), DL(X86_CUSTOM_DL_STRING) {
1289e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
1299e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1309e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
1319e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // This pass is run in isolation in a separate pass manager.  So setting
1329e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // AnalysisUsage is unnecessary.  Set just for completeness.
1339e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    AU.setPreservesCFG();
1349e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
1359e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1369e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  virtual bool runOnFunction(llvm::Function &F) override {
1379e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    bool changed = false;
1389e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    Context = &F.getParent()->getContext();
1399e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1409e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // To avoid updating/deleting instructions while walking a BasicBlock's instructions,
1419e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // collect the GEPs that need to be translated and process them
1429e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    // subsequently.
1439e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    std::vector<llvm::GetElementPtrInst *> GEPsToHandle;
1449e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1459e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    for (auto &BB: F) {
1469e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      for (auto &I: BB) {
1479e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        if (auto *GEP = llvm::dyn_cast<llvm::GetElementPtrInst>(&I)) {
1489e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar          if (GEPIndexesStructType(GEP)) {
1499e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar            GEPsToHandle.push_back(GEP);
1509e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar          }
1519e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar        }
1529e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      }
1539e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    }
1549e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1559e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    for (auto *GEP: GEPsToHandle) {
1569e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      // Translate GEPs and erase them
1579e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      translateGEP(GEP);
1589e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      changed = true;
1599e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar      GEP->eraseFromParent();
1609e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    }
1619e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1629e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    return changed;
1639e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
1649e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1659e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  virtual const char *getPassName() const override {
1669e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar    return "Translate GEPs on structs, intended for x86 target";
1679e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  }
1689e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar};
1699e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1709e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar}
1719e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1729e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainarchar RSX86TranslateGEPPass::ID = 0;
1739e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1749e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainarnamespace bcc {
1759e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1769e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainarllvm::FunctionPass *
1779e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga NainarcreateRSX86TranslateGEPPass() {
1789e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar  return new RSX86TranslateGEPPass();
1799e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar}
1809e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar
1819e0f8f0c8965834de02d007bb30e1dc950cf9762Pirama Arumuga Nainar}
182