From 7887c90a7b80b994a51a2a3b88eef3643473e67c Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Fri, 26 Oct 2012 23:56:38 +0000 Subject: Add class MipsCC which provides methods used to analyze formal and call arguments and inquire about calling convention information. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@166840 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/MipsISelLowering.cpp | 128 +++++++++++++++++++++++++++++++++++ lib/Target/Mips/MipsISelLowering.h | 64 ++++++++++++++++++ 2 files changed, 192 insertions(+) (limited to 'lib') diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index aef605bcab..077af0de3d 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -3808,3 +3808,131 @@ unsigned MipsTargetLowering::getJumpTableEncoding() const { return TargetLowering::getJumpTableEncoding(); } + +MipsTargetLowering::MipsCC::MipsCC(CallingConv::ID CallConv, bool IsVarArg, + bool IsO32, CCState &Info) : CCInfo(Info) { + UseRegsForByval = true; + + if (IsO32) { + RegSize = 4; + NumIntArgRegs = array_lengthof(O32IntRegs); + ReservedArgArea = 16; + IntArgRegs = ShadowRegs = O32IntRegs; + FixedFn = VarFn = CC_MipsO32; + } else { + RegSize = 8; + NumIntArgRegs = array_lengthof(Mips64IntRegs); + ReservedArgArea = 0; + IntArgRegs = Mips64IntRegs; + ShadowRegs = Mips64DPRegs; + FixedFn = CC_MipsN; + VarFn = CC_MipsN_VarArg; + } + + if (CallConv == CallingConv::Fast) { + assert(!IsVarArg); + UseRegsForByval = false; + ReservedArgArea = 0; + FixedFn = VarFn = CC_Mips_FastCC; + } + + // Pre-allocate reserved argument area. + CCInfo.AllocateStack(ReservedArgArea, 1); +} + +void MipsTargetLowering::MipsCC:: +analyzeCallOperands(const SmallVectorImpl &Args) { + unsigned NumOpnds = Args.size(); + + for (unsigned I = 0; I != NumOpnds; ++I) { + MVT ArgVT = Args[I].VT; + ISD::ArgFlagsTy ArgFlags = Args[I].Flags; + bool R; + + if (ArgFlags.isByVal()) { + handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags); + continue; + } + + if (Args[I].IsFixed) + R = FixedFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); + else + R = VarFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo); + + if (R) { +#ifndef NDEBUG + dbgs() << "Call operand #" << I << " has unhandled type " + << EVT(ArgVT).getEVTString(); +#endif + llvm_unreachable(0); + } + } +} + +void MipsTargetLowering::MipsCC:: +analyzeFormalArguments(const SmallVectorImpl &Args) { + unsigned NumArgs = Args.size(); + + for (unsigned I = 0; I != NumArgs; ++I) { + MVT ArgVT = Args[I].VT; + ISD::ArgFlagsTy ArgFlags = Args[I].Flags; + + if (ArgFlags.isByVal()) { + handleByValArg(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags); + continue; + } + + if (!FixedFn(I, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, CCInfo)) + continue; + +#ifndef NDEBUG + dbgs() << "Formal Arg #" << I << " has unhandled type " + << EVT(ArgVT).getEVTString(); +#endif + llvm_unreachable(0); + } +} + +void +MipsTargetLowering::MipsCC::handleByValArg(unsigned ValNo, MVT ValVT, + MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags) { + assert(ArgFlags.getByValSize() && "Byval argument's size shouldn't be 0."); + + struct ByValArgInfo ByVal; + unsigned ByValSize = RoundUpToAlignment(ArgFlags.getByValSize(), RegSize); + unsigned Align = std::min(std::max(ArgFlags.getByValAlign(), RegSize), + RegSize * 2); + + if (UseRegsForByval) + allocateRegs(ByVal, ByValSize, Align); + + // Allocate space on caller's stack. + ByVal.Address = CCInfo.AllocateStack(ByValSize - RegSize * ByVal.NumRegs, + Align); + CCInfo.addLoc(CCValAssign::getMem(ValNo, ValVT, ByVal.Address, LocVT, + LocInfo)); + ByValArgs.push_back(ByVal); +} + +void MipsTargetLowering::MipsCC::allocateRegs(ByValArgInfo &ByVal, + unsigned ByValSize, + unsigned Align) { + assert(!(ByValSize % RegSize) && !(Align % RegSize) && + "Byval argument's size and alignment should be a multiple of" + "RegSize."); + + ByVal.FirstIdx = CCInfo.getFirstUnallocated(IntArgRegs, NumIntArgRegs); + + // If Align > RegSize, the first arg register must be even. + if ((Align > RegSize) && (ByVal.FirstIdx % 2)) { + CCInfo.AllocateReg(IntArgRegs[ByVal.FirstIdx], ShadowRegs[ByVal.FirstIdx]); + ++ByVal.FirstIdx; + } + + // Mark the registers allocated. + for (unsigned I = ByVal.FirstIdx; ByValSize && (I < NumIntArgRegs); + ByValSize -= RegSize, ++I, ++ByVal.NumRegs) + CCInfo.AllocateReg(IntArgRegs[I], ShadowRegs[I]); +} diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index b75a513fa7..33ddce9a68 100644 --- a/lib/Target/Mips/MipsISelLowering.h +++ b/lib/Target/Mips/MipsISelLowering.h @@ -17,6 +17,7 @@ #include "Mips.h" #include "MipsSubtarget.h" +#include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Target/TargetLowering.h" @@ -171,6 +172,69 @@ namespace llvm { virtual SDValue PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const; private: + + /// ByValArgInfo - Byval argument information. + struct ByValArgInfo { + unsigned FirstIdx; // Index of the first register used. + unsigned NumRegs; // Number of registers used for this argument. + unsigned Address; // Offset of the stack area used to pass this argument. + + ByValArgInfo() : FirstIdx(0), NumRegs(0), Address(0) {} + }; + + /// MipsCC - This class provides methods used to analyze formal and call + /// arguments and inquire about calling convention information. + class MipsCC { + public: + MipsCC(CallingConv::ID CallConv, bool IsVarArg, bool IsO32, + CCState &Info); + + void analyzeCallOperands(const SmallVectorImpl &Outs); + void analyzeFormalArguments(const SmallVectorImpl &Ins); + void handleByValArg(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags); + + const CCState &getCCInfo() const { return CCInfo; } + + /// hasByValArg - Returns true if function has byval arguments. + bool hasByValArg() const { return !ByValArgs.empty(); } + + /// useRegsForByval - Returns true if the calling convention allows the + /// use of registers to pass byval arguments. + bool useRegsForByval() const { return UseRegsForByval; } + + /// regSize - Size (in number of bits) of integer registers. + unsigned regSize() const { return RegSize; } + + /// numIntArgRegs - Number of integer registers available for calls. + unsigned numIntArgRegs() const { return NumIntArgRegs; } + + /// reservedArgArea - The size of the area the caller reserves for + /// register arguments. This is 16-byte if ABI is O32. + unsigned reservedArgArea() const { return ReservedArgArea; } + + /// intArgRegs - Pointer to array of integer registers. + const uint16_t *intArgRegs() const { return IntArgRegs; } + + typedef SmallVector::const_iterator byval_iterator; + byval_iterator byval_begin() const { return ByValArgs.begin(); } + byval_iterator byval_end() const { return ByValArgs.end(); } + + private: + void allocateRegs(ByValArgInfo &ByVal, unsigned ByValSize, + unsigned Align); + + CCState &CCInfo; + bool UseRegsForByval; + unsigned RegSize; + unsigned NumIntArgRegs; + unsigned ReservedArgArea; + const uint16_t *IntArgRegs, *ShadowRegs; + SmallVector ByValArgs; + llvm::CCAssignFn *FixedFn, *VarFn; + }; + // Subtarget Info const MipsSubtarget *Subtarget; -- cgit v1.2.3