Index: lib/Target/Sparc/Sparc.td =================================================================== --- lib/Target/Sparc/Sparc.td +++ lib/Target/Sparc/Sparc.td @@ -60,6 +60,27 @@ def FeatureSoftFloat : SubtargetFeature<"soft-float", "UseSoftFloat", "true", "Use software emulation for floating point">; +def ReserveRegG2 : SubtargetFeature<"reserve-reg-g2", "ReserveRegG2", "true", + "Reserve use of register %g2">; + +def ReserveRegG3 : SubtargetFeature<"reserve-reg-g3", "ReserveRegG3", "true", + "Reserve use of register %g3">; + +def ReserveRegG4 : SubtargetFeature<"reserve-reg-g4", "ReserveRegG4", "true", + "Reserve use of register %g4">; + +def ReserveRegG5 : SubtargetFeature<"reserve-reg-g5", "ReserveRegG5", "true", + "Reserve use of register %g5">; + +def UseRegG5 : SubtargetFeature<"use-reg-g5", "ReserveRegG5", "false", + "Use %g5 as scratch register">; + +def UseRegG6 : SubtargetFeature<"use-reg-g6", "ReserveRegG6", "false", + "Use %g6 as scratch register">; + +def UseRegG7 : SubtargetFeature<"use-reg-g7", "ReserveRegG7", "false", + "Use %g7 as scratch register">; + //==== Features added predmoninantly for LEON subtarget support include "LeonFeatures.td" Index: lib/Target/Sparc/SparcAsmPrinter.cpp =================================================================== --- lib/Target/Sparc/SparcAsmPrinter.cpp +++ lib/Target/Sparc/SparcAsmPrinter.cpp @@ -277,13 +277,14 @@ return; const MachineRegisterInfo &MRI = MF->getRegInfo(); + const BitVector &Reserved = MRI.getReservedRegs(); const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 }; for (unsigned i = 0; globalRegs[i] != 0; ++i) { unsigned reg = globalRegs[i]; if (MRI.use_empty(reg)) continue; - if (reg == SP::G6 || reg == SP::G7) + if (Reserved[reg]) getTargetStreamer().emitSparcRegisterIgnore(reg); else getTargetStreamer().emitSparcRegisterScratch(reg); Index: lib/Target/Sparc/SparcISelLowering.h =================================================================== --- lib/Target/Sparc/SparcISelLowering.h +++ lib/Target/Sparc/SparcISelLowering.h @@ -119,6 +119,8 @@ return SP::I1; } + SDValue getThreadPointerRegister(SelectionDAG &DAG) const; + /// Override to support customized stack guard loading. bool useLoadStackGuardNode() const override; void insertSSPDeclarations(Module &M) const override; Index: lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- lib/Target/Sparc/SparcISelLowering.cpp +++ lib/Target/Sparc/SparcISelLowering.cpp @@ -2012,6 +2012,15 @@ return makeAddress(Op, DAG); } +SDValue SparcTargetLowering::getThreadPointerRegister(SelectionDAG &DAG) const { + const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); + if (!TRI->getReservedRegs(DAG.getMachineFunction())[SP::G7]) + report_fatal_error("The TLS model requires register %g7"); + + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + return DAG.getRegister(SP::G7, PtrVT); +} + SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { @@ -2101,7 +2110,7 @@ DL, PtrVT, Ptr, withTargetFlags(Op, ldTF, DAG)); return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, - DAG.getRegister(SP::G7, PtrVT), Offset, + getThreadPointerRegister(DAG), Offset, withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_IE_ADD, DAG)); } @@ -2114,7 +2123,7 @@ SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo); return DAG.getNode(ISD::ADD, DL, PtrVT, - DAG.getRegister(SP::G7, PtrVT), Offset); + getThreadPointerRegister(DAG), Offset); } SDValue SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, @@ -3004,10 +3013,8 @@ SDLoc dl(Op); switch (IntNo) { default: return SDValue(); // Don't custom lower most intrinsics. - case Intrinsic::thread_pointer: { - EVT PtrVT = getPointerTy(DAG.getDataLayout()); - return DAG.getRegister(SP::G7, PtrVT); - } + case Intrinsic::thread_pointer: + return getThreadPointerRegister(DAG); } } Index: lib/Target/Sparc/SparcInstrInfo.cpp =================================================================== --- lib/Target/Sparc/SparcInstrInfo.cpp +++ lib/Target/Sparc/SparcInstrInfo.cpp @@ -497,6 +497,8 @@ case TargetOpcode::LOAD_STACK_GUARD: { assert(Subtarget.isTargetLinux() && "Only Linux target is expected to contain LOAD_STACK_GUARD"); + if (!Subtarget.reserveRegG7()) + report_fatal_error("Stack protector requires register %g7"); // offsetof(tcbhead_t, stack_guard) from sysdeps/sparc/nptl/tls.h in glibc. const int64_t Offset = Subtarget.is64Bit() ? 0x28 : 0x14; MI.setDesc(get(Subtarget.is64Bit() ? SP::LDXri : SP::LDri)); Index: lib/Target/Sparc/SparcRegisterInfo.cpp =================================================================== --- lib/Target/Sparc/SparcRegisterInfo.cpp +++ lib/Target/Sparc/SparcRegisterInfo.cpp @@ -30,10 +30,6 @@ #define GET_REGINFO_TARGET_DESC #include "SparcGenRegisterInfo.inc" -static cl::opt -ReserveAppRegisters("sparc-reserve-app-registers", cl::Hidden, cl::init(false), - cl::desc("Reserve application registers (%g2-%g4)")); - SparcRegisterInfo::SparcRegisterInfo() : SparcGenRegisterInfo(SP::O7) {} const MCPhysReg* @@ -56,36 +52,25 @@ BitVector Reserved(getNumRegs()); const SparcSubtarget &Subtarget = MF.getSubtarget(); // FIXME: G1 reserved for now for large imm generation by frame code. - Reserved.set(SP::G1); - - // G1-G4 can be used in applications. - if (ReserveAppRegisters) { - Reserved.set(SP::G2); - Reserved.set(SP::G3); - Reserved.set(SP::G4); - } - // G5 is not reserved in 64 bit mode. - if (!Subtarget.is64Bit()) - Reserved.set(SP::G5); - - Reserved.set(SP::O6); - Reserved.set(SP::I6); - Reserved.set(SP::I7); - Reserved.set(SP::G0); - Reserved.set(SP::G6); - Reserved.set(SP::G7); - - // Also reserve the register pair aliases covering the above - // registers, with the same conditions. - Reserved.set(SP::G0_G1); - if (ReserveAppRegisters) - Reserved.set(SP::G2_G3); - if (ReserveAppRegisters || !Subtarget.is64Bit()) - Reserved.set(SP::G4_G5); - - Reserved.set(SP::O6_O7); - Reserved.set(SP::I6_I7); - Reserved.set(SP::G6_G7); + markSuperRegs(Reserved, SP::G1); + + if (Subtarget.reserveRegG2()) + markSuperRegs(Reserved, SP::G2); + if (Subtarget.reserveRegG3()) + markSuperRegs(Reserved, SP::G3); + if (Subtarget.reserveRegG4()) + markSuperRegs(Reserved, SP::G4); + if (Subtarget.reserveRegG5()) + markSuperRegs(Reserved, SP::G5); + if (Subtarget.reserveRegG6()) + markSuperRegs(Reserved, SP::G6); + if (Subtarget.reserveRegG7()) + markSuperRegs(Reserved, SP::G7); + + markSuperRegs(Reserved, SP::O6); + markSuperRegs(Reserved, SP::I6); + markSuperRegs(Reserved, SP::I7); + markSuperRegs(Reserved, SP::G0); // Unaliased double registers are not available in non-V9 targets. if (!Subtarget.isV9()) { Index: lib/Target/Sparc/SparcSubtarget.h =================================================================== --- lib/Target/Sparc/SparcSubtarget.h +++ lib/Target/Sparc/SparcSubtarget.h @@ -43,6 +43,12 @@ bool UseSoftFloat; bool HasNoFSMULD; bool HasNoFMULS; + bool ReserveRegG2; + bool ReserveRegG3; + bool ReserveRegG4; + bool ReserveRegG5; + bool ReserveRegG6; + bool ReserveRegG7; // LEON features bool HasUmacSmac; @@ -88,6 +94,12 @@ bool useSoftFloat() const { return UseSoftFloat; } bool hasNoFSMULD() const { return HasNoFSMULD; } bool hasNoFMULS() const { return HasNoFMULS; } + bool reserveRegG2() const { return ReserveRegG2; } + bool reserveRegG3() const { return ReserveRegG3; } + bool reserveRegG4() const { return ReserveRegG4; } + bool reserveRegG5() const { return ReserveRegG5; } + bool reserveRegG6() const { return ReserveRegG6; } + bool reserveRegG7() const { return ReserveRegG7; } // Leon options bool hasUmacSmac() const { return HasUmacSmac; } Index: lib/Target/Sparc/SparcSubtarget.cpp =================================================================== --- lib/Target/Sparc/SparcSubtarget.cpp +++ lib/Target/Sparc/SparcSubtarget.cpp @@ -41,6 +41,13 @@ HasNoFSMULD = false; HasNoFMULS = false; + ReserveRegG2 = false; + ReserveRegG3 = false; + ReserveRegG4 = false; + ReserveRegG5 = !Is64Bit; + ReserveRegG6 = true; + ReserveRegG7 = true; + // Leon features HasLeonCasa = false; HasUmacSmac = false; Index: test/CodeGen/SPARC/64abi.ll =================================================================== --- test/CodeGen/SPARC/64abi.ll +++ test/CodeGen/SPARC/64abi.ll @@ -1,5 +1,6 @@ ; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD ; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc -mattr=soft-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT +; RUN: llc < %s -march=sparcv9 -disable-sparc-delay-filler -disable-sparc-leaf-proc -mattr=use-reg-g6 | FileCheck %s --check-prefix=USEG6 ; CHECK-LABEL: intarg: ; The save/restore frame is not strictly necessary here, but we would need to @@ -439,18 +440,27 @@ ret i32 %a0 } +@local_symbol = internal thread_local global i32 0 + ; CHECK-LABEL: test_register_directive: ; CHECK: .register %g2, #scratch ; CHECK: .register %g3, #scratch -; CHECK: add %i0, 2, %g2 -; CHECK: add %i0, 3, %g3 +; CHECK: .register %g7, #ignore +; CHECK: ld [%g7+%i0], %g3 +; CHECK: add %g2, 3, %l1 +; USEG6-LABEL: test_register_directive: +; USEG6: .register %g6, #scratch define i32 @test_register_directive(i32 %i0) { entry: %0 = add nsw i32 %i0, 2 %1 = add nsw i32 %i0, 3 - tail call void asm sideeffect "", "r,r,~{l0},~{l1},~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6},~{o7},~{g1},~{g4},~{g5},~{g6},~{g7}"(i32 %0, i32 %1) - %2 = add nsw i32 %0, %1 - ret i32 %2 + %2 = add nsw i32 %i0, 4 + %tls = load i32, i32* @local_symbol, align 4 + tail call void asm sideeffect "", "r,r,~{l2},~{l3},~{l4},~{l5},~{l6},~{l7},~{i0},~{i1},~{i2},~{i3},~{i4},~{i5},~{i6},~{i7},~{o0},~{o1},~{o2},~{o3},~{o4},~{o5},~{o6},~{o7},~{g1},~{g4},~{g5},~{g7}"(i32 %0, i32 %1) + %3 = add nsw i32 %0, %1 + %4 = add nsw i32 %3, %2 + %5 = add nsw i32 %4, %tls + ret i32 %5 } ; CHECK-LABEL: test_large_stack: Index: test/CodeGen/SPARC/reserved-regs.ll =================================================================== --- test/CodeGen/SPARC/reserved-regs.ll +++ test/CodeGen/SPARC/reserved-regs.ll @@ -1,4 +1,8 @@ ; RUN: llc -march=sparc -verify-machineinstrs < %s | FileCheck %s +; RUN: llc -march=sparc -verify-machineinstrs -mattr=use-reg-g5 < %s | FileCheck %s -check-prefix=USEG5 +; RUN: llc -march=sparc -verify-machineinstrs -mattr=use-reg-g6 < %s | FileCheck %s -check-prefix=USEG6 +; RUN: not llc -march=sparc -verify-machineinstrs -mattr=use-reg-g7 < %s 2>&1 | FileCheck %s -check-prefix=USEG7 +; RUN: llc -march=sparc -verify-machineinstrs -mattr=reserve-reg-g3 < %s | FileCheck %s -check-prefix=RESG3 @g = common global [32 x i32] zeroinitializer, align 16 @h = common global [16 x i64] zeroinitializer, align 16 @@ -15,6 +19,10 @@ ; CHECK-NOT: %o6 ; CHECK-NOT: %i6 ; CHECK-NOT: %i7 +; USEG5: %g5 +; USEG6: %g6 +; USEG7: %g7 +; RESG3-NOT: %g3 ; CHECK: ret define void @use_all_i32_regs() { entry: @@ -98,6 +106,10 @@ ; CHECK-NOT: %o7 ; CHECK-NOT: %i6 ; CHECK-NOT: %i7 +; USEG5: %g5 +; USEG6: %g6 +; USEG7: %g7 +; RESG3-NOT: %g3 ; CHECK: ret define void @use_all_i64_regs() { entry: @@ -135,3 +147,12 @@ store volatile i64 %0, i64* getelementptr inbounds ([16 x i64], [16 x i64]* @h, i64 0, i64 15), align 4 ret void } + +@local_symbol = internal thread_local global i32 0 + +; USEG7: LLVM ERROR: The TLS model requires register %g7 +define i32 @use_thread_pointer_register() { +entry: + %0 = load i32, i32* @local_symbol, align 4 + ret i32 %0 +} Index: test/CodeGen/SPARC/stack-protector.ll =================================================================== --- test/CodeGen/SPARC/stack-protector.ll +++ test/CodeGen/SPARC/stack-protector.ll @@ -2,12 +2,14 @@ ; RUN: llc -mtriple=sparc64-unknown-linux < %s | FileCheck %s --check-prefix=LINUX-64 ; RUN: llc -mtriple=sparc-unknown-solaris < %s | FileCheck %s --check-prefix=GENERIC ; RUN: llc -mtriple=sparc64-unknown-solaris < %s | FileCheck %s --check-prefix=GENERIC +; RUN: not llc -mtriple=sparc-unknown-linux -mattr=use-reg-g7 2>&1 < %s | FileCheck %s --check-prefix=LINUX-32-ERR ; LINUX-32: ld [%g7+20], [[REG1:%[ilo][0-9]*]] ; LINUX-64: ldx [%g7+40], [[REG1:%[ilo][0-9]*]] ; LINUX-32-NOT: __stack_chk_guard ; LINUX-64-NOT: __stack_chk_guard ; GENERIC: __stack_chk_guard +; LINUX-32-ERR: Stack protector requires register %g7 @"\01LC" = internal constant [11 x i8] c"buf == %s\0A\00" ; <[11 x i8]*> [#uses=1]