#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"
MCSectionData::iterator CurInsertionPoint;
bool EmitEHFrame;
bool EmitDebugFrame;
+ SmallVector<MCSymbolData *, 2> 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);
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;
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();
CurInsertionPoint = MCSectionData::iterator();
EmitEHFrame = true;
EmitDebugFrame = false;
+ PendingLabels.clear();
MCStreamer::reset();
}
return nullptr;
}
-MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const {
+MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() {
MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
// When bundling is enabled, we don't want to add data to a fragment that
// already has instructions (see MCELFStreamer::EmitInstToData for details)
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<MCDataFragment>(getCurrentFragment())) {
+ SD.setFragment(F);
+ SD.setOffset(F->getContents().size());
+ } else {
+ PendingLabels.push_back(&SD);
+ }
}
void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) {
void MCObjectStreamer::ChangeSection(const MCSection *Section,
const MCExpr *Subsection) {
assert(Section && "Cannot switch to a null section!");
+ flushPendingLabels(nullptr);
CurSectionData = &getAssembler().getOrCreateSectionData(*Section);
// Dump out the dwarf file & directory tables and line tables.
MCDwarfLineTable::Emit(this);
+ flushPendingLabels(nullptr);
getAssembler().Finish();
}
--- /dev/null
+# 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
# 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