Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(99)

Side by Side Diff: lib/Transforms/NaCl/ExpandArithWithOverflow.cpp

Issue 15688011: PNaCl: Extend ExpandMulWithOverflow pass to handle uadd.with.overflow too (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Rebase Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/Transforms/NaCl/CMakeLists.txt ('k') | lib/Transforms/NaCl/ExpandMulWithOverflow.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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",
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 = false;
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 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/CMakeLists.txt ('k') | lib/Transforms/NaCl/ExpandMulWithOverflow.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698