diff --git a/lib/Transforms/Scalar/LowerConstantExprs.cpp b/lib/Transforms/Scalar/LowerConstantExprs.cpp new file mode 100644 index 00000000000..9eeef5e6460 --- /dev/null +++ b/lib/Transforms/Scalar/LowerConstantExprs.cpp @@ -0,0 +1,171 @@ +//===-- 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/iMemory.h" +#include "llvm/iPHINode.h" +#include "llvm/iOther.h" +#include "llvm/Support/InstIterator.h" +#include + +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 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(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(&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(c.getOpcode()), + c.getOperand(0), c.getOperand(1), "", where); + } + else + { + switch(c.getOpcode()) { + case Instruction::GetElementPtr: + { + vector 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(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; + } +}