https://github.com/quic-santdas updated https://github.com/llvm/llvm-project/pull/197208
>From 0a323e2484bc5e7ad407d5e1275d10f0e1eaddde Mon Sep 17 00:00:00 2001 From: quic-santdas <[email protected]> Date: Tue, 12 May 2026 07:14:00 -0700 Subject: [PATCH 1/4] [Hexagon] Support reserving R16-R28 registers via -ffixed-rN Extend register reservation from R19-only to R16-R28. This allows users to reserve callee-saved registers (R16-R27) and R28 via command-line flags -ffixed-r16 through -ffixed-r28. The single bool ReservedR19 is replaced with an array-based approach (ReservedR[32]) to scale cleanly across all supported registers. --- clang/lib/Driver/ToolChains/Hexagon.cpp | 23 ++++++++-- clang/test/Driver/hexagon-toolchain-elf.c | 42 ++++++++++++++++++- llvm/lib/Target/Hexagon/Hexagon.td | 5 ++- .../Target/Hexagon/HexagonRegisterInfo.cpp | 10 ++++- llvm/lib/Target/Hexagon/HexagonSubtarget.h | 4 +- 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 41f03e01b69c1..ce3fd5110953a 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -790,9 +790,26 @@ void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, UseInitArrayDefault)) CC1Args.push_back("-fno-use-init-array"); - if (DriverArgs.hasArg(options::OPT_ffixed_r19)) { - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+reserved-r19"); + 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"}, + }; + for (const auto &[Opt, Feature] : FixedRegs) { + if (DriverArgs.hasArg(Opt)) { + CC1Args.push_back("-target-feature"); + CC1Args.push_back(Feature); + } } if (isAutoHVXEnabled(DriverArgs)) { CC1Args.push_back("-mllvm"); diff --git a/clang/test/Driver/hexagon-toolchain-elf.c b/clang/test/Driver/hexagon-toolchain-elf.c index 6de646a0f836a..83797b731563a 100644 --- a/clang/test/Driver/hexagon-toolchain-elf.c +++ b/clang/test/Driver/hexagon-toolchain-elf.c @@ -544,14 +544,52 @@ // CHECK360: {{hexagon-link|ld}} // ----------------------------------------------------------------------------- -// ffixed-r19 -// ----------------------------------------------------------------------------- +// ffixed-r16 through ffixed-r28 +// ----------------------------------------------------------------------------- +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r16 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R16 %s +// CHECK-R16: "-target-feature" "+reserved-r16" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r17 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R17 %s +// CHECK-R17: "-target-feature" "+reserved-r17" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r18 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R18 %s +// CHECK-R18: "-target-feature" "+reserved-r18" // RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r19 %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK370 %s // CHECK370: "-target-feature" "+reserved-r19" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r20 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R20 %s +// CHECK-R20: "-target-feature" "+reserved-r20" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r21 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R21 %s +// CHECK-R21: "-target-feature" "+reserved-r21" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r22 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R22 %s +// CHECK-R22: "-target-feature" "+reserved-r22" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r23 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R23 %s +// CHECK-R23: "-target-feature" "+reserved-r23" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r24 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R24 %s +// CHECK-R24: "-target-feature" "+reserved-r24" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r25 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R25 %s +// CHECK-R25: "-target-feature" "+reserved-r25" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r26 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R26 %s +// CHECK-R26: "-target-feature" "+reserved-r26" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r27 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R27 %s +// CHECK-R27: "-target-feature" "+reserved-r27" +// RUN: %clang -### --target=hexagon-unknown-elf -ffixed-r28 %s 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-R28 %s +// CHECK-R28: "-target-feature" "+reserved-r28" // RUN: %clang -### --target=hexagon-unknown-elf %s 2>&1 \ // RUN: | FileCheck --check-prefix=CHECK371 %s +// CHECK371-NOT: "+reserved-r16" // CHECK371-NOT: "+reserved-r19" +// CHECK371-NOT: "+reserved-r28" // ----------------------------------------------------------------------------- // mcabac diff --git a/llvm/lib/Target/Hexagon/Hexagon.td b/llvm/lib/Target/Hexagon/Hexagon.td index 6532cbd085c2d..24052476d2fc4 100644 --- a/llvm/lib/Target/Hexagon/Hexagon.td +++ b/llvm/lib/Target/Hexagon/Hexagon.td @@ -116,8 +116,9 @@ 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">; -def FeatureReservedR19: SubtargetFeature<"reserved-r19", "ReservedR19", - "true", "Reserve register R19">; +foreach i = {16-28} in + def FeatureReservedR#i : SubtargetFeature<"reserved-r"#i, + "ReservedR["#i#"]", "true", "Reserve register R"#i>; def FeatureNoreturnStackElim: SubtargetFeature<"noreturn-stack-elim", "NoreturnStackElim", "true", "Eliminate stack allocation in a noreturn function when possible">; diff --git a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp index a56dfc5f58392..999b6dc239b3d 100644 --- a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp @@ -205,8 +205,14 @@ BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF) for (auto Reg : Hexagon_MC::GetVectRegRev()) Reserved.set(Reg); - if (MF.getSubtarget<HexagonSubtarget>().hasReservedR19()) - Reserved.set(Hexagon::R19); + static const MCPhysReg RRegs[] = { + 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}; + const auto &HST = MF.getSubtarget<HexagonSubtarget>(); + for (unsigned i = 0; i < std::size(RRegs); ++i) + if (HST.isRRegReserved(i + 16)) + Reserved.set(RRegs[i]); Register AP = MF.getInfo<HexagonMachineFunctionInfo>()->getStackAlignBaseReg(); diff --git a/llvm/lib/Target/Hexagon/HexagonSubtarget.h b/llvm/lib/Target/Hexagon/HexagonSubtarget.h index dde32298b6889..559f90e64df25 100644 --- a/llvm/lib/Target/Hexagon/HexagonSubtarget.h +++ b/llvm/lib/Target/Hexagon/HexagonSubtarget.h @@ -63,7 +63,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { bool HasPreV65 = false; bool HasMemNoShuf = false; bool EnableDuplex = false; - bool ReservedR19 = false; + bool ReservedR[32] = {}; bool NoreturnStackElim = false; public: @@ -286,7 +286,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { bool useHVX64BOps() const { return useHVXOps() && UseHVX64BOps; } bool hasMemNoShuf() const { return HasMemNoShuf; } - bool hasReservedR19() const { return ReservedR19; } + bool isRRegReserved(unsigned i) const { return ReservedR[i]; } bool usePredicatedCalls() const; bool noreturnStackElim() const { return NoreturnStackElim; } >From b09bee8a408e407fcfb4a1e64bc15d124dfb2cfd Mon Sep 17 00:00:00 2001 From: quic-santdas <[email protected]> Date: Wed, 13 May 2026 07:07:24 -0700 Subject: [PATCH 2/4] Fixed the formatting via clang-format --- llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp index 999b6dc239b3d..88205358874f3 100644 --- a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp @@ -206,9 +206,9 @@ BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF) Reserved.set(Reg); static const MCPhysReg RRegs[] = { - 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}; + 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}; const auto &HST = MF.getSubtarget<HexagonSubtarget>(); for (unsigned i = 0; i < std::size(RRegs); ++i) if (HST.isRRegReserved(i + 16)) >From d9f18aafe3b9889596f5a3bdc1611f5db2204f3a Mon Sep 17 00:00:00 2001 From: quic-santdas <[email protected]> Date: Tue, 19 May 2026 07:06:39 -0700 Subject: [PATCH 3/4] Addressed comments by quic-k 1. Added codegen test. 2. Modified clang test to add a regex. 3. Added assertion check for reserved register verification. --- clang/test/Driver/hexagon-toolchain-elf.c | 4 +-- llvm/lib/Target/Hexagon/HexagonSubtarget.h | 5 +++- llvm/test/CodeGen/Hexagon/reserved-regs.ll | 30 ++++++++++++++++++++++ 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 llvm/test/CodeGen/Hexagon/reserved-regs.ll diff --git a/clang/test/Driver/hexagon-toolchain-elf.c b/clang/test/Driver/hexagon-toolchain-elf.c index 83797b731563a..b2a3ce750fbc0 100644 --- a/clang/test/Driver/hexagon-toolchain-elf.c +++ b/clang/test/Driver/hexagon-toolchain-elf.c @@ -587,9 +587,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-r16" -// CHECK371-NOT: "+reserved-r19" -// CHECK371-NOT: "+reserved-r28" +// CHECK371-NOT: "+reserved-r{{(1[6-9]|2[0-8])}}" // ----------------------------------------------------------------------------- // mcabac diff --git a/llvm/lib/Target/Hexagon/HexagonSubtarget.h b/llvm/lib/Target/Hexagon/HexagonSubtarget.h index 559f90e64df25..950246d95d1f4 100644 --- a/llvm/lib/Target/Hexagon/HexagonSubtarget.h +++ b/llvm/lib/Target/Hexagon/HexagonSubtarget.h @@ -286,7 +286,10 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { bool useHVX64BOps() const { return useHVXOps() && UseHVX64BOps; } bool hasMemNoShuf() const { return HasMemNoShuf; } - bool isRRegReserved(unsigned i) const { return ReservedR[i]; } + bool isRRegReserved(unsigned i) const { + assert(i >= 16 && i <= 28 && "Register index out of reservable range"); + return ReservedR[i]; + } bool usePredicatedCalls() const; bool noreturnStackElim() const { return NoreturnStackElim; } diff --git a/llvm/test/CodeGen/Hexagon/reserved-regs.ll b/llvm/test/CodeGen/Hexagon/reserved-regs.ll new file mode 100644 index 0000000000000..80e5d77ba2964 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/reserved-regs.ll @@ -0,0 +1,30 @@ +; RUN: llc -mtriple=hexagon -O2 < %s | FileCheck -check-prefix=CHECK-DEFAULT %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. + +declare void @bar() + +define i32 @pressure(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f) { + %v1 = add i32 %a, %b + %v2 = mul i32 %v1, %c + %v3 = sub i32 %v2, %d + %v4 = add i32 %v3, %e + %v5 = mul i32 %v4, %f + call void @bar() + %v6 = add i32 %v5, %v1 + %v7 = sub i32 %v6, %v2 + %v8 = add i32 %v7, %v3 + %v9 = mul i32 %v8, %v4 + %v10 = sub i32 %v9, %v5 + ret i32 %v10 +} + +; CHECK-DEFAULT: r16 +; CHECK-DEFAULT: r17 +; CHECK-R16-NOT: r16 +; CHECK-R16R17-NOT: r16 +; CHECK-R16R17-NOT: r17 >From 29a60c8b36cb266c8fc0d652bd3380f5a36bb704 Mon Sep 17 00:00:00 2001 From: quic-santdas <[email protected]> Date: Wed, 20 May 2026 07:30:53 -0700 Subject: [PATCH 4/4] Addressed comments by quic-saravan Leveraged enum defined in tablegen to store reserved registers as bit values. Used TargetSubtargetInfo::isRegisterReservedByUser() API instead of creating a custom function. --- llvm/lib/Target/Hexagon/Hexagon.td | 3 ++- llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp | 7 +++---- llvm/lib/Target/Hexagon/HexagonSubtarget.h | 9 +++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Target/Hexagon/Hexagon.td b/llvm/lib/Target/Hexagon/Hexagon.td index 24052476d2fc4..ecb8a0a7a9738 100644 --- a/llvm/lib/Target/Hexagon/Hexagon.td +++ b/llvm/lib/Target/Hexagon/Hexagon.td @@ -118,7 +118,8 @@ def FeatureDuplex: SubtargetFeature<"duplex", "EnableDuplex", "true", "Enable generation of duplex instruction">; foreach i = {16-28} in def FeatureReservedR#i : SubtargetFeature<"reserved-r"#i, - "ReservedR["#i#"]", "true", "Reserve register R"#i>; + "UserReservedRegister[Hexagon::R"#i#"]", + "true", "Reserve register R"#i>; def FeatureNoreturnStackElim: SubtargetFeature<"noreturn-stack-elim", "NoreturnStackElim", "true", "Eliminate stack allocation in a noreturn function when possible">; diff --git a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp index 88205358874f3..9bd614c7b79f8 100644 --- a/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonRegisterInfo.cpp @@ -209,10 +209,9 @@ BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF) 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}; - const auto &HST = MF.getSubtarget<HexagonSubtarget>(); - for (unsigned i = 0; i < std::size(RRegs); ++i) - if (HST.isRRegReserved(i + 16)) - Reserved.set(RRegs[i]); + for (MCPhysReg Reg : RRegs) + if (MF.getSubtarget().isRegisterReservedByUser(Reg)) + Reserved.set(Reg); Register AP = MF.getInfo<HexagonMachineFunctionInfo>()->getStackAlignBaseReg(); diff --git a/llvm/lib/Target/Hexagon/HexagonSubtarget.h b/llvm/lib/Target/Hexagon/HexagonSubtarget.h index 950246d95d1f4..2019bbf64b365 100644 --- a/llvm/lib/Target/Hexagon/HexagonSubtarget.h +++ b/llvm/lib/Target/Hexagon/HexagonSubtarget.h @@ -25,6 +25,7 @@ #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/MC/MCInstrItineraries.h" #include "llvm/Support/Alignment.h" +#include <bitset> #include <memory> #include <string> #include <vector> @@ -63,7 +64,7 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { bool HasPreV65 = false; bool HasMemNoShuf = false; bool EnableDuplex = false; - bool ReservedR[32] = {}; + std::bitset<Hexagon::NUM_TARGET_REGS> UserReservedRegister; bool NoreturnStackElim = false; public: @@ -286,9 +287,9 @@ class HexagonSubtarget : public HexagonGenSubtargetInfo { bool useHVX64BOps() const { return useHVXOps() && UseHVX64BOps; } bool hasMemNoShuf() const { return HasMemNoShuf; } - bool isRRegReserved(unsigned i) const { - assert(i >= 16 && i <= 28 && "Register index out of reservable range"); - return ReservedR[i]; + bool isRegisterReservedByUser(Register i) const override { + assert(i.id() < Hexagon::NUM_TARGET_REGS && "Register out of range"); + return UserReservedRegister[i.id()]; } bool usePredicatedCalls() const; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
