Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions llvm/include/llvm/MC/MCAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@

namespace llvm {

class MCAlignFragment;
class MCFragment;
class MCLEBFragment;
class MCSymbol;
class MCAssembler;
class MCContext;
Expand Down Expand Up @@ -108,15 +106,14 @@ class LLVM_ABI MCAsmBackend {
/// Hook to check if extra nop bytes must be inserted for alignment directive.
/// For some targets this may be necessary in order to support linker
/// relaxation. The number of bytes to insert are returned in Size.
virtual bool shouldInsertExtraNopBytesForCodeAlign(const MCAlignFragment &AF,
virtual bool shouldInsertExtraNopBytesForCodeAlign(const MCFragment &AF,
unsigned &Size) {
return false;
}

/// Hook which indicates if the target requires a fixup to be generated when
/// handling an align directive in an executable section
virtual bool shouldInsertFixupForCodeAlign(MCAssembler &Asm,
MCAlignFragment &AF) {
virtual bool shouldInsertFixupForCodeAlign(MCAssembler &Asm, MCFragment &AF) {
return false;
}

Expand Down
96 changes: 50 additions & 46 deletions llvm/include/llvm/MC/MCSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,19 @@ class MCFragment {
uint32_t OperandStart;
uint32_t OperandSize;
} relax;
struct {
// The alignment to ensure, in bytes.
Align Alignment;
// The size of the integer (in bytes) of \p Value.
uint8_t FillLen;
// If true, fill with target-specific nop instructions.
bool EmitNops;
// The maximum number of bytes to emit; if the alignment
// cannot be satisfied in this width then this fragment is ignored.
unsigned MaxBytesToEmit;
// Value to use for filling padding bytes.
int64_t Fill;
} align;
struct {
// True if this is a sleb128, false if uleb128.
bool IsSigned;
Expand Down Expand Up @@ -441,6 +454,43 @@ class MCFragment {
llvm::copy(Inst, S.begin() + u.relax.OperandStart);
}

//== FT_Align functions
void makeAlign(Align Alignment, int64_t Fill, uint8_t FillLen,
unsigned MaxBytesToEmit) {
Kind = FT_Align;
u.align.EmitNops = false;
u.align.Alignment = Alignment;
u.align.Fill = Fill;
u.align.FillLen = FillLen;
u.align.MaxBytesToEmit = MaxBytesToEmit;
}

Align getAlignment() const {
assert(Kind == FT_Align);
return u.align.Alignment;
}
int64_t getAlignFill() const {
assert(Kind == FT_Align);
return u.align.Fill;
}
uint8_t getAlignFillLen() const {
assert(Kind == FT_Align);
return u.align.FillLen;
}
unsigned getAlignMaxBytesToEmit() const {
assert(Kind == FT_Align);
return u.align.MaxBytesToEmit;
}
bool hasAlignEmitNops() const {
assert(Kind == FT_Align);
return u.align.EmitNops;
}
void setAlignEmitNops(bool Value, const MCSubtargetInfo *STI) {
assert(Kind == FT_Align);
u.align.EmitNops = Value;
this->STI = STI;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert that STI didn't change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately we cannot.

The STI is not useful for FT_Data fragments.

  • The section initial fragment has no STI. We should allow the subsequent FT_Align (e.g. text section's implicit alignment) to be merged into it as a small optimization.
  • While emitInstToData has a STI, and it passes the STI to the created FT_Data fragment, the fragment's STI is not used.

https://reviews.llvm.org/D44928 added getSubtargetInfo to MCEncodedFragmentWithFixups (now replaced by MCFragment). I think we can remove STI from emitInstToData first (check-llvm-mc passes).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Created #149471

}

//== FT_LEB functions
const MCExpr &getLEBValue() const {
assert(Kind == FT_LEB);
Expand Down Expand Up @@ -486,52 +536,6 @@ class MCEncodedFragment : public MCFragment {
: MCFragment(FType, HasInstructions) {}
};

class MCAlignFragment : public MCFragment {
/// Flag to indicate that (optimal) NOPs should be emitted instead
/// of using the provided value. The exact interpretation of this flag is
/// target dependent.
bool EmitNops : 1;

/// The alignment to ensure, in bytes.
Align Alignment;

/// The size of the integer (in bytes) of \p Value.
uint8_t FillLen;

/// The maximum number of bytes to emit; if the alignment
/// cannot be satisfied in this width then this fragment is ignored.
unsigned MaxBytesToEmit;

/// Value to use for filling padding bytes.
int64_t Fill;

/// When emitting Nops some subtargets have specific nop encodings.
const MCSubtargetInfo *STI = nullptr;

public:
MCAlignFragment(Align Alignment, int64_t Fill, uint8_t FillLen,
unsigned MaxBytesToEmit)
: MCFragment(FT_Align, false), EmitNops(false), Alignment(Alignment),
FillLen(FillLen), MaxBytesToEmit(MaxBytesToEmit), Fill(Fill) {}

Align getAlignment() const { return Alignment; }
int64_t getFill() const { return Fill; }
uint8_t getFillLen() const { return FillLen; }
unsigned getMaxBytesToEmit() const { return MaxBytesToEmit; }

bool hasEmitNops() const { return EmitNops; }
void setEmitNops(bool Value, const MCSubtargetInfo *STI) {
EmitNops = Value;
this->STI = STI;
}

const MCSubtargetInfo *getSubtargetInfo() const { return STI; }

static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Align;
}
};

class MCFillFragment : public MCFragment {
uint8_t ValueSize;
/// Value to use for filling bytes.
Expand Down
136 changes: 66 additions & 70 deletions llvm/lib/MC/MCAssembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,25 +228,24 @@ uint64_t MCAssembler::computeFragmentSize(const MCFragment &F) const {
return 4;

case MCFragment::FT_Align: {
const MCAlignFragment &AF = cast<MCAlignFragment>(F);
unsigned Offset = getFragmentOffset(AF);
unsigned Size = offsetToAlignment(Offset, AF.getAlignment());
unsigned Offset = F.Offset + F.getFixedSize();
unsigned Size = offsetToAlignment(Offset, F.getAlignment());

// Insert extra Nops for code alignment if the target define
// shouldInsertExtraNopBytesForCodeAlign target hook.
if (AF.getParent()->useCodeAlign() && AF.hasEmitNops() &&
getBackend().shouldInsertExtraNopBytesForCodeAlign(AF, Size))
return Size;
if (F.getParent()->useCodeAlign() && F.hasAlignEmitNops() &&
getBackend().shouldInsertExtraNopBytesForCodeAlign(F, Size))
return F.getFixedSize() + Size;

// If we are padding with nops, force the padding to be larger than the
// minimum nop size.
if (Size > 0 && AF.hasEmitNops()) {
if (Size > 0 && F.hasAlignEmitNops()) {
while (Size % getBackend().getMinimumNopSize())
Size += AF.getAlignment().value();
Size += F.getAlignment().value();
}
if (Size > AF.getMaxBytesToEmit())
return 0;
return Size;
if (Size > F.getAlignMaxBytesToEmit())
Size = 0;
return F.getFixedSize() + Size;
}

case MCFragment::FT_Org: {
Expand Down Expand Up @@ -416,6 +415,7 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
switch (F.getKind()) {
case MCFragment::FT_Data:
case MCFragment::FT_Relaxable:
case MCFragment::FT_Align:
case MCFragment::FT_LEB:
case MCFragment::FT_Dwarf:
case MCFragment::FT_DwarfFrame:
Expand All @@ -429,48 +429,46 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
const auto &EF = cast<MCFragment>(F);
OS << StringRef(EF.getContents().data(), EF.getContents().size());
OS << StringRef(EF.getVarContents().data(), EF.getVarContents().size());
break;
}
case MCFragment::FT_Align: {
++stats::EmittedAlignFragments;
const MCAlignFragment &AF = cast<MCAlignFragment>(F);
assert(AF.getFillLen() && "Invalid virtual align in concrete fragment!");

uint64_t Count = FragmentSize / AF.getFillLen();
assert(FragmentSize % AF.getFillLen() == 0 &&
"computeFragmentSize computed size is incorrect");

// See if we are aligning with nops, and if so do that first to try to fill
// the Count bytes. Then if that did not fill any bytes or there are any
// bytes left to fill use the Value and ValueSize to fill the rest.
// If we are aligning with nops, ask that target to emit the right data.
if (AF.hasEmitNops()) {
if (!Asm.getBackend().writeNopData(OS, Count, AF.getSubtargetInfo()))
report_fatal_error("unable to write nop sequence of " +
Twine(Count) + " bytes");
break;
}

// Otherwise, write out in multiples of the value size.
for (uint64_t i = 0; i != Count; ++i) {
switch (AF.getFillLen()) {
default: llvm_unreachable("Invalid size!");
case 1:
OS << char(AF.getFill());
break;
case 2:
support::endian::write<uint16_t>(OS, AF.getFill(), Endian);
break;
case 4:
support::endian::write<uint32_t>(OS, AF.getFill(), Endian);
break;
case 8:
support::endian::write<uint64_t>(OS, AF.getFill(), Endian);
break;
if (F.getKind() == MCFragment::FT_Align) {
++stats::EmittedAlignFragments;
assert(F.getAlignFillLen() &&
"Invalid virtual align in concrete fragment!");

uint64_t Count = (FragmentSize - F.getFixedSize()) / F.getAlignFillLen();
assert((FragmentSize - F.getFixedSize()) % F.getAlignFillLen() == 0 &&
"computeFragmentSize computed size is incorrect");

// See if we are aligning with nops, and if so do that first to try to
// fill the Count bytes. Then if that did not fill any bytes or there are
// any bytes left to fill use the Value and ValueSize to fill the rest. If
// we are aligning with nops, ask that target to emit the right data.
if (F.hasAlignEmitNops()) {
if (!Asm.getBackend().writeNopData(OS, Count, F.getSubtargetInfo()))
report_fatal_error("unable to write nop sequence of " + Twine(Count) +
" bytes");
} else {
// Otherwise, write out in multiples of the value size.
for (uint64_t i = 0; i != Count; ++i) {
switch (F.getAlignFillLen()) {
default:
llvm_unreachable("Invalid size!");
case 1:
OS << char(F.getAlignFill());
break;
case 2:
support::endian::write<uint16_t>(OS, F.getAlignFill(), Endian);
break;
case 4:
support::endian::write<uint32_t>(OS, F.getAlignFill(), Endian);
break;
case 8:
support::endian::write<uint64_t>(OS, F.getAlignFill(), Endian);
break;
}
}
}
}
break;
}
} break;

case MCFragment::FT_Fill: {
++stats::EmittedFillFragments;
Expand Down Expand Up @@ -608,9 +606,7 @@ void MCAssembler::writeSectionData(raw_ostream &OS,
case MCFragment::FT_Align:
// Check that we aren't trying to write a non-zero value into a virtual
// section.
assert((cast<MCAlignFragment>(F).getFillLen() == 0 ||
cast<MCAlignFragment>(F).getFill() == 0) &&
"Invalid align in virtual section!");
assert(F.getAlignFill() == 0 && "Invalid align in virtual section!");
break;
case MCFragment::FT_Fill:
assert((cast<MCFillFragment>(F).getValue() == 0) &&
Expand Down Expand Up @@ -699,17 +695,22 @@ void MCAssembler::layout() {
for (MCSection &Sec : *this) {
for (MCFragment &F : Sec) {
// Process fragments with fixups here.
if (F.isEncoded()) {
auto Contents = F.getContents();
for (MCFixup &Fixup : F.getFixups()) {
uint64_t FixedValue;
MCValue Target;
evaluateFixup(F, Fixup, Target, FixedValue,
/*RecordReloc=*/true, Contents);
}
// In the variable part, fixup offsets are relative to the fixed part's
// start. Extend the variable contents to the left to account for the
// fixed part size.
auto Contents = F.getContents();
for (MCFixup &Fixup : F.getFixups()) {
uint64_t FixedValue;
MCValue Target;
evaluateFixup(F, Fixup, Target, FixedValue,
/*RecordReloc=*/true, Contents);
}
if (F.getKind() == MCFragment::FT_Align) {
// For RISC-V linker relaxation, an alignment relocation might be
// needed.
if (F.hasAlignEmitNops())
getBackend().shouldInsertFixupForCodeAlign(*this, F);
} else if (F.getVarFixups().size()) {
// In the variable part, fixup offsets are relative to the fixed
// part's start. Extend the variable contents to the left to account
// for the fixed part size.
Contents = MutableArrayRef(F.getParent()->ContentStorage)
.slice(F.VarContentStart - Contents.size(), F.getSize());
for (MCFixup &Fixup : F.getVarFixups()) {
Expand All @@ -718,11 +719,6 @@ void MCAssembler::layout() {
evaluateFixup(F, Fixup, Target, FixedValue,
/*RecordReloc=*/true, Contents);
}
} else if (auto *AF = dyn_cast<MCAlignFragment>(&F)) {
// For RISC-V linker relaxation, an alignment relocation might be
// needed.
if (AF->hasEmitNops())
getBackend().shouldInsertFixupForCodeAlign(*this, *AF);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/MC/MCExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -379,11 +379,11 @@ static void attemptToFoldSymbolOffsetDifference(const MCAssembler *Asm,
// After layout, during relocation generation, it can be treated as a
// data fragment.
Displacement += F->getSize();
} else if (auto *AF = dyn_cast<MCAlignFragment>(F);
AF && Layout && AF->hasEmitNops() &&
} else if (F->getKind() == MCFragment::FT_Align && Layout &&
F->hasAlignEmitNops() &&
!Asm->getBackend().shouldInsertExtraNopBytesForCodeAlign(
*AF, Count)) {
Displacement += Asm->computeFragmentSize(*AF);
*F, Count)) {
Displacement += Asm->computeFragmentSize(*F);
} else if (auto *FF = dyn_cast<MCFillFragment>(F);
FF && FF->getNumValues().evaluateAsAbsolute(Num)) {
Displacement += Num * FF->getValueSize();
Expand Down
17 changes: 8 additions & 9 deletions llvm/lib/MC/MCFragment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,9 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
};

switch (getKind()) {
case MCFragment::FT_Align: {
const auto *AF = cast<MCAlignFragment>(this);
OS << " Align:" << AF->getAlignment().value() << " Fill:" << AF->getFill()
<< " FillLen:" << unsigned(AF->getFillLen())
<< " MaxBytesToEmit:" << AF->getMaxBytesToEmit();
if (AF->hasEmitNops())
OS << " Nops";
break;
}
case MCFragment::FT_Data:
case MCFragment::FT_Relaxable:
case MCFragment::FT_Align:
case MCFragment::FT_LEB:
case MCFragment::FT_Dwarf:
case MCFragment::FT_DwarfFrame: {
Expand Down Expand Up @@ -112,6 +104,13 @@ LLVM_DUMP_METHOD void MCFragment::dump() const {
OS << ' ';
getInst().dump_pretty(OS);
break;
case MCFragment::FT_Align:
OS << "\n Align:" << getAlignment().value() << " Fill:" << getAlignFill()
<< " FillLen:" << unsigned(getAlignFillLen())
<< " MaxBytesToEmit:" << getAlignMaxBytesToEmit();
if (hasAlignEmitNops())
OS << " Nops";
break;
case MCFragment::FT_LEB: {
OS << " Value:";
getLEBValue().print(OS, nullptr);
Expand Down
Loading
Loading