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

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

Issue 13973018: PNaCl: Add ExpandByVal pass for expanding out by-value struct args and results (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: Cleanup Created 7 years, 8 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') | test/Transforms/NaCl/expand-byval.ll » ('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 //===- ExpandByVal.cpp - Expand out use of "byval" and "sret" attributes---===//
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 // This pass expands out by-value passing of structs as arguments and
11 // return values. In LLVM IR terms, it expands out the "byval" and
12 // "sret" function argument attributes.
13 //
14 // The semantics of the "byval" attribute are that the callee function
15 // gets a private copy of the pointed-to argument that it is allowed
16 // to modify. In implementing this, we have a choice between making
17 // the caller responsible for making the copy or making the callee
18 // responsible for making the copy. We choose the former, because
19 // this matches how the normal native calling conventions work, and
20 // because it often allows the caller to write struct contents
21 // directly into the stack slot that it passes the callee, without an
22 // additional copy.
23 //
24 // Note that this pass does not attempt to modify functions that pass
25 // structs by value without using "byval" or "sret", such as:
26 //
27 // define %struct.X @func() ; struct return
28 // define void @func(%struct.X %arg) ; struct arg
29 //
30 // The pass only handles functions such as:
31 //
32 // define void @func(%struct.X* sret %result_buffer) ; struct return
33 // define void @func(%struct.X* byval %ptr_to_arg) ; struct arg
34 //
35 // This is because PNaCl Clang generates the latter and not the former.
36 //
37 //===----------------------------------------------------------------------===//
38
39 #include "llvm/IR/Attributes.h"
40 #include "llvm/IR/DataLayout.h"
41 #include "llvm/IR/Function.h"
42 #include "llvm/IR/IRBuilder.h"
43 #include "llvm/IR/Instructions.h"
44 #include "llvm/IR/Module.h"
45 #include "llvm/Pass.h"
46 #include "llvm/Transforms/NaCl.h"
47
48 using namespace llvm;
49
50 namespace {
51 // This is a ModulePass so that it can strip attributes from
52 // declared functions as well as defined functions.
53 class ExpandByVal : public ModulePass {
54 public:
55 static char ID; // Pass identification, replacement for typeid
56 ExpandByVal() : ModulePass(ID) {
57 initializeExpandByValPass(*PassRegistry::getPassRegistry());
58 }
59
60 virtual bool runOnModule(Module &M);
61 };
62 }
63
64 char ExpandByVal::ID = 0;
65 INITIALIZE_PASS(ExpandByVal, "expand-byval",
66 "Expand out by-value passing of structs",
67 false, false)
68
69 // removeAttribute() currently does not work on Attribute::Alignment
70 // (it fails with an assertion error), so we have to take a more
71 // convoluted route to removing this attribute by recreating the
72 // AttributeSet.
73 AttributeSet RemoveAttrs(LLVMContext &Context, AttributeSet Attrs) {
74 SmallVector<AttributeSet, 8> AttrList;
75 for (unsigned Slot = 0; Slot < Attrs.getNumSlots(); ++Slot) {
76 unsigned Index = Attrs.getSlotIndex(Slot);
77 AttrBuilder AB;
78 for (AttributeSet::iterator Attr = Attrs.begin(Slot), E = Attrs.end(Slot);
79 Attr != E; ++Attr) {
80 if (!Attr->isAlignAttribute() &&
81 Attr->getKindAsEnum() != Attribute::ByVal &&
82 Attr->getKindAsEnum() != Attribute::StructRet) {
83 AB.addAttribute(*Attr);
84 }
85 }
86 AttrList.push_back(AttributeSet::get(Context, Index, AB));
87 }
88 return AttributeSet::get(Context, AttrList);
89 }
90
91 // ExpandCall() can take a CallInst or an InvokeInst. It returns
92 // whether the instruction was modified.
93 template <class InstType>
94 static bool ExpandCall(DataLayout *DL, InstType *Call) {
95 bool Modify = false;
96 AttributeSet Attrs = Call->getAttributes();
97 for (unsigned ArgIdx = 0; ArgIdx < Call->getNumArgOperands(); ++ArgIdx) {
98 unsigned AttrIdx = ArgIdx + 1;
99
100 if (Attrs.hasAttribute(AttrIdx, Attribute::StructRet))
101 Modify = true;
102
103 if (Attrs.hasAttribute(AttrIdx, Attribute::ByVal)) {
104 Modify = true;
105
106 Value *ArgPtr = Call->getArgOperand(ArgIdx);
107 Type *ArgType = ArgPtr->getType()->getPointerElementType();
108 ConstantInt *ArgSize = ConstantInt::get(
109 Call->getContext(), APInt(64, DL->getTypeStoreSize(ArgType)));
110 unsigned Alignment = Attrs.getParamAlignment(AttrIdx);
111 // In principle, using the alignment from the argument attribute
112 // should be enough. However, Clang is not emitting this
113 // attribute for PNaCl. LLVM alloca instructions do not use the
114 // ABI alignment of the type, so this must be specified
115 // explicitly.
116 // See https://code.google.com/p/nativeclient/issues/detail?id=3403
117 unsigned AllocAlignment =
118 std::max(Alignment, DL->getABITypeAlignment(ArgType));
119
120 // Make a copy of the byval argument.
121 Instruction *CopyBuf = new AllocaInst(ArgType, 0, AllocAlignment,
122 ArgPtr->getName() + ".byval_copy");
123 Function *Func = Call->getParent()->getParent();
124 Func->getEntryBlock().getInstList().push_front(CopyBuf);
125 IRBuilder<> Builder(Call);
126 Builder.CreateLifetimeStart(CopyBuf, ArgSize);
127 // Using the argument's alignment attribute for the memcpy
128 // should be OK because the LLVM Language Reference says that
129 // the alignment attribute specifies "the alignment of the stack
130 // slot to form and the known alignment of the pointer specified
131 // to the call site".
132 Instruction *MemCpy = Builder.CreateMemCpy(CopyBuf, ArgPtr, ArgSize,
133 Alignment);
134 MemCpy->setDebugLoc(Call->getDebugLoc());
135
136 Call->setArgOperand(ArgIdx, CopyBuf);
137
138 // Mark the argument copy as unused using llvm.lifetime.end.
139 if (isa<CallInst>(Call)) {
140 BasicBlock::iterator It = BasicBlock::iterator(Call);
141 Builder.SetInsertPoint(++It);
142 Builder.CreateLifetimeEnd(CopyBuf, ArgSize);
143 } else if (InvokeInst *Invoke = dyn_cast<InvokeInst>(Call)) {
144 Builder.SetInsertPoint(Invoke->getNormalDest()->getFirstInsertionPt());
145 Builder.CreateLifetimeEnd(CopyBuf, ArgSize);
146 Builder.SetInsertPoint(Invoke->getUnwindDest()->getFirstInsertionPt());
147 Builder.CreateLifetimeEnd(CopyBuf, ArgSize);
148 }
149 }
150 }
151 if (Modify) {
152 Call->setAttributes(RemoveAttrs(Call->getContext(), Attrs));
153
154 if (CallInst *CI = dyn_cast<CallInst>(Call)) {
155 // This is no longer a tail call because the callee references
156 // memory alloca'd by the caller.
157 CI->setTailCall(false);
158 }
159 }
160 return Modify;
161 }
162
163 bool ExpandByVal::runOnModule(Module &M) {
164 bool Modified = false;
165 DataLayout DL(&M);
166
167 for (Module::iterator Func = M.begin(), E = M.end(); Func != E; ++Func) {
168 AttributeSet NewAttrs = RemoveAttrs(Func->getContext(),
169 Func->getAttributes());
170 Modified |= (NewAttrs != Func->getAttributes());
171 Func->setAttributes(NewAttrs);
172
173 for (Function::iterator BB = Func->begin(), E = Func->end();
174 BB != E; ++BB) {
175 for (BasicBlock::iterator Inst = BB->begin(), E = BB->end();
176 Inst != E; ++Inst) {
177 if (CallInst *Call = dyn_cast<CallInst>(Inst)) {
178 Modified |= ExpandCall(&DL, Call);
179 } else if (InvokeInst *Call = dyn_cast<InvokeInst>(Inst)) {
180 Modified |= ExpandCall(&DL, Call);
181 }
182 }
183 }
184 }
185
186 return Modified;
187 }
188
189 ModulePass *llvm::createExpandByValPass() {
190 return new ExpandByVal();
191 }
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/CMakeLists.txt ('k') | test/Transforms/NaCl/expand-byval.ll » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698