blob: dccf081e26703de7765c5c5e892a1d153e5826ce [file] [log] [blame]
//===- 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();
}