OLD | NEW |
---|---|
(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 } | |
OLD | NEW |