Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
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
3 changes: 0 additions & 3 deletions llvm/include/llvm/MC/MCObjectStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,6 @@ class MCObjectStreamer : public MCStreamer {

protected:
bool changeSectionImpl(MCSection *Section, uint32_t Subsection);
MCAlignFragment *createAlignFragment(Align Alignment, int64_t Fill,
uint8_t FillLen,
unsigned MaxBytesToEmit);

public:
void visitUsedSymbol(const MCSymbol &Sym) override;
Expand Down
92 changes: 46 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 @@ -283,6 +296,7 @@ class MCFragment {
return false;
case MCFragment::FT_Relaxable:
case MCFragment::FT_Data:
case MCFragment::FT_Align:
case MCFragment::FT_Dwarf:
case MCFragment::FT_DwarfFrame:
case MCFragment::FT_LEB:
Expand Down Expand Up @@ -440,6 +454,38 @@ 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;
}

//== FT_LEB functions
void makeLEB(bool IsSigned, const MCExpr *Value) {
assert(Kind == FT_Data);
Expand Down Expand Up @@ -487,52 +533,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
142 changes: 67 additions & 75 deletions llvm/lib/MC/MCAssembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,25 +227,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 @@ -419,6 +418,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 @@ -431,48 +431,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 @@ -610,9 +608,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 @@ -722,34 +718,30 @@ 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()) {
auto Contents = F.getContents();
for (MCFixup &Fixup : F.getFixups()) {
uint64_t FixedValue;
MCValue Target;
evaluateFixup(F, Fixup, Target, FixedValue,
/*RecordReloc=*/true, Contents);
}
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()) {
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 VarFixups = F.getVarFixups();
if (VarFixups.size()) {
Contents =
MutableArrayRef(F.getParent()->ContentStorage)
.slice(F.VarContentStart - Contents.size(), F.getSize());
for (MCFixup &Fixup : VarFixups) {
uint64_t FixedValue;
MCValue Target;
evaluateFixup(F, Fixup, Target, FixedValue,
/*RecordReloc=*/true, Contents);
}
}
} else if (auto *AF = dyn_cast<MCAlignFragment>(&F)) {
} else if (F.getKind() == MCFragment::FT_Align) {
// For RISC-V linker relaxation, an alignment relocation might be
// needed.
if (AF->hasEmitNops())
getBackend().shouldInsertFixupForCodeAlign(*this, *AF);
if (F.hasAlignEmitNops())
getBackend().shouldInsertFixupForCodeAlign(*this, F);
}
}
}
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
Loading