| 1 | //===-- ThumbRegisterInfo.cpp - Thumb-1 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 Thumb-1 implementation of the TargetRegisterInfo |
| 10 | // class. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "ThumbRegisterInfo.h" |
| 15 | #include "ARMBaseInstrInfo.h" |
| 16 | #include "ARMMachineFunctionInfo.h" |
| 17 | #include "ARMSubtarget.h" |
| 18 | #include "llvm/CodeGen/MachineConstantPool.h" |
| 19 | #include "llvm/CodeGen/MachineFrameInfo.h" |
| 20 | #include "llvm/CodeGen/MachineFunction.h" |
| 21 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
| 22 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
| 23 | #include "llvm/CodeGen/RegisterScavenging.h" |
| 24 | #include "llvm/CodeGen/TargetFrameLowering.h" |
| 25 | #include "llvm/IR/Constants.h" |
| 26 | #include "llvm/IR/Function.h" |
| 27 | #include "llvm/IR/LLVMContext.h" |
| 28 | #include "llvm/Support/CommandLine.h" |
| 29 | #include "llvm/Support/ErrorHandling.h" |
| 30 | #include "llvm/Target/TargetMachine.h" |
| 31 | |
| 32 | namespace llvm { |
| 33 | extern cl::opt<bool> ReuseFrameIndexVals; |
| 34 | } |
| 35 | |
| 36 | using namespace llvm; |
| 37 | |
| 38 | ThumbRegisterInfo::ThumbRegisterInfo(const ARMSubtarget &STI) |
| 39 | : IsThumb1Only(STI.isThumb1Only()) {} |
| 40 | |
| 41 | const TargetRegisterClass * |
| 42 | ThumbRegisterInfo::getLargestLegalSuperClass(const TargetRegisterClass *RC, |
| 43 | const MachineFunction &MF) const { |
| 44 | if (!IsThumb1Only) |
| 45 | return ARMBaseRegisterInfo::getLargestLegalSuperClass(RC, MF); |
| 46 | |
| 47 | if (ARM::tGPRRegClass.hasSubClassEq(RC)) |
| 48 | return &ARM::tGPRRegClass; |
| 49 | return ARMBaseRegisterInfo::getLargestLegalSuperClass(RC, MF); |
| 50 | } |
| 51 | |
| 52 | const TargetRegisterClass * |
| 53 | ThumbRegisterInfo::getPointerRegClass(unsigned Kind) const { |
| 54 | if (!IsThumb1Only) |
| 55 | return ARMBaseRegisterInfo::getPointerRegClass(Kind); |
| 56 | return &ARM::tGPRRegClass; |
| 57 | } |
| 58 | |
| 59 | static void emitThumb1LoadConstPool(MachineBasicBlock &MBB, |
| 60 | MachineBasicBlock::iterator &MBBI, |
| 61 | const DebugLoc &dl, unsigned DestReg, |
| 62 | unsigned SubIdx, int Val, |
| 63 | ARMCC::CondCodes Pred, unsigned PredReg, |
| 64 | unsigned MIFlags) { |
| 65 | MachineFunction &MF = *MBB.getParent(); |
| 66 | const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>(); |
| 67 | const TargetInstrInfo &TII = *STI.getInstrInfo(); |
| 68 | MachineConstantPool *ConstantPool = MF.getConstantPool(); |
| 69 | const Constant *C = ConstantInt::getSigned( |
| 70 | Ty: Type::getInt32Ty(C&: MBB.getParent()->getFunction().getContext()), V: Val); |
| 71 | unsigned Idx = ConstantPool->getConstantPoolIndex(C, Alignment: Align(4)); |
| 72 | |
| 73 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::tLDRpci)) |
| 74 | .addReg(RegNo: DestReg, Flags: getDefRegState(B: true), SubReg: SubIdx) |
| 75 | .addConstantPoolIndex(Idx).addImm(Val: Pred).addReg(RegNo: PredReg) |
| 76 | .setMIFlags(MIFlags); |
| 77 | } |
| 78 | |
| 79 | static void emitThumb2LoadConstPool(MachineBasicBlock &MBB, |
| 80 | MachineBasicBlock::iterator &MBBI, |
| 81 | const DebugLoc &dl, unsigned DestReg, |
| 82 | unsigned SubIdx, int Val, |
| 83 | ARMCC::CondCodes Pred, unsigned PredReg, |
| 84 | unsigned MIFlags) { |
| 85 | MachineFunction &MF = *MBB.getParent(); |
| 86 | const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); |
| 87 | MachineConstantPool *ConstantPool = MF.getConstantPool(); |
| 88 | const Constant *C = ConstantInt::getSigned( |
| 89 | Ty: Type::getInt32Ty(C&: MBB.getParent()->getFunction().getContext()), V: Val); |
| 90 | unsigned Idx = ConstantPool->getConstantPoolIndex(C, Alignment: Align(4)); |
| 91 | |
| 92 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::t2LDRpci)) |
| 93 | .addReg(RegNo: DestReg, Flags: getDefRegState(B: true), SubReg: SubIdx) |
| 94 | .addConstantPoolIndex(Idx) |
| 95 | .add(MOs: predOps(Pred: ARMCC::AL)) |
| 96 | .setMIFlags(MIFlags); |
| 97 | } |
| 98 | |
| 99 | /// emitLoadConstPool - Emits a load from constpool to materialize the |
| 100 | /// specified immediate. |
| 101 | void ThumbRegisterInfo::emitLoadConstPool( |
| 102 | MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, |
| 103 | const DebugLoc &dl, Register DestReg, unsigned SubIdx, int Val, |
| 104 | ARMCC::CondCodes Pred, Register PredReg, unsigned MIFlags) const { |
| 105 | MachineFunction &MF = *MBB.getParent(); |
| 106 | const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>(); |
| 107 | if (STI.isThumb1Only()) { |
| 108 | assert((DestReg.isVirtual() || isARMLowRegister(DestReg)) && |
| 109 | "Thumb1 does not have ldr to high register" ); |
| 110 | return emitThumb1LoadConstPool(MBB, MBBI, dl, DestReg, SubIdx, Val, Pred, |
| 111 | PredReg, MIFlags); |
| 112 | } |
| 113 | return emitThumb2LoadConstPool(MBB, MBBI, dl, DestReg, SubIdx, Val, Pred, |
| 114 | PredReg, MIFlags); |
| 115 | } |
| 116 | |
| 117 | /// emitThumbRegPlusImmInReg - Emits a series of instructions to materialize a |
| 118 | /// destreg = basereg + immediate in Thumb code. Materialize the immediate in a |
| 119 | /// register using mov / mvn (armv6-M >) sequences, movs / lsls / adds / lsls / |
| 120 | /// adds / lsls / adds sequences (armv6-M) or load the immediate from a |
| 121 | /// constpool entry. |
| 122 | static void emitThumbRegPlusImmInReg( |
| 123 | MachineBasicBlock &MBB, MachineBasicBlock::iterator &MBBI, |
| 124 | const DebugLoc &dl, Register DestReg, Register BaseReg, int NumBytes, |
| 125 | bool CanChangeCC, const TargetInstrInfo &TII, |
| 126 | const ARMBaseRegisterInfo &MRI, unsigned MIFlags = MachineInstr::NoFlags) { |
| 127 | MachineFunction &MF = *MBB.getParent(); |
| 128 | const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>(); |
| 129 | |
| 130 | // Use a single sp-relative add if the immediate is small enough. |
| 131 | if (BaseReg == ARM::SP && |
| 132 | (DestReg.isVirtual() || isARMLowRegister(Reg: DestReg)) && NumBytes >= 0 && |
| 133 | NumBytes <= 1020 && (NumBytes % 4) == 0) { |
| 134 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::tADDrSPi), DestReg) |
| 135 | .addReg(RegNo: ARM::SP) |
| 136 | .addImm(Val: NumBytes / 4) |
| 137 | .add(MOs: predOps(Pred: ARMCC::AL)) |
| 138 | .setMIFlags(MIFlags); |
| 139 | return; |
| 140 | } |
| 141 | |
| 142 | bool isHigh = DestReg.isVirtual() || !isARMLowRegister(Reg: DestReg) || |
| 143 | (BaseReg != 0 && !isARMLowRegister(Reg: BaseReg)); |
| 144 | bool isSub = false; |
| 145 | // Subtract doesn't have high register version. Load the negative value |
| 146 | // if either base or dest register is a high register. Also, if do not |
| 147 | // issue sub as part of the sequence if condition register is to be |
| 148 | // preserved. |
| 149 | if (NumBytes < 0 && !isHigh && CanChangeCC) { |
| 150 | isSub = true; |
| 151 | NumBytes = -NumBytes; |
| 152 | } |
| 153 | Register LdReg = DestReg; |
| 154 | if (DestReg == ARM::SP) |
| 155 | assert(BaseReg == ARM::SP && "Unexpected!" ); |
| 156 | if (!DestReg.isVirtual() && !isARMLowRegister(Reg: DestReg)) |
| 157 | LdReg = MF.getRegInfo().createVirtualRegister(RegClass: &ARM::tGPRRegClass); |
| 158 | |
| 159 | if (NumBytes <= 255 && NumBytes >= 0 && CanChangeCC) { |
| 160 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::tMOVi8), DestReg: LdReg) |
| 161 | .add(MO: t1CondCodeOp()) |
| 162 | .addImm(Val: NumBytes) |
| 163 | .setMIFlags(MIFlags); |
| 164 | } else if (NumBytes < 0 && NumBytes >= -255 && CanChangeCC) { |
| 165 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::tMOVi8), DestReg: LdReg) |
| 166 | .add(MO: t1CondCodeOp()) |
| 167 | .addImm(Val: NumBytes) |
| 168 | .setMIFlags(MIFlags); |
| 169 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::tRSB), DestReg: LdReg) |
| 170 | .add(MO: t1CondCodeOp()) |
| 171 | .addReg(RegNo: LdReg, Flags: RegState::Kill) |
| 172 | .setMIFlags(MIFlags); |
| 173 | } else if (ST.genExecuteOnly()) { |
| 174 | if (ST.useMovt()) { |
| 175 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::t2MOVi32imm ), DestReg: LdReg) |
| 176 | .addImm(Val: NumBytes) |
| 177 | .setMIFlags(MIFlags); |
| 178 | } else if (!CanChangeCC) { |
| 179 | // tMOVi32imm is lowered to a sequence of flag-setting instructions, so |
| 180 | // if CPSR is live we need to save and restore CPSR around it. |
| 181 | // TODO Try inserting the tMOVi32imm at an earlier point, where CPSR is |
| 182 | // dead. |
| 183 | bool LiveCpsr = false, CpsrWrite = false; |
| 184 | auto isCpsr = [](auto &MO) { return MO.getReg() == ARM::CPSR; }; |
| 185 | for (auto Iter = MBBI; Iter != MBB.instr_end(); ++Iter) { |
| 186 | // If CPSR is used after this instruction (and there's not a def before |
| 187 | // that) then CPSR is live. |
| 188 | if (any_of(Range: Iter->all_uses(), P: isCpsr)) { |
| 189 | LiveCpsr = true; |
| 190 | break; |
| 191 | } |
| 192 | if (any_of(Range: Iter->all_defs(), P: isCpsr)) { |
| 193 | CpsrWrite = true; |
| 194 | break; |
| 195 | } |
| 196 | } |
| 197 | // If there's no use or def of CPSR then it may be live if it's a |
| 198 | // live-out value. |
| 199 | auto liveOutIsCpsr = [](auto &Out) { return Out.PhysReg == ARM::CPSR; }; |
| 200 | if (!LiveCpsr && !CpsrWrite) |
| 201 | LiveCpsr = any_of(Range: MBB.liveouts(), P: liveOutIsCpsr); |
| 202 | |
| 203 | Register CPSRSaveReg; |
| 204 | unsigned APSREncoding; |
| 205 | if (LiveCpsr) { |
| 206 | CPSRSaveReg = MF.getRegInfo().createVirtualRegister(RegClass: &ARM::tGPRRegClass); |
| 207 | APSREncoding = |
| 208 | ARMSysReg::lookupMClassSysRegByName(Name: "apsr_nzcvq" )->Encoding; |
| 209 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::t2MRS_M), DestReg: CPSRSaveReg) |
| 210 | .addImm(Val: APSREncoding) |
| 211 | .add(MOs: predOps(Pred: ARMCC::AL)) |
| 212 | .addReg(RegNo: ARM::CPSR, Flags: RegState::Implicit); |
| 213 | } |
| 214 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::tMOVi32imm), DestReg: LdReg) |
| 215 | .addImm(Val: NumBytes) |
| 216 | .setMIFlags(MIFlags); |
| 217 | if (LiveCpsr) { |
| 218 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::t2MSR_M)) |
| 219 | .addImm(Val: APSREncoding) |
| 220 | .addReg(RegNo: CPSRSaveReg, Flags: RegState::Kill) |
| 221 | .add(MOs: predOps(Pred: ARMCC::AL)); |
| 222 | } |
| 223 | } else { |
| 224 | BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ARM::tMOVi32imm), DestReg: LdReg) |
| 225 | .addImm(Val: NumBytes) |
| 226 | .setMIFlags(MIFlags); |
| 227 | } |
| 228 | } else |
| 229 | MRI.emitLoadConstPool(MBB, MBBI, dl, DestReg: LdReg, SubIdx: 0, Val: NumBytes, Pred: ARMCC::AL, PredReg: 0, |
| 230 | MIFlags); |
| 231 | |
| 232 | // Emit add / sub. |
| 233 | int Opc = (isSub) ? ARM::tSUBrr |
| 234 | : ((isHigh || !CanChangeCC) ? ARM::tADDhirr : ARM::tADDrr); |
| 235 | MachineInstrBuilder MIB = BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: Opc), DestReg); |
| 236 | if (Opc != ARM::tADDhirr) |
| 237 | MIB = MIB.add(MO: t1CondCodeOp()); |
| 238 | if (DestReg == ARM::SP || isSub) |
| 239 | MIB.addReg(RegNo: BaseReg).addReg(RegNo: LdReg, Flags: RegState::Kill); |
| 240 | else |
| 241 | MIB.addReg(RegNo: LdReg).addReg(RegNo: BaseReg, Flags: RegState::Kill); |
| 242 | MIB.add(MOs: predOps(Pred: ARMCC::AL)); |
| 243 | } |
| 244 | |
| 245 | /// emitThumbRegPlusImmediate - Emits a series of instructions to materialize |
| 246 | /// a destreg = basereg + immediate in Thumb code. Tries a series of ADDs or |
| 247 | /// SUBs first, and uses a constant pool value if the instruction sequence would |
| 248 | /// be too long. This is allowed to modify the condition flags. |
| 249 | void llvm::emitThumbRegPlusImmediate(MachineBasicBlock &MBB, |
| 250 | MachineBasicBlock::iterator &MBBI, |
| 251 | const DebugLoc &dl, Register DestReg, |
| 252 | Register BaseReg, int NumBytes, |
| 253 | const TargetInstrInfo &TII, |
| 254 | const ARMBaseRegisterInfo &MRI, |
| 255 | unsigned MIFlags) { |
| 256 | bool isSub = NumBytes < 0; |
| 257 | unsigned Bytes = (unsigned)NumBytes; |
| 258 | if (isSub) Bytes = -NumBytes; |
| 259 | |
| 260 | int CopyOpc = 0; |
| 261 | unsigned CopyBits = 0; |
| 262 | unsigned CopyScale = 1; |
| 263 | bool CopyNeedsCC = false; |
| 264 | int = 0; |
| 265 | unsigned = 0; |
| 266 | unsigned = 1; |
| 267 | bool = false; |
| 268 | |
| 269 | // Strategy: |
| 270 | // We need to select two types of instruction, maximizing the available |
| 271 | // immediate range of each. The instructions we use will depend on whether |
| 272 | // DestReg and BaseReg are low, high or the stack pointer. |
| 273 | // * CopyOpc - DestReg = BaseReg + imm |
| 274 | // This will be emitted once if DestReg != BaseReg, and never if |
| 275 | // DestReg == BaseReg. |
| 276 | // * ExtraOpc - DestReg = DestReg + imm |
| 277 | // This will be emitted as many times as necessary to add the |
| 278 | // full immediate. |
| 279 | // If the immediate ranges of these instructions are not large enough to cover |
| 280 | // NumBytes with a reasonable number of instructions, we fall back to using a |
| 281 | // value loaded from a constant pool. |
| 282 | if (DestReg == ARM::SP) { |
| 283 | if (BaseReg == ARM::SP) { |
| 284 | // sp -> sp |
| 285 | // Already in right reg, no copy needed |
| 286 | } else { |
| 287 | // low -> sp or high -> sp |
| 288 | CopyOpc = ARM::tMOVr; |
| 289 | CopyBits = 0; |
| 290 | } |
| 291 | ExtraOpc = isSub ? ARM::tSUBspi : ARM::tADDspi; |
| 292 | ExtraBits = 7; |
| 293 | ExtraScale = 4; |
| 294 | } else if (isARMLowRegister(Reg: DestReg)) { |
| 295 | if (BaseReg == ARM::SP) { |
| 296 | // sp -> low |
| 297 | assert(!isSub && "Thumb1 does not have tSUBrSPi" ); |
| 298 | CopyOpc = ARM::tADDrSPi; |
| 299 | CopyBits = 8; |
| 300 | CopyScale = 4; |
| 301 | } else if (DestReg == BaseReg) { |
| 302 | // low -> same low |
| 303 | // Already in right reg, no copy needed |
| 304 | } else if (isARMLowRegister(Reg: BaseReg)) { |
| 305 | // low -> different low |
| 306 | CopyOpc = isSub ? ARM::tSUBi3 : ARM::tADDi3; |
| 307 | CopyBits = 3; |
| 308 | CopyNeedsCC = true; |
| 309 | } else { |
| 310 | // high -> low |
| 311 | CopyOpc = ARM::tMOVr; |
| 312 | CopyBits = 0; |
| 313 | } |
| 314 | ExtraOpc = isSub ? ARM::tSUBi8 : ARM::tADDi8; |
| 315 | ExtraBits = 8; |
| 316 | ExtraNeedsCC = true; |
| 317 | } else /* DestReg is high */ { |
| 318 | if (DestReg == BaseReg) { |
| 319 | // high -> same high |
| 320 | // Already in right reg, no copy needed |
| 321 | } else { |
| 322 | // {low,high,sp} -> high |
| 323 | CopyOpc = ARM::tMOVr; |
| 324 | CopyBits = 0; |
| 325 | } |
| 326 | ExtraOpc = 0; |
| 327 | } |
| 328 | |
| 329 | // We could handle an unaligned immediate with an unaligned copy instruction |
| 330 | // and an aligned extra instruction, but this case is not currently needed. |
| 331 | assert(((Bytes & 3) == 0 || ExtraScale == 1) && |
| 332 | "Unaligned offset, but all instructions require alignment" ); |
| 333 | |
| 334 | unsigned CopyRange = ((1 << CopyBits) - 1) * CopyScale; |
| 335 | // If we would emit the copy with an immediate of 0, just use tMOVr. |
| 336 | if (CopyOpc && Bytes < CopyScale) { |
| 337 | CopyOpc = ARM::tMOVr; |
| 338 | CopyScale = 1; |
| 339 | CopyNeedsCC = false; |
| 340 | CopyRange = 0; |
| 341 | } |
| 342 | unsigned = ((1 << ExtraBits) - 1) * ExtraScale; // per instruction |
| 343 | unsigned RequiredCopyInstrs = CopyOpc ? 1 : 0; |
| 344 | unsigned RangeAfterCopy = (CopyRange > Bytes) ? 0 : (Bytes - CopyRange); |
| 345 | |
| 346 | // We could handle this case when the copy instruction does not require an |
| 347 | // aligned immediate, but we do not currently do this. |
| 348 | assert(RangeAfterCopy % ExtraScale == 0 && |
| 349 | "Extra instruction requires immediate to be aligned" ); |
| 350 | |
| 351 | unsigned ; |
| 352 | if (ExtraRange) |
| 353 | RequiredExtraInstrs = alignTo(Value: RangeAfterCopy, Align: ExtraRange) / ExtraRange; |
| 354 | else if (RangeAfterCopy > 0) |
| 355 | // We need an extra instruction but none is available |
| 356 | RequiredExtraInstrs = 1000000; |
| 357 | else |
| 358 | RequiredExtraInstrs = 0; |
| 359 | unsigned RequiredInstrs = RequiredCopyInstrs + RequiredExtraInstrs; |
| 360 | unsigned Threshold = (DestReg == ARM::SP) ? 3 : 2; |
| 361 | |
| 362 | // Use a constant pool, if the sequence of ADDs/SUBs is too expensive. |
| 363 | if (RequiredInstrs > Threshold) { |
| 364 | emitThumbRegPlusImmInReg(MBB, MBBI, dl, |
| 365 | DestReg, BaseReg, NumBytes, CanChangeCC: true, |
| 366 | TII, MRI, MIFlags); |
| 367 | return; |
| 368 | } |
| 369 | |
| 370 | // Emit zero or one copy instructions |
| 371 | if (CopyOpc) { |
| 372 | unsigned CopyImm = std::min(a: Bytes, b: CopyRange) / CopyScale; |
| 373 | Bytes -= CopyImm * CopyScale; |
| 374 | |
| 375 | MachineInstrBuilder MIB = BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: CopyOpc), DestReg); |
| 376 | if (CopyNeedsCC) |
| 377 | MIB = MIB.add(MO: t1CondCodeOp()); |
| 378 | MIB.addReg(RegNo: BaseReg, Flags: RegState::Kill); |
| 379 | if (CopyOpc != ARM::tMOVr) { |
| 380 | MIB.addImm(Val: CopyImm); |
| 381 | } |
| 382 | MIB.setMIFlags(MIFlags).add(MOs: predOps(Pred: ARMCC::AL)); |
| 383 | |
| 384 | BaseReg = DestReg; |
| 385 | } |
| 386 | |
| 387 | // Emit zero or more in-place add/sub instructions |
| 388 | while (Bytes) { |
| 389 | unsigned = std::min(a: Bytes, b: ExtraRange) / ExtraScale; |
| 390 | Bytes -= ExtraImm * ExtraScale; |
| 391 | |
| 392 | MachineInstrBuilder MIB = BuildMI(BB&: MBB, I: MBBI, MIMD: dl, MCID: TII.get(Opcode: ExtraOpc), DestReg); |
| 393 | if (ExtraNeedsCC) |
| 394 | MIB = MIB.add(MO: t1CondCodeOp()); |
| 395 | MIB.addReg(RegNo: BaseReg) |
| 396 | .addImm(Val: ExtraImm) |
| 397 | .add(MOs: predOps(Pred: ARMCC::AL)) |
| 398 | .setMIFlags(MIFlags); |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | static void removeOperands(MachineInstr &MI, unsigned i) { |
| 403 | unsigned Op = i; |
| 404 | for (unsigned e = MI.getNumOperands(); i != e; ++i) |
| 405 | MI.removeOperand(OpNo: Op); |
| 406 | } |
| 407 | |
| 408 | /// convertToNonSPOpcode - Change the opcode to the non-SP version, because |
| 409 | /// we're replacing the frame index with a non-SP register. |
| 410 | static unsigned convertToNonSPOpcode(unsigned Opcode) { |
| 411 | switch (Opcode) { |
| 412 | case ARM::tLDRspi: |
| 413 | return ARM::tLDRi; |
| 414 | |
| 415 | case ARM::tSTRspi: |
| 416 | return ARM::tSTRi; |
| 417 | } |
| 418 | |
| 419 | return Opcode; |
| 420 | } |
| 421 | |
| 422 | bool ThumbRegisterInfo::rewriteFrameIndex(MachineBasicBlock::iterator II, |
| 423 | unsigned FrameRegIdx, |
| 424 | Register FrameReg, int &Offset, |
| 425 | const ARMBaseInstrInfo &TII) const { |
| 426 | MachineInstr &MI = *II; |
| 427 | MachineBasicBlock &MBB = *MI.getParent(); |
| 428 | MachineFunction &MF = *MBB.getParent(); |
| 429 | assert(MBB.getParent()->getSubtarget<ARMSubtarget>().isThumb1Only() && |
| 430 | "This isn't needed for thumb2!" ); |
| 431 | DebugLoc dl = MI.getDebugLoc(); |
| 432 | MachineInstrBuilder MIB(*MBB.getParent(), &MI); |
| 433 | unsigned Opcode = MI.getOpcode(); |
| 434 | const MCInstrDesc &Desc = MI.getDesc(); |
| 435 | unsigned AddrMode = (Desc.TSFlags & ARMII::AddrModeMask); |
| 436 | |
| 437 | if (Opcode == ARM::tADDframe) { |
| 438 | Offset += MI.getOperand(i: FrameRegIdx+1).getImm(); |
| 439 | Register DestReg = MI.getOperand(i: 0).getReg(); |
| 440 | |
| 441 | emitThumbRegPlusImmediate(MBB, MBBI&: II, dl, DestReg, BaseReg: FrameReg, NumBytes: Offset, TII, |
| 442 | MRI: *this); |
| 443 | MBB.erase(I: II); |
| 444 | return true; |
| 445 | } else { |
| 446 | if (AddrMode != ARMII::AddrModeT1_s) |
| 447 | llvm_unreachable("Unsupported addressing mode!" ); |
| 448 | |
| 449 | unsigned ImmIdx = FrameRegIdx + 1; |
| 450 | int InstrOffs = MI.getOperand(i: ImmIdx).getImm(); |
| 451 | unsigned NumBits = (FrameReg == ARM::SP) ? 8 : 5; |
| 452 | unsigned Scale = 4; |
| 453 | |
| 454 | Offset += InstrOffs * Scale; |
| 455 | assert((Offset & (Scale - 1)) == 0 && "Can't encode this offset!" ); |
| 456 | |
| 457 | // Common case: small offset, fits into instruction. |
| 458 | MachineOperand &ImmOp = MI.getOperand(i: ImmIdx); |
| 459 | int ImmedOffset = Offset / Scale; |
| 460 | unsigned Mask = (1 << NumBits) - 1; |
| 461 | |
| 462 | if ((unsigned)Offset <= Mask * Scale) { |
| 463 | // Replace the FrameIndex with the frame register (e.g., sp). |
| 464 | Register DestReg = FrameReg; |
| 465 | |
| 466 | // In case FrameReg is a high register, move it to a low reg to ensure it |
| 467 | // can be used as an operand. |
| 468 | if (ARM::hGPRRegClass.contains(Reg: FrameReg) && FrameReg != ARM::SP) { |
| 469 | DestReg = MF.getRegInfo().createVirtualRegister(RegClass: &ARM::tGPRRegClass); |
| 470 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: ARM::tMOVr), DestReg) |
| 471 | .addReg(RegNo: FrameReg) |
| 472 | .add(MOs: predOps(Pred: ARMCC::AL)); |
| 473 | } |
| 474 | |
| 475 | MI.getOperand(i: FrameRegIdx).ChangeToRegister(Reg: DestReg, isDef: false); |
| 476 | ImmOp.ChangeToImmediate(ImmVal: ImmedOffset); |
| 477 | |
| 478 | // If we're using a register where sp was stored, convert the instruction |
| 479 | // to the non-SP version. |
| 480 | unsigned NewOpc = convertToNonSPOpcode(Opcode); |
| 481 | if (NewOpc != Opcode && FrameReg != ARM::SP) |
| 482 | MI.setDesc(TII.get(Opcode: NewOpc)); |
| 483 | |
| 484 | return true; |
| 485 | } |
| 486 | |
| 487 | // The offset doesn't fit, but we may be able to put some of the offset into |
| 488 | // the ldr to simplify the generation of the rest of it. |
| 489 | NumBits = 5; |
| 490 | Mask = (1 << NumBits) - 1; |
| 491 | InstrOffs = 0; |
| 492 | auto &ST = MF.getSubtarget<ARMSubtarget>(); |
| 493 | // If using the maximum ldr offset will put the rest into the range of a |
| 494 | // single sp-relative add then do so. |
| 495 | if (FrameReg == ARM::SP && Offset - (Mask * Scale) <= 1020) { |
| 496 | InstrOffs = Mask; |
| 497 | } else if (ST.genExecuteOnly()) { |
| 498 | // With execute-only the offset is generated either with movw+movt or an |
| 499 | // add+lsl sequence. If subtracting an offset will make the top half zero |
| 500 | // then that saves a movt or lsl+add. Otherwise if we don't have movw then |
| 501 | // we may be able to subtract a value such that it makes the bottom byte |
| 502 | // zero, saving an add. |
| 503 | unsigned BottomBits = (Offset / Scale) & Mask; |
| 504 | bool CanMakeBottomByteZero = ((Offset - BottomBits * Scale) & 0xff) == 0; |
| 505 | bool TopHalfZero = (Offset & 0xffff0000) == 0; |
| 506 | bool CanMakeTopHalfZero = ((Offset - Mask * Scale) & 0xffff0000) == 0; |
| 507 | if (!TopHalfZero && CanMakeTopHalfZero) |
| 508 | InstrOffs = Mask; |
| 509 | else if (!ST.useMovt() && CanMakeBottomByteZero) |
| 510 | InstrOffs = BottomBits; |
| 511 | } |
| 512 | ImmOp.ChangeToImmediate(ImmVal: InstrOffs); |
| 513 | Offset -= InstrOffs * Scale; |
| 514 | } |
| 515 | |
| 516 | return Offset == 0; |
| 517 | } |
| 518 | |
| 519 | void ThumbRegisterInfo::resolveFrameIndex(MachineInstr &MI, Register BaseReg, |
| 520 | int64_t Offset) const { |
| 521 | const MachineFunction &MF = *MI.getParent()->getParent(); |
| 522 | const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>(); |
| 523 | if (!STI.isThumb1Only()) |
| 524 | return ARMBaseRegisterInfo::resolveFrameIndex(MI, BaseReg, Offset); |
| 525 | |
| 526 | const ARMBaseInstrInfo &TII = *STI.getInstrInfo(); |
| 527 | int Off = Offset; // ARM doesn't need the general 64-bit offsets |
| 528 | unsigned i = 0; |
| 529 | |
| 530 | while (!MI.getOperand(i).isFI()) { |
| 531 | ++i; |
| 532 | assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!" ); |
| 533 | } |
| 534 | bool Done = rewriteFrameIndex(II: MI, FrameRegIdx: i, FrameReg: BaseReg, Offset&: Off, TII); |
| 535 | assert (Done && "Unable to resolve frame index!" ); |
| 536 | (void)Done; |
| 537 | } |
| 538 | |
| 539 | bool ThumbRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, |
| 540 | int SPAdj, unsigned FIOperandNum, |
| 541 | RegScavenger *RS) const { |
| 542 | MachineInstr &MI = *II; |
| 543 | MachineBasicBlock &MBB = *MI.getParent(); |
| 544 | MachineFunction &MF = *MBB.getParent(); |
| 545 | const ARMSubtarget &STI = MF.getSubtarget<ARMSubtarget>(); |
| 546 | if (!STI.isThumb1Only()) |
| 547 | return ARMBaseRegisterInfo::eliminateFrameIndex(II, SPAdj, FIOperandNum, |
| 548 | RS); |
| 549 | |
| 550 | Register VReg; |
| 551 | const ARMBaseInstrInfo &TII = *STI.getInstrInfo(); |
| 552 | DebugLoc dl = MI.getDebugLoc(); |
| 553 | MachineInstrBuilder MIB(*MBB.getParent(), &MI); |
| 554 | |
| 555 | Register FrameReg; |
| 556 | int FrameIndex = MI.getOperand(i: FIOperandNum).getIndex(); |
| 557 | const ARMFrameLowering *TFI = getFrameLowering(MF); |
| 558 | int Offset = TFI->ResolveFrameIndexReference(MF, FI: FrameIndex, FrameReg, SPAdj); |
| 559 | |
| 560 | // PEI::scavengeFrameVirtualRegs() cannot accurately track SPAdj because the |
| 561 | // call frame setup/destroy instructions have already been eliminated. That |
| 562 | // means the stack pointer cannot be used to access the emergency spill slot |
| 563 | // when !hasReservedCallFrame(). |
| 564 | #ifndef NDEBUG |
| 565 | if (RS && FrameReg == ARM::SP && RS->isScavengingFrameIndex(FrameIndex)){ |
| 566 | assert(STI.getFrameLowering()->hasReservedCallFrame(MF) && |
| 567 | "Cannot use SP to access the emergency spill slot in " |
| 568 | "functions without a reserved call frame" ); |
| 569 | assert(!MF.getFrameInfo().hasVarSizedObjects() && |
| 570 | "Cannot use SP to access the emergency spill slot in " |
| 571 | "functions with variable sized frame objects" ); |
| 572 | } |
| 573 | #endif // NDEBUG |
| 574 | |
| 575 | // Special handling of dbg_value instructions. |
| 576 | if (MI.isDebugValue()) { |
| 577 | MI.getOperand(i: FIOperandNum). ChangeToRegister(Reg: FrameReg, isDef: false /*isDef*/); |
| 578 | MI.getOperand(i: FIOperandNum+1).ChangeToImmediate(ImmVal: Offset); |
| 579 | return false; |
| 580 | } |
| 581 | |
| 582 | // Modify MI as necessary to handle as much of 'Offset' as possible |
| 583 | assert(MF.getInfo<ARMFunctionInfo>()->isThumbFunction() && |
| 584 | "This eliminateFrameIndex only supports Thumb1!" ); |
| 585 | if (rewriteFrameIndex(II: MI, FrameRegIdx: FIOperandNum, FrameReg, Offset, TII)) |
| 586 | return true; |
| 587 | |
| 588 | // If we get here, the immediate doesn't fit into the instruction. We folded |
| 589 | // as much as possible above, handle the rest, providing a register that is |
| 590 | // SP+LargeImm. |
| 591 | assert(Offset && "This code isn't needed if offset already handled!" ); |
| 592 | |
| 593 | unsigned Opcode = MI.getOpcode(); |
| 594 | |
| 595 | // Remove predicate first. |
| 596 | int PIdx = MI.findFirstPredOperandIdx(); |
| 597 | if (PIdx != -1) |
| 598 | removeOperands(MI, i: PIdx); |
| 599 | |
| 600 | if (MI.mayLoad()) { |
| 601 | // Use the destination register to materialize sp + offset. |
| 602 | Register TmpReg = MI.getOperand(i: 0).getReg(); |
| 603 | bool UseRR = false; |
| 604 | if (Opcode == ARM::tLDRspi) { |
| 605 | if (FrameReg == ARM::SP || STI.genExecuteOnly()) |
| 606 | emitThumbRegPlusImmInReg(MBB, MBBI&: II, dl, DestReg: TmpReg, BaseReg: FrameReg, |
| 607 | NumBytes: Offset, CanChangeCC: false, TII, MRI: *this); |
| 608 | else { |
| 609 | emitLoadConstPool(MBB, MBBI&: II, dl, DestReg: TmpReg, SubIdx: 0, Val: Offset); |
| 610 | if (!ARM::hGPRRegClass.contains(Reg: FrameReg)) { |
| 611 | UseRR = true; |
| 612 | } else { |
| 613 | // If FrameReg is a high register, add the reg values in a separate |
| 614 | // instruction as the load won't be able to access it. |
| 615 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: ARM::tADDhirr), DestReg: TmpReg) |
| 616 | .addReg(RegNo: TmpReg) |
| 617 | .addReg(RegNo: FrameReg) |
| 618 | .add(MOs: predOps(Pred: ARMCC::AL)); |
| 619 | } |
| 620 | } |
| 621 | } else { |
| 622 | emitThumbRegPlusImmediate(MBB, MBBI&: II, dl, DestReg: TmpReg, BaseReg: FrameReg, NumBytes: Offset, TII, |
| 623 | MRI: *this); |
| 624 | } |
| 625 | |
| 626 | MI.setDesc(TII.get(Opcode: UseRR ? ARM::tLDRr : ARM::tLDRi)); |
| 627 | MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: TmpReg, isDef: false, isImp: false, isKill: true); |
| 628 | if (UseRR) { |
| 629 | assert(!ARM::hGPRRegClass.contains(FrameReg) && |
| 630 | "Thumb1 loads can't use high register" ); |
| 631 | // Use [reg, reg] addrmode. Replace the immediate operand w/ the frame |
| 632 | // register. The offset is already handled in the vreg value. |
| 633 | MI.getOperand(i: FIOperandNum+1).ChangeToRegister(Reg: FrameReg, isDef: false, isImp: false, |
| 634 | isKill: false); |
| 635 | } |
| 636 | } else if (MI.mayStore()) { |
| 637 | VReg = MF.getRegInfo().createVirtualRegister(RegClass: &ARM::tGPRRegClass); |
| 638 | bool UseRR = false; |
| 639 | |
| 640 | if (Opcode == ARM::tSTRspi) { |
| 641 | if (FrameReg == ARM::SP || STI.genExecuteOnly()) |
| 642 | emitThumbRegPlusImmInReg(MBB, MBBI&: II, dl, DestReg: VReg, BaseReg: FrameReg, |
| 643 | NumBytes: Offset, CanChangeCC: false, TII, MRI: *this); |
| 644 | else { |
| 645 | emitLoadConstPool(MBB, MBBI&: II, dl, DestReg: VReg, SubIdx: 0, Val: Offset); |
| 646 | if (!ARM::hGPRRegClass.contains(Reg: FrameReg)) { |
| 647 | UseRR = true; |
| 648 | } else { |
| 649 | // If FrameReg is a high register, add the reg values in a separate |
| 650 | // instruction as the load won't be able to access it. |
| 651 | BuildMI(BB&: MBB, I: II, MIMD: dl, MCID: TII.get(Opcode: ARM::tADDhirr), DestReg: VReg) |
| 652 | .addReg(RegNo: VReg) |
| 653 | .addReg(RegNo: FrameReg) |
| 654 | .add(MOs: predOps(Pred: ARMCC::AL)); |
| 655 | } |
| 656 | } |
| 657 | } else |
| 658 | emitThumbRegPlusImmediate(MBB, MBBI&: II, dl, DestReg: VReg, BaseReg: FrameReg, NumBytes: Offset, TII, |
| 659 | MRI: *this); |
| 660 | MI.setDesc(TII.get(Opcode: UseRR ? ARM::tSTRr : ARM::tSTRi)); |
| 661 | MI.getOperand(i: FIOperandNum).ChangeToRegister(Reg: VReg, isDef: false, isImp: false, isKill: true); |
| 662 | if (UseRR) { |
| 663 | assert(!ARM::hGPRRegClass.contains(FrameReg) && |
| 664 | "Thumb1 stores can't use high register" ); |
| 665 | // Use [reg, reg] addrmode. Replace the immediate operand w/ the frame |
| 666 | // register. The offset is already handled in the vreg value. |
| 667 | MI.getOperand(i: FIOperandNum+1).ChangeToRegister(Reg: FrameReg, isDef: false, isImp: false, |
| 668 | isKill: false); |
| 669 | } |
| 670 | } else { |
| 671 | llvm_unreachable("Unexpected opcode!" ); |
| 672 | } |
| 673 | |
| 674 | // Add predicate back if it's needed. |
| 675 | if (MI.isPredicable()) |
| 676 | MIB.add(MOs: predOps(Pred: ARMCC::AL)); |
| 677 | return false; |
| 678 | } |
| 679 | |
| 680 | bool |
| 681 | ThumbRegisterInfo::useFPForScavengingIndex(const MachineFunction &MF) const { |
| 682 | if (MF.getSubtarget<ARMSubtarget>().isThumb1Only()) { |
| 683 | // For Thumb1, the emergency spill slot must be some small positive |
| 684 | // offset from the base/stack pointer. |
| 685 | return false; |
| 686 | } |
| 687 | // For Thumb2, put the emergency spill slot next to FP. |
| 688 | return true; |
| 689 | } |
| 690 | |