Home | History | Annotate | Line # | Download | only in SystemZ
      1 //===-- SystemZCallingConv.h - Calling conventions for SystemZ --*- 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 #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
     10 #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZCALLINGCONV_H
     11 
     12 #include "SystemZSubtarget.h"
     13 #include "llvm/ADT/SmallVector.h"
     14 #include "llvm/CodeGen/CallingConvLower.h"
     15 #include "llvm/MC/MCRegisterInfo.h"
     16 
     17 namespace llvm {
     18 namespace SystemZ {
     19   const unsigned ELFNumArgGPRs = 5;
     20   extern const MCPhysReg ELFArgGPRs[ELFNumArgGPRs];
     21 
     22   const unsigned ELFNumArgFPRs = 4;
     23   extern const MCPhysReg ELFArgFPRs[ELFNumArgFPRs];
     24 
     25   const unsigned XPLINK64NumArgGPRs = 3;
     26   extern const MCPhysReg XPLINK64ArgGPRs[XPLINK64NumArgGPRs];
     27 
     28   const unsigned XPLINK64NumArgFPRs = 4;
     29   extern const MCPhysReg XPLINK64ArgFPRs[XPLINK64NumArgFPRs];
     30 } // end namespace SystemZ
     31 
     32 class SystemZCCState : public CCState {
     33 private:
     34   /// Records whether the value was a fixed argument.
     35   /// See ISD::OutputArg::IsFixed.
     36   SmallVector<bool, 4> ArgIsFixed;
     37 
     38   /// Records whether the value was widened from a short vector type.
     39   SmallVector<bool, 4> ArgIsShortVector;
     40 
     41   // Check whether ArgVT is a short vector type.
     42   bool IsShortVectorType(EVT ArgVT) {
     43     return ArgVT.isVector() && ArgVT.getStoreSize() <= 8;
     44   }
     45 
     46 public:
     47   SystemZCCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
     48                  SmallVectorImpl<CCValAssign> &locs, LLVMContext &C)
     49       : CCState(CC, isVarArg, MF, locs, C) {}
     50 
     51   void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins,
     52                               CCAssignFn Fn) {
     53     // Formal arguments are always fixed.
     54     ArgIsFixed.clear();
     55     for (unsigned i = 0; i < Ins.size(); ++i)
     56       ArgIsFixed.push_back(true);
     57     // Record whether the call operand was a short vector.
     58     ArgIsShortVector.clear();
     59     for (unsigned i = 0; i < Ins.size(); ++i)
     60       ArgIsShortVector.push_back(IsShortVectorType(Ins[i].ArgVT));
     61 
     62     CCState::AnalyzeFormalArguments(Ins, Fn);
     63   }
     64 
     65   void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs,
     66                            CCAssignFn Fn) {
     67     // Record whether the call operand was a fixed argument.
     68     ArgIsFixed.clear();
     69     for (unsigned i = 0; i < Outs.size(); ++i)
     70       ArgIsFixed.push_back(Outs[i].IsFixed);
     71     // Record whether the call operand was a short vector.
     72     ArgIsShortVector.clear();
     73     for (unsigned i = 0; i < Outs.size(); ++i)
     74       ArgIsShortVector.push_back(IsShortVectorType(Outs[i].ArgVT));
     75 
     76     CCState::AnalyzeCallOperands(Outs, Fn);
     77   }
     78 
     79   // This version of AnalyzeCallOperands in the base class is not usable
     80   // since we must provide a means of accessing ISD::OutputArg::IsFixed.
     81   void AnalyzeCallOperands(const SmallVectorImpl<MVT> &Outs,
     82                            SmallVectorImpl<ISD::ArgFlagsTy> &Flags,
     83                            CCAssignFn Fn) = delete;
     84 
     85   bool IsFixed(unsigned ValNo) { return ArgIsFixed[ValNo]; }
     86   bool IsShortVector(unsigned ValNo) { return ArgIsShortVector[ValNo]; }
     87 };
     88 
     89 // Handle i128 argument types.  These need to be passed by implicit
     90 // reference.  This could be as simple as the following .td line:
     91 //    CCIfType<[i128], CCPassIndirect<i64>>,
     92 // except that i128 is not a legal type, and therefore gets split by
     93 // common code into a pair of i64 arguments.
     94 inline bool CC_SystemZ_I128Indirect(unsigned &ValNo, MVT &ValVT,
     95                                     MVT &LocVT,
     96                                     CCValAssign::LocInfo &LocInfo,
     97                                     ISD::ArgFlagsTy &ArgFlags,
     98                                     CCState &State) {
     99   SmallVectorImpl<CCValAssign> &PendingMembers = State.getPendingLocs();
    100 
    101   // ArgFlags.isSplit() is true on the first part of a i128 argument;
    102   // PendingMembers.empty() is false on all subsequent parts.
    103   if (!ArgFlags.isSplit() && PendingMembers.empty())
    104     return false;
    105 
    106   // Push a pending Indirect value location for each part.
    107   LocVT = MVT::i64;
    108   LocInfo = CCValAssign::Indirect;
    109   PendingMembers.push_back(CCValAssign::getPending(ValNo, ValVT,
    110                                                    LocVT, LocInfo));
    111   if (!ArgFlags.isSplitEnd())
    112     return true;
    113 
    114   // OK, we've collected all parts in the pending list.  Allocate
    115   // the location (register or stack slot) for the indirect pointer.
    116   // (This duplicates the usual i64 calling convention rules.)
    117   unsigned Reg;
    118   const SystemZSubtarget &Subtarget =
    119       State.getMachineFunction().getSubtarget<SystemZSubtarget>();
    120   if (Subtarget.isTargetELF())
    121     Reg = State.AllocateReg(SystemZ::ELFArgGPRs);
    122   else if (Subtarget.isTargetXPLINK64())
    123     Reg = State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
    124   else
    125     llvm_unreachable("Unknown Calling Convention!");
    126 
    127   unsigned Offset = Reg ? 0 : State.AllocateStack(8, Align(8));
    128 
    129   // Use that same location for all the pending parts.
    130   for (auto &It : PendingMembers) {
    131     if (Reg)
    132       It.convertToReg(Reg);
    133     else
    134       It.convertToMem(Offset);
    135     State.addLoc(It);
    136   }
    137 
    138   PendingMembers.clear();
    139 
    140   return true;
    141 }
    142 
    143 inline bool CC_XPLINK64_Shadow_Reg(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
    144                                    CCValAssign::LocInfo &LocInfo,
    145                                    ISD::ArgFlagsTy &ArgFlags, CCState &State) {
    146   if (LocVT == MVT::f32 || LocVT == MVT::f64) {
    147     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
    148   }
    149   if (LocVT == MVT::f128 || LocVT.is128BitVector()) {
    150     // Shadow next two GPRs, if available.
    151     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
    152     State.AllocateReg(SystemZ::XPLINK64ArgGPRs);
    153 
    154     // Quad precision floating point needs to
    155     // go inside pre-defined FPR pair.
    156     if (LocVT == MVT::f128) {
    157       for (unsigned I = 0; I < SystemZ::XPLINK64NumArgFPRs; I += 2)
    158         if (State.isAllocated(SystemZ::XPLINK64ArgFPRs[I]))
    159           State.AllocateReg(SystemZ::XPLINK64ArgFPRs[I + 1]);
    160     }
    161   }
    162   return false;
    163 }
    164 
    165 inline bool CC_XPLINK64_Allocate128BitVararg(unsigned &ValNo, MVT &ValVT,
    166                                              MVT &LocVT,
    167                                              CCValAssign::LocInfo &LocInfo,
    168                                              ISD::ArgFlagsTy &ArgFlags,
    169                                              CCState &State) {
    170   if (LocVT.getSizeInBits() < 128)
    171     return false;
    172 
    173   if (static_cast<SystemZCCState *>(&State)->IsFixed(ValNo))
    174     return false;
    175 
    176   // For any C or C++ program, this should always be
    177   // false, since it is illegal to have a function
    178   // where the first argument is variadic. Therefore
    179   // the first fixed argument should already have
    180   // allocated GPR1 either through shadowing it or
    181   // using it for parameter passing.
    182   State.AllocateReg(SystemZ::R1D);
    183 
    184   bool AllocGPR2 = State.AllocateReg(SystemZ::R2D);
    185   bool AllocGPR3 = State.AllocateReg(SystemZ::R3D);
    186 
    187   // If GPR2 and GPR3 are available, then we may pass vararg in R2Q.
    188   if (AllocGPR2 && AllocGPR3) {
    189     State.addLoc(
    190         CCValAssign::getReg(ValNo, ValVT, SystemZ::R2Q, LocVT, LocInfo));
    191     return true;
    192   }
    193 
    194   // If only GPR3 is available, we allocate on stack but need to
    195   // set custom handling to copy hi bits into GPR3.
    196   if (!AllocGPR2 && AllocGPR3) {
    197     auto Offset = State.AllocateStack(16, Align(8));
    198     State.addLoc(
    199         CCValAssign::getCustomMem(ValNo, ValVT, Offset, LocVT, LocInfo));
    200     return true;
    201   }
    202 
    203   return false;
    204 }
    205 
    206 inline bool RetCC_SystemZ_Error(unsigned &, MVT &, MVT &,
    207                                 CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
    208                                 CCState &) {
    209   llvm_unreachable("Return value calling convention currently unsupported.");
    210 }
    211 
    212 inline bool CC_SystemZ_Error(unsigned &, MVT &, MVT &, CCValAssign::LocInfo &,
    213                              ISD::ArgFlagsTy &, CCState &) {
    214   llvm_unreachable("Argument calling convention currently unsupported.");
    215 }
    216 
    217 inline bool CC_SystemZ_GHC_Error(unsigned &, MVT &, MVT &,
    218                                  CCValAssign::LocInfo &, ISD::ArgFlagsTy &,
    219                                  CCState &) {
    220   report_fatal_error("No registers left in GHC calling convention");
    221   return false;
    222 }
    223 
    224 } // end namespace llvm
    225 
    226 #endif
    227