>From 3fc4af9d0b77db02fc6981ee5d02a5b5edf5fb1e Mon Sep 17 00:00:00 2001
From: Martin Whitaker <mailing-list@martin-whitaker.me.uk>
Date: Mon, 11 Jul 2011 10:56:17 +0100
Subject: [PATCH] Enable use of SPARC g2-g4 global registers.

This patch adds a SPARC code generator feature that allows the code
generator to optionally use the global registers that are reserved
for application use by the SPARC ABI (g2,g3,g4). It also changes
the preferred register allocation order to give preference to the
global and input registers, to increase the chances of being able
to eliminate the frame save/restore in leaf functions.

diff --git a/lib/Target/Sparc/Sparc.td b/lib/Target/Sparc/Sparc.td
index 7643366..c0547ca 100644
--- a/lib/Target/Sparc/Sparc.td
+++ b/lib/Target/Sparc/Sparc.td
@@ -30,6 +30,10 @@ def FeatureVIS
   : SubtargetFeature<"vis", "IsVIS", "true",
                      "Enable UltraSPARC Visual Instruction Set extensions">;
 
+def FeatureAppRegs
+  : SubtargetFeature<"app-regs", "UseAppRegs", "true",
+                     "Enable use of global registers 2 to 4">;
+
 //===----------------------------------------------------------------------===//
 // Register File, Calling Conv, Instruction Descriptions
 //===----------------------------------------------------------------------===//
diff --git a/lib/Target/Sparc/SparcRegisterInfo.cpp b/lib/Target/Sparc/SparcRegisterInfo.cpp
index 3b0b5fa..82df88e 100644
--- a/lib/Target/Sparc/SparcRegisterInfo.cpp
+++ b/lib/Target/Sparc/SparcRegisterInfo.cpp
@@ -45,9 +45,11 @@ BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
   BitVector Reserved(getNumRegs());
   // FIXME: G1 reserved for now for large imm generation by frame code.
   Reserved.set(SP::G1);
-  Reserved.set(SP::G2);
-  Reserved.set(SP::G3);
-  Reserved.set(SP::G4);
+  if (!Subtarget.useAppRegs()) {
+    Reserved.set(SP::G2);
+    Reserved.set(SP::G3);
+    Reserved.set(SP::G4);
+  }
   Reserved.set(SP::O6);
   Reserved.set(SP::I6);
   Reserved.set(SP::I7);
diff --git a/lib/Target/Sparc/SparcRegisterInfo.td b/lib/Target/Sparc/SparcRegisterInfo.td
index cf92829..5b8dd61 100644
--- a/lib/Target/Sparc/SparcRegisterInfo.td
+++ b/lib/Target/Sparc/SparcRegisterInfo.td
@@ -136,17 +136,17 @@ def D15 : Rd<30, "F30", [F30, F31]>, DwarfRegNum<[87]>;
 
 // Register classes.
 //
-// FIXME: the register order should be defined in terms of the preferred
-// allocation order...
+// The register order indicates the preferred allocation order. We want
+// the global and input registers to be allocated first, to increase
+// the chances of being able to eliminate the frame save/restore in
+// leaf functions.
 //
 def IntRegs : RegisterClass<"SP", [i32], 32,
-                            (add L0, L1, L2, L3, L4, L5, L6,
-                                 L7, I0, I1, I2, I3, I4, I5,
+                            (add G1,
+                                 G2, G3, G4, // reserved for applications
+                                 I0, I1, I2, I3, I4, I5,
+                                 L0, L1, L2, L3, L4, L5, L6, L7, 
                                  O0, O1, O2, O3, O4, O5, O7,
-                                 G1,
-                                 // Non-allocatable regs:
-                                 G2, G3, G4, // FIXME: OK for use only in
-                                             // applications, not libraries.
                                  O6, // stack ptr
                                  I6, // frame ptr
                                  I7, // return address
diff --git a/lib/Target/Sparc/SparcSubtarget.cpp b/lib/Target/Sparc/SparcSubtarget.cpp
index 31e20eb..c3a5595 100644
--- a/lib/Target/Sparc/SparcSubtarget.cpp
+++ b/lib/Target/Sparc/SparcSubtarget.cpp
@@ -29,8 +29,9 @@ SparcSubtarget::SparcSubtarget(const std::string &TT, const std::string &CPU,
   IsV9(false),
   V8DeprecatedInsts(false),
   IsVIS(false),
-  Is64Bit(is64Bit) {
-  
+  Is64Bit(is64Bit),
+  UseAppRegs(false) {
+
   // Determine default and user specified characteristics
   std::string CPUName = CPU;
   if (CPUName.empty()) {
diff --git a/lib/Target/Sparc/SparcSubtarget.h b/lib/Target/Sparc/SparcSubtarget.h
index 00a04c3..9a0cf35 100644
--- a/lib/Target/Sparc/SparcSubtarget.h
+++ b/lib/Target/Sparc/SparcSubtarget.h
@@ -28,6 +28,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
   bool V8DeprecatedInsts;
   bool IsVIS;
   bool Is64Bit;
+  bool UseAppRegs;
   
 public:
   SparcSubtarget(const std::string &TT, const std::string &CPU,
@@ -36,6 +37,7 @@ public:
   bool isV9() const { return IsV9; }
   bool isVIS() const { return IsVIS; }
   bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; }
+  bool useAppRegs() const { return UseAppRegs; }
   
   /// ParseSubtargetFeatures - Parses features string setting specified 
   /// subtarget options.  Definition of function is auto generated by tblgen.
diff --git a/test/CodeGen/SPARC/2011-07-10-AppRegs.ll b/test/CodeGen/SPARC/2011-07-10-AppRegs.ll
new file mode 100644
index 0000000..9549137
--- /dev/null
+++ b/test/CodeGen/SPARC/2011-07-10-AppRegs.ll
@@ -0,0 +1,19 @@
+; RUN: llc -march=sparc -mattr=-app-regs <%s | FileCheck %s -check-prefix=CHECK_N
+; RUN: llc -march=sparc -mattr=+app-regs <%s | FileCheck %s -check-prefix=CHECK_Y
+
+define void @test(i32* %ptr) nounwind {
+entry:
+; CHECK_N: ld [%i0], %i3
+; CHECK_N: ld [%i0], %i2
+; CHECK_N: ld [%i0], %i1
+; CHECK_Y: ld [%i0], %g4
+; CHECK_Y: ld [%i0], %g3
+; CHECK_Y: ld [%i0], %g2
+  %tmp1 = volatile load i32* %ptr
+  %tmp2 = volatile load i32* %ptr
+  %tmp3 = volatile load i32* %ptr
+  volatile store i32 %tmp1, i32* %ptr
+  volatile store i32 %tmp2, i32* %ptr
+  volatile store i32 %tmp3, i32* %ptr
+  ret void
+}
-- 
1.7.4.4
