aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/NaCl/PromoteI1Ops.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/NaCl/PromoteI1Ops.cpp')
-rw-r--r--lib/Transforms/NaCl/PromoteI1Ops.cpp138
1 files changed, 138 insertions, 0 deletions
diff --git a/lib/Transforms/NaCl/PromoteI1Ops.cpp b/lib/Transforms/NaCl/PromoteI1Ops.cpp
new file mode 100644
index 0000000000..dccf081e26
--- /dev/null
+++ b/lib/Transforms/NaCl/PromoteI1Ops.cpp
@@ -0,0 +1,138 @@
+//===- 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<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();
+}