1 //===-- CSKYISelLowering.cpp - CSKY 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 CSKY uses to lower LLVM code into a 10 // selection DAG. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "CSKYISelLowering.h" 15 #include "CSKYCallingConv.h" 16 #include "CSKYMachineFunctionInfo.h" 17 #include "CSKYRegisterInfo.h" 18 #include "CSKYSubtarget.h" 19 #include "llvm/ADT/Statistic.h" 20 #include "llvm/CodeGen/CallingConvLower.h" 21 #include "llvm/CodeGen/MachineJumpTableInfo.h" 22 #include "llvm/Support/Debug.h" 23 24 using namespace llvm; 25 26 #define DEBUG_TYPE "csky-isel-lowering" 27 28 STATISTIC(NumTailCalls, "Number of tail calls"); 29 30 #include "CSKYGenCallingConv.inc" 31 32 static const MCPhysReg GPRArgRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3}; 33 34 CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM, 35 const CSKYSubtarget &STI) 36 : TargetLowering(TM), Subtarget(STI) { 37 // Register Class 38 addRegisterClass(MVT::i32, &CSKY::GPRRegClass); 39 40 // Compute derived properties from the register classes. 41 computeRegisterProperties(STI.getRegisterInfo()); 42 43 setBooleanContents(UndefinedBooleanContent); 44 setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); 45 46 // TODO: Add atomic support fully. 47 setMaxAtomicSizeInBitsSupported(0); 48 49 setStackPointerRegisterToSaveRestore(CSKY::R14); 50 const Align FunctionAlignment(2); 51 setMinFunctionAlignment(FunctionAlignment); 52 setSchedulingPreference(Sched::Source); 53 } 54 55 EVT CSKYTargetLowering::getSetCCResultType(const DataLayout &DL, 56 LLVMContext &Context, EVT VT) const { 57 if (!VT.isVector()) 58 return MVT::i32; 59 60 return VT.changeVectorElementTypeToInteger(); 61 } 62 63 static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, 64 const CCValAssign &VA, const SDLoc &DL) { 65 EVT LocVT = VA.getLocVT(); 66 67 switch (VA.getLocInfo()) { 68 default: 69 llvm_unreachable("Unexpected CCValAssign::LocInfo"); 70 case CCValAssign::Full: 71 break; 72 case CCValAssign::BCvt: 73 Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); 74 break; 75 } 76 return Val; 77 } 78 79 static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, 80 const CCValAssign &VA, const SDLoc &DL) { 81 switch (VA.getLocInfo()) { 82 default: 83 llvm_unreachable("Unexpected CCValAssign::LocInfo"); 84 case CCValAssign::Full: 85 break; 86 case CCValAssign::BCvt: 87 Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); 88 break; 89 } 90 return Val; 91 } 92 93 static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, 94 SelectionDAG &DAG, SDValue Chain, 95 const CCValAssign &VA, const SDLoc &DL) { 96 MachineFunction &MF = DAG.getMachineFunction(); 97 MachineRegisterInfo &RegInfo = MF.getRegInfo(); 98 EVT LocVT = VA.getLocVT(); 99 SDValue Val; 100 const TargetRegisterClass *RC; 101 102 switch (LocVT.getSimpleVT().SimpleTy) { 103 default: 104 llvm_unreachable("Unexpected register type"); 105 case MVT::i32: 106 RC = &CSKY::GPRRegClass; 107 break; 108 } 109 110 Register VReg = RegInfo.createVirtualRegister(RC); 111 RegInfo.addLiveIn(VA.getLocReg(), VReg); 112 Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); 113 114 return convertLocVTToValVT(DAG, Val, VA, DL); 115 } 116 117 static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, 118 const CCValAssign &VA, const SDLoc &DL) { 119 MachineFunction &MF = DAG.getMachineFunction(); 120 MachineFrameInfo &MFI = MF.getFrameInfo(); 121 EVT LocVT = VA.getLocVT(); 122 EVT ValVT = VA.getValVT(); 123 EVT PtrVT = MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)); 124 int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8, 125 VA.getLocMemOffset(), /*Immutable=*/true); 126 SDValue FIN = DAG.getFrameIndex(FI, PtrVT); 127 SDValue Val; 128 129 ISD::LoadExtType ExtType; 130 switch (VA.getLocInfo()) { 131 default: 132 llvm_unreachable("Unexpected CCValAssign::LocInfo"); 133 case CCValAssign::Full: 134 case CCValAssign::BCvt: 135 ExtType = ISD::NON_EXTLOAD; 136 break; 137 } 138 Val = DAG.getExtLoad( 139 ExtType, DL, LocVT, Chain, FIN, 140 MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); 141 return Val; 142 } 143 144 // Transform physical registers into virtual registers. 145 SDValue CSKYTargetLowering::LowerFormalArguments( 146 SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, 147 const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, 148 SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { 149 150 switch (CallConv) { 151 default: 152 report_fatal_error("Unsupported calling convention"); 153 case CallingConv::C: 154 case CallingConv::Fast: 155 break; 156 } 157 158 MachineFunction &MF = DAG.getMachineFunction(); 159 160 // Used with vargs to acumulate store chains. 161 std::vector<SDValue> OutChains; 162 163 // Assign locations to all of the incoming arguments. 164 SmallVector<CCValAssign, 16> ArgLocs; 165 CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); 166 167 CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg)); 168 169 for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { 170 CCValAssign &VA = ArgLocs[i]; 171 SDValue ArgValue; 172 173 if (VA.isRegLoc()) 174 ArgValue = unpackFromRegLoc(Subtarget, DAG, Chain, VA, DL); 175 else 176 ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); 177 178 InVals.push_back(ArgValue); 179 } 180 181 if (IsVarArg) { 182 const unsigned XLenInBytes = 4; 183 const MVT XLenVT = MVT::i32; 184 185 ArrayRef<MCPhysReg> ArgRegs = makeArrayRef(GPRArgRegs); 186 unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); 187 const TargetRegisterClass *RC = &CSKY::GPRRegClass; 188 MachineFrameInfo &MFI = MF.getFrameInfo(); 189 MachineRegisterInfo &RegInfo = MF.getRegInfo(); 190 CSKYMachineFunctionInfo *CSKYFI = MF.getInfo<CSKYMachineFunctionInfo>(); 191 192 // Offset of the first variable argument from stack pointer, and size of 193 // the vararg save area. For now, the varargs save area is either zero or 194 // large enough to hold a0-a4. 195 int VaArgOffset, VarArgsSaveSize; 196 197 // If all registers are allocated, then all varargs must be passed on the 198 // stack and we don't need to save any argregs. 199 if (ArgRegs.size() == Idx) { 200 VaArgOffset = CCInfo.getNextStackOffset(); 201 VarArgsSaveSize = 0; 202 } else { 203 VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx); 204 VaArgOffset = -VarArgsSaveSize; 205 } 206 207 // Record the frame index of the first variable argument 208 // which is a value necessary to VASTART. 209 int FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); 210 CSKYFI->setVarArgsFrameIndex(FI); 211 212 // Copy the integer registers that may have been used for passing varargs 213 // to the vararg save area. 214 for (unsigned I = Idx; I < ArgRegs.size(); 215 ++I, VaArgOffset += XLenInBytes) { 216 const Register Reg = RegInfo.createVirtualRegister(RC); 217 RegInfo.addLiveIn(ArgRegs[I], Reg); 218 SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, XLenVT); 219 FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); 220 SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); 221 SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, 222 MachinePointerInfo::getFixedStack(MF, FI)); 223 cast<StoreSDNode>(Store.getNode()) 224 ->getMemOperand() 225 ->setValue((Value *)nullptr); 226 OutChains.push_back(Store); 227 } 228 CSKYFI->setVarArgsSaveSize(VarArgsSaveSize); 229 } 230 231 // All stores are grouped in one node to allow the matching between 232 // the size of Ins and InVals. This only happens for vararg functions. 233 if (!OutChains.empty()) { 234 OutChains.push_back(Chain); 235 Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); 236 } 237 238 return Chain; 239 } 240 241 bool CSKYTargetLowering::CanLowerReturn( 242 CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, 243 const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context) const { 244 SmallVector<CCValAssign, 16> CSKYLocs; 245 CCState CCInfo(CallConv, IsVarArg, MF, CSKYLocs, Context); 246 return CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg)); 247 } 248 249 SDValue 250 CSKYTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, 251 bool IsVarArg, 252 const SmallVectorImpl<ISD::OutputArg> &Outs, 253 const SmallVectorImpl<SDValue> &OutVals, 254 const SDLoc &DL, SelectionDAG &DAG) const { 255 // Stores the assignment of the return value to a location. 256 SmallVector<CCValAssign, 16> CSKYLocs; 257 258 // Info about the registers and stack slot. 259 CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), CSKYLocs, 260 *DAG.getContext()); 261 CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg)); 262 263 SDValue Glue; 264 SmallVector<SDValue, 4> RetOps(1, Chain); 265 266 // Copy the result values into the output registers. 267 for (unsigned i = 0, e = CSKYLocs.size(); i < e; ++i) { 268 SDValue Val = OutVals[i]; 269 CCValAssign &VA = CSKYLocs[i]; 270 assert(VA.isRegLoc() && "Can only return in registers!"); 271 272 bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64; 273 274 if (IsF64OnCSKY) { 275 276 assert(VA.isRegLoc() && "Expected return via registers"); 277 SDValue Split64 = DAG.getNode(CSKYISD::BITCAST_TO_LOHI, DL, 278 DAG.getVTList(MVT::i32, MVT::i32), Val); 279 SDValue Lo = Split64.getValue(0); 280 SDValue Hi = Split64.getValue(1); 281 282 Register RegLo = VA.getLocReg(); 283 assert(RegLo < CSKY::R31 && "Invalid register pair"); 284 Register RegHi = RegLo + 1; 285 286 Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue); 287 Glue = Chain.getValue(1); 288 RetOps.push_back(DAG.getRegister(RegLo, MVT::i32)); 289 Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue); 290 Glue = Chain.getValue(1); 291 RetOps.push_back(DAG.getRegister(RegHi, MVT::i32)); 292 } else { 293 // Handle a 'normal' return. 294 Val = convertValVTToLocVT(DAG, Val, VA, DL); 295 Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); 296 297 // Guarantee that all emitted copies are stuck together. 298 Glue = Chain.getValue(1); 299 RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); 300 } 301 } 302 303 RetOps[0] = Chain; // Update chain. 304 305 // Add the glue node if we have it. 306 if (Glue.getNode()) { 307 RetOps.push_back(Glue); 308 } 309 310 // Interrupt service routines use different return instructions. 311 if (DAG.getMachineFunction().getFunction().hasFnAttribute("interrupt")) 312 return DAG.getNode(CSKYISD::NIR, DL, MVT::Other, RetOps); 313 314 return DAG.getNode(CSKYISD::RET, DL, MVT::Other, RetOps); 315 } 316 317 CCAssignFn *CSKYTargetLowering::CCAssignFnForReturn(CallingConv::ID CC, 318 bool IsVarArg) const { 319 if (IsVarArg || !Subtarget.useHardFloatABI()) 320 return RetCC_CSKY_ABIV2_SOFT; 321 else 322 return RetCC_CSKY_ABIV2_FP; 323 } 324 325 CCAssignFn *CSKYTargetLowering::CCAssignFnForCall(CallingConv::ID CC, 326 bool IsVarArg) const { 327 if (IsVarArg || !Subtarget.useHardFloatABI()) 328 return CC_CSKY_ABIV2_SOFT; 329 else 330 return CC_CSKY_ABIV2_FP; 331 } 332 333 const char *CSKYTargetLowering::getTargetNodeName(unsigned Opcode) const { 334 switch (Opcode) { 335 default: 336 llvm_unreachable("unknown CSKYISD node"); 337 case CSKYISD::NIE: 338 return "CSKYISD::NIE"; 339 case CSKYISD::NIR: 340 return "CSKYISD::NIR"; 341 case CSKYISD::RET: 342 return "CSKYISD::RET"; 343 case CSKYISD::BITCAST_TO_LOHI: 344 return "CSKYISD::BITCAST_TO_LOHI"; 345 } 346 } 347