OLD | NEW |
---|---|
1 //===- ExpandMulWithOverflow.cpp - Expand out usage of umul.with.overflow--===// | 1 //===- ExpandArithWithOverflow.cpp - Expand out uses of *.with.overflow----===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // The LLVM Compiler Infrastructure |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 // | 9 // |
10 // The llvm.*.with.overflow.*() intrinsics are awkward for PNaCl | 10 // The llvm.*.with.overflow.*() intrinsics are awkward for PNaCl |
11 // support because they return structs, and we want to omit struct | 11 // support because they return structs, and we want to omit struct |
12 // types from IR in PNaCl's stable ABI. | 12 // types from IR in PNaCl's stable ABI. |
13 // | 13 // |
14 // However, llvm.umul.with.overflow.*() is used by Clang to implement | 14 // However, llvm.{umul,uadd}.with.overflow.*() are used by Clang to |
15 // an overflow check for C++'s new[] operator. This pass expands out | 15 // implement an overflow check for C++'s new[] operator. This pass |
16 // these uses so that PNaCl does not have to support | 16 // expands out these uses so that PNaCl does not have to support |
17 // umul.with.overflow as part of PNaCl's stable ABI. | 17 // *.with.overflow as part of PNaCl's stable ABI. |
18 // | 18 // |
19 // This pass only handles multiplication by a constant, which is the | 19 // This pass only handles adding/multiplying by a constant, which is |
20 // only case of umul.with.overflow that is currently generated by | 20 // the only use of *.with.overflow that is currently generated by |
21 // Clang (unless '-ftrapv' is passed to Clang). | 21 // Clang (unless '-ftrapv' is passed to Clang). |
22 // | 22 // |
23 // X * Const overflows iff X > UINT_MAX / Const, where UINT_MAX is the | 23 // X * Const overflows iff X > UINT_MAX / Const, where UINT_MAX is the |
24 // maximum value for the integer type being multiplied. | 24 // maximum value for the integer type being used. |
25 // | |
26 // Similarly, X + Const overflows iff X > UINT_MAX - Const. | |
25 // | 27 // |
26 //===----------------------------------------------------------------------===// | 28 //===----------------------------------------------------------------------===// |
27 | 29 |
28 #include "llvm/IR/Function.h" | 30 #include "llvm/IR/Function.h" |
29 #include "llvm/IR/Instructions.h" | 31 #include "llvm/IR/Instructions.h" |
30 #include "llvm/IR/Intrinsics.h" | 32 #include "llvm/IR/Intrinsics.h" |
31 #include "llvm/IR/Module.h" | 33 #include "llvm/IR/Module.h" |
32 #include "llvm/Pass.h" | 34 #include "llvm/Pass.h" |
33 #include "llvm/Support/raw_ostream.h" | 35 #include "llvm/Support/raw_ostream.h" |
34 #include "llvm/Transforms/NaCl.h" | 36 #include "llvm/Transforms/NaCl.h" |
35 | 37 |
36 using namespace llvm; | 38 using namespace llvm; |
37 | 39 |
38 namespace { | 40 namespace { |
39 // This is a ModulePass so that the pass can easily iterate over all | 41 // This is a ModulePass so that the pass can easily iterate over all |
40 // uses of the intrinsics. | 42 // uses of the intrinsics. |
41 class ExpandMulWithOverflow : public ModulePass { | 43 class ExpandArithWithOverflow : public ModulePass { |
42 public: | 44 public: |
43 static char ID; // Pass identification, replacement for typeid | 45 static char ID; // Pass identification, replacement for typeid |
44 ExpandMulWithOverflow() : ModulePass(ID) { | 46 ExpandArithWithOverflow() : ModulePass(ID) { |
45 initializeExpandMulWithOverflowPass(*PassRegistry::getPassRegistry()); | 47 initializeExpandArithWithOverflowPass(*PassRegistry::getPassRegistry()); |
46 } | 48 } |
47 | 49 |
48 virtual bool runOnModule(Module &M); | 50 virtual bool runOnModule(Module &M); |
49 }; | 51 }; |
50 } | 52 } |
51 | 53 |
52 char ExpandMulWithOverflow::ID = 0; | 54 char ExpandArithWithOverflow::ID = 0; |
53 INITIALIZE_PASS(ExpandMulWithOverflow, "expand-mul-with-overflow", | 55 INITIALIZE_PASS(ExpandArithWithOverflow, "expand-arith-with-overflow", |
54 "Expand out uses of llvm.umul.with.overflow intrinsics", | 56 "Expand out some uses of *.with.overflow intrinsics", |
eliben
2013/05/28 17:59:55
What does "some" mean here? You either expand or r
Mark Seaborn
2013/05/28 18:41:23
Well, it doesn't touch usub.with.overflow or s{add
| |
55 false, false) | 57 false, false) |
56 | 58 |
57 static uint64_t UintTypeMax(unsigned Bits) { | 59 static uint64_t UintTypeMax(unsigned Bits) { |
58 // Avoid doing 1 << 64 because that is undefined on a uint64_t. | 60 // Avoid doing 1 << 64 because that is undefined on a uint64_t. |
59 if (Bits == 64) | 61 if (Bits == 64) |
60 return ~(uint64_t) 0; | 62 return ~(uint64_t) 0; |
61 return (((uint64_t) 1) << Bits) - 1; | 63 return (((uint64_t) 1) << Bits) - 1; |
62 } | 64 } |
63 | 65 |
64 static bool ExpandForIntSize(Module *M, unsigned Bits) { | 66 static bool ExpandOpForIntSize(Module *M, unsigned Bits, bool Mul) { |
65 IntegerType *IntTy = IntegerType::get(M->getContext(), Bits); | 67 IntegerType *IntTy = IntegerType::get(M->getContext(), Bits); |
66 SmallVector<Type *, 1> Types; | 68 SmallVector<Type *, 1> Types; |
67 Types.push_back(IntTy); | 69 Types.push_back(IntTy); |
68 std::string Name = Intrinsic::getName(Intrinsic::umul_with_overflow, Types); | 70 Intrinsic::ID ID = (Mul ? Intrinsic::umul_with_overflow |
71 : Intrinsic::uadd_with_overflow); | |
72 std::string Name = Intrinsic::getName(ID, Types); | |
69 Function *Intrinsic = M->getFunction(Name); | 73 Function *Intrinsic = M->getFunction(Name); |
70 if (!Intrinsic) | 74 if (!Intrinsic) |
71 return false; | 75 return false; |
72 for (Value::use_iterator CallIter = Intrinsic->use_begin(), | 76 for (Value::use_iterator CallIter = Intrinsic->use_begin(), |
73 E = Intrinsic->use_end(); CallIter != E; ) { | 77 E = Intrinsic->use_end(); CallIter != E; ) { |
74 CallInst *Call = dyn_cast<CallInst>(*CallIter++); | 78 CallInst *Call = dyn_cast<CallInst>(*CallIter++); |
75 if (!Call) { | 79 if (!Call) { |
76 report_fatal_error("ExpandMulWithOverflow: Taking the address of a " | 80 report_fatal_error("ExpandArithWithOverflow: Taking the address of a " |
77 "umul.with.overflow intrinsic is not allowed"); | 81 "*.with.overflow intrinsic is not allowed"); |
78 } | 82 } |
79 Value *VariableArg; | 83 Value *VariableArg; |
80 ConstantInt *ConstantArg; | 84 ConstantInt *ConstantArg; |
81 if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(0))) { | 85 if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(0))) { |
82 VariableArg = Call->getArgOperand(1); | 86 VariableArg = Call->getArgOperand(1); |
83 ConstantArg = C; | 87 ConstantArg = C; |
84 } else if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(1))) { | 88 } else if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(1))) { |
85 VariableArg = Call->getArgOperand(0); | 89 VariableArg = Call->getArgOperand(0); |
86 ConstantArg = C; | 90 ConstantArg = C; |
87 } else { | 91 } else { |
88 errs() << "Use: " << *Call << "\n"; | 92 errs() << "Use: " << *Call << "\n"; |
89 report_fatal_error("ExpandMulWithOverflow: At least one argument of " | 93 report_fatal_error("ExpandArithWithOverflow: At least one argument of " |
90 "umul.with.overflow must be a constant"); | 94 "*.with.overflow must be a constant"); |
91 } | 95 } |
92 | 96 |
93 Value *Mul = BinaryOperator::Create( | 97 Value *ArithResult = BinaryOperator::Create( |
94 Instruction::Mul, VariableArg, ConstantArg, | 98 (Mul ? Instruction::Mul : Instruction::Add), VariableArg, ConstantArg, |
95 Call->getName() + ".mul", Call); | 99 Call->getName() + ".arith", Call); |
96 | 100 |
97 uint64_t ArgMax = UintTypeMax(Bits) / ConstantArg->getZExtValue(); | 101 uint64_t ArgMax; |
102 if (Mul) { | |
103 ArgMax = UintTypeMax(Bits) / ConstantArg->getZExtValue(); | |
104 } else { | |
105 ArgMax = UintTypeMax(Bits) - ConstantArg->getZExtValue(); | |
106 } | |
98 Value *Overflow = new ICmpInst( | 107 Value *Overflow = new ICmpInst( |
99 Call, CmpInst::ICMP_UGT, VariableArg, ConstantInt::get(IntTy, ArgMax), | 108 Call, CmpInst::ICMP_UGT, VariableArg, ConstantInt::get(IntTy, ArgMax), |
100 Call->getName() + ".overflow"); | 109 Call->getName() + ".overflow"); |
101 | 110 |
102 for (Value::use_iterator FieldIter = Call->use_begin(), | 111 for (Value::use_iterator FieldIter = Call->use_begin(), |
103 E = Call->use_end(); FieldIter != E; ) { | 112 E = Call->use_end(); FieldIter != E; ) { |
104 User *U = *FieldIter++; | 113 User *U = *FieldIter++; |
105 ExtractValueInst *Field = dyn_cast<ExtractValueInst>(U); | 114 ExtractValueInst *Field = dyn_cast<ExtractValueInst>(U); |
106 if (!Field) { | 115 if (!Field) { |
107 errs() << "Use: " << *U << "\n"; | 116 errs() << "Use: " << *U << "\n"; |
108 report_fatal_error( | 117 report_fatal_error( |
109 "ExpandMulWithOverflow: Use is not an extractvalue"); | 118 "ExpandArithWithOverflow: Use is not an extractvalue"); |
110 } | 119 } |
111 if (Field->getNumIndices() != 1) { | 120 if (Field->getNumIndices() != 1) { |
112 report_fatal_error("ExpandMulWithOverflow: Unexpected indices"); | 121 report_fatal_error("ExpandArithWithOverflow: Unexpected indices"); |
113 } | 122 } |
114 unsigned Index = Field->getIndices()[0]; | 123 unsigned Index = Field->getIndices()[0]; |
115 if (Index == 0) { | 124 if (Index == 0) { |
116 Field->replaceAllUsesWith(Mul); | 125 Field->replaceAllUsesWith(ArithResult); |
117 } else if (Index == 1) { | 126 } else if (Index == 1) { |
118 Field->replaceAllUsesWith(Overflow); | 127 Field->replaceAllUsesWith(Overflow); |
119 } else { | 128 } else { |
120 report_fatal_error("ExpandMulWithOverflow: Unexpected index"); | 129 report_fatal_error("ExpandArithWithOverflow: Unexpected index"); |
121 } | 130 } |
122 Field->eraseFromParent(); | 131 Field->eraseFromParent(); |
123 } | 132 } |
124 Call->eraseFromParent(); | 133 Call->eraseFromParent(); |
125 } | 134 } |
126 Intrinsic->eraseFromParent(); | 135 Intrinsic->eraseFromParent(); |
127 return true; | 136 return true; |
128 } | 137 } |
129 | 138 |
130 bool ExpandMulWithOverflow::runOnModule(Module &M) { | 139 static bool ExpandForIntSize(Module *M, unsigned Bits) { |
140 bool Modified; | |
eliben
2013/05/28 17:59:55
= false
Mark Seaborn
2013/05/28 18:41:23
Thanks, fixed.
| |
141 Modified |= ExpandOpForIntSize(M, Bits, true); // Expand umul | |
142 Modified |= ExpandOpForIntSize(M, Bits, false); // Expand uadd | |
143 return Modified; | |
144 } | |
145 | |
146 bool ExpandArithWithOverflow::runOnModule(Module &M) { | |
131 bool Modified = false; | 147 bool Modified = false; |
132 Modified |= ExpandForIntSize(&M, 64); | 148 Modified |= ExpandForIntSize(&M, 64); |
133 Modified |= ExpandForIntSize(&M, 32); | 149 Modified |= ExpandForIntSize(&M, 32); |
134 Modified |= ExpandForIntSize(&M, 16); | 150 Modified |= ExpandForIntSize(&M, 16); |
135 Modified |= ExpandForIntSize(&M, 8); | 151 Modified |= ExpandForIntSize(&M, 8); |
136 return Modified; | 152 return Modified; |
137 } | 153 } |
138 | 154 |
139 ModulePass *llvm::createExpandMulWithOverflowPass() { | 155 ModulePass *llvm::createExpandArithWithOverflowPass() { |
140 return new ExpandMulWithOverflow(); | 156 return new ExpandArithWithOverflow(); |
141 } | 157 } |
OLD | NEW |