Add the align_to_end option to .bundle_lock in the MC implementation of aligned
authorEli Bendersky <eliben@google.com>
Mon, 7 Jan 2013 21:51:08 +0000 (21:51 +0000)
committerEli Bendersky <eliben@google.com>
Mon, 7 Jan 2013 21:51:08 +0000 (21:51 +0000)
bundling. The document describing this feature and the implementation has also
been updated:

https://sites.google.com/a/chromium.org/dev/nativeclient/pnacl/aligned-bundling-support-in-llvm

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@171797 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/llvm/MC/MCAssembler.h
include/llvm/MC/MCELFStreamer.h
include/llvm/MC/MCObjectStreamer.h
include/llvm/MC/MCStreamer.h
lib/MC/MCAsmStreamer.cpp
lib/MC/MCAssembler.cpp
lib/MC/MCELFStreamer.cpp
lib/MC/MCNullStreamer.cpp
lib/MC/MCObjectStreamer.cpp
lib/MC/MCParser/AsmParser.cpp
test/MC/ARM/AlignedBundling/group-bundle-arm.s
test/MC/X86/AlignedBundling/asm-printing-bundle-directives.s
tools/lto/LTOModule.cpp

index 6c2fdc5396208b47961ff8f766583496960d7563..1e953c9e22670f8806f161c2b95d160d57ae5544 100644 (file)
@@ -100,9 +100,12 @@ public:
   void setLayoutOrder(unsigned Value) { LayoutOrder = Value; }
 
   /// \brief Does this fragment have instructions emitted into it? By default
-  ///  this is false, but specific fragment types may set it to true.
+  /// this is false, but specific fragment types may set it to true.
   virtual bool hasInstructions() const { return false; }
 
+  /// \brief Should this fragment be placed at the end of an aligned bundle?
+  virtual bool alignToBundleEnd() const { return false; }
+
   /// \brief Get the padding size that must be inserted before this fragment.
   /// Used for bundling. By default, no padding is inserted.
   /// Note that padding size is restricted to 8 bits. This is an optimization
@@ -165,6 +168,9 @@ class MCDataFragment : public MCEncodedFragment {
   /// \brief Does this fragment contain encoded instructions anywhere in it?
   bool HasInstructions;
 
+  /// \brief Should this fragment be aligned to the end of a bundle?
+  bool AlignToBundleEnd;
+
   SmallVector<char, 32> Contents;
 
   /// Fixups - The list of fixups in this fragment.
@@ -172,7 +178,7 @@ class MCDataFragment : public MCEncodedFragment {
 public:
   MCDataFragment(MCSectionData *SD = 0)
     : MCEncodedFragment(FT_Data, SD),
-      HasInstructions(false)
+      HasInstructions(false), AlignToBundleEnd(false)
   {
   }
 
@@ -190,6 +196,9 @@ public:
   virtual bool hasInstructions() const { return HasInstructions; }
   virtual void setHasInstructions(bool V) { HasInstructions = V; }
 
+  virtual bool alignToBundleEnd() const { return AlignToBundleEnd; }
+  virtual void setAlignToBundleEnd(bool V) { AlignToBundleEnd = V; }
+
   fixup_iterator fixup_begin() { return Fixups.begin(); }
   const_fixup_iterator fixup_begin() const { return Fixups.begin(); }
 
@@ -476,6 +485,12 @@ public:
   typedef FragmentListType::const_reverse_iterator const_reverse_iterator;
   typedef FragmentListType::reverse_iterator reverse_iterator;
 
+  /// \brief Express the state of bundle locked groups while emitting code.
+  enum BundleLockStateType {
+    NotBundleLocked,
+    BundleLocked,
+    BundleLockedAlignToEnd
+  };
 private:
   FragmentListType Fragments;
   const MCSection *Section;
@@ -489,8 +504,8 @@ private:
   /// Alignment - The maximum alignment seen in this section.
   unsigned Alignment;
 
-  /// \brief We're currently inside a bundle-locked group.
-  bool BundleLocked;
+  /// \brief Keeping track of bundle-locked state.
+  BundleLockStateType BundleLockState; 
 
   /// \brief We've seen a bundle_lock directive but not its first instruction
   /// yet.
@@ -549,11 +564,15 @@ public:
   bool empty() const { return Fragments.empty(); }
 
   bool isBundleLocked() const {
-    return BundleLocked;
+    return BundleLockState != NotBundleLocked;
+  }
+
+  BundleLockStateType getBundleLockState() const {
+    return BundleLockState;
   }
 
-  void setBundleLocked(bool IsLocked) {
-    BundleLocked = IsLocked;
+  void setBundleLockState(BundleLockStateType NewState) {
+    BundleLockState = NewState;
   }
 
   bool isBundleGroupBeforeFirstInst() const {
index 5e148c3b09c54c8036e80e591107e2d008aa5333..ab20ee89a87828e38e8798c580eb4c3563dc8f55 100644 (file)
@@ -85,7 +85,7 @@ private:
   virtual void EmitInstToData(const MCInst &Inst);
 
   virtual void EmitBundleAlignMode(unsigned AlignPow2);
-  virtual void EmitBundleLock();
+  virtual void EmitBundleLock(bool AlignToEnd);
   virtual void EmitBundleUnlock();
 
   void fixSymbolsInTLSFixups(const MCExpr *expr);
index 4bc24d48c766dad0101866966f0730a8334fa36e..0ece09238a267d6253a8c1794a76330a98e9802e 100644 (file)
@@ -84,7 +84,7 @@ public:
   virtual void EmitInstToFragment(const MCInst &Inst);
 
   virtual void EmitBundleAlignMode(unsigned AlignPow2);
-  virtual void EmitBundleLock();
+  virtual void EmitBundleLock(bool AlignToEnd);
   virtual void EmitBundleUnlock();
   virtual void EmitBytes(StringRef Data, unsigned AddrSpace);
   virtual void EmitValueToAlignment(unsigned ByteAlignment,
index 8be46b5f1b98d10cb61df0e6bb49f407c90ca637..05a33c550f619fcecedd8d9853ddc297c03fe9af 100644 (file)
@@ -562,7 +562,10 @@ namespace llvm {
     virtual void EmitBundleAlignMode(unsigned AlignPow2) = 0;
 
     /// \brief The following instructions are a bundle-locked group.
-    virtual void EmitBundleLock() = 0;
+    ///
+    /// \param AlignToEnd - If true, the bundle-locked group will be aligned to
+    ///                     the end of a bundle.
+    virtual void EmitBundleLock(bool AlignToEnd) = 0;
 
     /// \brief Ends a bundle-locked group.
     virtual void EmitBundleUnlock() = 0;
index 9b7074d3b25d2f99bdb21d37874c189dd2419e74..e234dfed16ba88b9755818c3eaebbe07c8bbae8e 100644 (file)
@@ -260,7 +260,7 @@ public:
   virtual void EmitInstruction(const MCInst &Inst);
 
   virtual void EmitBundleAlignMode(unsigned AlignPow2);
-  virtual void EmitBundleLock();
+  virtual void EmitBundleLock(bool AlignToEnd);
   virtual void EmitBundleUnlock();
 
   /// EmitRawText - If this file is backed by an assembly streamer, this dumps
@@ -1370,8 +1370,10 @@ void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
   EmitEOL();
 }
 
-void MCAsmStreamer::EmitBundleLock() {
+void MCAsmStreamer::EmitBundleLock(bool AlignToEnd) {
   OS << "\t.bundle_lock";
+  if (AlignToEnd)
+    OS << " align_to_end";
   EmitEOL();
 }
 
index 20b64e2eeb9cd19899da12d9786304e1408d9a43..d30dc7d1f8122e4c8526eab2555f5fcf54abc12b 100644 (file)
@@ -167,10 +167,34 @@ uint64_t MCAsmLayout::computeBundlePadding(const MCFragment *F,
          "computeBundlePadding should only be called if bundling is enabled");
   uint64_t BundleMask = BundleSize - 1;
   uint64_t OffsetInBundle = FOffset & BundleMask;
-
-  // If the fragment would cross a bundle boundary, add enough padding until
-  // the end of the current bundle.
-  if (OffsetInBundle + FSize > BundleSize)
+  uint64_t EndOfFragment = OffsetInBundle + FSize;
+
+  // There are two kinds of bundling restrictions:
+  // 
+  // 1) For alignToBundleEnd(), add padding to ensure that the fragment will
+  //    *end* on a bundle boundary.
+  // 2) Otherwise, check if the fragment would cross a bundle boundary. If it
+  //    would, add padding until the end of the bundle so that the fragment
+  //    will start in a new one.
+  if (F->alignToBundleEnd()) {
+    // Three possibilities here:
+    //
+    // A) The fragment just happens to end at a bundle boundary, so we're good.
+    // B) The fragment ends before the current bundle boundary: pad it just
+    //    enough to reach the boundary.
+    // C) The fragment ends after the current bundle boundary: pad it until it
+    //    reaches the end of the next bundle boundary.
+    //
+    // Note: this code could be made shorter with some modulo trickery, but it's
+    // intentionally kept in its more explicit form for simplicity.
+    if (EndOfFragment == BundleSize)
+      return 0;
+    else if (EndOfFragment < BundleSize)
+      return BundleSize - EndOfFragment;
+    else { // EndOfFragment > BundleSize
+      return 2 * BundleSize - EndOfFragment;
+    }
+  } else if (EndOfFragment > BundleSize)
     return BundleSize - OffsetInBundle;
   else
     return 0;
@@ -204,7 +228,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
   : Section(&_Section),
     Ordinal(~UINT32_C(0)),
     Alignment(1),
-    BundleLocked(false), BundleGroupBeforeFirstInst(false),
+    BundleLockState(NotBundleLocked), BundleGroupBeforeFirstInst(false),
     HasInstructions(false)
 {
   if (A)
index e3acc44a859346d8e83f67c79cbddf352d99ebf2..e9afff6bed4c40e49ea2d0abbf109bfdd7c39a5b 100644 (file)
@@ -379,8 +379,14 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) {
     MCSectionData *SD = getCurrentSectionData();
     if (SD->isBundleLocked() && !SD->isBundleGroupBeforeFirstInst())
       DF = getOrCreateDataFragment();
-    else
+    else {
       DF = new MCDataFragment(SD);
+      if (SD->getBundleLockState() == MCSectionData::BundleLockedAlignToEnd) {
+        // If this is a new fragment created for a bundle-locked group, and the
+        // group was marked as "align_to_end", set a flag in the fragment.
+        DF->setAlignToBundleEnd(true);
+      }
+    }
 
     // We're now emitting an instruction in a bundle group, so this flag has
     // to be turned off.
@@ -407,7 +413,7 @@ void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
     report_fatal_error(".bundle_align_mode should be only set once per file");
 }
 
-void MCELFStreamer::EmitBundleLock() {
+void MCELFStreamer::EmitBundleLock(bool AlignToEnd) {
   MCSectionData *SD = getCurrentSectionData();
 
   // Sanity checks
@@ -417,7 +423,8 @@ void MCELFStreamer::EmitBundleLock() {
   else if (SD->isBundleLocked())
     report_fatal_error("Nesting of .bundle_lock is forbidden");
 
-  SD->setBundleLocked(true);
+  SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd :
+                                      MCSectionData::BundleLocked);
   SD->setBundleGroupBeforeFirstInst(true);
 }
 
@@ -432,7 +439,7 @@ void MCELFStreamer::EmitBundleUnlock() {
   else if (SD->isBundleGroupBeforeFirstInst())
     report_fatal_error("Empty bundle-locked group is forbidden");
 
-  SD->setBundleLocked(false);
+  SD->setBundleLockState(MCSectionData::NotBundleLocked);
 }
 
 void MCELFStreamer::FinishImpl() {
index d1cd0064ad2f639395a25645b5c7a7eabaa45a95..364c324b3f21e439a8bb3d14f794f44379f44e31 100644 (file)
@@ -96,7 +96,7 @@ namespace {
     virtual void EmitInstruction(const MCInst &Inst) {}
 
     virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
-    virtual void EmitBundleLock() {}
+    virtual void EmitBundleLock(bool AlignToEnd) {}
     virtual void EmitBundleUnlock() {}
 
     virtual void FinishImpl() {}
index 6d5c0a54f37789bbfe078e2b18f0d899b3bd9e70..a848615cb75ece08dc0bfaf76b9b06f52eb3e3f9 100644 (file)
@@ -233,7 +233,7 @@ void MCObjectStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
   llvm_unreachable(BundlingNotImplementedMsg);
 }
 
-void MCObjectStreamer::EmitBundleLock() {
+void MCObjectStreamer::EmitBundleLock(bool AlignToEnd) {
   llvm_unreachable(BundlingNotImplementedMsg);
 }
 
index 8a22ed59498d69680d1a714d7e50280acf9a0fa3..7c3fea5640086dfb1c720c3c691958a97012c948 100644 (file)
@@ -2473,15 +2473,31 @@ bool AsmParser::ParseDirectiveBundleAlignMode() {
 }
 
 /// ParseDirectiveBundleLock
-/// ::= {.bundle_lock}
+/// ::= {.bundle_lock} [align_to_end]
 bool AsmParser::ParseDirectiveBundleLock() {
   CheckForValidSection();
+  bool AlignToEnd = false;
+
+  if (getLexer().isNot(AsmToken::EndOfStatement)) {
+    StringRef Option;
+    SMLoc Loc = getTok().getLoc();
+    const char *kInvalidOptionError =
+      "invalid option for '.bundle_lock' directive";
+
+    if (ParseIdentifier(Option))
+      return Error(Loc, kInvalidOptionError);
+
+    if (Option != "align_to_end")
+      return Error(Loc, kInvalidOptionError);
+    else if (getLexer().isNot(AsmToken::EndOfStatement))
+      return Error(Loc,
+                   "unexpected token after '.bundle_lock' directive option");
+    AlignToEnd = true;
+  }
 
-  if (getLexer().isNot(AsmToken::EndOfStatement))
-    return TokError("unexpected token in '.bundle_lock' directive");
   Lex();
 
-  getStreamer().EmitBundleLock();
+  getStreamer().EmitBundleLock(AlignToEnd);
   return false;
 }
 
index 6a5e454bf09c5421c78ec769dd9754b8f302d9b8..823d9e0cb8eaf37fd6ed81ca7e055e5e49d47b52 100644 (file)
@@ -2,7 +2,7 @@
 # RUN:   | llvm-objdump -no-show-raw-insn -triple armv7 -disassemble - | FileCheck %s
 
 # On ARM each instruction is 4 bytes long so padding for individual
-# instructions should not be inserted. However, for bundle=locked groups
+# instructions should not be inserted. However, for bundle-locked groups
 # it can be.
 
        .syntax unified
index 1892e15850bbbb89b820cc9ab7f7d40ab37db7d1..387e0fe59bf29c076c318bf18ed89edb2754144f 100644 (file)
@@ -14,5 +14,9 @@ foo:
   jle     .L_ELSE
   .bundle_unlock
 # CHECK: .bundle_unlock
+  .bundle_lock align_to_end
+# CHECK: .bundle_lock align_to_end
+  add     %rbx, %rdx
+  .bundle_unlock
 
 
index 137f0ef0ab0c5612f441c4be50a7f92df28463fa..23a8fb4a78e370bcb2c79c6609149bb221a057e9 100644 (file)
@@ -766,7 +766,7 @@ namespace {
     }
 
     virtual void EmitBundleAlignMode(unsigned AlignPow2) {}
-    virtual void EmitBundleLock() {}
+    virtual void EmitBundleLock(bool AlignToEnd) {}
     virtual void EmitBundleUnlock() {}
 
     // Noop calls.