//===-- 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 #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; } }