forked from OSchip/llvm-project
[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
This commit is contained in:
parent
032743e18f
commit
39bcc76a92
|
@ -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.
|
||||
|
|
|
@ -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@GOT(%ecx)
|
||||
int3
|
||||
|
||||
.section ".text.other"
|
||||
bar:
|
||||
retq
|
Loading…
Reference in New Issue