1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-19 11:02:59 +02:00
llvm-mirror/lib/MC/MCFragment.cpp

481 lines
15 KiB
C++
Raw Normal View History

//===- lib/MC/MCFragment.cpp - Assembler Fragment Implementation ----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/MC/MCFragment.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCFixup.h"
#include "llvm/MC/MCSection.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/MC/MCValue.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <utility>
using namespace llvm;
MCAsmLayout::MCAsmLayout(MCAssembler &Asm) : Assembler(Asm) {
// Compute the section layout order. Virtual sections must go last.
for (MCSection &Sec : Asm)
if (!Sec.isVirtualSection())
SectionOrder.push_back(&Sec);
for (MCSection &Sec : Asm)
if (Sec.isVirtualSection())
SectionOrder.push_back(&Sec);
}
bool MCAsmLayout::isFragmentValid(const MCFragment *F) const {
const MCSection *Sec = F->getParent();
const MCFragment *LastValid = LastValidFragment.lookup(Sec);
if (!LastValid)
return false;
assert(LastValid->getParent() == Sec);
return F->getLayoutOrder() <= LastValid->getLayoutOrder();
}
bool MCAsmLayout::canGetFragmentOffset(const MCFragment *F) const {
MCSection *Sec = F->getParent();
MCSection::iterator I;
if (MCFragment *LastValid = LastValidFragment[Sec]) {
// Fragment already valid, offset is available.
if (F->getLayoutOrder() <= LastValid->getLayoutOrder())
return true;
I = ++MCSection::iterator(LastValid);
} else
I = Sec->begin();
// A fragment ordered before F is currently being laid out.
const MCFragment *FirstInvalidFragment = &*I;
if (FirstInvalidFragment->IsBeingLaidOut)
return false;
return true;
}
void MCAsmLayout::invalidateFragmentsFrom(MCFragment *F) {
// If this fragment wasn't already valid, we don't need to do anything.
if (!isFragmentValid(F))
return;
// Otherwise, reset the last valid fragment to the previous fragment
// (if this is the first fragment, it will be NULL).
LastValidFragment[F->getParent()] = F->getPrevNode();
}
void MCAsmLayout::ensureValid(const MCFragment *F) const {
MCSection *Sec = F->getParent();
MCSection::iterator I;
if (MCFragment *Cur = LastValidFragment[Sec])
I = ++MCSection::iterator(Cur);
else
I = Sec->begin();
// Advance the layout position until the fragment is valid.
while (!isFragmentValid(F)) {
assert(I != Sec->end() && "Layout bookkeeping error");
const_cast<MCAsmLayout *>(this)->layoutFragment(&*I);
++I;
}
}
uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const {
ensureValid(F);
assert(F->Offset != ~UINT64_C(0) && "Address not set!");
return F->Offset;
}
// Simple getSymbolOffset helper for the non-variable case.
static bool getLabelOffset(const MCAsmLayout &Layout, const MCSymbol &S,
bool ReportError, uint64_t &Val) {
if (!S.getFragment()) {
if (ReportError)
report_fatal_error("unable to evaluate offset to undefined symbol '" +
S.getName() + "'");
return false;
}
Val = Layout.getFragmentOffset(S.getFragment()) + S.getOffset();
return true;
}
static bool getSymbolOffsetImpl(const MCAsmLayout &Layout, const MCSymbol &S,
bool ReportError, uint64_t &Val) {
if (!S.isVariable())
return getLabelOffset(Layout, S, ReportError, Val);
// If SD is a variable, evaluate it.
MCValue Target;
if (!S.getVariableValue()->evaluateAsValue(Target, Layout))
report_fatal_error("unable to evaluate offset for variable '" +
S.getName() + "'");
uint64_t Offset = Target.getConstant();
const MCSymbolRefExpr *A = Target.getSymA();
if (A) {
uint64_t ValA;
if (!getLabelOffset(Layout, A->getSymbol(), ReportError, ValA))
return false;
Offset += ValA;
}
const MCSymbolRefExpr *B = Target.getSymB();
if (B) {
uint64_t ValB;
if (!getLabelOffset(Layout, B->getSymbol(), ReportError, ValB))
return false;
Offset -= ValB;
}
Val = Offset;
return true;
}
bool MCAsmLayout::getSymbolOffset(const MCSymbol &S, uint64_t &Val) const {
return getSymbolOffsetImpl(*this, S, false, Val);
}
uint64_t MCAsmLayout::getSymbolOffset(const MCSymbol &S) const {
uint64_t Val;
getSymbolOffsetImpl(*this, S, true, Val);
return Val;
}
const MCSymbol *MCAsmLayout::getBaseSymbol(const MCSymbol &Symbol) const {
if (!Symbol.isVariable())
return &Symbol;
const MCExpr *Expr = Symbol.getVariableValue();
MCValue Value;
if (!Expr->evaluateAsValue(Value, *this)) {
Assembler.getContext().reportError(
Expr->getLoc(), "expression could not be evaluated");
return nullptr;
}
const MCSymbolRefExpr *RefB = Value.getSymB();
if (RefB) {
Assembler.getContext().reportError(
Expr->getLoc(), Twine("symbol '") + RefB->getSymbol().getName() +
"' could not be evaluated in a subtraction expression");
return nullptr;
}
const MCSymbolRefExpr *A = Value.getSymA();
if (!A)
return nullptr;
const MCSymbol &ASym = A->getSymbol();
const MCAssembler &Asm = getAssembler();
if (ASym.isCommon()) {
Asm.getContext().reportError(Expr->getLoc(),
"Common symbol '" + ASym.getName() +
"' cannot be used in assignment expr");
return nullptr;
}
return &ASym;
}
uint64_t MCAsmLayout::getSectionAddressSize(const MCSection *Sec) const {
// The size is the last fragment's end offset.
const MCFragment &F = Sec->getFragmentList().back();
return getFragmentOffset(&F) + getAssembler().computeFragmentSize(*this, F);
}
uint64_t MCAsmLayout::getSectionFileSize(const MCSection *Sec) const {
// Virtual sections have no file size.
if (Sec->isVirtualSection())
return 0;
// Otherwise, the file size is the same as the address space size.
return getSectionAddressSize(Sec);
}
uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler,
const MCEncodedFragment *F,
uint64_t FOffset, uint64_t FSize) {
uint64_t BundleSize = Assembler.getBundleAlignSize();
assert(BundleSize > 0 &&
"computeBundlePadding should only be called if bundling is enabled");
uint64_t BundleMask = BundleSize - 1;
uint64_t OffsetInBundle = FOffset & BundleMask;
uint64_t EndOfFragment = OffsetInBundle + FSize;
// There are two kinds of bundling restrictions:
//
// 1) For alignToBundleEnd(), add padding to ensure that the fragment will
// *end* on a bundle boundary.
// 2) Otherwise, check if the fragment would cross a bundle boundary. If it
// would, add padding until the end of the bundle so that the fragment
// will start in a new one.
if (F->alignToBundleEnd()) {
// Three possibilities here:
//
// A) The fragment just happens to end at a bundle boundary, so we're good.
// B) The fragment ends before the current bundle boundary: pad it just
// enough to reach the boundary.
// C) The fragment ends after the current bundle boundary: pad it until it
// reaches the end of the next bundle boundary.
//
// Note: this code could be made shorter with some modulo trickery, but it's
// intentionally kept in its more explicit form for simplicity.
if (EndOfFragment == BundleSize)
return 0;
else if (EndOfFragment < BundleSize)
return BundleSize - EndOfFragment;
else { // EndOfFragment > BundleSize
return 2 * BundleSize - EndOfFragment;
}
} else if (OffsetInBundle > 0 && EndOfFragment > BundleSize)
return BundleSize - OffsetInBundle;
else
return 0;
}
/* *** */
void ilist_alloc_traits<MCFragment>::deleteNode(MCFragment *V) { V->destroy(); }
MCFragment::MCFragment(FragmentType Kind, bool HasInstructions,
MCSection *Parent)
: Parent(Parent), Atom(nullptr), Offset(~UINT64_C(0)), LayoutOrder(0),
Kind(Kind), IsBeingLaidOut(false), HasInstructions(HasInstructions) {
if (Parent && !isa<MCDummyFragment>(*this))
Parent->getFragmentList().push_back(this);
}
void MCFragment::destroy() {
// First check if we are the sentinal.
if (Kind == FragmentType(~0)) {
delete this;
return;
}
switch (Kind) {
case FT_Align:
delete cast<MCAlignFragment>(this);
return;
case FT_Data:
delete cast<MCDataFragment>(this);
return;
case FT_CompactEncodedInst:
delete cast<MCCompactEncodedInstFragment>(this);
return;
case FT_Fill:
delete cast<MCFillFragment>(this);
return;
case FT_Relaxable:
delete cast<MCRelaxableFragment>(this);
return;
case FT_Org:
delete cast<MCOrgFragment>(this);
return;
case FT_Dwarf:
delete cast<MCDwarfLineAddrFragment>(this);
return;
case FT_DwarfFrame:
delete cast<MCDwarfCallFrameFragment>(this);
return;
case FT_LEB:
delete cast<MCLEBFragment>(this);
return;
Align branches within 32-Byte boundary (NOP padding) WARNING: If you're looking at this patch because you're looking for a full performace mitigation of the Intel JCC Erratum, this is not it! This is a preliminary patch on the patch towards mitigating the performance regressions caused by Intel's microcode update for Jump Conditional Code Erratum. For context, see: https://www.intel.com/content/www/us/en/support/articles/000055650.html The patch adds the required assembler infrastructure and command line options needed to exercise the logic for INTERNAL TESTING. These are NOT public flags, and should not be used for anything other than LLVM's own testing/debugging purposes. They are likely to change both in spelling and meaning. WARNING: This patch is knowingly incorrect in some cornercases. We need, and do not yet provide, a mechanism to selective enable/disable the padding. Conversation on this will continue in parellel with work on extending this infrastructure to support prefix padding. The goal here is to have the assembler align specific instructions such that they neither cross or end at a 32 byte boundary. The impacted instructions are: a. Conditional jump. b. Fused conditional jump. c. Unconditional jump. d. Indirect jump. e. Ret. f. Call. The new options for llvm-mc are: -x86-align-branch-boundary=NUM aligns branches within NUM byte boundary. -x86-align-branch=TYPE[+TYPE...] specifies types of branches to align. A new MCFragment type, MCBoundaryAlignFragment, is added, which may emit NOP to align the fused/unfused branch. alignBranchesBegin inserts MCBoundaryAlignFragment before instructions, alignBranchesEnd marks the end of the branch to be aligned, relaxBoundaryAlign grows or shrinks sizes of NOP to align the target branch. Nop padding is disabled when the instruction may be rewritten by the linker, such as TLS Call. Process Note: I am landing a patch by skan as it has been LGTMed, and continuing to iterate on the review is simply slowing us down at this point. We can and will continue to iterate in tree. Patch By: skan Differential Revision: https://reviews.llvm.org/D70157
2019-12-20 19:51:05 +01:00
case FT_BoundaryAlign:
delete cast<MCBoundaryAlignFragment>(this);
return;
case FT_SymbolId:
delete cast<MCSymbolIdFragment>(this);
return;
case FT_CVInlineLines:
delete cast<MCCVInlineLineTableFragment>(this);
return;
case FT_CVDefRange:
delete cast<MCCVDefRangeFragment>(this);
return;
case FT_Dummy:
delete cast<MCDummyFragment>(this);
return;
}
}
// Debugging methods
namespace llvm {
raw_ostream &operator<<(raw_ostream &OS, const MCFixup &AF) {
OS << "<MCFixup" << " Offset:" << AF.getOffset()
<< " Value:" << *AF.getValue()
<< " Kind:" << AF.getKind() << ">";
return OS;
}
} // end namespace llvm
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void MCFragment::dump() const {
raw_ostream &OS = errs();
OS << "<";
switch (getKind()) {
case MCFragment::FT_Align: OS << "MCAlignFragment"; break;
case MCFragment::FT_Data: OS << "MCDataFragment"; break;
case MCFragment::FT_CompactEncodedInst:
OS << "MCCompactEncodedInstFragment"; break;
case MCFragment::FT_Fill: OS << "MCFillFragment"; break;
case MCFragment::FT_Relaxable: OS << "MCRelaxableFragment"; break;
case MCFragment::FT_Org: OS << "MCOrgFragment"; break;
case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break;
case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break;
case MCFragment::FT_LEB: OS << "MCLEBFragment"; break;
Align branches within 32-Byte boundary (NOP padding) WARNING: If you're looking at this patch because you're looking for a full performace mitigation of the Intel JCC Erratum, this is not it! This is a preliminary patch on the patch towards mitigating the performance regressions caused by Intel's microcode update for Jump Conditional Code Erratum. For context, see: https://www.intel.com/content/www/us/en/support/articles/000055650.html The patch adds the required assembler infrastructure and command line options needed to exercise the logic for INTERNAL TESTING. These are NOT public flags, and should not be used for anything other than LLVM's own testing/debugging purposes. They are likely to change both in spelling and meaning. WARNING: This patch is knowingly incorrect in some cornercases. We need, and do not yet provide, a mechanism to selective enable/disable the padding. Conversation on this will continue in parellel with work on extending this infrastructure to support prefix padding. The goal here is to have the assembler align specific instructions such that they neither cross or end at a 32 byte boundary. The impacted instructions are: a. Conditional jump. b. Fused conditional jump. c. Unconditional jump. d. Indirect jump. e. Ret. f. Call. The new options for llvm-mc are: -x86-align-branch-boundary=NUM aligns branches within NUM byte boundary. -x86-align-branch=TYPE[+TYPE...] specifies types of branches to align. A new MCFragment type, MCBoundaryAlignFragment, is added, which may emit NOP to align the fused/unfused branch. alignBranchesBegin inserts MCBoundaryAlignFragment before instructions, alignBranchesEnd marks the end of the branch to be aligned, relaxBoundaryAlign grows or shrinks sizes of NOP to align the target branch. Nop padding is disabled when the instruction may be rewritten by the linker, such as TLS Call. Process Note: I am landing a patch by skan as it has been LGTMed, and continuing to iterate on the review is simply slowing us down at this point. We can and will continue to iterate in tree. Patch By: skan Differential Revision: https://reviews.llvm.org/D70157
2019-12-20 19:51:05 +01:00
case MCFragment::FT_BoundaryAlign: OS<<"MCBoundaryAlignFragment"; break;
case MCFragment::FT_SymbolId: OS << "MCSymbolIdFragment"; break;
case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break;
case MCFragment::FT_CVDefRange: OS << "MCCVDefRangeTableFragment"; break;
case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break;
}
OS << "<MCFragment " << (const void *)this << " LayoutOrder:" << LayoutOrder
<< " Offset:" << Offset << " HasInstructions:" << hasInstructions();
if (const auto *EF = dyn_cast<MCEncodedFragment>(this))
OS << " BundlePadding:" << static_cast<unsigned>(EF->getBundlePadding());
OS << ">";
switch (getKind()) {
case MCFragment::FT_Align: {
const auto *AF = cast<MCAlignFragment>(this);
if (AF->hasEmitNops())
OS << " (emit nops)";
OS << "\n ";
OS << " Alignment:" << AF->getAlignment()
<< " Value:" << AF->getValue() << " ValueSize:" << AF->getValueSize()
<< " MaxBytesToEmit:" << AF->getMaxBytesToEmit() << ">";
break;
}
case MCFragment::FT_Data: {
const auto *DF = cast<MCDataFragment>(this);
OS << "\n ";
OS << " Contents:[";
const SmallVectorImpl<char> &Contents = DF->getContents();
for (unsigned i = 0, e = Contents.size(); i != e; ++i) {
if (i) OS << ",";
OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF);
}
OS << "] (" << Contents.size() << " bytes)";
if (DF->fixup_begin() != DF->fixup_end()) {
OS << ",\n ";
OS << " Fixups:[";
for (MCDataFragment::const_fixup_iterator it = DF->fixup_begin(),
ie = DF->fixup_end(); it != ie; ++it) {
if (it != DF->fixup_begin()) OS << ",\n ";
OS << *it;
}
OS << "]";
}
break;
}
case MCFragment::FT_CompactEncodedInst: {
const auto *CEIF =
cast<MCCompactEncodedInstFragment>(this);
OS << "\n ";
OS << " Contents:[";
const SmallVectorImpl<char> &Contents = CEIF->getContents();
for (unsigned i = 0, e = Contents.size(); i != e; ++i) {
if (i) OS << ",";
OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF);
}
OS << "] (" << Contents.size() << " bytes)";
break;
}
case MCFragment::FT_Fill: {
const auto *FF = cast<MCFillFragment>(this);
OS << " Value:" << static_cast<unsigned>(FF->getValue())
<< " ValueSize:" << static_cast<unsigned>(FF->getValueSize())
<< " NumValues:" << FF->getNumValues();
break;
}
case MCFragment::FT_Relaxable: {
const auto *F = cast<MCRelaxableFragment>(this);
OS << "\n ";
OS << " Inst:";
F->getInst().dump_pretty(OS);
OS << " (" << F->getContents().size() << " bytes)";
break;
}
case MCFragment::FT_Org: {
const auto *OF = cast<MCOrgFragment>(this);
OS << "\n ";
OS << " Offset:" << OF->getOffset()
<< " Value:" << static_cast<unsigned>(OF->getValue());
break;
}
case MCFragment::FT_Dwarf: {
const auto *OF = cast<MCDwarfLineAddrFragment>(this);
OS << "\n ";
OS << " AddrDelta:" << OF->getAddrDelta()
<< " LineDelta:" << OF->getLineDelta();
break;
}
case MCFragment::FT_DwarfFrame: {
const auto *CF = cast<MCDwarfCallFrameFragment>(this);
OS << "\n ";
OS << " AddrDelta:" << CF->getAddrDelta();
break;
}
case MCFragment::FT_LEB: {
const auto *LF = cast<MCLEBFragment>(this);
OS << "\n ";
OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned();
break;
}
Align branches within 32-Byte boundary (NOP padding) WARNING: If you're looking at this patch because you're looking for a full performace mitigation of the Intel JCC Erratum, this is not it! This is a preliminary patch on the patch towards mitigating the performance regressions caused by Intel's microcode update for Jump Conditional Code Erratum. For context, see: https://www.intel.com/content/www/us/en/support/articles/000055650.html The patch adds the required assembler infrastructure and command line options needed to exercise the logic for INTERNAL TESTING. These are NOT public flags, and should not be used for anything other than LLVM's own testing/debugging purposes. They are likely to change both in spelling and meaning. WARNING: This patch is knowingly incorrect in some cornercases. We need, and do not yet provide, a mechanism to selective enable/disable the padding. Conversation on this will continue in parellel with work on extending this infrastructure to support prefix padding. The goal here is to have the assembler align specific instructions such that they neither cross or end at a 32 byte boundary. The impacted instructions are: a. Conditional jump. b. Fused conditional jump. c. Unconditional jump. d. Indirect jump. e. Ret. f. Call. The new options for llvm-mc are: -x86-align-branch-boundary=NUM aligns branches within NUM byte boundary. -x86-align-branch=TYPE[+TYPE...] specifies types of branches to align. A new MCFragment type, MCBoundaryAlignFragment, is added, which may emit NOP to align the fused/unfused branch. alignBranchesBegin inserts MCBoundaryAlignFragment before instructions, alignBranchesEnd marks the end of the branch to be aligned, relaxBoundaryAlign grows or shrinks sizes of NOP to align the target branch. Nop padding is disabled when the instruction may be rewritten by the linker, such as TLS Call. Process Note: I am landing a patch by skan as it has been LGTMed, and continuing to iterate on the review is simply slowing us down at this point. We can and will continue to iterate in tree. Patch By: skan Differential Revision: https://reviews.llvm.org/D70157
2019-12-20 19:51:05 +01:00
case MCFragment::FT_BoundaryAlign: {
const auto *BF = cast<MCBoundaryAlignFragment>(this);
OS << "\n ";
OS << " BoundarySize:" << BF->getAlignment().value()
<< " LastFragment:" << BF->getLastFragment()
<< " Size:" << BF->getSize();
Align branches within 32-Byte boundary (NOP padding) WARNING: If you're looking at this patch because you're looking for a full performace mitigation of the Intel JCC Erratum, this is not it! This is a preliminary patch on the patch towards mitigating the performance regressions caused by Intel's microcode update for Jump Conditional Code Erratum. For context, see: https://www.intel.com/content/www/us/en/support/articles/000055650.html The patch adds the required assembler infrastructure and command line options needed to exercise the logic for INTERNAL TESTING. These are NOT public flags, and should not be used for anything other than LLVM's own testing/debugging purposes. They are likely to change both in spelling and meaning. WARNING: This patch is knowingly incorrect in some cornercases. We need, and do not yet provide, a mechanism to selective enable/disable the padding. Conversation on this will continue in parellel with work on extending this infrastructure to support prefix padding. The goal here is to have the assembler align specific instructions such that they neither cross or end at a 32 byte boundary. The impacted instructions are: a. Conditional jump. b. Fused conditional jump. c. Unconditional jump. d. Indirect jump. e. Ret. f. Call. The new options for llvm-mc are: -x86-align-branch-boundary=NUM aligns branches within NUM byte boundary. -x86-align-branch=TYPE[+TYPE...] specifies types of branches to align. A new MCFragment type, MCBoundaryAlignFragment, is added, which may emit NOP to align the fused/unfused branch. alignBranchesBegin inserts MCBoundaryAlignFragment before instructions, alignBranchesEnd marks the end of the branch to be aligned, relaxBoundaryAlign grows or shrinks sizes of NOP to align the target branch. Nop padding is disabled when the instruction may be rewritten by the linker, such as TLS Call. Process Note: I am landing a patch by skan as it has been LGTMed, and continuing to iterate on the review is simply slowing us down at this point. We can and will continue to iterate in tree. Patch By: skan Differential Revision: https://reviews.llvm.org/D70157
2019-12-20 19:51:05 +01:00
break;
}
case MCFragment::FT_SymbolId: {
const auto *F = cast<MCSymbolIdFragment>(this);
OS << "\n ";
OS << " Sym:" << F->getSymbol();
break;
}
case MCFragment::FT_CVInlineLines: {
const auto *F = cast<MCCVInlineLineTableFragment>(this);
OS << "\n ";
OS << " Sym:" << *F->getFnStartSym();
break;
}
case MCFragment::FT_CVDefRange: {
const auto *F = cast<MCCVDefRangeFragment>(this);
OS << "\n ";
for (std::pair<const MCSymbol *, const MCSymbol *> RangeStartEnd :
F->getRanges()) {
OS << " RangeStart:" << RangeStartEnd.first;
OS << " RangeEnd:" << RangeStartEnd.second;
}
break;
}
case MCFragment::FT_Dummy:
break;
}
OS << ">";
}
#endif