Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: lib/Target/ARM/ARMNaClDivideCheck.cpp

Issue 14607004: Insert denominator zero checks for NaCl (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Incorporate review comments and add test Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 //===- ARMNaClDivideCheck.cpp - Add divide by zero checks ----------------===//
Mark Seaborn 2013/05/03 21:25:36 Add 1 more '-' to line up right-hand edge
sehr 2013/05/03 23:29:05 Done.
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass adds a check for divide by zero before every integer DIV or REM.
eliben 2013/05/03 21:18:55 Once this CL is committed, we can check the perfor
sehr 2013/05/03 23:29:05 I know fixing it here is simpler a priori. But on
11 //
12 //===----------------------------------------------------------------------===//
13
14 #define DEBUG_TYPE "add-divide-check"
15 #include "ARM.h"
16 #include "llvm/ADT/SmallPtrSet.h"
17 #include "llvm/ADT/STLExtras.h"
18 #include "llvm/IR/BasicBlock.h"
19 #include "llvm/IR/Constants.h"
20 #include "llvm/IR/Function.h"
21 #include "llvm/IR/Instructions.h"
22 #include "llvm/IR/Intrinsics.h"
23 #include "llvm/IR/LLVMContext.h"
24 #include "llvm/Support/CFG.h"
25
26 using namespace llvm;
27
28 namespace llvm {
29 void initializeARMNaClDivideCheckPass(PassRegistry&);
30 }
31
32 namespace {
33
Mark Seaborn 2013/05/03 21:25:36 Remove this empty line
sehr 2013/05/03 23:29:05 Done.
34 class ARMNaClDivideCheck : public FunctionPass {
35
Mark Seaborn 2013/05/03 21:25:36 Remove this empty line
sehr 2013/05/03 23:29:05 Done.
36 public:
37 static char ID;
38 ARMNaClDivideCheck() : FunctionPass(ID) {
39 initializeARMNaClDivideCheckPass(*PassRegistry::getPassRegistry());
40 }
41
42 bool runOnFunction(Function &F);
43 };
44 }
45
46 static BasicBlock *CreateTrapBlock(Function &F) {
47 BasicBlock *TrapBlock = BasicBlock::Create(F.getContext(), "divrem.by.zero",
48 &F);
49 Value *TrapFn = Intrinsic::getDeclaration(F.getParent(), Intrinsic::trap);
50 CallInst::Create(TrapFn, "", TrapBlock);
51 new UnreachableInst(F.getContext(), TrapBlock);
52 return TrapBlock;
53 }
54
55 bool ARMNaClDivideCheck::runOnFunction(Function &F) {
56 SmallPtrSet<Instruction*, 8> GuardedDivs;
57 BasicBlock *TrapBlock = NULL;
58 // If the pass finds a DIV/REM that needs to be checked for zero denominator,
59 // it will insert a new "trap" block, and split the block that contains the
60 // DIV/REM into two blocks. The new BasicBlocks are added to the end of
eliben 2013/05/03 21:18:55 I'm not sure I understand the "at the end of the f
sehr 2013/05/03 23:29:05 I changed it to just emphasize the important point
61 // the function, so that if there is more than one DIV/REM in the same block,
62 // all are visited.
63 for (Function::iterator I = F.begin(); I != F.end(); I++) {
64 BasicBlock *BB = I;
65
66 for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
67 BI != BE; BI++) {
68 BinaryOperator *DivInst = dyn_cast<BinaryOperator>(BI);
69 if (!DivInst || (GuardedDivs.count(DivInst) != 0))
70 continue;
71 unsigned Opcode = DivInst->getOpcode();
72 if (Opcode != Instruction::SDiv && Opcode != Instruction::UDiv &&
73 Opcode != Instruction::SRem && Opcode != Instruction::URem)
74 continue;
75 Value *Denominator = DivInst->getOperand(1);
76 if (!Denominator->getType()->isIntegerTy())
77 continue;
78 ConstantInt *DenomConst = dyn_cast<ConstantInt>(Denominator);
79 if (DenomConst) {
Mark Seaborn 2013/05/03 21:25:36 Write as: if (ConstantInt *DenomConst = dyn_cast
sehr 2013/05/03 23:29:05 Done.
80 // Divides by constants do not need a denominator test.
81 if (DenomConst->isZero()) {
82 // For explicit divides by zero, insert a trap before DIV/REM
83 Value *TrapFn = Intrinsic::getDeclaration(F.getParent(),
84 Intrinsic::trap);
85 CallInst::Create(TrapFn, "", DivInst);
Mark Seaborn 2013/05/03 21:25:36 Preserve debug location: CallInst::Create(TrapFn,
sehr 2013/05/03 23:29:05 Done.
86 }
87 continue;
88 }
89 // Create a single trap block.
Mark Seaborn 2013/05/03 21:25:36 This could hinder debugging. It would be nice to
sehr 2013/05/03 23:29:05 I was only really interested in code size, and I g
90 if (TrapBlock == NULL) {
91 TrapBlock = CreateTrapBlock(F);
92 }
93 // Move instructions in BB from DivInst to BB's end to a new block.
94 BasicBlock *Successor = BB->splitBasicBlock(BI, "");
95 BB->getTerminator()->eraseFromParent();
Mark Seaborn 2013/05/03 21:25:36 Comment: "Remove unconditional branch"?
sehr 2013/05/03 23:29:05 Done.
96 // Remember that DivInst was already processed, so that when we process
97 // inserted blocks later, we do not attempt to again guard it.
98 GuardedDivs.insert(DivInst);
99 // Compare the denominator with zero.
100 Value *Zero = ConstantInt::get(Denominator->getType(), 0);
101 Value *DenomIsZero = new ICmpInst(*BB, ICmpInst::ICMP_EQ, Denominator,
102 Zero, "");
103 // Put in a condbranch to the trap block.
104 BranchInst::Create(TrapBlock, Successor, DenomIsZero, BB);
105 // BI is invalidated when we split. Stop the BasicBlock iterator.
106 break;
107 }
108 }
109
110 return false;
111 }
112
113 char ARMNaClDivideCheck::ID = 0;
114 INITIALIZE_PASS(ARMNaClDivideCheck, "arm-nacl-divide-check",
115 "Add divide by zero checks", false, false)
116
117 FunctionPass *llvm::createARMNaClDivideCheckPass() {
118 return new ARMNaClDivideCheck();
119 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698