| 1 | //===-- XCoreRegisterInfo.cpp - XCore 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 XCore implementation of the MRegisterInfo class. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #include "XCoreRegisterInfo.h" |
| 14 | #include "XCoreInstrInfo.h" |
| 15 | #include "XCoreSubtarget.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/MachineModuleInfo.h" |
| 21 | #include "llvm/CodeGen/RegisterScavenging.h" |
| 22 | #include "llvm/CodeGen/TargetFrameLowering.h" |
| 23 | #include "llvm/IR/Function.h" |
| 24 | #include "llvm/IR/Type.h" |
| 25 | #include "llvm/Support/Debug.h" |
| 26 | #include "llvm/Support/ErrorHandling.h" |
| 27 | #include "llvm/Support/raw_ostream.h" |
| 28 | #include "llvm/Target/TargetMachine.h" |
| 29 | #include "llvm/Target/TargetOptions.h" |
| 30 | |
| 31 | using namespace llvm; |
| 32 | |
| 33 | #define DEBUG_TYPE "xcore-reg-info" |
| 34 | |
| 35 | #define GET_REGINFO_TARGET_DESC |
| 36 | #include "XCoreGenRegisterInfo.inc" |
| 37 | |
| 38 | XCoreRegisterInfo::XCoreRegisterInfo() |
| 39 | : XCoreGenRegisterInfo(XCore::LR) { |
| 40 | } |
| 41 | |
| 42 | // helper functions |
| 43 | static inline bool isImmUs(unsigned val) { |
| 44 | return val <= 11; |
| 45 | } |
| 46 | |
| 47 | static inline bool isImmU6(unsigned val) { |
| 48 | return val < (1 << 6); |
| 49 | } |
| 50 | |
| 51 | static inline bool isImmU16(unsigned val) { |
| 52 | return val < (1 << 16); |
| 53 | } |
| 54 | |
| 55 | |
| 56 | static void InsertFPImmInst(MachineBasicBlock::iterator II, |
| 57 | const XCoreInstrInfo &TII, |
| 58 | unsigned Reg, unsigned FrameReg, int Offset ) { |
| 59 | MachineInstr &MI = *II; |
| 60 | MachineBasicBlock &MBB = *MI.getParent(); |
| 61 | DebugLoc dl = MI.getDebugLoc(); |
| 62 | |
| 63 | switch (MI.getOpcode()) { |
| 64 | case XCore::LDWFI: |
| 65 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::LDW_2rus), DestReg: Reg) |
| 66 | .addReg(RegNo: FrameReg) |
| 67 | .addImm(Val: Offset) |
| 68 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 69 | break; |
| 70 | case XCore::STWFI: |
| 71 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::STW_2rus)) |
| 72 | .addReg(RegNo: Reg, Flags: getKillRegState(B: MI.getOperand(i: 0).isKill())) |
| 73 | .addReg(RegNo: FrameReg) |
| 74 | .addImm(Val: Offset) |
| 75 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 76 | break; |
| 77 | case XCore::LDAWFI: |
| 78 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::LDAWF_l2rus), DestReg: Reg) |
| 79 | .addReg(RegNo: FrameReg) |
| 80 | .addImm(Val: Offset); |
| 81 | break; |
| 82 | default: |
| 83 | llvm_unreachable("Unexpected Opcode" ); |
| 84 | } |
| 85 | } |
| 86 | |
| 87 | static void InsertFPConstInst(MachineBasicBlock::iterator II, |
| 88 | const XCoreInstrInfo &TII, |
| 89 | unsigned Reg, unsigned FrameReg, |
| 90 | int Offset, RegScavenger *RS ) { |
| 91 | assert(RS && "requiresRegisterScavenging failed" ); |
| 92 | MachineInstr &MI = *II; |
| 93 | MachineBasicBlock &MBB = *MI.getParent(); |
| 94 | DebugLoc dl = MI.getDebugLoc(); |
| 95 | Register ScratchOffset = |
| 96 | RS->scavengeRegisterBackwards(RC: XCore::GRRegsRegClass, To: II, RestoreAfter: false, SPAdj: 0); |
| 97 | RS->setRegUsed(Reg: ScratchOffset); |
| 98 | TII.loadImmediate(MBB, MI: II, Reg: ScratchOffset, Value: Offset); |
| 99 | |
| 100 | switch (MI.getOpcode()) { |
| 101 | case XCore::LDWFI: |
| 102 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::LDW_3r), DestReg: Reg) |
| 103 | .addReg(RegNo: FrameReg) |
| 104 | .addReg(RegNo: ScratchOffset, Flags: RegState::Kill) |
| 105 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 106 | break; |
| 107 | case XCore::STWFI: |
| 108 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::STW_l3r)) |
| 109 | .addReg(RegNo: Reg, Flags: getKillRegState(B: MI.getOperand(i: 0).isKill())) |
| 110 | .addReg(RegNo: FrameReg) |
| 111 | .addReg(RegNo: ScratchOffset, Flags: RegState::Kill) |
| 112 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 113 | break; |
| 114 | case XCore::LDAWFI: |
| 115 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::LDAWF_l3r), DestReg: Reg) |
| 116 | .addReg(RegNo: FrameReg) |
| 117 | .addReg(RegNo: ScratchOffset, Flags: RegState::Kill); |
| 118 | break; |
| 119 | default: |
| 120 | llvm_unreachable("Unexpected Opcode" ); |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | static void InsertSPImmInst(MachineBasicBlock::iterator II, |
| 125 | const XCoreInstrInfo &TII, |
| 126 | unsigned Reg, int Offset) { |
| 127 | MachineInstr &MI = *II; |
| 128 | MachineBasicBlock &MBB = *MI.getParent(); |
| 129 | DebugLoc dl = MI.getDebugLoc(); |
| 130 | bool isU6 = isImmU6(val: Offset); |
| 131 | |
| 132 | switch (MI.getOpcode()) { |
| 133 | int NewOpcode; |
| 134 | case XCore::LDWFI: |
| 135 | NewOpcode = (isU6) ? XCore::LDWSP_ru6 : XCore::LDWSP_lru6; |
| 136 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: NewOpcode), DestReg: Reg) |
| 137 | .addImm(Val: Offset) |
| 138 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 139 | break; |
| 140 | case XCore::STWFI: |
| 141 | NewOpcode = (isU6) ? XCore::STWSP_ru6 : XCore::STWSP_lru6; |
| 142 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: NewOpcode)) |
| 143 | .addReg(RegNo: Reg, Flags: getKillRegState(B: MI.getOperand(i: 0).isKill())) |
| 144 | .addImm(Val: Offset) |
| 145 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 146 | break; |
| 147 | case XCore::LDAWFI: |
| 148 | NewOpcode = (isU6) ? XCore::LDAWSP_ru6 : XCore::LDAWSP_lru6; |
| 149 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: NewOpcode), DestReg: Reg) |
| 150 | .addImm(Val: Offset); |
| 151 | break; |
| 152 | default: |
| 153 | llvm_unreachable("Unexpected Opcode" ); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | static void InsertSPConstInst(MachineBasicBlock::iterator II, |
| 158 | const XCoreInstrInfo &TII, |
| 159 | unsigned Reg, int Offset, RegScavenger *RS ) { |
| 160 | assert(RS && "requiresRegisterScavenging failed" ); |
| 161 | MachineInstr &MI = *II; |
| 162 | MachineBasicBlock &MBB = *MI.getParent(); |
| 163 | DebugLoc dl = MI.getDebugLoc(); |
| 164 | unsigned OpCode = MI.getOpcode(); |
| 165 | |
| 166 | unsigned ScratchBase; |
| 167 | if (OpCode==XCore::STWFI) { |
| 168 | ScratchBase = |
| 169 | RS->scavengeRegisterBackwards(RC: XCore::GRRegsRegClass, To: II, RestoreAfter: false, SPAdj: 0); |
| 170 | RS->setRegUsed(Reg: ScratchBase); |
| 171 | } else |
| 172 | ScratchBase = Reg; |
| 173 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::LDAWSP_ru6), DestReg: ScratchBase).addImm(Val: 0); |
| 174 | Register ScratchOffset = |
| 175 | RS->scavengeRegisterBackwards(RC: XCore::GRRegsRegClass, To: II, RestoreAfter: false, SPAdj: 0); |
| 176 | RS->setRegUsed(Reg: ScratchOffset); |
| 177 | TII.loadImmediate(MBB, MI: II, Reg: ScratchOffset, Value: Offset); |
| 178 | |
| 179 | switch (OpCode) { |
| 180 | case XCore::LDWFI: |
| 181 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::LDW_3r), DestReg: Reg) |
| 182 | .addReg(RegNo: ScratchBase, Flags: RegState::Kill) |
| 183 | .addReg(RegNo: ScratchOffset, Flags: RegState::Kill) |
| 184 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 185 | break; |
| 186 | case XCore::STWFI: |
| 187 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::STW_l3r)) |
| 188 | .addReg(RegNo: Reg, Flags: getKillRegState(B: MI.getOperand(i: 0).isKill())) |
| 189 | .addReg(RegNo: ScratchBase, Flags: RegState::Kill) |
| 190 | .addReg(RegNo: ScratchOffset, Flags: RegState::Kill) |
| 191 | .addMemOperand(MMO: *MI.memoperands_begin()); |
| 192 | break; |
| 193 | case XCore::LDAWFI: |
| 194 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: XCore::LDAWF_l3r), DestReg: Reg) |
| 195 | .addReg(RegNo: ScratchBase, Flags: RegState::Kill) |
| 196 | .addReg(RegNo: ScratchOffset, Flags: RegState::Kill); |
| 197 | break; |
| 198 | default: |
| 199 | llvm_unreachable("Unexpected Opcode" ); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | bool XCoreRegisterInfo::needsFrameMoves(const MachineFunction &MF) { |
| 204 | return MF.needsFrameMoves(); |
| 205 | } |
| 206 | |
| 207 | const MCPhysReg * |
| 208 | XCoreRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { |
| 209 | // The callee saved registers LR & FP are explicitly handled during |
| 210 | // emitPrologue & emitEpilogue and related functions. |
| 211 | static const MCPhysReg CalleeSavedRegs[] = { |
| 212 | XCore::R4, XCore::R5, XCore::R6, XCore::R7, |
| 213 | XCore::R8, XCore::R9, XCore::R10, |
| 214 | 0 |
| 215 | }; |
| 216 | static const MCPhysReg CalleeSavedRegsFP[] = { |
| 217 | XCore::R4, XCore::R5, XCore::R6, XCore::R7, |
| 218 | XCore::R8, XCore::R9, |
| 219 | 0 |
| 220 | }; |
| 221 | const XCoreFrameLowering *TFI = getFrameLowering(MF: *MF); |
| 222 | if (TFI->hasFP(MF: *MF)) |
| 223 | return CalleeSavedRegsFP; |
| 224 | return CalleeSavedRegs; |
| 225 | } |
| 226 | |
| 227 | BitVector XCoreRegisterInfo::getReservedRegs(const MachineFunction &MF) const { |
| 228 | BitVector Reserved(getNumRegs()); |
| 229 | const XCoreFrameLowering *TFI = getFrameLowering(MF); |
| 230 | |
| 231 | Reserved.set(XCore::CP); |
| 232 | Reserved.set(XCore::DP); |
| 233 | Reserved.set(XCore::SP); |
| 234 | Reserved.set(XCore::LR); |
| 235 | if (TFI->hasFP(MF)) { |
| 236 | Reserved.set(XCore::R10); |
| 237 | } |
| 238 | return Reserved; |
| 239 | } |
| 240 | |
| 241 | bool |
| 242 | XCoreRegisterInfo::requiresRegisterScavenging(const MachineFunction &MF) const { |
| 243 | return true; |
| 244 | } |
| 245 | |
| 246 | bool |
| 247 | XCoreRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const { |
| 248 | return false; |
| 249 | } |
| 250 | |
| 251 | bool |
| 252 | XCoreRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, |
| 253 | int SPAdj, unsigned FIOperandNum, |
| 254 | RegScavenger *RS) const { |
| 255 | assert(SPAdj == 0 && "Unexpected" ); |
| 256 | MachineInstr &MI = *II; |
| 257 | MachineOperand &FrameOp = MI.getOperand(i: FIOperandNum); |
| 258 | int FrameIndex = FrameOp.getIndex(); |
| 259 | |
| 260 | MachineFunction &MF = *MI.getParent()->getParent(); |
| 261 | const XCoreInstrInfo &TII = |
| 262 | *static_cast<const XCoreInstrInfo *>(MF.getSubtarget().getInstrInfo()); |
| 263 | |
| 264 | const XCoreFrameLowering *TFI = getFrameLowering(MF); |
| 265 | int Offset = MF.getFrameInfo().getObjectOffset(ObjectIdx: FrameIndex); |
| 266 | int StackSize = MF.getFrameInfo().getStackSize(); |
| 267 | |
| 268 | #ifndef NDEBUG |
| 269 | LLVM_DEBUG(errs() << "\nFunction : " << MF.getName() << "\n" ); |
| 270 | LLVM_DEBUG(errs() << "<--------->\n" ); |
| 271 | LLVM_DEBUG(MI.print(errs())); |
| 272 | LLVM_DEBUG(errs() << "FrameIndex : " << FrameIndex << "\n" ); |
| 273 | LLVM_DEBUG(errs() << "FrameOffset : " << Offset << "\n" ); |
| 274 | LLVM_DEBUG(errs() << "StackSize : " << StackSize << "\n" ); |
| 275 | #endif |
| 276 | |
| 277 | Offset += StackSize; |
| 278 | |
| 279 | Register FrameReg = getFrameRegister(MF); |
| 280 | |
| 281 | // Special handling of DBG_VALUE instructions. |
| 282 | if (MI.isDebugValue()) { |
| 283 | MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: FrameReg, isDef: false /*isDef*/); |
| 284 | MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: Offset); |
| 285 | return false; |
| 286 | } |
| 287 | |
| 288 | // fold constant into offset. |
| 289 | Offset += MI.getOperand(i: FIOperandNum + 1).getImm(); |
| 290 | MI.getOperand(i: FIOperandNum + 1).ChangeToImmediate(ImmVal: 0); |
| 291 | |
| 292 | assert(Offset%4 == 0 && "Misaligned stack offset" ); |
| 293 | LLVM_DEBUG(errs() << "Offset : " << Offset << "\n" |
| 294 | << "<--------->\n" ); |
| 295 | Offset/=4; |
| 296 | |
| 297 | Register Reg = MI.getOperand(i: 0).getReg(); |
| 298 | assert(XCore::GRRegsRegClass.contains(Reg) && "Unexpected register operand" ); |
| 299 | |
| 300 | if (TFI->hasFP(MF)) { |
| 301 | if (isImmUs(val: Offset)) |
| 302 | InsertFPImmInst(II, TII, Reg, FrameReg, Offset); |
| 303 | else |
| 304 | InsertFPConstInst(II, TII, Reg, FrameReg, Offset, RS); |
| 305 | } else { |
| 306 | if (isImmU16(val: Offset)) |
| 307 | InsertSPImmInst(II, TII, Reg, Offset); |
| 308 | else |
| 309 | InsertSPConstInst(II, TII, Reg, Offset, RS); |
| 310 | } |
| 311 | // Erase old instruction. |
| 312 | MachineBasicBlock &MBB = *MI.getParent(); |
| 313 | MBB.erase(I: II); |
| 314 | return true; |
| 315 | } |
| 316 | |
| 317 | |
| 318 | Register XCoreRegisterInfo::getFrameRegister(const MachineFunction &MF) const { |
| 319 | const XCoreFrameLowering *TFI = getFrameLowering(MF); |
| 320 | |
| 321 | return TFI->hasFP(MF) ? XCore::R10 : XCore::SP; |
| 322 | } |
| 323 | |