//===- PromoteI1Ops.cpp - Promote various operations on the i1 type--------===// // // 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 various operations on the i1 type so that // these i1 operations do not need to be supported by the PNaCl // translator. // // This is similar to the PromoteIntegers pass in that it removes uses // of an unusual-size integer type. The difference is that i1 remains // a valid type in other operations. i1 can still be used in phi // nodes, "select" instructions, in "sext" and "zext", and so on. In // contrast, the integer types that PromoteIntegers removes are not // allowed in any context by PNaCl's ABI verifier. // // This pass expands out the following: // // * i1 loads and stores. // * All i1 comparisons and arithmetic operations, with the exception // of "and", "or" and "xor", because these are used in practice and // don't overflow. // // "switch" instructions on i1 are also disallowed by the PNaCl ABI // verifier, but they don't seem to be generated in practice and so // they are not currently expanded out by this pass. // //===----------------------------------------------------------------------===// #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Instructions.h" #include "llvm/Pass.h" #include "llvm/Transforms/NaCl.h" using namespace llvm; namespace { class PromoteI1Ops : public BasicBlockPass { public: static char ID; // Pass identification, replacement for typeid PromoteI1Ops() : BasicBlockPass(ID) { initializePromoteI1OpsPass(*PassRegistry::getPassRegistry()); } virtual bool runOnBasicBlock(BasicBlock &BB); }; } char PromoteI1Ops::ID = 0; INITIALIZE_PASS(PromoteI1Ops, "nacl-promote-i1-ops", "Promote various operations on the i1 type", false, false) static Value *promoteValue(Value *Val, bool SignExt, Instruction *InsertPt) { Instruction::CastOps CastType = SignExt ? Instruction::SExt : Instruction::ZExt; return CopyDebug(CastInst::Create(CastType, Val, Type::getInt8Ty(Val->getContext()), Val->getName() + ".expand_i1_val", InsertPt), InsertPt); } bool PromoteI1Ops::runOnBasicBlock(BasicBlock &BB) { bool Changed = false; Type *I1Ty = Type::getInt1Ty(BB.getContext()); Type *I8Ty = Type::getInt8Ty(BB.getContext()); for (BasicBlock::iterator Iter = BB.begin(), E = BB.end(); Iter != E; ) { Instruction *Inst = Iter++; if (LoadInst *Load = dyn_cast(Inst)) { if (Load->getType() == I1Ty) { Changed = true; Value *Ptr = CopyDebug( new BitCastInst( Load->getPointerOperand(), I8Ty->getPointerTo(), Load->getPointerOperand()->getName() + ".i8ptr", Load), Load); LoadInst *NewLoad = new LoadInst( Ptr, Load->getName() + ".pre_trunc", Load); CopyDebug(NewLoad, Load); CopyLoadOrStoreAttrs(NewLoad, Load); Value *Result = CopyDebug(new TruncInst(NewLoad, I1Ty, "", Load), Load); Result->takeName(Load); Load->replaceAllUsesWith(Result); Load->eraseFromParent(); } } else if (StoreInst *Store = dyn_cast(Inst)) { if (Store->getValueOperand()->getType() == I1Ty) { Changed = true; Value *Ptr = CopyDebug( new BitCastInst( Store->getPointerOperand(), I8Ty->getPointerTo(), Store->getPointerOperand()->getName() + ".i8ptr", Store), Store); Value *Val = promoteValue(Store->getValueOperand(), false, Store); StoreInst *NewStore = new StoreInst(Val, Ptr, Store); CopyDebug(NewStore, Store); CopyLoadOrStoreAttrs(NewStore, Store); Store->eraseFromParent(); } } else if (BinaryOperator *Op = dyn_cast(Inst)) { if (Op->getType() == I1Ty && !(Op->getOpcode() == Instruction::And || Op->getOpcode() == Instruction::Or || Op->getOpcode() == Instruction::Xor)) { Value *Arg1 = promoteValue(Op->getOperand(0), false, Op); Value *Arg2 = promoteValue(Op->getOperand(1), false, Op); Value *NewOp = CopyDebug( BinaryOperator::Create( Op->getOpcode(), Arg1, Arg2, Op->getName() + ".pre_trunc", Op), Op); Value *Result = CopyDebug(new TruncInst(NewOp, I1Ty, "", Op), Op); Result->takeName(Op); Op->replaceAllUsesWith(Result); Op->eraseFromParent(); } } else if (ICmpInst *Op = dyn_cast(Inst)) { if (Op->getOperand(0)->getType() == I1Ty) { Value *Arg1 = promoteValue(Op->getOperand(0), Op->isSigned(), Op); Value *Arg2 = promoteValue(Op->getOperand(1), Op->isSigned(), Op); Value *Result = CopyDebug( new ICmpInst(Op, Op->getPredicate(), Arg1, Arg2, ""), Op); Result->takeName(Op); Op->replaceAllUsesWith(Result); Op->eraseFromParent(); } } } return Changed; } BasicBlockPass *llvm::createPromoteI1OpsPass() { return new PromoteI1Ops(); }