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