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

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

Issue 939073008: Rebased PNaCl localmods in LLVM to 223109 (Closed)
Patch Set: undo localmod Created 5 years, 9 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/ExceptionInfoWriter.cpp ('k') | lib/Transforms/NaCl/ExpandByVal.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/ExceptionInfoWriter.cpp ('k') | lib/Transforms/NaCl/ExpandByVal.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698