| 1 | //===-- SparcRegisterInfo.cpp - SPARC Register Information ----------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // This file contains the SPARC implementation of the TargetRegisterInfo class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "SparcRegisterInfo.h" |
| 14 | #include "Sparc.h" |
| 15 | #include "SparcSubtarget.h" |
| 16 | #include "llvm/ADT/BitVector.h" |
| 17 | #include "llvm/CodeGen/MachineFrameInfo.h" |
| 18 | #include "llvm/CodeGen/MachineFunction.h" |
| 19 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
| 20 | #include "llvm/CodeGen/TargetInstrInfo.h" |
| 21 | #include "llvm/IR/Type.h" |
| 22 | #include "llvm/Support/CommandLine.h" |
| 23 | #include "llvm/Support/ErrorHandling.h" |
| 24 | |
| 25 | using namespace llvm; |
| 26 | |
| 27 | #define GET_REGINFO_TARGET_DESC |
| 28 | #include "SparcGenRegisterInfo.inc" |
| 29 | |
| 30 | static cl::opt<bool> |
| 31 | ReserveAppRegisters("sparc-reserve-app-registers" , cl::Hidden, cl::init(Val: false), |
| 32 | cl::desc("Reserve application registers (%g2-%g4)" )); |
| 33 | |
| 34 | SparcRegisterInfo::SparcRegisterInfo(const SparcSubtarget &STI) |
| 35 | : SparcGenRegisterInfo(SP::O7), Is64Bit(STI.is64Bit()) {} |
| 36 | |
| 37 | const MCPhysReg* |
| 38 | SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { |
| 39 | return CSR_SaveList; |
| 40 | } |
| 41 | |
| 42 | const uint32_t * |
| 43 | SparcRegisterInfo::getCallPreservedMask(const MachineFunction &MF, |
| 44 | CallingConv::ID CC) const { |
| 45 | return CSR_RegMask; |
| 46 | } |
| 47 | |
| 48 | const uint32_t* |
| 49 | SparcRegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const { |
| 50 | return RTCSR_RegMask; |
| 51 | } |
| 52 | |
| 53 | BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const { |
| 54 | BitVector Reserved(getNumRegs()); |
| 55 | const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>(); |
| 56 | // FIXME: G1 reserved for now for large imm generation by frame code. |
| 57 | Reserved.set(SP::G1); |
| 58 | |
| 59 | // G1-G4 can be used in applications. |
| 60 | if (ReserveAppRegisters) { |
| 61 | Reserved.set(SP::G2); |
| 62 | Reserved.set(SP::G3); |
| 63 | Reserved.set(SP::G4); |
| 64 | } |
| 65 | // G5 is not reserved in 64 bit mode. |
| 66 | if (!Subtarget.is64Bit()) |
| 67 | Reserved.set(SP::G5); |
| 68 | |
| 69 | Reserved.set(SP::O6); |
| 70 | Reserved.set(SP::I6); |
| 71 | Reserved.set(SP::I7); |
| 72 | Reserved.set(SP::G0); |
| 73 | Reserved.set(SP::G6); |
| 74 | Reserved.set(SP::G7); |
| 75 | |
| 76 | // Also reserve the register pair aliases covering the above |
| 77 | // registers, with the same conditions. |
| 78 | Reserved.set(SP::G0_G1); |
| 79 | if (ReserveAppRegisters) |
| 80 | Reserved.set(SP::G2_G3); |
| 81 | if (ReserveAppRegisters || !Subtarget.is64Bit()) |
| 82 | Reserved.set(SP::G4_G5); |
| 83 | |
| 84 | Reserved.set(SP::O6_O7); |
| 85 | Reserved.set(SP::I6_I7); |
| 86 | Reserved.set(SP::G6_G7); |
| 87 | |
| 88 | // Unaliased double registers are not available in non-V9 targets. |
| 89 | if (!Subtarget.isV9()) { |
| 90 | for (unsigned n = 0; n != 16; ++n) { |
| 91 | for (MCRegAliasIterator AI(SP::D16 + n, this, true); AI.isValid(); ++AI) |
| 92 | Reserved.set(*AI); |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | // Reserve ASR1-ASR31 |
| 97 | for (unsigned n = 0; n < 31; n++) |
| 98 | Reserved.set(SP::ASR1 + n); |
| 99 | |
| 100 | for (TargetRegisterClass::iterator i = SP::IntRegsRegClass.begin(); |
| 101 | i != SP::IntRegsRegClass.end(); ++i) { |
| 102 | if (MF.getSubtarget<SparcSubtarget>().isRegisterReserved(PhysReg: *i)) |
| 103 | markSuperRegs(RegisterSet&: Reserved, Reg: *i); |
| 104 | } |
| 105 | |
| 106 | assert(checkAllSuperRegsMarked(Reserved)); |
| 107 | return Reserved; |
| 108 | } |
| 109 | |
| 110 | bool SparcRegisterInfo::isReservedReg(const MachineFunction &MF, |
| 111 | MCRegister Reg) const { |
| 112 | return getReservedRegs(MF)[Reg]; |
| 113 | } |
| 114 | |
| 115 | const TargetRegisterClass * |
| 116 | SparcRegisterInfo::getPointerRegClass(unsigned Kind) const { |
| 117 | assert(Kind == 0 && "this should only be used for default cases" ); |
| 118 | return Is64Bit ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; |
| 119 | } |
| 120 | |
| 121 | static void replaceFI(MachineFunction &MF, MachineBasicBlock::iterator II, |
| 122 | MachineInstr &MI, const DebugLoc &dl, |
| 123 | unsigned FIOperandNum, int Offset, unsigned FramePtr) { |
| 124 | // Replace frame index with a frame pointer reference. |
| 125 | if (Offset >= -4096 && Offset <= 4095) { |
| 126 | // If the offset is small enough to fit in the immediate field, directly |
| 127 | // encode it. |
| 128 | MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: FramePtr, isDef: false); |
| 129 | MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: Offset); |
| 130 | return; |
| 131 | } |
| 132 | |
| 133 | const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); |
| 134 | |
| 135 | // FIXME: it would be better to scavenge a register here instead of |
| 136 | // reserving G1 all of the time. |
| 137 | if (Offset >= 0) { |
| 138 | // Emit nonnegaive immediates with sethi + or. |
| 139 | // sethi %hi(Offset), %g1 |
| 140 | // add %g1, %fp, %g1 |
| 141 | // Insert G1+%lo(offset) into the user. |
| 142 | BuildMI(BB&: *MI.getParent(), I: II, MIMD: dl, MCID: TII.get(Opcode: SP::SETHIi), DestReg: SP::G1) |
| 143 | .addImm(Val: HI22(imm: Offset)); |
| 144 | |
| 145 | |
| 146 | // Emit G1 = G1 + I6 |
| 147 | BuildMI(BB&: *MI.getParent(), I: II, MIMD: dl, MCID: TII.get(Opcode: SP::ADDrr), DestReg: SP::G1).addReg(RegNo: SP::G1) |
| 148 | .addReg(RegNo: FramePtr); |
| 149 | // Insert: G1+%lo(offset) into the user. |
| 150 | MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: SP::G1, isDef: false); |
| 151 | MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: LO10(imm: Offset)); |
| 152 | return; |
| 153 | } |
| 154 | |
| 155 | // Emit Negative numbers with sethi + xor |
| 156 | // sethi %hix(Offset), %g1 |
| 157 | // xor %g1, %lox(offset), %g1 |
| 158 | // add %g1, %fp, %g1 |
| 159 | // Insert: G1 + 0 into the user. |
| 160 | BuildMI(BB&: *MI.getParent(), I: II, MIMD: dl, MCID: TII.get(Opcode: SP::SETHIi), DestReg: SP::G1) |
| 161 | .addImm(Val: HIX22(imm: Offset)); |
| 162 | BuildMI(BB&: *MI.getParent(), I: II, MIMD: dl, MCID: TII.get(Opcode: SP::XORri), DestReg: SP::G1) |
| 163 | .addReg(RegNo: SP::G1).addImm(Val: LOX10(imm: Offset)); |
| 164 | |
| 165 | BuildMI(BB&: *MI.getParent(), I: II, MIMD: dl, MCID: TII.get(Opcode: SP::ADDrr), DestReg: SP::G1).addReg(RegNo: SP::G1) |
| 166 | .addReg(RegNo: FramePtr); |
| 167 | // Insert: G1+%lo(offset) into the user. |
| 168 | MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: SP::G1, isDef: false); |
| 169 | MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: 0); |
| 170 | } |
| 171 | |
| 172 | |
| 173 | bool |
| 174 | SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, |
| 175 | int SPAdj, unsigned FIOperandNum, |
| 176 | RegScavenger *RS) const { |
| 177 | assert(SPAdj == 0 && "Unexpected" ); |
| 178 | |
| 179 | MachineInstr &MI = *II; |
| 180 | DebugLoc dl = MI.getDebugLoc(); |
| 181 | int FrameIndex = MI.getOperand(i: FIOperandNum).getIndex(); |
| 182 | MachineFunction &MF = *MI.getParent()->getParent(); |
| 183 | const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>(); |
| 184 | const SparcFrameLowering *TFI = getFrameLowering(MF); |
| 185 | |
| 186 | Register FrameReg; |
| 187 | int Offset; |
| 188 | Offset = TFI->getFrameIndexReference(MF, FI: FrameIndex, FrameReg).getFixed(); |
| 189 | |
| 190 | Offset += MI.getOperand(i: FIOperandNum + 1).getImm(); |
| 191 | |
| 192 | if (!Subtarget.isV9() || !Subtarget.hasHardQuad()) { |
| 193 | if (MI.getOpcode() == SP::STQFri) { |
| 194 | const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); |
| 195 | Register SrcReg = MI.getOperand(i: 2).getReg(); |
| 196 | Register SrcEvenReg = getSubReg(Reg: SrcReg, Idx: SP::sub_even64); |
| 197 | Register SrcOddReg = getSubReg(Reg: SrcReg, Idx: SP::sub_odd64); |
| 198 | MachineInstr *StMI = |
| 199 | BuildMI(BB&: *MI.getParent(), I: II, MIMD: dl, MCID: TII.get(Opcode: SP::STDFri)) |
| 200 | .addReg(RegNo: FrameReg).addImm(Val: 0).addReg(RegNo: SrcEvenReg); |
| 201 | replaceFI(MF, II: *StMI, MI&: *StMI, dl, FIOperandNum: 0, Offset, FramePtr: FrameReg); |
| 202 | MI.setDesc(TII.get(Opcode: SP::STDFri)); |
| 203 | MI.getOperand(i: 2).setReg(SrcOddReg); |
| 204 | Offset += 8; |
| 205 | } else if (MI.getOpcode() == SP::LDQFri) { |
| 206 | const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); |
| 207 | Register DestReg = MI.getOperand(i: 0).getReg(); |
| 208 | Register DestEvenReg = getSubReg(Reg: DestReg, Idx: SP::sub_even64); |
| 209 | Register DestOddReg = getSubReg(Reg: DestReg, Idx: SP::sub_odd64); |
| 210 | MachineInstr *LdMI = |
| 211 | BuildMI(BB&: *MI.getParent(), I: II, MIMD: dl, MCID: TII.get(Opcode: SP::LDDFri), DestReg: DestEvenReg) |
| 212 | .addReg(RegNo: FrameReg).addImm(Val: 0); |
| 213 | replaceFI(MF, II: *LdMI, MI&: *LdMI, dl, FIOperandNum: 1, Offset, FramePtr: FrameReg); |
| 214 | |
| 215 | MI.setDesc(TII.get(Opcode: SP::LDDFri)); |
| 216 | MI.getOperand(i: 0).setReg(DestOddReg); |
| 217 | Offset += 8; |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | replaceFI(MF, II, MI, dl, FIOperandNum, Offset, FramePtr: FrameReg); |
| 222 | // replaceFI never removes II |
| 223 | return false; |
| 224 | } |
| 225 | |
| 226 | Register SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const { |
| 227 | return SP::I6; |
| 228 | } |
| 229 | |