[NFC][X86] Refine code in X86AsmBackend

Summary: Move code to a better place, rename function, etc

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D77778
This commit is contained in:
Shengchen Kan 2020-04-09 13:56:04 +08:00
parent 9aa5fbb3af
commit 2477cec2ac
1 changed files with 75 additions and 84 deletions

View File

@ -62,10 +62,9 @@ public:
else if (BranchType == "indirect") else if (BranchType == "indirect")
addKind(X86::AlignBranchIndirect); addKind(X86::AlignBranchIndirect);
else { else {
report_fatal_error( errs() << "invalid argument " << BranchType.str()
"'-x86-align-branch 'The branches's type is combination of jcc, " << " to -x86-align-branch=; each element must be one of: fused, "
"fused, jmp, call, ret, indirect.(plus separated)", "jcc, jmp, call, ret, indirect.(plus separated)";
false);
} }
} }
} }
@ -129,18 +128,18 @@ class X86AsmBackend : public MCAsmBackend {
std::unique_ptr<const MCInstrInfo> MCII; std::unique_ptr<const MCInstrInfo> MCII;
X86AlignBranchKind AlignBranchType; X86AlignBranchKind AlignBranchType;
Align AlignBoundary; Align AlignBoundary;
unsigned TargetPrefixMax = 0;
MCInst PrevInst;
MCBoundaryAlignFragment *PendingBA = nullptr;
std::pair<MCFragment *, size_t> PrevInstPosition;
bool CanPadInst;
uint8_t determinePaddingPrefix(const MCInst &Inst) const; uint8_t determinePaddingPrefix(const MCInst &Inst) const;
bool isMacroFused(const MCInst &Cmp, const MCInst &Jcc) const; bool isMacroFused(const MCInst &Cmp, const MCInst &Jcc) const;
bool needAlign(const MCInst &Inst) const;
bool needAlign(MCObjectStreamer &OS) const; bool canPadBranches(MCObjectStreamer &OS) const;
bool needAlignInst(const MCInst &Inst) const; bool canPadInst(const MCInst &Inst, MCObjectStreamer &OS) const;
bool allowAutoPaddingForInst(const MCInst &Inst, MCObjectStreamer &OS) const;
MCInst PrevInst;
MCBoundaryAlignFragment *PendingBoundaryAlign = nullptr;
std::pair<MCFragment *, size_t> PrevInstPosition;
bool AllowAutoPaddingForInst;
public: public:
X86AsmBackend(const Target &T, const MCSubtargetInfo &STI) X86AsmBackend(const Target &T, const MCSubtargetInfo &STI)
@ -161,6 +160,8 @@ public:
AlignBoundary = assumeAligned(X86AlignBranchBoundary); AlignBoundary = assumeAligned(X86AlignBranchBoundary);
if (X86AlignBranch.getNumOccurrences()) if (X86AlignBranch.getNumOccurrences())
AlignBranchType = X86AlignBranchKindLoc; AlignBranchType = X86AlignBranchKindLoc;
if (X86PadMaxPrefixSize.getNumOccurrences())
TargetPrefixMax = X86PadMaxPrefixSize;
} }
bool allowAutoPadding() const override; bool allowAutoPadding() const override;
@ -459,23 +460,7 @@ bool X86AsmBackend::allowAutoPadding() const {
} }
bool X86AsmBackend::allowEnhancedRelaxation() const { bool X86AsmBackend::allowEnhancedRelaxation() const {
return allowAutoPadding() && X86PadMaxPrefixSize != 0 && X86PadForBranchAlign; return allowAutoPadding() && TargetPrefixMax != 0 && X86PadForBranchAlign;
}
bool X86AsmBackend::needAlign(MCObjectStreamer &OS) const {
if (!OS.getAllowAutoPadding())
return false;
assert(allowAutoPadding() && "incorrect initialization!");
// To be Done: Currently don't deal with Bundle cases.
if (OS.getAssembler().isBundlingEnabled())
return false;
// Branches only need to be aligned in 32-bit or 64-bit mode.
if (!(STI.hasFeature(X86::Mode64Bit) || STI.hasFeature(X86::Mode32Bit)))
return false;
return true;
} }
/// X86 has certain instructions which enable interrupts exactly one /// X86 has certain instructions which enable interrupts exactly one
@ -545,25 +530,9 @@ static size_t getSizeForInstFragment(const MCFragment *F) {
} }
} }
/// Check if the instruction operand needs to be aligned.
bool X86AsmBackend::needAlignInst(const MCInst &Inst) const {
const MCInstrDesc &InstDesc = MCII->get(Inst.getOpcode());
return (InstDesc.isConditionalBranch() &&
(AlignBranchType & X86::AlignBranchJcc)) ||
(InstDesc.isUnconditionalBranch() &&
(AlignBranchType & X86::AlignBranchJmp)) ||
(InstDesc.isCall() &&
(AlignBranchType & X86::AlignBranchCall)) ||
(InstDesc.isReturn() &&
(AlignBranchType & X86::AlignBranchRet)) ||
(InstDesc.isIndirectBranch() &&
(AlignBranchType & X86::AlignBranchIndirect));
}
/// Return true if we can insert NOP or prefixes automatically before the /// Return true if we can insert NOP or prefixes automatically before the
/// the instruction to be emitted. /// the instruction to be emitted.
bool X86AsmBackend::allowAutoPaddingForInst(const MCInst &Inst, bool X86AsmBackend::canPadInst(const MCInst &Inst, MCObjectStreamer &OS) const {
MCObjectStreamer &OS) const {
if (hasVariantSymbol(Inst)) if (hasVariantSymbol(Inst))
// Linker may rewrite the instruction with variant symbol operand(e.g. // Linker may rewrite the instruction with variant symbol operand(e.g.
// TLSCALL). // TLSCALL).
@ -592,23 +561,51 @@ bool X86AsmBackend::allowAutoPaddingForInst(const MCInst &Inst,
return true; return true;
} }
bool X86AsmBackend::canPadBranches(MCObjectStreamer &OS) const {
if (!OS.getAllowAutoPadding())
return false;
assert(allowAutoPadding() && "incorrect initialization!");
// To be Done: Currently don't deal with Bundle cases.
if (OS.getAssembler().isBundlingEnabled())
return false;
// Branches only need to be aligned in 32-bit or 64-bit mode.
if (!(STI.hasFeature(X86::Mode64Bit) || STI.hasFeature(X86::Mode32Bit)))
return false;
return true;
}
/// Check if the instruction operand needs to be aligned.
bool X86AsmBackend::needAlign(const MCInst &Inst) const {
const MCInstrDesc &Desc = MCII->get(Inst.getOpcode());
return (Desc.isConditionalBranch() &&
(AlignBranchType & X86::AlignBranchJcc)) ||
(Desc.isUnconditionalBranch() &&
(AlignBranchType & X86::AlignBranchJmp)) ||
(Desc.isCall() && (AlignBranchType & X86::AlignBranchCall)) ||
(Desc.isReturn() && (AlignBranchType & X86::AlignBranchRet)) ||
(Desc.isIndirectBranch() &&
(AlignBranchType & X86::AlignBranchIndirect));
}
/// Insert BoundaryAlignFragment before instructions to align branches. /// Insert BoundaryAlignFragment before instructions to align branches.
void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS, void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
const MCInst &Inst) { const MCInst &Inst) {
AllowAutoPaddingForInst = allowAutoPaddingForInst(Inst, OS); CanPadInst = canPadInst(Inst, OS);
if (!needAlign(OS)) if (!canPadBranches(OS))
return; return;
if (!isMacroFused(PrevInst, Inst)) if (!isMacroFused(PrevInst, Inst))
// Macro fusion doesn't happen indeed, clear the pending. // Macro fusion doesn't happen indeed, clear the pending.
PendingBoundaryAlign = nullptr; PendingBA = nullptr;
if (!AllowAutoPaddingForInst) if (!CanPadInst)
return; return;
if (PendingBoundaryAlign && if (PendingBA && OS.getCurrentFragment()->getPrevNode() == PendingBA) {
OS.getCurrentFragment()->getPrevNode() == PendingBoundaryAlign) {
// Macro fusion actually happens and there is no other fragment inserted // Macro fusion actually happens and there is no other fragment inserted
// after the previous instruction. // after the previous instruction.
// //
@ -630,12 +627,11 @@ void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
return; return;
} }
if (needAlignInst(Inst) || ((AlignBranchType & X86::AlignBranchFused) && if (needAlign(Inst) || ((AlignBranchType & X86::AlignBranchFused) &&
isFirstMacroFusibleInst(Inst, *MCII))) { isFirstMacroFusibleInst(Inst, *MCII))) {
// If we meet a unfused branch or the first instuction in a fusiable pair, // If we meet a unfused branch or the first instuction in a fusiable pair,
// insert a BoundaryAlign fragment. // insert a BoundaryAlign fragment.
OS.insert(PendingBoundaryAlign = OS.insert(PendingBA = new MCBoundaryAlignFragment(AlignBoundary));
new MCBoundaryAlignFragment(AlignBoundary));
} }
} }
@ -645,17 +641,17 @@ void X86AsmBackend::emitInstructionEnd(MCObjectStreamer &OS, const MCInst &Inst)
MCFragment *CF = OS.getCurrentFragment(); MCFragment *CF = OS.getCurrentFragment();
PrevInstPosition = std::make_pair(CF, getSizeForInstFragment(CF)); PrevInstPosition = std::make_pair(CF, getSizeForInstFragment(CF));
if (auto *F = dyn_cast_or_null<MCRelaxableFragment>(CF)) if (auto *F = dyn_cast_or_null<MCRelaxableFragment>(CF))
F->setAllowAutoPadding(AllowAutoPaddingForInst); F->setAllowAutoPadding(CanPadInst);
if (!needAlign(OS)) if (!canPadBranches(OS))
return; return;
if (!needAlignInst(Inst) || !PendingBoundaryAlign) if (!needAlign(Inst) || !PendingBA)
return; return;
// Tie the aligned instructions into a a pending BoundaryAlign. // Tie the aligned instructions into a a pending BoundaryAlign.
PendingBoundaryAlign->setLastFragment(CF); PendingBA->setLastFragment(CF);
PendingBoundaryAlign = nullptr; PendingBA = nullptr;
// We need to ensure that further data isn't added to the current // 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 // DataFragment, so that we can get the size of instructions later in
@ -853,26 +849,6 @@ static bool isFullyRelaxed(const MCRelaxableFragment &RF) {
return getRelaxedOpcode(Inst, Is16BitMode) == Inst.getOpcode(); return getRelaxedOpcode(Inst, Is16BitMode) == Inst.getOpcode();
} }
static unsigned getRemainingPrefixSize(const MCInst &Inst,
const MCSubtargetInfo &STI,
MCCodeEmitter &Emitter) {
SmallString<256> Code;
raw_svector_ostream VecOS(Code);
Emitter.emitPrefix(Inst, VecOS, STI);
assert(Code.size() < 15 && "The number of prefixes must be less than 15.");
// TODO: It turns out we need a decent amount of plumbing for the target
// specific bits to determine number of prefixes its safe to add. Various
// targets (older chips mostly, but also Atom family) encounter decoder
// stalls with too many prefixes. For testing purposes, we set the value
// externally for the moment.
unsigned ExistingPrefixSize = Code.size();
unsigned TargetPrefixMax = X86PadMaxPrefixSize;
if (TargetPrefixMax <= ExistingPrefixSize)
return 0;
return TargetPrefixMax - ExistingPrefixSize;
}
bool X86AsmBackend::padInstructionViaPrefix(MCRelaxableFragment &RF, bool X86AsmBackend::padInstructionViaPrefix(MCRelaxableFragment &RF,
MCCodeEmitter &Emitter, MCCodeEmitter &Emitter,
unsigned &RemainingSize) const { unsigned &RemainingSize) const {
@ -890,9 +866,24 @@ bool X86AsmBackend::padInstructionViaPrefix(MCRelaxableFragment &RF,
return false; return false;
const unsigned MaxPossiblePad = std::min(15 - OldSize, RemainingSize); const unsigned MaxPossiblePad = std::min(15 - OldSize, RemainingSize);
const unsigned RemainingPrefixSize = [&]() -> unsigned {
SmallString<15> Code;
raw_svector_ostream VecOS(Code);
Emitter.emitPrefix(RF.getInst(), VecOS, STI);
assert(Code.size() < 15 && "The number of prefixes must be less than 15.");
// TODO: It turns out we need a decent amount of plumbing for the target
// specific bits to determine number of prefixes its safe to add. Various
// targets (older chips mostly, but also Atom family) encounter decoder
// stalls with too many prefixes. For testing purposes, we set the value
// externally for the moment.
unsigned ExistingPrefixSize = Code.size();
if (TargetPrefixMax <= ExistingPrefixSize)
return 0;
return TargetPrefixMax - ExistingPrefixSize;
}();
const unsigned PrefixBytesToAdd = const unsigned PrefixBytesToAdd =
std::min(MaxPossiblePad, std::min(MaxPossiblePad, RemainingPrefixSize);
getRemainingPrefixSize(RF.getInst(), STI, Emitter));
if (PrefixBytesToAdd == 0) if (PrefixBytesToAdd == 0)
return false; return false;