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

Side by Side Diff: lib/Transforms/NaCl/ExpandSmallArguments.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/ExpandShuffleVector.cpp ('k') | lib/Transforms/NaCl/ExpandStructRegs.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 //===- ExpandSmallArguments.cpp - Expand out arguments smaller than i32----===//
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 // LLVM IR allows function return types and argument types such as
11 // "zeroext i8" and "signext i8". The Language Reference says that
12 // zeroext "indicates to the code generator that the parameter or
13 // return value should be zero-extended to the extent required by the
14 // target's ABI (which is usually 32-bits, but is 8-bits for a i1 on
15 // x86-64) by the caller (for a parameter) or the callee (for a return
16 // value)".
17 //
18 // This can lead to non-portable behaviour when calling functions
19 // without C prototypes or with wrong C prototypes.
20 //
21 // In order to remove this non-portability from PNaCl, and to simplify
22 // the language that the PNaCl translator accepts, the
23 // ExpandSmallArguments pass widens integer arguments and return types
24 // to be at least 32 bits. The pass inserts explicit cast
25 // instructions (ZExtInst/SExtInst/TruncInst) as needed.
26 //
27 // The pass chooses between ZExtInst and SExtInst widening based on
28 // whether a "signext" attribute is present. However, in principle
29 // the pass could always use zero-extension, because the extent to
30 // which either zero-extension or sign-extension is done is up to the
31 // target ABI, which is up to PNaCl to specify.
32 //
33 //===----------------------------------------------------------------------===//
34
35 #include "llvm/IR/Function.h"
36 #include "llvm/IR/Instructions.h"
37 #include "llvm/IR/IntrinsicInst.h"
38 #include "llvm/IR/Module.h"
39 #include "llvm/Pass.h"
40 #include "llvm/Transforms/NaCl.h"
41 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
42
43 using namespace llvm;
44
45 namespace {
46 // This is a ModulePass because the pass recreates functions in
47 // order to change their arguments' types.
48 class ExpandSmallArguments : public ModulePass {
49 public:
50 static char ID; // Pass identification, replacement for typeid
51 ExpandSmallArguments() : ModulePass(ID) {
52 initializeExpandSmallArgumentsPass(*PassRegistry::getPassRegistry());
53 }
54
55 virtual bool runOnModule(Module &M);
56 };
57 }
58
59 char ExpandSmallArguments::ID = 0;
60 INITIALIZE_PASS(ExpandSmallArguments, "expand-small-arguments",
61 "Expand function arguments to be at least 32 bits in size",
62 false, false)
63
64 // Returns the normalized version of the given argument/return type.
65 static Type *NormalizeType(Type *Ty) {
66 if (IntegerType *IntTy = dyn_cast<IntegerType>(Ty)) {
67 if (IntTy->getBitWidth() < 32) {
68 return IntegerType::get(Ty->getContext(), 32);
69 }
70 }
71 return Ty;
72 }
73
74 // Returns the normalized version of the given function type.
75 static FunctionType *NormalizeFunctionType(FunctionType *FTy) {
76 if (FTy->isVarArg()) {
77 report_fatal_error(
78 "ExpandSmallArguments does not handle varargs functions");
79 }
80 SmallVector<Type *, 8> ArgTypes;
81 for (unsigned I = 0; I < FTy->getNumParams(); ++I) {
82 ArgTypes.push_back(NormalizeType(FTy->getParamType(I)));
83 }
84 return FunctionType::get(NormalizeType(FTy->getReturnType()),
85 ArgTypes, false);
86 }
87
88 // Convert the given function to use normalized argument/return types.
89 static bool ConvertFunction(Function *Func) {
90 FunctionType *FTy = Func->getFunctionType();
91 FunctionType *NFTy = NormalizeFunctionType(FTy);
92 if (NFTy == FTy)
93 return false; // No change needed.
94 Function *NewFunc = RecreateFunction(Func, NFTy);
95
96 // Move the arguments across to the new function.
97 for (Function::arg_iterator Arg = Func->arg_begin(), E = Func->arg_end(),
98 NewArg = NewFunc->arg_begin();
99 Arg != E; ++Arg, ++NewArg) {
100 NewArg->takeName(Arg);
101 if (Arg->getType() == NewArg->getType()) {
102 Arg->replaceAllUsesWith(NewArg);
103 } else {
104 Instruction *Trunc = new TruncInst(
105 NewArg, Arg->getType(), NewArg->getName() + ".arg_trunc",
106 NewFunc->getEntryBlock().getFirstInsertionPt());
107 Arg->replaceAllUsesWith(Trunc);
108 }
109 }
110
111 if (FTy->getReturnType() != NFTy->getReturnType()) {
112 // Fix up return instructions.
113 Instruction::CastOps CastType =
114 Func->getAttributes().hasAttribute(0, Attribute::SExt) ?
115 Instruction::SExt : Instruction::ZExt;
116 for (Function::iterator BB = NewFunc->begin(), E = NewFunc->end();
117 BB != E;
118 ++BB) {
119 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
120 Iter != E; ) {
121 Instruction *Inst = Iter++;
122 if (ReturnInst *Ret = dyn_cast<ReturnInst>(Inst)) {
123 Value *Ext = CopyDebug(
124 CastInst::Create(CastType, Ret->getReturnValue(),
125 NFTy->getReturnType(),
126 Ret->getReturnValue()->getName() + ".ret_ext",
127 Ret),
128 Ret);
129 CopyDebug(ReturnInst::Create(Ret->getContext(), Ext, Ret), Ret);
130 Ret->eraseFromParent();
131 }
132 }
133 }
134 }
135
136 Func->eraseFromParent();
137 return true;
138 }
139
140 // Convert the given call to use normalized argument/return types.
141 template <class T> static bool ConvertCall(T *Call, Pass *P) {
142 // Don't try to change calls to intrinsics.
143 if (isa<IntrinsicInst>(Call))
144 return false;
145 FunctionType *FTy = cast<FunctionType>(
146 Call->getCalledValue()->getType()->getPointerElementType());
147 FunctionType *NFTy = NormalizeFunctionType(FTy);
148 if (NFTy == FTy)
149 return false; // No change needed.
150
151 // Convert arguments.
152 SmallVector<Value *, 8> Args;
153 for (unsigned I = 0; I < Call->getNumArgOperands(); ++I) {
154 Value *Arg = Call->getArgOperand(I);
155 if (NFTy->getParamType(I) != FTy->getParamType(I)) {
156 Instruction::CastOps CastType =
157 Call->getAttributes().hasAttribute(I + 1, Attribute::SExt) ?
158 Instruction::SExt : Instruction::ZExt;
159 Arg = CopyDebug(CastInst::Create(CastType, Arg, NFTy->getParamType(I),
160 "arg_ext", Call), Call);
161 }
162 Args.push_back(Arg);
163 }
164 Value *CastFunc =
165 CopyDebug(new BitCastInst(Call->getCalledValue(), NFTy->getPointerTo(),
166 Call->getName() + ".arg_cast", Call), Call);
167 Value *Result = NULL;
168 if (CallInst *OldCall = dyn_cast<CallInst>(Call)) {
169 CallInst *NewCall = CopyDebug(CallInst::Create(CastFunc, Args, "", OldCall),
170 OldCall);
171 NewCall->takeName(OldCall);
172 NewCall->setAttributes(OldCall->getAttributes());
173 NewCall->setCallingConv(OldCall->getCallingConv());
174 NewCall->setTailCall(OldCall->isTailCall());
175 Result = NewCall;
176
177 if (FTy->getReturnType() != NFTy->getReturnType()) {
178 Result = CopyDebug(new TruncInst(NewCall, FTy->getReturnType(),
179 NewCall->getName() + ".ret_trunc", Call),
180 Call);
181 }
182 } else if (InvokeInst *OldInvoke = dyn_cast<InvokeInst>(Call)) {
183 BasicBlock *Parent = OldInvoke->getParent();
184 BasicBlock *NormalDest = OldInvoke->getNormalDest();
185 BasicBlock *UnwindDest = OldInvoke->getUnwindDest();
186
187 if (FTy->getReturnType() != NFTy->getReturnType()) {
188 if (BasicBlock *SplitDest = SplitCriticalEdge(Parent, NormalDest)) {
189 NormalDest = SplitDest;
190 }
191 }
192
193 InvokeInst *New = CopyDebug(InvokeInst::Create(CastFunc, NormalDest,
194 UnwindDest, Args,
195 "", OldInvoke),
196 OldInvoke);
197 New->takeName(OldInvoke);
198
199 if (FTy->getReturnType() != NFTy->getReturnType()) {
200 Result = CopyDebug(new TruncInst(New, FTy->getReturnType(),
201 New->getName() + ".ret_trunc",
202 NormalDest->getTerminator()),
203 OldInvoke);
204 } else {
205 Result = New;
206 }
207
208 New->setAttributes(OldInvoke->getAttributes());
209 New->setCallingConv(OldInvoke->getCallingConv());
210 }
211 Call->replaceAllUsesWith(Result);
212 Call->eraseFromParent();
213 return true;
214 }
215
216 bool ExpandSmallArguments::runOnModule(Module &M) {
217 bool Changed = false;
218 for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) {
219 Function *Func = Iter++;
220 // Don't try to change intrinsic declarations because intrinsics
221 // will continue to have non-normalized argument types. For
222 // example, memset() takes an i8 argument. It shouldn't matter
223 // whether we modify the types of other function declarations, but
224 // we don't expect to see non-intrinsic function declarations in a
225 // PNaCl pexe.
226 if (Func->empty())
227 continue;
228
229 for (Function::iterator BB = Func->begin(), E = Func->end(); BB != E;
230 ++BB) {
231 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); Iter != E;) {
232 Instruction *Inst = Iter++;
233 if (CallInst *Call = dyn_cast<CallInst>(Inst)) {
234 Changed |= ConvertCall(Call, this);
235 } else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Inst)) {
236 Changed |= ConvertCall(Invoke, this);
237 }
238 }
239 }
240
241 Changed |= ConvertFunction(Func);
242 }
243 return Changed;
244 }
245
246 ModulePass *llvm::createExpandSmallArgumentsPass() {
247 return new ExpandSmallArguments();
248 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/ExpandShuffleVector.cpp ('k') | lib/Transforms/NaCl/ExpandStructRegs.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698