Index: llvm/trunk/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCObjectStreamer.h +++ llvm/trunk/include/llvm/MC/MCObjectStreamer.h @@ -10,6 +10,7 @@ #ifndef LLVM_MC_MCOBJECTSTREAMER_H #define LLVM_MC_MCOBJECTSTREAMER_H +#include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCStreamer.h" @@ -37,11 +38,16 @@ MCSectionData::iterator CurInsertionPoint; bool EmitEHFrame; bool EmitDebugFrame; + SmallVector PendingLabels; virtual void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo&) = 0; void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override; void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override; + // If any labels have been emitted but not assigned fragments, ensure that + // they get assigned, either to F if possible or to a new data fragment. + void flushPendingLabels(MCFragment *F); + protected: MCObjectStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &_OS, MCCodeEmitter *_Emitter); @@ -69,14 +75,15 @@ MCFragment *getCurrentFragment() const; - void insert(MCFragment *F) const { + void insert(MCFragment *F) { + flushPendingLabels(F); CurSectionData->getFragmentList().insert(CurInsertionPoint, F); F->setParent(CurSectionData); } /// Get a data fragment to write into, creating a new one if the current /// fragment is not a data fragment. - MCDataFragment *getOrCreateDataFragment() const; + MCDataFragment *getOrCreateDataFragment(); public: void visitUsedSymbol(const MCSymbol &Sym) override; Index: llvm/trunk/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCObjectStreamer.cpp +++ llvm/trunk/lib/MC/MCObjectStreamer.cpp @@ -42,6 +42,21 @@ delete Assembler; } +void MCObjectStreamer::flushPendingLabels(MCFragment *F) { + if (PendingLabels.size()) { + if (!F) { + F = new MCDataFragment(); + CurSectionData->getFragmentList().insert(CurInsertionPoint, F); + F->setParent(CurSectionData); + } + for (MCSymbolData *SD : PendingLabels) { + SD->setFragment(F); + SD->setOffset(0); + } + PendingLabels.clear(); + } +} + void MCObjectStreamer::reset() { if (Assembler) Assembler->reset(); @@ -49,6 +64,7 @@ CurInsertionPoint = MCSectionData::iterator(); EmitEHFrame = true; EmitDebugFrame = false; + PendingLabels.clear(); MCStreamer::reset(); } @@ -72,7 +88,7 @@ return nullptr; } -MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { +MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() { MCDataFragment *F = dyn_cast_or_null(getCurrentFragment()); // When bundling is enabled, we don't want to add data to a fragment that // already has instructions (see MCELFStreamer::EmitInstToData for details) @@ -127,15 +143,17 @@ MCStreamer::EmitLabel(Symbol); MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); - - // FIXME: This is wasteful, we don't necessarily need to create a data - // fragment. Instead, we should mark the symbol as pointing into the data - // fragment if it exists, otherwise we should just queue the label and set its - // fragment pointer when we emit the next fragment. - MCDataFragment *F = getOrCreateDataFragment(); assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(F); - SD.setOffset(F->getContents().size()); + + // If there is a current fragment, mark the symbol as pointing into it. + // Otherwise queue the label and set its fragment pointer when we emit the + // next fragment. + if (dyn_cast_or_null(getCurrentFragment())) { + SD.setFragment(F); + SD.setOffset(F->getContents().size()); + } else { + PendingLabels.push_back(&SD); + } } void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { @@ -164,6 +182,7 @@ void MCObjectStreamer::ChangeSection(const MCSection *Section, const MCExpr *Subsection) { assert(Section && "Cannot switch to a null section!"); + flushPendingLabels(nullptr); CurSectionData = &getAssembler().getOrCreateSectionData(*Section); @@ -398,5 +417,6 @@ // Dump out the dwarf file & directory tables and line tables. MCDwarfLineTable::Emit(this); + flushPendingLabels(nullptr); getAssembler().Finish(); } Index: llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s =================================================================== --- llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s +++ llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s @@ -0,0 +1,83 @@ +# RUN: llvm-mc -triple=i686-linux -filetype=obj %s -o - | \ +# RUN: llvm-objdump -disassemble -no-show-raw-insn -r - | FileCheck %s +# RUN: llvm-mc -triple=i686-nacl -filetype=obj %s -o - | \ +# RUN: llvm-objdump -disassemble -no-show-raw-insn -r - | FileCheck %s + + .bundle_align_mode 5 + .text + .globl main + .align 32, 0x90 + .type main,@function +main: # @main +# CHECK-LABEL: main: +# Call + pop sequence for determining the PIC base. + .bundle_lock align_to_end + calll .L0$pb + .bundle_unlock +.L0$pb: + popl %eax +# CHECK: 20: popl +# 26 bytes of instructions between the pop and the use of the pic base symbol. + movl $3, 2(%ebx, %ebx) + movl $3, 2(%ebx, %ebx) + movl $3, 2(%ebx, %ebx) + hlt + hlt +# CHECK: nop +.Ltmp0: + addl (.Ltmp0-.L0$pb), %eax +# The addl has bundle padding to push it from 0x3b to 0x40. +# The difference between the labels should be 0x20 (0x40-0x20) not 0x1b +# (0x3b-0x20) +# CHECK: 40: addl 32, %eax + popl %ecx + jmp *%ecx + + +# Also make sure it works with a non-relaxable instruction (cmp vs add) +# and for 2 adjacent labels that both point to the correct instruction + .section .text.bar, "ax" + .globl bar + .align 32, 0x90 + .type bar,@function +bar: +# CHECK-LABEL: bar: + .bundle_lock align_to_end + calll .L1$pb + .bundle_unlock +.L1$pb: + popl %eax +# CHECK: 20: popl +# 26 bytes of instructions between the pop and the use of the pic base symbol. + movl $3, 2(%ebx, %ebx) + movl $3, 2(%ebx, %ebx) + movl $3, 2(%ebx, %ebx) + hlt + hlt +# CHECK: nop +.Ltmp1: +.Ltmp2: + cmpl %eax, .Ltmp1 +# CHECK: 40: cmpl %eax, 64 + cmpl %eax, (.Ltmp2-.L1$pb) +# CHECK: 46: cmpl %eax, 32 + popl %ecx + jmp *%ecx + + +# Switch sections in the middle of a function + .section .text.foo, "ax" + .globl foo + .align 32, 0x90 + .type foo,@function +# CHECK-LABEL: foo: +foo: + inc %eax +tmp3: + .rodata + .type obj,@object + .comm obj,4,4 + .section .text.foo + inc %eax +# CHECK: tmp3: +# CHECK-NEXT: 1: incl Index: llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s =================================================================== --- llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s +++ llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s @@ -14,7 +14,7 @@ # To align this group to a bundle end, we need a 15-byte NOP and a 12-byte NOP. # CHECK: 0: nop # CHECK-NEXT: f: nop -# CHECK-NEXT: 1b: callq +# CHECK: 1b: callq # This push instruction is 1 byte long .bundle_lock align_to_end