10b57cec5SDimitry Andric //===-- Thumb1InstrInfo.cpp - Thumb-1 Instruction Information -------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains the Thumb-1 implementation of the TargetInstrInfo class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "Thumb1InstrInfo.h"
140b57cec5SDimitry Andric #include "ARMSubtarget.h"
15*0fca6ea1SDimitry Andric #include "llvm/ADT/BitVector.h"
16*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveRegUnits.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h"
190b57cec5SDimitry Andric #include "llvm/CodeGen/MachineMemOperand.h"
20*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
22fe6060f1SDimitry Andric #include "llvm/MC/MCInstBuilder.h"
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric using namespace llvm;
250b57cec5SDimitry Andric
Thumb1InstrInfo(const ARMSubtarget & STI)260b57cec5SDimitry Andric Thumb1InstrInfo::Thumb1InstrInfo(const ARMSubtarget &STI)
2704eeddc0SDimitry Andric : ARMBaseInstrInfo(STI) {}
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric /// Return the noop instruction to use for a noop.
getNop() const30fe6060f1SDimitry Andric MCInst Thumb1InstrInfo::getNop() const {
31fe6060f1SDimitry Andric return MCInstBuilder(ARM::tMOVr)
32fe6060f1SDimitry Andric .addReg(ARM::R8)
33fe6060f1SDimitry Andric .addReg(ARM::R8)
34fe6060f1SDimitry Andric .addImm(ARMCC::AL)
35fe6060f1SDimitry Andric .addReg(0);
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric
getUnindexedOpcode(unsigned Opc) const380b57cec5SDimitry Andric unsigned Thumb1InstrInfo::getUnindexedOpcode(unsigned Opc) const {
390b57cec5SDimitry Andric return 0;
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const420b57cec5SDimitry Andric void Thumb1InstrInfo::copyPhysReg(MachineBasicBlock &MBB,
430b57cec5SDimitry Andric MachineBasicBlock::iterator I,
44480093f4SDimitry Andric const DebugLoc &DL, MCRegister DestReg,
45480093f4SDimitry Andric MCRegister SrcReg, bool KillSrc) const {
460b57cec5SDimitry Andric // Need to check the arch.
470b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent();
480b57cec5SDimitry Andric const ARMSubtarget &st = MF.getSubtarget<ARMSubtarget>();
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric assert(ARM::GPRRegClass.contains(DestReg, SrcReg) &&
510b57cec5SDimitry Andric "Thumb1 can only copy GPR registers");
520b57cec5SDimitry Andric
53*0fca6ea1SDimitry Andric if (st.hasV6Ops() || ARM::hGPRRegClass.contains(SrcReg) ||
54*0fca6ea1SDimitry Andric !ARM::tGPRRegClass.contains(DestReg))
550b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tMOVr), DestReg)
560b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc))
570b57cec5SDimitry Andric .add(predOps(ARMCC::AL));
580b57cec5SDimitry Andric else {
590b57cec5SDimitry Andric const TargetRegisterInfo *RegInfo = st.getRegisterInfo();
60*0fca6ea1SDimitry Andric LiveRegUnits UsedRegs(*RegInfo);
61*0fca6ea1SDimitry Andric UsedRegs.addLiveOuts(MBB);
62*0fca6ea1SDimitry Andric
63*0fca6ea1SDimitry Andric auto InstUpToI = MBB.end();
64*0fca6ea1SDimitry Andric while (InstUpToI != I)
65*0fca6ea1SDimitry Andric // The pre-decrement is on purpose here.
66*0fca6ea1SDimitry Andric // We want to have the liveness right before I.
67*0fca6ea1SDimitry Andric UsedRegs.stepBackward(*--InstUpToI);
68*0fca6ea1SDimitry Andric
69*0fca6ea1SDimitry Andric if (UsedRegs.available(ARM::CPSR)) {
700b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tMOVSr), DestReg)
710b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc))
720b57cec5SDimitry Andric ->addRegisterDead(ARM::CPSR, RegInfo);
730b57cec5SDimitry Andric return;
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric
76*0fca6ea1SDimitry Andric // Use high register to move source to destination
77*0fca6ea1SDimitry Andric // if movs is not an option.
78*0fca6ea1SDimitry Andric BitVector Allocatable = RegInfo->getAllocatableSet(
79*0fca6ea1SDimitry Andric MF, RegInfo->getRegClass(ARM::hGPRRegClassID));
80*0fca6ea1SDimitry Andric
81*0fca6ea1SDimitry Andric Register TmpReg = ARM::NoRegister;
82*0fca6ea1SDimitry Andric // Prefer R12 as it is known to not be preserved anyway
83*0fca6ea1SDimitry Andric if (UsedRegs.available(ARM::R12) && Allocatable.test(ARM::R12)) {
84*0fca6ea1SDimitry Andric TmpReg = ARM::R12;
85*0fca6ea1SDimitry Andric } else {
86*0fca6ea1SDimitry Andric for (Register Reg : Allocatable.set_bits()) {
87*0fca6ea1SDimitry Andric if (UsedRegs.available(Reg)) {
88*0fca6ea1SDimitry Andric TmpReg = Reg;
89*0fca6ea1SDimitry Andric break;
90*0fca6ea1SDimitry Andric }
91*0fca6ea1SDimitry Andric }
92*0fca6ea1SDimitry Andric }
93*0fca6ea1SDimitry Andric
94*0fca6ea1SDimitry Andric if (TmpReg) {
95*0fca6ea1SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tMOVr), TmpReg)
96*0fca6ea1SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc))
97*0fca6ea1SDimitry Andric .add(predOps(ARMCC::AL));
98*0fca6ea1SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tMOVr), DestReg)
99*0fca6ea1SDimitry Andric .addReg(TmpReg, getKillRegState(true))
100*0fca6ea1SDimitry Andric .add(predOps(ARMCC::AL));
101*0fca6ea1SDimitry Andric return;
102*0fca6ea1SDimitry Andric }
103*0fca6ea1SDimitry Andric
1040b57cec5SDimitry Andric // 'MOV lo, lo' is unpredictable on < v6, so use the stack to do it
1050b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tPUSH))
1060b57cec5SDimitry Andric .add(predOps(ARMCC::AL))
1070b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc));
1080b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tPOP))
1090b57cec5SDimitry Andric .add(predOps(ARMCC::AL))
1100b57cec5SDimitry Andric .addReg(DestReg, getDefRegState(true));
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric
storeRegToStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register SrcReg,bool isKill,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const114bdd1243dSDimitry Andric void Thumb1InstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
115bdd1243dSDimitry Andric MachineBasicBlock::iterator I,
1165ffd83dbSDimitry Andric Register SrcReg, bool isKill, int FI,
1170b57cec5SDimitry Andric const TargetRegisterClass *RC,
118bdd1243dSDimitry Andric const TargetRegisterInfo *TRI,
119bdd1243dSDimitry Andric Register VReg) const {
1200b57cec5SDimitry Andric assert((RC == &ARM::tGPRRegClass ||
121bdd1243dSDimitry Andric (SrcReg.isPhysical() && isARMLowRegister(SrcReg))) &&
1228bcb0991SDimitry Andric "Unknown regclass!");
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric if (RC == &ARM::tGPRRegClass ||
125bdd1243dSDimitry Andric (SrcReg.isPhysical() && isARMLowRegister(SrcReg))) {
1260b57cec5SDimitry Andric DebugLoc DL;
1270b57cec5SDimitry Andric if (I != MBB.end()) DL = I->getDebugLoc();
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent();
1300b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
1310b57cec5SDimitry Andric MachineMemOperand *MMO = MF.getMachineMemOperand(
1320b57cec5SDimitry Andric MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOStore,
1335ffd83dbSDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
1340b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tSTRspi))
1350b57cec5SDimitry Andric .addReg(SrcReg, getKillRegState(isKill))
1360b57cec5SDimitry Andric .addFrameIndex(FI)
1370b57cec5SDimitry Andric .addImm(0)
1380b57cec5SDimitry Andric .addMemOperand(MMO)
1390b57cec5SDimitry Andric .add(predOps(ARMCC::AL));
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric
loadRegFromStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator I,Register DestReg,int FI,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const143bdd1243dSDimitry Andric void Thumb1InstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
144bdd1243dSDimitry Andric MachineBasicBlock::iterator I,
1455ffd83dbSDimitry Andric Register DestReg, int FI,
1460b57cec5SDimitry Andric const TargetRegisterClass *RC,
147bdd1243dSDimitry Andric const TargetRegisterInfo *TRI,
148bdd1243dSDimitry Andric Register VReg) const {
149bdd1243dSDimitry Andric assert((RC->hasSuperClassEq(&ARM::tGPRRegClass) ||
150bdd1243dSDimitry Andric (DestReg.isPhysical() && isARMLowRegister(DestReg))) &&
1518bcb0991SDimitry Andric "Unknown regclass!");
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric if (RC->hasSuperClassEq(&ARM::tGPRRegClass) ||
154bdd1243dSDimitry Andric (DestReg.isPhysical() && isARMLowRegister(DestReg))) {
1550b57cec5SDimitry Andric DebugLoc DL;
1560b57cec5SDimitry Andric if (I != MBB.end()) DL = I->getDebugLoc();
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric MachineFunction &MF = *MBB.getParent();
1590b57cec5SDimitry Andric MachineFrameInfo &MFI = MF.getFrameInfo();
1600b57cec5SDimitry Andric MachineMemOperand *MMO = MF.getMachineMemOperand(
1610b57cec5SDimitry Andric MachinePointerInfo::getFixedStack(MF, FI), MachineMemOperand::MOLoad,
1625ffd83dbSDimitry Andric MFI.getObjectSize(FI), MFI.getObjectAlign(FI));
1630b57cec5SDimitry Andric BuildMI(MBB, I, DL, get(ARM::tLDRspi), DestReg)
1640b57cec5SDimitry Andric .addFrameIndex(FI)
1650b57cec5SDimitry Andric .addImm(0)
1660b57cec5SDimitry Andric .addMemOperand(MMO)
1670b57cec5SDimitry Andric .add(predOps(ARMCC::AL));
1680b57cec5SDimitry Andric }
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric
expandLoadStackGuard(MachineBasicBlock::iterator MI) const1710b57cec5SDimitry Andric void Thumb1InstrInfo::expandLoadStackGuard(
1720b57cec5SDimitry Andric MachineBasicBlock::iterator MI) const {
1730b57cec5SDimitry Andric MachineFunction &MF = *MI->getParent()->getParent();
17406c3fb27SDimitry Andric const ARMSubtarget &ST = MF.getSubtarget<ARMSubtarget>();
1757a6dacacSDimitry Andric const auto *GV = cast<GlobalValue>((*MI->memoperands_begin())->getValue());
176349cc55cSDimitry Andric
177349cc55cSDimitry Andric assert(MF.getFunction().getParent()->getStackProtectorGuard() != "tls" &&
178349cc55cSDimitry Andric "TLS stack protector not supported for Thumb1 targets");
179349cc55cSDimitry Andric
18006c3fb27SDimitry Andric unsigned Instr;
1817a6dacacSDimitry Andric if (!GV->isDSOLocal())
18206c3fb27SDimitry Andric Instr = ARM::tLDRLIT_ga_pcrel;
18306c3fb27SDimitry Andric else if (ST.genExecuteOnly() && ST.hasV8MBaselineOps())
18406c3fb27SDimitry Andric Instr = ARM::t2MOVi32imm;
18506c3fb27SDimitry Andric else if (ST.genExecuteOnly())
18606c3fb27SDimitry Andric Instr = ARM::tMOVi32imm;
1870b57cec5SDimitry Andric else
18806c3fb27SDimitry Andric Instr = ARM::tLDRLIT_ga_abs;
18906c3fb27SDimitry Andric expandLoadStackGuardBase(MI, Instr, ARM::tLDRi);
1900b57cec5SDimitry Andric }
1910b57cec5SDimitry Andric
canCopyGluedNodeDuringSchedule(SDNode * N) const1920b57cec5SDimitry Andric bool Thumb1InstrInfo::canCopyGluedNodeDuringSchedule(SDNode *N) const {
1930b57cec5SDimitry Andric // In Thumb1 the scheduler may need to schedule a cross-copy between GPRS and CPSR
1940b57cec5SDimitry Andric // but this is not always possible there, so allow the Scheduler to clone tADCS and tSBCS
1950b57cec5SDimitry Andric // even if they have glue.
1960b57cec5SDimitry Andric // FIXME. Actually implement the cross-copy where it is possible (post v6)
1970b57cec5SDimitry Andric // because these copies entail more spilling.
1980b57cec5SDimitry Andric unsigned Opcode = N->getMachineOpcode();
1990b57cec5SDimitry Andric if (Opcode == ARM::tADCS || Opcode == ARM::tSBCS)
2000b57cec5SDimitry Andric return true;
2010b57cec5SDimitry Andric
2020b57cec5SDimitry Andric return false;
2030b57cec5SDimitry Andric }
204