https://github.com/RKSimon updated https://github.com/llvm/llvm-project/pull/180242
>From 6cd2ccf54fdf7ef91bd8da37e3c7ba35d17739b7 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan <[email protected]> Date: Sat, 7 Feb 2026 00:09:33 +0800 Subject: [PATCH 1/2] [X86] support reserve r8~r15 on X86_64 Add new options -ffixed_r{8~15} for clang X86 target, like option "-ffixed_x" for RISCV/AArch64 target. Also, add target-feature +reserve-r{8~15} for the X86 backend. The registers which are specified reserved will not be used in RegAlloc/CalleeSave. Then the reserved registers can be maintained by user. It will be useful for the runtime/interpreter implementation. Other registers are used in specific instructions or mechanism, so they can't be reserved. Signed-off-by: ZhouGuangyuan <[email protected]> --- clang/include/clang/Options/Options.td | 8 +- clang/lib/Basic/Targets/X86.h | 7 ++ clang/lib/Driver/ToolChains/Arch/X86.cpp | 14 ++++ clang/test/Driver/x86_64-fixed-r-register.c | 65 ++++++++++++++ llvm/lib/Target/X86/X86.td | 4 + llvm/lib/Target/X86/X86FrameLowering.cpp | 8 ++ llvm/lib/Target/X86/X86ISelLowering.cpp | 12 +++ llvm/lib/Target/X86/X86RegisterInfo.cpp | 11 +++ llvm/lib/Target/X86/X86Subtarget.cpp | 3 +- llvm/lib/Target/X86/X86Subtarget.h | 8 ++ llvm/test/CodeGen/X86/reserveRreg.ll | 93 +++++++++++++++++++++ 11 files changed, 230 insertions(+), 3 deletions(-) create mode 100644 clang/test/Driver/x86_64-fixed-r-register.c create mode 100644 llvm/test/CodeGen/X86/reserveRreg.ll diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 1021d95e4005b..d71c599e3ac9a 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -5526,8 +5526,8 @@ def mrestrict_it: Flag<["-"], "mrestrict-it">, Group<m_arm_Features_Group>, def mno_restrict_it: Flag<["-"], "mno-restrict-it">, Group<m_arm_Features_Group>, HelpText<"Allow generation of complex IT blocks.">; def marm : Flag<["-"], "marm">, Alias<mno_thumb>; -def ffixed_r9 : Flag<["-"], "ffixed-r9">, Group<m_arm_Features_Group>, - HelpText<"Reserve the r9 register (ARM only)">; +def ffixed_r9 : Flag<["-"], "ffixed-r9">, Group<m_Group>, + HelpText<"Reserve the r9 register (ARM/x86_64 only)">; def mno_movt : Flag<["-"], "mno-movt">, Group<m_arm_Features_Group>, HelpText<"Disallow use of movt/movw pairs (ARM only)">; def mcrc : Flag<["-"], "mcrc">, Group<m_Group>, @@ -7168,6 +7168,10 @@ def mapxf : Flag<["-"], "mapxf">, Group<m_x86_Features_Group>; def mno_apxf : Flag<["-"], "mno-apxf">, Group<m_x86_Features_Group>; def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group<m_Group>, HelpText<"Enable use of GPR32 in inline assembly for APX">; +foreach i = {8, 10-15} in + def ffixed_r#i : Flag<["-"], "ffixed-r"#i>, Group<m_Group>, + HelpText<"Reserve the r"#i#" register (x86_64 only)">; + } // let Flags = [TargetSpecific] // VE feature flags diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 922e32906cd04..65617e4fcea21 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -807,6 +807,13 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo { return true; } + StringRef Reg64 = RegName; + if (Reg64.back() == 'd' || Reg64.back() == 'w' || Reg64.back() == 'b') { + Reg64 = Reg64.substr(0, Reg64.size() - 1); + } + if (getTargetOpts().FeatureMap.lookup(("reserve-" + Reg64).str())) + return true; + // Check if the register is a 32-bit register the backend can handle. return X86TargetInfo::validateGlobalRegisterVariable(RegName, RegSize, HasSizeMismatch); diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 61d512f9e093f..c4ccddffca9fa 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -332,4 +332,18 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, if (A->getOption().matches(options::OPT_m3dnow)) D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); } + + // Handle features corresponding to "-ffixed-X" options +#define RESERVE_REG(REG) \ + if (Args.hasArg(options::OPT_ffixed_##REG)) \ + Features.push_back("+reserve-" #REG); + RESERVE_REG(r8) + RESERVE_REG(r9) + RESERVE_REG(r10) + RESERVE_REG(r11) + RESERVE_REG(r12) + RESERVE_REG(r13) + RESERVE_REG(r14) + RESERVE_REG(r15) +#undef RESERVE_REG } diff --git a/clang/test/Driver/x86_64-fixed-r-register.c b/clang/test/Driver/x86_64-fixed-r-register.c new file mode 100644 index 0000000000000..714db3fdfdc91 --- /dev/null +++ b/clang/test/Driver/x86_64-fixed-r-register.c @@ -0,0 +1,65 @@ +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r8 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R8 < %t %s +// CHECK-FIXED-R8: "-target-feature" "+reserve-r8" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r9 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R9 < %t %s +// CHECK-FIXED-R9: "-target-feature" "+reserve-r9" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r10 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R10 < %t %s +// CHECK-FIXED-R10: "-target-feature" "+reserve-r10" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r11 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R11 < %t %s +// CHECK-FIXED-R11: "-target-feature" "+reserve-r11" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r12 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R12 < %t %s +// CHECK-FIXED-R12: "-target-feature" "+reserve-r12" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r13 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R13 < %t %s +// CHECK-FIXED-R13: "-target-feature" "+reserve-r13" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r14 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R14 < %t %s +// CHECK-FIXED-R14: "-target-feature" "+reserve-r14" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -ffixed-r15 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R15 < %t %s +// CHECK-FIXED-R15: "-target-feature" "+reserve-r15" + +// Test multiple of reserve-r# options together. +// RUN: %clang --target=x86_64-unknown-linux-gnu \ +// RUN: -ffixed-r8 \ +// RUN: -ffixed-r9 \ +// RUN: -ffixed-r15 \ +// RUN: -### %s 2> %t +// RUN: FileCheck \ +// RUN: --check-prefix=CHECK-FIXED-R8 \ +// RUN: --check-prefix=CHECK-FIXED-R9 \ +// RUN: --check-prefix=CHECK-FIXED-R15 \ +// RUN: < %t %s + +// Test all reserve-r# options together. +// RUN: %clang --target=x86_64-unknown-linux-gnu \ +// RUN: -ffixed-r8 \ +// RUN: -ffixed-r9 \ +// RUN: -ffixed-r10 \ +// RUN: -ffixed-r11 \ +// RUN: -ffixed-r12 \ +// RUN: -ffixed-r13 \ +// RUN: -ffixed-r14 \ +// RUN: -ffixed-r15 \ +// RUN: -### %s 2> %t +// RUN: FileCheck \ +// RUN: --check-prefix=CHECK-FIXED-R8 \ +// RUN: --check-prefix=CHECK-FIXED-R9 \ +// RUN: --check-prefix=CHECK-FIXED-R10 \ +// RUN: --check-prefix=CHECK-FIXED-R11 \ +// RUN: --check-prefix=CHECK-FIXED-R12 \ +// RUN: --check-prefix=CHECK-FIXED-R13 \ +// RUN: --check-prefix=CHECK-FIXED-R14 \ +// RUN: --check-prefix=CHECK-FIXED-R15 \ +// RUN: < %t %s diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td index fa41d7a7a7c5e..e4eafc3487f37 100644 --- a/llvm/lib/Target/X86/X86.td +++ b/llvm/lib/Target/X86/X86.td @@ -32,6 +32,10 @@ def IsX32 : SubtargetFeature<"x32", "IsX32", "true", // X86 Subtarget ISA features //===----------------------------------------------------------------------===// +foreach i = {8-15} in + def FeatureReserveR#i : SubtargetFeature<"reserve-r"#i, "ReservedRReg[X86::R"#i#"]", "true", + "Reserve R"#i#", making it unavailable as a GPR">; + def FeatureX87 : SubtargetFeature<"x87","HasX87", "true", "Enable X87 float instructions">; diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp index 8bca6344d6521..8791470b0b5e1 100644 --- a/llvm/lib/Target/X86/X86FrameLowering.cpp +++ b/llvm/lib/Target/X86/X86FrameLowering.cpp @@ -3211,6 +3211,14 @@ void X86FrameLowering::determineCalleeSaves(MachineFunction &MF, BasePtr = getX86SubSuperRegister(BasePtr, 64); SavedRegs.set(BasePtr); } + if (STI.is64Bit()) { + for (int Reg = SavedRegs.find_first(); Reg != -1; + Reg = SavedRegs.find_next(Reg)) { + if (STI.isRegisterReservedByUser(Reg)) { + SavedRegs.reset(Reg); + } + } + } } static bool HasNestArgument(const MachineFunction *MF) { diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 2188f6466682b..42c4ac3b943c3 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -28732,6 +28732,9 @@ SDValue X86TargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const { return FrameAddr; } +#define GET_REGISTER_MATCHER +#include "X86GenAsmMatcher.inc" + // FIXME? Maybe this could be a TableGen attribute on some registers and // this table could be generated automatically from RegInfo. Register X86TargetLowering::getRegisterByName(const char* RegName, LLT VT, @@ -28761,6 +28764,15 @@ Register X86TargetLowering::getRegisterByName(const char* RegName, LLT VT, #endif } + if (Reg) + return Reg; + + if (Subtarget.is64Bit()) { + Reg = MatchRegisterName(RegName); + if (!Subtarget.isRegisterReservedByUser(Reg)) + Reg = Register(); + } + return Reg; } diff --git a/llvm/lib/Target/X86/X86RegisterInfo.cpp b/llvm/lib/Target/X86/X86RegisterInfo.cpp index 72f38133e21ff..42d1bedb350f6 100644 --- a/llvm/lib/Target/X86/X86RegisterInfo.cpp +++ b/llvm/lib/Target/X86/X86RegisterInfo.cpp @@ -515,6 +515,17 @@ BitVector X86RegisterInfo::getReservedRegs(const MachineFunction &MF) const { // Set the Shadow Stack Pointer as reserved. Reserved.set(X86::SSP); + auto &ST = MF.getSubtarget<X86Subtarget>(); + if (ST.is64Bit()) { + for (size_t Reg = 0; Reg < getNumRegs(); Reg++) { + // Set r# as reserved register if user required + if (ST.isRegisterReservedByUser(Reg)) { + for (const MCPhysReg &SubReg : subregs_inclusive(Reg)) + Reserved.set(SubReg); + } + } + } + // Set the instruction pointer register and its aliases as reserved. for (const MCPhysReg &SubReg : subregs_inclusive(X86::RIP)) Reserved.set(SubReg); diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp index 4e2e98410f325..f73ca37a45c07 100644 --- a/llvm/lib/Target/X86/X86Subtarget.cpp +++ b/llvm/lib/Target/X86/X86Subtarget.cpp @@ -317,7 +317,8 @@ X86Subtarget::X86Subtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, unsigned PreferVectorWidthOverride, unsigned RequiredVectorWidth) : X86GenSubtargetInfo(TT, CPU, TuneCPU, FS), - PICStyle(PICStyles::Style::None), TM(TM), TargetTriple(TT), + PICStyle(PICStyles::Style::None), TM(TM), + ReservedRReg(X86::NUM_TARGET_REGS), TargetTriple(TT), StackAlignOverride(StackAlignOverride), PreferVectorWidthOverride(PreferVectorWidthOverride), RequiredVectorWidth(RequiredVectorWidth), diff --git a/llvm/lib/Target/X86/X86Subtarget.h b/llvm/lib/Target/X86/X86Subtarget.h index 3b920bc4ef7c1..dd9a5de3030ed 100644 --- a/llvm/lib/Target/X86/X86Subtarget.h +++ b/llvm/lib/Target/X86/X86Subtarget.h @@ -17,6 +17,7 @@ #include "X86ISelLowering.h" #include "X86InstrInfo.h" #include "X86SelectionDAGInfo.h" +#include "llvm/ADT/BitVector.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/CallingConv.h" #include "llvm/TargetParser/Triple.h" @@ -65,6 +66,9 @@ class X86Subtarget final : public X86GenSubtargetInfo { #define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER) \ bool ATTRIBUTE = DEFAULT; #include "X86GenSubtargetInfo.inc" + /// ReservedRReg R#i is not available as a general purpose register. + BitVector ReservedRReg; + /// The minimum alignment known to hold of the stack frame on /// entry to the function and which must be maintained by every function. Align stackAlignment = Align(4); @@ -155,6 +159,10 @@ class X86Subtarget final : public X86GenSubtargetInfo { const LegalizerInfo *getLegalizerInfo() const override; const RegisterBankInfo *getRegBankInfo() const override; + bool isRegisterReservedByUser(Register i) const override { + return ReservedRReg[i.id()]; + } + private: /// Initialize the full set of dependencies so we can use an initializer /// list for X86Subtarget. diff --git a/llvm/test/CodeGen/X86/reserveRreg.ll b/llvm/test/CodeGen/X86/reserveRreg.ll new file mode 100644 index 0000000000000..cfd80022e3cc4 --- /dev/null +++ b/llvm/test/CodeGen/X86/reserveRreg.ll @@ -0,0 +1,93 @@ +;; Check if manually reserved registers are always excluded from being saved by +;; the function prolog/epilog, even for callee-saved ones, as per GCC behavior. + +; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s + +define preserve_mostcc void @t8() "target-features"="+reserve-r8" { +; CHECK-LABEL: t8: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r8d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r8},{r8}"(i64 256) + ret void +} + +define preserve_mostcc void @t9() "target-features"="+reserve-r9" { +; CHECK-LABEL: t9: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r9d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r9},{r9}"(i64 256) + ret void +} + +define preserve_mostcc void @t10() "target-features"="+reserve-r10" { +; CHECK-LABEL: t10: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r10d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r10},{r10}"(i64 256) + ret void +} + +define preserve_mostcc void @t11() "target-features"="+reserve-r11" { +; CHECK-LABEL: t11: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r11d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r11},{r11}"(i64 256) + ret void +} + +define preserve_mostcc void @t12() "target-features"="+reserve-r12" { +; CHECK-LABEL: t12: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r12d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r12},{r12}"(i64 256) + ret void +} + +define preserve_mostcc void @t13() "target-features"="+reserve-r13" { +; CHECK-LABEL: t13: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r13d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r13},{r13}"(i64 256) + ret void +} + +define preserve_mostcc void @t14() "target-features"="+reserve-r14" { +; CHECK-LABEL: t14: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r14d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r14},{r14}"(i64 256) + ret void +} + +define preserve_mostcc void @t15() "target-features"="+reserve-r15" { +; CHECK-LABEL: t15: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r15d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r15},{r15}"(i64 256) + ret void +} + >From caf36e2933b0bf336d0845ebca5d3e27b66adbbc Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan <[email protected]> Date: Sun, 1 Mar 2026 17:38:59 +0800 Subject: [PATCH 2/2] [X86] extend -ffixed-r16-r31 support under APX Extend the x86_64 fixed-register support added for r8-r15 to cover\nAPX EGPR registers r16-r31 as well.\n\nOnly accept -ffixed-r16 through -ffixed-r31 when APX EGPR is\nenabled for the target, and diagnose them otherwise. When EGPR is\navailable, forward the options as reserve-r16 through reserve-r31\ntarget features so the backend marks those registers unavailable for\nallocation.\n\nAlso add driver tests for the APX-enabled and non-APX cases, plus\nCodeGen coverage for reserving r16 and r31. Signed-off-by: ZhouGuangyuan <[email protected]> --- clang/include/clang/Options/Options.td | 5 ++- clang/lib/Basic/Targets/X86.h | 3 ++ clang/lib/Driver/ToolChains/Arch/X86.cpp | 46 +++++++++++++++++++ clang/test/Driver/x86_64-fixed-r-register.c | 49 +++++++++++++++++++++ llvm/lib/Target/X86/X86.td | 3 ++ llvm/test/CodeGen/X86/reserveRreg.ll | 21 +++++++++ 6 files changed, 126 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index d71c599e3ac9a..34ddc29f6f738 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -6844,7 +6844,7 @@ def mno_hexagon_hvx_ieee_fp : Flag<["-"], "mno-hvx-ieee-fp">, Group<m_hexagon_Features_Group>, HelpText<"Disable Hexagon HVX IEEE floating-point">; def ffixed_r19: Flag<["-"], "ffixed-r19">, Group<f_Group>, - HelpText<"Reserve register r19 (Hexagon only)">; + HelpText<"Reserve register r19 (Hexagon/x86_64 only; x86_64 requires APX EGPR)">; } // let Flags = [TargetSpecific] def mmemops : Flag<["-"], "mmemops">, Group<m_hexagon_Features_Group>, Visibility<[ClangOption, CC1Option]>, @@ -7171,6 +7171,9 @@ def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group< foreach i = {8, 10-15} in def ffixed_r#i : Flag<["-"], "ffixed-r"#i>, Group<m_Group>, HelpText<"Reserve the r"#i#" register (x86_64 only)">; +foreach i = {16-18,20-31} in + def ffixed_r#i : Flag<["-"], "ffixed-r"#i>, Group<m_Group>, + HelpText<"Reserve the r"#i#" register (x86_64 with APX EGPR only)">; } // let Flags = [TargetSpecific] diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index 65617e4fcea21..f99bbf363458f 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -807,6 +807,9 @@ class LLVM_LIBRARY_VISIBILITY X86_64TargetInfo : public X86TargetInfo { return true; } + // -ffixed-r8 through -ffixed-r31 are lowered to reserve-r8 through + // reserve-r31 target features, so canonicalize subregister spellings + // like r15d/r15w/r15b back to the corresponding 64-bit register first. StringRef Reg64 = RegName; if (Reg64.back() == 'd' || Reg64.back() == 'w' || Reg64.back() == 'b') { Reg64 = Reg64.substr(0, Reg64.size() - 1); diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index c4ccddffca9fa..6a71512193800 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -9,10 +9,12 @@ #include "X86.h" #include "clang/Driver/Driver.h" #include "clang/Options/Options.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/Option/ArgList.h" #include "llvm/TargetParser/Host.h" +#include "llvm/TargetParser/X86TargetParser.h" using namespace clang::driver; using namespace clang::driver::tools; @@ -149,6 +151,17 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, } const llvm::Triple::ArchType ArchType = Triple.getArch(); + bool HasEGPR = false; + + // -ffixed-r16 through -ffixed-r31 are only valid when the selected x86_64 + // CPU enables APX EGPR by default; later -target-feature arguments still get + // their own validation when translated to backend features. + if (ArchType == llvm::Triple::x86_64) { + SmallVector<StringRef, 16> CPUFeatures; + llvm::X86::getFeaturesForCPU(getX86TargetCPU(D, Args, Triple), CPUFeatures); + HasEGPR = llvm::is_contained(CPUFeatures, "+egpr"); + } + // Add features to be compatible with gcc for Android. if (Triple.isAndroid()) { if (ArchType == llvm::Triple::x86_64) { @@ -258,11 +271,13 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, if (A->getOption().matches(options::OPT_mapxf) || A->getOption().matches(options::OPT_mno_apxf)) { if (IsNegative) { + HasEGPR = false; Features.insert(Features.end(), {"-egpr", "-ndd", "-ccmp", "-nf", "-zu"}); if (!Triple.isOSWindows()) Features.insert(Features.end(), {"-push2pop2", "-ppx"}); } else { + HasEGPR = true; Features.insert(Features.end(), {"+egpr", "+ndd", "+ccmp", "+nf", "+zu"}); if (!Triple.isOSWindows()) @@ -288,11 +303,17 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, D.Diag(clang::diag::err_drv_unsupported_option_argument) << A->getSpelling() << Value; + if (Value == "egpr") + HasEGPR = !IsNegative; + Features.push_back( Args.MakeArgString((IsNegative ? "-" : "+") + Value)); } continue; } + + if (Name == "egpr") + HasEGPR = !IsNegative; Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); } @@ -345,5 +366,30 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, RESERVE_REG(r13) RESERVE_REG(r14) RESERVE_REG(r15) +#define RESERVE_EGPR(REG) \ + if (Args.hasArg(options::OPT_ffixed_##REG)) { \ + if (!HasEGPR) \ + D.Diag(diag::err_drv_unsupported_opt_for_target) \ + << "-ffixed-" #REG << Triple.getTriple(); \ + else \ + Features.push_back("+reserve-" #REG); \ + } + RESERVE_EGPR(r16) + RESERVE_EGPR(r17) + RESERVE_EGPR(r18) + RESERVE_EGPR(r19) + RESERVE_EGPR(r20) + RESERVE_EGPR(r21) + RESERVE_EGPR(r22) + RESERVE_EGPR(r23) + RESERVE_EGPR(r24) + RESERVE_EGPR(r25) + RESERVE_EGPR(r26) + RESERVE_EGPR(r27) + RESERVE_EGPR(r28) + RESERVE_EGPR(r29) + RESERVE_EGPR(r30) + RESERVE_EGPR(r31) +#undef RESERVE_EGPR #undef RESERVE_REG } diff --git a/clang/test/Driver/x86_64-fixed-r-register.c b/clang/test/Driver/x86_64-fixed-r-register.c index 714db3fdfdc91..90f50a94e9606 100644 --- a/clang/test/Driver/x86_64-fixed-r-register.c +++ b/clang/test/Driver/x86_64-fixed-r-register.c @@ -30,6 +30,17 @@ // RUN: FileCheck --check-prefix=CHECK-FIXED-R15 < %t %s // CHECK-FIXED-R15: "-target-feature" "+reserve-r15" +// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=egpr -ffixed-r16 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R16 < %t %s +// CHECK-FIXED-R16: "-target-feature" "+reserve-r16" + +// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=egpr -ffixed-r31 -### %s 2> %t +// RUN: FileCheck --check-prefix=CHECK-FIXED-R31 < %t %s +// CHECK-FIXED-R31: "-target-feature" "+reserve-r31" + +// RUN: not %clang --target=x86_64-unknown-linux-gnu -ffixed-r16 -### %s 2>&1 | FileCheck --check-prefix=CHECK-NO-APX %s +// CHECK-NO-APX: error: unsupported option '-ffixed-r16' for target 'x86_64-unknown-linux-gnu' + // Test multiple of reserve-r# options together. // RUN: %clang --target=x86_64-unknown-linux-gnu \ // RUN: -ffixed-r8 \ @@ -63,3 +74,41 @@ // RUN: --check-prefix=CHECK-FIXED-R14 \ // RUN: --check-prefix=CHECK-FIXED-R15 \ // RUN: < %t %s + +// Test all reserve-r# options together with APX EGPR. +// RUN: %clang --target=x86_64-unknown-linux-gnu \ +// RUN: -mapx-features=egpr \ +// RUN: -ffixed-r16 \ +// RUN: -ffixed-r17 \ +// RUN: -ffixed-r18 \ +// RUN: -ffixed-r19 \ +// RUN: -ffixed-r20 \ +// RUN: -ffixed-r21 \ +// RUN: -ffixed-r22 \ +// RUN: -ffixed-r23 \ +// RUN: -ffixed-r24 \ +// RUN: -ffixed-r25 \ +// RUN: -ffixed-r26 \ +// RUN: -ffixed-r27 \ +// RUN: -ffixed-r28 \ +// RUN: -ffixed-r29 \ +// RUN: -ffixed-r30 \ +// RUN: -ffixed-r31 \ +// RUN: -### %s 2> %t +// RUN: FileCheck \ +// RUN: --check-prefix=CHECK-ALL-EGPR \ +// RUN: < %t %s +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r17" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r18" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r19" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r20" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r21" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r22" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r23" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r24" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r25" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r26" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r27" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r28" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r29" +// CHECK-ALL-EGPR: "-target-feature" "+reserve-r30" diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td index e4eafc3487f37..eca763735c315 100644 --- a/llvm/lib/Target/X86/X86.td +++ b/llvm/lib/Target/X86/X86.td @@ -35,6 +35,9 @@ def IsX32 : SubtargetFeature<"x32", "IsX32", "true", foreach i = {8-15} in def FeatureReserveR#i : SubtargetFeature<"reserve-r"#i, "ReservedRReg[X86::R"#i#"]", "true", "Reserve R"#i#", making it unavailable as a GPR">; +foreach i = {16-31} in + def FeatureReserveR#i : SubtargetFeature<"reserve-r"#i, "ReservedRReg[X86::R"#i#"]", "true", + "Reserve R"#i#", making it unavailable as a GPR">; def FeatureX87 : SubtargetFeature<"x87","HasX87", "true", "Enable X87 float instructions">; diff --git a/llvm/test/CodeGen/X86/reserveRreg.ll b/llvm/test/CodeGen/X86/reserveRreg.ll index cfd80022e3cc4..b6b10ad5169a4 100644 --- a/llvm/test/CodeGen/X86/reserveRreg.ll +++ b/llvm/test/CodeGen/X86/reserveRreg.ll @@ -91,3 +91,24 @@ define preserve_mostcc void @t15() "target-features"="+reserve-r15" { ret void } +define preserve_mostcc void @t16() "target-features"="+egpr,+reserve-r16" { +; CHECK-LABEL: t16: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r16d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r16},{r16}"(i64 256) + ret void +} + +define preserve_mostcc void @t31() "target-features"="+egpr,+reserve-r31" { +; CHECK-LABEL: t31: +; CHECK: # %bb.0: +; CHECK-NEXT: movl $256, %r31d +; CHECK-NEXT: #APP +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ret + call i64 asm sideeffect "", "={r31},{r31}"(i64 256) + ret void +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
