Index: lib/Transforms/NaCl/PromoteI1Ops.cpp |
diff --git a/lib/Transforms/NaCl/PromoteI1Ops.cpp b/lib/Transforms/NaCl/PromoteI1Ops.cpp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3a5cf276c4ee10912bb2c9b9507d12105adfad23 |
--- /dev/null |
+++ b/lib/Transforms/NaCl/PromoteI1Ops.cpp |
@@ -0,0 +1,170 @@ |
+//===- 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. |
+// |
+//===----------------------------------------------------------------------===// |
+ |
+#include "llvm/IR/BasicBlock.h" |
+#include "llvm/IR/Constants.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()); |
+ |
+ // Rewrite boolean Switch terminators: |
+ if (SwitchInst *Switch = dyn_cast<SwitchInst>(BB.getTerminator())) { |
+ Value *Condition = Switch->getCondition(); |
+ Type *ConditionTy = Condition->getType(); |
+ if (ConditionTy->isIntegerTy(1)) { |
+ ConstantInt *False = |
+ cast<ConstantInt>(ConstantInt::getFalse(ConditionTy)); |
+ ConstantInt *True = |
+ cast<ConstantInt>(ConstantInt::getTrue(ConditionTy)); |
+ |
+ SwitchInst::CaseIt FalseCase = Switch->findCaseValue(False); |
+ SwitchInst::CaseIt TrueCase = Switch->findCaseValue(True); |
+ |
+ BasicBlock *FalseBlock = FalseCase.getCaseSuccessor(); |
+ BasicBlock *TrueBlock = TrueCase.getCaseSuccessor(); |
+ BasicBlock *DefaultDest = Switch->getDefaultDest(); |
+ |
+ if (TrueBlock && FalseBlock) { |
+ // impossible destination |
+ DefaultDest->removePredecessor(Switch->getParent()); |
+ } |
+ |
+ if (!TrueBlock) { |
+ TrueBlock = DefaultDest; |
+ } |
+ if (!FalseBlock) { |
+ FalseBlock = DefaultDest; |
+ } |
+ |
+ CopyDebug(BranchInst::Create(TrueBlock, FalseBlock, Condition, Switch), |
+ Switch); |
+ Switch->eraseFromParent(); |
+ } |
+ } |
+ |
+ for (BasicBlock::iterator Iter = BB.begin(), E = BB.end(); Iter != E; ) { |
+ Instruction *Inst = Iter++; |
+ if (LoadInst *Load = dyn_cast<LoadInst>(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<StoreInst>(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<BinaryOperator>(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<ICmpInst>(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(); |
+} |