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