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

Side by Side Diff: lib/Transforms/NaCl/ExpandMulWithOverflow.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
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/ExpandArithWithOverflow.cpp ('k') | lib/Transforms/NaCl/PNaClABISimplify.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698