blob: 6de6c0d3c37f31f9c1836125073f473c20504f54 [file] [log] [blame]
//===-- lib/Transforms/Scalar/LowerConstantExprs.cpp ------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was written by Vladimir Prus and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the LowerConstantExpression pass, which converts all
// constant expressions into instructions. This is primarily usefull for
// code generators which don't yet want or don't have a need to handle
// constant expressions themself.
//
//===----------------------------------------------------------------------===//
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Support/InstIterator.h"
#include <vector>
#include <iostream>
using namespace llvm;
using namespace std;
namespace {
class ConstantExpressionsLower : public FunctionPass {
private: // FunctionPass overrides
bool runOnFunction(Function& f);
private: // internal methods
/// For all operands of 'insn' which are constant expressions, generates
/// an appropriate instruction and replaces the use of constant
/// expression with the use of the generated instruction.
bool runOnInstruction(Instruction& insn);
/// Given an constant expression 'c' which occures in 'instruction',
/// at position 'pos',
/// generates instruction to compute 'c' and replaces the use of 'c'
/// with the use of that instruction. This handles only top-level
/// expression in 'c', any subexpressions are not handled.
Instruction* convert(const ConstantExpr& c, Instruction* where);
};
RegisterOpt<ConstantExpressionsLower> X(
"lowerconstantexprs", "Lower constant expressions");
}
bool ConstantExpressionsLower::runOnFunction(Function& f)
{
bool modified = false;
for (inst_iterator i = inst_begin(f), e = inst_end(f); i != e; ++i)
{
modified |= runOnInstruction(*i);
}
return modified;
}
bool ConstantExpressionsLower::runOnInstruction(Instruction& instruction)
{
bool modified = false;
for (unsigned pos = 0; pos < instruction.getNumOperands(); ++pos)
{
if (ConstantExpr* ce
= dyn_cast<ConstantExpr>(instruction.getOperand(pos))) {
// Decide where to insert the new instruction
Instruction* where = &instruction;
// For PHI nodes we can't insert new instruction before phi,
// since phi should always come at the beginning of the
// basic block.
// So, we need to insert it in the predecessor, right before
// the terminating instruction.
if (PHINode* p = dyn_cast<PHINode>(&instruction)) {
BasicBlock* predecessor = 0;
for(unsigned i = 0; i < p->getNumIncomingValues(); ++i)
if (p->getIncomingValue(i) == ce) {
predecessor = p->getIncomingBlock(i);
break;
}
assert(predecessor && "could not find predecessor");
where = predecessor->getTerminator();
}
Instruction* n = convert(*ce, where);
// Note: we can't call replaceAllUsesWith, since
// that might replace uses in another functions,
// where the instruction(s) we've generated are not
// available.
// Moreover, we can't replace all the users in the same
// function, because we can't be sure the definition
// made in this block will be available in other
// places where the constant is used.
instruction.setOperand(pos, n);
// The new instruction might have constant expressions in
// it. Extract them too.
runOnInstruction(*n);
modified = true;
}
}
return modified;
}
Instruction*
ConstantExpressionsLower::convert(const ConstantExpr& c, Instruction* where)
{
Instruction* result = 0;
if (c.getOpcode() >= Instruction::BinaryOpsBegin &&
c.getOpcode() < Instruction::BinaryOpsEnd)
{
result = BinaryOperator::create(
static_cast<Instruction::BinaryOps>(c.getOpcode()),
c.getOperand(0), c.getOperand(1), "", where);
}
else
{
switch(c.getOpcode()) {
case Instruction::GetElementPtr:
{
vector<Value*> idx;
for (unsigned i = 1; i < c.getNumOperands(); ++i)
idx.push_back(c.getOperand(i));
result = new GetElementPtrInst(c.getOperand(0),
idx, "", where);
break;
}
case Instruction::Cast:
result = new CastInst(c.getOperand(0), c.getType(), "",
where);
break;
case Instruction::Shl:
case Instruction::Shr:
result = new ShiftInst(
static_cast<Instruction::OtherOps>(c.getOpcode()),
c.getOperand(0), c.getOperand(1), "", where);
break;
case Instruction::Select:
result = new SelectInst(c.getOperand(0), c.getOperand(1),
c.getOperand(2), "", where);
break;
default:
std::cerr << "Offending expr: " << c << "\n";
assert(0 && "Constant expression not yet handled!\n");
}
}
return result;
}
namespace llvm {
FunctionPass* createLowerConstantExpressionsPass()
{
return new ConstantExpressionsLower;
}
}