/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/lib/MC/MCFragment.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===- lib/MC/MCFragment.cpp - Assembler Fragment Implementation ----------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "llvm/MC/MCFragment.h" |
10 | | #include "llvm/ADT/SmallVector.h" |
11 | | #include "llvm/ADT/StringExtras.h" |
12 | | #include "llvm/ADT/Twine.h" |
13 | | #include "llvm/Config/llvm-config.h" |
14 | | #include "llvm/MC/MCAsmLayout.h" |
15 | | #include "llvm/MC/MCAssembler.h" |
16 | | #include "llvm/MC/MCContext.h" |
17 | | #include "llvm/MC/MCExpr.h" |
18 | | #include "llvm/MC/MCFixup.h" |
19 | | #include "llvm/MC/MCSection.h" |
20 | | #include "llvm/MC/MCSymbol.h" |
21 | | #include "llvm/MC/MCValue.h" |
22 | | #include "llvm/Support/Casting.h" |
23 | | #include "llvm/Support/Compiler.h" |
24 | | #include "llvm/Support/ErrorHandling.h" |
25 | | #include "llvm/Support/raw_ostream.h" |
26 | | #include <cassert> |
27 | | #include <cstdint> |
28 | | #include <utility> |
29 | | |
30 | | using namespace llvm; |
31 | | |
32 | 20.5k | MCAsmLayout::MCAsmLayout(MCAssembler &Asm) : Assembler(Asm) { |
33 | 20.5k | // Compute the section layout order. Virtual sections must go last. |
34 | 20.5k | for (MCSection &Sec : Asm) |
35 | 557k | if (!Sec.isVirtualSection()) |
36 | 552k | SectionOrder.push_back(&Sec); |
37 | 20.5k | for (MCSection &Sec : Asm) |
38 | 557k | if (Sec.isVirtualSection()) |
39 | 4.99k | SectionOrder.push_back(&Sec); |
40 | 20.5k | } |
41 | | |
42 | 28.0M | bool MCAsmLayout::isFragmentValid(const MCFragment *F) const { |
43 | 28.0M | const MCSection *Sec = F->getParent(); |
44 | 28.0M | const MCFragment *LastValid = LastValidFragment.lookup(Sec); |
45 | 28.0M | if (!LastValid) |
46 | 561k | return false; |
47 | 27.5M | assert(LastValid->getParent() == Sec); |
48 | 27.5M | return F->getLayoutOrder() <= LastValid->getLayoutOrder(); |
49 | 27.5M | } |
50 | | |
51 | 5.79k | void MCAsmLayout::invalidateFragmentsFrom(MCFragment *F) { |
52 | 5.79k | // If this fragment wasn't already valid, we don't need to do anything. |
53 | 5.79k | if (!isFragmentValid(F)) |
54 | 3.75k | return; |
55 | 2.03k | |
56 | 2.03k | // Otherwise, reset the last valid fragment to the previous fragment |
57 | 2.03k | // (if this is the first fragment, it will be NULL). |
58 | 2.03k | LastValidFragment[F->getParent()] = F->getPrevNode(); |
59 | 2.03k | } |
60 | | |
61 | 21.8M | void MCAsmLayout::ensureValid(const MCFragment *F) const { |
62 | 21.8M | MCSection *Sec = F->getParent(); |
63 | 21.8M | MCSection::iterator I; |
64 | 21.8M | if (MCFragment *Cur = LastValidFragment[Sec]) |
65 | 21.3M | I = ++MCSection::iterator(Cur); |
66 | 557k | else |
67 | 557k | I = Sec->begin(); |
68 | 21.8M | |
69 | 21.8M | // Advance the layout position until the fragment is valid. |
70 | 28.0M | while (!isFragmentValid(F)) { |
71 | 6.20M | assert(I != Sec->end() && "Layout bookkeeping error"); |
72 | 6.20M | const_cast<MCAsmLayout *>(this)->layoutFragment(&*I); |
73 | 6.20M | ++I; |
74 | 6.20M | } |
75 | 21.8M | } |
76 | | |
77 | 21.8M | uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const { |
78 | 21.8M | ensureValid(F); |
79 | 21.8M | assert(F->Offset != ~UINT64_C(0) && "Address not set!"); |
80 | 21.8M | return F->Offset; |
81 | 21.8M | } |
82 | | |
83 | | // Simple getSymbolOffset helper for the non-variable case. |
84 | | static bool getLabelOffset(const MCAsmLayout &Layout, const MCSymbol &S, |
85 | 11.3M | bool ReportError, uint64_t &Val) { |
86 | 11.3M | if (!S.getFragment()) { |
87 | 2.69k | if (ReportError) |
88 | 1 | report_fatal_error("unable to evaluate offset to undefined symbol '" + |
89 | 1 | S.getName() + "'"); |
90 | 2.69k | return false; |
91 | 2.69k | } |
92 | 11.3M | Val = Layout.getFragmentOffset(S.getFragment()) + S.getOffset(); |
93 | 11.3M | return true; |
94 | 11.3M | } |
95 | | |
96 | | static bool getSymbolOffsetImpl(const MCAsmLayout &Layout, const MCSymbol &S, |
97 | 11.3M | bool ReportError, uint64_t &Val) { |
98 | 11.3M | if (!S.isVariable()) |
99 | 11.2M | return getLabelOffset(Layout, S, ReportError, Val); |
100 | 23.6k | |
101 | 23.6k | // If SD is a variable, evaluate it. |
102 | 23.6k | MCValue Target; |
103 | 23.6k | if (!S.getVariableValue()->evaluateAsValue(Target, Layout)) |
104 | 0 | report_fatal_error("unable to evaluate offset for variable '" + |
105 | 0 | S.getName() + "'"); |
106 | 23.6k | |
107 | 23.6k | uint64_t Offset = Target.getConstant(); |
108 | 23.6k | |
109 | 23.6k | const MCSymbolRefExpr *A = Target.getSymA(); |
110 | 23.6k | if (A) { |
111 | 23.1k | uint64_t ValA; |
112 | 23.1k | if (!getLabelOffset(Layout, A->getSymbol(), ReportError, ValA)) |
113 | 10 | return false; |
114 | 23.0k | Offset += ValA; |
115 | 23.0k | } |
116 | 23.6k | |
117 | 23.6k | const MCSymbolRefExpr *B = Target.getSymB(); |
118 | 23.6k | if (B) { |
119 | 22.6k | uint64_t ValB; |
120 | 22.6k | if (!getLabelOffset(Layout, B->getSymbol(), ReportError, ValB)) |
121 | 0 | return false; |
122 | 22.6k | Offset -= ValB; |
123 | 22.6k | } |
124 | 23.6k | |
125 | 23.6k | Val = Offset; |
126 | 23.6k | return true; |
127 | 23.6k | } |
128 | | |
129 | 99.9k | bool MCAsmLayout::getSymbolOffset(const MCSymbol &S, uint64_t &Val) const { |
130 | 99.9k | return getSymbolOffsetImpl(*this, S, false, Val); |
131 | 99.9k | } |
132 | | |
133 | 11.2M | uint64_t MCAsmLayout::getSymbolOffset(const MCSymbol &S) const { |
134 | 11.2M | uint64_t Val; |
135 | 11.2M | getSymbolOffsetImpl(*this, S, true, Val); |
136 | 11.2M | return Val; |
137 | 11.2M | } |
138 | | |
139 | 100k | const MCSymbol *MCAsmLayout::getBaseSymbol(const MCSymbol &Symbol) const { |
140 | 100k | if (!Symbol.isVariable()) |
141 | 99.3k | return &Symbol; |
142 | 851 | |
143 | 851 | const MCExpr *Expr = Symbol.getVariableValue(); |
144 | 851 | MCValue Value; |
145 | 851 | if (!Expr->evaluateAsValue(Value, *this)) { |
146 | 3 | Assembler.getContext().reportError( |
147 | 3 | Expr->getLoc(), "expression could not be evaluated"); |
148 | 3 | return nullptr; |
149 | 3 | } |
150 | 848 | |
151 | 848 | const MCSymbolRefExpr *RefB = Value.getSymB(); |
152 | 848 | if (RefB) { |
153 | 2 | Assembler.getContext().reportError( |
154 | 2 | Expr->getLoc(), Twine("symbol '") + RefB->getSymbol().getName() + |
155 | 2 | "' could not be evaluated in a subtraction expression"); |
156 | 2 | return nullptr; |
157 | 2 | } |
158 | 846 | |
159 | 846 | const MCSymbolRefExpr *A = Value.getSymA(); |
160 | 846 | if (!A) |
161 | 555 | return nullptr; |
162 | 291 | |
163 | 291 | const MCSymbol &ASym = A->getSymbol(); |
164 | 291 | const MCAssembler &Asm = getAssembler(); |
165 | 291 | if (ASym.isCommon()) { |
166 | 4 | Asm.getContext().reportError(Expr->getLoc(), |
167 | 4 | "Common symbol '" + ASym.getName() + |
168 | 4 | "' cannot be used in assignment expr"); |
169 | 4 | return nullptr; |
170 | 4 | } |
171 | 287 | |
172 | 287 | return &ASym; |
173 | 287 | } |
174 | | |
175 | 507k | uint64_t MCAsmLayout::getSectionAddressSize(const MCSection *Sec) const { |
176 | 507k | // The size is the last fragment's end offset. |
177 | 507k | const MCFragment &F = Sec->getFragmentList().back(); |
178 | 507k | return getFragmentOffset(&F) + getAssembler().computeFragmentSize(*this, F); |
179 | 507k | } |
180 | | |
181 | 73.1k | uint64_t MCAsmLayout::getSectionFileSize(const MCSection *Sec) const { |
182 | 73.1k | // Virtual sections have no file size. |
183 | 73.1k | if (Sec->isVirtualSection()) |
184 | 3.56k | return 0; |
185 | 69.5k | |
186 | 69.5k | // Otherwise, the file size is the same as the address space size. |
187 | 69.5k | return getSectionAddressSize(Sec); |
188 | 69.5k | } |
189 | | |
190 | | uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler, |
191 | | const MCEncodedFragment *F, |
192 | 886 | uint64_t FOffset, uint64_t FSize) { |
193 | 886 | uint64_t BundleSize = Assembler.getBundleAlignSize(); |
194 | 886 | assert(BundleSize > 0 && |
195 | 886 | "computeBundlePadding should only be called if bundling is enabled"); |
196 | 886 | uint64_t BundleMask = BundleSize - 1; |
197 | 886 | uint64_t OffsetInBundle = FOffset & BundleMask; |
198 | 886 | uint64_t EndOfFragment = OffsetInBundle + FSize; |
199 | 886 | |
200 | 886 | // There are two kinds of bundling restrictions: |
201 | 886 | // |
202 | 886 | // 1) For alignToBundleEnd(), add padding to ensure that the fragment will |
203 | 886 | // *end* on a bundle boundary. |
204 | 886 | // 2) Otherwise, check if the fragment would cross a bundle boundary. If it |
205 | 886 | // would, add padding until the end of the bundle so that the fragment |
206 | 886 | // will start in a new one. |
207 | 886 | if (F->alignToBundleEnd()) { |
208 | 288 | // Three possibilities here: |
209 | 288 | // |
210 | 288 | // A) The fragment just happens to end at a bundle boundary, so we're good. |
211 | 288 | // B) The fragment ends before the current bundle boundary: pad it just |
212 | 288 | // enough to reach the boundary. |
213 | 288 | // C) The fragment ends after the current bundle boundary: pad it until it |
214 | 288 | // reaches the end of the next bundle boundary. |
215 | 288 | // |
216 | 288 | // Note: this code could be made shorter with some modulo trickery, but it's |
217 | 288 | // intentionally kept in its more explicit form for simplicity. |
218 | 288 | if (EndOfFragment == BundleSize) |
219 | 18 | return 0; |
220 | 270 | else if (EndOfFragment < BundleSize) |
221 | 142 | return BundleSize - EndOfFragment; |
222 | 128 | else { // EndOfFragment > BundleSize |
223 | 128 | return 2 * BundleSize - EndOfFragment; |
224 | 128 | } |
225 | 598 | } else if (OffsetInBundle > 0 && EndOfFragment > BundleSize487 ) |
226 | 161 | return BundleSize - OffsetInBundle; |
227 | 437 | else |
228 | 437 | return 0; |
229 | 886 | } |
230 | | |
231 | | /* *** */ |
232 | | |
233 | 7.19M | void ilist_alloc_traits<MCFragment>::deleteNode(MCFragment *V) { V->destroy(); } |
234 | | |
235 | 10.4M | MCFragment::~MCFragment() = default; |
236 | | |
237 | | MCFragment::MCFragment(FragmentType Kind, bool HasInstructions, |
238 | | MCSection *Parent) |
239 | | : Kind(Kind), HasInstructions(HasInstructions), LayoutOrder(0), |
240 | 10.4M | Parent(Parent), Atom(nullptr), Offset(~UINT64_C(0)) { |
241 | 10.4M | if (Parent && !isDummy()3.12M ) |
242 | 1.64k | Parent->getFragmentList().push_back(this); |
243 | 10.4M | } |
244 | | |
245 | 7.19M | void MCFragment::destroy() { |
246 | 7.19M | // First check if we are the sentinal. |
247 | 7.19M | if (Kind == FragmentType(~0)) { |
248 | 0 | delete this; |
249 | 0 | return; |
250 | 0 | } |
251 | 7.19M | |
252 | 7.19M | switch (Kind) { |
253 | 7.19M | case FT_Align: |
254 | 488k | delete cast<MCAlignFragment>(this); |
255 | 488k | return; |
256 | 7.19M | case FT_Data: |
257 | 4.75M | delete cast<MCDataFragment>(this); |
258 | 4.75M | return; |
259 | 7.19M | case FT_CompactEncodedInst: |
260 | 135 | delete cast<MCCompactEncodedInstFragment>(this); |
261 | 135 | return; |
262 | 7.19M | case FT_Fill: |
263 | 609k | delete cast<MCFillFragment>(this); |
264 | 609k | return; |
265 | 7.19M | case FT_Relaxable: |
266 | 237k | delete cast<MCRelaxableFragment>(this); |
267 | 237k | return; |
268 | 7.19M | case FT_Org: |
269 | 19 | delete cast<MCOrgFragment>(this); |
270 | 19 | return; |
271 | 7.19M | case FT_Dwarf: |
272 | 965k | delete cast<MCDwarfLineAddrFragment>(this); |
273 | 965k | return; |
274 | 7.19M | case FT_DwarfFrame: |
275 | 131k | delete cast<MCDwarfCallFrameFragment>(this); |
276 | 131k | return; |
277 | 7.19M | case FT_LEB: |
278 | 4.82k | delete cast<MCLEBFragment>(this); |
279 | 4.82k | return; |
280 | 7.19M | case FT_Padding: |
281 | 0 | delete cast<MCPaddingFragment>(this); |
282 | 0 | return; |
283 | 7.19M | case FT_SymbolId: |
284 | 16 | delete cast<MCSymbolIdFragment>(this); |
285 | 16 | return; |
286 | 7.19M | case FT_CVInlineLines: |
287 | 33 | delete cast<MCCVInlineLineTableFragment>(this); |
288 | 33 | return; |
289 | 7.19M | case FT_CVDefRange: |
290 | 358 | delete cast<MCCVDefRangeFragment>(this); |
291 | 358 | return; |
292 | 7.19M | case FT_Dummy: |
293 | 0 | delete cast<MCDummyFragment>(this); |
294 | 0 | return; |
295 | 7.19M | } |
296 | 7.19M | } |
297 | | |
298 | | // Debugging methods |
299 | | |
300 | | namespace llvm { |
301 | | |
302 | 0 | raw_ostream &operator<<(raw_ostream &OS, const MCFixup &AF) { |
303 | 0 | OS << "<MCFixup" << " Offset:" << AF.getOffset() |
304 | 0 | << " Value:" << *AF.getValue() |
305 | 0 | << " Kind:" << AF.getKind() << ">"; |
306 | 0 | return OS; |
307 | 0 | } |
308 | | |
309 | | } // end namespace llvm |
310 | | |
311 | | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) |
312 | | LLVM_DUMP_METHOD void MCFragment::dump() const { |
313 | | raw_ostream &OS = errs(); |
314 | | |
315 | | OS << "<"; |
316 | | switch (getKind()) { |
317 | | case MCFragment::FT_Align: OS << "MCAlignFragment"; break; |
318 | | case MCFragment::FT_Data: OS << "MCDataFragment"; break; |
319 | | case MCFragment::FT_CompactEncodedInst: |
320 | | OS << "MCCompactEncodedInstFragment"; break; |
321 | | case MCFragment::FT_Fill: OS << "MCFillFragment"; break; |
322 | | case MCFragment::FT_Relaxable: OS << "MCRelaxableFragment"; break; |
323 | | case MCFragment::FT_Org: OS << "MCOrgFragment"; break; |
324 | | case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break; |
325 | | case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break; |
326 | | case MCFragment::FT_LEB: OS << "MCLEBFragment"; break; |
327 | | case MCFragment::FT_Padding: OS << "MCPaddingFragment"; break; |
328 | | case MCFragment::FT_SymbolId: OS << "MCSymbolIdFragment"; break; |
329 | | case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break; |
330 | | case MCFragment::FT_CVDefRange: OS << "MCCVDefRangeTableFragment"; break; |
331 | | case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break; |
332 | | } |
333 | | |
334 | | OS << "<MCFragment " << (const void *)this << " LayoutOrder:" << LayoutOrder |
335 | | << " Offset:" << Offset << " HasInstructions:" << hasInstructions(); |
336 | | if (const MCEncodedFragment *EF = dyn_cast<MCEncodedFragment>(this)) |
337 | | OS << " BundlePadding:" << static_cast<unsigned>(EF->getBundlePadding()); |
338 | | OS << ">"; |
339 | | |
340 | | switch (getKind()) { |
341 | | case MCFragment::FT_Align: { |
342 | | const MCAlignFragment *AF = cast<MCAlignFragment>(this); |
343 | | if (AF->hasEmitNops()) |
344 | | OS << " (emit nops)"; |
345 | | OS << "\n "; |
346 | | OS << " Alignment:" << AF->getAlignment() |
347 | | << " Value:" << AF->getValue() << " ValueSize:" << AF->getValueSize() |
348 | | << " MaxBytesToEmit:" << AF->getMaxBytesToEmit() << ">"; |
349 | | break; |
350 | | } |
351 | | case MCFragment::FT_Data: { |
352 | | const MCDataFragment *DF = cast<MCDataFragment>(this); |
353 | | OS << "\n "; |
354 | | OS << " Contents:["; |
355 | | const SmallVectorImpl<char> &Contents = DF->getContents(); |
356 | | for (unsigned i = 0, e = Contents.size(); i != e; ++i) { |
357 | | if (i) OS << ","; |
358 | | OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF); |
359 | | } |
360 | | OS << "] (" << Contents.size() << " bytes)"; |
361 | | |
362 | | if (DF->fixup_begin() != DF->fixup_end()) { |
363 | | OS << ",\n "; |
364 | | OS << " Fixups:["; |
365 | | for (MCDataFragment::const_fixup_iterator it = DF->fixup_begin(), |
366 | | ie = DF->fixup_end(); it != ie; ++it) { |
367 | | if (it != DF->fixup_begin()) OS << ",\n "; |
368 | | OS << *it; |
369 | | } |
370 | | OS << "]"; |
371 | | } |
372 | | break; |
373 | | } |
374 | | case MCFragment::FT_CompactEncodedInst: { |
375 | | const MCCompactEncodedInstFragment *CEIF = |
376 | | cast<MCCompactEncodedInstFragment>(this); |
377 | | OS << "\n "; |
378 | | OS << " Contents:["; |
379 | | const SmallVectorImpl<char> &Contents = CEIF->getContents(); |
380 | | for (unsigned i = 0, e = Contents.size(); i != e; ++i) { |
381 | | if (i) OS << ","; |
382 | | OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF); |
383 | | } |
384 | | OS << "] (" << Contents.size() << " bytes)"; |
385 | | break; |
386 | | } |
387 | | case MCFragment::FT_Fill: { |
388 | | const MCFillFragment *FF = cast<MCFillFragment>(this); |
389 | | OS << " Value:" << static_cast<unsigned>(FF->getValue()) |
390 | | << " ValueSize:" << static_cast<unsigned>(FF->getValueSize()) |
391 | | << " NumValues:" << FF->getNumValues(); |
392 | | break; |
393 | | } |
394 | | case MCFragment::FT_Relaxable: { |
395 | | const MCRelaxableFragment *F = cast<MCRelaxableFragment>(this); |
396 | | OS << "\n "; |
397 | | OS << " Inst:"; |
398 | | F->getInst().dump_pretty(OS); |
399 | | break; |
400 | | } |
401 | | case MCFragment::FT_Org: { |
402 | | const MCOrgFragment *OF = cast<MCOrgFragment>(this); |
403 | | OS << "\n "; |
404 | | OS << " Offset:" << OF->getOffset() |
405 | | << " Value:" << static_cast<unsigned>(OF->getValue()); |
406 | | break; |
407 | | } |
408 | | case MCFragment::FT_Dwarf: { |
409 | | const MCDwarfLineAddrFragment *OF = cast<MCDwarfLineAddrFragment>(this); |
410 | | OS << "\n "; |
411 | | OS << " AddrDelta:" << OF->getAddrDelta() |
412 | | << " LineDelta:" << OF->getLineDelta(); |
413 | | break; |
414 | | } |
415 | | case MCFragment::FT_DwarfFrame: { |
416 | | const MCDwarfCallFrameFragment *CF = cast<MCDwarfCallFrameFragment>(this); |
417 | | OS << "\n "; |
418 | | OS << " AddrDelta:" << CF->getAddrDelta(); |
419 | | break; |
420 | | } |
421 | | case MCFragment::FT_LEB: { |
422 | | const MCLEBFragment *LF = cast<MCLEBFragment>(this); |
423 | | OS << "\n "; |
424 | | OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned(); |
425 | | break; |
426 | | } |
427 | | case MCFragment::FT_Padding: { |
428 | | const MCPaddingFragment *F = cast<MCPaddingFragment>(this); |
429 | | OS << "\n "; |
430 | | OS << " PaddingPoliciesMask:" << F->getPaddingPoliciesMask() |
431 | | << " IsInsertionPoint:" << F->isInsertionPoint() |
432 | | << " Size:" << F->getSize(); |
433 | | OS << "\n "; |
434 | | OS << " Inst:"; |
435 | | F->getInst().dump_pretty(OS); |
436 | | OS << " InstSize:" << F->getInstSize(); |
437 | | OS << "\n "; |
438 | | break; |
439 | | } |
440 | | case MCFragment::FT_SymbolId: { |
441 | | const MCSymbolIdFragment *F = cast<MCSymbolIdFragment>(this); |
442 | | OS << "\n "; |
443 | | OS << " Sym:" << F->getSymbol(); |
444 | | break; |
445 | | } |
446 | | case MCFragment::FT_CVInlineLines: { |
447 | | const auto *F = cast<MCCVInlineLineTableFragment>(this); |
448 | | OS << "\n "; |
449 | | OS << " Sym:" << *F->getFnStartSym(); |
450 | | break; |
451 | | } |
452 | | case MCFragment::FT_CVDefRange: { |
453 | | const auto *F = cast<MCCVDefRangeFragment>(this); |
454 | | OS << "\n "; |
455 | | for (std::pair<const MCSymbol *, const MCSymbol *> RangeStartEnd : |
456 | | F->getRanges()) { |
457 | | OS << " RangeStart:" << RangeStartEnd.first; |
458 | | OS << " RangeEnd:" << RangeStartEnd.second; |
459 | | } |
460 | | break; |
461 | | } |
462 | | case MCFragment::FT_Dummy: |
463 | | break; |
464 | | } |
465 | | OS << ">"; |
466 | | } |
467 | | #endif |