Index: include/llvm/MC/MCAsmBackend.h =================================================================== --- include/llvm/MC/MCAsmBackend.h +++ include/llvm/MC/MCAsmBackend.h @@ -92,7 +92,8 @@ /// Check whether the given instruction may need relaxation. /// /// \param Inst - The instruction to test. - virtual bool mayNeedRelaxation(const MCInst &Inst) const = 0; + 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: include/llvm/MC/MCFragment.h =================================================================== --- include/llvm/MC/MCFragment.h +++ include/llvm/MC/MCFragment.h @@ -271,7 +271,7 @@ const MCInst &getInst() const { return Inst; } void setInst(const MCInst &Value) { Inst = Value; } - const MCSubtargetInfo &getSubtargetInfo() { return STI; } + const MCSubtargetInfo &getSubtargetInfo() const { return STI; } static bool classof(const MCFragment *F) { return F->getKind() == MCFragment::FT_Relaxable; Index: lib/MC/MCAssembler.cpp =================================================================== --- lib/MC/MCAssembler.cpp +++ lib/MC/MCAssembler.cpp @@ -804,7 +804,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()) Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -292,7 +292,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; } @@ -306,7 +306,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; Index: lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp =================================================================== --- lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp +++ lib/Target/AArch64/MCTargetDesc/AArch64AsmBackend.cpp @@ -77,7 +77,8 @@ const MCValue &Target, MutableArrayRef Data, uint64_t Value, bool IsResolved) 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; @@ -323,7 +324,8 @@ } } -bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst) const { +bool AArch64AsmBackend::mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const { return false; } Index: lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp =================================================================== --- lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp +++ lib/Target/AMDGPU/MCTargetDesc/AMDGPUAsmBackend.cpp @@ -43,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(uint64_t Count, MCObjectWriter *OW) const override; Index: lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h +++ lib/Target/ARM/MCTargetDesc/ARMAsmBackend.h @@ -48,9 +48,10 @@ const MCValue &Target, MutableArrayRef Data, uint64_t Value, bool IsResolved) 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: lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp +++ lib/Target/ARM/MCTargetDesc/ARMAsmBackend.cpp @@ -171,7 +171,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]; @@ -193,8 +194,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; } @@ -261,7 +263,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()) { Index: lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp =================================================================== --- lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp +++ lib/Target/BPF/MCTargetDesc/BPFAsmBackend.cpp @@ -43,7 +43,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 {} Index: lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp =================================================================== --- lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp +++ lib/Target/Hexagon/MCTargetDesc/HexagonAsmBackend.cpp @@ -562,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; } Index: lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp =================================================================== --- lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp +++ lib/Target/Lanai/MCTargetDesc/LanaiAsmBackend.cpp @@ -69,7 +69,8 @@ return Lanai::NumTargetFixupKinds; } - bool mayNeedRelaxation(const MCInst & /*Inst*/) const override { + bool mayNeedRelaxation(const MCInst & /*Inst*/, + const MCSubtargetInfo &STI) const override { return false; } Index: lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h =================================================================== --- lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h +++ lib/Target/Mips/MCTargetDesc/MipsAsmBackend.h @@ -58,7 +58,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: lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp =================================================================== --- lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp +++ lib/Target/PowerPC/MCTargetDesc/PPCAsmBackend.cpp @@ -156,7 +156,8 @@ } } - bool mayNeedRelaxation(const MCInst &Inst) const override { + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { // FIXME. return false; } Index: lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp =================================================================== --- lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -234,7 +234,8 @@ } } - bool mayNeedRelaxation(const MCInst &Inst) const override { + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { // FIXME. return false; } Index: lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp =================================================================== --- lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp +++ lib/Target/SystemZ/MCTargetDesc/SystemZMCAsmBackend.cpp @@ -54,7 +54,8 @@ 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 { + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override { return false; } bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, Index: lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp =================================================================== --- lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp +++ lib/Target/X86/MCTargetDesc/X86AsmBackend.cpp @@ -117,7 +117,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 +265,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: test/CodeGen/ARM/relax-per-target-feature.ll =================================================================== --- /dev/null +++ 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 }