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