aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/NaCl/PromoteI1Ops.cpp
blob: dccf081e26703de7765c5c5e892a1d153e5826ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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();
}