OLD | NEW |
| (Empty) |
1 //===- ExpandMulWithOverflow.cpp - Expand out usage of umul.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.with.overflow.*() is used by Clang to implement | |
15 // an overflow check for C++'s new[] operator. This pass expands out | |
16 // these uses so that PNaCl does not have to support | |
17 // umul.with.overflow as part of PNaCl's stable ABI. | |
18 // | |
19 // This pass only handles multiplication by a constant, which is the | |
20 // only case of umul.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 multiplied. | |
25 // | |
26 //===----------------------------------------------------------------------===// | |
27 | |
28 #include "llvm/IR/Function.h" | |
29 #include "llvm/IR/Instructions.h" | |
30 #include "llvm/IR/Intrinsics.h" | |
31 #include "llvm/IR/Module.h" | |
32 #include "llvm/Pass.h" | |
33 #include "llvm/Support/raw_ostream.h" | |
34 #include "llvm/Transforms/NaCl.h" | |
35 | |
36 using namespace llvm; | |
37 | |
38 namespace { | |
39 // This is a ModulePass so that the pass can easily iterate over all | |
40 // uses of the intrinsics. | |
41 class ExpandMulWithOverflow : public ModulePass { | |
42 public: | |
43 static char ID; // Pass identification, replacement for typeid | |
44 ExpandMulWithOverflow() : ModulePass(ID) { | |
45 initializeExpandMulWithOverflowPass(*PassRegistry::getPassRegistry()); | |
46 } | |
47 | |
48 virtual bool runOnModule(Module &M); | |
49 }; | |
50 } | |
51 | |
52 char ExpandMulWithOverflow::ID = 0; | |
53 INITIALIZE_PASS(ExpandMulWithOverflow, "expand-mul-with-overflow", | |
54 "Expand out uses of llvm.umul.with.overflow intrinsics", | |
55 false, false) | |
56 | |
57 static uint64_t UintTypeMax(unsigned Bits) { | |
58 // Avoid doing 1 << 64 because that is undefined on a uint64_t. | |
59 if (Bits == 64) | |
60 return ~(uint64_t) 0; | |
61 return (((uint64_t) 1) << Bits) - 1; | |
62 } | |
63 | |
64 static bool ExpandForIntSize(Module *M, unsigned Bits) { | |
65 IntegerType *IntTy = IntegerType::get(M->getContext(), Bits); | |
66 SmallVector<Type *, 1> Types; | |
67 Types.push_back(IntTy); | |
68 std::string Name = Intrinsic::getName(Intrinsic::umul_with_overflow, Types); | |
69 Function *Intrinsic = M->getFunction(Name); | |
70 if (!Intrinsic) | |
71 return false; | |
72 for (Value::use_iterator CallIter = Intrinsic->use_begin(), | |
73 E = Intrinsic->use_end(); CallIter != E; ) { | |
74 CallInst *Call = dyn_cast<CallInst>(*CallIter++); | |
75 if (!Call) { | |
76 report_fatal_error("ExpandMulWithOverflow: Taking the address of a " | |
77 "umul.with.overflow intrinsic is not allowed"); | |
78 } | |
79 Value *VariableArg; | |
80 ConstantInt *ConstantArg; | |
81 if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(0))) { | |
82 VariableArg = Call->getArgOperand(1); | |
83 ConstantArg = C; | |
84 } else if (ConstantInt *C = dyn_cast<ConstantInt>(Call->getArgOperand(1))) { | |
85 VariableArg = Call->getArgOperand(0); | |
86 ConstantArg = C; | |
87 } else { | |
88 errs() << "Use: " << *Call << "\n"; | |
89 report_fatal_error("ExpandMulWithOverflow: At least one argument of " | |
90 "umul.with.overflow must be a constant"); | |
91 } | |
92 | |
93 Value *Mul = BinaryOperator::Create( | |
94 Instruction::Mul, VariableArg, ConstantArg, | |
95 Call->getName() + ".mul", Call); | |
96 | |
97 uint64_t ArgMax = UintTypeMax(Bits) / ConstantArg->getZExtValue(); | |
98 Value *Overflow = new ICmpInst( | |
99 Call, CmpInst::ICMP_UGT, VariableArg, ConstantInt::get(IntTy, ArgMax), | |
100 Call->getName() + ".overflow"); | |
101 | |
102 for (Value::use_iterator FieldIter = Call->use_begin(), | |
103 E = Call->use_end(); FieldIter != E; ) { | |
104 User *U = *FieldIter++; | |
105 ExtractValueInst *Field = dyn_cast<ExtractValueInst>(U); | |
106 if (!Field) { | |
107 errs() << "Use: " << *U << "\n"; | |
108 report_fatal_error( | |
109 "ExpandMulWithOverflow: Use is not an extractvalue"); | |
110 } | |
111 if (Field->getNumIndices() != 1) { | |
112 report_fatal_error("ExpandMulWithOverflow: Unexpected indices"); | |
113 } | |
114 unsigned Index = Field->getIndices()[0]; | |
115 if (Index == 0) { | |
116 Field->replaceAllUsesWith(Mul); | |
117 } else if (Index == 1) { | |
118 Field->replaceAllUsesWith(Overflow); | |
119 } else { | |
120 report_fatal_error("ExpandMulWithOverflow: Unexpected index"); | |
121 } | |
122 Field->eraseFromParent(); | |
123 } | |
124 Call->eraseFromParent(); | |
125 } | |
126 Intrinsic->eraseFromParent(); | |
127 return true; | |
128 } | |
129 | |
130 bool ExpandMulWithOverflow::runOnModule(Module &M) { | |
131 bool Modified = false; | |
132 Modified |= ExpandForIntSize(&M, 64); | |
133 Modified |= ExpandForIntSize(&M, 32); | |
134 Modified |= ExpandForIntSize(&M, 16); | |
135 Modified |= ExpandForIntSize(&M, 8); | |
136 return Modified; | |
137 } | |
138 | |
139 ModulePass *llvm::createExpandMulWithOverflowPass() { | |
140 return new ExpandMulWithOverflow(); | |
141 } | |
OLD | NEW |