[clang] a280b1b - [Hexagon] Allow reservation of caller saved registers via -ffixed-rXX (#205733)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Jul 5 22:49:33 PDT 2026
Author: Santanu Das
Date: 2026-07-06T11:19:28+05:30
New Revision: a280b1b4f84186255c41a989312ab01ee4c30b88
URL: https://github.com/llvm/llvm-project/commit/a280b1b4f84186255c41a989312ab01ee4c30b88
DIFF: https://github.com/llvm/llvm-project/commit/a280b1b4f84186255c41a989312ab01ee4c30b88.diff
LOG: [Hexagon] Allow reservation of caller saved registers via -ffixed-rXX (#205733)
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. However, a warning will be displayed if the user tries to reserve a
caller saved register.
---------
Co-authored-by: quic-santdas <quic_santdas at qti.qualcomm.com>
Added:
Modified:
clang/include/clang/Basic/DiagnosticDriverKinds.td
clang/include/clang/Options/Options.td
clang/lib/Driver/ToolChains/Hexagon.cpp
clang/test/Driver/hexagon-toolchain-elf.c
llvm/lib/Target/Hexagon/Hexagon.td
llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp
llvm/test/CodeGen/Hexagon/reserved-regs.ll
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index 3f8fc16e346cf..ae3eecc60fc78 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 35b0390bd2fc0..e6e8a46b846c8 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5699,7 +5699,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>,
@@ -7063,7 +7063,10 @@ 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">;
-def ffixed_r19: Flag<["-"], "ffixed-r19">, Group<f_Group>,
+foreach i = {6-7} in
+ 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<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>,
@@ -7396,10 +7399,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 fd2ec694abb2f..827b0e6201428 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -806,23 +806,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_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 b2a3ce750fbc0..2832a8393feb7 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,24 @@
// 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])}}"
+
+// -----------------------------------------------------------------------------
+// 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
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
More information about the cfe-commits
mailing list