1 //===-- RISCVCallLowering.cpp - Call lowering -------------------*- C++ -*-===// 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 /// \file 10 /// This file implements the lowering of LLVM calls to machine code calls for 11 /// GlobalISel. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "RISCVCallLowering.h" 16 #include "RISCVISelLowering.h" 17 #include "RISCVSubtarget.h" 18 #include "llvm/CodeGen/Analysis.h" 19 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 20 21 using namespace llvm; 22 23 namespace { 24 25 struct RISCVOutgoingValueAssigner : public CallLowering::OutgoingValueAssigner { 26 private: 27 // The function used internally to assign args - we ignore the AssignFn stored 28 // by OutgoingValueAssigner since RISC-V implements its CC using a custom 29 // function with a different signature. 30 RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn; 31 32 // Whether this is assigning args for a return. 33 bool IsRet; 34 35 public: 36 RISCVOutgoingValueAssigner( 37 RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet) 38 : CallLowering::OutgoingValueAssigner(nullptr), 39 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {} 40 41 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT, 42 CCValAssign::LocInfo LocInfo, 43 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags, 44 CCState &State) override { 45 MachineFunction &MF = State.getMachineFunction(); 46 const DataLayout &DL = MF.getDataLayout(); 47 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>(); 48 49 return RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT, 50 LocInfo, Flags, State, /*IsFixed=*/true, IsRet, 51 Info.Ty, *Subtarget.getTargetLowering(), 52 /*FirstMaskArgument=*/std::nullopt); 53 } 54 }; 55 56 struct RISCVOutgoingValueHandler : public CallLowering::OutgoingValueHandler { 57 RISCVOutgoingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 58 MachineInstrBuilder MIB) 59 : OutgoingValueHandler(B, MRI), MIB(MIB) {} 60 61 MachineInstrBuilder MIB; 62 63 Register getStackAddress(uint64_t MemSize, int64_t Offset, 64 MachinePointerInfo &MPO, 65 ISD::ArgFlagsTy Flags) override { 66 llvm_unreachable("not implemented"); 67 } 68 69 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, 70 MachinePointerInfo &MPO, CCValAssign &VA) override { 71 llvm_unreachable("not implemented"); 72 } 73 74 void assignValueToReg(Register ValVReg, Register PhysReg, 75 CCValAssign VA) override { 76 Register ExtReg = extendRegister(ValVReg, VA); 77 MIRBuilder.buildCopy(PhysReg, ExtReg); 78 MIB.addUse(PhysReg, RegState::Implicit); 79 } 80 }; 81 82 struct RISCVIncomingValueAssigner : public CallLowering::IncomingValueAssigner { 83 private: 84 // The function used internally to assign args - we ignore the AssignFn stored 85 // by IncomingValueAssigner since RISC-V implements its CC using a custom 86 // function with a different signature. 87 RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn; 88 89 // Whether this is assigning args from a return. 90 bool IsRet; 91 92 public: 93 RISCVIncomingValueAssigner( 94 RISCVTargetLowering::RISCVCCAssignFn *RISCVAssignFn_, bool IsRet) 95 : CallLowering::IncomingValueAssigner(nullptr), 96 RISCVAssignFn(RISCVAssignFn_), IsRet(IsRet) {} 97 98 bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT, 99 CCValAssign::LocInfo LocInfo, 100 const CallLowering::ArgInfo &Info, ISD::ArgFlagsTy Flags, 101 CCState &State) override { 102 MachineFunction &MF = State.getMachineFunction(); 103 const DataLayout &DL = MF.getDataLayout(); 104 const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>(); 105 106 return RISCVAssignFn(DL, Subtarget.getTargetABI(), ValNo, ValVT, LocVT, 107 LocInfo, Flags, State, /*IsFixed=*/true, IsRet, 108 Info.Ty, *Subtarget.getTargetLowering(), 109 /*FirstMaskArgument=*/std::nullopt); 110 } 111 }; 112 113 struct RISCVIncomingValueHandler : public CallLowering::IncomingValueHandler { 114 RISCVIncomingValueHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI) 115 : IncomingValueHandler(B, MRI) {} 116 117 Register getStackAddress(uint64_t MemSize, int64_t Offset, 118 MachinePointerInfo &MPO, 119 ISD::ArgFlagsTy Flags) override { 120 llvm_unreachable("not implemented"); 121 } 122 123 void assignValueToAddress(Register ValVReg, Register Addr, LLT MemTy, 124 MachinePointerInfo &MPO, CCValAssign &VA) override { 125 llvm_unreachable("not implemented"); 126 } 127 128 void assignValueToReg(Register ValVReg, Register PhysReg, 129 CCValAssign VA) override { 130 // Copy argument received in physical register to desired VReg. 131 MIRBuilder.getMBB().addLiveIn(PhysReg); 132 MIRBuilder.buildCopy(ValVReg, PhysReg); 133 } 134 }; 135 136 struct RISCVCallReturnHandler : public RISCVIncomingValueHandler { 137 RISCVCallReturnHandler(MachineIRBuilder &B, MachineRegisterInfo &MRI, 138 MachineInstrBuilder &MIB) 139 : RISCVIncomingValueHandler(B, MRI), MIB(MIB) {} 140 141 MachineInstrBuilder MIB; 142 143 void assignValueToReg(Register ValVReg, Register PhysReg, 144 CCValAssign VA) override { 145 // Copy argument received in physical register to desired VReg. 146 MIB.addDef(PhysReg, RegState::Implicit); 147 MIRBuilder.buildCopy(ValVReg, PhysReg); 148 } 149 }; 150 151 } // namespace 152 153 RISCVCallLowering::RISCVCallLowering(const RISCVTargetLowering &TLI) 154 : CallLowering(&TLI) {} 155 156 bool RISCVCallLowering::lowerReturnVal(MachineIRBuilder &MIRBuilder, 157 const Value *Val, 158 ArrayRef<Register> VRegs, 159 MachineInstrBuilder &Ret) const { 160 if (!Val) 161 return true; 162 163 // TODO: Only integer, pointer and aggregate types are supported now. 164 if (!Val->getType()->isIntOrPtrTy() && !Val->getType()->isAggregateType()) 165 return false; 166 167 MachineFunction &MF = MIRBuilder.getMF(); 168 const DataLayout &DL = MF.getDataLayout(); 169 const Function &F = MF.getFunction(); 170 CallingConv::ID CC = F.getCallingConv(); 171 172 ArgInfo OrigRetInfo(VRegs, Val->getType(), 0); 173 setArgFlags(OrigRetInfo, AttributeList::ReturnIndex, DL, F); 174 175 SmallVector<ArgInfo, 4> SplitRetInfos; 176 splitToValueTypes(OrigRetInfo, SplitRetInfos, DL, CC); 177 178 RISCVOutgoingValueAssigner Assigner( 179 CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 180 /*IsRet=*/true); 181 RISCVOutgoingValueHandler Handler(MIRBuilder, MF.getRegInfo(), Ret); 182 return determineAndHandleAssignments(Handler, Assigner, SplitRetInfos, 183 MIRBuilder, CC, F.isVarArg()); 184 } 185 186 bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, 187 const Value *Val, ArrayRef<Register> VRegs, 188 FunctionLoweringInfo &FLI) const { 189 assert(!Val == VRegs.empty() && "Return value without a vreg"); 190 MachineInstrBuilder Ret = MIRBuilder.buildInstrNoInsert(RISCV::PseudoRET); 191 192 if (!lowerReturnVal(MIRBuilder, Val, VRegs, Ret)) 193 return false; 194 195 MIRBuilder.insertInstr(Ret); 196 return true; 197 } 198 199 bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, 200 const Function &F, 201 ArrayRef<ArrayRef<Register>> VRegs, 202 FunctionLoweringInfo &FLI) const { 203 // Early exit if there are no arguments. 204 if (F.arg_empty()) 205 return true; 206 207 // TODO: Support vararg functions. 208 if (F.isVarArg()) 209 return false; 210 211 // TODO: Support all argument types. 212 for (auto &Arg : F.args()) { 213 if (Arg.getType()->isIntegerTy()) 214 continue; 215 if (Arg.getType()->isPointerTy()) 216 continue; 217 return false; 218 } 219 220 MachineFunction &MF = MIRBuilder.getMF(); 221 const DataLayout &DL = MF.getDataLayout(); 222 CallingConv::ID CC = F.getCallingConv(); 223 224 SmallVector<ArgInfo, 32> SplitArgInfos; 225 unsigned Index = 0; 226 for (auto &Arg : F.args()) { 227 // Construct the ArgInfo object from destination register and argument type. 228 ArgInfo AInfo(VRegs[Index], Arg.getType(), Index); 229 setArgFlags(AInfo, Index + AttributeList::FirstArgIndex, DL, F); 230 231 // Handle any required merging from split value types from physical 232 // registers into the desired VReg. ArgInfo objects are constructed 233 // correspondingly and appended to SplitArgInfos. 234 splitToValueTypes(AInfo, SplitArgInfos, DL, CC); 235 236 ++Index; 237 } 238 239 RISCVIncomingValueAssigner Assigner( 240 CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 241 /*IsRet=*/false); 242 RISCVIncomingValueHandler Handler(MIRBuilder, MF.getRegInfo()); 243 244 return determineAndHandleAssignments(Handler, Assigner, SplitArgInfos, 245 MIRBuilder, CC, F.isVarArg()); 246 } 247 248 bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, 249 CallLoweringInfo &Info) const { 250 MachineFunction &MF = MIRBuilder.getMF(); 251 const DataLayout &DL = MF.getDataLayout(); 252 const Function &F = MF.getFunction(); 253 CallingConv::ID CC = F.getCallingConv(); 254 255 // TODO: Support vararg functions. 256 if (Info.IsVarArg) 257 return false; 258 259 // TODO: Support all argument types. 260 for (auto &AInfo : Info.OrigArgs) { 261 if (AInfo.Ty->isIntegerTy()) 262 continue; 263 if (AInfo.Ty->isPointerTy()) 264 continue; 265 if (AInfo.Ty->isFloatingPointTy()) 266 continue; 267 return false; 268 } 269 270 SmallVector<ArgInfo, 32> SplitArgInfos; 271 SmallVector<ISD::OutputArg, 8> Outs; 272 for (auto &AInfo : Info.OrigArgs) { 273 // Handle any required unmerging of split value types from a given VReg into 274 // physical registers. ArgInfo objects are constructed correspondingly and 275 // appended to SplitArgInfos. 276 splitToValueTypes(AInfo, SplitArgInfos, DL, CC); 277 } 278 279 // TODO: Support tail calls. 280 Info.IsTailCall = false; 281 282 if (!Info.Callee.isReg()) 283 Info.Callee.setTargetFlags(RISCVII::MO_CALL); 284 285 MachineInstrBuilder Call = 286 MIRBuilder 287 .buildInstrNoInsert(Info.Callee.isReg() ? RISCV::PseudoCALLIndirect 288 : RISCV::PseudoCALL) 289 .add(Info.Callee); 290 291 RISCVOutgoingValueAssigner ArgAssigner( 292 CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 293 /*IsRet=*/false); 294 RISCVOutgoingValueHandler ArgHandler(MIRBuilder, MF.getRegInfo(), Call); 295 if (!determineAndHandleAssignments(ArgHandler, ArgAssigner, SplitArgInfos, 296 MIRBuilder, CC, Info.IsVarArg)) 297 return false; 298 299 MIRBuilder.insertInstr(Call); 300 301 if (Info.OrigRet.Ty->isVoidTy()) 302 return true; 303 304 // TODO: Only integer, pointer and aggregate types are supported now. 305 if (!Info.OrigRet.Ty->isIntOrPtrTy() && !Info.OrigRet.Ty->isAggregateType()) 306 return false; 307 308 SmallVector<ArgInfo, 4> SplitRetInfos; 309 splitToValueTypes(Info.OrigRet, SplitRetInfos, DL, CC); 310 311 // Assignments should be handled *before* the merging of values takes place. 312 // To ensure this, the insert point is temporarily adjusted to just after the 313 // call instruction. 314 MachineBasicBlock::iterator CallInsertPt = Call; 315 MIRBuilder.setInsertPt(MIRBuilder.getMBB(), std::next(CallInsertPt)); 316 317 RISCVIncomingValueAssigner RetAssigner( 318 CC == CallingConv::Fast ? RISCV::CC_RISCV_FastCC : RISCV::CC_RISCV, 319 /*IsRet=*/true); 320 RISCVCallReturnHandler RetHandler(MIRBuilder, MF.getRegInfo(), Call); 321 if (!determineAndHandleAssignments(RetHandler, RetAssigner, SplitRetInfos, 322 MIRBuilder, CC, Info.IsVarArg)) 323 return false; 324 325 // Readjust insert point to end of basic block. 326 MIRBuilder.setMBB(MIRBuilder.getMBB()); 327 328 return true; 329 } 330