|  | //===-- ARMCallingConv.h - ARM Custom Calling Convention Routines ---------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file contains the custom routines for the ARM Calling Convention that | 
|  | // aren't done by tablegen. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef ARMCALLINGCONV_H | 
|  | #define ARMCALLINGCONV_H | 
|  |  | 
|  | #include "llvm/CallingConv.h" | 
|  | #include "llvm/CodeGen/CallingConvLower.h" | 
|  | #include "llvm/Target/TargetInstrInfo.h" | 
|  | #include "ARMBaseInstrInfo.h" | 
|  | #include "ARMRegisterInfo.h" | 
|  | #include "ARMSubtarget.h" | 
|  | #include "ARM.h" | 
|  |  | 
|  | namespace llvm { | 
|  |  | 
|  | // APCS f64 is in register pairs, possibly split to stack | 
|  | static bool f64AssignAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, | 
|  | CCValAssign::LocInfo &LocInfo, | 
|  | CCState &State, bool CanFail) { | 
|  | static const unsigned RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; | 
|  |  | 
|  | // Try to get the first register. | 
|  | if (unsigned Reg = State.AllocateReg(RegList, 4)) | 
|  | State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); | 
|  | else { | 
|  | // For the 2nd half of a v2f64, do not fail. | 
|  | if (CanFail) | 
|  | return false; | 
|  |  | 
|  | // Put the whole thing on the stack. | 
|  | State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, | 
|  | State.AllocateStack(8, 4), | 
|  | LocVT, LocInfo)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Try to get the second register. | 
|  | if (unsigned Reg = State.AllocateReg(RegList, 4)) | 
|  | State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); | 
|  | else | 
|  | State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, | 
|  | State.AllocateStack(4, 4), | 
|  | LocVT, LocInfo)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, | 
|  | CCValAssign::LocInfo &LocInfo, | 
|  | ISD::ArgFlagsTy &ArgFlags, | 
|  | CCState &State) { | 
|  | if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) | 
|  | return false; | 
|  | if (LocVT == MVT::v2f64 && | 
|  | !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) | 
|  | return false; | 
|  | return true;  // we handled it | 
|  | } | 
|  |  | 
|  | // AAPCS f64 is in aligned register pairs | 
|  | static bool f64AssignAAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, | 
|  | CCValAssign::LocInfo &LocInfo, | 
|  | CCState &State, bool CanFail) { | 
|  | static const unsigned HiRegList[] = { ARM::R0, ARM::R2 }; | 
|  | static const unsigned LoRegList[] = { ARM::R1, ARM::R3 }; | 
|  | static const unsigned ShadowRegList[] = { ARM::R0, ARM::R1 }; | 
|  |  | 
|  | unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2); | 
|  | if (Reg == 0) { | 
|  | // For the 2nd half of a v2f64, do not just fail. | 
|  | if (CanFail) | 
|  | return false; | 
|  |  | 
|  | // Put the whole thing on the stack. | 
|  | State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, | 
|  | State.AllocateStack(8, 8), | 
|  | LocVT, LocInfo)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | unsigned i; | 
|  | for (i = 0; i < 2; ++i) | 
|  | if (HiRegList[i] == Reg) | 
|  | break; | 
|  |  | 
|  | unsigned T = State.AllocateReg(LoRegList[i]); | 
|  | (void)T; | 
|  | assert(T == LoRegList[i] && "Could not allocate register"); | 
|  |  | 
|  | State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); | 
|  | State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], | 
|  | LocVT, LocInfo)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, | 
|  | CCValAssign::LocInfo &LocInfo, | 
|  | ISD::ArgFlagsTy &ArgFlags, | 
|  | CCState &State) { | 
|  | if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) | 
|  | return false; | 
|  | if (LocVT == MVT::v2f64 && | 
|  | !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) | 
|  | return false; | 
|  | return true;  // we handled it | 
|  | } | 
|  |  | 
|  | static bool f64RetAssign(unsigned &ValNo, MVT &ValVT, MVT &LocVT, | 
|  | CCValAssign::LocInfo &LocInfo, CCState &State) { | 
|  | static const unsigned HiRegList[] = { ARM::R0, ARM::R2 }; | 
|  | static const unsigned LoRegList[] = { ARM::R1, ARM::R3 }; | 
|  |  | 
|  | unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2); | 
|  | if (Reg == 0) | 
|  | return false; // we didn't handle it | 
|  |  | 
|  | unsigned i; | 
|  | for (i = 0; i < 2; ++i) | 
|  | if (HiRegList[i] == Reg) | 
|  | break; | 
|  |  | 
|  | State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); | 
|  | State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], | 
|  | LocVT, LocInfo)); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, | 
|  | CCValAssign::LocInfo &LocInfo, | 
|  | ISD::ArgFlagsTy &ArgFlags, | 
|  | CCState &State) { | 
|  | if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) | 
|  | return false; | 
|  | if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) | 
|  | return false; | 
|  | return true;  // we handled it | 
|  | } | 
|  |  | 
|  | static bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, | 
|  | CCValAssign::LocInfo &LocInfo, | 
|  | ISD::ArgFlagsTy &ArgFlags, | 
|  | CCState &State) { | 
|  | return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, | 
|  | State); | 
|  | } | 
|  |  | 
|  | } // End llvm namespace | 
|  |  | 
|  | #endif |