[llvm-commits] [llvm] r98396 - in /llvm/trunk: include/llvm/MC/MCAssembler.h lib/MC/MCAssembler.cpp test/MC/MachO/relax-jumps.s test/MC/MachO/relax-recompute-align.s

Daniel Dunbar daniel at zuster.org
Fri Mar 12 14:07:14 PST 2010


Author: ddunbar
Date: Fri Mar 12 16:07:14 2010
New Revision: 98396

URL: http://llvm.org/viewvc/llvm-project?rev=98396&view=rev
Log:
MC/Mach-O: Implement initial support for relaxation.
 - The implementation is currently very brain dead and inefficient, but I have a
   clear plan on how to fix it.

 - The good news is, it works and correctly assembles 403.gcc (when built with
   Clang, at '-Os', '-Os -g', and '-O3'). Even better, at '-Os' and '-Os -g',
   the resulting binary is exactly equivalent to that when built with the system
   assembler. So it probably works! :)

Added:
    llvm/trunk/test/MC/MachO/relax-jumps.s
    llvm/trunk/test/MC/MachO/relax-recompute-align.s
Modified:
    llvm/trunk/include/llvm/MC/MCAssembler.h
    llvm/trunk/lib/MC/MCAssembler.cpp

Modified: llvm/trunk/include/llvm/MC/MCAssembler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCAssembler.h?rev=98396&r1=98395&r2=98396&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCAssembler.h (original)
+++ llvm/trunk/include/llvm/MC/MCAssembler.h Fri Mar 12 16:07:14 2010
@@ -621,11 +621,19 @@
   unsigned SubsectionsViaSymbols : 1;
 
 private:
+  /// Check whether a fixup can be satisfied, or whether it needs to be relaxed
+  /// (increased in size, in order to hold its value correctly).
+  bool FixupNeedsRelaxation(MCAsmFixup &Fixup, MCDataFragment *DF);
+
   /// LayoutSection - Assign offsets and sizes to the fragments in the section
   /// \arg SD, and update the section size. The section file offset should
   /// already have been computed.
   void LayoutSection(MCSectionData &SD);
 
+  /// LayoutOnce - Perform one layout iteration and return true if any offsets
+  /// were adjusted.
+  bool LayoutOnce();
+
   // FIXME: Make protected once we factor out object writer classes.
 public:
   /// Evaluate a fixup to a relocatable expression and the value which should be

Modified: llvm/trunk/lib/MC/MCAssembler.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCAssembler.cpp?rev=98396&r1=98395&r2=98396&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCAssembler.cpp (original)
+++ llvm/trunk/lib/MC/MCAssembler.cpp Fri Mar 12 16:07:14 2010
@@ -1275,6 +1275,40 @@
       llvm::errs() << "assembler backend - pre-layout\n--\n";
       dump(); });
 
+  // Layout until everything fits.
+  while (LayoutOnce())
+    continue;
+
+  DEBUG_WITH_TYPE("mc-dump", {
+      llvm::errs() << "assembler backend - post-layout\n--\n";
+      dump(); });
+
+  // Write the object file.
+  MachObjectWriter MOW(OS);
+  MOW.WriteObject(*this);
+
+  OS.flush();
+}
+
+bool MCAssembler::FixupNeedsRelaxation(MCAsmFixup &Fixup, MCDataFragment *DF) {
+  // FIXME: Share layout object.
+  MCAsmLayout Layout(*this);
+
+  // Currently we only need to relax X86::reloc_pcrel_1byte.
+  if (unsigned(Fixup.Kind) != X86::reloc_pcrel_1byte)
+    return false;
+
+  // If we cannot resolve the fixup value, it requires relaxation.
+  MCValue Target;
+  uint64_t Value;
+  if (!EvaluateFixup(Layout, Fixup, DF, Target, Value))
+    return true;
+
+  // Otherwise, relax if the value is too big for a (signed) i8.
+  return int64_t(Value) != int64_t(int8_t(Value));
+}
+
+bool MCAssembler::LayoutOnce() {
   // Layout the concrete sections and fragments.
   uint64_t Address = 0;
   MCSectionData *Prev = 0;
@@ -1316,21 +1350,95 @@
     SD.setAddress(Address);
     LayoutSection(SD);
     Address += SD.getSize();
-
   }
 
-  DEBUG_WITH_TYPE("mc-dump", {
-      llvm::errs() << "assembler backend - post-layout\n--\n";
-      dump(); });
+  // Scan the fixups in order and relax any that don't fit.
+  for (iterator it = begin(), ie = end(); it != ie; ++it) {
+    MCSectionData &SD = *it;
 
-  // Write the object file.
-  MachObjectWriter MOW(OS);
-  MOW.WriteObject(*this);
+    for (MCSectionData::iterator it2 = SD.begin(),
+           ie2 = SD.end(); it2 != ie2; ++it2) {
+      MCDataFragment *DF = dyn_cast<MCDataFragment>(it2);
+      if (!DF)
+        continue;
+
+      for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(),
+             ie3 = DF->fixup_end(); it3 != ie3; ++it3) {
+        MCAsmFixup &Fixup = *it3;
+
+        // Check whether we need to relax this fixup.
+        if (!FixupNeedsRelaxation(Fixup, DF))
+          continue;
+
+        // Relax the instruction.
+        //
+        // FIXME: This is a huge temporary hack which just looks for x86
+        // branches; the only thing we need to relax on x86 is
+        // 'X86::reloc_pcrel_1byte'. Once we have MCInst fragments, this will be
+        // replaced by a TargetAsmBackend hook (most likely tblgen'd) to relax
+        // an individual MCInst.
+        SmallVectorImpl<char> &C = DF->getContents();
+        uint64_t PrevOffset = Fixup.Offset;
+        unsigned Amt = 0;
+
+          // jcc instructions
+        if (unsigned(C[Fixup.Offset-1]) >= 0x70 &&
+            unsigned(C[Fixup.Offset-1]) <= 0x7f) {
+          C[Fixup.Offset] = C[Fixup.Offset-1] + 0x10;
+          C[Fixup.Offset-1] = char(0x0f);
+          ++Fixup.Offset;
+          Amt = 4;
+
+          // jmp rel8
+        } else if (C[Fixup.Offset-1] == char(0xeb)) {
+          C[Fixup.Offset-1] = char(0xe9);
+          Amt = 3;
+
+        } else
+          llvm_unreachable("unknown 1 byte pcrel instruction!");
+
+        Fixup.Value = MCBinaryExpr::Create(
+          MCBinaryExpr::Sub, Fixup.Value,
+          MCConstantExpr::Create(3, getContext()),
+          getContext());
+        C.insert(C.begin() + Fixup.Offset, Amt, char(0));
+        Fixup.Kind = MCFixupKind(X86::reloc_pcrel_4byte);
+
+        // Update the remaining fixups, which have slid.
+        //
+        // FIXME: This is bad for performance, but will be eliminated by the
+        // move to MCInst specific fragments.
+        ++it3;
+        for (; it3 != ie3; ++it3)
+          it3->Offset += Amt;
+
+        // Update all the symbols for this fragment, which may have slid.
+        //
+        // FIXME: This is really really bad for performance, but will be
+        // eliminated by the move to MCInst specific fragments.
+        for (MCAssembler::symbol_iterator it = symbol_begin(),
+               ie = symbol_end(); it != ie; ++it) {
+          MCSymbolData &SD = *it;
+
+          if (it->getFragment() != DF)
+            continue;
+
+          if (SD.getOffset() > PrevOffset)
+            SD.setOffset(SD.getOffset() + Amt);
+        }
+
+        // Restart layout.
+        //
+        // FIXME: This is O(N^2), but will be eliminated once we have a smart
+        // MCAsmLayout object.
+        return true;
+      }
+    }
+  }
 
-  OS.flush();
+  return false;
 }
 
-
 // Debugging methods
 
 namespace llvm {

Added: llvm/trunk/test/MC/MachO/relax-jumps.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/MachO/relax-jumps.s?rev=98396&view=auto
==============================================================================
--- llvm/trunk/test/MC/MachO/relax-jumps.s (added)
+++ llvm/trunk/test/MC/MachO/relax-jumps.s Fri Mar 12 16:07:14 2010
@@ -0,0 +1,31 @@
+// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump --dump-section-data | FileCheck %s
+
+// FIXME: This is a horrible way of checking the output, we need an llvm-mc
+// based 'otool'. Use:
+//   (f=relax-jumps;
+//    llvm-mc -filetype=obj -o $f.mc.o $f.s &&
+//    as -arch i386 -o $f.as.o $f.s &&
+//    otool -tvr $f.mc.o | tail +2 > $f.mc.dump &&
+//    otool -tvr $f.as.o | tail +2 > $f.as.dump &&
+//    diff $f.{as,mc}.dump)
+// to examine the results in a more sensible fashion.
+
+// CHECK: ('_section_data', '\x90
+// CHECK: \x0f\x842\xff\xff\xff\x0f\x82\xe6\x00\x00\x00\x0f\x87&\xff\xff\xff\x0f\x8f\xda\x00\x00\x00\x0f\x88\x1a\xff\xff\xff\x0f\x83\xce\x00\x00\x00\x0f\x89\x0e\xff\xff\xff\x90
+// CHECK: \x901\xc0')
+
+L1:
+        .space 200, 0x90
+
+        je L1
+        jb L2
+        ja L1
+        jg L2
+        js L1
+        jae L2
+        jns L1
+
+        .space 200, 0x90
+L2:
+
+        xorl %eax, %eax

Added: llvm/trunk/test/MC/MachO/relax-recompute-align.s
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/MC/MachO/relax-recompute-align.s?rev=98396&view=auto
==============================================================================
--- llvm/trunk/test/MC/MachO/relax-recompute-align.s (added)
+++ llvm/trunk/test/MC/MachO/relax-recompute-align.s Fri Mar 12 16:07:14 2010
@@ -0,0 +1,37 @@
+// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump --dump-section-data | FileCheck %s
+
+// FIXME: This is a horrible way of checking the output, we need an llvm-mc
+// based 'otool'.
+
+// This is a case where llvm-mc computes a better layout than Darwin 'as'. This
+// issue is that after the first jmp slides, the .align size must be
+// recomputed -- otherwise the second jump will appear to be out-of-range for a
+// 1-byte jump.
+
+// CHECK:  # Section 0
+// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:  ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
+// CHECK:  ('address', 0)
+// CHECK:  ('size', 306)
+// CHECK:  ('offset', 324)
+// CHECK:  ('alignment', 4)
+// CHECK:  ('reloc_offset', 0)
+// CHECK:  ('num_reloc', 0)
+// CHECK:  ('flags', 0x80000400)
+// CHECK:  ('reserved1', 0)
+// CHECK:  ('reserved2', 0)
+// CHECK: ),
+
+L0:
+        .space 0x8a, 0x90
+	jmp	L0
+        .space (0xb3 - 0x8f), 0x90
+	jle	L2
+        .space (0xcd - 0xb5), 0x90
+	.align	4, 0x90
+L1:
+        .space (0x130 - 0xd0),0x90
+	jl	L1
+L2:
+
+.zerofill __DATA,__bss,_sym,4,2





More information about the llvm-commits mailing list