From 6c1d4972cf1cd6b6072e31c05f97abb1ed7a8497 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Mon, 7 Jan 2013 21:51:08 +0000 Subject: [PATCH] Add the align_to_end option to .bundle_lock in the MC implementation of aligned 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 --- include/llvm/MC/MCAssembler.h | 33 ++++++++++++++---- include/llvm/MC/MCELFStreamer.h | 2 +- include/llvm/MC/MCObjectStreamer.h | 2 +- include/llvm/MC/MCStreamer.h | 5 ++- lib/MC/MCAsmStreamer.cpp | 6 ++-- lib/MC/MCAssembler.cpp | 34 ++++++++++++++++--- lib/MC/MCELFStreamer.cpp | 15 +++++--- lib/MC/MCNullStreamer.cpp | 2 +- lib/MC/MCObjectStreamer.cpp | 2 +- lib/MC/MCParser/AsmParser.cpp | 24 ++++++++++--- .../MC/ARM/AlignedBundling/group-bundle-arm.s | 2 +- .../asm-printing-bundle-directives.s | 4 +++ tools/lto/LTOModule.cpp | 2 +- 13 files changed, 104 insertions(+), 29 deletions(-) diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index 6c2fdc53962..1e953c9e226 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -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 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 { diff --git a/include/llvm/MC/MCELFStreamer.h b/include/llvm/MC/MCELFStreamer.h index 5e148c3b09c..ab20ee89a87 100644 --- a/include/llvm/MC/MCELFStreamer.h +++ b/include/llvm/MC/MCELFStreamer.h @@ -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); diff --git a/include/llvm/MC/MCObjectStreamer.h b/include/llvm/MC/MCObjectStreamer.h index 4bc24d48c76..0ece09238a2 100644 --- a/include/llvm/MC/MCObjectStreamer.h +++ b/include/llvm/MC/MCObjectStreamer.h @@ -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, diff --git a/include/llvm/MC/MCStreamer.h b/include/llvm/MC/MCStreamer.h index 8be46b5f1b9..05a33c550f6 100644 --- a/include/llvm/MC/MCStreamer.h +++ b/include/llvm/MC/MCStreamer.h @@ -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; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 9b7074d3b25..e234dfed16b 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -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(); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 20b64e2eeb9..d30dc7d1f81 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -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) diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index e3acc44a859..e9afff6bed4 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -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() { diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index d1cd0064ad2..364c324b3f2 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -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() {} diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 6d5c0a54f37..a848615cb75 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -233,7 +233,7 @@ void MCObjectStreamer::EmitBundleAlignMode(unsigned AlignPow2) { llvm_unreachable(BundlingNotImplementedMsg); } -void MCObjectStreamer::EmitBundleLock() { +void MCObjectStreamer::EmitBundleLock(bool AlignToEnd) { llvm_unreachable(BundlingNotImplementedMsg); } diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 8a22ed59498..7c3fea56400 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -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; } diff --git a/test/MC/ARM/AlignedBundling/group-bundle-arm.s b/test/MC/ARM/AlignedBundling/group-bundle-arm.s index 6a5e454bf09..823d9e0cb8e 100644 --- a/test/MC/ARM/AlignedBundling/group-bundle-arm.s +++ b/test/MC/ARM/AlignedBundling/group-bundle-arm.s @@ -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 diff --git a/test/MC/X86/AlignedBundling/asm-printing-bundle-directives.s b/test/MC/X86/AlignedBundling/asm-printing-bundle-directives.s index 1892e15850b..387e0fe59bf 100644 --- a/test/MC/X86/AlignedBundling/asm-printing-bundle-directives.s +++ b/test/MC/X86/AlignedBundling/asm-printing-bundle-directives.s @@ -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 diff --git a/tools/lto/LTOModule.cpp b/tools/lto/LTOModule.cpp index 137f0ef0ab0..23a8fb4a78e 100644 --- a/tools/lto/LTOModule.cpp +++ b/tools/lto/LTOModule.cpp @@ -766,7 +766,7 @@ namespace { } virtual void EmitBundleAlignMode(unsigned AlignPow2) {} - virtual void EmitBundleLock() {} + virtual void EmitBundleLock(bool AlignToEnd) {} virtual void EmitBundleUnlock() {} // Noop calls. -- 2.34.1