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 &
addFrameReference(const MachineInstrBuilder & MIB,int FI)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
XtensaInstrInfo(const XtensaSubtarget & STI)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
isLoadFromStackSlot(const MachineInstr & MI,int & FrameIndex) const51*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
isStoreToStackSlot(const MachineInstr & MI,int & FrameIndex) const63*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.
adjustStackPtr(unsigned SP,int64_t Amount,MachineBasicBlock & MBB,MachineBasicBlock::iterator I) const76*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
copyPhysReg(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,const DebugLoc & DL,MCRegister DestReg,MCRegister SrcReg,bool KillSrc) const105*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
storeRegToStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,Register SrcReg,bool isKill,int FrameIdx,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const119*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
loadRegFromStackSlot(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,Register DestReg,int FrameIdx,const TargetRegisterClass * RC,const TargetRegisterInfo * TRI,Register VReg) const131*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
getLoadStoreOpcodes(const TargetRegisterClass * RC,unsigned & LoadOpcode,unsigned & StoreOpcode,int64_t offset) const143*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
loadImmediate(MachineBasicBlock & MBB,MachineBasicBlock::iterator MBBI,unsigned * Reg,int64_t Value) const154*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