[MC] Use local MCSubtargetInfo in writeNops

On some architectures such as Arm and X86 the encoding for a nop may
change depending on the subtarget in operation at the time of
encoding. This change replaces the per module MCSubtargetInfo retained
by the targets AsmBackend in favour of passing through the local
MCSubtargetInfo in operation at the time.

On Arm using the architectural NOP instruction can have a performance
benefit on some implementations.

For Arm I've deleted the copy of the AsmBackend's MCSubtargetInfo to
limit the chances of this causing problems in the future. I've not
done this for other targets such as X86 as there is more frequent use
of the MCSubtargetInfo and it looks to be for stable properties that
we would not expect to vary per function.

This change required threading STI through MCNopsFragment and
MCBoundaryAlignFragment.

I've attempted to take into account the in tree experimental backends.

Differential Revision: https://reviews.llvm.org/D45962
This commit is contained in:
Peter Smith 2021-08-09 11:40:22 +01:00
parent 5e71839f77
commit e63455d5e0
37 changed files with 225 additions and 91 deletions

View File

@ -55,7 +55,8 @@ public:
/// Give the target a chance to manipulate state related to instruction
/// alignment (e.g. padding for optimization), instruction relaxablility, etc.
/// before and after actually emitting the instruction.
virtual void emitInstructionBegin(MCObjectStreamer &OS, const MCInst &Inst) {}
virtual void emitInstructionBegin(MCObjectStreamer &OS, const MCInst &Inst,
const MCSubtargetInfo &STI) {}
virtual void emitInstructionEnd(MCObjectStreamer &OS, const MCInst &Inst) {}
/// lifetime management
@ -185,13 +186,16 @@ public:
/// Returns the maximum size of a nop in bytes on this target.
///
virtual unsigned getMaximumNopSize() const { return 0; }
virtual unsigned getMaximumNopSize(const MCSubtargetInfo &STI) const {
return 0;
}
/// Write an (optimal) nop sequence of Count bytes to the given output. If the
/// target cannot generate such a sequence, it should return an error.
///
/// \return - True on success.
virtual bool writeNopData(raw_ostream &OS, uint64_t Count) const = 0;
virtual bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const = 0;
/// Give backend an opportunity to finish layout after relaxation
virtual void finishLayout(MCAssembler const &Asm,

View File

@ -377,17 +377,22 @@ class MCNopsFragment : public MCFragment {
/// Source location of the directive that this fragment was created for.
SMLoc Loc;
/// When emitting Nops some subtargets have specific nop encodings.
const MCSubtargetInfo &STI;
public:
MCNopsFragment(int64_t NumBytes, int64_t ControlledNopLength, SMLoc L,
MCSection *Sec = nullptr)
const MCSubtargetInfo &STI, MCSection *Sec = nullptr)
: MCFragment(FT_Nops, false, Sec), Size(NumBytes),
ControlledNopLength(ControlledNopLength), Loc(L) {}
ControlledNopLength(ControlledNopLength), Loc(L), STI(STI) {}
int64_t getNumBytes() const { return Size; }
int64_t getControlledNopLength() const { return ControlledNopLength; }
SMLoc getLoc() const { return Loc; }
const MCSubtargetInfo *getSubtargetInfo() const { return &STI; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Nops;
}
@ -580,10 +585,14 @@ class MCBoundaryAlignFragment : public MCFragment {
/// is not meaningful before that.
uint64_t Size = 0;
/// When emitting Nops some subtargets have specific nop encodings.
const MCSubtargetInfo &STI;
public:
MCBoundaryAlignFragment(Align AlignBoundary, MCSection *Sec = nullptr)
: MCFragment(FT_BoundaryAlign, false, Sec), AlignBoundary(AlignBoundary) {
}
MCBoundaryAlignFragment(Align AlignBoundary, const MCSubtargetInfo &STI,
MCSection *Sec = nullptr)
: MCFragment(FT_BoundaryAlign, false, Sec), AlignBoundary(AlignBoundary),
STI(STI) {}
uint64_t getSize() const { return Size; }
void setSize(uint64_t Value) { Size = Value; }
@ -597,6 +606,8 @@ public:
LastFragment = F;
}
const MCSubtargetInfo *getSubtargetInfo() const { return &STI; }
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_BoundaryAlign;
}

View File

@ -181,8 +181,8 @@ public:
SMLoc Loc = SMLoc()) override;
void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
SMLoc Loc = SMLoc()) override;
void emitNops(int64_t NumBytes, int64_t ControlledNopLength,
SMLoc Loc) override;
void emitNops(int64_t NumBytes, int64_t ControlledNopLength, SMLoc Loc,
const MCSubtargetInfo &STI) override;
void emitFileDirective(StringRef Filename) override;
void emitFileDirective(StringRef Filename, StringRef CompilerVerion,
StringRef TimeStamp, StringRef Description) override;

View File

@ -799,7 +799,7 @@ public:
SMLoc Loc = SMLoc());
virtual void emitNops(int64_t NumBytes, int64_t ControlledNopLength,
SMLoc Loc);
SMLoc Loc, const MCSubtargetInfo& STI);
/// Emit NumBytes worth of zeros.
/// This function properly handles data in virtual sections.

View File

@ -483,6 +483,7 @@ void MCAssembler::writeFragmentPadding(raw_ostream &OS,
"Writing bundle padding for a fragment without instructions");
unsigned TotalLength = BundlePadding + static_cast<unsigned>(FSize);
const MCSubtargetInfo *STI = EF.getSubtargetInfo();
if (EF.alignToBundleEnd() && TotalLength > getBundleAlignSize()) {
// If the padding itself crosses a bundle boundary, it must be emitted
// in 2 pieces, since even nop instructions must not cross boundaries.
@ -493,12 +494,12 @@ void MCAssembler::writeFragmentPadding(raw_ostream &OS,
// ----------------------------
// ^-------------------^ <- TotalLength
unsigned DistanceToBoundary = TotalLength - getBundleAlignSize();
if (!getBackend().writeNopData(OS, DistanceToBoundary))
if (!getBackend().writeNopData(OS, DistanceToBoundary, STI))
report_fatal_error("unable to write NOP sequence of " +
Twine(DistanceToBoundary) + " bytes");
BundlePadding -= DistanceToBoundary;
}
if (!getBackend().writeNopData(OS, BundlePadding))
if (!getBackend().writeNopData(OS, BundlePadding, STI))
report_fatal_error("unable to write NOP sequence of " +
Twine(BundlePadding) + " bytes");
}
@ -544,7 +545,7 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
// 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))
if (!Asm.getBackend().writeNopData(OS, Count, AF.getSubtargetInfo()))
report_fatal_error("unable to write nop sequence of " +
Twine(Count) + " bytes");
break;
@ -621,9 +622,11 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
case MCFragment::FT_Nops: {
++stats::EmittedNopsFragments;
const MCNopsFragment &NF = cast<MCNopsFragment>(F);
int64_t NumBytes = NF.getNumBytes();
int64_t ControlledNopLength = NF.getControlledNopLength();
int64_t MaximumNopLength = Asm.getBackend().getMaximumNopSize();
int64_t MaximumNopLength =
Asm.getBackend().getMaximumNopSize(*NF.getSubtargetInfo());
assert(NumBytes > 0 && "Expected positive NOPs fragment size");
assert(ControlledNopLength >= 0 && "Expected non-negative NOP size");
@ -647,7 +650,8 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
uint64_t NumBytesToEmit =
(uint64_t)std::min(NumBytes, ControlledNopLength);
assert(NumBytesToEmit && "try to emit empty NOP instruction");
if (!Asm.getBackend().writeNopData(OS, NumBytesToEmit)) {
if (!Asm.getBackend().writeNopData(OS, NumBytesToEmit,
NF.getSubtargetInfo())) {
report_fatal_error("unable to write nop sequence of the remaining " +
Twine(NumBytesToEmit) + " bytes");
break;
@ -664,7 +668,8 @@ static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
}
case MCFragment::FT_BoundaryAlign: {
if (!Asm.getBackend().writeNopData(OS, FragmentSize))
const MCBoundaryAlignFragment &BF = cast<MCBoundaryAlignFragment>(F);
if (!Asm.getBackend().writeNopData(OS, FragmentSize, BF.getSubtargetInfo()))
report_fatal_error("unable to write nop sequence of " +
Twine(FragmentSize) + " bytes");
break;

View File

@ -368,7 +368,7 @@ void MCObjectStreamer::emitInstruction(const MCInst &Inst,
"' cannot have instructions");
return;
}
getAssembler().getBackend().emitInstructionBegin(*this, Inst);
getAssembler().getBackend().emitInstructionBegin(*this, Inst, STI);
emitInstructionImpl(Inst, STI);
getAssembler().getBackend().emitInstructionEnd(*this, Inst);
}
@ -836,13 +836,14 @@ void MCObjectStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
}
void MCObjectStreamer::emitNops(int64_t NumBytes, int64_t ControlledNopLength,
SMLoc Loc) {
SMLoc Loc, const MCSubtargetInfo &STI) {
// Emit an NOP fragment.
MCDataFragment *DF = getOrCreateDataFragment();
flushPendingLabels(DF, DF->getContents().size());
assert(getCurrentSectionOnly() && "need a section");
insert(new MCNopsFragment(NumBytes, ControlledNopLength, Loc));
insert(new MCNopsFragment(NumBytes, ControlledNopLength, Loc, STI));
}
void MCObjectStreamer::emitFileDirective(StringRef Filename) {

View File

@ -220,7 +220,7 @@ void MCStreamer::emitFill(uint64_t NumBytes, uint8_t FillValue) {
}
void llvm::MCStreamer::emitNops(int64_t NumBytes, int64_t ControlledNopLen,
llvm::SMLoc) {}
llvm::SMLoc, const MCSubtargetInfo& STI) {}
/// The implementation in this class just redirects to emitFill.
void MCStreamer::emitZeros(uint64_t NumBytes) { emitFill(NumBytes, 0); }

View File

@ -92,7 +92,8 @@ public:
const MCAsmLayout &Layout) const override;
void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
unsigned getFixupKindContainereSizeInBytes(unsigned Kind) const;
@ -456,7 +457,8 @@ void AArch64AsmBackend::relaxInstruction(MCInst &Inst,
llvm_unreachable("AArch64AsmBackend::relaxInstruction() unimplemented");
}
bool AArch64AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool AArch64AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
// If the count is not 4-byte aligned, we must be writing data into the text
// section (otherwise we have unaligned instructions, and thus have far
// bigger problems), so just write zeros instead.

View File

@ -44,7 +44,8 @@ public:
const MCSubtargetInfo &STI) const override;
unsigned getMinimumNopSize() const override;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
};
@ -169,7 +170,8 @@ unsigned AMDGPUAsmBackend::getMinimumNopSize() const {
return 4;
}
bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool AMDGPUAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
// If the count is not 4-byte aligned, we must be writing data into the text
// section (otherwise we have unaligned instructions, and thus have far
// bigger problems), so just write zeros instead.

View File

@ -48,9 +48,10 @@ public:
} // end anonymous namespace
Optional<MCFixupKind> ARMAsmBackend::getFixupKind(StringRef Name) const {
if (!STI.getTargetTriple().isOSBinFormatELF())
return None;
return None;
}
Optional<MCFixupKind> ARMAsmBackendELF::getFixupKind(StringRef Name) const {
unsigned Type = llvm::StringSwitch<unsigned>(Name)
#define ELF_RELOC(X, Y) .Case(#X, Y)
#include "llvm/BinaryFormat/ELFRelocs/ARM.def"
@ -357,14 +358,15 @@ void ARMAsmBackend::relaxInstruction(MCInst &Inst,
Inst.setOpcode(RelaxedOp);
}
bool ARMAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool ARMAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
const uint16_t Thumb1_16bitNopEncoding = 0x46c0; // using MOV r8,r8
const uint16_t Thumb2_16bitNopEncoding = 0xbf00; // NOP
const uint32_t ARMv4_NopEncoding = 0xe1a00000; // using MOV r0,r0
const uint32_t ARMv6T2_NopEncoding = 0xe320f000; // NOP
if (isThumb()) {
const uint16_t nopEncoding =
hasNOP() ? Thumb2_16bitNopEncoding : Thumb1_16bitNopEncoding;
hasNOP(STI) ? Thumb2_16bitNopEncoding : Thumb1_16bitNopEncoding;
uint64_t NumNops = Count / 2;
for (uint64_t i = 0; i != NumNops; ++i)
support::endian::write(OS, nopEncoding, Endian);
@ -374,7 +376,7 @@ bool ARMAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
}
// ARM mode
const uint32_t nopEncoding =
hasNOP() ? ARMv6T2_NopEncoding : ARMv4_NopEncoding;
hasNOP(STI) ? ARMv6T2_NopEncoding : ARMv4_NopEncoding;
uint64_t NumNops = Count / 4;
for (uint64_t i = 0; i != NumNops; ++i)
support::endian::write(OS, nopEncoding, Endian);
@ -1300,11 +1302,12 @@ static MCAsmBackend *createARMAsmBackend(const Target &T,
return new ARMAsmBackendDarwin(T, STI, MRI);
case Triple::COFF:
assert(TheTriple.isOSWindows() && "non-Windows ARM COFF is not supported");
return new ARMAsmBackendWinCOFF(T, STI);
return new ARMAsmBackendWinCOFF(T, STI.getTargetTriple().isThumb());
case Triple::ELF:
assert(TheTriple.isOSBinFormatELF() && "using ELF for non-ELF target");
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS());
return new ARMAsmBackendELF(T, STI, OSABI, Endian);
return new ARMAsmBackendELF(T, STI.getTargetTriple().isThumb(), OSABI,
Endian);
}
}

View File

@ -18,24 +18,18 @@
namespace llvm {
class ARMAsmBackend : public MCAsmBackend {
// The STI from the target triple the MCAsmBackend was instantiated with
// note that MCFragments may have a different local STI that should be
// used in preference.
const MCSubtargetInfo &STI;
bool isThumbMode; // Currently emitting Thumb code.
public:
ARMAsmBackend(const Target &T, const MCSubtargetInfo &STI,
support::endianness Endian)
: MCAsmBackend(Endian), STI(STI),
isThumbMode(STI.getTargetTriple().isThumb()) {}
ARMAsmBackend(const Target &T, bool isThumb, support::endianness Endian)
: MCAsmBackend(Endian), isThumbMode(isThumb) {}
unsigned getNumFixupKinds() const override {
return ARM::NumTargetFixupKinds;
}
// FIXME: this should be calculated per fragment as the STI may be
// different.
bool hasNOP() const { return STI.getFeatureBits()[ARM::HasV6T2Ops]; }
bool hasNOP(const MCSubtargetInfo *STI) const {
return STI->getFeatureBits()[ARM::HasV6T2Ops];
}
Optional<MCFixupKind> getFixupKind(StringRef Name) const override;
@ -69,7 +63,8 @@ public:
void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
void handleAssemblerFlag(MCAssemblerFlag Flag) override;

View File

@ -21,8 +21,8 @@ public:
const MachO::CPUSubTypeARM Subtype;
ARMAsmBackendDarwin(const Target &T, const MCSubtargetInfo &STI,
const MCRegisterInfo &MRI)
: ARMAsmBackend(T, STI, support::little), MRI(MRI),
TT(STI.getTargetTriple()),
: ARMAsmBackend(T, STI.getTargetTriple().isThumb(), support::little),
MRI(MRI), TT(STI.getTargetTriple()),
Subtype((MachO::CPUSubTypeARM)cantFail(
MachO::getCPUSubType(STI.getTargetTriple()))) {}

View File

@ -19,14 +19,16 @@ namespace {
class ARMAsmBackendELF : public ARMAsmBackend {
public:
uint8_t OSABI;
ARMAsmBackendELF(const Target &T, const MCSubtargetInfo &STI, uint8_t OSABI,
ARMAsmBackendELF(const Target &T, bool isThumb, uint8_t OSABI,
support::endianness Endian)
: ARMAsmBackend(T, STI, Endian), OSABI(OSABI) {}
: ARMAsmBackend(T, isThumb, Endian), OSABI(OSABI) {}
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
return createARMELFObjectWriter(OSABI);
}
Optional<MCFixupKind> getFixupKind(StringRef Name) const override;
};
}

View File

@ -16,8 +16,8 @@ using namespace llvm;
namespace {
class ARMAsmBackendWinCOFF : public ARMAsmBackend {
public:
ARMAsmBackendWinCOFF(const Target &T, const MCSubtargetInfo &STI)
: ARMAsmBackend(T, STI, support::little) {}
ARMAsmBackendWinCOFF(const Target &T, bool isThumb)
: ARMAsmBackend(T, isThumb, support::little) {}
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
return createARMWinCOFFObjectWriter();

View File

@ -458,7 +458,8 @@ MCFixupKindInfo const &AVRAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
return Infos[Kind - FirstTargetFixupKind];
}
bool AVRAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool AVRAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
// If the count is not 2-byte aligned, we must be writing data into the text
// section (otherwise we have unaligned instructions, and thus have far
// bigger problems), so just write zeros instead.

View File

@ -55,7 +55,8 @@ public:
return false;
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target) override;

View File

@ -43,12 +43,14 @@ public:
unsigned getNumFixupKinds() const override { return 1; }
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
};
} // end anonymous namespace
bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
if ((Count % 8) != 0)
return false;

View File

@ -145,7 +145,8 @@ void CSKYAsmBackend::relaxInstruction(MCInst &Inst,
llvm_unreachable("CSKYAsmBackend::relaxInstruction() unimplemented");
}
bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool CSKYAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
if (Count % 2)
return false;

View File

@ -39,7 +39,8 @@ public:
void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override;

View File

@ -686,10 +686,11 @@ public:
assert(Update && "Didn't find relaxation target");
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override {
static const uint32_t Nopcode = 0x7f000000, // Hard-coded NOP.
ParseIn = 0x00004000, // In packet parse-bits.
ParseEnd = 0x0000c000; // End of packet parse-bits.
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override {
static const uint32_t Nopcode = 0x7f000000, // Hard-coded NOP.
ParseIn = 0x00004000, // In packet parse-bits.
ParseEnd = 0x0000c000; // End of packet parse-bits.
while (Count % HEXAGON_INSTR_SIZE) {
LLVM_DEBUG(dbgs() << "Alignment not a multiple of the instruction size:"

View File

@ -69,10 +69,12 @@ public:
return Lanai::NumTargetFixupKinds;
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
};
bool LanaiAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool LanaiAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
if ((Count % 4) != 0)
return false;

View File

@ -82,7 +82,8 @@ public:
/// Write a sequence of optimal nops to the output, covering \p Count bytes.
/// \return - true on success, false on failure
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
};
} // end anonymous namespace
@ -200,7 +201,8 @@ void M68kAsmBackend::relaxInstruction(MCInst &Inst,
Inst.setOpcode(RelaxedOp);
}
bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool M68kAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
// Cannot emit NOP with size being not multiple of 16 bits.
if (Count % 2 != 0)
return false;

View File

@ -90,7 +90,8 @@ public:
return Infos[Kind - FirstTargetFixupKind];
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
};
uint64_t MSP430AsmBackend::adjustFixupValue(const MCFixup &Fixup,
@ -147,7 +148,8 @@ void MSP430AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
}
}
bool MSP430AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool MSP430AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
if ((Count % 2) != 0)
return false;

View File

@ -518,7 +518,8 @@ getFixupKindInfo(MCFixupKind Kind) const {
/// it should return an error.
///
/// \return - True on success.
bool MipsAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool MipsAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
// Check for a less than instruction size number of bytes
// FIXME: 16 bit instructions are not handled yet here.
// We shouldn't be using a hard coded number for instruction size.

View File

@ -63,7 +63,8 @@ public:
return false;
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
bool shouldForceRelocation(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target) override;

View File

@ -196,7 +196,8 @@ public:
llvm_unreachable("relaxInstruction() unimplemented");
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override {
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override {
uint64_t NumNops = Count / 4;
for (uint64_t i = 0; i != NumNops; ++i)
support::endian::write<uint32_t>(OS, 0x60000000, Endian);

View File

@ -352,8 +352,9 @@ bool RISCVAsmBackend::mayNeedRelaxation(const MCInst &Inst,
return getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode();
}
bool RISCVAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool HasStdExtC = STI.getFeatureBits()[RISCV::FeatureStdExtC];
bool RISCVAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
bool HasStdExtC = STI->getFeatureBits()[RISCV::FeatureStdExtC];
unsigned MinNopLen = HasStdExtC ? 2 : 4;
if ((Count % MinNopLen) != 0)

View File

@ -99,7 +99,8 @@ public:
bool relaxDwarfCFA(MCDwarfCallFrameFragment &DF, MCAsmLayout &Layout,
bool &WasRelaxed) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
const MCTargetOptions &getTargetOptions() const { return TargetOptions; }
RISCVABI::ABI getTargetABI() const { return TargetABI; }

View File

@ -274,7 +274,8 @@ namespace {
llvm_unreachable("relaxInstruction() unimplemented");
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override {
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override {
// Cannot emit NOP with size not multiple of 32 bits.
if (Count % 4 != 0)
return false;

View File

@ -63,7 +63,8 @@ public:
const MCAsmLayout &Layout) const override {
return false;
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override {
return createSystemZObjectWriter(OSABI);
@ -142,7 +143,8 @@ void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm,
}
}
bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool SystemZMCAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
for (uint64_t I = 0; I != Count; ++I)
OS << '\x7';
return true;

View File

@ -164,7 +164,8 @@ public:
llvm_unreachable("relaxInstruction() should not be called");
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override {
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override {
if ((Count % 8) != 0)
return false;

View File

@ -59,7 +59,8 @@ public:
return false;
}
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
};
const MCFixupKindInfo &
@ -83,8 +84,8 @@ WebAssemblyAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
return Infos[Kind - FirstTargetFixupKind];
}
bool WebAssemblyAsmBackend::writeNopData(raw_ostream &OS,
uint64_t Count) const {
bool WebAssemblyAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
for (uint64_t I = 0; I < Count; ++I)
OS << char(WebAssembly::Nop);

View File

@ -4855,7 +4855,7 @@ bool X86AsmParser::parseDirectiveArch() {
bool X86AsmParser::parseDirectiveNops(SMLoc L) {
int64_t NumBytes = 0, Control = 0;
SMLoc NumBytesLoc, ControlLoc;
const MCSubtargetInfo STI = getSTI();
const MCSubtargetInfo& STI = getSTI();
NumBytesLoc = getTok().getLoc();
if (getParser().checkForValidSection() ||
getParser().parseAbsoluteExpression(NumBytes))
@ -4881,7 +4881,7 @@ bool X86AsmParser::parseDirectiveNops(SMLoc L) {
}
/// Emit nops
getParser().getStreamer().emitNops(NumBytes, Control, L);
getParser().getStreamer().emitNops(NumBytes, Control, L, STI);
return false;
}

View File

@ -166,7 +166,8 @@ public:
bool allowAutoPadding() const override;
bool allowEnhancedRelaxation() const override;
void emitInstructionBegin(MCObjectStreamer &OS, const MCInst &Inst) override;
void emitInstructionBegin(MCObjectStreamer &OS, const MCInst &Inst,
const MCSubtargetInfo &STI) override;
void emitInstructionEnd(MCObjectStreamer &OS, const MCInst &Inst) override;
unsigned getNumFixupKinds() const override {
@ -207,9 +208,10 @@ public:
void finishLayout(MCAssembler const &Asm, MCAsmLayout &Layout) const override;
unsigned getMaximumNopSize() const override;
unsigned getMaximumNopSize(const MCSubtargetInfo &STI) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const override;
};
} // end anonymous namespace
@ -598,7 +600,7 @@ bool X86AsmBackend::needAlign(const MCInst &Inst) const {
/// Insert BoundaryAlignFragment before instructions to align branches.
void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
const MCInst &Inst) {
const MCInst &Inst, const MCSubtargetInfo &STI) {
CanPadInst = canPadInst(Inst, OS);
if (!canPadBranches(OS))
@ -637,7 +639,7 @@ void X86AsmBackend::emitInstructionBegin(MCObjectStreamer &OS,
isFirstMacroFusibleInst(Inst, *MCII))) {
// If we meet a unfused branch or the first instuction in a fusiable pair,
// insert a BoundaryAlign fragment.
OS.insert(PendingBA = new MCBoundaryAlignFragment(AlignBoundary));
OS.insert(PendingBA = new MCBoundaryAlignFragment(AlignBoundary, STI));
}
}
@ -1081,7 +1083,7 @@ void X86AsmBackend::finishLayout(MCAssembler const &Asm,
}
}
unsigned X86AsmBackend::getMaximumNopSize() const {
unsigned X86AsmBackend::getMaximumNopSize(const MCSubtargetInfo &STI) const {
if (STI.hasFeature(X86::Mode16Bit))
return 4;
if (!STI.hasFeature(X86::FeatureNOPL) && !STI.hasFeature(X86::Mode64Bit))
@ -1101,7 +1103,8 @@ unsigned X86AsmBackend::getMaximumNopSize() const {
/// Write a sequence of optimal nops to the output, covering \p Count
/// bytes.
/// \return - true on success, false on failure
bool X86AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
bool X86AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count,
const MCSubtargetInfo *STI) const {
static const char Nops32Bit[10][11] = {
// nop
"\x90",
@ -1138,9 +1141,9 @@ bool X86AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
};
const char(*Nops)[11] =
STI.getFeatureBits()[X86::Mode16Bit] ? Nops16Bit : Nops32Bit;
STI->getFeatureBits()[X86::Mode16Bit] ? Nops16Bit : Nops32Bit;
uint64_t MaxNopLength = (uint64_t)getMaximumNopSize();
uint64_t MaxNopLength = (uint64_t)getMaximumNopSize(*STI);
// Emit as many MaxNopLength NOPs as needed, then emit a NOP of the remaining
// length.

View File

@ -0,0 +1,39 @@
; RUN: llc -mtriple=arm-linux-gnueabihf -filetype=obj <%s | llvm-objdump --triple=armv7 --no-show-raw-insn -d - | FileCheck %s
;; Expect architectural nop to be used between func2 and func3 but not func1
;; and func2 due to lack of subtarget support in func2.
define i32 @func1() #0 align 16 {
entry:
ret i32 0
}
define i32 @func2() #1 align 16 {
entry:
ret i32 0
}
define i32 @func3() #0 align 16 {
entry:
ret i32 0
}
attributes #0 = { "target-cpu"="generic" "target-features"="+armv7-a,+dsp,+neon,+vfp3,-thumb-mode" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "target-cpu"="arm7tdmi" "target-features"="+armv4t" "use-soft-float"="true" }
; CHECK: 00000000 <func1>:
; CHECK-NEXT: 0: mov r0, #0
; CHECK-NEXT: 4: bx lr
; CHECK-NEXT: 8: mov r0, r0
; CHECK-NEXT: c: mov r0, r0
; CHECK: 00000010 <func2>:
; CHECK-NEXT: 10: mov r0, #0
; CHECK-NEXT: 14: bx lr
; CHECK-NEXT: 18: nop
; CHECK-NEXT: 1c: nop
; CHECK: 00000020 <func3>:
; CHECK-NEXT: 20: mov r0, #0
; CHECK-NEXT: 24: bx lr

View File

@ -0,0 +1,44 @@
// RUN: llvm-mc %s --triple=arm-linux-gnueabihf -filetype=obj | llvm-objdump --no-show-raw-insn --triple=armv7 -d - | FileCheck %s
// Check that the architectural nop is only produced for subtargets that
// support it. This includes nop padding for alignment.
.syntax unified
.arch armv6
foo:
mov r1, r0
nop
.p2align 4
bx lr
.arch armv7-a
bar:
mov r1, r0
nop
.p2align 4
bx lr
.arch armv4t
baz:
mov r1, r0
nop
.p2align 4
bx lr
// CHECK: 00000000 <foo>:
// CHECK-NEXT: 0: mov r1, r0
// CHECK-NEXT: 4: mov r0, r0
// CHECK-NEXT: 8: mov r0, r0
// CHECK-NEXT: c: mov r0, r0
// CHECK-NEXT: 10: bx lr
// CHECK: 00000014 <bar>:
// CHECK-NEXT: 14: mov r1, r0
// CHECK-NEXT: 18: nop
// CHECK-NEXT: 1c: nop
// CHECK-NEXT: 20: bx lr
// CHECK: 00000024 <baz>:
// CHECK-NEXT: 24: mov r1, r0
// CHECK-NEXT: 28: mov r0, r0
// CHECK-NEXT: 2c: mov r0, r0
// CHECK-NEXT: 30: bx lr

View File

@ -135,7 +135,7 @@ SmallString<0> DWARFExpressionCopyBytesTest::emitObjFile(StringRef ExprBytes) {
C.Streamer->emitCFIStartProc(true);
auto Str = EncodeDefCfaExpr(ExprBytes);
C.Streamer->emitCFIEscape(Str);
C.Streamer->emitNops(4, 1, SMLoc());
C.Streamer->emitNops(4, 1, SMLoc(), *STI);
C.Streamer->emitCFIEndProc();
C.Streamer->Finish();
return Storage;