1*0fca6ea1SDimitry Andric //===- XtensaInstrInfo.cpp - Xtensa Instruction Information ---------------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // The LLVM Compiler Infrastructure 4*0fca6ea1SDimitry Andric // 5*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 7*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 8*0fca6ea1SDimitry Andric // 9*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 10*0fca6ea1SDimitry Andric // 11*0fca6ea1SDimitry Andric // This file contains the Xtensa implementation of the TargetInstrInfo class. 12*0fca6ea1SDimitry Andric // 13*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 14*0fca6ea1SDimitry Andric 15*0fca6ea1SDimitry Andric #include "XtensaInstrInfo.h" 16*0fca6ea1SDimitry Andric #include "XtensaTargetMachine.h" 17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h" 18*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h" 19*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 20*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 21*0fca6ea1SDimitry Andric 22*0fca6ea1SDimitry Andric #define GET_INSTRINFO_CTOR_DTOR 23*0fca6ea1SDimitry Andric #include "XtensaGenInstrInfo.inc" 24*0fca6ea1SDimitry Andric 25*0fca6ea1SDimitry Andric using namespace llvm; 26*0fca6ea1SDimitry Andric 27*0fca6ea1SDimitry Andric static const MachineInstrBuilder & 28*0fca6ea1SDimitry Andric addFrameReference(const MachineInstrBuilder &MIB, int FI) { 29*0fca6ea1SDimitry Andric MachineInstr *MI = MIB; 30*0fca6ea1SDimitry Andric MachineFunction &MF = *MI->getParent()->getParent(); 31*0fca6ea1SDimitry Andric MachineFrameInfo &MFFrame = MF.getFrameInfo(); 32*0fca6ea1SDimitry Andric const MCInstrDesc &MCID = MI->getDesc(); 33*0fca6ea1SDimitry Andric MachineMemOperand::Flags Flags = MachineMemOperand::MONone; 34*0fca6ea1SDimitry Andric if (MCID.mayLoad()) 35*0fca6ea1SDimitry Andric Flags |= MachineMemOperand::MOLoad; 36*0fca6ea1SDimitry Andric if (MCID.mayStore()) 37*0fca6ea1SDimitry Andric Flags |= MachineMemOperand::MOStore; 38*0fca6ea1SDimitry Andric int64_t Offset = 0; 39*0fca6ea1SDimitry Andric Align Alignment = MFFrame.getObjectAlign(FI); 40*0fca6ea1SDimitry Andric 41*0fca6ea1SDimitry Andric MachineMemOperand *MMO = 42*0fca6ea1SDimitry Andric MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI, Offset), 43*0fca6ea1SDimitry Andric Flags, MFFrame.getObjectSize(FI), Alignment); 44*0fca6ea1SDimitry Andric return MIB.addFrameIndex(FI).addImm(Offset).addMemOperand(MMO); 45*0fca6ea1SDimitry Andric } 46*0fca6ea1SDimitry Andric 47*0fca6ea1SDimitry Andric XtensaInstrInfo::XtensaInstrInfo(const XtensaSubtarget &STI) 48*0fca6ea1SDimitry Andric : XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP), 49*0fca6ea1SDimitry Andric RI(STI), STI(STI) {} 50*0fca6ea1SDimitry Andric 51*0fca6ea1SDimitry Andric Register XtensaInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, 52*0fca6ea1SDimitry Andric int &FrameIndex) const { 53*0fca6ea1SDimitry Andric if (MI.getOpcode() == Xtensa::L32I) { 54*0fca6ea1SDimitry Andric if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() && 55*0fca6ea1SDimitry Andric MI.getOperand(2).getImm() == 0) { 56*0fca6ea1SDimitry Andric FrameIndex = MI.getOperand(1).getIndex(); 57*0fca6ea1SDimitry Andric return MI.getOperand(0).getReg(); 58*0fca6ea1SDimitry Andric } 59*0fca6ea1SDimitry Andric } 60*0fca6ea1SDimitry Andric return Register(); 61*0fca6ea1SDimitry Andric } 62*0fca6ea1SDimitry Andric 63*0fca6ea1SDimitry Andric Register XtensaInstrInfo::isStoreToStackSlot(const MachineInstr &MI, 64*0fca6ea1SDimitry Andric int &FrameIndex) const { 65*0fca6ea1SDimitry Andric if (MI.getOpcode() == Xtensa::S32I) { 66*0fca6ea1SDimitry Andric if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() && 67*0fca6ea1SDimitry Andric MI.getOperand(2).getImm() == 0) { 68*0fca6ea1SDimitry Andric FrameIndex = MI.getOperand(1).getIndex(); 69*0fca6ea1SDimitry Andric return MI.getOperand(0).getReg(); 70*0fca6ea1SDimitry Andric } 71*0fca6ea1SDimitry Andric } 72*0fca6ea1SDimitry Andric return Register(); 73*0fca6ea1SDimitry Andric } 74*0fca6ea1SDimitry Andric 75*0fca6ea1SDimitry Andric /// Adjust SP by Amount bytes. 76*0fca6ea1SDimitry Andric void XtensaInstrInfo::adjustStackPtr(unsigned SP, int64_t Amount, 77*0fca6ea1SDimitry Andric MachineBasicBlock &MBB, 78*0fca6ea1SDimitry Andric MachineBasicBlock::iterator I) const { 79*0fca6ea1SDimitry Andric DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc(); 80*0fca6ea1SDimitry Andric 81*0fca6ea1SDimitry Andric if (Amount == 0) 82*0fca6ea1SDimitry Andric return; 83*0fca6ea1SDimitry Andric 84*0fca6ea1SDimitry Andric MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); 85*0fca6ea1SDimitry Andric const TargetRegisterClass *RC = &Xtensa::ARRegClass; 86*0fca6ea1SDimitry Andric 87*0fca6ea1SDimitry Andric // create virtual reg to store immediate 88*0fca6ea1SDimitry Andric unsigned Reg = RegInfo.createVirtualRegister(RC); 89*0fca6ea1SDimitry Andric 90*0fca6ea1SDimitry Andric if (isInt<8>(Amount)) { // addi sp, sp, amount 91*0fca6ea1SDimitry Andric BuildMI(MBB, I, DL, get(Xtensa::ADDI), Reg).addReg(SP).addImm(Amount); 92*0fca6ea1SDimitry Andric } else { // Expand immediate that doesn't fit in 8-bit. 93*0fca6ea1SDimitry Andric unsigned Reg1; 94*0fca6ea1SDimitry Andric loadImmediate(MBB, I, &Reg1, Amount); 95*0fca6ea1SDimitry Andric BuildMI(MBB, I, DL, get(Xtensa::ADD), Reg) 96*0fca6ea1SDimitry Andric .addReg(SP) 97*0fca6ea1SDimitry Andric .addReg(Reg1, RegState::Kill); 98*0fca6ea1SDimitry Andric } 99*0fca6ea1SDimitry Andric 100*0fca6ea1SDimitry Andric BuildMI(MBB, I, DL, get(Xtensa::OR), SP) 101*0fca6ea1SDimitry Andric .addReg(Reg, RegState::Kill) 102*0fca6ea1SDimitry Andric .addReg(Reg, RegState::Kill); 103*0fca6ea1SDimitry Andric } 104*0fca6ea1SDimitry Andric 105*0fca6ea1SDimitry Andric void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB, 106*0fca6ea1SDimitry Andric MachineBasicBlock::iterator MBBI, 107*0fca6ea1SDimitry Andric const DebugLoc &DL, MCRegister DestReg, 108*0fca6ea1SDimitry Andric MCRegister SrcReg, bool KillSrc) const { 109*0fca6ea1SDimitry Andric // The MOV instruction is not present in core ISA, 110*0fca6ea1SDimitry Andric // so use OR instruction. 111*0fca6ea1SDimitry Andric if (Xtensa::ARRegClass.contains(DestReg, SrcReg)) 112*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, get(Xtensa::OR), DestReg) 113*0fca6ea1SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)) 114*0fca6ea1SDimitry Andric .addReg(SrcReg, getKillRegState(KillSrc)); 115*0fca6ea1SDimitry Andric else 116*0fca6ea1SDimitry Andric report_fatal_error("Impossible reg-to-reg copy"); 117*0fca6ea1SDimitry Andric } 118*0fca6ea1SDimitry Andric 119*0fca6ea1SDimitry Andric void XtensaInstrInfo::storeRegToStackSlot( 120*0fca6ea1SDimitry Andric MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg, 121*0fca6ea1SDimitry Andric bool isKill, int FrameIdx, const TargetRegisterClass *RC, 122*0fca6ea1SDimitry Andric const TargetRegisterInfo *TRI, Register VReg) const { 123*0fca6ea1SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 124*0fca6ea1SDimitry Andric unsigned LoadOpcode, StoreOpcode; 125*0fca6ea1SDimitry Andric getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx); 126*0fca6ea1SDimitry Andric MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, get(StoreOpcode)) 127*0fca6ea1SDimitry Andric .addReg(SrcReg, getKillRegState(isKill)); 128*0fca6ea1SDimitry Andric addFrameReference(MIB, FrameIdx); 129*0fca6ea1SDimitry Andric } 130*0fca6ea1SDimitry Andric 131*0fca6ea1SDimitry Andric void XtensaInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB, 132*0fca6ea1SDimitry Andric MachineBasicBlock::iterator MBBI, 133*0fca6ea1SDimitry Andric Register DestReg, int FrameIdx, 134*0fca6ea1SDimitry Andric const TargetRegisterClass *RC, 135*0fca6ea1SDimitry Andric const TargetRegisterInfo *TRI, 136*0fca6ea1SDimitry Andric Register VReg) const { 137*0fca6ea1SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 138*0fca6ea1SDimitry Andric unsigned LoadOpcode, StoreOpcode; 139*0fca6ea1SDimitry Andric getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx); 140*0fca6ea1SDimitry Andric addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg), FrameIdx); 141*0fca6ea1SDimitry Andric } 142*0fca6ea1SDimitry Andric 143*0fca6ea1SDimitry Andric void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC, 144*0fca6ea1SDimitry Andric unsigned &LoadOpcode, 145*0fca6ea1SDimitry Andric unsigned &StoreOpcode, 146*0fca6ea1SDimitry Andric int64_t offset) const { 147*0fca6ea1SDimitry Andric assert((RC == &Xtensa::ARRegClass) && 148*0fca6ea1SDimitry Andric "Unsupported regclass to load or store"); 149*0fca6ea1SDimitry Andric 150*0fca6ea1SDimitry Andric LoadOpcode = Xtensa::L32I; 151*0fca6ea1SDimitry Andric StoreOpcode = Xtensa::S32I; 152*0fca6ea1SDimitry Andric } 153*0fca6ea1SDimitry Andric 154*0fca6ea1SDimitry Andric void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB, 155*0fca6ea1SDimitry Andric MachineBasicBlock::iterator MBBI, 156*0fca6ea1SDimitry Andric unsigned *Reg, int64_t Value) const { 157*0fca6ea1SDimitry Andric DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); 158*0fca6ea1SDimitry Andric MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo(); 159*0fca6ea1SDimitry Andric const TargetRegisterClass *RC = &Xtensa::ARRegClass; 160*0fca6ea1SDimitry Andric 161*0fca6ea1SDimitry Andric // create virtual reg to store immediate 162*0fca6ea1SDimitry Andric *Reg = RegInfo.createVirtualRegister(RC); 163*0fca6ea1SDimitry Andric if (Value >= -2048 && Value <= 2047) { 164*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Value); 165*0fca6ea1SDimitry Andric } else if (Value >= -32768 && Value <= 32767) { 166*0fca6ea1SDimitry Andric int Low = Value & 0xFF; 167*0fca6ea1SDimitry Andric int High = Value & ~0xFF; 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Low); 170*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, get(Xtensa::ADDMI), *Reg).addReg(*Reg).addImm(High); 171*0fca6ea1SDimitry Andric } else if (Value >= -4294967296LL && Value <= 4294967295LL) { 172*0fca6ea1SDimitry Andric // 32 bit arbitrary constant 173*0fca6ea1SDimitry Andric MachineConstantPool *MCP = MBB.getParent()->getConstantPool(); 174*0fca6ea1SDimitry Andric uint64_t UVal = ((uint64_t)Value) & 0xFFFFFFFFLL; 175*0fca6ea1SDimitry Andric const Constant *CVal = ConstantInt::get( 176*0fca6ea1SDimitry Andric Type::getInt32Ty(MBB.getParent()->getFunction().getContext()), UVal, 177*0fca6ea1SDimitry Andric false); 178*0fca6ea1SDimitry Andric unsigned Idx = MCP->getConstantPoolIndex(CVal, Align(2U)); 179*0fca6ea1SDimitry Andric // MCSymbol MSym 180*0fca6ea1SDimitry Andric BuildMI(MBB, MBBI, DL, get(Xtensa::L32R), *Reg).addConstantPoolIndex(Idx); 181*0fca6ea1SDimitry Andric } else { 182*0fca6ea1SDimitry Andric // use L32R to let assembler load immediate best 183*0fca6ea1SDimitry Andric // TODO replace to L32R 184*0fca6ea1SDimitry Andric report_fatal_error("Unsupported load immediate value"); 185*0fca6ea1SDimitry Andric } 186*0fca6ea1SDimitry Andric } 187