OLD | NEW |
1 //===- subzero/src/IceCfg.cpp - Control flow graph implementation ---------===// | 1 //===- subzero/src/IceCfg.cpp - Control flow graph implementation ---------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
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 // This file implements the Cfg class, including constant pool | 10 // This file implements the Cfg class, including constant pool |
11 // management. | 11 // management. |
12 // | 12 // |
13 //===----------------------------------------------------------------------===// | 13 //===----------------------------------------------------------------------===// |
14 | 14 |
15 #include "IceCfg.h" | 15 #include "IceCfg.h" |
16 #include "IceCfgNode.h" | 16 #include "IceCfgNode.h" |
17 #include "IceClFlags.h" | 17 #include "IceClFlags.h" |
18 #include "IceDefs.h" | 18 #include "IceDefs.h" |
19 #include "IceInst.h" | 19 #include "IceInst.h" |
20 #include "IceLiveness.h" | 20 #include "IceLiveness.h" |
21 #include "IceOperand.h" | 21 #include "IceOperand.h" |
22 #include "IceTargetLowering.h" | 22 #include "IceTargetLowering.h" |
23 | 23 |
24 namespace Ice { | 24 namespace Ice { |
25 | 25 |
26 Cfg::Cfg(GlobalContext *Ctx) | 26 Cfg::Cfg(GlobalContext *Ctx) |
27 : Ctx(Ctx), FunctionName(""), ReturnType(IceType_void), | 27 : Ctx(Ctx), FunctionName(""), ReturnType(IceType_void), |
28 IsInternalLinkage(false), HasError(false), ErrorMessage(""), Entry(NULL), | 28 IsInternalLinkage(false), HasError(false), FocusedTiming(false), |
29 NextInstNumber(1), Live(nullptr), | 29 ErrorMessage(""), Entry(NULL), NextInstNumber(1), Live(nullptr), |
30 Target(TargetLowering::createLowering(Ctx->getTargetArch(), this)), | 30 Target(TargetLowering::createLowering(Ctx->getTargetArch(), this)), |
31 VMetadata(new VariablesMetadata(this)), | 31 VMetadata(new VariablesMetadata(this)), |
32 TargetAssembler( | 32 TargetAssembler( |
33 TargetLowering::createAssembler(Ctx->getTargetArch(), this)), | 33 TargetLowering::createAssembler(Ctx->getTargetArch(), this)), |
34 CurrentNode(NULL) {} | 34 CurrentNode(NULL) {} |
35 | 35 |
36 Cfg::~Cfg() {} | 36 Cfg::~Cfg() {} |
37 | 37 |
38 void Cfg::setError(const IceString &Message) { | 38 void Cfg::setError(const IceString &Message) { |
39 HasError = true; | 39 HasError = true; |
(...skipping 22 matching lines...) Expand all Loading... |
62 ImplicitArgs.push_back(Arg); | 62 ImplicitArgs.push_back(Arg); |
63 } | 63 } |
64 | 64 |
65 // Returns whether the stack frame layout has been computed yet. This | 65 // Returns whether the stack frame layout has been computed yet. This |
66 // is used for dumping the stack frame location of Variables. | 66 // is used for dumping the stack frame location of Variables. |
67 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } | 67 bool Cfg::hasComputedFrame() const { return getTarget()->hasComputedFrame(); } |
68 | 68 |
69 void Cfg::translate() { | 69 void Cfg::translate() { |
70 if (hasError()) | 70 if (hasError()) |
71 return; | 71 return; |
72 static TimerIdT IDtranslate = GlobalContext::getTimerID("translate"); | 72 VerboseMask OldVerboseMask = getContext()->getVerbose(); |
73 TimerMarker T(IDtranslate, getContext()); | 73 const IceString &TimingFocusOn = getContext()->getFlags().TimingFocusOn; |
| 74 if (TimingFocusOn == "*" || TimingFocusOn == getFunctionName()) |
| 75 setFocusedTiming(); |
| 76 bool VerboseFocus = |
| 77 (getContext()->getFlags().VerboseFocusOn == getFunctionName()); |
| 78 if (VerboseFocus) |
| 79 getContext()->setVerbose(IceV_All); |
| 80 TimerMarker T(TimerStack::TT_translate, this); |
74 | 81 |
75 dump("Initial CFG"); | 82 dump("Initial CFG"); |
76 | 83 |
77 // The set of translation passes and their order are determined by | 84 // The set of translation passes and their order are determined by |
78 // the target. | 85 // the target. |
79 getTarget()->translate(); | 86 getTarget()->translate(); |
80 | 87 |
81 dump("Final output"); | 88 dump("Final output"); |
| 89 if (getFocusedTiming()) |
| 90 getContext()->dumpTimers(); |
| 91 if (VerboseFocus) |
| 92 getContext()->setVerbose(OldVerboseMask); |
82 } | 93 } |
83 | 94 |
84 void Cfg::computePredecessors() { | 95 void Cfg::computePredecessors() { |
85 for (CfgNode *Node : Nodes) | 96 for (CfgNode *Node : Nodes) |
86 Node->computePredecessors(); | 97 Node->computePredecessors(); |
87 } | 98 } |
88 | 99 |
89 void Cfg::renumberInstructions() { | 100 void Cfg::renumberInstructions() { |
90 static TimerIdT IDrenumberInstructions = | 101 TimerMarker T(TimerStack::TT_renumberInstructions, this); |
91 GlobalContext::getTimerID("renumberInstructions"); | |
92 TimerMarker T(IDrenumberInstructions, getContext()); | |
93 NextInstNumber = 1; | 102 NextInstNumber = 1; |
94 for (CfgNode *Node : Nodes) | 103 for (CfgNode *Node : Nodes) |
95 Node->renumberInstructions(); | 104 Node->renumberInstructions(); |
96 } | 105 } |
97 | 106 |
98 // placePhiLoads() must be called before placePhiStores(). | 107 // placePhiLoads() must be called before placePhiStores(). |
99 void Cfg::placePhiLoads() { | 108 void Cfg::placePhiLoads() { |
100 static TimerIdT IDplacePhiLoads = GlobalContext::getTimerID("placePhiLoads"); | 109 TimerMarker T(TimerStack::TT_placePhiLoads, this); |
101 TimerMarker T(IDplacePhiLoads, getContext()); | |
102 for (CfgNode *Node : Nodes) | 110 for (CfgNode *Node : Nodes) |
103 Node->placePhiLoads(); | 111 Node->placePhiLoads(); |
104 } | 112 } |
105 | 113 |
106 // placePhiStores() must be called after placePhiLoads(). | 114 // placePhiStores() must be called after placePhiLoads(). |
107 void Cfg::placePhiStores() { | 115 void Cfg::placePhiStores() { |
108 static TimerIdT IDplacePhiStores = | 116 TimerMarker T(TimerStack::TT_placePhiStores, this); |
109 GlobalContext::getTimerID("placePhiStores"); | |
110 TimerMarker T(IDplacePhiStores, getContext()); | |
111 for (CfgNode *Node : Nodes) | 117 for (CfgNode *Node : Nodes) |
112 Node->placePhiStores(); | 118 Node->placePhiStores(); |
113 } | 119 } |
114 | 120 |
115 void Cfg::deletePhis() { | 121 void Cfg::deletePhis() { |
116 static TimerIdT IDdeletePhis = GlobalContext::getTimerID("deletePhis"); | 122 TimerMarker T(TimerStack::TT_deletePhis, this); |
117 TimerMarker T(IDdeletePhis, getContext()); | |
118 for (CfgNode *Node : Nodes) | 123 for (CfgNode *Node : Nodes) |
119 Node->deletePhis(); | 124 Node->deletePhis(); |
120 } | 125 } |
121 | 126 |
122 void Cfg::doArgLowering() { | 127 void Cfg::doArgLowering() { |
123 static TimerIdT IDdoArgLowering = GlobalContext::getTimerID("doArgLowering"); | 128 TimerMarker T(TimerStack::TT_doArgLowering, this); |
124 TimerMarker T(IDdoArgLowering, getContext()); | |
125 getTarget()->lowerArguments(); | 129 getTarget()->lowerArguments(); |
126 } | 130 } |
127 | 131 |
128 void Cfg::doAddressOpt() { | 132 void Cfg::doAddressOpt() { |
129 static TimerIdT IDdoAddressOpt = GlobalContext::getTimerID("doAddressOpt"); | 133 TimerMarker T(TimerStack::TT_doAddressOpt, this); |
130 TimerMarker T(IDdoAddressOpt, getContext()); | |
131 for (CfgNode *Node : Nodes) | 134 for (CfgNode *Node : Nodes) |
132 Node->doAddressOpt(); | 135 Node->doAddressOpt(); |
133 } | 136 } |
134 | 137 |
135 void Cfg::doNopInsertion() { | 138 void Cfg::doNopInsertion() { |
136 static TimerIdT IDdoNopInsertion = | 139 TimerMarker T(TimerStack::TT_doNopInsertion, this); |
137 GlobalContext::getTimerID("doNopInsertion"); | |
138 TimerMarker T(IDdoNopInsertion, getContext()); | |
139 for (CfgNode *Node : Nodes) | 140 for (CfgNode *Node : Nodes) |
140 Node->doNopInsertion(); | 141 Node->doNopInsertion(); |
141 } | 142 } |
142 | 143 |
143 void Cfg::genCode() { | 144 void Cfg::genCode() { |
144 static TimerIdT IDgenCode = GlobalContext::getTimerID("genCode"); | 145 TimerMarker T(TimerStack::TT_genCode, this); |
145 TimerMarker T(IDgenCode, getContext()); | |
146 for (CfgNode *Node : Nodes) | 146 for (CfgNode *Node : Nodes) |
147 Node->genCode(); | 147 Node->genCode(); |
148 } | 148 } |
149 | 149 |
150 // Compute the stack frame layout. | 150 // Compute the stack frame layout. |
151 void Cfg::genFrame() { | 151 void Cfg::genFrame() { |
152 static TimerIdT IDgenFrame = GlobalContext::getTimerID("genFrame"); | 152 TimerMarker T(TimerStack::TT_genFrame, this); |
153 TimerMarker T(IDgenFrame, getContext()); | |
154 getTarget()->addProlog(Entry); | 153 getTarget()->addProlog(Entry); |
155 // TODO: Consider folding epilog generation into the final | 154 // TODO: Consider folding epilog generation into the final |
156 // emission/assembly pass to avoid an extra iteration over the node | 155 // emission/assembly pass to avoid an extra iteration over the node |
157 // list. Or keep a separate list of exit nodes. | 156 // list. Or keep a separate list of exit nodes. |
158 for (CfgNode *Node : Nodes) | 157 for (CfgNode *Node : Nodes) |
159 if (Node->getHasReturn()) | 158 if (Node->getHasReturn()) |
160 getTarget()->addEpilog(Node); | 159 getTarget()->addEpilog(Node); |
161 } | 160 } |
162 | 161 |
163 // This is a lightweight version of live-range-end calculation. Marks | 162 // This is a lightweight version of live-range-end calculation. Marks |
164 // the last use of only those variables whose definition and uses are | 163 // the last use of only those variables whose definition and uses are |
165 // completely with a single block. It is a quick single pass and | 164 // completely with a single block. It is a quick single pass and |
166 // doesn't need to iterate until convergence. | 165 // doesn't need to iterate until convergence. |
167 void Cfg::livenessLightweight() { | 166 void Cfg::livenessLightweight() { |
168 static TimerIdT IDlivenessLightweight = | 167 TimerMarker T(TimerStack::TT_livenessLightweight, this); |
169 GlobalContext::getTimerID("livenessLightweight"); | |
170 TimerMarker T(IDlivenessLightweight, getContext()); | |
171 getVMetadata()->init(); | 168 getVMetadata()->init(); |
172 for (CfgNode *Node : Nodes) | 169 for (CfgNode *Node : Nodes) |
173 Node->livenessLightweight(); | 170 Node->livenessLightweight(); |
174 } | 171 } |
175 | 172 |
176 void Cfg::liveness(LivenessMode Mode) { | 173 void Cfg::liveness(LivenessMode Mode) { |
177 static TimerIdT IDliveness = GlobalContext::getTimerID("liveness"); | 174 TimerMarker T(TimerStack::TT_liveness, this); |
178 TimerMarker T(IDliveness, getContext()); | |
179 Live.reset(new Liveness(this, Mode)); | 175 Live.reset(new Liveness(this, Mode)); |
180 getVMetadata()->init(); | 176 getVMetadata()->init(); |
181 Live->init(); | 177 Live->init(); |
182 // Initialize with all nodes needing to be processed. | 178 // Initialize with all nodes needing to be processed. |
183 llvm::BitVector NeedToProcess(Nodes.size(), true); | 179 llvm::BitVector NeedToProcess(Nodes.size(), true); |
184 while (NeedToProcess.any()) { | 180 while (NeedToProcess.any()) { |
185 // Iterate in reverse topological order to speed up convergence. | 181 // Iterate in reverse topological order to speed up convergence. |
186 // TODO(stichnot): Use llvm::make_range with LLVM 3.5. | 182 // TODO(stichnot): Use llvm::make_range with LLVM 3.5. |
187 for (auto I = Nodes.rbegin(), E = Nodes.rend(); I != E; ++I) { | 183 for (auto I = Nodes.rbegin(), E = Nodes.rend(); I != E; ++I) { |
188 CfgNode *Node = *I; | 184 CfgNode *Node = *I; |
(...skipping 12 matching lines...) Expand all Loading... |
201 if (Mode == Liveness_Intervals) { | 197 if (Mode == Liveness_Intervals) { |
202 // Reset each variable's live range. | 198 // Reset each variable's live range. |
203 for (Variable *Var : Variables) | 199 for (Variable *Var : Variables) |
204 Var->resetLiveRange(); | 200 Var->resetLiveRange(); |
205 } | 201 } |
206 // Collect timing for just the portion that constructs the live | 202 // Collect timing for just the portion that constructs the live |
207 // range intervals based on the end-of-live-range computation, for a | 203 // range intervals based on the end-of-live-range computation, for a |
208 // finer breakdown of the cost. | 204 // finer breakdown of the cost. |
209 // Make a final pass over instructions to delete dead instructions | 205 // Make a final pass over instructions to delete dead instructions |
210 // and build each Variable's live range. | 206 // and build each Variable's live range. |
211 static TimerIdT IDliveRange = GlobalContext::getTimerID("liveRange"); | 207 TimerMarker T1(TimerStack::TT_liveRange, this); |
212 TimerMarker T1(IDliveRange, getContext()); | |
213 for (CfgNode *Node : Nodes) | 208 for (CfgNode *Node : Nodes) |
214 Node->livenessPostprocess(Mode, getLiveness()); | 209 Node->livenessPostprocess(Mode, getLiveness()); |
215 if (Mode == Liveness_Intervals) { | 210 if (Mode == Liveness_Intervals) { |
216 // Special treatment for live in-args. Their liveness needs to | 211 // Special treatment for live in-args. Their liveness needs to |
217 // extend beyond the beginning of the function, otherwise an arg | 212 // extend beyond the beginning of the function, otherwise an arg |
218 // whose only use is in the first instruction will end up having | 213 // whose only use is in the first instruction will end up having |
219 // the trivial live range [1,1) and will *not* interfere with | 214 // the trivial live range [1,1) and will *not* interfere with |
220 // other arguments. So if the first instruction of the method is | 215 // other arguments. So if the first instruction of the method is |
221 // "r=arg1+arg2", both args may be assigned the same register. | 216 // "r=arg1+arg2", both args may be assigned the same register. |
222 for (SizeT I = 0; I < Args.size(); ++I) { | 217 for (SizeT I = 0; I < Args.size(); ++I) { |
(...skipping 25 matching lines...) Expand all Loading... |
248 if (Var->getWeight().isInf()) | 243 if (Var->getWeight().isInf()) |
249 Var->setLiveRangeInfiniteWeight(); | 244 Var->setLiveRangeInfiniteWeight(); |
250 } | 245 } |
251 dump(); | 246 dump(); |
252 } | 247 } |
253 } | 248 } |
254 | 249 |
255 // Traverse every Variable of every Inst and verify that it | 250 // Traverse every Variable of every Inst and verify that it |
256 // appears within the Variable's computed live range. | 251 // appears within the Variable's computed live range. |
257 bool Cfg::validateLiveness() const { | 252 bool Cfg::validateLiveness() const { |
258 static TimerIdT IDvalidateLiveness = | 253 TimerMarker T(TimerStack::TT_validateLiveness, this); |
259 GlobalContext::getTimerID("validateLiveness"); | |
260 TimerMarker T(IDvalidateLiveness, getContext()); | |
261 bool Valid = true; | 254 bool Valid = true; |
262 Ostream &Str = Ctx->getStrDump(); | 255 Ostream &Str = Ctx->getStrDump(); |
263 for (CfgNode *Node : Nodes) { | 256 for (CfgNode *Node : Nodes) { |
264 for (Inst *Inst : Node->getInsts()) { | 257 for (Inst *Inst : Node->getInsts()) { |
265 if (Inst->isDeleted()) | 258 if (Inst->isDeleted()) |
266 continue; | 259 continue; |
267 if (llvm::isa<InstFakeKill>(Inst)) | 260 if (llvm::isa<InstFakeKill>(Inst)) |
268 continue; | 261 continue; |
269 InstNumberT InstNumber = Inst->getNumber(); | 262 InstNumberT InstNumber = Inst->getNumber(); |
270 Variable *Dest = Inst->getDest(); | 263 Variable *Dest = Inst->getDest(); |
(...skipping 22 matching lines...) Expand all Loading... |
293 Str << " live range " << Var->getLiveRange() << "\n"; | 286 Str << " live range " << Var->getLiveRange() << "\n"; |
294 } | 287 } |
295 } | 288 } |
296 } | 289 } |
297 } | 290 } |
298 } | 291 } |
299 return Valid; | 292 return Valid; |
300 } | 293 } |
301 | 294 |
302 void Cfg::doBranchOpt() { | 295 void Cfg::doBranchOpt() { |
303 static TimerIdT IDdoBranchOpt = GlobalContext::getTimerID("doBranchOpt"); | 296 TimerMarker T(TimerStack::TT_doBranchOpt, this); |
304 TimerMarker T(IDdoBranchOpt, getContext()); | |
305 for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { | 297 for (auto I = Nodes.begin(), E = Nodes.end(); I != E; ++I) { |
306 auto NextNode = I; | 298 auto NextNode = I; |
307 ++NextNode; | 299 ++NextNode; |
308 (*I)->doBranchOpt(NextNode == E ? NULL : *NextNode); | 300 (*I)->doBranchOpt(NextNode == E ? NULL : *NextNode); |
309 } | 301 } |
310 } | 302 } |
311 | 303 |
312 // ======================== Dump routines ======================== // | 304 // ======================== Dump routines ======================== // |
313 | 305 |
314 void Cfg::emit() { | 306 void Cfg::emit() { |
315 static TimerIdT IDemit = GlobalContext::getTimerID("emit"); | 307 TimerMarker T(TimerStack::TT_emit, this); |
316 TimerMarker T(IDemit, getContext()); | |
317 Ostream &Str = Ctx->getStrEmit(); | 308 Ostream &Str = Ctx->getStrEmit(); |
318 if (!Ctx->testAndSetHasEmittedFirstMethod()) { | 309 if (!Ctx->testAndSetHasEmittedFirstMethod()) { |
319 // Print a helpful command for assembling the output. | 310 // Print a helpful command for assembling the output. |
320 // TODO: have the Target emit the header | 311 // TODO: have the Target emit the header |
321 // TODO: need a per-file emit in addition to per-CFG | 312 // TODO: need a per-file emit in addition to per-CFG |
322 Str << "# $LLVM_BIN_PATH/llvm-mc" | 313 Str << "# $LLVM_BIN_PATH/llvm-mc" |
323 << " -arch=x86" | 314 << " -arch=x86" |
324 << " -x86-asm-syntax=intel" | 315 << " -x86-asm-syntax=intel" |
325 << " -filetype=obj" | 316 << " -filetype=obj" |
326 << " -o=MyObj.o" | 317 << " -o=MyObj.o" |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 } | 371 } |
381 } | 372 } |
382 // Print each basic block | 373 // Print each basic block |
383 for (CfgNode *Node : Nodes) | 374 for (CfgNode *Node : Nodes) |
384 Node->dump(this); | 375 Node->dump(this); |
385 if (getContext()->isVerbose(IceV_Instructions)) | 376 if (getContext()->isVerbose(IceV_Instructions)) |
386 Str << "}\n"; | 377 Str << "}\n"; |
387 } | 378 } |
388 | 379 |
389 } // end of namespace Ice | 380 } // end of namespace Ice |
OLD | NEW |