/// the offset specified by the fixup and following the fixup kind as
/// appropriate. Errors (such as an out of range fixup value) should be
/// 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,
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
/// symbols as a set of relocations.
/// Check whether the given instruction may need relaxation.
///
/// \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
/// associated instruction to be relaxed.
: MCEncodedFragmentWithContents<ContentsSize>(FType, HasInstructions,
Sec) {}
+ /// STI - The MCSubtargetInfo in effect when the instruction was encoded.
+ /// must be non-null for instructions.
+ const MCSubtargetInfo *STI = nullptr;
+
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 fixup_iterator = SmallVectorImpl<MCFixup>::iterator;
MCDataFragment(MCSection *Sec = nullptr)
: 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) {
return F->getKind() == MCFragment::FT_Data;
/// Inst - The instruction this is a fragment for.
MCInst Inst;
- /// STI - The MCSubtargetInfo in effect when the instruction was encoded.
- const MCSubtargetInfo &STI;
-
public:
MCRelaxableFragment(const MCInst &Inst, const MCSubtargetInfo &STI,
MCSection *Sec = nullptr)
: MCEncodedFragmentWithFixups(FT_Relaxable, true, Sec),
- Inst(Inst), STI(STI) {}
+ Inst(Inst) { this->STI = &STI; }
const MCInst &getInst() const { return Inst; }
void setInst(const MCInst &Value) { Inst = Value; }
- const MCSubtargetInfo &getSubtargetInfo() { return STI; }
-
static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Relaxable;
}
/// Get a data fragment to write into, creating a new one if the current
/// 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();
protected:
void EmitGPRel32Value(const MCExpr *Value) override;
void EmitGPRel64Value(const MCExpr *Value) override;
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;
void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
SMLoc Loc = SMLoc()) override;
/// Returns true if the relocation could not be emitted because Name is not
/// known.
virtual bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
- const MCExpr *Expr, SMLoc Loc) {
+ const MCExpr *Expr, SMLoc Loc,
+ const MCSubtargetInfo &STI) {
return true;
}
void EmitBundleUnlock() override;
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
/// string in the output .s file. This capability is indicated by the
}
bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
- const MCExpr *Expr, SMLoc) {
+ const MCExpr *Expr, SMLoc,
+ const MCSubtargetInfo &STI) {
OS << "\t.reloc ";
Offset.print(OS, MAI);
OS << ", " << Name;
continue;
ArrayRef<MCFixup> Fixups;
MutableArrayRef<char> Contents;
+ const MCSubtargetInfo *STI = nullptr;
if (auto *FragWithFixups = dyn_cast<MCDataFragment>(&Frag)) {
Fixups = FragWithFixups->getFixups();
Contents = FragWithFixups->getContents();
+ STI = FragWithFixups->getSubtargetInfo();
+ assert(!FragWithFixups->hasInstructions() || STI != nullptr);
} else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(&Frag)) {
Fixups = FragWithFixups->getFixups();
Contents = FragWithFixups->getContents();
+ STI = FragWithFixups->getSubtargetInfo();
+ assert(!FragWithFixups->hasInstructions() || STI != nullptr);
} else if (auto *FragWithFixups = dyn_cast<MCCVDefRangeFragment>(&Frag)) {
Fixups = FragWithFixups->getFixups();
Contents = FragWithFixups->getContents();
std::tie(Target, FixedValue, IsResolved) =
handleFixup(Layout, Frag, Fixup);
getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue,
- IsResolved);
+ IsResolved, STI);
}
}
}
// 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
// previous instruction to one that doesn't need relaxation.
- if (!getBackend().mayNeedRelaxation(F->getInst()))
+ if (!getBackend().mayNeedRelaxation(F->getInst(), *F->getSubtargetInfo()))
return false;
for (const MCFixup &Fixup : F->getFixups())
// Relax the fragment.
MCInst Relaxed;
- getBackend().relaxInstruction(F.getInst(), F.getSubtargetInfo(), Relaxed);
+ getBackend().relaxInstruction(F.getInst(), *F.getSubtargetInfo(), Relaxed);
// Encode the new instruction.
//
SmallVector<MCFixup, 4> Fixups;
SmallString<256> Code;
raw_svector_ostream VecOS(Code);
- getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, F.getSubtargetInfo());
+ getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, *F.getSubtargetInfo());
// Update the fragment.
F.setInst(Relaxed);
DF->getContents().size());
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());
}
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,
const MCSubtargetInfo &STI) {
MCAssembler &Assembler = getAssembler();
//
// 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
- // data fragment).
+ // data fragment, or the Subtarget has changed).
//
// If bundling is enabled:
// - If we're not in a bundle-locked group, emit the instruction into a
if (Assembler.isBundlingEnabled()) {
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
// the current bundle group.
DF = BundleGroups.back();
+ CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
+ }
else if (Assembler.getRelaxAll() && !isBundleLocked())
// 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
// the current fragment.
DF = new MCDataFragment();
- else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst())
+ else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) {
// If we are bundle-locked, we re-use the current fragment.
// The bundle-locking directive ensures this is a new data fragment.
DF = cast<MCDataFragment>(getCurrentFragment());
+ CheckBundleSubtargets(DF->getSubtargetInfo(), &STI);
+ }
else if (!isBundleLocked() && Fixups.size() == 0) {
// Optimize memory usage by emitting the instruction to a
// MCCompactEncodedInstFragment when not in a bundle-locked group and
// to be turned off.
Sec.setBundleGroupBeforeFirstInst(false);
} else {
- DF = getOrCreateDataFragment();
+ DF = getOrCreateDataFragment(&STI);
}
// Add the fixups and data.
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
DF->getFixups().push_back(Fixups[i]);
}
- DF->setHasInstructions(true);
+ DF->setHasInstructions(STI);
DF->getContents().append(Code.begin(), Code.end());
if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) {
if (!isBundleLocked()) {
- mergeFragment(getOrCreateDataFragment(), DF);
+ mergeFragment(getOrCreateDataFragment(&STI), DF);
delete DF;
}
}
// FIXME: Use more separate fragments for nested groups.
if (!isBundleLocked()) {
- mergeFragment(getOrCreateDataFragment(), DF);
+ mergeFragment(getOrCreateDataFragment(DF->getSubtargetInfo()), DF);
BundleGroups.pop_back();
delete DF;
}
Fixup.setOffset(Fixup.getOffset() + DF->getContents().size());
DF->getFixups().push_back(Fixup);
}
+ DF->setHasInstructions(STI);
DF->getContents().append(Code.begin(), Code.end());
}
return nullptr;
}
-MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() {
- MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
+static bool CanReuseDataFragment(const MCDataFragment &F,
+ 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
// already has instructions (see MCELFStreamer::EmitInstToData for details)
- if (!F || (Assembler->isBundlingEnabled() && !Assembler->getRelaxAll() &&
- F->hasInstructions())) {
+ if (Assembler.isBundlingEnabled())
+ 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();
insert(F);
}
// If this instruction doesn't need relaxation, just emit it as data.
MCAssembler &Assembler = getAssembler();
- if (!Assembler.getBackend().mayNeedRelaxation(Inst)) {
+ if (!Assembler.getBackend().mayNeedRelaxation(Inst, STI)) {
EmitInstToData(Inst, STI);
return;
}
(Assembler.isBundlingEnabled() && Sec->isBundleLocked())) {
MCInst Relaxed;
getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed);
- while (getAssembler().getBackend().mayNeedRelaxation(Relaxed))
+ while (getAssembler().getBackend().mayNeedRelaxation(Relaxed, STI))
getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed);
EmitInstToData(Relaxed, STI);
return;
}
bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
- const MCExpr *Expr, SMLoc Loc) {
+ const MCExpr *Expr, SMLoc Loc,
+ const MCSubtargetInfo &STI) {
int64_t OffsetValue;
if (!Offset.evaluateAsAbsolute(OffsetValue))
llvm_unreachable("Offset is not absolute");
if (OffsetValue < 0)
llvm_unreachable("Offset is negative");
- MCDataFragment *DF = getOrCreateDataFragment();
+ MCDataFragment *DF = getOrCreateDataFragment(&STI);
flushPendingLabels(DF, DF->getContents().size());
Optional<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name);
"unexpected token in .reloc directive"))
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 false;
DF->getContents().size());
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());
}
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
DF->getFixups().push_back(Fixups[i]);
}
- DF->setHasInstructions(true);
+ DF->setHasInstructions(STI);
DF->getContents().append(Code.begin(), Code.end());
}
Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
DF->getFixups().push_back(Fixups[i]);
}
-
+ DF->setHasInstructions(STI);
DF->getContents().append(Code.begin(), Code.end());
}
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override;
void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
- bool IsResolved) const {
+ bool IsResolved,
+ const MCSubtargetInfo *STI) const {
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
if (!Value)
return; // Doesn't change encoding.
}
}
-bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
+bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const {
return false;
}
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override {
MCInst &Res) const override {
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;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
- bool IsResolved) const {
+ bool IsResolved,
+ const MCSubtargetInfo *STI) const {
Value = adjustFixupValue(Fixup, Value, &Asm.getContext());
if (!Value)
return; // Doesn't change encoding.
}
}
-unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op) const {
+unsigned ARMAsmBackend::getRelaxedOpcode(unsigned Op,
+ const MCSubtargetInfo &STI) const {
bool HasThumb2 = STI.getFeatureBits()[ARM::FeatureThumb2];
bool HasV8MBaselineOps = STI.getFeatureBits()[ARM::HasV8MBaselineOps];
}
}
-bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst) const {
- if (getRelaxedOpcode(Inst.getOpcode()) != Inst.getOpcode())
+bool ARMAsmBackend::mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const {
+ if (getRelaxedOpcode(Inst.getOpcode(), STI) != Inst.getOpcode())
return true;
return false;
}
void ARMAsmBackend::relaxInstruction(const MCInst &Inst,
const MCSubtargetInfo &STI,
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.
if (RelaxedOp == Inst.getOpcode()) {
unsigned ARMAsmBackend::adjustFixupValue(const MCAssembler &Asm,
const MCFixup &Fixup,
const MCValue &Target, uint64_t Value,
- bool IsResolved, MCContext &Ctx) const {
+ bool IsResolved, MCContext &Ctx,
+ const MCSubtargetInfo* STI) const {
unsigned Kind = Fixup.getKind();
// MachO tries to make .o files that look vaguely pre-linked, so for MOVW/MOVT
case FK_SecRel_4:
return Value;
case ARM::fixup_arm_movt_hi16:
- if (IsResolved || !STI.getTargetTriple().isOSBinFormatELF())
+ assert(STI != nullptr);
+ if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
Value >>= 16;
LLVM_FALLTHROUGH;
case ARM::fixup_arm_movw_lo16: {
return Value;
}
case ARM::fixup_t2_movt_hi16:
- if (IsResolved || !STI.getTargetTriple().isOSBinFormatELF())
+ assert(STI != nullptr);
+ if (IsResolved || !STI->getTargetTriple().isOSBinFormatELF())
Value >>= 16;
LLVM_FALLTHROUGH;
case ARM::fixup_t2_movw_lo16: {
}
case ARM::fixup_arm_thumb_bl: {
if (!isInt<25>(Value - 4) ||
- (!STI.getFeatureBits()[ARM::FeatureThumb2] &&
- !STI.getFeatureBits()[ARM::HasV8MBaselineOps] &&
- !STI.getFeatureBits()[ARM::HasV6MOps] &&
+ (!STI->getFeatureBits()[ARM::FeatureThumb2] &&
+ !STI->getFeatureBits()[ARM::HasV8MBaselineOps] &&
+ !STI->getFeatureBits()[ARM::HasV6MOps] &&
!isInt<23>(Value - 4))) {
Ctx.reportError(Fixup.getLoc(), "Relocation out of range");
return 0;
case ARM::fixup_arm_thumb_cp:
// On CPUs supporting Thumb2, this will be relaxed to an ldr.w, otherwise we
// 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);
if (FixupDiagnostic) {
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
}
case ARM::fixup_arm_thumb_br:
// Offset by 4 and don't encode the lower bit, which is always 0.
- if (!STI.getFeatureBits()[ARM::FeatureThumb2] &&
- !STI.getFeatureBits()[ARM::HasV8MBaselineOps]) {
+ assert(STI != nullptr);
+ if (!STI->getFeatureBits()[ARM::FeatureThumb2] &&
+ !STI->getFeatureBits()[ARM::HasV8MBaselineOps]) {
const char *FixupDiagnostic = reasonForFixupRelaxation(Fixup, Value);
if (FixupDiagnostic) {
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
return ((Value - 4) >> 1) & 0x7ff;
case ARM::fixup_arm_thumb_bcc:
// 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);
if (FixupDiagnostic) {
Ctx.reportError(Fixup.getLoc(), FixupDiagnostic);
void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
- bool IsResolved) const {
+ bool IsResolved,
+ const MCSubtargetInfo* STI) const {
unsigned NumBytes = getFixupKindNumBytes(Fixup.getKind());
MCContext &Ctx = Asm.getContext();
- Value = adjustFixupValue(Asm, Fixup, Target, Value, IsResolved, Ctx);
+ Value = adjustFixupValue(Asm, Fixup, Target, Value, IsResolved, Ctx, STI);
if (!Value)
return; // Doesn't change encoding.
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:
return ARM::NumTargetFixupKinds;
}
+ // FIXME: this should be calculated per fragment as the STI may be
+ // different.
bool hasNOP() const { return STI.getFeatureBits()[ARM::HasV6T2Ops]; }
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
unsigned adjustFixupValue(const MCAssembler &Asm, const MCFixup &Fixup,
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,
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,
uint64_t Value) const;
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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>
createObjectTargetWriter() const override;
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,
MCInst &Res) const override {}
void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
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) {
assert(Value == 0);
} else if (Fixup.getKind() == FK_Data_4) {
SmallVector<MCFixup, 4> Fixups;
SmallString<256> Code;
raw_svector_ostream VecOS(Code);
- E.encodeInstruction(HMB, VecOS, Fixups, RF.getSubtargetInfo());
+ E.encodeInstruction(HMB, VecOS, Fixups, *RF.getSubtargetInfo());
// Update the fragment.
RF.setInst(HMB);
/// fixup kind as appropriate.
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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
// is nothing for us to do.
/// relaxation.
///
/// \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;
}
Inst.addOperand(MCOperand::createInst(Nop));
Size -= 4;
if (!HexagonMCChecker(
- Context, *MCII, RF.getSubtargetInfo(), Inst,
+ Context, *MCII, *RF.getSubtargetInfo(), Inst,
*Context.getRegisterInfo(), false)
.check()) {
Inst.erase(Inst.end() - 1);
}
}
bool Error = HexagonMCShuffle(Context, true, *MCII,
- RF.getSubtargetInfo(), Inst);
+ *RF.getSubtargetInfo(), Inst);
//assert(!Error);
(void)Error;
ReplaceInstruction(Asm.getEmitter(), RF, Inst);
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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>
createObjectTargetWriter() const override;
return Lanai::NumTargetFixupKinds;
}
- bool mayNeedRelaxation(const MCInst & /*Inst*/) const override {
+ bool mayNeedRelaxation(const MCInst & /*Inst*/,
+ const MCSubtargetInfo &STI) const override {
return false;
}
void LanaiAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
- bool /*IsResolved*/) const {
+ bool /*IsResolved*/,
+ const MCSubtargetInfo */*STI*/) const {
MCFixupKind Kind = Fixup.getKind();
Value = adjustFixupValue(static_cast<unsigned>(Kind), Value);
void MipsAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
- bool IsResolved) const {
+ bool IsResolved,
+ const MCSubtargetInfo *STI) const {
MCFixupKind Kind = Fixup.getKind();
MCContext &Ctx = Asm.getContext();
Value = adjustFixupValue(Fixup, Value, Ctx);
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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;
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
/// relaxation.
///
/// \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;
}
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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);
if (!Value) return; // Doesn't change encoding.
}
}
- bool mayNeedRelaxation(const MCInst &Inst) const override {
+ bool mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const override {
// FIXME.
return false;
}
}
}
- bool mayNeedRelaxation(const MCInst &Inst) const override {
+ bool mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const override {
// FIXME.
return false;
}
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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);
if (!Value) return; // Doesn't change encoding.
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
- uint64_t Value, bool IsResolved) const override;
- bool mayNeedRelaxation(const MCInst &Inst) const override {
+ uint64_t Value, bool IsResolved,
+ const MCSubtargetInfo *STI) const override;
+ bool mayNeedRelaxation(const MCInst &Inst,
+ const MCSubtargetInfo &STI) const override {
return false;
}
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
- bool IsResolved) const {
+ bool IsResolved,
+ const MCSubtargetInfo *STI) const {
MCFixupKind Kind = Fixup.getKind();
unsigned Offset = Fixup.getOffset();
unsigned BitSize = getFixupKindInfo(Kind).TargetSize;
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
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());
assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!");
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,
const MCRelaxableFragment *DF,
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.
if (getRelaxedOpcodeBranch(Inst, false) != Inst.getOpcode())
return true;
--- /dev/null
+; 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 }
--- /dev/null
+# 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.
--- /dev/null
+# 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
--- /dev/null
+@ 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
--- /dev/null
+# 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.