mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-01 16:22:41 +00:00
[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
This commit is contained in:
parent
ffc65d2bfe
commit
279b5504a3
@ -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;
|
||||
|
@ -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) {}
|
||||
|
@ -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() {
|
||||
|
67
test/MC/X86/AlignedBundling/nesting.s
Normal file
67
test/MC/X86/AlignedBundling/nesting.s
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user