Index: llvm/trunk/include/llvm/MC/MCAsmBackend.h =================================================================== --- llvm/trunk/include/llvm/MC/MCAsmBackend.h +++ llvm/trunk/include/llvm/MC/MCAsmBackend.h @@ -92,9 +92,12 @@ /// 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 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. @@ -108,7 +111,10 @@ /// 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. Index: llvm/trunk/include/llvm/MC/MCFragment.h =================================================================== --- llvm/trunk/include/llvm/MC/MCFragment.h +++ llvm/trunk/include/llvm/MC/MCFragment.h @@ -201,7 +201,16 @@ : MCEncodedFragmentWithContents(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::const_iterator; using fixup_iterator = SmallVectorImpl::iterator; @@ -228,7 +237,12 @@ 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; @@ -259,20 +273,15 @@ /// 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; } Index: llvm/trunk/include/llvm/MC/MCObjectStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCObjectStreamer.h +++ llvm/trunk/include/llvm/MC/MCObjectStreamer.h @@ -73,7 +73,9 @@ /// 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: @@ -158,7 +160,8 @@ 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; Index: llvm/trunk/include/llvm/MC/MCStreamer.h =================================================================== --- llvm/trunk/include/llvm/MC/MCStreamer.h +++ llvm/trunk/include/llvm/MC/MCStreamer.h @@ -918,7 +918,8 @@ /// 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; } Index: llvm/trunk/lib/MC/MCAsmStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCAsmStreamer.cpp +++ llvm/trunk/lib/MC/MCAsmStreamer.cpp @@ -315,7 +315,8 @@ 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 @@ -1820,7 +1821,8 @@ } 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; Index: llvm/trunk/lib/MC/MCAssembler.cpp =================================================================== --- llvm/trunk/lib/MC/MCAssembler.cpp +++ llvm/trunk/lib/MC/MCAssembler.cpp @@ -805,12 +805,17 @@ continue; ArrayRef Fixups; MutableArrayRef Contents; + const MCSubtargetInfo *STI = nullptr; if (auto *FragWithFixups = dyn_cast(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); + STI = FragWithFixups->getSubtargetInfo(); + assert(!FragWithFixups->hasInstructions() || STI != nullptr); } else if (auto *FragWithFixups = dyn_cast(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); + STI = FragWithFixups->getSubtargetInfo(); + assert(!FragWithFixups->hasInstructions() || STI != nullptr); } else if (auto *FragWithFixups = dyn_cast(&Frag)) { Fixups = FragWithFixups->getFixups(); Contents = FragWithFixups->getContents(); @@ -823,7 +828,7 @@ std::tie(Target, FixedValue, IsResolved) = handleFixup(Layout, Frag, Fixup); getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue, - IsResolved); + IsResolved, STI); } } } @@ -860,7 +865,7 @@ // 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()) @@ -885,7 +890,7 @@ // Relax the fragment. MCInst Relaxed; - getBackend().relaxInstruction(F.getInst(), F.getSubtargetInfo(), Relaxed); + getBackend().relaxInstruction(F.getInst(), *F.getSubtargetInfo(), Relaxed); // Encode the new instruction. // @@ -894,7 +899,7 @@ SmallVector 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); Index: llvm/trunk/lib/MC/MCELFStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCELFStreamer.cpp +++ llvm/trunk/lib/MC/MCELFStreamer.cpp @@ -83,7 +83,8 @@ 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()); } @@ -493,6 +494,15 @@ 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(); @@ -508,7 +518,7 @@ // // 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 @@ -523,19 +533,23 @@ 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(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 @@ -560,7 +574,7 @@ // to be turned off. Sec.setBundleGroupBeforeFirstInst(false); } else { - DF = getOrCreateDataFragment(); + DF = getOrCreateDataFragment(&STI); } // Add the fixups and data. @@ -568,12 +582,12 @@ 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; } } @@ -633,7 +647,7 @@ // FIXME: Use more separate fragments for nested groups. if (!isBundleLocked()) { - mergeFragment(getOrCreateDataFragment(), DF); + mergeFragment(getOrCreateDataFragment(DF->getSubtargetInfo()), DF); BundleGroups.pop_back(); delete DF; } Index: llvm/trunk/lib/MC/MCMachOStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCMachOStreamer.cpp +++ llvm/trunk/lib/MC/MCMachOStreamer.cpp @@ -450,6 +450,7 @@ Fixup.setOffset(Fixup.getOffset() + DF->getContents().size()); DF->getFixups().push_back(Fixup); } + DF->setHasInstructions(STI); DF->getContents().append(Code.begin(), Code.end()); } Index: llvm/trunk/lib/MC/MCObjectStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCObjectStreamer.cpp +++ llvm/trunk/lib/MC/MCObjectStreamer.cpp @@ -146,12 +146,24 @@ return nullptr; } -MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() { - MCDataFragment *F = dyn_cast_or_null(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(getCurrentFragment()); + if (!F || !CanReuseDataFragment(*F, *Assembler, STI)) { F = new MCDataFragment(); insert(F); } @@ -327,7 +339,7 @@ // 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; } @@ -341,7 +353,7 @@ (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; @@ -606,7 +618,8 @@ } 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"); @@ -614,7 +627,7 @@ if (OffsetValue < 0) llvm_unreachable("Offset is negative"); - MCDataFragment *DF = getOrCreateDataFragment(); + MCDataFragment *DF = getOrCreateDataFragment(&STI); flushPendingLabels(DF, DF->getContents().size()); Optional MaybeKind = Assembler->getBackend().getFixupKind(Name); Index: llvm/trunk/lib/MC/MCParser/AsmParser.cpp =================================================================== --- llvm/trunk/lib/MC/MCParser/AsmParser.cpp +++ llvm/trunk/lib/MC/MCParser/AsmParser.cpp @@ -2949,7 +2949,9 @@ "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; Index: llvm/trunk/lib/MC/MCWasmStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCWasmStreamer.cpp +++ llvm/trunk/lib/MC/MCWasmStreamer.cpp @@ -45,7 +45,8 @@ 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()); } @@ -183,7 +184,7 @@ 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()); } Index: llvm/trunk/lib/MC/MCWinCOFFStreamer.cpp =================================================================== --- llvm/trunk/lib/MC/MCWinCOFFStreamer.cpp +++ llvm/trunk/lib/MC/MCWinCOFFStreamer.cpp @@ -63,7 +63,7 @@ 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()); } Index: llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -73,9 +73,11 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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; @@ -285,7 +287,8 @@ void AArch64AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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. @@ -321,7 +324,8 @@ } } -bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst) const { +bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const { return false; } Index: llvm/trunk/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp +++ llvm/trunk/lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp @@ -32,7 +32,8 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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 { @@ -42,7 +43,10 @@ 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; @@ -102,7 +106,8 @@ void AMDGPUAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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. Index: llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h =================================================================== --- llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h +++ llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h @@ -19,6 +19,9 @@ 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: @@ -31,6 +34,8 @@ 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; @@ -40,15 +45,18 @@ 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 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; Index: llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ llvm/trunk/lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -173,7 +173,8 @@ } } -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]; @@ -195,8 +196,9 @@ } } -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; } @@ -263,7 +265,7 @@ 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()) { @@ -360,7 +362,8 @@ 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 @@ -389,7 +392,8 @@ 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: { @@ -401,7 +405,8 @@ 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: { @@ -529,9 +534,9 @@ } 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; @@ -603,7 +608,8 @@ 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); @@ -627,8 +633,9 @@ } 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); @@ -638,7 +645,8 @@ 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); @@ -894,10 +902,11 @@ void ARMAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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. Index: llvm/trunk/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp +++ llvm/trunk/lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -27,7 +27,8 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, - uint64_t Value, bool IsResolved) const override; + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override; std::unique_ptr createObjectTargetWriter() const override; @@ -41,7 +42,10 @@ 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 {} @@ -64,7 +68,8 @@ void BPFAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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) { Index: llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp +++ llvm/trunk/lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp @@ -51,7 +51,7 @@ SmallVector 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); @@ -414,7 +414,8 @@ /// fixup kind as appropriate. void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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. @@ -561,7 +562,8 @@ /// 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; } @@ -736,7 +738,7 @@ 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); @@ -744,7 +746,7 @@ } } bool Error = HexagonMCShuffle(Context, true, *MCII, - RF.getSubtargetInfo(), Inst); + *RF.getSubtargetInfo(), Inst); //assert(!Error); (void)Error; ReplaceInstruction(Asm.getEmitter(), RF, Inst); Index: llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp +++ llvm/trunk/lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp @@ -51,7 +51,8 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, - uint64_t Value, bool IsResolved) const override; + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override; std::unique_ptr createObjectTargetWriter() const override; @@ -69,7 +70,8 @@ return Lanai::NumTargetFixupKinds; } - bool mayNeedRelaxation(const MCInst & /*Inst*/) const override { + bool mayNeedRelaxation(const MCInst & /*Inst*/, + const MCSubtargetInfo &STI) const override { return false; } @@ -93,7 +95,8 @@ void LanaiAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, uint64_t Value, - bool /*IsResolved*/) const { + bool /*IsResolved*/, + const MCSubtargetInfo */*STI*/) const { MCFixupKind Kind = Fixup.getKind(); Value = adjustFixupValue(static_cast(Kind), Value); Index: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h =================================================================== --- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -42,7 +42,8 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef Data, - uint64_t Value, bool IsResolved) const override; + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override; Optional getFixupKind(StringRef Name) const override; const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; @@ -58,7 +59,8 @@ /// 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; } Index: llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp +++ llvm/trunk/lib/Target/Mips/MCTargetDesc/MipsAsmBackend.cpp @@ -243,7 +243,8 @@ void MipsAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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); Index: llvm/trunk/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ llvm/trunk/lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -117,7 +117,8 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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. @@ -157,7 +158,8 @@ } } - bool mayNeedRelaxation(const MCInst &Inst) const override { + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { // FIXME. return false; } Index: llvm/trunk/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ llvm/trunk/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -233,7 +233,8 @@ } } - bool mayNeedRelaxation(const MCInst &Inst) const override { + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { // FIXME. return false; } @@ -275,7 +276,8 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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. Index: llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp +++ llvm/trunk/lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -53,8 +53,10 @@ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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, @@ -96,7 +98,8 @@ const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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; Index: llvm/trunk/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp =================================================================== --- llvm/trunk/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ llvm/trunk/lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -101,7 +101,8 @@ void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, const MCValue &Target, MutableArrayRef 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!"); @@ -117,7 +118,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, const MCRelaxableFragment *DF, @@ -264,7 +266,8 @@ 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; Index: llvm/trunk/test/CodeGen/ARM/relax-per-target-feature.ll =================================================================== --- llvm/trunk/test/CodeGen/ARM/relax-per-target-feature.ll +++ llvm/trunk/test/CodeGen/ARM/relax-per-target-feature.ll @@ -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 } Index: llvm/trunk/test/MC/ARM/AlignedBundling/illegal-subtarget-change.s =================================================================== --- llvm/trunk/test/MC/ARM/AlignedBundling/illegal-subtarget-change.s +++ llvm/trunk/test/MC/ARM/AlignedBundling/illegal-subtarget-change.s @@ -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. Index: llvm/trunk/test/MC/ARM/AlignedBundling/subtarget-change.s =================================================================== --- llvm/trunk/test/MC/ARM/AlignedBundling/subtarget-change.s +++ llvm/trunk/test/MC/ARM/AlignedBundling/subtarget-change.s @@ -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 Index: llvm/trunk/test/MC/ARM/fixup-per-fragment.s =================================================================== --- llvm/trunk/test/MC/ARM/fixup-per-fragment.s +++ llvm/trunk/test/MC/ARM/fixup-per-fragment.s @@ -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 Index: llvm/trunk/test/MC/X86/AlignedBundling/bundle-subtarget-change-error.s =================================================================== --- llvm/trunk/test/MC/X86/AlignedBundling/bundle-subtarget-change-error.s +++ llvm/trunk/test/MC/X86/AlignedBundling/bundle-subtarget-change-error.s @@ -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.