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

Side by Side Diff: src/IceCfgNode.cpp

Issue 300563003: Subzero: Initial O2 lowering (Closed) Base URL: https://gerrit.chromium.org/gerrit/p/native_client/pnacl-subzero.git@master
Patch Set: Jan's third-round comments Created 6 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
« no previous file with comments | « src/IceCfgNode.h ('k') | src/IceDefs.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 //===- subzero/src/IceCfgNode.cpp - Basic block (node) implementation -----===// 1 //===- subzero/src/IceCfgNode.cpp - Basic block (node) 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 CfgNode class, including the complexities 10 // This file implements the CfgNode class, including the complexities
11 // of instruction insertion and in-edge calculation. 11 // of instruction insertion and in-edge calculation.
12 // 12 //
13 //===----------------------------------------------------------------------===// 13 //===----------------------------------------------------------------------===//
14 14
15 #include "IceCfg.h" 15 #include "IceCfg.h"
16 #include "IceCfgNode.h" 16 #include "IceCfgNode.h"
17 #include "IceInst.h" 17 #include "IceInst.h"
18 #include "IceLiveness.h"
18 #include "IceOperand.h" 19 #include "IceOperand.h"
19 #include "IceTargetLowering.h" 20 #include "IceTargetLowering.h"
20 21
21 namespace Ice { 22 namespace Ice {
22 23
23 CfgNode::CfgNode(Cfg *Func, SizeT LabelNumber, IceString Name) 24 CfgNode::CfgNode(Cfg *Func, SizeT LabelNumber, IceString Name)
24 : Func(Func), Number(LabelNumber), Name(Name), HasReturn(false) {} 25 : Func(Func), Number(LabelNumber), Name(Name), HasReturn(false) {}
25 26
26 // Returns the name the node was created with. If no name was given, 27 // Returns the name the node was created with. If no name was given,
27 // it synthesizes a (hopefully) unique name. 28 // it synthesizes a (hopefully) unique name.
(...skipping 14 matching lines...) Expand all
42 Func->setError("Phi instruction added to the middle of a block"); 43 Func->setError("Phi instruction added to the middle of a block");
43 return; 44 return;
44 } 45 }
45 Phis.push_back(Phi); 46 Phis.push_back(Phi);
46 } else { 47 } else {
47 Insts.push_back(Inst); 48 Insts.push_back(Inst);
48 } 49 }
49 Inst->updateVars(this); 50 Inst->updateVars(this);
50 } 51 }
51 52
53 // Renumbers the non-deleted instructions in the node. This needs to
54 // be done in preparation for live range analysis. The instruction
55 // numbers in a block must be monotonically increasing. The range of
56 // instruction numbers in a block, from lowest to highest, must not
57 // overlap with the range of any other block.
58 void CfgNode::renumberInstructions() {
59 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
60 (*I)->renumber(Func);
61 }
62 InstList::const_iterator I = Insts.begin(), E = Insts.end();
63 while (I != E) {
64 Inst *Inst = *I++;
65 Inst->renumber(Func);
66 }
67 }
68
52 // When a node is created, the OutEdges are immediately knows, but the 69 // When a node is created, the OutEdges are immediately knows, but the
53 // InEdges have to be built up incrementally. After the CFG has been 70 // InEdges have to be built up incrementally. After the CFG has been
54 // constructed, the computePredecessors() pass finalizes it by 71 // constructed, the computePredecessors() pass finalizes it by
55 // creating the InEdges list. 72 // creating the InEdges list.
56 void CfgNode::computePredecessors() { 73 void CfgNode::computePredecessors() {
57 OutEdges = (*Insts.rbegin())->getTerminatorEdges(); 74 OutEdges = (*Insts.rbegin())->getTerminatorEdges();
58 for (NodeList::const_iterator I = OutEdges.begin(), E = OutEdges.end(); 75 for (NodeList::const_iterator I = OutEdges.begin(), E = OutEdges.end();
59 I != E; ++I) { 76 I != E; ++I) {
60 CfgNode *Node = *I; 77 CfgNode *Node = *I;
61 Node->InEdges.push_back(this); 78 Node->InEdges.push_back(this);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 // Find the insertion point. TODO: After branch/compare fusing is 117 // Find the insertion point. TODO: After branch/compare fusing is
101 // implemented, try not to insert Phi stores between the compare and 118 // implemented, try not to insert Phi stores between the compare and
102 // conditional branch instructions, otherwise the branch/compare 119 // conditional branch instructions, otherwise the branch/compare
103 // pattern matching may fail. However, the branch/compare sequence 120 // pattern matching may fail. However, the branch/compare sequence
104 // will have to be broken if the compare result is read (by the 121 // will have to be broken if the compare result is read (by the
105 // assignment) before it is written (by the compare). 122 // assignment) before it is written (by the compare).
106 InstList::iterator InsertionPoint = Insts.end(); 123 InstList::iterator InsertionPoint = Insts.end();
107 // Every block must end in a terminator instruction. 124 // Every block must end in a terminator instruction.
108 assert(InsertionPoint != Insts.begin()); 125 assert(InsertionPoint != Insts.begin());
109 --InsertionPoint; 126 --InsertionPoint;
110 // Confirm via assert() that InsertionPoint is a terminator 127 // Confirm that InsertionPoint is a terminator instruction. Calling
111 // instruction. Calling getTerminatorEdges() on a non-terminator 128 // getTerminatorEdges() on a non-terminator instruction will cause
112 // instruction will cause an llvm_unreachable(). 129 // an llvm_unreachable().
113 assert(((*InsertionPoint)->getTerminatorEdges(), true)); 130 (void)(*InsertionPoint)->getTerminatorEdges();
131 // If the current insertion point is at a conditional branch
132 // instruction, and the previous instruction is a compare
133 // instruction, then we move the insertion point before the compare
134 // instruction so as not to interfere with compare/branch fusing.
135 if (InstBr *Branch = llvm::dyn_cast<InstBr>(*InsertionPoint)) {
136 if (!Branch->isUnconditional()) {
137 if (InsertionPoint != Insts.begin()) {
138 --InsertionPoint;
139 if (!llvm::isa<InstIcmp>(*InsertionPoint) &&
140 !llvm::isa<InstFcmp>(*InsertionPoint)) {
141 ++InsertionPoint;
142 }
143 }
144 }
145 }
114 146
115 // Consider every out-edge. 147 // Consider every out-edge.
116 for (NodeList::const_iterator I1 = OutEdges.begin(), E1 = OutEdges.end(); 148 for (NodeList::const_iterator I1 = OutEdges.begin(), E1 = OutEdges.end();
117 I1 != E1; ++I1) { 149 I1 != E1; ++I1) {
118 CfgNode *Target = *I1; 150 CfgNode *Target = *I1;
119 // Consider every Phi instruction at the out-edge. 151 // Consider every Phi instruction at the out-edge.
120 for (PhiList::const_iterator I2 = Target->Phis.begin(), 152 for (PhiList::const_iterator I2 = Target->Phis.begin(),
121 E2 = Target->Phis.end(); 153 E2 = Target->Phis.end();
122 I2 != E2; ++I2) { 154 I2 != E2; ++I2) {
123 Operand *Operand = (*I2)->getOperandForTarget(this); 155 Operand *Operand = (*I2)->getOperandForTarget(this);
(...skipping 14 matching lines...) Expand all
138 } 170 }
139 } 171 }
140 172
141 // Deletes the phi instructions after the loads and stores are placed. 173 // Deletes the phi instructions after the loads and stores are placed.
142 void CfgNode::deletePhis() { 174 void CfgNode::deletePhis() {
143 for (PhiList::iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) { 175 for (PhiList::iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
144 (*I)->setDeleted(); 176 (*I)->setDeleted();
145 } 177 }
146 } 178 }
147 179
180 // Does address mode optimization. Pass each instruction to the
181 // TargetLowering object. If it returns a new instruction
182 // (representing the optimized address mode), then insert the new
183 // instruction and delete the old.
184 void CfgNode::doAddressOpt() {
185 TargetLowering *Target = Func->getTarget();
186 LoweringContext &Context = Target->getContext();
187 Context.init(this);
188 while (!Context.atEnd()) {
189 Target->doAddressOpt();
190 }
191 }
192
148 // Drives the target lowering. Passes the current instruction and the 193 // Drives the target lowering. Passes the current instruction and the
149 // next non-deleted instruction for target lowering. 194 // next non-deleted instruction for target lowering.
150 void CfgNode::genCode() { 195 void CfgNode::genCode() {
151 TargetLowering *Target = Func->getTarget(); 196 TargetLowering *Target = Func->getTarget();
152 LoweringContext &Context = Target->getContext(); 197 LoweringContext &Context = Target->getContext();
153 // Lower only the regular instructions. Defer the Phi instructions. 198 // Lower only the regular instructions. Defer the Phi instructions.
154 Context.init(this); 199 Context.init(this);
155 while (!Context.atEnd()) { 200 while (!Context.atEnd()) {
156 InstList::iterator Orig = Context.getCur(); 201 InstList::iterator Orig = Context.getCur();
157 if (llvm::isa<InstRet>(*Orig)) 202 if (llvm::isa<InstRet>(*Orig))
158 setHasReturn(); 203 setHasReturn();
159 Target->lower(); 204 Target->lower();
160 // Ensure target lowering actually moved the cursor. 205 // Ensure target lowering actually moved the cursor.
161 assert(Context.getCur() != Orig); 206 assert(Context.getCur() != Orig);
162 } 207 }
163 } 208 }
164 209
210 void CfgNode::livenessLightweight() {
211 SizeT NumVars = Func->getNumVariables();
212 llvm::BitVector Live(NumVars);
213 // Process regular instructions in reverse order.
214 for (InstList::const_reverse_iterator I = Insts.rbegin(), E = Insts.rend();
215 I != E; ++I) {
216 if ((*I)->isDeleted())
217 continue;
218 (*I)->livenessLightweight(Live);
219 }
220 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
221 if ((*I)->isDeleted())
222 continue;
223 (*I)->livenessLightweight(Live);
224 }
225 }
226
227 // Performs liveness analysis on the block. Returns true if the
228 // incoming liveness changed from before, false if it stayed the same.
229 // (If it changes, the node's predecessors need to be processed
230 // again.)
231 bool CfgNode::liveness(Liveness *Liveness) {
232 SizeT NumVars = Liveness->getNumVarsInNode(this);
233 llvm::BitVector Live(NumVars);
234 // Mark the beginning and ending of each variable's live range
235 // with the sentinel instruction number 0.
236 std::vector<InstNumberT> &LiveBegin = Liveness->getLiveBegin(this);
237 std::vector<InstNumberT> &LiveEnd = Liveness->getLiveEnd(this);
238 LiveBegin.assign(NumVars, Inst::NumberSentinel);
239 LiveEnd.assign(NumVars, Inst::NumberSentinel);
240 // Initialize Live to be the union of all successors' LiveIn.
241 for (NodeList::const_iterator I = OutEdges.begin(), E = OutEdges.end();
242 I != E; ++I) {
243 CfgNode *Succ = *I;
244 Live |= Liveness->getLiveIn(Succ);
245 // Mark corresponding argument of phis in successor as live.
246 for (PhiList::const_iterator I1 = Succ->Phis.begin(), E1 = Succ->Phis.end();
247 I1 != E1; ++I1) {
248 (*I1)->livenessPhiOperand(Live, this, Liveness);
249 }
250 }
251 Liveness->getLiveOut(this) = Live;
252
253 // Process regular instructions in reverse order.
254 for (InstList::const_reverse_iterator I = Insts.rbegin(), E = Insts.rend();
255 I != E; ++I) {
256 if ((*I)->isDeleted())
257 continue;
258 (*I)->liveness((*I)->getNumber(), Live, Liveness, this);
259 }
260 // Process phis in forward order so that we can override the
261 // instruction number to be that of the earliest phi instruction in
262 // the block.
263 InstNumberT FirstPhiNumber = Inst::NumberSentinel;
264 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
265 if ((*I)->isDeleted())
266 continue;
267 if (FirstPhiNumber == Inst::NumberSentinel)
268 FirstPhiNumber = (*I)->getNumber();
269 (*I)->liveness(FirstPhiNumber, Live, Liveness, this);
270 }
271
272 // When using the sparse representation, after traversing the
273 // instructions in the block, the Live bitvector should only contain
274 // set bits for global variables upon block entry. We validate this
275 // by shrinking the Live vector and then testing it against the
276 // pre-shrunk version. (The shrinking is required, but the
277 // validation is not.)
278 llvm::BitVector LiveOrig = Live;
279 Live.resize(Liveness->getNumGlobalVars());
280 // Non-global arguments in the entry node are allowed to be live on
281 // entry.
282 bool IsEntry = (Func->getEntryNode() == this);
283 if (!(IsEntry || Live == LiveOrig)) {
284 // This is a fatal liveness consistency error. Print some
285 // diagnostics and abort.
286 Ostream &Str = Func->getContext()->getStrDump();
287 Func->setCurrentNode(NULL);
288 Str << "LiveOrig-Live =";
289 for (SizeT i = Live.size(); i < LiveOrig.size(); ++i) {
290 if (LiveOrig.test(i)) {
291 Str << " ";
292 Liveness->getVariable(i, this)->dump(Func);
293 }
294 }
295 Str << "\n";
296 llvm_unreachable("Fatal inconsistency in liveness analysis");
297 }
298
299 bool Changed = false;
300 llvm::BitVector &LiveIn = Liveness->getLiveIn(this);
301 // Add in current LiveIn
302 Live |= LiveIn;
303 // Check result, set LiveIn=Live
304 Changed = (Live != LiveIn);
305 if (Changed)
306 LiveIn = Live;
307 return Changed;
308 }
309
310 // Now that basic liveness is complete, remove dead instructions that
311 // were tentatively marked as dead, and compute actual live ranges.
312 // It is assumed that within a single basic block, a live range begins
313 // at most once and ends at most once. This is certainly true for
314 // pure SSA form. It is also true once phis are lowered, since each
315 // assignment to the phi-based temporary is in a different basic
316 // block, and there is a single read that ends the live in the basic
317 // block that contained the actual phi instruction.
318 void CfgNode::livenessPostprocess(LivenessMode Mode, Liveness *Liveness) {
319 InstNumberT FirstInstNum = Inst::NumberSentinel;
320 InstNumberT LastInstNum = Inst::NumberSentinel;
321 // Process phis in any order. Process only Dest operands.
322 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
323 InstPhi *Inst = *I;
324 Inst->deleteIfDead();
325 if (Inst->isDeleted())
326 continue;
327 if (FirstInstNum == Inst::NumberSentinel)
328 FirstInstNum = Inst->getNumber();
329 assert(Inst->getNumber() > LastInstNum);
330 LastInstNum = Inst->getNumber();
331 }
332 // Process instructions
333 for (InstList::const_iterator I = Insts.begin(), E = Insts.end(); I != E;
334 ++I) {
335 Inst *Inst = *I;
336 Inst->deleteIfDead();
337 if (Inst->isDeleted())
338 continue;
339 if (FirstInstNum == Inst::NumberSentinel)
340 FirstInstNum = Inst->getNumber();
341 assert(Inst->getNumber() > LastInstNum);
342 LastInstNum = Inst->getNumber();
343 // Create fake live ranges for a Kill instruction, but only if the
344 // linked instruction is still alive.
345 if (Mode == Liveness_Intervals) {
346 if (InstFakeKill *Kill = llvm::dyn_cast<InstFakeKill>(Inst)) {
347 if (!Kill->getLinked()->isDeleted()) {
348 SizeT NumSrcs = Inst->getSrcSize();
349 for (SizeT i = 0; i < NumSrcs; ++i) {
350 Variable *Var = llvm::cast<Variable>(Inst->getSrc(i));
351 InstNumberT InstNumber = Inst->getNumber();
352 Liveness->addLiveRange(Var, InstNumber, InstNumber, 1);
353 }
354 }
355 }
356 }
357 }
358 if (Mode != Liveness_Intervals)
359 return;
360
361 SizeT NumVars = Liveness->getNumVarsInNode(this);
362 SizeT NumGlobals = Liveness->getNumGlobalVars();
363 llvm::BitVector &LiveIn = Liveness->getLiveIn(this);
364 llvm::BitVector &LiveOut = Liveness->getLiveOut(this);
365 std::vector<InstNumberT> &LiveBegin = Liveness->getLiveBegin(this);
366 std::vector<InstNumberT> &LiveEnd = Liveness->getLiveEnd(this);
367 for (SizeT i = 0; i < NumVars; ++i) {
368 // Deal with the case where the variable is both live-in and
369 // live-out, but LiveEnd comes before LiveBegin. In this case, we
370 // need to add two segments to the live range because there is a
371 // hole in the middle. This would typically happen as a result of
372 // phi lowering in the presence of loopback edges.
373 bool IsGlobal = (i < NumGlobals);
374 if (IsGlobal && LiveIn[i] && LiveOut[i] && LiveBegin[i] > LiveEnd[i]) {
375 Variable *Var = Liveness->getVariable(i, this);
376 Liveness->addLiveRange(Var, FirstInstNum, LiveEnd[i], 1);
377 Liveness->addLiveRange(Var, LiveBegin[i], LastInstNum + 1, 1);
378 continue;
379 }
380 InstNumberT Begin = (IsGlobal && LiveIn[i]) ? FirstInstNum : LiveBegin[i];
381 InstNumberT End = (IsGlobal && LiveOut[i]) ? LastInstNum + 1 : LiveEnd[i];
382 if (Begin == Inst::NumberSentinel && End == Inst::NumberSentinel)
383 continue;
384 if (Begin <= FirstInstNum)
385 Begin = FirstInstNum;
386 if (End == Inst::NumberSentinel)
387 End = LastInstNum + 1;
388 Variable *Var = Liveness->getVariable(i, this);
389 Liveness->addLiveRange(Var, Begin, End, 1);
390 }
391 }
392
165 // ======================== Dump routines ======================== // 393 // ======================== Dump routines ======================== //
166 394
167 void CfgNode::emit(Cfg *Func) const { 395 void CfgNode::emit(Cfg *Func) const {
168 Func->setCurrentNode(this); 396 Func->setCurrentNode(this);
169 Ostream &Str = Func->getContext()->getStrEmit(); 397 Ostream &Str = Func->getContext()->getStrEmit();
170 if (Func->getEntryNode() == this) { 398 if (Func->getEntryNode() == this) {
171 Str << Func->getContext()->mangleName(Func->getFunctionName()) << ":\n"; 399 Str << Func->getContext()->mangleName(Func->getFunctionName()) << ":\n";
172 } 400 }
173 Str << getAsmName() << ":\n"; 401 Str << getAsmName() << ":\n";
174 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) { 402 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; ++I) {
(...skipping 12 matching lines...) Expand all
187 // suppress them. 415 // suppress them.
188 if (Inst->isRedundantAssign()) 416 if (Inst->isRedundantAssign())
189 continue; 417 continue;
190 (*I)->emit(Func); 418 (*I)->emit(Func);
191 } 419 }
192 } 420 }
193 421
194 void CfgNode::dump(Cfg *Func) const { 422 void CfgNode::dump(Cfg *Func) const {
195 Func->setCurrentNode(this); 423 Func->setCurrentNode(this);
196 Ostream &Str = Func->getContext()->getStrDump(); 424 Ostream &Str = Func->getContext()->getStrDump();
425 Liveness *Liveness = Func->getLiveness();
197 if (Func->getContext()->isVerbose(IceV_Instructions)) { 426 if (Func->getContext()->isVerbose(IceV_Instructions)) {
198 Str << getName() << ":\n"; 427 Str << getName() << ":\n";
199 } 428 }
200 // Dump list of predecessor nodes. 429 // Dump list of predecessor nodes.
201 if (Func->getContext()->isVerbose(IceV_Preds) && !InEdges.empty()) { 430 if (Func->getContext()->isVerbose(IceV_Preds) && !InEdges.empty()) {
202 Str << " // preds = "; 431 Str << " // preds = ";
203 for (NodeList::const_iterator I = InEdges.begin(), E = InEdges.end(); 432 for (NodeList::const_iterator I = InEdges.begin(), E = InEdges.end();
204 I != E; ++I) { 433 I != E; ++I) {
205 if (I != InEdges.begin()) 434 if (I != InEdges.begin())
206 Str << ", "; 435 Str << ", ";
207 Str << "%" << (*I)->getName(); 436 Str << "%" << (*I)->getName();
208 } 437 }
209 Str << "\n"; 438 Str << "\n";
210 } 439 }
440 // Dump the live-in variables.
441 llvm::BitVector LiveIn;
442 if (Liveness)
443 LiveIn = Liveness->getLiveIn(this);
444 if (Func->getContext()->isVerbose(IceV_Liveness) && !LiveIn.empty()) {
445 Str << " // LiveIn:";
446 for (SizeT i = 0; i < LiveIn.size(); ++i) {
447 if (LiveIn[i]) {
448 Str << " %" << Liveness->getVariable(i, this)->getName();
449 }
450 }
451 Str << "\n";
452 }
211 // Dump each instruction. 453 // Dump each instruction.
212 if (Func->getContext()->isVerbose(IceV_Instructions)) { 454 if (Func->getContext()->isVerbose(IceV_Instructions)) {
213 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E; 455 for (PhiList::const_iterator I = Phis.begin(), E = Phis.end(); I != E;
214 ++I) { 456 ++I) {
215 const Inst *Inst = *I; 457 const Inst *Inst = *I;
216 Inst->dumpDecorated(Func); 458 Inst->dumpDecorated(Func);
217 } 459 }
218 InstList::const_iterator I = Insts.begin(), E = Insts.end(); 460 InstList::const_iterator I = Insts.begin(), E = Insts.end();
219 while (I != E) { 461 while (I != E) {
220 Inst *Inst = *I++; 462 Inst *Inst = *I++;
221 Inst->dumpDecorated(Func); 463 Inst->dumpDecorated(Func);
222 } 464 }
223 } 465 }
466 // Dump the live-out variables.
467 llvm::BitVector LiveOut;
468 if (Liveness)
469 LiveOut = Liveness->getLiveOut(this);
470 if (Func->getContext()->isVerbose(IceV_Liveness) && !LiveOut.empty()) {
471 Str << " // LiveOut:";
472 for (SizeT i = 0; i < LiveOut.size(); ++i) {
473 if (LiveOut[i]) {
474 Str << " %" << Liveness->getVariable(i, this)->getName();
475 }
476 }
477 Str << "\n";
478 }
224 // Dump list of successor nodes. 479 // Dump list of successor nodes.
225 if (Func->getContext()->isVerbose(IceV_Succs)) { 480 if (Func->getContext()->isVerbose(IceV_Succs)) {
226 Str << " // succs = "; 481 Str << " // succs = ";
227 for (NodeList::const_iterator I = OutEdges.begin(), E = OutEdges.end(); 482 for (NodeList::const_iterator I = OutEdges.begin(), E = OutEdges.end();
228 I != E; ++I) { 483 I != E; ++I) {
229 if (I != OutEdges.begin()) 484 if (I != OutEdges.begin())
230 Str << ", "; 485 Str << ", ";
231 Str << "%" << (*I)->getName(); 486 Str << "%" << (*I)->getName();
232 } 487 }
233 Str << "\n"; 488 Str << "\n";
234 } 489 }
235 } 490 }
236 491
237 } // end of namespace Ice 492 } // end of namespace Ice
OLDNEW
« no previous file with comments | « src/IceCfgNode.h ('k') | src/IceDefs.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698