Chromium Code Reviews| 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 |