[llvm] r220439 - [MC] Attach labels to existing fragments instead of using a separate fragment

Derek Schuff dschuff at google.com
Wed Oct 22 15:38:06 PDT 2014


Author: dschuff
Date: Wed Oct 22 17:38:06 2014
New Revision: 220439

URL: http://llvm.org/viewvc/llvm-project?rev=220439&view=rev
Log:
[MC] Attach labels to existing fragments instead of using a separate fragment

Summary:
Currently when emitting a label, a new data fragment is created for it if the
current fragment isn't a data fragment.
This change instead enqueues the label and attaches it to the next fragment
(e.g. created for the next instruction) if possible.

When bundle alignment is not enabled, this has no functionality change (it
just results in fewer extra fragments being created). For bundle alignment,
previously labels would point to the beginning of the bundle padding instead
of the beginning of the emitted instruction. This was not only less efficient
(e.g. jumping to the nops instead of past them) but also led to miscalculation
of the address of the GOT (since MC uses a label difference rather than
emitting a "." symbol).

Fixes https://code.google.com/p/nativeclient/issues/detail?id=3982

Test Plan: regression test attached

Reviewers: jvoung, eliben

Subscribers: jfb, llvm-commits

Differential Revision: http://reviews.llvm.org/D5915

Added:
    llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s
Modified:
    llvm/trunk/include/llvm/MC/MCObjectStreamer.h
    llvm/trunk/lib/MC/MCObjectStreamer.cpp
    llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s

Modified: llvm/trunk/include/llvm/MC/MCObjectStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCObjectStreamer.h?rev=220439&r1=220438&r2=220439&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCObjectStreamer.h (original)
+++ llvm/trunk/include/llvm/MC/MCObjectStreamer.h Wed Oct 22 17:38:06 2014
@@ -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 @@ class MCObjectStreamer : public MCStream
   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);
@@ -69,14 +75,15 @@ protected:
 
   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;

Modified: llvm/trunk/lib/MC/MCObjectStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCObjectStreamer.cpp?rev=220439&r1=220438&r2=220439&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCObjectStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCObjectStreamer.cpp Wed Oct 22 17:38:06 2014
@@ -42,6 +42,21 @@ MCObjectStreamer::~MCObjectStreamer() {
   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 @@ void MCObjectStreamer::reset() {
   CurInsertionPoint = MCSectionData::iterator();
   EmitEHFrame = true;
   EmitDebugFrame = false;
+  PendingLabels.clear();
   MCStreamer::reset();
 }
 
@@ -72,7 +88,7 @@ MCFragment *MCObjectStreamer::getCurrent
   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)
@@ -127,15 +143,17 @@ void MCObjectStreamer::EmitLabel(MCSymbo
   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) {
@@ -164,6 +182,7 @@ void MCObjectStreamer::EmitWeakReference
 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 @@ void MCObjectStreamer::FinishImpl() {
   // Dump out the dwarf file & directory tables and line tables.
   MCDwarfLineTable::Emit(this);
 
+  flushPendingLabels(nullptr);
   getAssembler().Finish();
 }

Added: llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s?rev=220439&view=auto
==============================================================================
--- llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s (added)
+++ llvm/trunk/test/MC/X86/AlignedBundling/labeloffset.s Wed Oct 22 17:38:06 2014
@@ -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, at 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, at 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, at function
+# CHECK-LABEL: foo:
+foo:
+        inc %eax
+tmp3:
+        .rodata
+        .type   obj, at object
+        .comm   obj,4,4
+        .section .text.foo
+        inc %eax
+# CHECK: tmp3:
+# CHECK-NEXT: 1: incl

Modified: llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s?rev=220439&r1=220438&r2=220439&view=diff
==============================================================================
--- llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s (original)
+++ llvm/trunk/test/MC/X86/AlignedBundling/long-nop-pad.s Wed Oct 22 17:38:06 2014
@@ -14,7 +14,7 @@ foo:
 # 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





More information about the llvm-commits mailing list