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