aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/NaCl/InsertDivideCheck.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/NaCl/InsertDivideCheck.cpp')
-rw-r--r--lib/Transforms/NaCl/InsertDivideCheck.cpp112
1 files changed, 112 insertions, 0 deletions
diff --git a/lib/Transforms/NaCl/InsertDivideCheck.cpp b/lib/Transforms/NaCl/InsertDivideCheck.cpp
new file mode 100644
index 0000000000..f1deae618f
--- /dev/null
+++ b/lib/Transforms/NaCl/InsertDivideCheck.cpp
@@ -0,0 +1,112 @@
+//===- InsertDivideCheck.cpp - Add divide by zero checks ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass adds a check for divide by zero before every integer DIV or REM.
+//
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "add-divide-check"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/IR/BasicBlock.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Intrinsics.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/CFG.h"
+#include "llvm/Transforms/NaCl.h"
+
+using namespace llvm;
+
+namespace {
+ class InsertDivideCheck : public FunctionPass {
+ public:
+ static char ID;
+ InsertDivideCheck() : FunctionPass(ID) {
+ initializeInsertDivideCheckPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F);
+ };
+}
+
+static BasicBlock *CreateTrapBlock(Function &F, DebugLoc dl) {
+ BasicBlock *TrapBlock = BasicBlock::Create(F.getContext(), "divrem.by.zero",
+ &F);
+ Value *TrapFn = Intrinsic::getDeclaration(F.getParent(), Intrinsic::trap);
+ CallInst::Create(TrapFn, "", TrapBlock)->setDebugLoc(dl);
+ (new UnreachableInst(F.getContext(), TrapBlock))->setDebugLoc(dl);
+ return TrapBlock;
+}
+
+bool InsertDivideCheck::runOnFunction(Function &F) {
+ SmallPtrSet<Instruction*, 8> GuardedDivs;
+ // If the pass finds a DIV/REM that needs to be checked for zero denominator,
+ // it will insert a new "trap" block, and split the block that contains the
+ // DIV/REM into two blocks. The new BasicBlocks are added after the current
+ // BasicBlock, so that if there is more than one DIV/REM in the same block,
+ // all are visited.
+ for (Function::iterator I = F.begin(); I != F.end(); I++) {
+ BasicBlock *BB = I;
+
+ for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
+ BI != BE; BI++) {
+ BinaryOperator *DivInst = dyn_cast<BinaryOperator>(BI);
+ if (!DivInst || (GuardedDivs.count(DivInst) != 0))
+ continue;
+ unsigned Opcode = DivInst->getOpcode();
+ if (Opcode != Instruction::SDiv && Opcode != Instruction::UDiv &&
+ Opcode != Instruction::SRem && Opcode != Instruction::URem)
+ continue;
+ Value *Denominator = DivInst->getOperand(1);
+ if (!Denominator->getType()->isIntegerTy())
+ continue;
+ DebugLoc dl = DivInst->getDebugLoc();
+ if (ConstantInt *DenomConst = dyn_cast<ConstantInt>(Denominator)) {
+ // Divides by constants do not need a denominator test.
+ if (DenomConst->isZero()) {
+ // For explicit divides by zero, insert a trap before DIV/REM
+ Value *TrapFn = Intrinsic::getDeclaration(F.getParent(),
+ Intrinsic::trap);
+ CallInst::Create(TrapFn, "", DivInst)->setDebugLoc(dl);
+ }
+ continue;
+ }
+ // Create a trap block.
+ BasicBlock *TrapBlock = CreateTrapBlock(F, dl);
+ // Move instructions in BB from DivInst to BB's end to a new block.
+ BasicBlock *Successor = BB->splitBasicBlock(BI, "guarded.divrem");
+ // Remove the unconditional branch inserted by splitBasicBlock.
+ BB->getTerminator()->eraseFromParent();
+ // Remember that DivInst was already processed, so that when we process
+ // inserted blocks later, we do not attempt to again guard it.
+ GuardedDivs.insert(DivInst);
+ // Compare the denominator with zero.
+ Value *Zero = ConstantInt::get(Denominator->getType(), 0);
+ Value *DenomIsZero = new ICmpInst(*BB, ICmpInst::ICMP_EQ, Denominator,
+ Zero, "");
+ // Put in a condbranch to the trap block.
+ BranchInst::Create(TrapBlock, Successor, DenomIsZero, BB);
+ // BI is invalidated when we split. Stop the BasicBlock iterator.
+ break;
+ }
+ }
+
+ return false;
+}
+
+char InsertDivideCheck::ID = 0;
+INITIALIZE_PASS(InsertDivideCheck, "insert-divide-check",
+ "Insert divide by zero checks", false, false)
+
+FunctionPass *llvm::createInsertDivideCheckPass() {
+ return new InsertDivideCheck();
+}