From: Derek Schuff Date: Wed, 15 Oct 2014 17:10:04 +0000 (+0000) Subject: [MC] Make bundle alignment mode setting idempotent and support nested bundles X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=279b5504a3441b2d2d8330af2b02b99ebe74d38a [MC] Make bundle alignment mode setting idempotent and support nested bundles Summary: Currently an error is thrown if bundle alignment mode is set more than once per module (either via the API or the .bundle_align_mode directive). This change allows setting it multiple times as long as the alignment doesn't change. Also nested bundle_lock groups are currently not allowed. This change allows them, with the effect that the group stays open until all nests are exited, and if any of the bundle_lock directives has the align_to_end flag, the group becomes align_to_end. These changes make the bundle aligment simpler to use in the compiler, and also better match the corresponding support in GNU as. Reviewers: jvoung, eliben Differential Revision: http://reviews.llvm.org/D5801 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@219811 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index b0a706de341..681a3172879 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -594,7 +594,10 @@ private: unsigned Alignment; /// \brief Keeping track of bundle-locked state. - BundleLockStateType BundleLockState; + BundleLockStateType BundleLockState; + + /// \brief Current nesting depth of bundle_lock directives. + unsigned BundleLockNestingDepth; /// \brief We've seen a bundle_lock directive but not its first instruction /// yet. @@ -666,9 +669,7 @@ public: return BundleLockState; } - void setBundleLockState(BundleLockStateType NewState) { - BundleLockState = NewState; - } + void setBundleLockState(BundleLockStateType NewState); bool isBundleGroupBeforeFirstInst() const { return BundleGroupBeforeFirstInst; diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index bc78a298639..85d0c13c710 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -291,7 +291,9 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) : Section(&_Section), Ordinal(~UINT32_C(0)), Alignment(1), - BundleLockState(NotBundleLocked), BundleGroupBeforeFirstInst(false), + BundleLockState(NotBundleLocked), + BundleLockNestingDepth(0), + BundleGroupBeforeFirstInst(false), HasInstructions(false) { if (A) @@ -328,6 +330,25 @@ MCSectionData::getSubsectionInsertionPoint(unsigned Subsection) { return IP; } +void MCSectionData::setBundleLockState(BundleLockStateType NewState) { + if (NewState == NotBundleLocked) { + if (BundleLockNestingDepth == 0) { + report_fatal_error("Mismatched bundle_lock/unlock directives"); + } + if (--BundleLockNestingDepth == 0) { + BundleLockState = NotBundleLocked; + } + return; + } + + // If any of the directives is an align_to_end directive, the whole nested + // group is align_to_end. So don't downgrade from align_to_end to just locked. + if (BundleLockState != BundleLockedAlignToEnd) { + BundleLockState = NewState; + } + ++BundleLockNestingDepth; +} + /* *** */ MCSymbolData::MCSymbolData() : Symbol(nullptr) {} diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 34049b7c967..4ef22d00224 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -453,11 +453,13 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, } else { DF = new MCDataFragment(); insert(DF); - 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); - } + } + if (SD->getBundleLockState() == MCSectionData::BundleLockedAlignToEnd) { + // If this fragment is for a group marked "align_to_end", set a flag + // in the fragment. This can happen after the fragment has already been + // created if there are nested bundle_align groups and an inner one + // is the one marked align_to_end. + DF->setAlignToBundleEnd(true); } // We're now emitting an instruction in a bundle group, so this flag has @@ -479,10 +481,11 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst, void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) { assert(AlignPow2 <= 30 && "Invalid bundle alignment"); MCAssembler &Assembler = getAssembler(); - if (Assembler.getBundleAlignSize() == 0 && AlignPow2 > 0) - Assembler.setBundleAlignSize(1 << AlignPow2); + if (AlignPow2 > 0 && (Assembler.getBundleAlignSize() == 0 || + Assembler.getBundleAlignSize() == 1U << AlignPow2)) + Assembler.setBundleAlignSize(1U << AlignPow2); else - report_fatal_error(".bundle_align_mode should be only set once per file"); + report_fatal_error(".bundle_align_mode cannot be changed once set"); } void MCELFStreamer::EmitBundleLock(bool AlignToEnd) { @@ -492,12 +495,12 @@ void MCELFStreamer::EmitBundleLock(bool AlignToEnd) { // if (!getAssembler().isBundlingEnabled()) report_fatal_error(".bundle_lock forbidden when bundling is disabled"); - else if (SD->isBundleLocked()) - report_fatal_error("Nesting of .bundle_lock is forbidden"); + + if (!SD->isBundleLocked()) + SD->setBundleGroupBeforeFirstInst(true); SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd : MCSectionData::BundleLocked); - SD->setBundleGroupBeforeFirstInst(true); } void MCELFStreamer::EmitBundleUnlock() { diff --git a/test/MC/X86/AlignedBundling/nesting.s b/test/MC/X86/AlignedBundling/nesting.s new file mode 100644 index 00000000000..8996170a1d1 --- /dev/null +++ b/test/MC/X86/AlignedBundling/nesting.s @@ -0,0 +1,67 @@ +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - \ +# RUN: | llvm-objdump -disassemble -no-show-raw-insn - | FileCheck %s + +# Will be bundle-aligning to 16 byte boundaries + .bundle_align_mode 4 + .text +# CHECK-LABEL: foo +foo: +# Test that bundle alignment mode can be set more than once. + .bundle_align_mode 4 +# Each of these callq instructions is 5 bytes long + callq bar + callq bar + .bundle_lock + .bundle_lock + callq bar + callq bar + .bundle_unlock + .bundle_unlock +# CHECK: 10: callq +# CHECK-NEXT: 15: callq + + .p2align 4 +# CHECK-LABEL: bar +bar: + callq foo + callq foo +# Check that the callqs get bundled together, and that the whole group is +# align_to_end + .bundle_lock + callq bar + .bundle_lock align_to_end + callq bar + .bundle_unlock + .bundle_unlock +# CHECK: 36: callq +# CHECK-NEXT: 3b: callq + +# CHECK-LABEL: baz +baz: + callq foo + callq foo +# Check that the callqs get bundled together, and that the whole group is +# align_to_end (with the outer directive marked align_to_end) + .bundle_lock align_to_end + callq bar + .bundle_lock + callq bar + .bundle_unlock + .bundle_unlock +# CHECK: 56: callq +# CHECK-NEXT: 5b: callq + +# CHECK-LABEL: quux +quux: + callq bar + callq bar + .bundle_lock + .bundle_lock + callq bar + .bundle_unlock + callq bar + .bundle_unlock +# Check that the calls are bundled together when the second one is after the +# inner nest is closed. +# CHECK: 70: callq +# CHECK-NEXT: 75: callq