[clang] [llvm] [Hexagon] Allow reservation of caller saved registers via -ffixed-rXX (PR #205733)
Santanu Das via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 4 09:23:46 PDT 2026
https://github.com/quic-santdas updated https://github.com/llvm/llvm-project/pull/205733
>From d27e557cfa8e90fac4b1638b2cb4720476671902 Mon Sep 17 00:00:00 2001
From: quic-santdas <quic_santdas at qti.qualcomm.com>
Date: Wed, 24 Jun 2026 22:55:48 -0700
Subject: [PATCH 1/2] [Hexagon] Allow reservation of caller saved registers via
-ffixed-rXX
Previously, hexagon allowed only callee saved registers to be reserved
since reserving caller saved regs can create problems, since it
cannot be sure that the callee (from a different module) also
reserves the register.
The responsibility of reserving register and managing it is now
on the user.
---
clang/include/clang/Options/Options.td | 9 +++--
clang/lib/Driver/ToolChains/Hexagon.cpp | 10 ++++++
clang/test/Driver/hexagon-toolchain-elf.c | 36 +++++++++++++++++--
llvm/lib/Target/Hexagon/Hexagon.td | 2 +-
.../Target/Hexagon/HexagonRegisterInfo.cpp | 2 ++
llvm/test/CodeGen/Hexagon/reserved-regs.ll | 6 ++++
6 files changed, 58 insertions(+), 7 deletions(-)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 4fc9f4d4c3472..125ac5ca366c9 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5680,7 +5680,7 @@ 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_Group>,
- HelpText<"Reserve the r9 register (ARM/x86_64 only)">;
+ HelpText<"Reserve the r9 register (ARM/Hexagon/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>,
@@ -7041,6 +7041,9 @@ def mhexagon_hvx_ieee_fp : Flag<["-"], "mhvx-ieee-fp">,
def mno_hexagon_hvx_ieee_fp : Flag<["-"], "mno-hvx-ieee-fp">,
Group<m_hexagon_Features_Group>,
HelpText<"Disable Hexagon HVX IEEE floating-point">;
+foreach i = {6-7} in
+ def ffixed_r#i : Flag<["-"], "ffixed-r"#i>, Group<f_Group>,
+ HelpText<"Reserve register r"#i#" (Hexagon only)">;
def ffixed_r19: Flag<["-"], "ffixed-r19">, Group<f_Group>,
HelpText<"Reserve register r19 (Hexagon/x86_64 only; x86_64 requires APX EGPR)">;
} // let Flags = [TargetSpecific]
@@ -7374,10 +7377,10 @@ def ffixed_edi : Flag<["-"], "ffixed-edi">, Group<m_Group>,
HelpText<"Reserve the edi register (x86 only)">;
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)">;
+ HelpText<"Reserve the r"#i#" register (Hexagon/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)">;
+ HelpText<"Reserve the r"#i#" register (Hexagon/x86_64 only; x86_64 requires APX EGPR)">;
} // let Flags = [TargetSpecific]
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index 3643c0d4e526c..e779647386616 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -790,6 +790,16 @@ void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
CC1Args.push_back("-fno-use-init-array");
static const std::pair<options::ID, const char *> FixedRegs[] = {
+ {options::OPT_ffixed_r6, "+reserved-r6"},
+ {options::OPT_ffixed_r7, "+reserved-r7"},
+ {options::OPT_ffixed_r8, "+reserved-r8"},
+ {options::OPT_ffixed_r9, "+reserved-r9"},
+ {options::OPT_ffixed_r10, "+reserved-r10"},
+ {options::OPT_ffixed_r11, "+reserved-r11"},
+ {options::OPT_ffixed_r12, "+reserved-r12"},
+ {options::OPT_ffixed_r13, "+reserved-r13"},
+ {options::OPT_ffixed_r14, "+reserved-r14"},
+ {options::OPT_ffixed_r15, "+reserved-r15"},
{options::OPT_ffixed_r16, "+reserved-r16"},
{options::OPT_ffixed_r17, "+reserved-r17"},
{options::OPT_ffixed_r18, "+reserved-r18"},
diff --git a/clang/test/Driver/hexagon-toolchain-elf.c b/clang/test/Driver/hexagon-toolchain-elf.c
index b2a3ce750fbc0..fce6f3e250136 100644
--- a/clang/test/Driver/hexagon-toolchain-elf.c
+++ b/clang/test/Driver/hexagon-toolchain-elf.c
@@ -544,8 +544,38 @@
// CHECK360: {{hexagon-link|ld}}
// -----------------------------------------------------------------------------
-// ffixed-r16 through ffixed-r28
-// -----------------------------------------------------------------------------
+// ffixed-r6 through ffixed-r28
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r6 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R6 %s
+// CHECK-R6: "-target-feature" "+reserved-r6"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r7 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R7 %s
+// CHECK-R7: "-target-feature" "+reserved-r7"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r8 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R8 %s
+// CHECK-R8: "-target-feature" "+reserved-r8"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r9 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R9 %s
+// CHECK-R9: "-target-feature" "+reserved-r9"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r10 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R10 %s
+// CHECK-R10: "-target-feature" "+reserved-r10"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r11 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R11 %s
+// CHECK-R11: "-target-feature" "+reserved-r11"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r12 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R12 %s
+// CHECK-R12: "-target-feature" "+reserved-r12"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r13 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R13 %s
+// CHECK-R13: "-target-feature" "+reserved-r13"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r14 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R14 %s
+// CHECK-R14: "-target-feature" "+reserved-r14"
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r15 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-R15 %s
+// CHECK-R15: "-target-feature" "+reserved-r15"
// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r16 %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK-R16 %s
// CHECK-R16: "-target-feature" "+reserved-r16"
@@ -587,7 +617,7 @@
// CHECK-R28: "-target-feature" "+reserved-r28"
// RUN: %clang -### --target=hexagon-unknown-elf %s 2>&1 \
// RUN: | FileCheck --check-prefix=CHECK371 %s
-// CHECK371-NOT: "+reserved-r{{(1[6-9]|2[0-8])}}"
+// CHECK371-NOT: "+reserved-r{{([6-9]|1[0-9]|2[0-8])}}"
// -----------------------------------------------------------------------------
// mcabac
diff --git a/llvm/lib/Target/Hexagon/Hexagon.td b/llvm/lib/Target/Hexagon/Hexagon.td
index ecb8a0a7a9738..b6fe3b4c80777 100644
--- a/llvm/lib/Target/Hexagon/Hexagon.td
+++ b/llvm/lib/Target/Hexagon/Hexagon.td
@@ -116,7 +116,7 @@ def FeatureSmallData: SubtargetFeature<"small-data", "UseSmallData", "true",
"Allow GP-relative addressing of global variables">;
def FeatureDuplex: SubtargetFeature<"duplex", "EnableDuplex", "true",
"Enable generation of duplex instruction">;
-foreach i = {16-28} in
+foreach i = {6-28} in
def FeatureReservedR#i : SubtargetFeature<"reserved-r"#i,
"UserReservedRegister[Hexagon::R"#i#"]",
"true", "Reserve register R"#i>;
diff --git a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
index 9bd614c7b79f8..63d6717ad7b68 100644
--- a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
@@ -206,6 +206,8 @@ BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF)
Reserved.set(Reg);
static const MCPhysReg RRegs[] = {
+ Hexagon::R6, Hexagon::R7, Hexagon::R8, Hexagon::R9, Hexagon::R10,
+ Hexagon::R11, Hexagon::R12, Hexagon::R13, Hexagon::R14, Hexagon::R15,
Hexagon::R16, Hexagon::R17, Hexagon::R18, Hexagon::R19, Hexagon::R20,
Hexagon::R21, Hexagon::R22, Hexagon::R23, Hexagon::R24, Hexagon::R25,
Hexagon::R26, Hexagon::R27, Hexagon::R28};
diff --git a/llvm/test/CodeGen/Hexagon/reserved-regs.ll b/llvm/test/CodeGen/Hexagon/reserved-regs.ll
index 80e5d77ba2964..9d2d172276b42 100644
--- a/llvm/test/CodeGen/Hexagon/reserved-regs.ll
+++ b/llvm/test/CodeGen/Hexagon/reserved-regs.ll
@@ -1,10 +1,13 @@
; RUN: llc -mtriple=hexagon -O2 < %s | FileCheck -check-prefix=CHECK-DEFAULT %s
+; RUN: llc -mtriple=hexagon -mattr=+reserved-r6 -O2 < %s | FileCheck -check-prefix=CHECK-R6 %s
+; RUN: llc -mtriple=hexagon -mattr=+reserved-r6,+reserved-r7 -O2 < %s | FileCheck -check-prefix=CHECK-R6R7 %s
; RUN: llc -mtriple=hexagon -mattr=+reserved-r16 -O2 < %s | FileCheck -check-prefix=CHECK-R16 %s
; RUN: llc -mtriple=hexagon -mattr=+reserved-r16,+reserved-r17 -O2 < %s | FileCheck -check-prefix=CHECK-R16R17 %s
; Test that reserved registers are not used by the register allocator.
; The function has a call, forcing values to be placed in callee-saved
; registers (R16-R27). Reserving a register must prevent its use.
+; Caller-saved registers (R6-R15) can also be reserved.
declare void @bar()
@@ -25,6 +28,9 @@ define i32 @pressure(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) {
; CHECK-DEFAULT: r16
; CHECK-DEFAULT: r17
+; CHECK-R6-NOT: r6
+; CHECK-R6R7-NOT: r6
+; CHECK-R6R7-NOT: r7
; CHECK-R16-NOT: r16
; CHECK-R16R17-NOT: r16
; CHECK-R16R17-NOT: r17
>From 107e17e2878c59bf8556c13de777cd06ae040fcf Mon Sep 17 00:00:00 2001
From: quic-santdas <quic_santdas at qti.qualcomm.com>
Date: Fri, 3 Jul 2026 02:36:53 -0700
Subject: [PATCH 2/2] Addressed comments by asaravan
---
.../clang/Basic/DiagnosticDriverKinds.td | 5 ++
clang/include/clang/Options/Options.td | 4 +-
clang/lib/Driver/ToolChains/Hexagon.cpp | 58 ++++++++++---------
clang/test/Driver/hexagon-toolchain-elf.c | 17 ++++++
4 files changed, 56 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 8edac14f4972a..44b0b77b98c5b 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -171,6 +171,11 @@ def warn_drv_unsupported_option_for_processor : Warning<
def warn_drv_unsupported_option_for_runtime : Warning<
"ignoring '%0' option as it is not currently supported for runtime '%1'">,
InGroup<OptionIgnored>;
+def warn_drv_hexagon_reserved_caller_saved_reg : Warning<
+ "reserving the caller-saved register '%0' may lead to incorrect code if it "
+ "is not also reserved in all other translation units and libraries; you are "
+ "responsible for ensuring the register is managed consistently">,
+ InGroup<DiagGroup<"hexagon-reserved-caller-saved">>;
def warn_drv_unsupported_openmp_library : Warning<
"the library '%0=%1' is not supported, OpenMP will not be enabled">,
InGroup<OptionIgnored>;
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 125ac5ca366c9..a1da8f4df559e 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -7042,9 +7042,9 @@ def mno_hexagon_hvx_ieee_fp : Flag<["-"], "mno-hvx-ieee-fp">,
Group<m_hexagon_Features_Group>,
HelpText<"Disable Hexagon HVX IEEE floating-point">;
foreach i = {6-7} in
- def ffixed_r#i : Flag<["-"], "ffixed-r"#i>, Group<f_Group>,
+ def ffixed_r#i : Flag<["-"], "ffixed-r"#i>, Group<m_Group>,
HelpText<"Reserve register r"#i#" (Hexagon only)">;
-def ffixed_r19: Flag<["-"], "ffixed-r19">, Group<f_Group>,
+def ffixed_r19: Flag<["-"], "ffixed-r19">, Group<m_Group>,
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>,
diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index e779647386616..28442e7d6928a 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -789,33 +789,39 @@ void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs,
UseInitArrayDefault))
CC1Args.push_back("-fno-use-init-array");
- static const std::pair<options::ID, const char *> FixedRegs[] = {
- {options::OPT_ffixed_r6, "+reserved-r6"},
- {options::OPT_ffixed_r7, "+reserved-r7"},
- {options::OPT_ffixed_r8, "+reserved-r8"},
- {options::OPT_ffixed_r9, "+reserved-r9"},
- {options::OPT_ffixed_r10, "+reserved-r10"},
- {options::OPT_ffixed_r11, "+reserved-r11"},
- {options::OPT_ffixed_r12, "+reserved-r12"},
- {options::OPT_ffixed_r13, "+reserved-r13"},
- {options::OPT_ffixed_r14, "+reserved-r14"},
- {options::OPT_ffixed_r15, "+reserved-r15"},
- {options::OPT_ffixed_r16, "+reserved-r16"},
- {options::OPT_ffixed_r17, "+reserved-r17"},
- {options::OPT_ffixed_r18, "+reserved-r18"},
- {options::OPT_ffixed_r19, "+reserved-r19"},
- {options::OPT_ffixed_r20, "+reserved-r20"},
- {options::OPT_ffixed_r21, "+reserved-r21"},
- {options::OPT_ffixed_r22, "+reserved-r22"},
- {options::OPT_ffixed_r23, "+reserved-r23"},
- {options::OPT_ffixed_r24, "+reserved-r24"},
- {options::OPT_ffixed_r25, "+reserved-r25"},
- {options::OPT_ffixed_r26, "+reserved-r26"},
- {options::OPT_ffixed_r27, "+reserved-r27"},
- {options::OPT_ffixed_r28, "+reserved-r28"},
+ // The bool marks caller-saved (scratch) registers in the Hexagon ABI.
+ // Reserving those only behaves correctly if every other translation unit and
+ // library reserves them too, so we warn when the user does so.
+ static const std::tuple<options::ID, const char *, bool> FixedRegs[] = {
+ {options::OPT_ffixed_r6, "+reserved-r6", true},
+ {options::OPT_ffixed_r7, "+reserved-r7", true},
+ {options::OPT_ffixed_r8, "+reserved-r8", true},
+ {options::OPT_ffixed_r9, "+reserved-r9", true},
+ {options::OPT_ffixed_r10, "+reserved-r10", true},
+ {options::OPT_ffixed_r11, "+reserved-r11", true},
+ {options::OPT_ffixed_r12, "+reserved-r12", true},
+ {options::OPT_ffixed_r13, "+reserved-r13", true},
+ {options::OPT_ffixed_r14, "+reserved-r14", true},
+ {options::OPT_ffixed_r15, "+reserved-r15", true},
+ {options::OPT_ffixed_r16, "+reserved-r16", false},
+ {options::OPT_ffixed_r17, "+reserved-r17", false},
+ {options::OPT_ffixed_r18, "+reserved-r18", false},
+ {options::OPT_ffixed_r19, "+reserved-r19", false},
+ {options::OPT_ffixed_r20, "+reserved-r20", false},
+ {options::OPT_ffixed_r21, "+reserved-r21", false},
+ {options::OPT_ffixed_r22, "+reserved-r22", false},
+ {options::OPT_ffixed_r23, "+reserved-r23", false},
+ {options::OPT_ffixed_r24, "+reserved-r24", false},
+ {options::OPT_ffixed_r25, "+reserved-r25", false},
+ {options::OPT_ffixed_r26, "+reserved-r26", false},
+ {options::OPT_ffixed_r27, "+reserved-r27", false},
+ {options::OPT_ffixed_r28, "+reserved-r28", false},
};
- for (const auto &[Opt, Feature] : FixedRegs) {
- if (DriverArgs.hasArg(Opt)) {
+ for (const auto &[Opt, Feature, IsCallerSaved] : FixedRegs) {
+ if (Arg *A = DriverArgs.getLastArg(Opt)) {
+ if (IsCallerSaved)
+ getDriver().Diag(diag::warn_drv_hexagon_reserved_caller_saved_reg)
+ << A->getOption().getName();
CC1Args.push_back("-target-feature");
CC1Args.push_back(Feature);
}
diff --git a/clang/test/Driver/hexagon-toolchain-elf.c b/clang/test/Driver/hexagon-toolchain-elf.c
index fce6f3e250136..2832a8393feb7 100644
--- a/clang/test/Driver/hexagon-toolchain-elf.c
+++ b/clang/test/Driver/hexagon-toolchain-elf.c
@@ -619,6 +619,23 @@
// RUN: | FileCheck --check-prefix=CHECK371 %s
// CHECK371-NOT: "+reserved-r{{([6-9]|1[0-9]|2[0-8])}}"
+// -----------------------------------------------------------------------------
+// Reserving a caller-saved register (r6-r15) warns; a callee-saved one
+// (r16-r28) does not. The warning can be silenced with -Wno-....
+// -----------------------------------------------------------------------------
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r6 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-WARN-R6 %s
+// CHECK-WARN-R6: warning: reserving the caller-saved register 'ffixed-r6'
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r15 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-WARN-R15 %s
+// CHECK-WARN-R15: warning: reserving the caller-saved register 'ffixed-r15'
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r16 %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOWARN %s
+// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r6 \
+// RUN: -Wno-hexagon-reserved-caller-saved %s 2>&1 \
+// RUN: | FileCheck --check-prefix=CHECK-NOWARN %s
+// CHECK-NOWARN-NOT: warning: reserving the caller-saved register
+
// -----------------------------------------------------------------------------
// mcabac
// -----------------------------------------------------------------------------
More information about the llvm-commits
mailing list