[llvm] 39bcc76 - [X86] Disable nop padding before instruction following hardcode
Shengchen Kan via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 16 18:45:47 PDT 2020
Author: Shengchen Kan
Date: 2020-03-17T09:45:12+08:00
New Revision: 39bcc76a9253181023e8e39af082b2f0de688b1d
URL: https://github.com/llvm/llvm-project/commit/39bcc76a9253181023e8e39af082b2f0de688b1d
DIFF: https://github.com/llvm/llvm-project/commit/39bcc76a9253181023e8e39af082b2f0de688b1d.diff
LOG: [X86] Disable nop padding before instruction following hardcode
Reviewers: reames, MaskRay, craig.topper, LuoYuanke, jyknight
Reviewed By: LuoYuanke
Subscribers: annita.zhang, llvm-commits, hiraditya
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76176
Added:
llvm/test/MC/X86/align-branch-64-hardcode.s
Modified:
llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
index 141fcf89555f..e3d8b7715f5a 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp
@@ -138,6 +138,7 @@ class X86AsmBackend : public MCAsmBackend {
bool needAlignInst(const MCInst &Inst) const;
MCInst PrevInst;
MCBoundaryAlignFragment *PendingBoundaryAlign = nullptr;
+ std::pair<MCFragment *, size_t> PrevInstPosition;
public:
X86AsmBackend(const Target &T, const MCSubtargetInfo &STI)
@@ -491,6 +492,52 @@ static bool hasInterruptDelaySlot(const MCInst &Inst) {
return false;
}
+/// Check if the instruction to be emitted is right after any data.
+static bool
+isRightAfterData(MCFragment *CurrentFragment,
+ const std::pair<MCFragment *, size_t> &PrevInstPosition) {
+ MCFragment *F = CurrentFragment;
+ // Empty data fragments may be created to prevent further data being
+ // added into the previous fragment, we need to skip them since they
+ // have no contents.
+ for (; isa_and_nonnull<MCDataFragment>(F); F = F->getPrevNode())
+ if (cast<MCDataFragment>(F)->getContents().size() != 0)
+ break;
+
+ // Since data is always emitted into a DataFragment, our check strategy is
+ // simple here.
+ // - If the fragment is a DataFragment
+ // - If it's not the fragment where the previous instruction is,
+ // returns true.
+ // - If it's the fragment holding the previous instruction but its
+ // size changed since the the previous instruction was emitted into
+ // it, returns true.
+ // - Otherwise returns false.
+ // - If the fragment is not a DataFragment, returns false.
+ if (auto *DF = dyn_cast_or_null<MCDataFragment>(F))
+ return DF != PrevInstPosition.first ||
+ DF->getContents().size() != PrevInstPosition.second;
+
+ return false;
+}
+
+/// \returns the fragment size if it has instructions, otherwise returns 0.
+static size_t getSizeForInstFragment(const MCFragment *F) {
+ if (!F || !F->hasInstructions())
+ return 0;
+ // MCEncodedFragmentWithContents being templated makes this tricky.
+ switch (F->getKind()) {
+ default:
+ llvm_unreachable("Unknown fragment with instructions!");
+ case MCFragment::FT_Data:
+ return cast<MCDataFragment>(*F).getContents().size();
+ case MCFragment::FT_Relaxable:
+ return cast<MCRelaxableFragment>(*F).getContents().size();
+ case MCFragment::FT_CompactEncodedInst:
+ return cast<MCCompactEncodedInstFragment>(*F).getContents().size();
+ }
+}
+
/// Check if the instruction operand needs to be aligned. Padding is disabled
/// before intruction which may be rewritten by linker(e.g. TLSCALL).
bool X86AsmBackend::needAlignInst(const MCInst &Inst) const {
@@ -527,6 +574,11 @@ void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
// semantic.
return;
+ if (isRightAfterData(OS.getCurrentFragment(), PrevInstPosition))
+ // If this instruction follows any data, there is no clear
+ // instruction boundary, inserting a nop would change semantic.
+ return;
+
if (!isMacroFused(PrevInst, Inst))
// Macro fusion doesn't happen indeed, clear the pending.
PendingBoundaryAlign = nullptr;
@@ -569,19 +621,21 @@ void X86AsmBackend::emitInstructionEnd(MCObjectStreamer &OS, const MCInst &Inst)
return;
PrevInst = Inst;
+ MCFragment *CF = OS.getCurrentFragment();
+ PrevInstPosition = std::make_pair(CF, getSizeForInstFragment(CF));
if (!needAlignInst(Inst) || !PendingBoundaryAlign)
return;
// Tie the aligned instructions into a a pending BoundaryAlign.
- PendingBoundaryAlign->setLastFragment(OS.getCurrentFragment());
+ PendingBoundaryAlign->setLastFragment(CF);
PendingBoundaryAlign = nullptr;
// We need to ensure that further data isn't added to the current
// DataFragment, so that we can get the size of instructions later in
// MCAssembler::relaxBoundaryAlign. The easiest way is to insert a new empty
// DataFragment.
- if (isa_and_nonnull<MCDataFragment>(OS.getCurrentFragment()))
+ if (isa_and_nonnull<MCDataFragment>(CF))
OS.insert(new MCDataFragment());
// Update the maximum alignment on the current section if necessary.
diff --git a/llvm/test/MC/X86/align-branch-64-hardcode.s b/llvm/test/MC/X86/align-branch-64-hardcode.s
new file mode 100644
index 000000000000..103e90534762
--- /dev/null
+++ b/llvm/test/MC/X86/align-branch-64-hardcode.s
@@ -0,0 +1,32 @@
+ # RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu --x86-align-branch-boundary=32 --x86-align-branch=jmp+call %s | llvm-objdump -d --no-show-raw-insn - | FileCheck %s
+
+ # Exercise cases where instructions to be aligned is after hardcode
+ # and thus can't add a nop in between without changing semantic.
+
+ .text
+
+ # CHECK: 1d: int3
+ # CHECK: 1e: jmp
+ # CHECK: 24: int3
+ .p2align 5
+ .rept 30
+ int3
+ .endr
+ .byte 0x2e
+ jmp baz
+ int3
+
+ # CHECK: 5d: int3
+ # CHECK: 5e: call
+ # CHECK: 66: int3
+ .p2align 5
+ .rept 30
+ int3
+ .endr
+ .byte 0x66
+ call *___tls_get_addr at GOT(%ecx)
+ int3
+
+ .section ".text.other"
+bar:
+ retq
More information about the llvm-commits
mailing list