xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/Thumb1InstrInfo.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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