AArch64LegalizerInfo.cpp revision 327952
1//===- AArch64LegalizerInfo.cpp ----------------------------------*- 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/// \file 10/// This file implements the targeting of the Machinelegalizer class for 11/// AArch64. 12/// \todo This should be generated by TableGen. 13//===----------------------------------------------------------------------===// 14 15#include "AArch64LegalizerInfo.h" 16#include "AArch64Subtarget.h" 17#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 18#include "llvm/CodeGen/MachineInstr.h" 19#include "llvm/CodeGen/MachineRegisterInfo.h" 20#include "llvm/CodeGen/TargetOpcodes.h" 21#include "llvm/CodeGen/ValueTypes.h" 22#include "llvm/IR/DerivedTypes.h" 23#include "llvm/IR/Type.h" 24 25using namespace llvm; 26 27/// FIXME: The following static functions are SizeChangeStrategy functions 28/// that are meant to temporarily mimic the behaviour of the old legalization 29/// based on doubling/halving non-legal types as closely as possible. This is 30/// not entirly possible as only legalizing the types that are exactly a power 31/// of 2 times the size of the legal types would require specifying all those 32/// sizes explicitly. 33/// In practice, not specifying those isn't a problem, and the below functions 34/// should disappear quickly as we add support for legalizing non-power-of-2 35/// sized types further. 36static void 37addAndInterleaveWithUnsupported(LegalizerInfo::SizeAndActionsVec &result, 38 const LegalizerInfo::SizeAndActionsVec &v) { 39 for (unsigned i = 0; i < v.size(); ++i) { 40 result.push_back(v[i]); 41 if (i + 1 < v[i].first && i + 1 < v.size() && 42 v[i + 1].first != v[i].first + 1) 43 result.push_back({v[i].first + 1, LegalizerInfo::Unsupported}); 44 } 45} 46 47static LegalizerInfo::SizeAndActionsVec 48widen_1_narrow_128_ToLargest(const LegalizerInfo::SizeAndActionsVec &v) { 49 assert(v.size() >= 1); 50 assert(v[0].first > 2); 51 LegalizerInfo::SizeAndActionsVec result = {{1, LegalizerInfo::WidenScalar}, 52 {2, LegalizerInfo::Unsupported}}; 53 addAndInterleaveWithUnsupported(result, v); 54 auto Largest = result.back().first; 55 assert(Largest + 1 < 128); 56 result.push_back({Largest + 1, LegalizerInfo::Unsupported}); 57 result.push_back({128, LegalizerInfo::NarrowScalar}); 58 result.push_back({129, LegalizerInfo::Unsupported}); 59 return result; 60} 61 62static LegalizerInfo::SizeAndActionsVec 63widen_16(const LegalizerInfo::SizeAndActionsVec &v) { 64 assert(v.size() >= 1); 65 assert(v[0].first > 17); 66 LegalizerInfo::SizeAndActionsVec result = {{1, LegalizerInfo::Unsupported}, 67 {16, LegalizerInfo::WidenScalar}, 68 {17, LegalizerInfo::Unsupported}}; 69 addAndInterleaveWithUnsupported(result, v); 70 auto Largest = result.back().first; 71 result.push_back({Largest + 1, LegalizerInfo::Unsupported}); 72 return result; 73} 74 75static LegalizerInfo::SizeAndActionsVec 76widen_1_8(const LegalizerInfo::SizeAndActionsVec &v) { 77 assert(v.size() >= 1); 78 assert(v[0].first > 9); 79 LegalizerInfo::SizeAndActionsVec result = { 80 {1, LegalizerInfo::WidenScalar}, {2, LegalizerInfo::Unsupported}, 81 {8, LegalizerInfo::WidenScalar}, {9, LegalizerInfo::Unsupported}}; 82 addAndInterleaveWithUnsupported(result, v); 83 auto Largest = result.back().first; 84 result.push_back({Largest + 1, LegalizerInfo::Unsupported}); 85 return result; 86} 87 88static LegalizerInfo::SizeAndActionsVec 89widen_1_8_16(const LegalizerInfo::SizeAndActionsVec &v) { 90 assert(v.size() >= 1); 91 assert(v[0].first > 17); 92 LegalizerInfo::SizeAndActionsVec result = { 93 {1, LegalizerInfo::WidenScalar}, {2, LegalizerInfo::Unsupported}, 94 {8, LegalizerInfo::WidenScalar}, {9, LegalizerInfo::Unsupported}, 95 {16, LegalizerInfo::WidenScalar}, {17, LegalizerInfo::Unsupported}}; 96 addAndInterleaveWithUnsupported(result, v); 97 auto Largest = result.back().first; 98 result.push_back({Largest + 1, LegalizerInfo::Unsupported}); 99 return result; 100} 101 102static LegalizerInfo::SizeAndActionsVec 103widen_1_8_16_narrowToLargest(const LegalizerInfo::SizeAndActionsVec &v) { 104 assert(v.size() >= 1); 105 assert(v[0].first > 17); 106 LegalizerInfo::SizeAndActionsVec result = { 107 {1, LegalizerInfo::WidenScalar}, {2, LegalizerInfo::Unsupported}, 108 {8, LegalizerInfo::WidenScalar}, {9, LegalizerInfo::Unsupported}, 109 {16, LegalizerInfo::WidenScalar}, {17, LegalizerInfo::Unsupported}}; 110 addAndInterleaveWithUnsupported(result, v); 111 auto Largest = result.back().first; 112 result.push_back({Largest + 1, LegalizerInfo::NarrowScalar}); 113 return result; 114} 115 116static LegalizerInfo::SizeAndActionsVec 117widen_1_8_16_32(const LegalizerInfo::SizeAndActionsVec &v) { 118 assert(v.size() >= 1); 119 assert(v[0].first > 33); 120 LegalizerInfo::SizeAndActionsVec result = { 121 {1, LegalizerInfo::WidenScalar}, {2, LegalizerInfo::Unsupported}, 122 {8, LegalizerInfo::WidenScalar}, {9, LegalizerInfo::Unsupported}, 123 {16, LegalizerInfo::WidenScalar}, {17, LegalizerInfo::Unsupported}, 124 {32, LegalizerInfo::WidenScalar}, {33, LegalizerInfo::Unsupported}}; 125 addAndInterleaveWithUnsupported(result, v); 126 auto Largest = result.back().first; 127 result.push_back({Largest + 1, LegalizerInfo::Unsupported}); 128 return result; 129} 130 131AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST) { 132 using namespace TargetOpcode; 133 const LLT p0 = LLT::pointer(0, 64); 134 const LLT s1 = LLT::scalar(1); 135 const LLT s8 = LLT::scalar(8); 136 const LLT s16 = LLT::scalar(16); 137 const LLT s32 = LLT::scalar(32); 138 const LLT s64 = LLT::scalar(64); 139 const LLT s128 = LLT::scalar(128); 140 const LLT v2s32 = LLT::vector(2, 32); 141 const LLT v4s32 = LLT::vector(4, 32); 142 const LLT v2s64 = LLT::vector(2, 64); 143 144 for (auto Ty : {p0, s1, s8, s16, s32, s64}) 145 setAction({G_IMPLICIT_DEF, Ty}, Legal); 146 147 for (auto Ty : {s16, s32, s64, p0}) 148 setAction({G_PHI, Ty}, Legal); 149 150 setLegalizeScalarToDifferentSizeStrategy(G_PHI, 0, widen_1_8); 151 152 for (auto Ty : { s32, s64 }) 153 setAction({G_BSWAP, Ty}, Legal); 154 155 for (unsigned BinOp : {G_ADD, G_SUB, G_MUL, G_AND, G_OR, G_XOR, G_SHL}) { 156 // These operations naturally get the right answer when used on 157 // GPR32, even if the actual type is narrower. 158 for (auto Ty : {s32, s64, v2s32, v4s32, v2s64}) 159 setAction({BinOp, Ty}, Legal); 160 161 if (BinOp != G_ADD) 162 setLegalizeScalarToDifferentSizeStrategy(BinOp, 0, 163 widen_1_8_16_narrowToLargest); 164 } 165 166 setAction({G_GEP, p0}, Legal); 167 setAction({G_GEP, 1, s64}, Legal); 168 169 setLegalizeScalarToDifferentSizeStrategy(G_GEP, 1, widen_1_8_16_32); 170 171 setAction({G_PTR_MASK, p0}, Legal); 172 173 for (unsigned BinOp : {G_LSHR, G_ASHR, G_SDIV, G_UDIV}) { 174 for (auto Ty : {s32, s64}) 175 setAction({BinOp, Ty}, Legal); 176 177 setLegalizeScalarToDifferentSizeStrategy(BinOp, 0, widen_1_8_16); 178 } 179 180 for (unsigned BinOp : {G_SREM, G_UREM}) 181 for (auto Ty : { s1, s8, s16, s32, s64 }) 182 setAction({BinOp, Ty}, Lower); 183 184 for (unsigned Op : {G_SMULO, G_UMULO}) { 185 setAction({Op, 0, s64}, Lower); 186 setAction({Op, 1, s1}, Legal); 187 } 188 189 for (unsigned Op : {G_UADDE, G_USUBE, G_SADDO, G_SSUBO, G_SMULH, G_UMULH}) { 190 for (auto Ty : { s32, s64 }) 191 setAction({Op, Ty}, Legal); 192 193 setAction({Op, 1, s1}, Legal); 194 } 195 196 for (unsigned BinOp : {G_FADD, G_FSUB, G_FMA, G_FMUL, G_FDIV}) 197 for (auto Ty : {s32, s64}) 198 setAction({BinOp, Ty}, Legal); 199 200 for (unsigned BinOp : {G_FREM, G_FPOW}) { 201 setAction({BinOp, s32}, Libcall); 202 setAction({BinOp, s64}, Libcall); 203 } 204 205 for (auto Ty : {s32, s64, p0}) { 206 setAction({G_INSERT, Ty}, Legal); 207 setAction({G_INSERT, 1, Ty}, Legal); 208 } 209 setLegalizeScalarToDifferentSizeStrategy(G_INSERT, 0, 210 widen_1_8_16_narrowToLargest); 211 for (auto Ty : {s1, s8, s16}) { 212 setAction({G_INSERT, 1, Ty}, Legal); 213 // FIXME: Can't widen the sources because that violates the constraints on 214 // G_INSERT (It seems entirely reasonable that inputs shouldn't overlap). 215 } 216 217 for (auto Ty : {s1, s8, s16, s32, s64, p0}) 218 setAction({G_EXTRACT, Ty}, Legal); 219 220 for (auto Ty : {s32, s64}) 221 setAction({G_EXTRACT, 1, Ty}, Legal); 222 223 for (unsigned MemOp : {G_LOAD, G_STORE}) { 224 for (auto Ty : {s8, s16, s32, s64, p0, v2s32}) 225 setAction({MemOp, Ty}, Legal); 226 227 setLegalizeScalarToDifferentSizeStrategy(MemOp, 0, 228 widen_1_narrow_128_ToLargest); 229 230 // And everything's fine in addrspace 0. 231 setAction({MemOp, 1, p0}, Legal); 232 } 233 234 // Constants 235 for (auto Ty : {s32, s64}) { 236 setAction({TargetOpcode::G_CONSTANT, Ty}, Legal); 237 setAction({TargetOpcode::G_FCONSTANT, Ty}, Legal); 238 } 239 240 setAction({G_CONSTANT, p0}, Legal); 241 242 setLegalizeScalarToDifferentSizeStrategy(G_CONSTANT, 0, widen_1_8_16); 243 setLegalizeScalarToDifferentSizeStrategy(G_FCONSTANT, 0, widen_16); 244 245 setAction({G_ICMP, 1, s32}, Legal); 246 setAction({G_ICMP, 1, s64}, Legal); 247 setAction({G_ICMP, 1, p0}, Legal); 248 249 setLegalizeScalarToDifferentSizeStrategy(G_ICMP, 0, widen_1_8_16); 250 setLegalizeScalarToDifferentSizeStrategy(G_FCMP, 0, widen_1_8_16); 251 setLegalizeScalarToDifferentSizeStrategy(G_ICMP, 1, widen_1_8_16); 252 253 setAction({G_ICMP, s32}, Legal); 254 setAction({G_FCMP, s32}, Legal); 255 setAction({G_FCMP, 1, s32}, Legal); 256 setAction({G_FCMP, 1, s64}, Legal); 257 258 // Extensions 259 for (auto Ty : { s1, s8, s16, s32, s64 }) { 260 setAction({G_ZEXT, Ty}, Legal); 261 setAction({G_SEXT, Ty}, Legal); 262 setAction({G_ANYEXT, Ty}, Legal); 263 } 264 265 // FP conversions 266 for (auto Ty : { s16, s32 }) { 267 setAction({G_FPTRUNC, Ty}, Legal); 268 setAction({G_FPEXT, 1, Ty}, Legal); 269 } 270 271 for (auto Ty : { s32, s64 }) { 272 setAction({G_FPTRUNC, 1, Ty}, Legal); 273 setAction({G_FPEXT, Ty}, Legal); 274 } 275 276 // Conversions 277 for (auto Ty : { s32, s64 }) { 278 setAction({G_FPTOSI, 0, Ty}, Legal); 279 setAction({G_FPTOUI, 0, Ty}, Legal); 280 setAction({G_SITOFP, 1, Ty}, Legal); 281 setAction({G_UITOFP, 1, Ty}, Legal); 282 } 283 setLegalizeScalarToDifferentSizeStrategy(G_FPTOSI, 0, widen_1_8_16); 284 setLegalizeScalarToDifferentSizeStrategy(G_FPTOUI, 0, widen_1_8_16); 285 setLegalizeScalarToDifferentSizeStrategy(G_SITOFP, 1, widen_1_8_16); 286 setLegalizeScalarToDifferentSizeStrategy(G_UITOFP, 1, widen_1_8_16); 287 288 for (auto Ty : { s32, s64 }) { 289 setAction({G_FPTOSI, 1, Ty}, Legal); 290 setAction({G_FPTOUI, 1, Ty}, Legal); 291 setAction({G_SITOFP, 0, Ty}, Legal); 292 setAction({G_UITOFP, 0, Ty}, Legal); 293 } 294 295 // Control-flow 296 for (auto Ty : {s1, s8, s16, s32}) 297 setAction({G_BRCOND, Ty}, Legal); 298 setAction({G_BRINDIRECT, p0}, Legal); 299 300 // Select 301 setLegalizeScalarToDifferentSizeStrategy(G_SELECT, 0, widen_1_8_16); 302 303 for (auto Ty : {s32, s64, p0}) 304 setAction({G_SELECT, Ty}, Legal); 305 306 setAction({G_SELECT, 1, s1}, Legal); 307 308 // Pointer-handling 309 setAction({G_FRAME_INDEX, p0}, Legal); 310 setAction({G_GLOBAL_VALUE, p0}, Legal); 311 312 for (auto Ty : {s1, s8, s16, s32, s64}) 313 setAction({G_PTRTOINT, 0, Ty}, Legal); 314 315 setAction({G_PTRTOINT, 1, p0}, Legal); 316 317 setAction({G_INTTOPTR, 0, p0}, Legal); 318 setAction({G_INTTOPTR, 1, s64}, Legal); 319 320 // Casts for 32 and 64-bit width type are just copies. 321 // Same for 128-bit width type, except they are on the FPR bank. 322 for (auto Ty : {s1, s8, s16, s32, s64, s128}) { 323 setAction({G_BITCAST, 0, Ty}, Legal); 324 setAction({G_BITCAST, 1, Ty}, Legal); 325 } 326 327 // For the sake of copying bits around, the type does not really 328 // matter as long as it fits a register. 329 for (int EltSize = 8; EltSize <= 64; EltSize *= 2) { 330 setAction({G_BITCAST, 0, LLT::vector(128/EltSize, EltSize)}, Legal); 331 setAction({G_BITCAST, 1, LLT::vector(128/EltSize, EltSize)}, Legal); 332 if (EltSize >= 64) 333 continue; 334 335 setAction({G_BITCAST, 0, LLT::vector(64/EltSize, EltSize)}, Legal); 336 setAction({G_BITCAST, 1, LLT::vector(64/EltSize, EltSize)}, Legal); 337 if (EltSize >= 32) 338 continue; 339 340 setAction({G_BITCAST, 0, LLT::vector(32/EltSize, EltSize)}, Legal); 341 setAction({G_BITCAST, 1, LLT::vector(32/EltSize, EltSize)}, Legal); 342 } 343 344 setAction({G_VASTART, p0}, Legal); 345 346 // va_list must be a pointer, but most sized types are pretty easy to handle 347 // as the destination. 348 setAction({G_VAARG, 1, p0}, Legal); 349 350 for (auto Ty : {s8, s16, s32, s64, p0}) 351 setAction({G_VAARG, Ty}, Custom); 352 353 if (ST.hasLSE()) { 354 for (auto Ty : {s8, s16, s32, s64}) { 355 setAction({G_ATOMIC_CMPXCHG_WITH_SUCCESS, Ty}, Lower); 356 setAction({G_ATOMIC_CMPXCHG, Ty}, Legal); 357 } 358 setAction({G_ATOMIC_CMPXCHG, 1, p0}, Legal); 359 360 for (unsigned Op : 361 {G_ATOMICRMW_XCHG, G_ATOMICRMW_ADD, G_ATOMICRMW_SUB, G_ATOMICRMW_AND, 362 G_ATOMICRMW_OR, G_ATOMICRMW_XOR, G_ATOMICRMW_MIN, G_ATOMICRMW_MAX, 363 G_ATOMICRMW_UMIN, G_ATOMICRMW_UMAX}) { 364 for (auto Ty : {s8, s16, s32, s64}) { 365 setAction({Op, Ty}, Legal); 366 } 367 setAction({Op, 1, p0}, Legal); 368 } 369 } 370 371 // Merge/Unmerge 372 for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) 373 for (int Sz : {8, 16, 32, 64, 128, 192, 256, 384, 512}) { 374 LLT ScalarTy = LLT::scalar(Sz); 375 setAction({Op, ScalarTy}, Legal); 376 setAction({Op, 1, ScalarTy}, Legal); 377 if (Sz < 32) 378 continue; 379 for (int EltSize = 8; EltSize <= 64; EltSize *= 2) { 380 if (EltSize >= Sz) 381 continue; 382 LLT VecTy = LLT::vector(Sz / EltSize, EltSize); 383 setAction({Op, VecTy}, Legal); 384 setAction({Op, 1, VecTy}, Legal); 385 } 386 } 387 388 computeTables(); 389} 390 391bool AArch64LegalizerInfo::legalizeCustom(MachineInstr &MI, 392 MachineRegisterInfo &MRI, 393 MachineIRBuilder &MIRBuilder) const { 394 switch (MI.getOpcode()) { 395 default: 396 // No idea what to do. 397 return false; 398 case TargetOpcode::G_VAARG: 399 return legalizeVaArg(MI, MRI, MIRBuilder); 400 } 401 402 llvm_unreachable("expected switch to return"); 403} 404 405bool AArch64LegalizerInfo::legalizeVaArg(MachineInstr &MI, 406 MachineRegisterInfo &MRI, 407 MachineIRBuilder &MIRBuilder) const { 408 MIRBuilder.setInstr(MI); 409 MachineFunction &MF = MIRBuilder.getMF(); 410 unsigned Align = MI.getOperand(2).getImm(); 411 unsigned Dst = MI.getOperand(0).getReg(); 412 unsigned ListPtr = MI.getOperand(1).getReg(); 413 414 LLT PtrTy = MRI.getType(ListPtr); 415 LLT IntPtrTy = LLT::scalar(PtrTy.getSizeInBits()); 416 417 const unsigned PtrSize = PtrTy.getSizeInBits() / 8; 418 unsigned List = MRI.createGenericVirtualRegister(PtrTy); 419 MIRBuilder.buildLoad( 420 List, ListPtr, 421 *MF.getMachineMemOperand(MachinePointerInfo(), MachineMemOperand::MOLoad, 422 PtrSize, /* Align = */ PtrSize)); 423 424 unsigned DstPtr; 425 if (Align > PtrSize) { 426 // Realign the list to the actual required alignment. 427 auto AlignMinus1 = MIRBuilder.buildConstant(IntPtrTy, Align - 1); 428 429 unsigned ListTmp = MRI.createGenericVirtualRegister(PtrTy); 430 MIRBuilder.buildGEP(ListTmp, List, AlignMinus1->getOperand(0).getReg()); 431 432 DstPtr = MRI.createGenericVirtualRegister(PtrTy); 433 MIRBuilder.buildPtrMask(DstPtr, ListTmp, Log2_64(Align)); 434 } else 435 DstPtr = List; 436 437 uint64_t ValSize = MRI.getType(Dst).getSizeInBits() / 8; 438 MIRBuilder.buildLoad( 439 Dst, DstPtr, 440 *MF.getMachineMemOperand(MachinePointerInfo(), MachineMemOperand::MOLoad, 441 ValSize, std::max(Align, PtrSize))); 442 443 unsigned SizeReg = MRI.createGenericVirtualRegister(IntPtrTy); 444 MIRBuilder.buildConstant(SizeReg, alignTo(ValSize, PtrSize)); 445 446 unsigned NewList = MRI.createGenericVirtualRegister(PtrTy); 447 MIRBuilder.buildGEP(NewList, DstPtr, SizeReg); 448 449 MIRBuilder.buildStore( 450 NewList, ListPtr, 451 *MF.getMachineMemOperand(MachinePointerInfo(), MachineMemOperand::MOStore, 452 PtrSize, /* Align = */ PtrSize)); 453 454 MI.eraseFromParent(); 455 return true; 456} 457