• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- subzero/src/IceOperand.cpp - High-level operand implementation -----===//
2 //
3 //                        The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Implements the Operand class and its target-independent subclasses,
12 /// primarily for the methods of the Variable class.
13 ///
14 //===----------------------------------------------------------------------===//
15 
16 #include "IceOperand.h"
17 
18 #include "IceCfg.h"
19 #include "IceCfgNode.h"
20 #include "IceInst.h"
21 #include "IceInstVarIter.h"
22 #include "IceMemory.h"
23 #include "IceTargetLowering.h" // dumping stack/frame pointer register
24 
25 namespace Ice {
26 
initShouldBePooled()27 void Constant::initShouldBePooled() {
28   ShouldBePooled = TargetLowering::shouldBePooled(this);
29 }
30 
operator ==(const RelocatableTuple & A,const RelocatableTuple & B)31 bool operator==(const RelocatableTuple &A, const RelocatableTuple &B) {
32   // A and B are the same if:
33   //   (1) they have the same name; and
34   //   (2) they have the same offset.
35   //
36   // (1) is trivial to check, but (2) requires some care.
37   //
38   // For (2):
39   //  if A and B have known offsets (i.e., no symbolic references), then
40   //     A == B -> A.Offset == B.Offset.
41   //  else each element i in A.OffsetExpr[i] must be the same (or have the same
42   //    value) as B.OffsetExpr[i].
43   if (A.Name != B.Name) {
44     return false;
45   }
46 
47   bool BothHaveKnownOffsets = true;
48   RelocOffsetT OffsetA = A.Offset;
49   RelocOffsetT OffsetB = B.Offset;
50   for (SizeT i = 0; i < A.OffsetExpr.size() && BothHaveKnownOffsets; ++i) {
51     BothHaveKnownOffsets = A.OffsetExpr[i]->hasOffset();
52     if (BothHaveKnownOffsets) {
53       OffsetA += A.OffsetExpr[i]->getOffset();
54     }
55   }
56   for (SizeT i = 0; i < B.OffsetExpr.size() && BothHaveKnownOffsets; ++i) {
57     BothHaveKnownOffsets = B.OffsetExpr[i]->hasOffset();
58     if (BothHaveKnownOffsets) {
59       OffsetB += B.OffsetExpr[i]->getOffset();
60     }
61   }
62   if (BothHaveKnownOffsets) {
63     // Both have known offsets (i.e., no unresolved symbolic references), so
64     // A == B -> A.Offset == B.Offset.
65     return OffsetA == OffsetB;
66   }
67 
68   // Otherwise, A and B are not the same if their OffsetExpr's have different
69   // sizes.
70   if (A.OffsetExpr.size() != B.OffsetExpr.size()) {
71     return false;
72   }
73 
74   // If the OffsetExprs' sizes are the same, then
75   // for each i in OffsetExprSize:
76   for (SizeT i = 0; i < A.OffsetExpr.size(); ++i) {
77     const auto *const RelocOffsetA = A.OffsetExpr[i];
78     const auto *const RelocOffsetB = B.OffsetExpr[i];
79     if (RelocOffsetA->hasOffset() && RelocOffsetB->hasOffset()) {
80       // A.OffsetExpr[i].Offset == B.OffsetExpr[i].Offset iff they are both
81       // defined;
82       if (RelocOffsetA->getOffset() != RelocOffsetB->getOffset()) {
83         return false;
84       }
85     } else if (RelocOffsetA != RelocOffsetB) {
86       // or, if they are undefined, then the RelocOffsets must be the same.
87       return false;
88     }
89   }
90 
91   return true;
92 }
93 
94 RegNumT::BaseType RegNumT::Limit = 0;
95 
operator <(const RegWeight & A,const RegWeight & B)96 bool operator<(const RegWeight &A, const RegWeight &B) {
97   return A.getWeight() < B.getWeight();
98 }
operator <=(const RegWeight & A,const RegWeight & B)99 bool operator<=(const RegWeight &A, const RegWeight &B) { return !(B < A); }
operator ==(const RegWeight & A,const RegWeight & B)100 bool operator==(const RegWeight &A, const RegWeight &B) {
101   return !(B < A) && !(A < B);
102 }
103 
addSegment(InstNumberT Start,InstNumberT End,CfgNode * Node)104 void LiveRange::addSegment(InstNumberT Start, InstNumberT End, CfgNode *Node) {
105   if (getFlags().getSplitGlobalVars()) {
106     // Disable merging to make sure a live range 'segment' has a single node.
107     // Might be possible to enable when the target segment has the same node.
108     assert(NodeMap.find(Start) == NodeMap.end());
109     NodeMap[Start] = Node;
110   } else {
111     if (!Range.empty()) {
112       // Check for merge opportunity.
113       InstNumberT CurrentEnd = Range.back().second;
114       assert(Start >= CurrentEnd);
115       if (Start == CurrentEnd) {
116         Range.back().second = End;
117         return;
118       }
119     }
120   }
121   Range.push_back(RangeElementType(Start, End));
122 }
123 
124 // Returns true if this live range ends before Other's live range starts. This
125 // means that the highest instruction number in this live range is less than or
126 // equal to the lowest instruction number of the Other live range.
endsBefore(const LiveRange & Other) const127 bool LiveRange::endsBefore(const LiveRange &Other) const {
128   // Neither range should be empty, but let's be graceful.
129   if (Range.empty() || Other.Range.empty())
130     return true;
131   InstNumberT MyEnd = (*Range.rbegin()).second;
132   InstNumberT OtherStart = (*Other.Range.begin()).first;
133   return MyEnd <= OtherStart;
134 }
135 
136 // Returns true if there is any overlap between the two live ranges.
overlaps(const LiveRange & Other,bool UseTrimmed) const137 bool LiveRange::overlaps(const LiveRange &Other, bool UseTrimmed) const {
138   // Do a two-finger walk through the two sorted lists of segments.
139   auto I1 = (UseTrimmed ? TrimmedBegin : Range.begin()),
140        I2 = (UseTrimmed ? Other.TrimmedBegin : Other.Range.begin());
141   auto E1 = Range.end(), E2 = Other.Range.end();
142   while (I1 != E1 && I2 != E2) {
143     if (I1->second <= I2->first) {
144       ++I1;
145       continue;
146     }
147     if (I2->second <= I1->first) {
148       ++I2;
149       continue;
150     }
151     return true;
152   }
153   return false;
154 }
155 
overlapsInst(InstNumberT OtherBegin,bool UseTrimmed) const156 bool LiveRange::overlapsInst(InstNumberT OtherBegin, bool UseTrimmed) const {
157   bool Result = false;
158   for (auto I = (UseTrimmed ? TrimmedBegin : Range.begin()), E = Range.end();
159        I != E; ++I) {
160     if (OtherBegin < I->first) {
161       Result = false;
162       break;
163     }
164     if (OtherBegin < I->second) {
165       Result = true;
166       break;
167     }
168   }
169   // This is an equivalent but less inefficient implementation. It's expensive
170   // enough that we wouldn't want to run it under any build, but it could be
171   // enabled if e.g. the LiveRange implementation changes and extra testing is
172   // needed.
173   if (BuildDefs::extraValidation()) {
174     LiveRange Temp;
175     Temp.addSegment(OtherBegin, OtherBegin + 1);
176     bool Validation = overlaps(Temp);
177     (void)Validation;
178     assert(Result == Validation);
179   }
180   return Result;
181 }
182 
183 // Returns true if the live range contains the given instruction number. This
184 // is only used for validating the live range calculation. The IsDest argument
185 // indicates whether the Variable being tested is used in the Dest position (as
186 // opposed to a Src position).
containsValue(InstNumberT Value,bool IsDest) const187 bool LiveRange::containsValue(InstNumberT Value, bool IsDest) const {
188   for (const RangeElementType &I : Range) {
189     if (I.first <= Value &&
190         (Value < I.second || (!IsDest && Value == I.second)))
191       return true;
192   }
193   return false;
194 }
195 
trim(InstNumberT Lower)196 void LiveRange::trim(InstNumberT Lower) {
197   while (TrimmedBegin != Range.end() && TrimmedBegin->second <= Lower)
198     ++TrimmedBegin;
199 }
200 
asType(const Cfg * Func,Type Ty,RegNumT NewRegNum) const201 const Variable *Variable::asType(const Cfg *Func, Type Ty,
202                                  RegNumT NewRegNum) const {
203   // Note: This returns a Variable, even if the "this" object is a subclass of
204   // Variable.
205   if (!BuildDefs::dump() || getType() == Ty)
206     return this;
207   static constexpr SizeT One = 1;
208   auto *V = new (CfgLocalAllocator<Variable>().allocate(One))
209       Variable(Func, kVariable, Ty, Number);
210   V->Name = Name;
211   V->RegNum = NewRegNum.hasValue() ? NewRegNum : RegNum;
212   V->StackOffset = StackOffset;
213   V->LinkedTo = LinkedTo;
214   return V;
215 }
216 
getWeight(const Cfg * Func) const217 RegWeight Variable::getWeight(const Cfg *Func) const {
218   if (mustHaveReg())
219     return RegWeight(RegWeight::Inf);
220   if (mustNotHaveReg())
221     return RegWeight(RegWeight::Zero);
222   return Func->getVMetadata()->getUseWeight(this);
223 }
224 
markUse(MetadataKind TrackingKind,const Inst * Instr,CfgNode * Node,bool IsImplicit)225 void VariableTracking::markUse(MetadataKind TrackingKind, const Inst *Instr,
226                                CfgNode *Node, bool IsImplicit) {
227   (void)TrackingKind;
228 
229   // Increment the use weight depending on the loop nest depth. The weight is
230   // exponential in the nest depth as inner loops are expected to be executed
231   // an exponentially greater number of times.
232   constexpr uint32_t LogLoopTripCountEstimate = 2; // 2^2 = 4
233   constexpr SizeT MaxShift = sizeof(uint32_t) * CHAR_BIT - 1;
234   constexpr SizeT MaxLoopNestDepth = MaxShift / LogLoopTripCountEstimate;
235   const uint32_t LoopNestDepth =
236       std::min(Node->getLoopNestDepth(), MaxLoopNestDepth);
237   const uint32_t ThisUseWeight = uint32_t(1)
238                                  << LoopNestDepth * LogLoopTripCountEstimate;
239   UseWeight.addWeight(ThisUseWeight);
240 
241   if (MultiBlock == MBS_MultiBlock)
242     return;
243   // TODO(stichnot): If the use occurs as a source operand in the first
244   // instruction of the block, and its definition is in this block's only
245   // predecessor, we might consider not marking this as a separate use. This
246   // may also apply if it's the first instruction of the block that actually
247   // uses a Variable.
248   assert(Node);
249   bool MakeMulti = false;
250   if (IsImplicit)
251     MakeMulti = true;
252   // A phi source variable conservatively needs to be marked as multi-block,
253   // even if its definition is in the same block. This is because there can be
254   // additional control flow before branching back to this node, and the
255   // variable is live throughout those nodes.
256   if (Instr && llvm::isa<InstPhi>(Instr))
257     MakeMulti = true;
258 
259   if (!MakeMulti) {
260     switch (MultiBlock) {
261     case MBS_Unknown:
262     case MBS_NoUses:
263       MultiBlock = MBS_SingleBlock;
264       SingleUseNode = Node;
265       break;
266     case MBS_SingleBlock:
267       if (SingleUseNode != Node)
268         MakeMulti = true;
269       break;
270     case MBS_MultiBlock:
271       break;
272     }
273   }
274 
275   if (MakeMulti) {
276     MultiBlock = MBS_MultiBlock;
277     SingleUseNode = nullptr;
278   }
279 }
280 
markDef(MetadataKind TrackingKind,const Inst * Instr,CfgNode * Node)281 void VariableTracking::markDef(MetadataKind TrackingKind, const Inst *Instr,
282                                CfgNode *Node) {
283   // TODO(stichnot): If the definition occurs in the last instruction of the
284   // block, consider not marking this as a separate use. But be careful not to
285   // omit all uses of the variable if markDef() and markUse() both use this
286   // optimization.
287   assert(Node);
288   // Verify that instructions are added in increasing order.
289   if (BuildDefs::asserts()) {
290     if (TrackingKind == VMK_All) {
291       const Inst *LastInstruction =
292           Definitions.empty() ? FirstOrSingleDefinition : Definitions.back();
293       (void)LastInstruction;
294       assert(LastInstruction == nullptr ||
295              Instr->getNumber() >= LastInstruction->getNumber());
296     }
297   }
298   constexpr bool IsImplicit = false;
299   markUse(TrackingKind, Instr, Node, IsImplicit);
300   if (TrackingKind == VMK_Uses)
301     return;
302   if (FirstOrSingleDefinition == nullptr)
303     FirstOrSingleDefinition = Instr;
304   else if (TrackingKind == VMK_All)
305     Definitions.push_back(Instr);
306   switch (MultiDef) {
307   case MDS_Unknown:
308     assert(SingleDefNode == nullptr);
309     MultiDef = MDS_SingleDef;
310     SingleDefNode = Node;
311     break;
312   case MDS_SingleDef:
313     assert(SingleDefNode);
314     if (Node == SingleDefNode) {
315       MultiDef = MDS_MultiDefSingleBlock;
316     } else {
317       MultiDef = MDS_MultiDefMultiBlock;
318       SingleDefNode = nullptr;
319     }
320     break;
321   case MDS_MultiDefSingleBlock:
322     assert(SingleDefNode);
323     if (Node != SingleDefNode) {
324       MultiDef = MDS_MultiDefMultiBlock;
325       SingleDefNode = nullptr;
326     }
327     break;
328   case MDS_MultiDefMultiBlock:
329     assert(SingleDefNode == nullptr);
330     break;
331   }
332 }
333 
getFirstDefinitionSingleBlock() const334 const Inst *VariableTracking::getFirstDefinitionSingleBlock() const {
335   switch (MultiDef) {
336   case MDS_Unknown:
337   case MDS_MultiDefMultiBlock:
338     return nullptr;
339   case MDS_SingleDef:
340   case MDS_MultiDefSingleBlock:
341     assert(FirstOrSingleDefinition);
342     return FirstOrSingleDefinition;
343   }
344   return nullptr;
345 }
346 
getSingleDefinition() const347 const Inst *VariableTracking::getSingleDefinition() const {
348   switch (MultiDef) {
349   case MDS_Unknown:
350   case MDS_MultiDefMultiBlock:
351   case MDS_MultiDefSingleBlock:
352     return nullptr;
353   case MDS_SingleDef:
354     assert(FirstOrSingleDefinition);
355     return FirstOrSingleDefinition;
356   }
357   return nullptr;
358 }
359 
getFirstDefinition() const360 const Inst *VariableTracking::getFirstDefinition() const {
361   switch (MultiDef) {
362   case MDS_Unknown:
363     return nullptr;
364   case MDS_MultiDefMultiBlock:
365   case MDS_SingleDef:
366   case MDS_MultiDefSingleBlock:
367     assert(FirstOrSingleDefinition);
368     return FirstOrSingleDefinition;
369   }
370   return nullptr;
371 }
372 
init(MetadataKind TrackingKind)373 void VariablesMetadata::init(MetadataKind TrackingKind) {
374   TimerMarker T(TimerStack::TT_vmetadata, Func);
375   Kind = TrackingKind;
376   Metadata.clear();
377   Metadata.resize(Func->getNumVariables(), VariableTracking::MBS_NoUses);
378 
379   // Mark implicit args as being used in the entry node.
380   for (Variable *Var : Func->getImplicitArgs()) {
381     constexpr Inst *NoInst = nullptr;
382     CfgNode *EntryNode = Func->getEntryNode();
383     constexpr bool IsImplicit = true;
384     Metadata[Var->getIndex()].markUse(Kind, NoInst, EntryNode, IsImplicit);
385   }
386 
387   for (CfgNode *Node : Func->getNodes())
388     addNode(Node);
389 }
390 
addNode(CfgNode * Node)391 void VariablesMetadata::addNode(CfgNode *Node) {
392   if (Func->getNumVariables() > Metadata.size())
393     Metadata.resize(Func->getNumVariables());
394 
395   for (Inst &I : Node->getPhis()) {
396     if (I.isDeleted())
397       continue;
398     if (Variable *Dest = I.getDest()) {
399       SizeT DestNum = Dest->getIndex();
400       assert(DestNum < Metadata.size());
401       Metadata[DestNum].markDef(Kind, &I, Node);
402     }
403     for (SizeT SrcNum = 0; SrcNum < I.getSrcSize(); ++SrcNum) {
404       if (auto *Var = llvm::dyn_cast<Variable>(I.getSrc(SrcNum))) {
405         SizeT VarNum = Var->getIndex();
406         assert(VarNum < Metadata.size());
407         constexpr bool IsImplicit = false;
408         Metadata[VarNum].markUse(Kind, &I, Node, IsImplicit);
409       }
410     }
411   }
412 
413   for (Inst &I : Node->getInsts()) {
414     if (I.isDeleted())
415       continue;
416     // Note: The implicit definitions (and uses) from InstFakeKill are
417     // deliberately ignored.
418     if (Variable *Dest = I.getDest()) {
419       SizeT DestNum = Dest->getIndex();
420       assert(DestNum < Metadata.size());
421       Metadata[DestNum].markDef(Kind, &I, Node);
422     }
423     FOREACH_VAR_IN_INST(Var, I) {
424       SizeT VarNum = Var->getIndex();
425       assert(VarNum < Metadata.size());
426       constexpr bool IsImplicit = false;
427       Metadata[VarNum].markUse(Kind, &I, Node, IsImplicit);
428     }
429   }
430 }
431 
isMultiDef(const Variable * Var) const432 bool VariablesMetadata::isMultiDef(const Variable *Var) const {
433   assert(Kind != VMK_Uses);
434   if (Var->getIsArg())
435     return false;
436   if (!isTracked(Var))
437     return true; // conservative answer
438   SizeT VarNum = Var->getIndex();
439   // Conservatively return true if the state is unknown.
440   return Metadata[VarNum].getMultiDef() != VariableTracking::MDS_SingleDef;
441 }
442 
isMultiBlock(const Variable * Var) const443 bool VariablesMetadata::isMultiBlock(const Variable *Var) const {
444   if (Var->getIsArg())
445     return true;
446   if (Var->isRematerializable())
447     return false;
448   if (!isTracked(Var))
449     return true; // conservative answer
450   SizeT VarNum = Var->getIndex();
451   switch (Metadata[VarNum].getMultiBlock()) {
452   case VariableTracking::MBS_NoUses:
453   case VariableTracking::MBS_SingleBlock:
454     return false;
455   // Conservatively return true if the state is unknown.
456   case VariableTracking::MBS_Unknown:
457   case VariableTracking::MBS_MultiBlock:
458     return true;
459   }
460   assert(0);
461   return true;
462 }
463 
isSingleBlock(const Variable * Var) const464 bool VariablesMetadata::isSingleBlock(const Variable *Var) const {
465   if (Var->getIsArg())
466     return false;
467   if (Var->isRematerializable())
468     return false;
469   if (!isTracked(Var))
470     return false; // conservative answer
471   SizeT VarNum = Var->getIndex();
472   switch (Metadata[VarNum].getMultiBlock()) {
473   case VariableTracking::MBS_SingleBlock:
474     return true;
475   case VariableTracking::MBS_Unknown:
476   case VariableTracking::MBS_NoUses:
477   case VariableTracking::MBS_MultiBlock:
478     return false;
479   }
480   assert(0);
481   return false;
482 }
483 
484 const Inst *
getFirstDefinitionSingleBlock(const Variable * Var) const485 VariablesMetadata::getFirstDefinitionSingleBlock(const Variable *Var) const {
486   assert(Kind != VMK_Uses);
487   if (!isTracked(Var))
488     return nullptr; // conservative answer
489   SizeT VarNum = Var->getIndex();
490   return Metadata[VarNum].getFirstDefinitionSingleBlock();
491 }
492 
getSingleDefinition(const Variable * Var) const493 const Inst *VariablesMetadata::getSingleDefinition(const Variable *Var) const {
494   assert(Kind != VMK_Uses);
495   if (!isTracked(Var))
496     return nullptr; // conservative answer
497   SizeT VarNum = Var->getIndex();
498   return Metadata[VarNum].getSingleDefinition();
499 }
500 
getFirstDefinition(const Variable * Var) const501 const Inst *VariablesMetadata::getFirstDefinition(const Variable *Var) const {
502   assert(Kind != VMK_Uses);
503   if (!isTracked(Var))
504     return nullptr; // conservative answer
505   SizeT VarNum = Var->getIndex();
506   return Metadata[VarNum].getFirstDefinition();
507 }
508 
509 const InstDefList &
getLatterDefinitions(const Variable * Var) const510 VariablesMetadata::getLatterDefinitions(const Variable *Var) const {
511   assert(Kind == VMK_All);
512   if (!isTracked(Var)) {
513     // NoDefinitions has to be initialized after we've had a chance to set the
514     // CfgAllocator, so it can't be a static global object. Also, while C++11
515     // guarantees the initialization of static local objects to be thread-safe,
516     // we use a pointer to it so we can avoid frequent  mutex locking overhead.
517     if (NoDefinitions == nullptr) {
518       static const InstDefList NoDefinitionsInstance;
519       NoDefinitions = &NoDefinitionsInstance;
520     }
521     return *NoDefinitions;
522   }
523   SizeT VarNum = Var->getIndex();
524   return Metadata[VarNum].getLatterDefinitions();
525 }
526 
getLocalUseNode(const Variable * Var) const527 CfgNode *VariablesMetadata::getLocalUseNode(const Variable *Var) const {
528   if (!isTracked(Var))
529     return nullptr; // conservative answer
530   SizeT VarNum = Var->getIndex();
531   return Metadata[VarNum].getNode();
532 }
533 
getUseWeight(const Variable * Var) const534 RegWeight VariablesMetadata::getUseWeight(const Variable *Var) const {
535   if (!isTracked(Var))
536     return RegWeight(1); // conservative answer
537   SizeT VarNum = Var->getIndex();
538   return Metadata[VarNum].getUseWeight();
539 }
540 
541 const InstDefList *VariablesMetadata::NoDefinitions = nullptr;
542 
543 // ======================== dump routines ======================== //
544 
emit(const Cfg * Func) const545 void Variable::emit(const Cfg *Func) const {
546   if (BuildDefs::dump())
547     Func->getTarget()->emitVariable(this);
548 }
549 
dump(const Cfg * Func,Ostream & Str) const550 void Variable::dump(const Cfg *Func, Ostream &Str) const {
551   if (!BuildDefs::dump())
552     return;
553   if (Func == nullptr) {
554     Str << "%" << getName();
555     return;
556   }
557   if (Func->isVerbose(IceV_RegOrigins) ||
558       (!hasReg() && !Func->getTarget()->hasComputedFrame())) {
559     Str << "%" << getName();
560     for (Variable *Link = getLinkedTo(); Link != nullptr;
561          Link = Link->getLinkedTo()) {
562       Str << ":%" << Link->getName();
563     }
564   }
565   if (hasReg()) {
566     if (Func->isVerbose(IceV_RegOrigins))
567       Str << ":";
568     Str << Func->getTarget()->getRegName(RegNum, getType());
569   } else if (Func->getTarget()->hasComputedFrame()) {
570     if (Func->isVerbose(IceV_RegOrigins))
571       Str << ":";
572     const auto BaseRegisterNumber =
573         hasReg() ? getBaseRegNum() : Func->getTarget()->getFrameOrStackReg();
574     Str << "["
575         << Func->getTarget()->getRegName(BaseRegisterNumber, IceType_i32);
576     if (hasKnownStackOffset()) {
577       int32_t Offset = getStackOffset();
578       if (Offset) {
579         if (Offset > 0)
580           Str << "+";
581         Str << Offset;
582       }
583     }
584     Str << "]";
585   }
586 }
587 
emit(TargetLowering * Target) const588 template <> void ConstantInteger32::emit(TargetLowering *Target) const {
589   Target->emit(this);
590 }
591 
emit(TargetLowering * Target) const592 template <> void ConstantInteger64::emit(TargetLowering *Target) const {
593   Target->emit(this);
594 }
595 
emit(TargetLowering * Target) const596 template <> void ConstantFloat::emit(TargetLowering *Target) const {
597   Target->emit(this);
598 }
599 
emit(TargetLowering * Target) const600 template <> void ConstantDouble::emit(TargetLowering *Target) const {
601   Target->emit(this);
602 }
603 
emit(TargetLowering * Target) const604 void ConstantRelocatable::emit(TargetLowering *Target) const {
605   Target->emit(this);
606 }
607 
emitWithoutPrefix(const TargetLowering * Target,const char * Suffix) const608 void ConstantRelocatable::emitWithoutPrefix(const TargetLowering *Target,
609                                             const char *Suffix) const {
610   Target->emitWithoutPrefix(this, Suffix);
611 }
612 
dump(const Cfg *,Ostream & Str) const613 void ConstantRelocatable::dump(const Cfg *, Ostream &Str) const {
614   if (!BuildDefs::dump())
615     return;
616   if (!EmitString.empty()) {
617     Str << EmitString;
618     return;
619   }
620   Str << "@" << (Name.hasStdString() ? Name.toString() : "<Unnamed>");
621   const RelocOffsetT Offset = getOffset();
622   if (Offset) {
623     if (Offset >= 0) {
624       Str << "+";
625     }
626     Str << Offset;
627   }
628 }
629 
emit(TargetLowering * Target) const630 void ConstantUndef::emit(TargetLowering *Target) const { Target->emit(this); }
631 
dump(Ostream & Str) const632 void LiveRange::dump(Ostream &Str) const {
633   if (!BuildDefs::dump())
634     return;
635   bool First = true;
636   for (const RangeElementType &I : Range) {
637     if (!First)
638       Str << ", ";
639     First = false;
640     Str << "[" << I.first << ":" << I.second << ")";
641   }
642 }
643 
operator <<(Ostream & Str,const LiveRange & L)644 Ostream &operator<<(Ostream &Str, const LiveRange &L) {
645   if (!BuildDefs::dump())
646     return Str;
647   L.dump(Str);
648   return Str;
649 }
650 
operator <<(Ostream & Str,const RegWeight & W)651 Ostream &operator<<(Ostream &Str, const RegWeight &W) {
652   if (!BuildDefs::dump())
653     return Str;
654   if (W.getWeight() == RegWeight::Inf)
655     Str << "Inf";
656   else
657     Str << W.getWeight();
658   return Str;
659 }
660 
661 } // end of namespace Ice
662