forked from OSchip/llvm-project
[MC] Pass MCSubtargetInfo to fixupNeedsRelaxation and applyFixup
On targets like Arm some relaxations may only be performed when certain architectural features are available. As functions can be compiled with differing levels of architectural support we must make a judgement on whether we can relax based on the MCSubtargetInfo for the function. This change passes through the MCSubtargetInfo for the function to fixupNeedsRelaxation so that the decision on whether to relax can be made per function. In this patch, only the ARM backend makes use of this information. We must also pass the MCSubtargetInfo to applyFixup because some fixups skip error checking on the assumption that relaxation has occurred, to prevent code-generation errors applyFixup must see the same MCSubtargetInfo as fixupNeedsRelaxation. Differential Revision: https://reviews.llvm.org/D44928 llvm-svn: 334078
This commit is contained in:
parent
b7c3745006
commit
57f661bd7d
|
@ -92,9 +92,12 @@ public:
|
||||||
/// the offset specified by the fixup and following the fixup kind as
|
/// the offset specified by the fixup and following the fixup kind as
|
||||||
/// appropriate. Errors (such as an out of range fixup value) should be
|
/// appropriate. Errors (such as an out of range fixup value) should be
|
||||||
/// reported via \p Ctx.
|
/// reported via \p Ctx.
|
||||||
|
/// The \p STI is present only for fragments of type MCRelaxableFragment and
|
||||||
|
/// MCDataFragment with hasInstructions() == true.
|
||||||
virtual void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
virtual void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const = 0;
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const = 0;
|
||||||
|
|
||||||
/// Check whether the given target requires emitting differences of two
|
/// Check whether the given target requires emitting differences of two
|
||||||
/// symbols as a set of relocations.
|
/// symbols as a set of relocations.
|
||||||
|
@ -108,7 +111,10 @@ public:
|
||||||
/// Check whether the given instruction may need relaxation.
|
/// Check whether the given instruction may need relaxation.
|
||||||
///
|
///
|
||||||
/// \param Inst - The instruction to test.
|
/// \param Inst - The instruction to test.
|
||||||
virtual bool mayNeedRelaxation(const MCInst &Inst) const = 0;
|
/// \param STI - The MCSubtargetInfo in effect when the instruction was
|
||||||
|
/// encoded.
|
||||||
|
virtual bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const = 0;
|
||||||
|
|
||||||
/// Target specific predicate for whether a given fixup requires the
|
/// Target specific predicate for whether a given fixup requires the
|
||||||
/// associated instruction to be relaxed.
|
/// associated instruction to be relaxed.
|
||||||
|
|
|
@ -201,7 +201,16 @@ protected:
|
||||||
: MCEncodedFragmentWithContents<ContentsSize>(FType, HasInstructions,
|
: MCEncodedFragmentWithContents<ContentsSize>(FType, HasInstructions,
|
||||||
Sec) {}
|
Sec) {}
|
||||||
|
|
||||||
|
/// STI - The MCSubtargetInfo in effect when the instruction was encoded.
|
||||||
|
/// must be non-null for instructions.
|
||||||
|
const MCSubtargetInfo *STI = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/// Retrieve the MCSubTargetInfo in effect when the instruction was encoded.
|
||||||
|
/// Guaranteed to be non-null if hasInstructions() == true
|
||||||
|
const MCSubtargetInfo *getSubtargetInfo() const { return STI; }
|
||||||
|
|
||||||
using const_fixup_iterator = SmallVectorImpl<MCFixup>::const_iterator;
|
using const_fixup_iterator = SmallVectorImpl<MCFixup>::const_iterator;
|
||||||
using fixup_iterator = SmallVectorImpl<MCFixup>::iterator;
|
using fixup_iterator = SmallVectorImpl<MCFixup>::iterator;
|
||||||
|
|
||||||
|
@ -228,7 +237,12 @@ public:
|
||||||
MCDataFragment(MCSection *Sec = nullptr)
|
MCDataFragment(MCSection *Sec = nullptr)
|
||||||
: MCEncodedFragmentWithFixups<32, 4>(FT_Data, false, Sec) {}
|
: MCEncodedFragmentWithFixups<32, 4>(FT_Data, false, Sec) {}
|
||||||
|
|
||||||
void setHasInstructions(bool V) { HasInstructions = V; }
|
/// Record that the fragment contains instructions with the MCSubtargetInfo in
|
||||||
|
/// effect when the instruction was encoded.
|
||||||
|
void setHasInstructions(const MCSubtargetInfo &STI) {
|
||||||
|
HasInstructions = true;
|
||||||
|
this->STI = &STI;
|
||||||
|
}
|
||||||
|
|
||||||
static bool classof(const MCFragment *F) {
|
static bool classof(const MCFragment *F) {
|
||||||
return F->getKind() == MCFragment::FT_Data;
|
return F->getKind() == MCFragment::FT_Data;
|
||||||
|
@ -259,20 +273,15 @@ class MCRelaxableFragment : public MCEncodedFragmentWithFixups<8, 1> {
|
||||||
/// Inst - The instruction this is a fragment for.
|
/// Inst - The instruction this is a fragment for.
|
||||||
MCInst Inst;
|
MCInst Inst;
|
||||||
|
|
||||||
/// STI - The MCSubtargetInfo in effect when the instruction was encoded.
|
|
||||||
const MCSubtargetInfo &STI;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI,
|
MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI,
|
||||||
MCSection *Sec = nullptr)
|
MCSection *Sec = nullptr)
|
||||||
: MCEncodedFragmentWithFixups(FT_Relaxable, true, Sec),
|
: MCEncodedFragmentWithFixups(FT_Relaxable, true, Sec),
|
||||||
Inst(Inst), STI(STI) {}
|
Inst(Inst) { this->STI = &STI; }
|
||||||
|
|
||||||
const MCInst &getInst() const { return Inst; }
|
const MCInst &getInst() const { return Inst; }
|
||||||
void setInst(const MCInst &Value) { Inst = Value; }
|
void setInst(const MCInst &Value) { Inst = Value; }
|
||||||
|
|
||||||
const MCSubtargetInfo &getSubtargetInfo() { return STI; }
|
|
||||||
|
|
||||||
static bool classof(const MCFragment *F) {
|
static bool classof(const MCFragment *F) {
|
||||||
return F->getKind() == MCFragment::FT_Relaxable;
|
return F->getKind() == MCFragment::FT_Relaxable;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,9 @@ public:
|
||||||
|
|
||||||
/// Get a data fragment to write into, creating a new one if the current
|
/// Get a data fragment to write into, creating a new one if the current
|
||||||
/// fragment is not a data fragment.
|
/// fragment is not a data fragment.
|
||||||
MCDataFragment *getOrCreateDataFragment();
|
/// Optionally a \p STI can be passed in so that a new fragment is created
|
||||||
|
/// if the Subtarget differs from the current fragment.
|
||||||
|
MCDataFragment *getOrCreateDataFragment(const MCSubtargetInfo* STI = nullptr);
|
||||||
MCPaddingFragment *getOrCreatePaddingFragment();
|
MCPaddingFragment *getOrCreatePaddingFragment();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -158,7 +160,8 @@ public:
|
||||||
void EmitGPRel32Value(const MCExpr *Value) override;
|
void EmitGPRel32Value(const MCExpr *Value) override;
|
||||||
void EmitGPRel64Value(const MCExpr *Value) override;
|
void EmitGPRel64Value(const MCExpr *Value) override;
|
||||||
bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||||
const MCExpr *Expr, SMLoc Loc) override;
|
const MCExpr *Expr, SMLoc Loc,
|
||||||
|
const MCSubtargetInfo &STI) override;
|
||||||
using MCStreamer::emitFill;
|
using MCStreamer::emitFill;
|
||||||
void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
|
void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
|
||||||
SMLoc Loc = SMLoc()) override;
|
SMLoc Loc = SMLoc()) override;
|
||||||
|
|
|
@ -918,7 +918,8 @@ public:
|
||||||
/// Returns true if the relocation could not be emitted because Name is not
|
/// Returns true if the relocation could not be emitted because Name is not
|
||||||
/// known.
|
/// known.
|
||||||
virtual bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
virtual bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||||
const MCExpr *Expr, SMLoc Loc) {
|
const MCExpr *Expr, SMLoc Loc,
|
||||||
|
const MCSubtargetInfo &STI) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -315,7 +315,8 @@ public:
|
||||||
void EmitBundleUnlock() override;
|
void EmitBundleUnlock() override;
|
||||||
|
|
||||||
bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||||
const MCExpr *Expr, SMLoc Loc) override;
|
const MCExpr *Expr, SMLoc Loc,
|
||||||
|
const MCSubtargetInfo &STI) override;
|
||||||
|
|
||||||
/// If this file is backed by an assembly streamer, this dumps the specified
|
/// If this file is backed by an assembly streamer, this dumps the specified
|
||||||
/// string in the output .s file. This capability is indicated by the
|
/// string in the output .s file. This capability is indicated by the
|
||||||
|
@ -1820,7 +1821,8 @@ void MCAsmStreamer::EmitBundleUnlock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||||
const MCExpr *Expr, SMLoc) {
|
const MCExpr *Expr, SMLoc,
|
||||||
|
const MCSubtargetInfo &STI) {
|
||||||
OS << "\t.reloc ";
|
OS << "\t.reloc ";
|
||||||
Offset.print(OS, MAI);
|
Offset.print(OS, MAI);
|
||||||
OS << ", " << Name;
|
OS << ", " << Name;
|
||||||
|
|
|
@ -805,12 +805,17 @@ void MCAssembler::layout(MCAsmLayout &Layout) {
|
||||||
continue;
|
continue;
|
||||||
ArrayRef<MCFixup> Fixups;
|
ArrayRef<MCFixup> Fixups;
|
||||||
MutableArrayRef<char> Contents;
|
MutableArrayRef<char> Contents;
|
||||||
|
const MCSubtargetInfo *STI = nullptr;
|
||||||
if (auto *FragWithFixups = dyn_cast<MCDataFragment>(&Frag)) {
|
if (auto *FragWithFixups = dyn_cast<MCDataFragment>(&Frag)) {
|
||||||
Fixups = FragWithFixups->getFixups();
|
Fixups = FragWithFixups->getFixups();
|
||||||
Contents = FragWithFixups->getContents();
|
Contents = FragWithFixups->getContents();
|
||||||
|
STI = FragWithFixups->getSubtargetInfo();
|
||||||
|
assert(!FragWithFixups->hasInstructions() || STI != nullptr);
|
||||||
} else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(&Frag)) {
|
} else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(&Frag)) {
|
||||||
Fixups = FragWithFixups->getFixups();
|
Fixups = FragWithFixups->getFixups();
|
||||||
Contents = FragWithFixups->getContents();
|
Contents = FragWithFixups->getContents();
|
||||||
|
STI = FragWithFixups->getSubtargetInfo();
|
||||||
|
assert(!FragWithFixups->hasInstructions() || STI != nullptr);
|
||||||
} else if (auto *FragWithFixups = dyn_cast<MCCVDefRangeFragment>(&Frag)) {
|
} else if (auto *FragWithFixups = dyn_cast<MCCVDefRangeFragment>(&Frag)) {
|
||||||
Fixups = FragWithFixups->getFixups();
|
Fixups = FragWithFixups->getFixups();
|
||||||
Contents = FragWithFixups->getContents();
|
Contents = FragWithFixups->getContents();
|
||||||
|
@ -823,7 +828,7 @@ void MCAssembler::layout(MCAsmLayout &Layout) {
|
||||||
std::tie(Target, FixedValue, IsResolved) =
|
std::tie(Target, FixedValue, IsResolved) =
|
||||||
handleFixup(Layout, Frag, Fixup);
|
handleFixup(Layout, Frag, Fixup);
|
||||||
getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue,
|
getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue,
|
||||||
IsResolved);
|
IsResolved, STI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -860,7 +865,7 @@ bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F,
|
||||||
// If this inst doesn't ever need relaxation, ignore it. This occurs when we
|
// If this inst doesn't ever need relaxation, ignore it. This occurs when we
|
||||||
// are intentionally pushing out inst fragments, or because we relaxed a
|
// are intentionally pushing out inst fragments, or because we relaxed a
|
||||||
// previous instruction to one that doesn't need relaxation.
|
// previous instruction to one that doesn't need relaxation.
|
||||||
if (!getBackend().mayNeedRelaxation(F->getInst()))
|
if (!getBackend().mayNeedRelaxation(F->getInst(), *F->getSubtargetInfo()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (const MCFixup &Fixup : F->getFixups())
|
for (const MCFixup &Fixup : F->getFixups())
|
||||||
|
@ -885,7 +890,7 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout,
|
||||||
// Relax the fragment.
|
// Relax the fragment.
|
||||||
|
|
||||||
MCInst Relaxed;
|
MCInst Relaxed;
|
||||||
getBackend().relaxInstruction(F.getInst(), F.getSubtargetInfo(), Relaxed);
|
getBackend().relaxInstruction(F.getInst(), *F.getSubtargetInfo(), Relaxed);
|
||||||
|
|
||||||
// Encode the new instruction.
|
// Encode the new instruction.
|
||||||
//
|
//
|
||||||
|
@ -894,7 +899,7 @@ bool MCAssembler::relaxInstruction(MCAsmLayout &Layout,
|
||||||
SmallVector<MCFixup, 4> Fixups;
|
SmallVector<MCFixup, 4> Fixups;
|
||||||
SmallString<256> Code;
|
SmallString<256> Code;
|
||||||
raw_svector_ostream VecOS(Code);
|
raw_svector_ostream VecOS(Code);
|
||||||
getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, F.getSubtargetInfo());
|
getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, *F.getSubtargetInfo());
|
||||||
|
|
||||||
// Update the fragment.
|
// Update the fragment.
|
||||||
F.setInst(Relaxed);
|
F.setInst(Relaxed);
|
||||||
|
|
|
@ -83,7 +83,8 @@ void MCELFStreamer::mergeFragment(MCDataFragment *DF,
|
||||||
DF->getContents().size());
|
DF->getContents().size());
|
||||||
DF->getFixups().push_back(EF->getFixups()[i]);
|
DF->getFixups().push_back(EF->getFixups()[i]);
|
||||||
}
|
}
|
||||||
DF->setHasInstructions(true);
|
if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo())
|
||||||
|
DF->setHasInstructions(*EF->getSubtargetInfo());
|
||||||
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
|
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,6 +494,15 @@ void MCELFStreamer::EmitInstToFragment(const MCInst &Inst,
|
||||||
fixSymbolsInTLSFixups(F.getFixups()[i].getValue());
|
fixSymbolsInTLSFixups(F.getFixups()[i].getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A fragment can only have one Subtarget, and when bundling is enabled we
|
||||||
|
// sometimes need to use the same fragment. We give an error if there
|
||||||
|
// are conflicting Subtargets.
|
||||||
|
static void CheckBundleSubtargets(const MCSubtargetInfo *OldSTI,
|
||||||
|
const MCSubtargetInfo *NewSTI) {
|
||||||
|
if (OldSTI && NewSTI && OldSTI != NewSTI)
|
||||||
|
report_fatal_error("A Bundle can only have one Subtarget.");
|
||||||
|
}
|
||||||
|
|
||||||
void MCELFStreamer::EmitInstToData(const MCInst &Inst,
|
void MCELFStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
const MCSubtargetInfo &STI) {
|
const MCSubtargetInfo &STI) {
|
||||||
MCAssembler &Assembler = getAssembler();
|
MCAssembler &Assembler = getAssembler();
|
||||||
|
@ -508,7 +518,7 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
//
|
//
|
||||||
// If bundling is disabled, append the encoded instruction to the current data
|
// If bundling is disabled, append the encoded instruction to the current data
|
||||||
// fragment (or create a new such fragment if the current fragment is not a
|
// fragment (or create a new such fragment if the current fragment is not a
|
||||||
// data fragment).
|
// data fragment, or the Subtarget has changed).
|
||||||
//
|
//
|
||||||
// If bundling is enabled:
|
// If bundling is enabled:
|
||||||
// - If we're not in a bundle-locked group, emit the instruction into a
|
// - If we're not in a bundle-locked group, emit the instruction into a
|
||||||
|
@ -523,19 +533,23 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
|
|
||||||
if (Assembler.isBundlingEnabled()) {
|
if (Assembler.isBundlingEnabled()) {
|
||||||
MCSection &Sec = *getCurrentSectionOnly();
|
MCSection &Sec = *getCurrentSectionOnly();
|
||||||
if (Assembler.getRelaxAll() && isBundleLocked())
|
if (Assembler.getRelaxAll() && isBundleLocked()) {
|
||||||
// If the -mc-relax-all flag is used and we are bundle-locked, we re-use
|
// If the -mc-relax-all flag is used and we are bundle-locked, we re-use
|
||||||
// the current bundle group.
|
// the current bundle group.
|
||||||
DF = BundleGroups.back();
|
DF = BundleGroups.back();
|
||||||
|
CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
|
||||||
|
}
|
||||||
else if (Assembler.getRelaxAll() && !isBundleLocked())
|
else if (Assembler.getRelaxAll() && !isBundleLocked())
|
||||||
// When not in a bundle-locked group and the -mc-relax-all flag is used,
|
// When not in a bundle-locked group and the -mc-relax-all flag is used,
|
||||||
// we create a new temporary fragment which will be later merged into
|
// we create a new temporary fragment which will be later merged into
|
||||||
// the current fragment.
|
// the current fragment.
|
||||||
DF = new MCDataFragment();
|
DF = new MCDataFragment();
|
||||||
else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst())
|
else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) {
|
||||||
// If we are bundle-locked, we re-use the current fragment.
|
// If we are bundle-locked, we re-use the current fragment.
|
||||||
// The bundle-locking directive ensures this is a new data fragment.
|
// The bundle-locking directive ensures this is a new data fragment.
|
||||||
DF = cast<MCDataFragment>(getCurrentFragment());
|
DF = cast<MCDataFragment>(getCurrentFragment());
|
||||||
|
CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
|
||||||
|
}
|
||||||
else if (!isBundleLocked() && Fixups.size() == 0) {
|
else if (!isBundleLocked() && Fixups.size() == 0) {
|
||||||
// Optimize memory usage by emitting the instruction to a
|
// Optimize memory usage by emitting the instruction to a
|
||||||
// MCCompactEncodedInstFragment when not in a bundle-locked group and
|
// MCCompactEncodedInstFragment when not in a bundle-locked group and
|
||||||
|
@ -560,7 +574,7 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
// to be turned off.
|
// to be turned off.
|
||||||
Sec.setBundleGroupBeforeFirstInst(false);
|
Sec.setBundleGroupBeforeFirstInst(false);
|
||||||
} else {
|
} else {
|
||||||
DF = getOrCreateDataFragment();
|
DF = getOrCreateDataFragment(&STI);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the fixups and data.
|
// Add the fixups and data.
|
||||||
|
@ -568,12 +582,12 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
||||||
DF->getFixups().push_back(Fixups[i]);
|
DF->getFixups().push_back(Fixups[i]);
|
||||||
}
|
}
|
||||||
DF->setHasInstructions(true);
|
DF->setHasInstructions(STI);
|
||||||
DF->getContents().append(Code.begin(), Code.end());
|
DF->getContents().append(Code.begin(), Code.end());
|
||||||
|
|
||||||
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
|
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
|
||||||
if (!isBundleLocked()) {
|
if (!isBundleLocked()) {
|
||||||
mergeFragment(getOrCreateDataFragment(), DF);
|
mergeFragment(getOrCreateDataFragment(&STI), DF);
|
||||||
delete DF;
|
delete DF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -633,7 +647,7 @@ void MCELFStreamer::EmitBundleUnlock() {
|
||||||
|
|
||||||
// FIXME: Use more separate fragments for nested groups.
|
// FIXME: Use more separate fragments for nested groups.
|
||||||
if (!isBundleLocked()) {
|
if (!isBundleLocked()) {
|
||||||
mergeFragment(getOrCreateDataFragment(), DF);
|
mergeFragment(getOrCreateDataFragment(DF->getSubtargetInfo()), DF);
|
||||||
BundleGroups.pop_back();
|
BundleGroups.pop_back();
|
||||||
delete DF;
|
delete DF;
|
||||||
}
|
}
|
||||||
|
|
|
@ -450,6 +450,7 @@ void MCMachOStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
Fixup.setOffset(Fixup.getOffset() + DF->getContents().size());
|
Fixup.setOffset(Fixup.getOffset() + DF->getContents().size());
|
||||||
DF->getFixups().push_back(Fixup);
|
DF->getFixups().push_back(Fixup);
|
||||||
}
|
}
|
||||||
|
DF->setHasInstructions(STI);
|
||||||
DF->getContents().append(Code.begin(), Code.end());
|
DF->getContents().append(Code.begin(), Code.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -146,12 +146,24 @@ MCFragment *MCObjectStreamer::getCurrentFragment() const {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() {
|
static bool CanReuseDataFragment(const MCDataFragment &F,
|
||||||
MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
|
const MCAssembler &Assembler,
|
||||||
|
const MCSubtargetInfo *STI) {
|
||||||
|
if (!F.hasInstructions())
|
||||||
|
return true;
|
||||||
// When bundling is enabled, we don't want to add data to a fragment that
|
// When bundling is enabled, we don't want to add data to a fragment that
|
||||||
// already has instructions (see MCELFStreamer::EmitInstToData for details)
|
// already has instructions (see MCELFStreamer::EmitInstToData for details)
|
||||||
if (!F || (Assembler->isBundlingEnabled() && !Assembler->getRelaxAll() &&
|
if (Assembler.isBundlingEnabled())
|
||||||
F->hasInstructions())) {
|
return Assembler.getRelaxAll();
|
||||||
|
// If the subtarget is changed mid fragment we start a new fragment to record
|
||||||
|
// the new STI.
|
||||||
|
return !STI || F.getSubtargetInfo() == STI;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCDataFragment *
|
||||||
|
MCObjectStreamer::getOrCreateDataFragment(const MCSubtargetInfo *STI) {
|
||||||
|
MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
|
||||||
|
if (!F || !CanReuseDataFragment(*F, *Assembler, STI)) {
|
||||||
F = new MCDataFragment();
|
F = new MCDataFragment();
|
||||||
insert(F);
|
insert(F);
|
||||||
}
|
}
|
||||||
|
@ -327,7 +339,7 @@ void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst,
|
||||||
|
|
||||||
// If this instruction doesn't need relaxation, just emit it as data.
|
// If this instruction doesn't need relaxation, just emit it as data.
|
||||||
MCAssembler &Assembler = getAssembler();
|
MCAssembler &Assembler = getAssembler();
|
||||||
if (!Assembler.getBackend().mayNeedRelaxation(Inst)) {
|
if (!Assembler.getBackend().mayNeedRelaxation(Inst, STI)) {
|
||||||
EmitInstToData(Inst, STI);
|
EmitInstToData(Inst, STI);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -341,7 +353,7 @@ void MCObjectStreamer::EmitInstructionImpl(const MCInst &Inst,
|
||||||
(Assembler.isBundlingEnabled() && Sec->isBundleLocked())) {
|
(Assembler.isBundlingEnabled() && Sec->isBundleLocked())) {
|
||||||
MCInst Relaxed;
|
MCInst Relaxed;
|
||||||
getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed);
|
getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed);
|
||||||
while (getAssembler().getBackend().mayNeedRelaxation(Relaxed))
|
while (getAssembler().getBackend().mayNeedRelaxation(Relaxed, STI))
|
||||||
getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed);
|
getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed);
|
||||||
EmitInstToData(Relaxed, STI);
|
EmitInstToData(Relaxed, STI);
|
||||||
return;
|
return;
|
||||||
|
@ -606,7 +618,8 @@ void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||||
const MCExpr *Expr, SMLoc Loc) {
|
const MCExpr *Expr, SMLoc Loc,
|
||||||
|
const MCSubtargetInfo &STI) {
|
||||||
int64_t OffsetValue;
|
int64_t OffsetValue;
|
||||||
if (!Offset.evaluateAsAbsolute(OffsetValue))
|
if (!Offset.evaluateAsAbsolute(OffsetValue))
|
||||||
llvm_unreachable("Offset is not absolute");
|
llvm_unreachable("Offset is not absolute");
|
||||||
|
@ -614,7 +627,7 @@ bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
|
||||||
if (OffsetValue < 0)
|
if (OffsetValue < 0)
|
||||||
llvm_unreachable("Offset is negative");
|
llvm_unreachable("Offset is negative");
|
||||||
|
|
||||||
MCDataFragment *DF = getOrCreateDataFragment();
|
MCDataFragment *DF = getOrCreateDataFragment(&STI);
|
||||||
flushPendingLabels(DF, DF->getContents().size());
|
flushPendingLabels(DF, DF->getContents().size());
|
||||||
|
|
||||||
Optional<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name);
|
Optional<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name);
|
||||||
|
|
|
@ -2949,7 +2949,9 @@ bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) {
|
||||||
"unexpected token in .reloc directive"))
|
"unexpected token in .reloc directive"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc))
|
const MCTargetAsmParser &MCT = getTargetParser();
|
||||||
|
const MCSubtargetInfo &STI = MCT.getSTI();
|
||||||
|
if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc, STI))
|
||||||
return Error(NameLoc, "unknown relocation name");
|
return Error(NameLoc, "unknown relocation name");
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -45,7 +45,8 @@ void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) {
|
||||||
DF->getContents().size());
|
DF->getContents().size());
|
||||||
DF->getFixups().push_back(EF->getFixups()[i]);
|
DF->getFixups().push_back(EF->getFixups()[i]);
|
||||||
}
|
}
|
||||||
DF->setHasInstructions(true);
|
if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo())
|
||||||
|
DF->setHasInstructions(*EF->getSubtargetInfo());
|
||||||
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
|
DF->getContents().append(EF->getContents().begin(), EF->getContents().end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ void MCWasmStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
||||||
DF->getFixups().push_back(Fixups[i]);
|
DF->getFixups().push_back(Fixups[i]);
|
||||||
}
|
}
|
||||||
DF->setHasInstructions(true);
|
DF->setHasInstructions(STI);
|
||||||
DF->getContents().append(Code.begin(), Code.end());
|
DF->getContents().append(Code.begin(), Code.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst,
|
||||||
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
|
||||||
DF->getFixups().push_back(Fixups[i]);
|
DF->getFixups().push_back(Fixups[i]);
|
||||||
}
|
}
|
||||||
|
DF->setHasInstructions(STI);
|
||||||
DF->getContents().append(Code.begin(), Code.end());
|
DF->getContents().append(Code.begin(), Code.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,9 +73,11 @@ public:
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override;
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override;
|
||||||
|
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override;
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override;
|
||||||
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
||||||
const MCRelaxableFragment *DF,
|
const MCRelaxableFragment *DF,
|
||||||
const MCAsmLayout &Layout) const override;
|
const MCAsmLayout &Layout) const override;
|
||||||
|
@ -285,7 +287,8 @@ unsigned AArch64AsmBackend::getFixupKindContainereSizeInBytes(unsigned Kind) con
|
||||||
void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target,
|
const MCValue &Target,
|
||||||
MutableArrayRef<char> Data, uint64_t Value,
|
MutableArrayRef<char> Data, uint64_t Value,
|
||||||
bool IsResolved) const {
|
bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const {
|
||||||
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
|
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
|
||||||
if (!Value)
|
if (!Value)
|
||||||
return; // Doesn't change encoding.
|
return; // Doesn't change encoding.
|
||||||
|
@ -321,7 +324,8 @@ void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
|
bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ public:
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override;
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override;
|
||||||
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
||||||
const MCRelaxableFragment *DF,
|
const MCRelaxableFragment *DF,
|
||||||
const MCAsmLayout &Layout) const override {
|
const MCAsmLayout &Layout) const override {
|
||||||
|
@ -42,7 +43,10 @@ public:
|
||||||
MCInst &Res) const override {
|
MCInst &Res) const override {
|
||||||
llvm_unreachable("Not implemented");
|
llvm_unreachable("Not implemented");
|
||||||
}
|
}
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned getMinimumNopSize() 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 override;
|
||||||
|
@ -102,7 +106,8 @@ static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
|
||||||
void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target,
|
const MCValue &Target,
|
||||||
MutableArrayRef<char> Data, uint64_t Value,
|
MutableArrayRef<char> Data, uint64_t Value,
|
||||||
bool IsResolved) const {
|
bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const {
|
||||||
Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
|
Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
|
||||||
if (!Value)
|
if (!Value)
|
||||||
return; // Doesn't change encoding.
|
return; // Doesn't change encoding.
|
||||||
|
|
|
@ -173,7 +173,8 @@ void ARMAsmBackend::handleAssemblerFlag(MCAssemblerFlag Flag) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op) const {
|
unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op,
|
||||||
|
const MCSubtargetInfo &STI) const {
|
||||||
bool HasThumb2 = STI.getFeatureBits()[ARM::FeatureThumb2];
|
bool HasThumb2 = STI.getFeatureBits()[ARM::FeatureThumb2];
|
||||||
bool HasV8MBaselineOps = STI.getFeatureBits()[ARM::HasV8MBaselineOps];
|
bool HasV8MBaselineOps = STI.getFeatureBits()[ARM::HasV8MBaselineOps];
|
||||||
|
|
||||||
|
@ -195,8 +196,9 @@ unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
|
bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst,
|
||||||
if (getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode())
|
const MCSubtargetInfo &STI) const {
|
||||||
|
if (getRelaxedOpcode(Inst.getOpcode(), STI) != Inst.getOpcode())
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -263,7 +265,7 @@ bool ARMAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
||||||
void ARMAsmBackend::relaxInstruction(const MCInst &Inst,
|
void ARMAsmBackend::relaxInstruction(const MCInst &Inst,
|
||||||
const MCSubtargetInfo &STI,
|
const MCSubtargetInfo &STI,
|
||||||
MCInst &Res) const {
|
MCInst &Res) const {
|
||||||
unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode());
|
unsigned RelaxedOp = getRelaxedOpcode(Inst.getOpcode(), STI);
|
||||||
|
|
||||||
// Sanity check w/ diagnostic if we get here w/ a bogus instruction.
|
// Sanity check w/ diagnostic if we get here w/ a bogus instruction.
|
||||||
if (RelaxedOp == Inst.getOpcode()) {
|
if (RelaxedOp == Inst.getOpcode()) {
|
||||||
|
@ -360,7 +362,8 @@ static uint32_t joinHalfWords(uint32_t FirstHalf, uint32_t SecondHalf,
|
||||||
unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
||||||
const MCFixup &Fixup,
|
const MCFixup &Fixup,
|
||||||
const MCValue &Target, uint64_t Value,
|
const MCValue &Target, uint64_t Value,
|
||||||
bool IsResolved, MCContext &Ctx) const {
|
bool IsResolved, MCContext &Ctx,
|
||||||
|
const MCSubtargetInfo* STI) const {
|
||||||
unsigned Kind = Fixup.getKind();
|
unsigned Kind = Fixup.getKind();
|
||||||
|
|
||||||
// MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
|
// MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
|
||||||
|
@ -389,7 +392,8 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
||||||
case FK_SecRel_4:
|
case FK_SecRel_4:
|
||||||
return Value;
|
return Value;
|
||||||
case ARM::fixup_arm_movt_hi16:
|
case ARM::fixup_arm_movt_hi16:
|
||||||
if (IsResolved || !STI.getTargetTriple().isOSBinFormatELF())
|
assert(STI != nullptr);
|
||||||
|
if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
|
||||||
Value >>= 16;
|
Value >>= 16;
|
||||||
LLVM_FALLTHROUGH;
|
LLVM_FALLTHROUGH;
|
||||||
case ARM::fixup_arm_movw_lo16: {
|
case ARM::fixup_arm_movw_lo16: {
|
||||||
|
@ -401,7 +405,8 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
||||||
return Value;
|
return Value;
|
||||||
}
|
}
|
||||||
case ARM::fixup_t2_movt_hi16:
|
case ARM::fixup_t2_movt_hi16:
|
||||||
if (IsResolved || !STI.getTargetTriple().isOSBinFormatELF())
|
assert(STI != nullptr);
|
||||||
|
if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
|
||||||
Value >>= 16;
|
Value >>= 16;
|
||||||
LLVM_FALLTHROUGH;
|
LLVM_FALLTHROUGH;
|
||||||
case ARM::fixup_t2_movw_lo16: {
|
case ARM::fixup_t2_movw_lo16: {
|
||||||
|
@ -529,9 +534,9 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
||||||
}
|
}
|
||||||
case ARM::fixup_arm_thumb_bl: {
|
case ARM::fixup_arm_thumb_bl: {
|
||||||
if (!isInt<25>(Value - 4) ||
|
if (!isInt<25>(Value - 4) ||
|
||||||
(!STI.getFeatureBits()[ARM::FeatureThumb2] &&
|
(!STI->getFeatureBits()[ARM::FeatureThumb2] &&
|
||||||
!STI.getFeatureBits()[ARM::HasV8MBaselineOps] &&
|
!STI->getFeatureBits()[ARM::HasV8MBaselineOps] &&
|
||||||
!STI.getFeatureBits()[ARM::HasV6MOps] &&
|
!STI->getFeatureBits()[ARM::HasV6MOps] &&
|
||||||
!isInt<23>(Value - 4))) {
|
!isInt<23>(Value - 4))) {
|
||||||
Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
|
Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -603,7 +608,8 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
||||||
case ARM::fixup_arm_thumb_cp:
|
case ARM::fixup_arm_thumb_cp:
|
||||||
// On CPUs supporting Thumb2, this will be relaxed to an ldr.w, otherwise we
|
// On CPUs supporting Thumb2, this will be relaxed to an ldr.w, otherwise we
|
||||||
// could have an error on our hands.
|
// could have an error on our hands.
|
||||||
if (!STI.getFeatureBits()[ARM::FeatureThumb2] && IsResolved) {
|
assert(STI != nullptr);
|
||||||
|
if (!STI->getFeatureBits()[ARM::FeatureThumb2] && IsResolved) {
|
||||||
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
|
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
|
||||||
if (FixupDiagnostic) {
|
if (FixupDiagnostic) {
|
||||||
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
|
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
|
||||||
|
@ -627,8 +633,9 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
||||||
}
|
}
|
||||||
case ARM::fixup_arm_thumb_br:
|
case ARM::fixup_arm_thumb_br:
|
||||||
// Offset by 4 and don't encode the lower bit, which is always 0.
|
// Offset by 4 and don't encode the lower bit, which is always 0.
|
||||||
if (!STI.getFeatureBits()[ARM::FeatureThumb2] &&
|
assert(STI != nullptr);
|
||||||
!STI.getFeatureBits()[ARM::HasV8MBaselineOps]) {
|
if (!STI->getFeatureBits()[ARM::FeatureThumb2] &&
|
||||||
|
!STI->getFeatureBits()[ARM::HasV8MBaselineOps]) {
|
||||||
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
|
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
|
||||||
if (FixupDiagnostic) {
|
if (FixupDiagnostic) {
|
||||||
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
|
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
|
||||||
|
@ -638,7 +645,8 @@ unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
|
||||||
return ((Value - 4) >> 1) & 0x7ff;
|
return ((Value - 4) >> 1) & 0x7ff;
|
||||||
case ARM::fixup_arm_thumb_bcc:
|
case ARM::fixup_arm_thumb_bcc:
|
||||||
// Offset by 4 and don't encode the lower bit, which is always 0.
|
// Offset by 4 and don't encode the lower bit, which is always 0.
|
||||||
if (!STI.getFeatureBits()[ARM::FeatureThumb2]) {
|
assert(STI != nullptr);
|
||||||
|
if (!STI->getFeatureBits()[ARM::FeatureThumb2]) {
|
||||||
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
|
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
|
||||||
if (FixupDiagnostic) {
|
if (FixupDiagnostic) {
|
||||||
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
|
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
|
||||||
|
@ -894,10 +902,11 @@ static unsigned getFixupKindContainerSizeBytes(unsigned Kind) {
|
||||||
void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target,
|
const MCValue &Target,
|
||||||
MutableArrayRef<char> Data, uint64_t Value,
|
MutableArrayRef<char> Data, uint64_t Value,
|
||||||
bool IsResolved) const {
|
bool IsResolved,
|
||||||
|
const MCSubtargetInfo* STI) const {
|
||||||
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
|
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
|
||||||
MCContext &Ctx = Asm.getContext();
|
MCContext &Ctx = Asm.getContext();
|
||||||
Value = adjustFixupValue(Asm, Fixup, Target, Value, IsResolved, Ctx);
|
Value = adjustFixupValue(Asm, Fixup, Target, Value, IsResolved, Ctx, STI);
|
||||||
if (!Value)
|
if (!Value)
|
||||||
return; // Doesn't change encoding.
|
return; // Doesn't change encoding.
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
|
||||||
class ARMAsmBackend : public MCAsmBackend {
|
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;
|
const MCSubtargetInfo &STI;
|
||||||
bool isThumbMode; // Currently emitting Thumb code.
|
bool isThumbMode; // Currently emitting Thumb code.
|
||||||
public:
|
public:
|
||||||
|
@ -31,6 +34,8 @@ public:
|
||||||
return ARM::NumTargetFixupKinds;
|
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 { return STI.getFeatureBits()[ARM::HasV6T2Ops]; }
|
||||||
|
|
||||||
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
|
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
|
||||||
|
@ -40,15 +45,18 @@ public:
|
||||||
|
|
||||||
unsigned adjustFixupValue(const MCAssembler &Asm, const MCFixup &Fixup,
|
unsigned adjustFixupValue(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, uint64_t Value,
|
const MCValue &Target, uint64_t Value,
|
||||||
bool IsResolved, MCContext &Ctx) const;
|
bool IsResolved, MCContext &Ctx,
|
||||||
|
const MCSubtargetInfo *STI) const;
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override;
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override;
|
||||||
|
|
||||||
unsigned getRelaxedOpcode(unsigned Op) const;
|
unsigned getRelaxedOpcode(unsigned Op, const MCSubtargetInfo &STI) const;
|
||||||
|
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override;
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override;
|
||||||
|
|
||||||
const char *reasonForFixupRelaxation(const MCFixup &Fixup,
|
const char *reasonForFixupRelaxation(const MCFixup &Fixup,
|
||||||
uint64_t Value) const;
|
uint64_t Value) const;
|
||||||
|
|
|
@ -27,7 +27,8 @@ public:
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override;
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override;
|
||||||
|
|
||||||
std::unique_ptr<MCObjectTargetWriter>
|
std::unique_ptr<MCObjectTargetWriter>
|
||||||
createObjectTargetWriter() const override;
|
createObjectTargetWriter() const override;
|
||||||
|
@ -41,7 +42,10 @@ public:
|
||||||
|
|
||||||
unsigned getNumFixupKinds() const override { return 1; }
|
unsigned getNumFixupKinds() const override { return 1; }
|
||||||
|
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
|
void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
|
||||||
MCInst &Res) const override {}
|
MCInst &Res) const override {}
|
||||||
|
@ -64,7 +68,8 @@ bool BPFAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
|
||||||
void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target,
|
const MCValue &Target,
|
||||||
MutableArrayRef<char> Data, uint64_t Value,
|
MutableArrayRef<char> Data, uint64_t Value,
|
||||||
bool IsResolved) const {
|
bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const {
|
||||||
if (Fixup.getKind() == FK_SecRel_4 || Fixup.getKind() == FK_SecRel_8) {
|
if (Fixup.getKind() == FK_SecRel_4 || Fixup.getKind() == FK_SecRel_8) {
|
||||||
assert(Value == 0);
|
assert(Value == 0);
|
||||||
} else if (Fixup.getKind() == FK_Data_4) {
|
} else if (Fixup.getKind() == FK_Data_4) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ class HexagonAsmBackend : public MCAsmBackend {
|
||||||
SmallVector<MCFixup, 4> Fixups;
|
SmallVector<MCFixup, 4> Fixups;
|
||||||
SmallString<256> Code;
|
SmallString<256> Code;
|
||||||
raw_svector_ostream VecOS(Code);
|
raw_svector_ostream VecOS(Code);
|
||||||
E.encodeInstruction(HMB, VecOS, Fixups, RF.getSubtargetInfo());
|
E.encodeInstruction(HMB, VecOS, Fixups, *RF.getSubtargetInfo());
|
||||||
|
|
||||||
// Update the fragment.
|
// Update the fragment.
|
||||||
RF.setInst(HMB);
|
RF.setInst(HMB);
|
||||||
|
@ -414,7 +414,8 @@ public:
|
||||||
/// fixup kind as appropriate.
|
/// fixup kind as appropriate.
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t FixupValue, bool IsResolved) const override {
|
uint64_t FixupValue, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override {
|
||||||
|
|
||||||
// When FixupValue is 0 the relocation is external and there
|
// When FixupValue is 0 the relocation is external and there
|
||||||
// is nothing for us to do.
|
// is nothing for us to do.
|
||||||
|
@ -561,7 +562,8 @@ public:
|
||||||
/// relaxation.
|
/// relaxation.
|
||||||
///
|
///
|
||||||
/// \param Inst - The instruction to test.
|
/// \param Inst - The instruction to test.
|
||||||
bool mayNeedRelaxation(MCInst const &Inst) const override {
|
bool mayNeedRelaxation(MCInst const &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,7 +738,7 @@ public:
|
||||||
Inst.addOperand(MCOperand::createInst(Nop));
|
Inst.addOperand(MCOperand::createInst(Nop));
|
||||||
Size -= 4;
|
Size -= 4;
|
||||||
if (!HexagonMCChecker(
|
if (!HexagonMCChecker(
|
||||||
Context, *MCII, RF.getSubtargetInfo(), Inst,
|
Context, *MCII, *RF.getSubtargetInfo(), Inst,
|
||||||
*Context.getRegisterInfo(), false)
|
*Context.getRegisterInfo(), false)
|
||||||
.check()) {
|
.check()) {
|
||||||
Inst.erase(Inst.end() - 1);
|
Inst.erase(Inst.end() - 1);
|
||||||
|
@ -744,7 +746,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool Error = HexagonMCShuffle(Context, true, *MCII,
|
bool Error = HexagonMCShuffle(Context, true, *MCII,
|
||||||
RF.getSubtargetInfo(), Inst);
|
*RF.getSubtargetInfo(), Inst);
|
||||||
//assert(!Error);
|
//assert(!Error);
|
||||||
(void)Error;
|
(void)Error;
|
||||||
ReplaceInstruction(Asm.getEmitter(), RF, Inst);
|
ReplaceInstruction(Asm.getEmitter(), RF, Inst);
|
||||||
|
|
|
@ -51,7 +51,8 @@ public:
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override;
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override;
|
||||||
|
|
||||||
std::unique_ptr<MCObjectTargetWriter>
|
std::unique_ptr<MCObjectTargetWriter>
|
||||||
createObjectTargetWriter() const override;
|
createObjectTargetWriter() const override;
|
||||||
|
@ -69,7 +70,8 @@ public:
|
||||||
return Lanai::NumTargetFixupKinds;
|
return Lanai::NumTargetFixupKinds;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mayNeedRelaxation(const MCInst & /*Inst*/) const override {
|
bool mayNeedRelaxation(const MCInst & /*Inst*/,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +95,8 @@ bool LanaiAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
|
||||||
void LanaiAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void LanaiAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target,
|
const MCValue &Target,
|
||||||
MutableArrayRef<char> Data, uint64_t Value,
|
MutableArrayRef<char> Data, uint64_t Value,
|
||||||
bool /*IsResolved*/) const {
|
bool /*IsResolved*/,
|
||||||
|
const MCSubtargetInfo */*STI*/) const {
|
||||||
MCFixupKind Kind = Fixup.getKind();
|
MCFixupKind Kind = Fixup.getKind();
|
||||||
Value = adjustFixupValue(static_cast<unsigned>(Kind), Value);
|
Value = adjustFixupValue(static_cast<unsigned>(Kind), Value);
|
||||||
|
|
||||||
|
|
|
@ -243,7 +243,8 @@ static unsigned calculateMMLEIndex(unsigned i) {
|
||||||
void MipsAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void MipsAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target,
|
const MCValue &Target,
|
||||||
MutableArrayRef<char> Data, uint64_t Value,
|
MutableArrayRef<char> Data, uint64_t Value,
|
||||||
bool IsResolved) const {
|
bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const {
|
||||||
MCFixupKind Kind = Fixup.getKind();
|
MCFixupKind Kind = Fixup.getKind();
|
||||||
MCContext &Ctx = Asm.getContext();
|
MCContext &Ctx = Asm.getContext();
|
||||||
Value = adjustFixupValue(Fixup, Value, Ctx);
|
Value = adjustFixupValue(Fixup, Value, Ctx);
|
||||||
|
|
|
@ -42,7 +42,8 @@ public:
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override;
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override;
|
||||||
|
|
||||||
Optional<MCFixupKind> getFixupKind(StringRef Name) const override;
|
Optional<MCFixupKind> getFixupKind(StringRef Name) const override;
|
||||||
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
|
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
|
||||||
|
@ -58,7 +59,8 @@ public:
|
||||||
/// relaxation.
|
/// relaxation.
|
||||||
///
|
///
|
||||||
/// \param Inst - The instruction to test.
|
/// \param Inst - The instruction to test.
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override {
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,8 @@ public:
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override {
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override {
|
||||||
Value = adjustFixupValue(Fixup.getKind(), Value);
|
Value = adjustFixupValue(Fixup.getKind(), Value);
|
||||||
if (!Value) return; // Doesn't change encoding.
|
if (!Value) return; // Doesn't change encoding.
|
||||||
|
|
||||||
|
@ -157,7 +158,8 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override {
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
// FIXME.
|
// FIXME.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,7 +233,8 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override {
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
// FIXME.
|
// FIXME.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -275,7 +276,8 @@ namespace {
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override {
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override {
|
||||||
|
|
||||||
Value = adjustFixupValue(Fixup.getKind(), Value);
|
Value = adjustFixupValue(Fixup.getKind(), Value);
|
||||||
if (!Value) return; // Doesn't change encoding.
|
if (!Value) return; // Doesn't change encoding.
|
||||||
|
|
|
@ -53,8 +53,10 @@ public:
|
||||||
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
|
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override;
|
uint64_t Value, bool IsResolved,
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override {
|
const MCSubtargetInfo *STI) const override;
|
||||||
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
||||||
|
@ -96,7 +98,8 @@ void SystemZMCAsmBackend::applyFixup(const MCAssembler &Asm,
|
||||||
const MCFixup &Fixup,
|
const MCFixup &Fixup,
|
||||||
const MCValue &Target,
|
const MCValue &Target,
|
||||||
MutableArrayRef<char> Data, uint64_t Value,
|
MutableArrayRef<char> Data, uint64_t Value,
|
||||||
bool IsResolved) const {
|
bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const {
|
||||||
MCFixupKind Kind = Fixup.getKind();
|
MCFixupKind Kind = Fixup.getKind();
|
||||||
unsigned Offset = Fixup.getOffset();
|
unsigned Offset = Fixup.getOffset();
|
||||||
unsigned BitSize = getFixupKindInfo(Kind).TargetSize;
|
unsigned BitSize = getFixupKindInfo(Kind).TargetSize;
|
||||||
|
|
|
@ -101,7 +101,8 @@ public:
|
||||||
|
|
||||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||||
const MCValue &Target, MutableArrayRef<char> Data,
|
const MCValue &Target, MutableArrayRef<char> Data,
|
||||||
uint64_t Value, bool IsResolved) const override {
|
uint64_t Value, bool IsResolved,
|
||||||
|
const MCSubtargetInfo *STI) const override {
|
||||||
unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
|
unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind());
|
||||||
|
|
||||||
assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
|
assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
|
||||||
|
@ -117,7 +118,8 @@ public:
|
||||||
Data[Fixup.getOffset() + i] = uint8_t(Value >> (i * 8));
|
Data[Fixup.getOffset() + i] = uint8_t(Value >> (i * 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mayNeedRelaxation(const MCInst &Inst) const override;
|
bool mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const override;
|
||||||
|
|
||||||
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
||||||
const MCRelaxableFragment *DF,
|
const MCRelaxableFragment *DF,
|
||||||
|
@ -264,7 +266,8 @@ static unsigned getRelaxedOpcode(const MCInst &Inst, bool is16BitMode) {
|
||||||
return getRelaxedOpcodeBranch(Inst, is16BitMode);
|
return getRelaxedOpcodeBranch(Inst, is16BitMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool X86AsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
|
bool X86AsmBackend::mayNeedRelaxation(const MCInst &Inst,
|
||||||
|
const MCSubtargetInfo &STI) const {
|
||||||
// Branches can always be relaxed in either mode.
|
// Branches can always be relaxed in either mode.
|
||||||
if (getRelaxedOpcodeBranch(Inst, false) != Inst.getOpcode())
|
if (getRelaxedOpcodeBranch(Inst, false) != Inst.getOpcode())
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
; RUN: llc -mtriple=thumbv4t-linux-gnueabi -o - %s | FileCheck %s
|
||||||
|
|
||||||
|
; Functions may have more features than the base triple; code generation and
|
||||||
|
; instruction selection may be performed based on this information. This test
|
||||||
|
; makes sure that the MC layer performs instruction relaxation based on the
|
||||||
|
; target-features of the function. The relaxation for tail call is particularly
|
||||||
|
; important on Thumb2 as the 16-bit Thumb branch instruction has an extremely
|
||||||
|
; short range.
|
||||||
|
|
||||||
|
declare dso_local void @g(...) local_unnamed_addr #2
|
||||||
|
|
||||||
|
define dso_local void @f() local_unnamed_addr #0 {
|
||||||
|
entry:
|
||||||
|
tail call void bitcast (void (...)* @g to void ()*)() #3
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; Function has thumb2 target-feature, tail call is allowed and must be widened.
|
||||||
|
; CHECK: f:
|
||||||
|
; CHECK: b g
|
||||||
|
|
||||||
|
define dso_local void @h() local_unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
tail call void bitcast (void (...)* @g to void ()*)() #3
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
; Function does not have thumb2 target-feature, tail call should not be
|
||||||
|
; generated as it cannot be widened.
|
||||||
|
; CHECK: h:
|
||||||
|
; CHECK: bl g
|
||||||
|
|
||||||
|
attributes #0 = { nounwind "disable-tail-calls"="false" "target-cpu"="cortex-a53" "target-features"="+crypto,+fp-armv8,+neon,+soft-float-abi,+strict-align,+thumb-mode,-crc,-dotprod,-dsp,-hwdiv,-hwdiv-arm,-ras" "use-soft-float"="true" }
|
||||||
|
|
||||||
|
attributes #2 = { nounwind "disable-tail-calls"="false" "target-cpu"="arm7tdmi" "target-features"="+strict-align,+thumb-mode,-crc,-dotprod,-dsp,-hwdiv,-hwdiv-arm,-ras" "unsafe-fp-math"="false" "use-soft-float"="true" }
|
||||||
|
attributes #3 = { nounwind }
|
|
@ -0,0 +1,16 @@
|
||||||
|
# RUN: not llvm-mc -filetype=obj -triple armv7-linux-gnueabi %s -o - 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
# We cannot switch subtargets mid-bundle
|
||||||
|
.syntax unified
|
||||||
|
.text
|
||||||
|
.bundle_align_mode 4
|
||||||
|
.arch armv4t
|
||||||
|
bx lr
|
||||||
|
.bundle_lock
|
||||||
|
bx lr
|
||||||
|
.arch armv7a
|
||||||
|
movt r0, #0xffff
|
||||||
|
movw r0, #0xffff
|
||||||
|
.bundle_unlock
|
||||||
|
bx lr
|
||||||
|
# CHECK: LLVM ERROR: A Bundle can only have one Subtarget.
|
|
@ -0,0 +1,33 @@
|
||||||
|
# RUN: llvm-mc -filetype=obj -triple armv7-linux-gnueabi %s -o - \
|
||||||
|
# RUN: | llvm-objdump -no-show-raw-insn -triple armv7 -disassemble - | FileCheck %s
|
||||||
|
|
||||||
|
# We can switch subtargets with .arch outside of a bundle
|
||||||
|
.syntax unified
|
||||||
|
.text
|
||||||
|
.bundle_align_mode 4
|
||||||
|
.arch armv4t
|
||||||
|
bx lr
|
||||||
|
.bundle_lock
|
||||||
|
and r1, r1, r1
|
||||||
|
and r1, r1, r1
|
||||||
|
.bundle_unlock
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
# We can switch subtargets at the start of a bundle
|
||||||
|
bx lr
|
||||||
|
.bundle_lock align_to_end
|
||||||
|
.arch armv7a
|
||||||
|
movt r0, #0xffff
|
||||||
|
movw r0, #0xffff
|
||||||
|
.bundle_unlock
|
||||||
|
bx lr
|
||||||
|
|
||||||
|
# CHECK: 0: bx lr
|
||||||
|
# CHECK-NEXT: 4: and r1, r1, r1
|
||||||
|
# CHECK-NEXT: 8: and r1, r1, r1
|
||||||
|
# CHECK-NEXT: c: bx lr
|
||||||
|
# CHECK-NEXT: 10: bx lr
|
||||||
|
# CHECK-NEXT: 14: nop
|
||||||
|
# CHECK-NEXT: 18: movt r0, #65535
|
||||||
|
# CHECK-NEXT: 1c: movw r0, #65535
|
||||||
|
# CHECK-NEXT: 20: bx lr
|
|
@ -0,0 +1,20 @@
|
||||||
|
@ RUN: not llvm-mc -triple armv7a-linux-gnueabihf %s -filetype=obj -o %s.o 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
@ The relaxations should be applied using the subtarget from the fragment
|
||||||
|
@ containing the fixup and not the per module subtarget.
|
||||||
|
|
||||||
|
.syntax unified
|
||||||
|
.thumb
|
||||||
|
@ Place a literal pool out of range of the 16-bit ldr but within
|
||||||
|
@ range of the 32-bit ldr.w
|
||||||
|
.text
|
||||||
|
@ Relaxation to ldr.w as target triple supports Thumb2
|
||||||
|
ldr r0,=0x12345678
|
||||||
|
.arch armv4t
|
||||||
|
@ No relaxation as v4t does not support Thumb
|
||||||
|
@ expect out of range error message
|
||||||
|
ldr r0,=0x87654321
|
||||||
|
.space 1024
|
||||||
|
|
||||||
|
@ CHECK: error: out of range pc-relative fixup value
|
||||||
|
@ CHECK-NEXT: ldr r0,=0x87654321
|
|
@ -0,0 +1,16 @@
|
||||||
|
# RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu -mcpu=pentiumpro %s -o - 2>&1 | FileCheck %s
|
||||||
|
# RUN: not llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu -mcpu=pentiumpro -mc-relax-all %s -o - 2>&1 | FileCheck %s
|
||||||
|
|
||||||
|
# Switching mode will change subtarget, which we can't do within a bundle
|
||||||
|
.text
|
||||||
|
.code64
|
||||||
|
.bundle_align_mode 4
|
||||||
|
foo:
|
||||||
|
pushq %rbp
|
||||||
|
.bundle_lock
|
||||||
|
addl %ebp, %eax
|
||||||
|
.code32
|
||||||
|
movb $0x0, (%si)
|
||||||
|
.bundle_unlock
|
||||||
|
|
||||||
|
CHECK: LLVM ERROR: A Bundle can only have one Subtarget.
|
Loading…
Reference in New Issue