1 //=- LoongArchISelLowering.cpp - LoongArch DAG Lowering Implementation  ---===//
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 defines the interfaces that LoongArch uses to lower LLVM code into
10 // a selection DAG.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "LoongArchISelLowering.h"
15 #include "LoongArch.h"
16 #include "LoongArchMachineFunctionInfo.h"
17 #include "LoongArchRegisterInfo.h"
18 #include "LoongArchSubtarget.h"
19 #include "LoongArchTargetMachine.h"
20 #include "llvm/ADT/Statistic.h"
21 #include "llvm/Support/Debug.h"
22 
23 using namespace llvm;
24 
25 #define DEBUG_TYPE "loongarch-isel-lowering"
26 
27 LoongArchTargetLowering::LoongArchTargetLowering(const TargetMachine &TM,
28                                                  const LoongArchSubtarget &STI)
29     : TargetLowering(TM), Subtarget(STI) {
30 
31   MVT GRLenVT = Subtarget.getGRLenVT();
32   // Set up the register classes.
33   addRegisterClass(GRLenVT, &LoongArch::GPRRegClass);
34 
35   // TODO: add necessary setOperationAction calls later.
36 
37   // Compute derived properties from the register classes.
38   computeRegisterProperties(STI.getRegisterInfo());
39 
40   setStackPointerRegisterToSaveRestore(LoongArch::R3);
41 
42   // Function alignments.
43   const Align FunctionAlignment(4);
44   setMinFunctionAlignment(FunctionAlignment);
45 }
46 
47 const char *LoongArchTargetLowering::getTargetNodeName(unsigned Opcode) const {
48   switch ((LoongArchISD::NodeType)Opcode) {
49   case LoongArchISD::FIRST_NUMBER:
50     break;
51 
52 #define NODE_NAME_CASE(node)                                                   \
53   case LoongArchISD::node:                                                     \
54     return "LoongArchISD::" #node;
55 
56     // TODO: Add more target-dependent nodes later.
57     NODE_NAME_CASE(RET)
58   }
59 #undef NODE_NAME_CASE
60   return nullptr;
61 }
62 
63 //===----------------------------------------------------------------------===//
64 //                     Calling Convention Implementation
65 //===----------------------------------------------------------------------===//
66 // FIXME: Now, we only support CallingConv::C with fixed arguments which are
67 // passed with integer registers.
68 const MCPhysReg ArgGPRs[] = {LoongArch::R4,  LoongArch::R5, LoongArch::R6,
69                              LoongArch::R7,  LoongArch::R8, LoongArch::R9,
70                              LoongArch::R10, LoongArch::R11};
71 
72 // Implements the LoongArch calling convention. Returns true upon failure.
73 static bool CC_LoongArch(unsigned ValNo, MVT ValVT,
74                          CCValAssign::LocInfo LocInfo, CCState &State) {
75   // Allocate to a register if possible.
76   Register Reg = State.AllocateReg(ArgGPRs);
77   if (Reg) {
78     State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, ValVT, LocInfo));
79     return false;
80   }
81 
82   // TODO: Handle arguments passed without register.
83   return true;
84 }
85 
86 void LoongArchTargetLowering::analyzeInputArgs(
87     CCState &CCInfo, const SmallVectorImpl<ISD::InputArg> &Ins,
88     LoongArchCCAssignFn Fn) const {
89   for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
90     MVT ArgVT = Ins[i].VT;
91 
92     if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) {
93       LLVM_DEBUG(dbgs() << "InputArg #" << i << " has unhandled type "
94                         << EVT(ArgVT).getEVTString() << '\n');
95       llvm_unreachable("");
96     }
97   }
98 }
99 
100 void LoongArchTargetLowering::analyzeOutputArgs(
101     CCState &CCInfo, const SmallVectorImpl<ISD::OutputArg> &Outs,
102     LoongArchCCAssignFn Fn) const {
103   for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
104     MVT ArgVT = Outs[i].VT;
105 
106     if (Fn(i, ArgVT, CCValAssign::Full, CCInfo)) {
107       LLVM_DEBUG(dbgs() << "OutputArg #" << i << " has unhandled type "
108                         << EVT(ArgVT).getEVTString() << "\n");
109       llvm_unreachable("");
110     }
111   }
112 }
113 
114 static SDValue unpackFromRegLoc(SelectionDAG &DAG, SDValue Chain,
115                                 const CCValAssign &VA, const SDLoc &DL,
116                                 const LoongArchTargetLowering &TLI) {
117   MachineFunction &MF = DAG.getMachineFunction();
118   MachineRegisterInfo &RegInfo = MF.getRegInfo();
119   EVT LocVT = VA.getLocVT();
120   const TargetRegisterClass *RC = TLI.getRegClassFor(LocVT.getSimpleVT());
121   Register VReg = RegInfo.createVirtualRegister(RC);
122   RegInfo.addLiveIn(VA.getLocReg(), VReg);
123 
124   return DAG.getCopyFromReg(Chain, DL, VReg, LocVT);
125 }
126 
127 // Transform physical registers into virtual registers.
128 SDValue LoongArchTargetLowering::LowerFormalArguments(
129     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
130     const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL,
131     SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
132 
133   MachineFunction &MF = DAG.getMachineFunction();
134 
135   switch (CallConv) {
136   default:
137     llvm_unreachable("Unsupported calling convention");
138   case CallingConv::C:
139     break;
140   }
141 
142   // Assign locations to all of the incoming arguments.
143   SmallVector<CCValAssign> ArgLocs;
144   CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext());
145 
146   analyzeInputArgs(CCInfo, Ins, CC_LoongArch);
147 
148   for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i)
149     InVals.push_back(unpackFromRegLoc(DAG, Chain, ArgLocs[i], DL, *this));
150 
151   return Chain;
152 }
153 
154 bool LoongArchTargetLowering::CanLowerReturn(
155     CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
156     const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const {
157   // Any return value split in to more than two values can't be returned
158   // directly.
159   return Outs.size() <= 2;
160 }
161 
162 SDValue LoongArchTargetLowering::LowerReturn(
163     SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
164     const SmallVectorImpl<ISD::OutputArg> &Outs,
165     const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL,
166     SelectionDAG &DAG) const {
167   // Stores the assignment of the return value to a location.
168   SmallVector<CCValAssign> RVLocs;
169 
170   // Info about the registers and stack slot.
171   CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
172                  *DAG.getContext());
173 
174   analyzeOutputArgs(CCInfo, Outs, CC_LoongArch);
175 
176   SDValue Glue;
177   SmallVector<SDValue, 4> RetOps(1, Chain);
178 
179   // Copy the result values into the output registers.
180   for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) {
181     CCValAssign &VA = RVLocs[i];
182     assert(VA.isRegLoc() && "Can only return in registers!");
183 
184     // Handle a 'normal' return.
185     Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Glue);
186 
187     // Guarantee that all emitted copies are stuck together.
188     Glue = Chain.getValue(1);
189     RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
190   }
191 
192   RetOps[0] = Chain; // Update chain.
193 
194   // Add the glue node if we have it.
195   if (Glue.getNode())
196     RetOps.push_back(Glue);
197 
198   return DAG.getNode(LoongArchISD::RET, DL, MVT::Other, RetOps);
199 }
200