1 //=== ARMCallingConv.h - ARM Custom Calling Convention Routines -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file contains the custom routines for the ARM Calling Convention that 11 // aren't done by tablegen. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef ARMCALLINGCONV_H 16 #define ARMCALLINGCONV_H 17 18 #include "ARM.h" 19 #include "ARMBaseInstrInfo.h" 20 #include "ARMSubtarget.h" 21 #include "llvm/CodeGen/CallingConvLower.h" 22 #include "llvm/IR/CallingConv.h" 23 #include "llvm/Target/TargetInstrInfo.h" 24 25 namespace llvm { 26 27 // APCS f64 is in register pairs, possibly split to stack 28 static bool f64AssignAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 29 CCValAssign::LocInfo &LocInfo, 30 CCState &State, bool CanFail) { 31 static const MCPhysReg RegList[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; 32 33 // Try to get the first register. 34 if (unsigned Reg = State.AllocateReg(RegList, 4)) 35 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 36 else { 37 // For the 2nd half of a v2f64, do not fail. 38 if (CanFail) 39 return false; 40 41 // Put the whole thing on the stack. 42 State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 43 State.AllocateStack(8, 4), 44 LocVT, LocInfo)); 45 return true; 46 } 47 48 // Try to get the second register. 49 if (unsigned Reg = State.AllocateReg(RegList, 4)) 50 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 51 else 52 State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 53 State.AllocateStack(4, 4), 54 LocVT, LocInfo)); 55 return true; 56 } 57 58 static bool CC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 59 CCValAssign::LocInfo &LocInfo, 60 ISD::ArgFlagsTy &ArgFlags, 61 CCState &State) { 62 if (!f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) 63 return false; 64 if (LocVT == MVT::v2f64 && 65 !f64AssignAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) 66 return false; 67 return true; // we handled it 68 } 69 70 // AAPCS f64 is in aligned register pairs 71 static bool f64AssignAAPCS(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 72 CCValAssign::LocInfo &LocInfo, 73 CCState &State, bool CanFail) { 74 static const MCPhysReg HiRegList[] = { ARM::R0, ARM::R2 }; 75 static const MCPhysReg LoRegList[] = { ARM::R1, ARM::R3 }; 76 static const MCPhysReg ShadowRegList[] = { ARM::R0, ARM::R1 }; 77 static const MCPhysReg GPRArgRegs[] = { ARM::R0, ARM::R1, ARM::R2, ARM::R3 }; 78 79 unsigned Reg = State.AllocateReg(HiRegList, ShadowRegList, 2); 80 if (Reg == 0) { 81 82 // If we had R3 unallocated only, now we still must to waste it. 83 Reg = State.AllocateReg(GPRArgRegs, 4); 84 assert((!Reg || Reg == ARM::R3) && "Wrong GPRs usage for f64"); 85 86 // For the 2nd half of a v2f64, do not just fail. 87 if (CanFail) 88 return false; 89 90 // Put the whole thing on the stack. 91 State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT, 92 State.AllocateStack(8, 8), 93 LocVT, LocInfo)); 94 return true; 95 } 96 97 unsigned i; 98 for (i = 0; i < 2; ++i) 99 if (HiRegList[i] == Reg) 100 break; 101 102 unsigned T = State.AllocateReg(LoRegList[i]); 103 (void)T; 104 assert(T == LoRegList[i] && "Could not allocate register"); 105 106 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 107 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], 108 LocVT, LocInfo)); 109 return true; 110 } 111 112 static bool CC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 113 CCValAssign::LocInfo &LocInfo, 114 ISD::ArgFlagsTy &ArgFlags, 115 CCState &State) { 116 if (!f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, true)) 117 return false; 118 if (LocVT == MVT::v2f64 && 119 !f64AssignAAPCS(ValNo, ValVT, LocVT, LocInfo, State, false)) 120 return false; 121 return true; // we handled it 122 } 123 124 static bool f64RetAssign(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 125 CCValAssign::LocInfo &LocInfo, CCState &State) { 126 static const MCPhysReg HiRegList[] = { ARM::R0, ARM::R2 }; 127 static const MCPhysReg LoRegList[] = { ARM::R1, ARM::R3 }; 128 129 unsigned Reg = State.AllocateReg(HiRegList, LoRegList, 2); 130 if (Reg == 0) 131 return false; // we didn't handle it 132 133 unsigned i; 134 for (i = 0; i < 2; ++i) 135 if (HiRegList[i] == Reg) 136 break; 137 138 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo)); 139 State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, LoRegList[i], 140 LocVT, LocInfo)); 141 return true; 142 } 143 144 static bool RetCC_ARM_APCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 145 CCValAssign::LocInfo &LocInfo, 146 ISD::ArgFlagsTy &ArgFlags, 147 CCState &State) { 148 if (!f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) 149 return false; 150 if (LocVT == MVT::v2f64 && !f64RetAssign(ValNo, ValVT, LocVT, LocInfo, State)) 151 return false; 152 return true; // we handled it 153 } 154 155 static bool RetCC_ARM_AAPCS_Custom_f64(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 156 CCValAssign::LocInfo &LocInfo, 157 ISD::ArgFlagsTy &ArgFlags, 158 CCState &State) { 159 return RetCC_ARM_APCS_Custom_f64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, 160 State); 161 } 162 163 static const uint16_t SRegList[] = { ARM::S0, ARM::S1, ARM::S2, ARM::S3, 164 ARM::S4, ARM::S5, ARM::S6, ARM::S7, 165 ARM::S8, ARM::S9, ARM::S10, ARM::S11, 166 ARM::S12, ARM::S13, ARM::S14, ARM::S15 }; 167 static const uint16_t DRegList[] = { ARM::D0, ARM::D1, ARM::D2, ARM::D3, 168 ARM::D4, ARM::D5, ARM::D6, ARM::D7 }; 169 static const uint16_t QRegList[] = { ARM::Q0, ARM::Q1, ARM::Q2, ARM::Q3 }; 170 171 // Allocate part of an AAPCS HFA or HVA. We assume that each member of the HA 172 // has InConsecutiveRegs set, and that the last member also has 173 // InConsecutiveRegsLast set. We must process all members of the HA before 174 // we can allocate it, as we need to know the total number of registers that 175 // will be needed in order to (attempt to) allocate a contiguous block. 176 static bool CC_ARM_AAPCS_Custom_HA(unsigned &ValNo, MVT &ValVT, MVT &LocVT, 177 CCValAssign::LocInfo &LocInfo, 178 ISD::ArgFlagsTy &ArgFlags, CCState &State) { 179 SmallVectorImpl<CCValAssign> &PendingHAMembers = State.getPendingLocs(); 180 // AAPCS HFAs must have 1-4 elements, all of the same type 181 assert(PendingHAMembers.size() < 8); 182 if (PendingHAMembers.size() > 0) 183 assert(PendingHAMembers[0].getLocVT() == LocVT); 184 185 // Add the argument to the list to be allocated once we know the size of the 186 // HA 187 PendingHAMembers.push_back( 188 CCValAssign::getPending(ValNo, ValVT, LocVT, LocInfo)); 189 190 if (ArgFlags.isInConsecutiveRegsLast()) { 191 assert(PendingHAMembers.size() > 0 && PendingHAMembers.size() <= 8 && 192 "Homogeneous aggregates must have between 1 and 4 members"); 193 194 // Try to allocate a contiguous block of registers, each of the correct 195 // size to hold one member. 196 const uint16_t *RegList; 197 unsigned NumRegs; 198 switch (LocVT.SimpleTy) { 199 case MVT::i32: 200 case MVT::f32: 201 RegList = SRegList; 202 NumRegs = 16; 203 break; 204 case MVT::f64: 205 RegList = DRegList; 206 NumRegs = 8; 207 break; 208 case MVT::v2f64: 209 RegList = QRegList; 210 NumRegs = 4; 211 break; 212 default: 213 llvm_unreachable("Unexpected member type for HA"); 214 break; 215 } 216 217 unsigned RegResult = 218 State.AllocateRegBlock(RegList, NumRegs, PendingHAMembers.size()); 219 220 if (RegResult) { 221 for (SmallVectorImpl<CCValAssign>::iterator It = PendingHAMembers.begin(); 222 It != PendingHAMembers.end(); ++It) { 223 It->convertToReg(RegResult); 224 State.addLoc(*It); 225 ++RegResult; 226 } 227 PendingHAMembers.clear(); 228 return true; 229 } 230 231 // Register allocation failed, fall back to the stack 232 233 // Mark all VFP regs as unavailable (AAPCS rule C.2.vfp) 234 for (unsigned regNo = 0; regNo < 16; ++regNo) 235 State.AllocateReg(SRegList[regNo]); 236 237 unsigned Size = LocVT.getSizeInBits() / 8; 238 unsigned Align = Size; 239 240 if (LocVT.SimpleTy == MVT::v2f64 || LocVT.SimpleTy == MVT::i32) { 241 // Vectors are always aligned to 8 bytes. If we've seen an i32 here 242 // it's because it's been split from a larger type, also with align 8. 243 Align = 8; 244 } 245 246 for (auto It : PendingHAMembers) { 247 It.convertToMem(State.AllocateStack(Size, Align)); 248 State.addLoc(It); 249 250 // Only the first member needs to be aligned. 251 Align = 1; 252 } 253 254 // All pending members have now been allocated 255 PendingHAMembers.clear(); 256 } 257 258 // This will be allocated by the last member of the HA 259 return true; 260 } 261 262 } // End llvm namespace 263 264 #endif 265