OLD | NEW |
---|---|
(Empty) | |
1 //===- ARMNaClDivideCheck.cpp - Add divide by zero checks ----------------===// | |
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 after every integer DIV or REM. | |
eliben
2013/05/02 21:47:31
after?
sehr
2013/05/03 20:33:07
I changed the code to put the branch before.
| |
11 // | |
12 //===----------------------------------------------------------------------===// | |
13 | |
14 #define DEBUG_TYPE "add-divide-check" | |
15 #include "ARM.h" | |
16 #include "llvm/ADT/STLExtras.h" | |
17 #include "llvm/IR/BasicBlock.h" | |
18 #include "llvm/IR/Constants.h" | |
19 #include "llvm/IR/Function.h" | |
20 #include "llvm/IR/Instructions.h" | |
21 #include "llvm/IR/Intrinsics.h" | |
22 #include "llvm/IR/LLVMContext.h" | |
23 #include "llvm/Support/CFG.h" | |
24 | |
25 using namespace llvm; | |
26 | |
27 namespace llvm { | |
28 void initializeARMNaClDivideCheckPass(PassRegistry&); | |
29 } | |
30 | |
31 namespace { | |
32 | |
33 class ARMNaClDivideCheck : public FunctionPass { | |
34 | |
35 public: | |
36 static char ID; | |
37 ARMNaClDivideCheck() : FunctionPass(ID) { | |
38 initializeARMNaClDivideCheckPass(*PassRegistry::getPassRegistry()); | |
39 } | |
40 | |
41 bool runOnFunction(Function &F); | |
42 }; | |
43 } | |
44 | |
45 | |
46 bool ARMNaClDivideCheck::runOnFunction(Function &F) { | |
47 Module *M = F.getParent(); | |
48 BasicBlock *TrapBlock = NULL; | |
49 // BasicBlock list is being appended to during the optimization. | |
eliben
2013/05/02 21:47:31
I'd prefer to see a beefier comment explaining tha
sehr
2013/05/03 20:33:07
Done.
| |
50 for (Function::iterator I = F.begin(); I != F.end(); I++) { | |
51 BasicBlock *BB = I; | |
52 | |
53 for (BasicBlock::iterator BI = BB->begin(), BE = BB->end(); BI != BE;) { | |
54 BinaryOperator *DivInst = dyn_cast<BinaryOperator>(BI++); | |
55 if (!DivInst) | |
56 continue; | |
57 unsigned Opcode = DivInst->getOpcode(); | |
58 if (Opcode != Instruction::SDiv && Opcode != Instruction::UDiv && | |
59 Opcode != Instruction::SRem && Opcode != Instruction::URem) | |
60 continue; | |
61 // Create a single trap block. | |
Jim Stichnoth
2013/05/02 21:37:16
You might want to check whether the denominator is
sehr
2013/05/03 20:33:07
Done. I insert a trap before any explicit divide
| |
62 if (TrapBlock == NULL) { | |
eliben
2013/05/02 21:47:31
Put the trap block creation into a helper method?
sehr
2013/05/03 20:33:07
Done.
| |
63 TrapBlock = BasicBlock::Create(F.getContext(), "divrem.by.zero", | |
64 &F, NULL); | |
eliben
2013/05/02 21:47:31
No need for explicit NULL here
sehr
2013/05/03 20:33:07
Done.
| |
65 Value *TrapFn = Intrinsic::getDeclaration(M, Intrinsic::trap); | |
66 CallInst::Create(TrapFn, "", TrapBlock); | |
67 new UnreachableInst(DivInst->getContext(), TrapBlock); | |
68 } | |
69 // Move all of the instructions from BB after DivInst to a new block. | |
70 BasicBlock *Successor = BB->splitBasicBlock(BI, ""); | |
eliben
2013/05/02 21:47:31
suggested tests: the div/rem is first / last instr
sehr
2013/05/03 20:33:07
Done.
| |
71 BB->getTerminator()->eraseFromParent(); | |
72 // Compare the denominator with zero. | |
73 Value *Denominator = DivInst->getOperand(1); | |
74 Value *Zero = ConstantInt::get(Denominator->getType(), 0); | |
75 Value *DenomIsZero = new ICmpInst(DivInst, ICmpInst::ICMP_EQ, Denominator, | |
76 Zero, ""); | |
77 // Put in a condbranch to the trap block. | |
78 BranchInst::Create(TrapBlock, Successor, DenomIsZero, BB); | |
79 // BI became invalid when we split. Stop BasicBlock iterator. | |
80 break; | |
81 } | |
82 } | |
83 | |
84 return false; | |
85 } | |
86 | |
87 char ARMNaClDivideCheck::ID = 0; | |
88 INITIALIZE_PASS(ARMNaClDivideCheck, "arm-nacl-divide-check", | |
89 "Add divide by zero checks", false, false) | |
90 | |
91 FunctionPass *llvm::createARMNaClDivideCheckPass() { | |
92 return new ARMNaClDivideCheck(); | |
93 } | |
OLD | NEW |