//===-- RISCVCallingConv.cpp - RISC-V Custom CC Routines ------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains the custom routines for the RISC-V Calling Convention. // //===----------------------------------------------------------------------===// #include "RISCVCallingConv.h" #include "RISCVSubtarget.h" #include "llvm/IR/DataLayout.h" #include "llvm/MC/MCRegister.h" usingnamespacellvm; // Calling Convention Implementation. // The expectations for frontend ABI lowering vary from target to target. // Ideally, an LLVM frontend would be able to avoid worrying about many ABI // details, but this is a longer term goal. For now, we simply try to keep the // role of the frontend as simple and well-defined as possible. The rules can // be summarised as: // * Never split up large scalar arguments. We handle them here. // * If a hardfloat calling convention is being used, and the struct may be // passed in a pair of registers (fp+fp, int+fp), and both registers are // available, then pass as two separate arguments. If either the GPRs or FPRs // are exhausted, then pass according to the rule below. // * If a struct could never be passed in registers or directly in a stack // slot (as it is larger than 2*XLEN and the floating point rules don't // apply), then pass it using a pointer with the byval attribute. // * If a struct is less than 2*XLEN, then coerce to either a two-element // word-sized array or a 2*XLEN scalar (depending on alignment). // * The frontend can determine whether a struct is returned by reference or // not based on its size and fields. If it will be returned by reference, the // frontend must modify the prototype so a pointer with the sret annotation is // passed as the first argument. This is not necessary for large scalar // returns. // * Struct return values and varargs should be coerced to structs containing // register-size fields in the same situations they would be for fixed // arguments. static const MCPhysReg ArgFPR16s[] = …; static const MCPhysReg ArgFPR32s[] = …; static const MCPhysReg ArgFPR64s[] = …; // This is an interim calling convention and it may be changed in the future. static const MCPhysReg ArgVRs[] = …; static const MCPhysReg ArgVRM2s[] = …; static const MCPhysReg ArgVRM4s[] = …; static const MCPhysReg ArgVRM8s[] = …; static const MCPhysReg ArgVRN2M1s[] = …; static const MCPhysReg ArgVRN3M1s[] = …; static const MCPhysReg ArgVRN4M1s[] = …; static const MCPhysReg ArgVRN5M1s[] = …; static const MCPhysReg ArgVRN6M1s[] = …; static const MCPhysReg ArgVRN7M1s[] = …; static const MCPhysReg ArgVRN8M1s[] = …; static const MCPhysReg ArgVRN2M2s[] = …; static const MCPhysReg ArgVRN3M2s[] = …; static const MCPhysReg ArgVRN4M2s[] = …; static const MCPhysReg ArgVRN2M4s[] = …; ArrayRef<MCPhysReg> RISCV::getArgGPRs(const RISCVABI::ABI ABI) { … } static ArrayRef<MCPhysReg> getArgGPR16s(const RISCVABI::ABI ABI) { … } static ArrayRef<MCPhysReg> getArgGPR32s(const RISCVABI::ABI ABI) { … } static ArrayRef<MCPhysReg> getFastCCArgGPRs(const RISCVABI::ABI ABI) { … } static ArrayRef<MCPhysReg> getFastCCArgGPRF16s(const RISCVABI::ABI ABI) { … } static ArrayRef<MCPhysReg> getFastCCArgGPRF32s(const RISCVABI::ABI ABI) { … } // Pass a 2*XLEN argument that has been split into two XLEN values through // registers or the stack as necessary. static bool CC_RISCVAssign2XLen(unsigned XLen, CCState &State, CCValAssign VA1, ISD::ArgFlagsTy ArgFlags1, unsigned ValNo2, MVT ValVT2, MVT LocVT2, ISD::ArgFlagsTy ArgFlags2, bool EABI) { … } static MCRegister allocateRVVReg(MVT ValVT, unsigned ValNo, CCState &State, const RISCVTargetLowering &TLI) { … } // Implements the RISC-V calling convention. Returns true upon failure. bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy) { … } // FastCC has less than 1% performance improvement for some particular // benchmark. But theoretically, it may have benefit for some cases. bool llvm::CC_RISCV_FastCC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State, bool IsFixed, bool IsRet, Type *OrigTy) { … } bool llvm::CC_RISCV_GHC(unsigned ValNo, MVT ValVT, MVT LocVT, CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, CCState &State) { … }