blob: 0718b6e429b997b6097a1e17b616781d1a912b39 [file] [log] [blame] [edit]
//===- ExpandGetElementPtr.cpp - Expand GetElementPtr into arithmetic------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass expands out GetElementPtr instructions into ptrtoint,
// inttoptr and arithmetic instructions.
//
// This simplifies the language so that the PNaCl translator does not
// need to handle GetElementPtr and struct types as part of a stable
// wire format for PNaCl.
//
// Note that we drop the "inbounds" attribute of GetElementPtr.
//
//===----------------------------------------------------------------------===//
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/NaCl.h"
using namespace llvm;
namespace {
class ExpandGetElementPtr : public BasicBlockPass {
public:
static char ID; // Pass identification, replacement for typeid
ExpandGetElementPtr() : BasicBlockPass(ID) {
initializeExpandGetElementPtrPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnBasicBlock(BasicBlock &BB);
};
}
char ExpandGetElementPtr::ID = 0;
INITIALIZE_PASS(ExpandGetElementPtr, "expand-getelementptr",
"Expand out GetElementPtr instructions into arithmetic",
false, false)
static Value *CastToPtrSize(Value *Val, Instruction *InsertPt,
const DebugLoc &Debug, Type *PtrType) {
unsigned ValSize = Val->getType()->getIntegerBitWidth();
unsigned PtrSize = PtrType->getIntegerBitWidth();
if (ValSize == PtrSize)
return Val;
Instruction *Inst;
if (ValSize > PtrSize) {
Inst = new TruncInst(Val, PtrType, "gep_trunc", InsertPt);
} else {
// GEP indexes must be sign-extended.
Inst = new SExtInst(Val, PtrType, "gep_sext", InsertPt);
}
Inst->setDebugLoc(Debug);
return Inst;
}
static void FlushOffset(Instruction **Ptr, uint64_t *CurrentOffset,
Instruction *InsertPt, const DebugLoc &Debug,
Type *PtrType) {
if (*CurrentOffset) {
*Ptr = BinaryOperator::Create(Instruction::Add, *Ptr,
ConstantInt::get(PtrType, *CurrentOffset),
"gep", InsertPt);
(*Ptr)->setDebugLoc(Debug);
*CurrentOffset = 0;
}
}
static void ExpandGEP(GetElementPtrInst *GEP, DataLayout *DL, Type *PtrType) {
const DebugLoc &Debug = GEP->getDebugLoc();
Instruction *Ptr = new PtrToIntInst(GEP->getPointerOperand(), PtrType,
"gep_int", GEP);
Ptr->setDebugLoc(Debug);
Type *CurrentTy = GEP->getPointerOperand()->getType();
// We do some limited constant folding ourselves. An alternative
// would be to generate verbose, unfolded output (e.g. multiple
// adds; adds of zero constants) and use a later pass such as
// "-instcombine" to clean that up. However, "-instcombine" can
// reintroduce GetElementPtr instructions.
uint64_t CurrentOffset = 0;
for (GetElementPtrInst::op_iterator Op = GEP->op_begin() + 1;
Op != GEP->op_end();
++Op) {
Value *Index = *Op;
if (StructType *StTy = dyn_cast<StructType>(CurrentTy)) {
uint64_t Field = cast<ConstantInt>(Op)->getZExtValue();
CurrentTy = StTy->getElementType(Field);
CurrentOffset += DL->getStructLayout(StTy)->getElementOffset(Field);
} else {
CurrentTy = cast<SequentialType>(CurrentTy)->getElementType();
uint64_t ElementSize = DL->getTypeAllocSize(CurrentTy);
if (ConstantInt *C = dyn_cast<ConstantInt>(Index)) {
CurrentOffset += C->getSExtValue() * ElementSize;
} else {
FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType);
Index = CastToPtrSize(Index, GEP, Debug, PtrType);
if (ElementSize != 1) {
Index = CopyDebug(
BinaryOperator::Create(Instruction::Mul, Index,
ConstantInt::get(PtrType, ElementSize),
"gep_array", GEP),
GEP);
}
Ptr = BinaryOperator::Create(Instruction::Add, Ptr,
Index, "gep", GEP);
Ptr->setDebugLoc(Debug);
}
}
}
FlushOffset(&Ptr, &CurrentOffset, GEP, Debug, PtrType);
assert(CurrentTy == GEP->getType()->getElementType());
Instruction *Result = new IntToPtrInst(Ptr, GEP->getType(), "", GEP);
Result->setDebugLoc(Debug);
Result->takeName(GEP);
GEP->replaceAllUsesWith(Result);
GEP->eraseFromParent();
}
bool ExpandGetElementPtr::runOnBasicBlock(BasicBlock &BB) {
bool Modified = false;
DataLayout DL(BB.getParent()->getParent());
Type *PtrType = DL.getIntPtrType(BB.getContext());
for (BasicBlock::InstListType::iterator Iter = BB.begin();
Iter != BB.end(); ) {
Instruction *Inst = Iter++;
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Inst)) {
Modified = true;
ExpandGEP(GEP, &DL, PtrType);
}
}
return Modified;
}
BasicBlockPass *llvm::createExpandGetElementPtrPass() {
return new ExpandGetElementPtr();
}