1235633Sdim//=== ARMCallingConv.h - ARM Custom Calling Convention Routines -*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file contains the custom routines for the ARM Calling Convention that 11218885Sdim// aren't done by tablegen. 12218885Sdim// 13218885Sdim//===----------------------------------------------------------------------===// 14218885Sdim 15218885Sdim#ifndef ARMCALLINGCONV_H 16218885Sdim#define ARMCALLINGCONV_H 17218885Sdim 18235633Sdim#include "ARM.h" 19235633Sdim#include "ARMBaseInstrInfo.h" 20235633Sdim#include "ARMSubtarget.h" 21218885Sdim#include "llvm/CodeGen/CallingConvLower.h" 22252723Sdim#include "llvm/IR/CallingConv.h" 23218885Sdim#include "llvm/Target/TargetInstrInfo.h" 24218885Sdim 25218885Sdimnamespace llvm { 26218885Sdim 27218885Sdim// APCS f64 is in register pairs, possibly split to stack 28218885Sdimstatic bool f64AssignAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 29218885Sdim CCValAssign::LocInfo &LocInfo, 30218885Sdim CCState &State, bool CanFail) { 31235633Sdim static const uint16_t RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; 32218885Sdim 33218885Sdim // Try to get the first register. 34218885Sdim if (unsigned Reg = State.AllocateReg(RegList, 4)) 35218885Sdim State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 36218885Sdim else { 37218885Sdim // For the 2nd half of a v2f64, do not fail. 38218885Sdim if (CanFail) 39218885Sdim return false; 40218885Sdim 41218885Sdim // Put the whole thing on the stack. 42218885Sdim State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 43218885Sdim State.AllocateStack(8, 4), 44218885Sdim LocVT, LocInfo)); 45218885Sdim return true; 46218885Sdim } 47218885Sdim 48218885Sdim // Try to get the second register. 49218885Sdim if (unsigned Reg = State.AllocateReg(RegList, 4)) 50218885Sdim State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 51218885Sdim else 52218885Sdim State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 53218885Sdim State.AllocateStack(4, 4), 54218885Sdim LocVT, LocInfo)); 55218885Sdim return true; 56218885Sdim} 57218885Sdim 58218885Sdimstatic bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 59218885Sdim CCValAssign::LocInfo &LocInfo, 60218885Sdim ISD::ArgFlagsTy &ArgFlags, 61218885Sdim CCState &State) { 62218885Sdim if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) 63218885Sdim return false; 64218885Sdim if (LocVT == MVT::v2f64 && 65218885Sdim !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) 66218885Sdim return false; 67218885Sdim return true; // we handled it 68218885Sdim} 69218885Sdim 70218885Sdim// AAPCS f64 is in aligned register pairs 71218885Sdimstatic bool f64AssignAAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 72218885Sdim CCValAssign::LocInfo &LocInfo, 73218885Sdim CCState &State, bool CanFail) { 74235633Sdim static const uint16_t HiRegList[] = { ARM::R0, ARM::R2 }; 75235633Sdim static const uint16_t LoRegList[] = { ARM::R1, ARM::R3 }; 76235633Sdim static const uint16_t ShadowRegList[] = { ARM::R0, ARM::R1 }; 77252723Sdim static const uint16_t GPRArgRegs[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; 78218885Sdim 79218885Sdim unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2); 80218885Sdim if (Reg == 0) { 81252723Sdim 82252723Sdim // If we had R3 unallocated only, now we still must to waste it. 83252723Sdim Reg = State.AllocateReg(GPRArgRegs, 4); 84252723Sdim assert((!Reg || Reg == ARM::R3) && "Wrong GPRs usage for f64"); 85252723Sdim 86218885Sdim // For the 2nd half of a v2f64, do not just fail. 87218885Sdim if (CanFail) 88218885Sdim return false; 89218885Sdim 90218885Sdim // Put the whole thing on the stack. 91218885Sdim State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 92218885Sdim State.AllocateStack(8, 8), 93218885Sdim LocVT, LocInfo)); 94218885Sdim return true; 95218885Sdim } 96218885Sdim 97218885Sdim unsigned i; 98218885Sdim for (i = 0; i < 2; ++i) 99218885Sdim if (HiRegList[i] == Reg) 100218885Sdim break; 101218885Sdim 102218885Sdim unsigned T = State.AllocateReg(LoRegList[i]); 103218885Sdim (void)T; 104218885Sdim assert(T == LoRegList[i] && "Could not allocate register"); 105218885Sdim 106218885Sdim State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 107218885Sdim State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], 108218885Sdim LocVT, LocInfo)); 109218885Sdim return true; 110218885Sdim} 111218885Sdim 112218885Sdimstatic bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 113218885Sdim CCValAssign::LocInfo &LocInfo, 114218885Sdim ISD::ArgFlagsTy &ArgFlags, 115218885Sdim CCState &State) { 116218885Sdim if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) 117218885Sdim return false; 118218885Sdim if (LocVT == MVT::v2f64 && 119218885Sdim !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) 120218885Sdim return false; 121218885Sdim return true; // we handled it 122218885Sdim} 123218885Sdim 124218885Sdimstatic bool f64RetAssign(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 125218885Sdim CCValAssign::LocInfo &LocInfo, CCState &State) { 126235633Sdim static const uint16_t HiRegList[] = { ARM::R0, ARM::R2 }; 127235633Sdim static const uint16_t LoRegList[] = { ARM::R1, ARM::R3 }; 128218885Sdim 129218885Sdim unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2); 130218885Sdim if (Reg == 0) 131218885Sdim return false; // we didn't handle it 132218885Sdim 133218885Sdim unsigned i; 134218885Sdim for (i = 0; i < 2; ++i) 135218885Sdim if (HiRegList[i] == Reg) 136218885Sdim break; 137218885Sdim 138218885Sdim State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 139218885Sdim State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], 140218885Sdim LocVT, LocInfo)); 141218885Sdim return true; 142218885Sdim} 143218885Sdim 144218885Sdimstatic bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 145218885Sdim CCValAssign::LocInfo &LocInfo, 146218885Sdim ISD::ArgFlagsTy &ArgFlags, 147218885Sdim CCState &State) { 148218885Sdim if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) 149218885Sdim return false; 150218885Sdim if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) 151218885Sdim return false; 152218885Sdim return true; // we handled it 153218885Sdim} 154218885Sdim 155218885Sdimstatic bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 156218885Sdim CCValAssign::LocInfo &LocInfo, 157218885Sdim ISD::ArgFlagsTy &ArgFlags, 158218885Sdim CCState &State) { 159218885Sdim return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, 160218885Sdim State); 161218885Sdim} 162218885Sdim 163218885Sdim} // End llvm namespace 164218885Sdim 165218885Sdim#endif 166