| 1 | //===-- MipsSERegisterInfo.cpp - MIPS32/64 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 MIPS32/64 implementation of the TargetRegisterInfo |
| 10 | // class. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "MipsSERegisterInfo.h" |
| 15 | #include "Mips.h" |
| 16 | #include "MipsMachineFunction.h" |
| 17 | #include "MipsSEInstrInfo.h" |
| 18 | #include "MipsSubtarget.h" |
| 19 | #include "MipsTargetMachine.h" |
| 20 | #include "llvm/CodeGen/MachineFrameInfo.h" |
| 21 | #include "llvm/CodeGen/MachineFunction.h" |
| 22 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
| 23 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
| 24 | #include "llvm/CodeGen/TargetFrameLowering.h" |
| 25 | #include "llvm/CodeGen/TargetInstrInfo.h" |
| 26 | #include "llvm/IR/Function.h" |
| 27 | #include "llvm/IR/Type.h" |
| 28 | #include "llvm/Support/Debug.h" |
| 29 | #include "llvm/Support/raw_ostream.h" |
| 30 | #include "llvm/Target/TargetMachine.h" |
| 31 | #include "llvm/Target/TargetOptions.h" |
| 32 | |
| 33 | using namespace llvm; |
| 34 | |
| 35 | #define DEBUG_TYPE "mips-reg-info" |
| 36 | |
| 37 | MipsSERegisterInfo::MipsSERegisterInfo(const MipsSubtarget &STI) |
| 38 | : MipsRegisterInfo(STI) {} |
| 39 | |
| 40 | bool MipsSERegisterInfo:: |
| 41 | requiresRegisterScavenging(const MachineFunction &MF) const { |
| 42 | return true; |
| 43 | } |
| 44 | |
| 45 | bool MipsSERegisterInfo:: |
| 46 | requiresFrameIndexScavenging(const MachineFunction &MF) const { |
| 47 | return true; |
| 48 | } |
| 49 | |
| 50 | const TargetRegisterClass * |
| 51 | MipsSERegisterInfo::intRegClass(unsigned Size) const { |
| 52 | if (Size == 4) |
| 53 | return &Mips::GPR32RegClass; |
| 54 | |
| 55 | assert(Size == 8); |
| 56 | return &Mips::GPR64RegClass; |
| 57 | } |
| 58 | |
| 59 | /// Get the size of the offset supported by the given load/store/inline asm. |
| 60 | /// The result includes the effects of any scale factors applied to the |
| 61 | /// instruction immediate. |
| 62 | static inline unsigned getLoadStoreOffsetSizeInBits(const unsigned Opcode, |
| 63 | MachineOperand MO) { |
| 64 | switch (Opcode) { |
| 65 | case Mips::LD_B: |
| 66 | case Mips::ST_B: |
| 67 | return 10; |
| 68 | case Mips::LD_H: |
| 69 | case Mips::ST_H: |
| 70 | return 10 + 1 /* scale factor */; |
| 71 | case Mips::LD_W: |
| 72 | case Mips::ST_W: |
| 73 | return 10 + 2 /* scale factor */; |
| 74 | case Mips::LD_D: |
| 75 | case Mips::ST_D: |
| 76 | return 10 + 3 /* scale factor */; |
| 77 | case Mips::LL: |
| 78 | case Mips::LL64: |
| 79 | case Mips::LLD: |
| 80 | case Mips::LLE: |
| 81 | case Mips::SC: |
| 82 | case Mips::SC64: |
| 83 | case Mips::SCD: |
| 84 | case Mips::SCE: |
| 85 | return 16; |
| 86 | case Mips::LLE_MM: |
| 87 | case Mips::LL_MM: |
| 88 | case Mips::SCE_MM: |
| 89 | case Mips::SC_MM: |
| 90 | return 12; |
| 91 | case Mips::LL64_R6: |
| 92 | case Mips::LL_R6: |
| 93 | case Mips::LLD_R6: |
| 94 | case Mips::SC64_R6: |
| 95 | case Mips::SCD_R6: |
| 96 | case Mips::SC_R6: |
| 97 | case Mips::LL_MMR6: |
| 98 | case Mips::SC_MMR6: |
| 99 | return 9; |
| 100 | case Mips::INLINEASM: { |
| 101 | const InlineAsm::Flag F(MO.getImm()); |
| 102 | switch (F.getMemoryConstraintID()) { |
| 103 | case InlineAsm::ConstraintCode::ZC: { |
| 104 | const MipsSubtarget &Subtarget = MO.getParent() |
| 105 | ->getParent() |
| 106 | ->getParent() |
| 107 | ->getSubtarget<MipsSubtarget>(); |
| 108 | if (Subtarget.inMicroMipsMode()) |
| 109 | return 12; |
| 110 | |
| 111 | if (Subtarget.hasMips32r6()) |
| 112 | return 9; |
| 113 | |
| 114 | return 16; |
| 115 | } |
| 116 | default: |
| 117 | return 16; |
| 118 | } |
| 119 | } |
| 120 | default: |
| 121 | return 16; |
| 122 | } |
| 123 | } |
| 124 | |
| 125 | /// Get the scale factor applied to the immediate in the given load/store. |
| 126 | static inline unsigned getLoadStoreOffsetAlign(const unsigned Opcode) { |
| 127 | switch (Opcode) { |
| 128 | case Mips::LD_H: |
| 129 | case Mips::ST_H: |
| 130 | return 2; |
| 131 | case Mips::LD_W: |
| 132 | case Mips::ST_W: |
| 133 | return 4; |
| 134 | case Mips::LD_D: |
| 135 | case Mips::ST_D: |
| 136 | return 8; |
| 137 | default: |
| 138 | return 1; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | void MipsSERegisterInfo::eliminateFI(MachineBasicBlock::iterator II, |
| 143 | unsigned OpNo, int FrameIndex, |
| 144 | uint64_t StackSize, |
| 145 | int64_t SPOffset) const { |
| 146 | MachineInstr &MI = *II; |
| 147 | MachineFunction &MF = *MI.getParent()->getParent(); |
| 148 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
| 149 | MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>(); |
| 150 | |
| 151 | MipsABIInfo ABI = |
| 152 | static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI(); |
| 153 | const MipsRegisterInfo *RegInfo = |
| 154 | static_cast<const MipsRegisterInfo *>(MF.getSubtarget().getRegisterInfo()); |
| 155 | |
| 156 | const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); |
| 157 | int MinCSFI = 0; |
| 158 | int MaxCSFI = -1; |
| 159 | |
| 160 | if (CSI.size()) { |
| 161 | MinCSFI = CSI[0].getFrameIdx(); |
| 162 | MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); |
| 163 | } |
| 164 | |
| 165 | bool EhDataRegFI = MipsFI->isEhDataRegFI(FI: FrameIndex); |
| 166 | bool IsISRRegFI = MipsFI->isISRRegFI(FI: FrameIndex); |
| 167 | // The following stack frame objects are always referenced relative to $sp: |
| 168 | // 1. Outgoing arguments. |
| 169 | // 2. Pointer to dynamically allocated stack space. |
| 170 | // 3. Locations for callee-saved registers. |
| 171 | // 4. Locations for eh data registers. |
| 172 | // 5. Locations for ISR saved Coprocessor 0 registers 12 & 14. |
| 173 | // Everything else is referenced relative to whatever register |
| 174 | // getFrameRegister() returns. |
| 175 | unsigned FrameReg; |
| 176 | |
| 177 | if ((FrameIndex >= MinCSFI && FrameIndex <= MaxCSFI) || EhDataRegFI || |
| 178 | IsISRRegFI) |
| 179 | FrameReg = ABI.GetStackPtr(); |
| 180 | else if (RegInfo->hasStackRealignment(MF)) { |
| 181 | if (MFI.hasVarSizedObjects() && !MFI.isFixedObjectIndex(ObjectIdx: FrameIndex)) |
| 182 | FrameReg = ABI.GetBasePtr(); |
| 183 | else if (MFI.isFixedObjectIndex(ObjectIdx: FrameIndex)) |
| 184 | FrameReg = getFrameRegister(MF); |
| 185 | else |
| 186 | FrameReg = ABI.GetStackPtr(); |
| 187 | } else |
| 188 | FrameReg = getFrameRegister(MF); |
| 189 | |
| 190 | // Calculate final offset. |
| 191 | // - There is no need to change the offset if the frame object is one of the |
| 192 | // following: an outgoing argument, pointer to a dynamically allocated |
| 193 | // stack space or a $gp restore location, |
| 194 | // - If the frame object is any of the following, its offset must be adjusted |
| 195 | // by adding the size of the stack: |
| 196 | // incoming argument, callee-saved register location or local variable. |
| 197 | bool IsKill = false; |
| 198 | int64_t Offset; |
| 199 | |
| 200 | Offset = SPOffset + (int64_t)StackSize; |
| 201 | Offset += MI.getOperand(i: OpNo + 1).getImm(); |
| 202 | |
| 203 | LLVM_DEBUG(errs() << "Offset : " << Offset << "\n" |
| 204 | << "<--------->\n" ); |
| 205 | |
| 206 | if (!MI.isDebugValue()) { |
| 207 | // Make sure Offset fits within the field available. |
| 208 | // For MSA instructions, this is a 10-bit signed immediate (scaled by |
| 209 | // element size), otherwise it is a 16-bit signed immediate. |
| 210 | unsigned OffsetBitSize = |
| 211 | getLoadStoreOffsetSizeInBits(Opcode: MI.getOpcode(), MO: MI.getOperand(i: OpNo - 1)); |
| 212 | const Align OffsetAlign(getLoadStoreOffsetAlign(Opcode: MI.getOpcode())); |
| 213 | if (OffsetBitSize < 16 && isInt<16>(x: Offset) && |
| 214 | (!isIntN(N: OffsetBitSize, x: Offset) || !isAligned(Lhs: OffsetAlign, SizeInBytes: Offset))) { |
| 215 | // If we have an offset that needs to fit into a signed n-bit immediate |
| 216 | // (where n < 16) and doesn't, but does fit into 16-bits then use an ADDiu |
| 217 | MachineBasicBlock &MBB = *MI.getParent(); |
| 218 | DebugLoc DL = II->getDebugLoc(); |
| 219 | const TargetRegisterClass *PtrRC = |
| 220 | ABI.ArePtrs64bit() ? &Mips::GPR64RegClass : &Mips::GPR32RegClass; |
| 221 | MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); |
| 222 | Register Reg = RegInfo.createVirtualRegister(RegClass: PtrRC); |
| 223 | const MipsSEInstrInfo &TII = |
| 224 | *static_cast<const MipsSEInstrInfo *>( |
| 225 | MBB.getParent()->getSubtarget().getInstrInfo()); |
| 226 | BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: TII.get(Opcode: ABI.GetPtrAddiuOp()), DestReg: Reg) |
| 227 | .addReg(RegNo: FrameReg) |
| 228 | .addImm(Val: Offset); |
| 229 | |
| 230 | FrameReg = Reg; |
| 231 | Offset = 0; |
| 232 | IsKill = true; |
| 233 | } else if (!isInt<16>(x: Offset)) { |
| 234 | // Otherwise split the offset into 16-bit pieces and add it in multiple |
| 235 | // instructions. |
| 236 | MachineBasicBlock &MBB = *MI.getParent(); |
| 237 | DebugLoc DL = II->getDebugLoc(); |
| 238 | unsigned NewImm = 0; |
| 239 | const MipsSEInstrInfo &TII = |
| 240 | *static_cast<const MipsSEInstrInfo *>( |
| 241 | MBB.getParent()->getSubtarget().getInstrInfo()); |
| 242 | unsigned Reg = TII.loadImmediate(Imm: Offset, MBB, II, DL, |
| 243 | NewImm: OffsetBitSize == 16 ? &NewImm : nullptr); |
| 244 | BuildMI(BB&: MBB, I: II, MIMD: DL, MCID: TII.get(Opcode: ABI.GetPtrAdduOp()), DestReg: Reg).addReg(RegNo: FrameReg) |
| 245 | .addReg(RegNo: Reg, Flags: RegState::Kill); |
| 246 | |
| 247 | FrameReg = Reg; |
| 248 | Offset = SignExtend64<16>(x: NewImm); |
| 249 | IsKill = true; |
| 250 | } |
| 251 | } |
| 252 | |
| 253 | MI.getOperand(i: OpNo).ChangeToRegister(Reg: FrameReg, isDef: false, isImp: false, isKill: IsKill); |
| 254 | MI.getOperand(i: OpNo + 1).ChangeToImmediate(ImmVal: Offset); |
| 255 | } |
| 256 | |