1 //===----- AArch64InstrInfo.td - AArch64 Instruction Info ----*- tablegen -*-=// 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 describes the AArch64 scalar instructions in TableGen format. 11 // 12 //===----------------------------------------------------------------------===// 13 14 //===----------------------------------------------------------------------===// 15 // ARM Instruction Predicate Definitions. 16 // 17 def HasNEON : Predicate<"Subtarget->hasNEON()">, 18 AssemblerPredicate<"FeatureNEON", "neon">; 19 def HasCrypto : Predicate<"Subtarget->hasCrypto()">, 20 AssemblerPredicate<"FeatureCrypto","crypto">; 21 22 // Use fused MAC if more precision in FP computation is allowed. 23 def UseFusedMAC : Predicate<"(TM.Options.AllowFPOpFusion ==" 24 " FPOpFusion::Fast)">; 25 include "AArch64InstrFormats.td" 26 27 //===----------------------------------------------------------------------===// 28 // Target-specific ISD nodes and profiles 29 //===----------------------------------------------------------------------===// 30 31 def SDT_A64ret : SDTypeProfile<0, 0, []>; 32 def A64ret : SDNode<"AArch64ISD::Ret", SDT_A64ret, [SDNPHasChain, 33 SDNPOptInGlue, 34 SDNPVariadic]>; 35 36 // (ins NZCV, Condition, Dest) 37 def SDT_A64br_cc : SDTypeProfile<0, 3, [SDTCisVT<0, i32>]>; 38 def A64br_cc : SDNode<"AArch64ISD::BR_CC", SDT_A64br_cc, [SDNPHasChain]>; 39 40 // (outs Result), (ins NZCV, IfTrue, IfFalse, Condition) 41 def SDT_A64select_cc : SDTypeProfile<1, 4, [SDTCisVT<1, i32>, 42 SDTCisSameAs<0, 2>, 43 SDTCisSameAs<2, 3>]>; 44 def A64select_cc : SDNode<"AArch64ISD::SELECT_CC", SDT_A64select_cc>; 45 46 // (outs NZCV), (ins LHS, RHS, Condition) 47 def SDT_A64setcc : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, 48 SDTCisSameAs<1, 2>]>; 49 def A64setcc : SDNode<"AArch64ISD::SETCC", SDT_A64setcc>; 50 51 52 // (outs GPR64), (ins) 53 def A64threadpointer : SDNode<"AArch64ISD::THREAD_POINTER", SDTPtrLeaf>; 54 55 // A64 compares don't care about the cond really (they set all flags) so a 56 // simple binary operator is useful. 57 def A64cmp : PatFrag<(ops node:$lhs, node:$rhs), 58 (A64setcc node:$lhs, node:$rhs, cond)>; 59 60 61 // When matching a notional (CMP op1, (sub 0, op2)), we'd like to use a CMN 62 // instruction on the grounds that "op1 - (-op2) == op1 + op2". However, the C 63 // and V flags can be set differently by this operation. It comes down to 64 // whether "SInt(~op2)+1 == SInt(~op2+1)" (and the same for UInt). If they are 65 // then everything is fine. If not then the optimization is wrong. Thus general 66 // comparisons are only valid if op2 != 0. 67 68 // So, finally, the only LLVM-native comparisons that don't mention C and V are 69 // SETEQ and SETNE. They're the only ones we can safely use CMN for in the 70 // absence of information about op2. 71 def equality_cond : PatLeaf<(cond), [{ 72 return N->get() == ISD::SETEQ || N->get() == ISD::SETNE; 73 }]>; 74 75 def A64cmn : PatFrag<(ops node:$lhs, node:$rhs), 76 (A64setcc node:$lhs, (sub 0, node:$rhs), equality_cond)>; 77 78 // There are two layers of indirection here, driven by the following 79 // considerations. 80 // + TableGen does not know CodeModel or Reloc so that decision should be 81 // made for a variable/address at ISelLowering. 82 // + The output of ISelLowering should be selectable (hence the Wrapper, 83 // rather than a bare target opcode) 84 def SDTAArch64WrapperLarge : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, 85 SDTCisSameAs<0, 2>, 86 SDTCisSameAs<0, 3>, 87 SDTCisSameAs<0, 4>, 88 SDTCisPtrTy<0>]>; 89 90 def A64WrapperLarge :SDNode<"AArch64ISD::WrapperLarge", SDTAArch64WrapperLarge>; 91 92 def SDTAArch64WrapperSmall : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, 93 SDTCisSameAs<1, 2>, 94 SDTCisVT<3, i32>, 95 SDTCisPtrTy<0>]>; 96 97 def A64WrapperSmall :SDNode<"AArch64ISD::WrapperSmall", SDTAArch64WrapperSmall>; 98 99 100 def SDTAArch64GOTLoad : SDTypeProfile<1, 1, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; 101 def A64GOTLoad : SDNode<"AArch64ISD::GOTLoad", SDTAArch64GOTLoad, 102 [SDNPHasChain]>; 103 104 105 // (A64BFI LHS, RHS, LSB, Width) 106 def SDTA64BFI : SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, 107 SDTCisSameAs<1, 2>, 108 SDTCisVT<3, i64>, 109 SDTCisVT<4, i64>]>; 110 111 def A64Bfi : SDNode<"AArch64ISD::BFI", SDTA64BFI>; 112 113 // (A64EXTR HiReg, LoReg, LSB) 114 def SDTA64EXTR : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, 115 SDTCisVT<3, i64>]>; 116 def A64Extr : SDNode<"AArch64ISD::EXTR", SDTA64EXTR>; 117 118 // (A64[SU]BFX Field, ImmR, ImmS). 119 // 120 // Note that ImmR and ImmS are already encoded for the actual instructions. The 121 // more natural LSB and Width mix together to form ImmR and ImmS, something 122 // which TableGen can't handle. 123 def SDTA64BFX : SDTypeProfile<1, 3, [SDTCisVT<2, i64>, SDTCisVT<3, i64>]>; 124 def A64Sbfx : SDNode<"AArch64ISD::SBFX", SDTA64BFX>; 125 126 def A64Ubfx : SDNode<"AArch64ISD::UBFX", SDTA64BFX>; 127 128 //===----------------------------------------------------------------------===// 129 // Call sequence pseudo-instructions 130 //===----------------------------------------------------------------------===// 131 132 133 def SDT_AArch64Call : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; 134 def AArch64Call : SDNode<"AArch64ISD::Call", SDT_AArch64Call, 135 [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; 136 137 def AArch64tcret : SDNode<"AArch64ISD::TC_RETURN", SDT_AArch64Call, 138 [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; 139 140 // The TLSDESCCALL node is a variant call which goes to an indirectly calculated 141 // destination but needs a relocation against a fixed symbol. As such it has two 142 // certain operands: the callee and the relocated variable. 143 // 144 // The TLS ABI only allows it to be selected to a BLR instructin (with 145 // appropriate relocation). 146 def SDTTLSDescCall : SDTypeProfile<0, -2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; 147 148 def A64tlsdesc_blr : SDNode<"AArch64ISD::TLSDESCCALL", SDTTLSDescCall, 149 [SDNPInGlue, SDNPOutGlue, SDNPHasChain, 150 SDNPVariadic]>; 151 152 153 def SDT_AArch64CallSeqStart : SDCallSeqStart<[ SDTCisPtrTy<0> ]>; 154 def AArch64callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_AArch64CallSeqStart, 155 [SDNPHasChain, SDNPOutGlue]>; 156 157 def SDT_AArch64CallSeqEnd : SDCallSeqEnd<[ SDTCisPtrTy<0>, SDTCisPtrTy<1> ]>; 158 def AArch64callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_AArch64CallSeqEnd, 159 [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; 160 161 162 163 // These pseudo-instructions have special semantics by virtue of being passed to 164 // the InstrInfo constructor. CALLSEQ_START/CALLSEQ_END are produced by 165 // LowerCall to (in our case) tell the back-end about stack adjustments for 166 // arguments passed on the stack. Here we select those markers to 167 // pseudo-instructions which explicitly set the stack, and finally in the 168 // RegisterInfo we convert them to a true stack adjustment. 169 let Defs = [XSP], Uses = [XSP] in { 170 def ADJCALLSTACKDOWN : PseudoInst<(outs), (ins i64imm:$amt), 171 [(AArch64callseq_start timm:$amt)]>; 172 173 def ADJCALLSTACKUP : PseudoInst<(outs), (ins i64imm:$amt1, i64imm:$amt2), 174 [(AArch64callseq_end timm:$amt1, timm:$amt2)]>; 175 } 176 177 //===----------------------------------------------------------------------===// 178 // Atomic operation pseudo-instructions 179 //===----------------------------------------------------------------------===// 180 181 // These get selected from C++ code as a pretty much direct translation from the 182 // generic DAG nodes. The one exception is the AtomicOrdering is added as an 183 // operand so that the eventual lowering can make use of it and choose 184 // acquire/release operations when required. 185 186 let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1 in { 187 multiclass AtomicSizes { 188 def _I8 : PseudoInst<(outs GPR32:$dst), 189 (ins GPR64xsp:$ptr, GPR32:$incr, i32imm:$ordering), []>; 190 def _I16 : PseudoInst<(outs GPR32:$dst), 191 (ins GPR64xsp:$ptr, GPR32:$incr, i32imm:$ordering), []>; 192 def _I32 : PseudoInst<(outs GPR32:$dst), 193 (ins GPR64xsp:$ptr, GPR32:$incr, i32imm:$ordering), []>; 194 def _I64 : PseudoInst<(outs GPR64:$dst), 195 (ins GPR64xsp:$ptr, GPR64:$incr, i32imm:$ordering), []>; 196 } 197 } 198 199 defm ATOMIC_LOAD_ADD : AtomicSizes; 200 defm ATOMIC_LOAD_SUB : AtomicSizes; 201 defm ATOMIC_LOAD_AND : AtomicSizes; 202 defm ATOMIC_LOAD_OR : AtomicSizes; 203 defm ATOMIC_LOAD_XOR : AtomicSizes; 204 defm ATOMIC_LOAD_NAND : AtomicSizes; 205 defm ATOMIC_SWAP : AtomicSizes; 206 let Defs = [NZCV] in { 207 // These operations need a CMP to calculate the correct value 208 defm ATOMIC_LOAD_MIN : AtomicSizes; 209 defm ATOMIC_LOAD_MAX : AtomicSizes; 210 defm ATOMIC_LOAD_UMIN : AtomicSizes; 211 defm ATOMIC_LOAD_UMAX : AtomicSizes; 212 } 213 214 class AtomicCmpSwap<RegisterClass GPRData> 215 : PseudoInst<(outs GPRData:$dst), 216 (ins GPR64xsp:$ptr, GPRData:$old, GPRData:$new, 217 i32imm:$ordering), []> { 218 let usesCustomInserter = 1; 219 let hasCtrlDep = 1; 220 let mayLoad = 1; 221 let mayStore = 1; 222 let Defs = [NZCV]; 223 } 224 225 def ATOMIC_CMP_SWAP_I8 : AtomicCmpSwap<GPR32>; 226 def ATOMIC_CMP_SWAP_I16 : AtomicCmpSwap<GPR32>; 227 def ATOMIC_CMP_SWAP_I32 : AtomicCmpSwap<GPR32>; 228 def ATOMIC_CMP_SWAP_I64 : AtomicCmpSwap<GPR64>; 229 230 //===----------------------------------------------------------------------===// 231 // Add-subtract (extended register) instructions 232 //===----------------------------------------------------------------------===// 233 // Contains: ADD, ADDS, SUB, SUBS + aliases CMN, CMP 234 235 // The RHS of these operations is conceptually a sign/zero-extended 236 // register, optionally shifted left by 1-4. The extension can be a 237 // NOP (e.g. "sxtx" sign-extending a 64-bit register to 64-bits) but 238 // must be specified with one exception: 239 240 // If one of the registers is sp/wsp then LSL is an alias for UXTW in 241 // 32-bit instructions and UXTX in 64-bit versions, the shift amount 242 // is not optional in that case (but can explicitly be 0), and the 243 // entire suffix can be skipped (e.g. "add sp, x3, x2"). 244 245 multiclass extend_operands<string PREFIX, string Diag> { 246 def _asmoperand : AsmOperandClass { 247 let Name = PREFIX; 248 let RenderMethod = "addRegExtendOperands"; 249 let PredicateMethod = "isRegExtend<A64SE::" # PREFIX # ">"; 250 let DiagnosticType = "AddSubRegExtend" # Diag; 251 } 252 253 def _operand : Operand<i64>, 254 ImmLeaf<i64, [{ return Imm >= 0 && Imm <= 4; }]> { 255 let PrintMethod = "printRegExtendOperand<A64SE::" # PREFIX # ">"; 256 let DecoderMethod = "DecodeRegExtendOperand"; 257 let ParserMatchClass = !cast<AsmOperandClass>(PREFIX # "_asmoperand"); 258 } 259 } 260 261 defm UXTB : extend_operands<"UXTB", "Small">; 262 defm UXTH : extend_operands<"UXTH", "Small">; 263 defm UXTW : extend_operands<"UXTW", "Small">; 264 defm UXTX : extend_operands<"UXTX", "Large">; 265 defm SXTB : extend_operands<"SXTB", "Small">; 266 defm SXTH : extend_operands<"SXTH", "Small">; 267 defm SXTW : extend_operands<"SXTW", "Small">; 268 defm SXTX : extend_operands<"SXTX", "Large">; 269 270 def LSL_extasmoperand : AsmOperandClass { 271 let Name = "RegExtendLSL"; 272 let RenderMethod = "addRegExtendOperands"; 273 let DiagnosticType = "AddSubRegExtendLarge"; 274 } 275 276 def LSL_extoperand : Operand<i64> { 277 let ParserMatchClass = LSL_extasmoperand; 278 } 279 280 281 // The patterns for various sign-extensions are a little ugly and 282 // non-uniform because everything has already been promoted to the 283 // legal i64 and i32 types. We'll wrap the various variants up in a 284 // class for use later. 285 class extend_types { 286 dag uxtb; dag uxth; dag uxtw; dag uxtx; 287 dag sxtb; dag sxth; dag sxtw; dag sxtx; 288 ValueType ty; 289 RegisterClass GPR; 290 } 291 292 def extends_to_i64 : extend_types { 293 let uxtb = (and (anyext i32:$Rm), 255); 294 let uxth = (and (anyext i32:$Rm), 65535); 295 let uxtw = (zext i32:$Rm); 296 let uxtx = (i64 $Rm); 297 298 let sxtb = (sext_inreg (anyext i32:$Rm), i8); 299 let sxth = (sext_inreg (anyext i32:$Rm), i16); 300 let sxtw = (sext i32:$Rm); 301 let sxtx = (i64 $Rm); 302 303 let ty = i64; 304 let GPR = GPR64xsp; 305 } 306 307 308 def extends_to_i32 : extend_types { 309 let uxtb = (and i32:$Rm, 255); 310 let uxth = (and i32:$Rm, 65535); 311 let uxtw = (i32 i32:$Rm); 312 let uxtx = (i32 i32:$Rm); 313 314 let sxtb = (sext_inreg i32:$Rm, i8); 315 let sxth = (sext_inreg i32:$Rm, i16); 316 let sxtw = (i32 i32:$Rm); 317 let sxtx = (i32 i32:$Rm); 318 319 let ty = i32; 320 let GPR = GPR32wsp; 321 } 322 323 // Now, six of the extensions supported are easy and uniform: if the source size 324 // is 32-bits or less, then Rm is always a 32-bit register. We'll instantiate 325 // those instructions in one block. 326 327 // The uxtx/sxtx could potentially be merged in, but three facts dissuaded me: 328 // + It would break the naming scheme: either ADDxx_uxtx or ADDww_uxtx would 329 // be impossible. 330 // + Patterns are very different as well. 331 // + Passing different registers would be ugly (more fields in extend_types 332 // would probably be the best option). 333 multiclass addsub_exts<bit sf, bit op, bit S, string asmop, 334 SDPatternOperator opfrag, 335 dag outs, extend_types exts> { 336 def w_uxtb : A64I_addsubext<sf, op, S, 0b00, 0b000, 337 outs, (ins exts.GPR:$Rn, GPR32:$Rm, UXTB_operand:$Imm3), 338 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 339 [(opfrag exts.ty:$Rn, (shl exts.uxtb, UXTB_operand:$Imm3))], 340 NoItinerary>; 341 def w_uxth : A64I_addsubext<sf, op, S, 0b00, 0b001, 342 outs, (ins exts.GPR:$Rn, GPR32:$Rm, UXTH_operand:$Imm3), 343 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 344 [(opfrag exts.ty:$Rn, (shl exts.uxth, UXTH_operand:$Imm3))], 345 NoItinerary>; 346 def w_uxtw : A64I_addsubext<sf, op, S, 0b00, 0b010, 347 outs, (ins exts.GPR:$Rn, GPR32:$Rm, UXTW_operand:$Imm3), 348 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 349 [(opfrag exts.ty:$Rn, (shl exts.uxtw, UXTW_operand:$Imm3))], 350 NoItinerary>; 351 352 def w_sxtb : A64I_addsubext<sf, op, S, 0b00, 0b100, 353 outs, (ins exts.GPR:$Rn, GPR32:$Rm, SXTB_operand:$Imm3), 354 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 355 [(opfrag exts.ty:$Rn, (shl exts.sxtb, SXTB_operand:$Imm3))], 356 NoItinerary>; 357 def w_sxth : A64I_addsubext<sf, op, S, 0b00, 0b101, 358 outs, (ins exts.GPR:$Rn, GPR32:$Rm, SXTH_operand:$Imm3), 359 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 360 [(opfrag exts.ty:$Rn, (shl exts.sxth, SXTH_operand:$Imm3))], 361 NoItinerary>; 362 def w_sxtw : A64I_addsubext<sf, op, S, 0b00, 0b110, 363 outs, (ins exts.GPR:$Rn, GPR32:$Rm, SXTW_operand:$Imm3), 364 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 365 [(opfrag exts.ty:$Rn, (shl exts.sxtw, SXTW_operand:$Imm3))], 366 NoItinerary>; 367 } 368 369 // These two could be merge in with the above, but their patterns aren't really 370 // necessary and the naming-scheme would necessarily break: 371 multiclass addsub_xxtx<bit op, bit S, string asmop, SDPatternOperator opfrag, 372 dag outs> { 373 def x_uxtx : A64I_addsubext<0b1, op, S, 0b00, 0b011, 374 outs, 375 (ins GPR64xsp:$Rn, GPR64:$Rm, UXTX_operand:$Imm3), 376 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 377 [(opfrag i64:$Rn, (shl i64:$Rm, UXTX_operand:$Imm3))], 378 NoItinerary>; 379 380 def x_sxtx : A64I_addsubext<0b1, op, S, 0b00, 0b111, 381 outs, 382 (ins GPR64xsp:$Rn, GPR64:$Rm, SXTX_operand:$Imm3), 383 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 384 [/* No Pattern: same as uxtx */], 385 NoItinerary>; 386 } 387 388 multiclass addsub_wxtx<bit op, bit S, string asmop, dag outs> { 389 def w_uxtx : A64I_addsubext<0b0, op, S, 0b00, 0b011, 390 outs, 391 (ins GPR32wsp:$Rn, GPR32:$Rm, UXTX_operand:$Imm3), 392 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 393 [/* No pattern: probably same as uxtw */], 394 NoItinerary>; 395 396 def w_sxtx : A64I_addsubext<0b0, op, S, 0b00, 0b111, 397 outs, 398 (ins GPR32wsp:$Rn, GPR32:$Rm, SXTX_operand:$Imm3), 399 !strconcat(asmop, "$Rn, $Rm, $Imm3"), 400 [/* No Pattern: probably same as uxtw */], 401 NoItinerary>; 402 } 403 404 class SetRD<RegisterClass RC, SDPatternOperator op> 405 : PatFrag<(ops node:$lhs, node:$rhs), (set RC:$Rd, (op node:$lhs, node:$rhs))>; 406 class SetNZCV<SDPatternOperator op> 407 : PatFrag<(ops node:$lhs, node:$rhs), (set NZCV, (op node:$lhs, node:$rhs))>; 408 409 defm ADDxx :addsub_exts<0b1, 0b0, 0b0, "add\t$Rd, ", SetRD<GPR64xsp, add>, 410 (outs GPR64xsp:$Rd), extends_to_i64>, 411 addsub_xxtx< 0b0, 0b0, "add\t$Rd, ", SetRD<GPR64xsp, add>, 412 (outs GPR64xsp:$Rd)>; 413 defm ADDww :addsub_exts<0b0, 0b0, 0b0, "add\t$Rd, ", SetRD<GPR32wsp, add>, 414 (outs GPR32wsp:$Rd), extends_to_i32>, 415 addsub_wxtx< 0b0, 0b0, "add\t$Rd, ", 416 (outs GPR32wsp:$Rd)>; 417 defm SUBxx :addsub_exts<0b1, 0b1, 0b0, "sub\t$Rd, ", SetRD<GPR64xsp, sub>, 418 (outs GPR64xsp:$Rd), extends_to_i64>, 419 addsub_xxtx< 0b1, 0b0, "sub\t$Rd, ", SetRD<GPR64xsp, sub>, 420 (outs GPR64xsp:$Rd)>; 421 defm SUBww :addsub_exts<0b0, 0b1, 0b0, "sub\t$Rd, ", SetRD<GPR32wsp, sub>, 422 (outs GPR32wsp:$Rd), extends_to_i32>, 423 addsub_wxtx< 0b1, 0b0, "sub\t$Rd, ", 424 (outs GPR32wsp:$Rd)>; 425 426 let Defs = [NZCV] in { 427 defm ADDSxx :addsub_exts<0b1, 0b0, 0b1, "adds\t$Rd, ", SetRD<GPR64, addc>, 428 (outs GPR64:$Rd), extends_to_i64>, 429 addsub_xxtx< 0b0, 0b1, "adds\t$Rd, ", SetRD<GPR64, addc>, 430 (outs GPR64:$Rd)>; 431 defm ADDSww :addsub_exts<0b0, 0b0, 0b1, "adds\t$Rd, ", SetRD<GPR32, addc>, 432 (outs GPR32:$Rd), extends_to_i32>, 433 addsub_wxtx< 0b0, 0b1, "adds\t$Rd, ", 434 (outs GPR32:$Rd)>; 435 defm SUBSxx :addsub_exts<0b1, 0b1, 0b1, "subs\t$Rd, ", SetRD<GPR64, subc>, 436 (outs GPR64:$Rd), extends_to_i64>, 437 addsub_xxtx< 0b1, 0b1, "subs\t$Rd, ", SetRD<GPR64, subc>, 438 (outs GPR64:$Rd)>; 439 defm SUBSww :addsub_exts<0b0, 0b1, 0b1, "subs\t$Rd, ", SetRD<GPR32, subc>, 440 (outs GPR32:$Rd), extends_to_i32>, 441 addsub_wxtx< 0b1, 0b1, "subs\t$Rd, ", 442 (outs GPR32:$Rd)>; 443 444 445 let Rd = 0b11111, isCompare = 1 in { 446 defm CMNx : addsub_exts<0b1, 0b0, 0b1, "cmn\t", SetNZCV<A64cmn>, 447 (outs), extends_to_i64>, 448 addsub_xxtx< 0b0, 0b1, "cmn\t", SetNZCV<A64cmn>, (outs)>; 449 defm CMNw : addsub_exts<0b0, 0b0, 0b1, "cmn\t", SetNZCV<A64cmn>, 450 (outs), extends_to_i32>, 451 addsub_wxtx< 0b0, 0b1, "cmn\t", (outs)>; 452 defm CMPx : addsub_exts<0b1, 0b1, 0b1, "cmp\t", SetNZCV<A64cmp>, 453 (outs), extends_to_i64>, 454 addsub_xxtx< 0b1, 0b1, "cmp\t", SetNZCV<A64cmp>, (outs)>; 455 defm CMPw : addsub_exts<0b0, 0b1, 0b1, "cmp\t", SetNZCV<A64cmp>, 456 (outs), extends_to_i32>, 457 addsub_wxtx< 0b1, 0b1, "cmp\t", (outs)>; 458 } 459 } 460 461 // Now patterns for the operation without a shift being needed. No patterns are 462 // created for uxtx/sxtx since they're non-uniform and it's expected that 463 // add/sub (shifted register) will handle those cases anyway. 464 multiclass addsubext_noshift_patterns<string prefix, SDPatternOperator nodeop, 465 extend_types exts> { 466 def : Pat<(nodeop exts.ty:$Rn, exts.uxtb), 467 (!cast<Instruction>(prefix # "w_uxtb") $Rn, $Rm, 0)>; 468 def : Pat<(nodeop exts.ty:$Rn, exts.uxth), 469 (!cast<Instruction>(prefix # "w_uxth") $Rn, $Rm, 0)>; 470 def : Pat<(nodeop exts.ty:$Rn, exts.uxtw), 471 (!cast<Instruction>(prefix # "w_uxtw") $Rn, $Rm, 0)>; 472 473 def : Pat<(nodeop exts.ty:$Rn, exts.sxtb), 474 (!cast<Instruction>(prefix # "w_sxtb") $Rn, $Rm, 0)>; 475 def : Pat<(nodeop exts.ty:$Rn, exts.sxth), 476 (!cast<Instruction>(prefix # "w_sxth") $Rn, $Rm, 0)>; 477 def : Pat<(nodeop exts.ty:$Rn, exts.sxtw), 478 (!cast<Instruction>(prefix # "w_sxtw") $Rn, $Rm, 0)>; 479 } 480 481 defm : addsubext_noshift_patterns<"ADDxx", add, extends_to_i64>; 482 defm : addsubext_noshift_patterns<"ADDww", add, extends_to_i32>; 483 defm : addsubext_noshift_patterns<"SUBxx", sub, extends_to_i64>; 484 defm : addsubext_noshift_patterns<"SUBww", sub, extends_to_i32>; 485 486 defm : addsubext_noshift_patterns<"CMNx", A64cmn, extends_to_i64>; 487 defm : addsubext_noshift_patterns<"CMNw", A64cmn, extends_to_i32>; 488 defm : addsubext_noshift_patterns<"CMPx", A64cmp, extends_to_i64>; 489 defm : addsubext_noshift_patterns<"CMPw", A64cmp, extends_to_i32>; 490 491 // An extend of "lsl #imm" is valid if and only if one of Rn and Rd is 492 // sp/wsp. It is synonymous with uxtx/uxtw depending on the size of the 493 // operation. Also permitted in this case is complete omission of the argument, 494 // which implies "lsl #0". 495 multiclass lsl_aliases<string asmop, Instruction inst, RegisterClass GPR_Rd, 496 RegisterClass GPR_Rn, RegisterClass GPR_Rm> { 497 def : InstAlias<!strconcat(asmop, " $Rd, $Rn, $Rm"), 498 (inst GPR_Rd:$Rd, GPR_Rn:$Rn, GPR_Rm:$Rm, 0)>; 499 500 def : InstAlias<!strconcat(asmop, " $Rd, $Rn, $Rm, $LSL"), 501 (inst GPR_Rd:$Rd, GPR_Rn:$Rn, GPR_Rm:$Rm, LSL_extoperand:$LSL)>; 502 503 } 504 505 defm : lsl_aliases<"add", ADDxxx_uxtx, Rxsp, GPR64xsp, GPR64>; 506 defm : lsl_aliases<"add", ADDxxx_uxtx, GPR64xsp, Rxsp, GPR64>; 507 defm : lsl_aliases<"add", ADDwww_uxtw, Rwsp, GPR32wsp, GPR32>; 508 defm : lsl_aliases<"add", ADDwww_uxtw, GPR32wsp, Rwsp, GPR32>; 509 defm : lsl_aliases<"sub", SUBxxx_uxtx, Rxsp, GPR64xsp, GPR64>; 510 defm : lsl_aliases<"sub", SUBxxx_uxtx, GPR64xsp, Rxsp, GPR64>; 511 defm : lsl_aliases<"sub", SUBwww_uxtw, Rwsp, GPR32wsp, GPR32>; 512 defm : lsl_aliases<"sub", SUBwww_uxtw, GPR32wsp, Rwsp, GPR32>; 513 514 // Rd cannot be sp for flag-setting variants so only half of the aliases are 515 // needed. 516 defm : lsl_aliases<"adds", ADDSxxx_uxtx, GPR64, Rxsp, GPR64>; 517 defm : lsl_aliases<"adds", ADDSwww_uxtw, GPR32, Rwsp, GPR32>; 518 defm : lsl_aliases<"subs", SUBSxxx_uxtx, GPR64, Rxsp, GPR64>; 519 defm : lsl_aliases<"subs", SUBSwww_uxtw, GPR32, Rwsp, GPR32>; 520 521 // CMP unfortunately has to be different because the instruction doesn't have a 522 // dest register. 523 multiclass cmp_lsl_aliases<string asmop, Instruction inst, 524 RegisterClass GPR_Rn, RegisterClass GPR_Rm> { 525 def : InstAlias<!strconcat(asmop, " $Rn, $Rm"), 526 (inst GPR_Rn:$Rn, GPR_Rm:$Rm, 0)>; 527 528 def : InstAlias<!strconcat(asmop, " $Rn, $Rm, $LSL"), 529 (inst GPR_Rn:$Rn, GPR_Rm:$Rm, LSL_extoperand:$LSL)>; 530 } 531 532 defm : cmp_lsl_aliases<"cmp", CMPxx_uxtx, Rxsp, GPR64>; 533 defm : cmp_lsl_aliases<"cmp", CMPww_uxtw, Rwsp, GPR32>; 534 defm : cmp_lsl_aliases<"cmn", CMNxx_uxtx, Rxsp, GPR64>; 535 defm : cmp_lsl_aliases<"cmn", CMNww_uxtw, Rwsp, GPR32>; 536 537 //===----------------------------------------------------------------------===// 538 // Add-subtract (immediate) instructions 539 //===----------------------------------------------------------------------===// 540 // Contains: ADD, ADDS, SUB, SUBS + aliases CMN, CMP, MOV 541 542 // These instructions accept a 12-bit unsigned immediate, optionally shifted 543 // left by 12 bits. Official assembly format specifies a 12 bit immediate with 544 // one of "", "LSL #0", "LSL #12" supplementary operands. 545 546 // There are surprisingly few ways to make this work with TableGen, so this 547 // implementation has separate instructions for the "LSL #0" and "LSL #12" 548 // variants. 549 550 // If the MCInst retained a single combined immediate (which could be 0x123000, 551 // for example) then both components (imm & shift) would have to be delegated to 552 // a single assembly operand. This would entail a separate operand parser 553 // (because the LSL would have to live in the same AArch64Operand as the 554 // immediate to be accessible); assembly parsing is rather complex and 555 // error-prone C++ code. 556 // 557 // By splitting the immediate, we can delegate handling this optional operand to 558 // an InstAlias. Supporting functions to generate the correct MCInst are still 559 // required, but these are essentially trivial and parsing can remain generic. 560 // 561 // Rejected plans with rationale: 562 // ------------------------------ 563 // 564 // In an ideal world you'de have two first class immediate operands (in 565 // InOperandList, specifying imm12 and shift). Unfortunately this is not 566 // selectable by any means I could discover. 567 // 568 // An Instruction with two MCOperands hidden behind a single entry in 569 // InOperandList (expanded by ComplexPatterns and MIOperandInfo) was functional, 570 // but required more C++ code to handle encoding/decoding. Parsing (the intended 571 // main beneficiary) ended up equally complex because of the optional nature of 572 // "LSL #0". 573 // 574 // Attempting to circumvent the need for a custom OperandParser above by giving 575 // InstAliases without the "lsl #0" failed. add/sub could be accommodated but 576 // the cmp/cmn aliases didn't use the MIOperandInfo to determine how operands 577 // should be parsed: there was no way to accommodate an "lsl #12". 578 579 let ParserMethod = "ParseImmWithLSLOperand", 580 RenderMethod = "addImmWithLSLOperands" in { 581 // Derived PredicateMethod fields are different for each 582 def addsubimm_lsl0_asmoperand : AsmOperandClass { 583 let Name = "AddSubImmLSL0"; 584 // If an error is reported against this operand, instruction could also be a 585 // register variant. 586 let DiagnosticType = "AddSubSecondSource"; 587 } 588 589 def addsubimm_lsl12_asmoperand : AsmOperandClass { 590 let Name = "AddSubImmLSL12"; 591 let DiagnosticType = "AddSubSecondSource"; 592 } 593 } 594 595 def shr_12_XFORM : SDNodeXForm<imm, [{ 596 return CurDAG->getTargetConstant(N->getSExtValue() >> 12, MVT::i32); 597 }]>; 598 599 def shr_12_neg_XFORM : SDNodeXForm<imm, [{ 600 return CurDAG->getTargetConstant((-N->getSExtValue()) >> 12, MVT::i32); 601 }]>; 602 603 def neg_XFORM : SDNodeXForm<imm, [{ 604 return CurDAG->getTargetConstant(-N->getSExtValue(), MVT::i32); 605 }]>; 606 607 608 multiclass addsub_imm_operands<ValueType ty> { 609 let PrintMethod = "printAddSubImmLSL0Operand", 610 EncoderMethod = "getAddSubImmOpValue", 611 ParserMatchClass = addsubimm_lsl0_asmoperand in { 612 def _posimm_lsl0 : Operand<ty>, 613 ImmLeaf<ty, [{ return Imm >= 0 && (Imm & ~0xfff) == 0; }]>; 614 def _negimm_lsl0 : Operand<ty>, 615 ImmLeaf<ty, [{ return Imm < 0 && (-Imm & ~0xfff) == 0; }], 616 neg_XFORM>; 617 } 618 619 let PrintMethod = "printAddSubImmLSL12Operand", 620 EncoderMethod = "getAddSubImmOpValue", 621 ParserMatchClass = addsubimm_lsl12_asmoperand in { 622 def _posimm_lsl12 : Operand<ty>, 623 ImmLeaf<ty, [{ return Imm >= 0 && (Imm & ~0xfff000) == 0; }], 624 shr_12_XFORM>; 625 626 def _negimm_lsl12 : Operand<ty>, 627 ImmLeaf<ty, [{ return Imm < 0 && (-Imm & ~0xfff000) == 0; }], 628 shr_12_neg_XFORM>; 629 } 630 } 631 632 // The add operands don't need any transformation 633 defm addsubimm_operand_i32 : addsub_imm_operands<i32>; 634 defm addsubimm_operand_i64 : addsub_imm_operands<i64>; 635 636 multiclass addsubimm_varieties<string prefix, bit sf, bit op, bits<2> shift, 637 string asmop, string cmpasmop, 638 Operand imm_operand, Operand cmp_imm_operand, 639 RegisterClass GPR, RegisterClass GPRsp, 640 AArch64Reg ZR, ValueType Ty> { 641 // All registers for non-S variants allow SP 642 def _s : A64I_addsubimm<sf, op, 0b0, shift, 643 (outs GPRsp:$Rd), 644 (ins GPRsp:$Rn, imm_operand:$Imm12), 645 !strconcat(asmop, "\t$Rd, $Rn, $Imm12"), 646 [(set Ty:$Rd, (add Ty:$Rn, imm_operand:$Imm12))], 647 NoItinerary>; 648 649 650 // S variants can read SP but would write to ZR 651 def _S : A64I_addsubimm<sf, op, 0b1, shift, 652 (outs GPR:$Rd), 653 (ins GPRsp:$Rn, imm_operand:$Imm12), 654 !strconcat(asmop, "s\t$Rd, $Rn, $Imm12"), 655 [(set Ty:$Rd, (addc Ty:$Rn, imm_operand:$Imm12))], 656 NoItinerary> { 657 let Defs = [NZCV]; 658 } 659 660 // Note that the pattern here for ADDS is subtle. Canonically CMP 661 // a, b becomes SUBS a, b. If b < 0 then this is equivalent to 662 // ADDS a, (-b). This is not true in general. 663 def _cmp : A64I_addsubimm<sf, op, 0b1, shift, 664 (outs), (ins GPRsp:$Rn, imm_operand:$Imm12), 665 !strconcat(cmpasmop, " $Rn, $Imm12"), 666 [(set NZCV, 667 (A64cmp Ty:$Rn, cmp_imm_operand:$Imm12))], 668 NoItinerary> { 669 let Rd = 0b11111; 670 let Defs = [NZCV]; 671 let isCompare = 1; 672 } 673 } 674 675 676 multiclass addsubimm_shifts<string prefix, bit sf, bit op, 677 string asmop, string cmpasmop, string operand, string cmpoperand, 678 RegisterClass GPR, RegisterClass GPRsp, AArch64Reg ZR, 679 ValueType Ty> { 680 defm _lsl0 : addsubimm_varieties<prefix # "_lsl0", sf, op, 0b00, 681 asmop, cmpasmop, 682 !cast<Operand>(operand # "_lsl0"), 683 !cast<Operand>(cmpoperand # "_lsl0"), 684 GPR, GPRsp, ZR, Ty>; 685 686 defm _lsl12 : addsubimm_varieties<prefix # "_lsl12", sf, op, 0b01, 687 asmop, cmpasmop, 688 !cast<Operand>(operand # "_lsl12"), 689 !cast<Operand>(cmpoperand # "_lsl12"), 690 GPR, GPRsp, ZR, Ty>; 691 } 692 693 defm ADDwwi : addsubimm_shifts<"ADDwi", 0b0, 0b0, "add", "cmn", 694 "addsubimm_operand_i32_posimm", 695 "addsubimm_operand_i32_negimm", 696 GPR32, GPR32wsp, WZR, i32>; 697 defm ADDxxi : addsubimm_shifts<"ADDxi", 0b1, 0b0, "add", "cmn", 698 "addsubimm_operand_i64_posimm", 699 "addsubimm_operand_i64_negimm", 700 GPR64, GPR64xsp, XZR, i64>; 701 defm SUBwwi : addsubimm_shifts<"SUBwi", 0b0, 0b1, "sub", "cmp", 702 "addsubimm_operand_i32_negimm", 703 "addsubimm_operand_i32_posimm", 704 GPR32, GPR32wsp, WZR, i32>; 705 defm SUBxxi : addsubimm_shifts<"SUBxi", 0b1, 0b1, "sub", "cmp", 706 "addsubimm_operand_i64_negimm", 707 "addsubimm_operand_i64_posimm", 708 GPR64, GPR64xsp, XZR, i64>; 709 710 multiclass MOVsp<RegisterClass GPRsp, RegisterClass SP, Instruction addop> { 711 def _fromsp : InstAlias<"mov $Rd, $Rn", 712 (addop GPRsp:$Rd, SP:$Rn, 0), 713 0b1>; 714 715 def _tosp : InstAlias<"mov $Rd, $Rn", 716 (addop SP:$Rd, GPRsp:$Rn, 0), 717 0b1>; 718 } 719 720 // Recall Rxsp is a RegisterClass containing *just* xsp. 721 defm MOVxx : MOVsp<GPR64xsp, Rxsp, ADDxxi_lsl0_s>; 722 defm MOVww : MOVsp<GPR32wsp, Rwsp, ADDwwi_lsl0_s>; 723 724 //===----------------------------------------------------------------------===// 725 // Add-subtract (shifted register) instructions 726 //===----------------------------------------------------------------------===// 727 // Contains: ADD, ADDS, SUB, SUBS + aliases CMN, CMP, NEG, NEGS 728 729 //===------------------------------- 730 // 1. The "shifed register" operands. Shared with logical insts. 731 //===------------------------------- 732 733 multiclass shift_operands<string prefix, string form> { 734 def _asmoperand_i32 : AsmOperandClass { 735 let Name = "Shift" # form # "i32"; 736 let RenderMethod = "addShiftOperands"; 737 let PredicateMethod = "isShift<A64SE::" # form # ", false>"; 738 let DiagnosticType = "AddSubRegShift32"; 739 } 740 741 // Note that the operand type is intentionally i64 because the DAGCombiner 742 // puts these into a canonical form. 743 def _i32 : Operand<i64>, ImmLeaf<i64, [{ return Imm >= 0 && Imm <= 31; }]> { 744 let ParserMatchClass 745 = !cast<AsmOperandClass>(prefix # "_asmoperand_i32"); 746 let PrintMethod = "printShiftOperand<A64SE::" # form # ">"; 747 let DecoderMethod = "Decode32BitShiftOperand"; 748 } 749 750 def _asmoperand_i64 : AsmOperandClass { 751 let Name = "Shift" # form # "i64"; 752 let RenderMethod = "addShiftOperands"; 753 let PredicateMethod = "isShift<A64SE::" # form # ", true>"; 754 let DiagnosticType = "AddSubRegShift64"; 755 } 756 757 def _i64 : Operand<i64>, ImmLeaf<i64, [{ return Imm >= 0 && Imm <= 63; }]> { 758 let ParserMatchClass 759 = !cast<AsmOperandClass>(prefix # "_asmoperand_i64"); 760 let PrintMethod = "printShiftOperand<A64SE::" # form # ">"; 761 } 762 } 763 764 defm lsl_operand : shift_operands<"lsl_operand", "LSL">; 765 defm lsr_operand : shift_operands<"lsr_operand", "LSR">; 766 defm asr_operand : shift_operands<"asr_operand", "ASR">; 767 768 // Not used for add/sub, but defined here for completeness. The "logical 769 // (shifted register)" instructions *do* have an ROR variant. 770 defm ror_operand : shift_operands<"ror_operand", "ROR">; 771 772 //===------------------------------- 773 // 2. The basic 3.5-operand ADD/SUB/ADDS/SUBS instructions. 774 //===------------------------------- 775 776 // N.b. the commutable parameter is just !N. It will be first against the wall 777 // when the revolution comes. 778 multiclass addsub_shifts<string prefix, bit sf, bit op, bit s, bit commutable, 779 string asmop, SDPatternOperator opfrag, ValueType ty, 780 RegisterClass GPR, list<Register> defs> { 781 let isCommutable = commutable, Defs = defs in { 782 def _lsl : A64I_addsubshift<sf, op, s, 0b00, 783 (outs GPR:$Rd), 784 (ins GPR:$Rn, GPR:$Rm, 785 !cast<Operand>("lsl_operand_" # ty):$Imm6), 786 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"), 787 [(set GPR:$Rd, (opfrag ty:$Rn, (shl ty:$Rm, 788 !cast<Operand>("lsl_operand_" # ty):$Imm6)) 789 )], 790 NoItinerary>; 791 792 def _lsr : A64I_addsubshift<sf, op, s, 0b01, 793 (outs GPR:$Rd), 794 (ins GPR:$Rn, GPR:$Rm, 795 !cast<Operand>("lsr_operand_" # ty):$Imm6), 796 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"), 797 [(set ty:$Rd, (opfrag ty:$Rn, (srl ty:$Rm, 798 !cast<Operand>("lsr_operand_" # ty):$Imm6)) 799 )], 800 NoItinerary>; 801 802 def _asr : A64I_addsubshift<sf, op, s, 0b10, 803 (outs GPR:$Rd), 804 (ins GPR:$Rn, GPR:$Rm, 805 !cast<Operand>("asr_operand_" # ty):$Imm6), 806 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"), 807 [(set ty:$Rd, (opfrag ty:$Rn, (sra ty:$Rm, 808 !cast<Operand>("asr_operand_" # ty):$Imm6)) 809 )], 810 NoItinerary>; 811 } 812 813 def _noshift 814 : InstAlias<!strconcat(asmop, " $Rd, $Rn, $Rm"), 815 (!cast<Instruction>(prefix # "_lsl") GPR:$Rd, GPR:$Rn, 816 GPR:$Rm, 0)>; 817 818 def : Pat<(opfrag ty:$Rn, ty:$Rm), 819 (!cast<Instruction>(prefix # "_lsl") $Rn, $Rm, 0)>; 820 } 821 822 multiclass addsub_sizes<string prefix, bit op, bit s, bit commutable, 823 string asmop, SDPatternOperator opfrag, 824 list<Register> defs> { 825 defm xxx : addsub_shifts<prefix # "xxx", 0b1, op, s, 826 commutable, asmop, opfrag, i64, GPR64, defs>; 827 defm www : addsub_shifts<prefix # "www", 0b0, op, s, 828 commutable, asmop, opfrag, i32, GPR32, defs>; 829 } 830 831 832 defm ADD : addsub_sizes<"ADD", 0b0, 0b0, 0b1, "add", add, []>; 833 defm SUB : addsub_sizes<"SUB", 0b1, 0b0, 0b0, "sub", sub, []>; 834 835 defm ADDS : addsub_sizes<"ADDS", 0b0, 0b1, 0b1, "adds", addc, [NZCV]>; 836 defm SUBS : addsub_sizes<"SUBS", 0b1, 0b1, 0b0, "subs", subc, [NZCV]>; 837 838 //===------------------------------- 839 // 1. The NEG/NEGS aliases 840 //===------------------------------- 841 842 multiclass neg_alias<Instruction INST, RegisterClass GPR, Register ZR, 843 ValueType ty, Operand shift_operand, SDNode shiftop> { 844 def : InstAlias<"neg $Rd, $Rm, $Imm6", 845 (INST GPR:$Rd, ZR, GPR:$Rm, shift_operand:$Imm6)>; 846 847 def : Pat<(sub 0, (shiftop ty:$Rm, shift_operand:$Imm6)), 848 (INST ZR, $Rm, shift_operand:$Imm6)>; 849 } 850 851 defm : neg_alias<SUBwww_lsl, GPR32, WZR, i32, lsl_operand_i32, shl>; 852 defm : neg_alias<SUBwww_lsr, GPR32, WZR, i32, lsr_operand_i32, srl>; 853 defm : neg_alias<SUBwww_asr, GPR32, WZR, i32, asr_operand_i32, sra>; 854 def : InstAlias<"neg $Rd, $Rm", (SUBwww_lsl GPR32:$Rd, WZR, GPR32:$Rm, 0)>; 855 def : Pat<(sub 0, i32:$Rm), (SUBwww_lsl WZR, $Rm, 0)>; 856 857 defm : neg_alias<SUBxxx_lsl, GPR64, XZR, i64, lsl_operand_i64, shl>; 858 defm : neg_alias<SUBxxx_lsr, GPR64, XZR, i64, lsr_operand_i64, srl>; 859 defm : neg_alias<SUBxxx_asr, GPR64, XZR, i64, asr_operand_i64, sra>; 860 def : InstAlias<"neg $Rd, $Rm", (SUBxxx_lsl GPR64:$Rd, XZR, GPR64:$Rm, 0)>; 861 def : Pat<(sub 0, i64:$Rm), (SUBxxx_lsl XZR, $Rm, 0)>; 862 863 // NEGS doesn't get any patterns yet: defining multiple outputs means C++ has to 864 // be involved. 865 class negs_alias<Instruction INST, RegisterClass GPR, 866 Register ZR, Operand shift_operand, SDNode shiftop> 867 : InstAlias<"negs $Rd, $Rm, $Imm6", 868 (INST GPR:$Rd, ZR, GPR:$Rm, shift_operand:$Imm6)>; 869 870 def : negs_alias<SUBSwww_lsl, GPR32, WZR, lsl_operand_i32, shl>; 871 def : negs_alias<SUBSwww_lsr, GPR32, WZR, lsr_operand_i32, srl>; 872 def : negs_alias<SUBSwww_asr, GPR32, WZR, asr_operand_i32, sra>; 873 def : InstAlias<"negs $Rd, $Rm", (SUBSwww_lsl GPR32:$Rd, WZR, GPR32:$Rm, 0)>; 874 875 def : negs_alias<SUBSxxx_lsl, GPR64, XZR, lsl_operand_i64, shl>; 876 def : negs_alias<SUBSxxx_lsr, GPR64, XZR, lsr_operand_i64, srl>; 877 def : negs_alias<SUBSxxx_asr, GPR64, XZR, asr_operand_i64, sra>; 878 def : InstAlias<"negs $Rd, $Rm", (SUBSxxx_lsl GPR64:$Rd, XZR, GPR64:$Rm, 0)>; 879 880 //===------------------------------- 881 // 1. The CMP/CMN aliases 882 //===------------------------------- 883 884 multiclass cmp_shifts<string prefix, bit sf, bit op, bit commutable, 885 string asmop, SDPatternOperator opfrag, ValueType ty, 886 RegisterClass GPR> { 887 let isCommutable = commutable, Rd = 0b11111, Defs = [NZCV] in { 888 def _lsl : A64I_addsubshift<sf, op, 0b1, 0b00, 889 (outs), 890 (ins GPR:$Rn, GPR:$Rm, 891 !cast<Operand>("lsl_operand_" # ty):$Imm6), 892 !strconcat(asmop, "\t$Rn, $Rm, $Imm6"), 893 [(set NZCV, (opfrag ty:$Rn, (shl ty:$Rm, 894 !cast<Operand>("lsl_operand_" # ty):$Imm6)) 895 )], 896 NoItinerary>; 897 898 def _lsr : A64I_addsubshift<sf, op, 0b1, 0b01, 899 (outs), 900 (ins GPR:$Rn, GPR:$Rm, 901 !cast<Operand>("lsr_operand_" # ty):$Imm6), 902 !strconcat(asmop, "\t$Rn, $Rm, $Imm6"), 903 [(set NZCV, (opfrag ty:$Rn, (srl ty:$Rm, 904 !cast<Operand>("lsr_operand_" # ty):$Imm6)) 905 )], 906 NoItinerary>; 907 908 def _asr : A64I_addsubshift<sf, op, 0b1, 0b10, 909 (outs), 910 (ins GPR:$Rn, GPR:$Rm, 911 !cast<Operand>("asr_operand_" # ty):$Imm6), 912 !strconcat(asmop, "\t$Rn, $Rm, $Imm6"), 913 [(set NZCV, (opfrag ty:$Rn, (sra ty:$Rm, 914 !cast<Operand>("asr_operand_" # ty):$Imm6)) 915 )], 916 NoItinerary>; 917 } 918 919 def _noshift 920 : InstAlias<!strconcat(asmop, " $Rn, $Rm"), 921 (!cast<Instruction>(prefix # "_lsl") GPR:$Rn, GPR:$Rm, 0)>; 922 923 def : Pat<(opfrag ty:$Rn, ty:$Rm), 924 (!cast<Instruction>(prefix # "_lsl") $Rn, $Rm, 0)>; 925 } 926 927 defm CMPww : cmp_shifts<"CMPww", 0b0, 0b1, 0b0, "cmp", A64cmp, i32, GPR32>; 928 defm CMPxx : cmp_shifts<"CMPxx", 0b1, 0b1, 0b0, "cmp", A64cmp, i64, GPR64>; 929 930 defm CMNww : cmp_shifts<"CMNww", 0b0, 0b0, 0b1, "cmn", A64cmn, i32, GPR32>; 931 defm CMNxx : cmp_shifts<"CMNxx", 0b1, 0b0, 0b1, "cmn", A64cmn, i64, GPR64>; 932 933 //===----------------------------------------------------------------------===// 934 // Add-subtract (with carry) instructions 935 //===----------------------------------------------------------------------===// 936 // Contains: ADC, ADCS, SBC, SBCS + aliases NGC, NGCS 937 938 multiclass A64I_addsubcarrySizes<bit op, bit s, string asmop> { 939 let Uses = [NZCV] in { 940 def www : A64I_addsubcarry<0b0, op, s, 0b000000, 941 (outs GPR32:$Rd), (ins GPR32:$Rn, GPR32:$Rm), 942 !strconcat(asmop, "\t$Rd, $Rn, $Rm"), 943 [], NoItinerary>; 944 945 def xxx : A64I_addsubcarry<0b1, op, s, 0b000000, 946 (outs GPR64:$Rd), (ins GPR64:$Rn, GPR64:$Rm), 947 !strconcat(asmop, "\t$Rd, $Rn, $Rm"), 948 [], NoItinerary>; 949 } 950 } 951 952 let isCommutable = 1 in { 953 defm ADC : A64I_addsubcarrySizes<0b0, 0b0, "adc">; 954 } 955 956 defm SBC : A64I_addsubcarrySizes<0b1, 0b0, "sbc">; 957 958 let Defs = [NZCV] in { 959 let isCommutable = 1 in { 960 defm ADCS : A64I_addsubcarrySizes<0b0, 0b1, "adcs">; 961 } 962 963 defm SBCS : A64I_addsubcarrySizes<0b1, 0b1, "sbcs">; 964 } 965 966 def : InstAlias<"ngc $Rd, $Rm", (SBCwww GPR32:$Rd, WZR, GPR32:$Rm)>; 967 def : InstAlias<"ngc $Rd, $Rm", (SBCxxx GPR64:$Rd, XZR, GPR64:$Rm)>; 968 def : InstAlias<"ngcs $Rd, $Rm", (SBCSwww GPR32:$Rd, WZR, GPR32:$Rm)>; 969 def : InstAlias<"ngcs $Rd, $Rm", (SBCSxxx GPR64:$Rd, XZR, GPR64:$Rm)>; 970 971 // Note that adde and sube can form a chain longer than two (e.g. for 256-bit 972 // addition). So the flag-setting instructions are appropriate. 973 def : Pat<(adde i32:$Rn, i32:$Rm), (ADCSwww $Rn, $Rm)>; 974 def : Pat<(adde i64:$Rn, i64:$Rm), (ADCSxxx $Rn, $Rm)>; 975 def : Pat<(sube i32:$Rn, i32:$Rm), (SBCSwww $Rn, $Rm)>; 976 def : Pat<(sube i64:$Rn, i64:$Rm), (SBCSxxx $Rn, $Rm)>; 977 978 //===----------------------------------------------------------------------===// 979 // Bitfield 980 //===----------------------------------------------------------------------===// 981 // Contains: SBFM, BFM, UBFM, [SU]XT[BHW], ASR, LSR, LSL, SBFI[ZX], BFI, BFXIL, 982 // UBFIZ, UBFX 983 984 // Because of the rather complicated nearly-overlapping aliases, the decoding of 985 // this range of instructions is handled manually. The architectural 986 // instructions are BFM, SBFM and UBFM but a disassembler should never produce 987 // these. 988 // 989 // In the end, the best option was to use BFM instructions for decoding under 990 // almost all circumstances, but to create aliasing *Instructions* for each of 991 // the canonical forms and specify a completely custom decoder which would 992 // substitute the correct MCInst as needed. 993 // 994 // This also simplifies instruction selection, parsing etc because the MCInsts 995 // have a shape that's closer to their use in code. 996 997 //===------------------------------- 998 // 1. The architectural BFM instructions 999 //===------------------------------- 1000 1001 def uimm5_asmoperand : AsmOperandClass { 1002 let Name = "UImm5"; 1003 let PredicateMethod = "isUImm<5>"; 1004 let RenderMethod = "addImmOperands"; 1005 let DiagnosticType = "UImm5"; 1006 } 1007 1008 def uimm6_asmoperand : AsmOperandClass { 1009 let Name = "UImm6"; 1010 let PredicateMethod = "isUImm<6>"; 1011 let RenderMethod = "addImmOperands"; 1012 let DiagnosticType = "UImm6"; 1013 } 1014 1015 def bitfield32_imm : Operand<i64>, 1016 ImmLeaf<i64, [{ return Imm >= 0 && Imm < 32; }]> { 1017 let ParserMatchClass = uimm5_asmoperand; 1018 1019 let DecoderMethod = "DecodeBitfield32ImmOperand"; 1020 } 1021 1022 1023 def bitfield64_imm : Operand<i64>, 1024 ImmLeaf<i64, [{ return Imm >= 0 && Imm < 64; }]> { 1025 let ParserMatchClass = uimm6_asmoperand; 1026 1027 // Default decoder works in 64-bit case: the 6-bit field can take any value. 1028 } 1029 1030 multiclass A64I_bitfieldSizes<bits<2> opc, string asmop> { 1031 def wwii : A64I_bitfield<0b0, opc, 0b0, (outs GPR32:$Rd), 1032 (ins GPR32:$Rn, bitfield32_imm:$ImmR, bitfield32_imm:$ImmS), 1033 !strconcat(asmop, "\t$Rd, $Rn, $ImmR, $ImmS"), 1034 [], NoItinerary> { 1035 let DecoderMethod = "DecodeBitfieldInstruction"; 1036 } 1037 1038 def xxii : A64I_bitfield<0b1, opc, 0b1, (outs GPR64:$Rd), 1039 (ins GPR64:$Rn, bitfield64_imm:$ImmR, bitfield64_imm:$ImmS), 1040 !strconcat(asmop, "\t$Rd, $Rn, $ImmR, $ImmS"), 1041 [], NoItinerary> { 1042 let DecoderMethod = "DecodeBitfieldInstruction"; 1043 } 1044 } 1045 1046 defm SBFM : A64I_bitfieldSizes<0b00, "sbfm">; 1047 defm UBFM : A64I_bitfieldSizes<0b10, "ubfm">; 1048 1049 // BFM instructions modify the destination register rather than defining it 1050 // completely. 1051 def BFMwwii : 1052 A64I_bitfield<0b0, 0b01, 0b0, (outs GPR32:$Rd), 1053 (ins GPR32:$src, GPR32:$Rn, bitfield32_imm:$ImmR, bitfield32_imm:$ImmS), 1054 "bfm\t$Rd, $Rn, $ImmR, $ImmS", [], NoItinerary> { 1055 let DecoderMethod = "DecodeBitfieldInstruction"; 1056 let Constraints = "$src = $Rd"; 1057 } 1058 1059 def BFMxxii : 1060 A64I_bitfield<0b1, 0b01, 0b1, (outs GPR64:$Rd), 1061 (ins GPR64:$src, GPR64:$Rn, bitfield64_imm:$ImmR, bitfield64_imm:$ImmS), 1062 "bfm\t$Rd, $Rn, $ImmR, $ImmS", [], NoItinerary> { 1063 let DecoderMethod = "DecodeBitfieldInstruction"; 1064 let Constraints = "$src = $Rd"; 1065 } 1066 1067 1068 //===------------------------------- 1069 // 2. Extend aliases to 64-bit dest 1070 //===------------------------------- 1071 1072 // Unfortunately the extensions that end up as 64-bits cannot be handled by an 1073 // instruction alias: their syntax is (for example) "SXTB x0, w0", which needs 1074 // to be mapped to "SBFM x0, x0, #0, 7" (changing the class of Rn). InstAlias is 1075 // not capable of such a map as far as I'm aware 1076 1077 // Note that these instructions are strictly more specific than the 1078 // BFM ones (in ImmR) so they can handle their own decoding. 1079 class A64I_bf_ext<bit sf, bits<2> opc, RegisterClass GPRDest, ValueType dty, 1080 string asmop, bits<6> imms, dag pattern> 1081 : A64I_bitfield<sf, opc, sf, 1082 (outs GPRDest:$Rd), (ins GPR32:$Rn), 1083 !strconcat(asmop, "\t$Rd, $Rn"), 1084 [(set dty:$Rd, pattern)], NoItinerary> { 1085 let ImmR = 0b000000; 1086 let ImmS = imms; 1087 } 1088 1089 // Signed extensions 1090 def SXTBxw : A64I_bf_ext<0b1, 0b00, GPR64, i64, "sxtb", 7, 1091 (sext_inreg (anyext i32:$Rn), i8)>; 1092 def SXTBww : A64I_bf_ext<0b0, 0b00, GPR32, i32, "sxtb", 7, 1093 (sext_inreg i32:$Rn, i8)>; 1094 def SXTHxw : A64I_bf_ext<0b1, 0b00, GPR64, i64, "sxth", 15, 1095 (sext_inreg (anyext i32:$Rn), i16)>; 1096 def SXTHww : A64I_bf_ext<0b0, 0b00, GPR32, i32, "sxth", 15, 1097 (sext_inreg i32:$Rn, i16)>; 1098 def SXTWxw : A64I_bf_ext<0b1, 0b00, GPR64, i64, "sxtw", 31, (sext i32:$Rn)>; 1099 1100 // Unsigned extensions 1101 def UXTBww : A64I_bf_ext<0b0, 0b10, GPR32, i32, "uxtb", 7, 1102 (and i32:$Rn, 255)>; 1103 def UXTHww : A64I_bf_ext<0b0, 0b10, GPR32, i32, "uxth", 15, 1104 (and i32:$Rn, 65535)>; 1105 1106 // The 64-bit unsigned variants are not strictly architectural but recommended 1107 // for consistency. 1108 let isAsmParserOnly = 1 in { 1109 def UXTBxw : A64I_bf_ext<0b0, 0b10, GPR64, i64, "uxtb", 7, 1110 (and (anyext i32:$Rn), 255)>; 1111 def UXTHxw : A64I_bf_ext<0b0, 0b10, GPR64, i64, "uxth", 15, 1112 (and (anyext i32:$Rn), 65535)>; 1113 } 1114 1115 // Extra patterns for when the source register is actually 64-bits 1116 // too. There's no architectural difference here, it's just LLVM 1117 // shinanigans. There's no need for equivalent zero-extension patterns 1118 // because they'll already be caught by logical (immediate) matching. 1119 def : Pat<(sext_inreg i64:$Rn, i8), 1120 (SXTBxw (EXTRACT_SUBREG $Rn, sub_32))>; 1121 def : Pat<(sext_inreg i64:$Rn, i16), 1122 (SXTHxw (EXTRACT_SUBREG $Rn, sub_32))>; 1123 def : Pat<(sext_inreg i64:$Rn, i32), 1124 (SXTWxw (EXTRACT_SUBREG $Rn, sub_32))>; 1125 1126 1127 //===------------------------------- 1128 // 3. Aliases for ASR and LSR (the simple shifts) 1129 //===------------------------------- 1130 1131 // These also handle their own decoding because ImmS being set makes 1132 // them take precedence over BFM. 1133 multiclass A64I_shift<bits<2> opc, string asmop, SDNode opnode> { 1134 def wwi : A64I_bitfield<0b0, opc, 0b0, 1135 (outs GPR32:$Rd), (ins GPR32:$Rn, bitfield32_imm:$ImmR), 1136 !strconcat(asmop, "\t$Rd, $Rn, $ImmR"), 1137 [(set i32:$Rd, (opnode i32:$Rn, bitfield32_imm:$ImmR))], 1138 NoItinerary> { 1139 let ImmS = 31; 1140 } 1141 1142 def xxi : A64I_bitfield<0b1, opc, 0b1, 1143 (outs GPR64:$Rd), (ins GPR64:$Rn, bitfield64_imm:$ImmR), 1144 !strconcat(asmop, "\t$Rd, $Rn, $ImmR"), 1145 [(set i64:$Rd, (opnode i64:$Rn, bitfield64_imm:$ImmR))], 1146 NoItinerary> { 1147 let ImmS = 63; 1148 } 1149 1150 } 1151 1152 defm ASR : A64I_shift<0b00, "asr", sra>; 1153 defm LSR : A64I_shift<0b10, "lsr", srl>; 1154 1155 //===------------------------------- 1156 // 4. Aliases for LSL 1157 //===------------------------------- 1158 1159 // Unfortunately LSL and subsequent aliases are much more complicated. We need 1160 // to be able to say certain output instruction fields depend in a complex 1161 // manner on combinations of input assembly fields). 1162 // 1163 // MIOperandInfo *might* have been able to do it, but at the cost of 1164 // significantly more C++ code. 1165 1166 // N.b. contrary to usual practice these operands store the shift rather than 1167 // the machine bits in an MCInst. The complexity overhead of consistency 1168 // outweighed the benefits in this case (custom asmparser, printer and selection 1169 // vs custom encoder). 1170 def bitfield32_lsl_imm : Operand<i64>, 1171 ImmLeaf<i64, [{ return Imm >= 0 && Imm <= 31; }]> { 1172 let ParserMatchClass = uimm5_asmoperand; 1173 let EncoderMethod = "getBitfield32LSLOpValue"; 1174 } 1175 1176 def bitfield64_lsl_imm : Operand<i64>, 1177 ImmLeaf<i64, [{ return Imm >= 0 && Imm <= 63; }]> { 1178 let ParserMatchClass = uimm6_asmoperand; 1179 let EncoderMethod = "getBitfield64LSLOpValue"; 1180 } 1181 1182 class A64I_bitfield_lsl<bit sf, RegisterClass GPR, ValueType ty, 1183 Operand operand> 1184 : A64I_bitfield<sf, 0b10, sf, (outs GPR:$Rd), (ins GPR:$Rn, operand:$FullImm), 1185 "lsl\t$Rd, $Rn, $FullImm", 1186 [(set ty:$Rd, (shl ty:$Rn, operand:$FullImm))], 1187 NoItinerary> { 1188 bits<12> FullImm; 1189 let ImmR = FullImm{5-0}; 1190 let ImmS = FullImm{11-6}; 1191 1192 // No disassembler allowed because it would overlap with BFM which does the 1193 // actual work. 1194 let isAsmParserOnly = 1; 1195 } 1196 1197 def LSLwwi : A64I_bitfield_lsl<0b0, GPR32, i32, bitfield32_lsl_imm>; 1198 def LSLxxi : A64I_bitfield_lsl<0b1, GPR64, i64, bitfield64_lsl_imm>; 1199 1200 //===------------------------------- 1201 // 5. Aliases for bitfield extract instructions 1202 //===------------------------------- 1203 1204 def bfx32_width_asmoperand : AsmOperandClass { 1205 let Name = "BFX32Width"; 1206 let PredicateMethod = "isBitfieldWidth<32>"; 1207 let RenderMethod = "addBFXWidthOperands"; 1208 let DiagnosticType = "Width32"; 1209 } 1210 1211 def bfx32_width : Operand<i64>, ImmLeaf<i64, [{ return true; }]> { 1212 let PrintMethod = "printBFXWidthOperand"; 1213 let ParserMatchClass = bfx32_width_asmoperand; 1214 } 1215 1216 def bfx64_width_asmoperand : AsmOperandClass { 1217 let Name = "BFX64Width"; 1218 let PredicateMethod = "isBitfieldWidth<64>"; 1219 let RenderMethod = "addBFXWidthOperands"; 1220 let DiagnosticType = "Width64"; 1221 } 1222 1223 def bfx64_width : Operand<i64> { 1224 let PrintMethod = "printBFXWidthOperand"; 1225 let ParserMatchClass = bfx64_width_asmoperand; 1226 } 1227 1228 1229 multiclass A64I_bitfield_extract<bits<2> opc, string asmop, SDNode op> { 1230 def wwii : A64I_bitfield<0b0, opc, 0b0, (outs GPR32:$Rd), 1231 (ins GPR32:$Rn, bitfield32_imm:$ImmR, bfx32_width:$ImmS), 1232 !strconcat(asmop, "\t$Rd, $Rn, $ImmR, $ImmS"), 1233 [(set i32:$Rd, (op i32:$Rn, imm:$ImmR, imm:$ImmS))], 1234 NoItinerary> { 1235 // As above, no disassembler allowed. 1236 let isAsmParserOnly = 1; 1237 } 1238 1239 def xxii : A64I_bitfield<0b1, opc, 0b1, (outs GPR64:$Rd), 1240 (ins GPR64:$Rn, bitfield64_imm:$ImmR, bfx64_width:$ImmS), 1241 !strconcat(asmop, "\t$Rd, $Rn, $ImmR, $ImmS"), 1242 [(set i64:$Rd, (op i64:$Rn, imm:$ImmR, imm:$ImmS))], 1243 NoItinerary> { 1244 // As above, no disassembler allowed. 1245 let isAsmParserOnly = 1; 1246 } 1247 } 1248 1249 defm SBFX : A64I_bitfield_extract<0b00, "sbfx", A64Sbfx>; 1250 defm UBFX : A64I_bitfield_extract<0b10, "ubfx", A64Ubfx>; 1251 1252 // Again, variants based on BFM modify Rd so need it as an input too. 1253 def BFXILwwii : A64I_bitfield<0b0, 0b01, 0b0, (outs GPR32:$Rd), 1254 (ins GPR32:$src, GPR32:$Rn, bitfield32_imm:$ImmR, bfx32_width:$ImmS), 1255 "bfxil\t$Rd, $Rn, $ImmR, $ImmS", [], NoItinerary> { 1256 // As above, no disassembler allowed. 1257 let isAsmParserOnly = 1; 1258 let Constraints = "$src = $Rd"; 1259 } 1260 1261 def BFXILxxii : A64I_bitfield<0b1, 0b01, 0b1, (outs GPR64:$Rd), 1262 (ins GPR64:$src, GPR64:$Rn, bitfield64_imm:$ImmR, bfx64_width:$ImmS), 1263 "bfxil\t$Rd, $Rn, $ImmR, $ImmS", [], NoItinerary> { 1264 // As above, no disassembler allowed. 1265 let isAsmParserOnly = 1; 1266 let Constraints = "$src = $Rd"; 1267 } 1268 1269 // SBFX instructions can do a 1-instruction sign-extension of boolean values. 1270 def : Pat<(sext_inreg i64:$Rn, i1), (SBFXxxii $Rn, 0, 0)>; 1271 def : Pat<(sext_inreg i32:$Rn, i1), (SBFXwwii $Rn, 0, 0)>; 1272 def : Pat<(i64 (sext_inreg (anyext i32:$Rn), i1)), 1273 (SBFXxxii (SUBREG_TO_REG (i64 0), $Rn, sub_32), 0, 0)>; 1274 1275 // UBFX makes sense as an implementation of a 64-bit zero-extension too. Could 1276 // use either 64-bit or 32-bit variant, but 32-bit might be more efficient. 1277 def : Pat<(zext i32:$Rn), (SUBREG_TO_REG (i64 0), (UBFXwwii $Rn, 0, 31), 1278 sub_32)>; 1279 1280 //===------------------------------- 1281 // 6. Aliases for bitfield insert instructions 1282 //===------------------------------- 1283 1284 def bfi32_lsb_asmoperand : AsmOperandClass { 1285 let Name = "BFI32LSB"; 1286 let PredicateMethod = "isUImm<5>"; 1287 let RenderMethod = "addBFILSBOperands<32>"; 1288 let DiagnosticType = "UImm5"; 1289 } 1290 1291 def bfi32_lsb : Operand<i64>, 1292 ImmLeaf<i64, [{ return Imm >= 0 && Imm <= 31; }]> { 1293 let PrintMethod = "printBFILSBOperand<32>"; 1294 let ParserMatchClass = bfi32_lsb_asmoperand; 1295 } 1296 1297 def bfi64_lsb_asmoperand : AsmOperandClass { 1298 let Name = "BFI64LSB"; 1299 let PredicateMethod = "isUImm<6>"; 1300 let RenderMethod = "addBFILSBOperands<64>"; 1301 let DiagnosticType = "UImm6"; 1302 } 1303 1304 def bfi64_lsb : Operand<i64>, 1305 ImmLeaf<i64, [{ return Imm >= 0 && Imm <= 63; }]> { 1306 let PrintMethod = "printBFILSBOperand<64>"; 1307 let ParserMatchClass = bfi64_lsb_asmoperand; 1308 } 1309 1310 // Width verification is performed during conversion so width operand can be 1311 // shared between 32/64-bit cases. Still needed for the print method though 1312 // because ImmR encodes "width - 1". 1313 def bfi32_width_asmoperand : AsmOperandClass { 1314 let Name = "BFI32Width"; 1315 let PredicateMethod = "isBitfieldWidth<32>"; 1316 let RenderMethod = "addBFIWidthOperands"; 1317 let DiagnosticType = "Width32"; 1318 } 1319 1320 def bfi32_width : Operand<i64>, 1321 ImmLeaf<i64, [{ return Imm >= 1 && Imm <= 32; }]> { 1322 let PrintMethod = "printBFIWidthOperand"; 1323 let ParserMatchClass = bfi32_width_asmoperand; 1324 } 1325 1326 def bfi64_width_asmoperand : AsmOperandClass { 1327 let Name = "BFI64Width"; 1328 let PredicateMethod = "isBitfieldWidth<64>"; 1329 let RenderMethod = "addBFIWidthOperands"; 1330 let DiagnosticType = "Width64"; 1331 } 1332 1333 def bfi64_width : Operand<i64>, 1334 ImmLeaf<i64, [{ return Imm >= 1 && Imm <= 64; }]> { 1335 let PrintMethod = "printBFIWidthOperand"; 1336 let ParserMatchClass = bfi64_width_asmoperand; 1337 } 1338 1339 multiclass A64I_bitfield_insert<bits<2> opc, string asmop> { 1340 def wwii : A64I_bitfield<0b0, opc, 0b0, (outs GPR32:$Rd), 1341 (ins GPR32:$Rn, bfi32_lsb:$ImmR, bfi32_width:$ImmS), 1342 !strconcat(asmop, "\t$Rd, $Rn, $ImmR, $ImmS"), 1343 [], NoItinerary> { 1344 // As above, no disassembler allowed. 1345 let isAsmParserOnly = 1; 1346 } 1347 1348 def xxii : A64I_bitfield<0b1, opc, 0b1, (outs GPR64:$Rd), 1349 (ins GPR64:$Rn, bfi64_lsb:$ImmR, bfi64_width:$ImmS), 1350 !strconcat(asmop, "\t$Rd, $Rn, $ImmR, $ImmS"), 1351 [], NoItinerary> { 1352 // As above, no disassembler allowed. 1353 let isAsmParserOnly = 1; 1354 } 1355 } 1356 1357 defm SBFIZ : A64I_bitfield_insert<0b00, "sbfiz">; 1358 defm UBFIZ : A64I_bitfield_insert<0b10, "ubfiz">; 1359 1360 1361 def BFIwwii : A64I_bitfield<0b0, 0b01, 0b0, (outs GPR32:$Rd), 1362 (ins GPR32:$src, GPR32:$Rn, bfi32_lsb:$ImmR, bfi32_width:$ImmS), 1363 "bfi\t$Rd, $Rn, $ImmR, $ImmS", [], NoItinerary> { 1364 // As above, no disassembler allowed. 1365 let isAsmParserOnly = 1; 1366 let Constraints = "$src = $Rd"; 1367 } 1368 1369 def BFIxxii : A64I_bitfield<0b1, 0b01, 0b1, (outs GPR64:$Rd), 1370 (ins GPR64:$src, GPR64:$Rn, bfi64_lsb:$ImmR, bfi64_width:$ImmS), 1371 "bfi\t$Rd, $Rn, $ImmR, $ImmS", [], NoItinerary> { 1372 // As above, no disassembler allowed. 1373 let isAsmParserOnly = 1; 1374 let Constraints = "$src = $Rd"; 1375 } 1376 1377 //===----------------------------------------------------------------------===// 1378 // Compare and branch (immediate) 1379 //===----------------------------------------------------------------------===// 1380 // Contains: CBZ, CBNZ 1381 1382 class label_asmoperand<int width, int scale> : AsmOperandClass { 1383 let Name = "Label" # width # "_" # scale; 1384 let PredicateMethod = "isLabel<" # width # "," # scale # ">"; 1385 let RenderMethod = "addLabelOperands<" # width # ", " # scale # ">"; 1386 let DiagnosticType = "Label"; 1387 } 1388 1389 def label_wid19_scal4_asmoperand : label_asmoperand<19, 4>; 1390 1391 // All conditional immediate branches are the same really: 19 signed bits scaled 1392 // by the instruction-size (4). 1393 def bcc_target : Operand<OtherVT> { 1394 // This label is a 19-bit offset from PC, scaled by the instruction-width: 4. 1395 let ParserMatchClass = label_wid19_scal4_asmoperand; 1396 let PrintMethod = "printLabelOperand<19, 4>"; 1397 let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_condbr>"; 1398 let OperandType = "OPERAND_PCREL"; 1399 } 1400 1401 multiclass cmpbr_sizes<bit op, string asmop, ImmLeaf SETOP> { 1402 let isBranch = 1, isTerminator = 1 in { 1403 def x : A64I_cmpbr<0b1, op, 1404 (outs), 1405 (ins GPR64:$Rt, bcc_target:$Label), 1406 !strconcat(asmop,"\t$Rt, $Label"), 1407 [(A64br_cc (A64cmp i64:$Rt, 0), SETOP, bb:$Label)], 1408 NoItinerary>; 1409 1410 def w : A64I_cmpbr<0b0, op, 1411 (outs), 1412 (ins GPR32:$Rt, bcc_target:$Label), 1413 !strconcat(asmop,"\t$Rt, $Label"), 1414 [(A64br_cc (A64cmp i32:$Rt, 0), SETOP, bb:$Label)], 1415 NoItinerary>; 1416 } 1417 } 1418 1419 defm CBZ : cmpbr_sizes<0b0, "cbz", ImmLeaf<i32, [{ 1420 return Imm == A64CC::EQ; 1421 }]> >; 1422 defm CBNZ : cmpbr_sizes<0b1, "cbnz", ImmLeaf<i32, [{ 1423 return Imm == A64CC::NE; 1424 }]> >; 1425 1426 //===----------------------------------------------------------------------===// 1427 // Conditional branch (immediate) instructions 1428 //===----------------------------------------------------------------------===// 1429 // Contains: B.cc 1430 1431 def cond_code_asmoperand : AsmOperandClass { 1432 let Name = "CondCode"; 1433 let DiagnosticType = "CondCode"; 1434 } 1435 1436 def cond_code : Operand<i32>, ImmLeaf<i32, [{ 1437 return Imm >= 0 && Imm <= 15; 1438 }]> { 1439 let PrintMethod = "printCondCodeOperand"; 1440 let ParserMatchClass = cond_code_asmoperand; 1441 } 1442 1443 def Bcc : A64I_condbr<0b0, 0b0, (outs), 1444 (ins cond_code:$Cond, bcc_target:$Label), 1445 "b.$Cond $Label", [(A64br_cc NZCV, (i32 imm:$Cond), bb:$Label)], 1446 NoItinerary> { 1447 let Uses = [NZCV]; 1448 let isBranch = 1; 1449 let isTerminator = 1; 1450 } 1451 1452 //===----------------------------------------------------------------------===// 1453 // Conditional compare (immediate) instructions 1454 //===----------------------------------------------------------------------===// 1455 // Contains: CCMN, CCMP 1456 1457 def uimm4_asmoperand : AsmOperandClass { 1458 let Name = "UImm4"; 1459 let PredicateMethod = "isUImm<4>"; 1460 let RenderMethod = "addImmOperands"; 1461 let DiagnosticType = "UImm4"; 1462 } 1463 1464 def uimm4 : Operand<i32> { 1465 let ParserMatchClass = uimm4_asmoperand; 1466 } 1467 1468 def uimm5 : Operand<i32> { 1469 let ParserMatchClass = uimm5_asmoperand; 1470 } 1471 1472 // The only difference between this operand and the one for instructions like 1473 // B.cc is that it's parsed manually. The other get parsed implicitly as part of 1474 // the mnemonic handling. 1475 def cond_code_op_asmoperand : AsmOperandClass { 1476 let Name = "CondCodeOp"; 1477 let RenderMethod = "addCondCodeOperands"; 1478 let PredicateMethod = "isCondCode"; 1479 let ParserMethod = "ParseCondCodeOperand"; 1480 let DiagnosticType = "CondCode"; 1481 } 1482 1483 def cond_code_op : Operand<i32> { 1484 let PrintMethod = "printCondCodeOperand"; 1485 let ParserMatchClass = cond_code_op_asmoperand; 1486 } 1487 1488 class A64I_condcmpimmImpl<bit sf, bit op, RegisterClass GPR, string asmop> 1489 : A64I_condcmpimm<sf, op, 0b0, 0b0, 0b1, (outs), 1490 (ins GPR:$Rn, uimm5:$UImm5, uimm4:$NZCVImm, cond_code_op:$Cond), 1491 !strconcat(asmop, "\t$Rn, $UImm5, $NZCVImm, $Cond"), 1492 [], NoItinerary> { 1493 let Defs = [NZCV]; 1494 } 1495 1496 def CCMNwi : A64I_condcmpimmImpl<0b0, 0b0, GPR32, "ccmn">; 1497 def CCMNxi : A64I_condcmpimmImpl<0b1, 0b0, GPR64, "ccmn">; 1498 def CCMPwi : A64I_condcmpimmImpl<0b0, 0b1, GPR32, "ccmp">; 1499 def CCMPxi : A64I_condcmpimmImpl<0b1, 0b1, GPR64, "ccmp">; 1500 1501 //===----------------------------------------------------------------------===// 1502 // Conditional compare (register) instructions 1503 //===----------------------------------------------------------------------===// 1504 // Contains: CCMN, CCMP 1505 1506 class A64I_condcmpregImpl<bit sf, bit op, RegisterClass GPR, string asmop> 1507 : A64I_condcmpreg<sf, op, 0b0, 0b0, 0b1, 1508 (outs), 1509 (ins GPR:$Rn, GPR:$Rm, uimm4:$NZCVImm, cond_code_op:$Cond), 1510 !strconcat(asmop, "\t$Rn, $Rm, $NZCVImm, $Cond"), 1511 [], NoItinerary> { 1512 let Defs = [NZCV]; 1513 } 1514 1515 def CCMNww : A64I_condcmpregImpl<0b0, 0b0, GPR32, "ccmn">; 1516 def CCMNxx : A64I_condcmpregImpl<0b1, 0b0, GPR64, "ccmn">; 1517 def CCMPww : A64I_condcmpregImpl<0b0, 0b1, GPR32, "ccmp">; 1518 def CCMPxx : A64I_condcmpregImpl<0b1, 0b1, GPR64, "ccmp">; 1519 1520 //===----------------------------------------------------------------------===// 1521 // Conditional select instructions 1522 //===----------------------------------------------------------------------===// 1523 // Contains: CSEL, CSINC, CSINV, CSNEG + aliases CSET, CSETM, CINC, CINV, CNEG 1524 1525 // Condition code which is encoded as the inversion (semantically rather than 1526 // bitwise) in the instruction. 1527 def inv_cond_code_op_asmoperand : AsmOperandClass { 1528 let Name = "InvCondCodeOp"; 1529 let RenderMethod = "addInvCondCodeOperands"; 1530 let PredicateMethod = "isCondCode"; 1531 let ParserMethod = "ParseCondCodeOperand"; 1532 let DiagnosticType = "CondCode"; 1533 } 1534 1535 def inv_cond_code_op : Operand<i32> { 1536 let ParserMatchClass = inv_cond_code_op_asmoperand; 1537 } 1538 1539 // Having a separate operand for the selectable use-case is debatable, but gives 1540 // consistency with cond_code. 1541 def inv_cond_XFORM : SDNodeXForm<imm, [{ 1542 A64CC::CondCodes CC = static_cast<A64CC::CondCodes>(N->getZExtValue()); 1543 return CurDAG->getTargetConstant(A64InvertCondCode(CC), MVT::i32); 1544 }]>; 1545 1546 def inv_cond_code 1547 : ImmLeaf<i32, [{ return Imm >= 0 && Imm <= 15; }], inv_cond_XFORM>; 1548 1549 1550 multiclass A64I_condselSizes<bit op, bits<2> op2, string asmop, 1551 SDPatternOperator select> { 1552 let Uses = [NZCV] in { 1553 def wwwc : A64I_condsel<0b0, op, 0b0, op2, 1554 (outs GPR32:$Rd), 1555 (ins GPR32:$Rn, GPR32:$Rm, cond_code_op:$Cond), 1556 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Cond"), 1557 [(set i32:$Rd, (select i32:$Rn, i32:$Rm))], 1558 NoItinerary>; 1559 1560 1561 def xxxc : A64I_condsel<0b1, op, 0b0, op2, 1562 (outs GPR64:$Rd), 1563 (ins GPR64:$Rn, GPR64:$Rm, cond_code_op:$Cond), 1564 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Cond"), 1565 [(set i64:$Rd, (select i64:$Rn, i64:$Rm))], 1566 NoItinerary>; 1567 } 1568 } 1569 1570 def simple_select 1571 : PatFrag<(ops node:$lhs, node:$rhs), 1572 (A64select_cc NZCV, node:$lhs, node:$rhs, (i32 imm:$Cond))>; 1573 1574 class complex_select<SDPatternOperator opnode> 1575 : PatFrag<(ops node:$lhs, node:$rhs), 1576 (A64select_cc NZCV, node:$lhs, (opnode node:$rhs), (i32 imm:$Cond))>; 1577 1578 1579 defm CSEL : A64I_condselSizes<0b0, 0b00, "csel", simple_select>; 1580 defm CSINC : A64I_condselSizes<0b0, 0b01, "csinc", 1581 complex_select<PatFrag<(ops node:$val), 1582 (add node:$val, 1)>>>; 1583 defm CSINV : A64I_condselSizes<0b1, 0b00, "csinv", complex_select<not>>; 1584 defm CSNEG : A64I_condselSizes<0b1, 0b01, "csneg", complex_select<ineg>>; 1585 1586 // Now the instruction aliases, which fit nicely into LLVM's model: 1587 1588 def : InstAlias<"cset $Rd, $Cond", 1589 (CSINCwwwc GPR32:$Rd, WZR, WZR, inv_cond_code_op:$Cond)>; 1590 def : InstAlias<"cset $Rd, $Cond", 1591 (CSINCxxxc GPR64:$Rd, XZR, XZR, inv_cond_code_op:$Cond)>; 1592 def : InstAlias<"csetm $Rd, $Cond", 1593 (CSINVwwwc GPR32:$Rd, WZR, WZR, inv_cond_code_op:$Cond)>; 1594 def : InstAlias<"csetm $Rd, $Cond", 1595 (CSINVxxxc GPR64:$Rd, XZR, XZR, inv_cond_code_op:$Cond)>; 1596 def : InstAlias<"cinc $Rd, $Rn, $Cond", 1597 (CSINCwwwc GPR32:$Rd, GPR32:$Rn, GPR32:$Rn, inv_cond_code_op:$Cond)>; 1598 def : InstAlias<"cinc $Rd, $Rn, $Cond", 1599 (CSINCxxxc GPR64:$Rd, GPR64:$Rn, GPR64:$Rn, inv_cond_code_op:$Cond)>; 1600 def : InstAlias<"cinv $Rd, $Rn, $Cond", 1601 (CSINVwwwc GPR32:$Rd, GPR32:$Rn, GPR32:$Rn, inv_cond_code_op:$Cond)>; 1602 def : InstAlias<"cinv $Rd, $Rn, $Cond", 1603 (CSINVxxxc GPR64:$Rd, GPR64:$Rn, GPR64:$Rn, inv_cond_code_op:$Cond)>; 1604 def : InstAlias<"cneg $Rd, $Rn, $Cond", 1605 (CSNEGwwwc GPR32:$Rd, GPR32:$Rn, GPR32:$Rn, inv_cond_code_op:$Cond)>; 1606 def : InstAlias<"cneg $Rd, $Rn, $Cond", 1607 (CSNEGxxxc GPR64:$Rd, GPR64:$Rn, GPR64:$Rn, inv_cond_code_op:$Cond)>; 1608 1609 // Finally some helper patterns. 1610 1611 // For CSET (a.k.a. zero-extension of icmp) 1612 def : Pat<(A64select_cc NZCV, 0, 1, cond_code:$Cond), 1613 (CSINCwwwc WZR, WZR, cond_code:$Cond)>; 1614 def : Pat<(A64select_cc NZCV, 1, 0, inv_cond_code:$Cond), 1615 (CSINCwwwc WZR, WZR, inv_cond_code:$Cond)>; 1616 1617 def : Pat<(A64select_cc NZCV, 0, 1, cond_code:$Cond), 1618 (CSINCxxxc XZR, XZR, cond_code:$Cond)>; 1619 def : Pat<(A64select_cc NZCV, 1, 0, inv_cond_code:$Cond), 1620 (CSINCxxxc XZR, XZR, inv_cond_code:$Cond)>; 1621 1622 // For CSETM (a.k.a. sign-extension of icmp) 1623 def : Pat<(A64select_cc NZCV, 0, -1, cond_code:$Cond), 1624 (CSINVwwwc WZR, WZR, cond_code:$Cond)>; 1625 def : Pat<(A64select_cc NZCV, -1, 0, inv_cond_code:$Cond), 1626 (CSINVwwwc WZR, WZR, inv_cond_code:$Cond)>; 1627 1628 def : Pat<(A64select_cc NZCV, 0, -1, cond_code:$Cond), 1629 (CSINVxxxc XZR, XZR, cond_code:$Cond)>; 1630 def : Pat<(A64select_cc NZCV, -1, 0, inv_cond_code:$Cond), 1631 (CSINVxxxc XZR, XZR, inv_cond_code:$Cond)>; 1632 1633 // CINC, CINV and CNEG get dealt with automatically, which leaves the issue of 1634 // commutativity. The instructions are to complex for isCommutable to be used, 1635 // so we have to create the patterns manually: 1636 1637 // No commutable pattern for CSEL since the commuted version is isomorphic. 1638 1639 // CSINC 1640 def :Pat<(A64select_cc NZCV, (add i32:$Rm, 1), i32:$Rn, inv_cond_code:$Cond), 1641 (CSINCwwwc $Rn, $Rm, inv_cond_code:$Cond)>; 1642 def :Pat<(A64select_cc NZCV, (add i64:$Rm, 1), i64:$Rn, inv_cond_code:$Cond), 1643 (CSINCxxxc $Rn, $Rm, inv_cond_code:$Cond)>; 1644 1645 // CSINV 1646 def :Pat<(A64select_cc NZCV, (not i32:$Rm), i32:$Rn, inv_cond_code:$Cond), 1647 (CSINVwwwc $Rn, $Rm, inv_cond_code:$Cond)>; 1648 def :Pat<(A64select_cc NZCV, (not i64:$Rm), i64:$Rn, inv_cond_code:$Cond), 1649 (CSINVxxxc $Rn, $Rm, inv_cond_code:$Cond)>; 1650 1651 // CSNEG 1652 def :Pat<(A64select_cc NZCV, (ineg i32:$Rm), i32:$Rn, inv_cond_code:$Cond), 1653 (CSNEGwwwc $Rn, $Rm, inv_cond_code:$Cond)>; 1654 def :Pat<(A64select_cc NZCV, (ineg i64:$Rm), i64:$Rn, inv_cond_code:$Cond), 1655 (CSNEGxxxc $Rn, $Rm, inv_cond_code:$Cond)>; 1656 1657 //===----------------------------------------------------------------------===// 1658 // Data Processing (1 source) instructions 1659 //===----------------------------------------------------------------------===// 1660 // Contains: RBIT, REV16, REV, REV32, CLZ, CLS. 1661 1662 // We define an unary operator which always fails. We will use this to 1663 // define unary operators that cannot be matched. 1664 1665 class A64I_dp_1src_impl<bit sf, bits<6> opcode, string asmop, 1666 list<dag> patterns, RegisterClass GPRrc, 1667 InstrItinClass itin>: 1668 A64I_dp_1src<sf, 1669 0, 1670 0b00000, 1671 opcode, 1672 !strconcat(asmop, "\t$Rd, $Rn"), 1673 (outs GPRrc:$Rd), 1674 (ins GPRrc:$Rn), 1675 patterns, 1676 itin>; 1677 1678 multiclass A64I_dp_1src <bits<6> opcode, string asmop> { 1679 let hasSideEffects = 0 in { 1680 def ww : A64I_dp_1src_impl<0b0, opcode, asmop, [], GPR32, NoItinerary>; 1681 def xx : A64I_dp_1src_impl<0b1, opcode, asmop, [], GPR64, NoItinerary>; 1682 } 1683 } 1684 1685 defm RBIT : A64I_dp_1src<0b000000, "rbit">; 1686 defm CLS : A64I_dp_1src<0b000101, "cls">; 1687 defm CLZ : A64I_dp_1src<0b000100, "clz">; 1688 1689 def : Pat<(ctlz i32:$Rn), (CLZww $Rn)>; 1690 def : Pat<(ctlz i64:$Rn), (CLZxx $Rn)>; 1691 def : Pat<(ctlz_zero_undef i32:$Rn), (CLZww $Rn)>; 1692 def : Pat<(ctlz_zero_undef i64:$Rn), (CLZxx $Rn)>; 1693 1694 def : Pat<(cttz i32:$Rn), (CLZww (RBITww $Rn))>; 1695 def : Pat<(cttz i64:$Rn), (CLZxx (RBITxx $Rn))>; 1696 def : Pat<(cttz_zero_undef i32:$Rn), (CLZww (RBITww $Rn))>; 1697 def : Pat<(cttz_zero_undef i64:$Rn), (CLZxx (RBITxx $Rn))>; 1698 1699 1700 def REVww : A64I_dp_1src_impl<0b0, 0b000010, "rev", 1701 [(set i32:$Rd, (bswap i32:$Rn))], 1702 GPR32, NoItinerary>; 1703 def REVxx : A64I_dp_1src_impl<0b1, 0b000011, "rev", 1704 [(set i64:$Rd, (bswap i64:$Rn))], 1705 GPR64, NoItinerary>; 1706 def REV32xx : A64I_dp_1src_impl<0b1, 0b000010, "rev32", 1707 [(set i64:$Rd, (bswap (rotr i64:$Rn, (i64 32))))], 1708 GPR64, NoItinerary>; 1709 def REV16ww : A64I_dp_1src_impl<0b0, 0b000001, "rev16", 1710 [(set i32:$Rd, (bswap (rotr i32:$Rn, (i64 16))))], 1711 GPR32, 1712 NoItinerary>; 1713 def REV16xx : A64I_dp_1src_impl<0b1, 0b000001, "rev16", [], GPR64, NoItinerary>; 1714 1715 //===----------------------------------------------------------------------===// 1716 // Data Processing (2 sources) instructions 1717 //===----------------------------------------------------------------------===// 1718 // Contains: CRC32C?[BHWX], UDIV, SDIV, LSLV, LSRV, ASRV, RORV + aliases LSL, 1719 // LSR, ASR, ROR 1720 1721 1722 class dp_2src_impl<bit sf, bits<6> opcode, string asmop, list<dag> patterns, 1723 RegisterClass GPRsp, 1724 InstrItinClass itin>: 1725 A64I_dp_2src<sf, 1726 opcode, 1727 0, 1728 !strconcat(asmop, "\t$Rd, $Rn, $Rm"), 1729 (outs GPRsp:$Rd), 1730 (ins GPRsp:$Rn, GPRsp:$Rm), 1731 patterns, 1732 itin>; 1733 1734 multiclass dp_2src_crc<bit c, string asmop> { 1735 def B_www : dp_2src_impl<0b0, {0, 1, 0, c, 0, 0}, 1736 !strconcat(asmop, "b"), [], GPR32, NoItinerary>; 1737 def H_www : dp_2src_impl<0b0, {0, 1, 0, c, 0, 1}, 1738 !strconcat(asmop, "h"), [], GPR32, NoItinerary>; 1739 def W_www : dp_2src_impl<0b0, {0, 1, 0, c, 1, 0}, 1740 !strconcat(asmop, "w"), [], GPR32, NoItinerary>; 1741 def X_wwx : A64I_dp_2src<0b1, {0, 1, 0, c, 1, 1}, 0b0, 1742 !strconcat(asmop, "x\t$Rd, $Rn, $Rm"), 1743 (outs GPR32:$Rd), (ins GPR32:$Rn, GPR64:$Rm), [], 1744 NoItinerary>; 1745 } 1746 1747 multiclass dp_2src_zext <bits<6> opcode, string asmop, SDPatternOperator op> { 1748 def www : dp_2src_impl<0b0, 1749 opcode, 1750 asmop, 1751 [(set i32:$Rd, 1752 (op i32:$Rn, (i64 (zext i32:$Rm))))], 1753 GPR32, 1754 NoItinerary>; 1755 def xxx : dp_2src_impl<0b1, 1756 opcode, 1757 asmop, 1758 [(set i64:$Rd, (op i64:$Rn, i64:$Rm))], 1759 GPR64, 1760 NoItinerary>; 1761 } 1762 1763 1764 multiclass dp_2src <bits<6> opcode, string asmop, SDPatternOperator op> { 1765 def www : dp_2src_impl<0b0, 1766 opcode, 1767 asmop, 1768 [(set i32:$Rd, (op i32:$Rn, i32:$Rm))], 1769 GPR32, 1770 NoItinerary>; 1771 def xxx : dp_2src_impl<0b1, 1772 opcode, 1773 asmop, 1774 [(set i64:$Rd, (op i64:$Rn, i64:$Rm))], 1775 GPR64, 1776 NoItinerary>; 1777 } 1778 1779 // Here we define the data processing 2 source instructions. 1780 defm CRC32 : dp_2src_crc<0b0, "crc32">; 1781 defm CRC32C : dp_2src_crc<0b1, "crc32c">; 1782 1783 defm UDIV : dp_2src<0b000010, "udiv", udiv>; 1784 defm SDIV : dp_2src<0b000011, "sdiv", sdiv>; 1785 1786 defm LSLV : dp_2src_zext<0b001000, "lsl", shl>; 1787 defm LSRV : dp_2src_zext<0b001001, "lsr", srl>; 1788 defm ASRV : dp_2src_zext<0b001010, "asr", sra>; 1789 defm RORV : dp_2src_zext<0b001011, "ror", rotr>; 1790 1791 // Extra patterns for an incoming 64-bit value for a 32-bit 1792 // operation. Since the LLVM operations are undefined (as in C) if the 1793 // RHS is out of range, it's perfectly permissible to discard the high 1794 // bits of the GPR64. 1795 def : Pat<(shl i32:$Rn, i64:$Rm), 1796 (LSLVwww $Rn, (EXTRACT_SUBREG $Rm, sub_32))>; 1797 def : Pat<(srl i32:$Rn, i64:$Rm), 1798 (LSRVwww $Rn, (EXTRACT_SUBREG $Rm, sub_32))>; 1799 def : Pat<(sra i32:$Rn, i64:$Rm), 1800 (ASRVwww $Rn, (EXTRACT_SUBREG $Rm, sub_32))>; 1801 def : Pat<(rotr i32:$Rn, i64:$Rm), 1802 (RORVwww $Rn, (EXTRACT_SUBREG $Rm, sub_32))>; 1803 1804 // Here we define the aliases for the data processing 2 source instructions. 1805 def LSL_mnemonic : MnemonicAlias<"lslv", "lsl">; 1806 def LSR_mnemonic : MnemonicAlias<"lsrv", "lsr">; 1807 def ASR_menmonic : MnemonicAlias<"asrv", "asr">; 1808 def ROR_menmonic : MnemonicAlias<"rorv", "ror">; 1809 1810 //===----------------------------------------------------------------------===// 1811 // Data Processing (3 sources) instructions 1812 //===----------------------------------------------------------------------===// 1813 // Contains: MADD, MSUB, SMADDL, SMSUBL, SMULH, UMADDL, UMSUBL, UMULH 1814 // + aliases MUL, MNEG, SMULL, SMNEGL, UMULL, UMNEGL 1815 1816 class A64I_dp3_4operand<bit sf, bits<6> opcode, RegisterClass AccReg, 1817 ValueType AccTy, RegisterClass SrcReg, 1818 string asmop, dag pattern> 1819 : A64I_dp3<sf, opcode, 1820 (outs AccReg:$Rd), (ins SrcReg:$Rn, SrcReg:$Rm, AccReg:$Ra), 1821 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Ra"), 1822 [(set AccTy:$Rd, pattern)], NoItinerary> { 1823 RegisterClass AccGPR = AccReg; 1824 RegisterClass SrcGPR = SrcReg; 1825 } 1826 1827 def MADDwwww : A64I_dp3_4operand<0b0, 0b000000, GPR32, i32, GPR32, "madd", 1828 (add i32:$Ra, (mul i32:$Rn, i32:$Rm))>; 1829 def MADDxxxx : A64I_dp3_4operand<0b1, 0b000000, GPR64, i64, GPR64, "madd", 1830 (add i64:$Ra, (mul i64:$Rn, i64:$Rm))>; 1831 1832 def MSUBwwww : A64I_dp3_4operand<0b0, 0b000001, GPR32, i32, GPR32, "msub", 1833 (sub i32:$Ra, (mul i32:$Rn, i32:$Rm))>; 1834 def MSUBxxxx : A64I_dp3_4operand<0b1, 0b000001, GPR64, i64, GPR64, "msub", 1835 (sub i64:$Ra, (mul i64:$Rn, i64:$Rm))>; 1836 1837 def SMADDLxwwx : A64I_dp3_4operand<0b1, 0b000010, GPR64, i64, GPR32, "smaddl", 1838 (add i64:$Ra, (mul (i64 (sext i32:$Rn)), (sext i32:$Rm)))>; 1839 def SMSUBLxwwx : A64I_dp3_4operand<0b1, 0b000011, GPR64, i64, GPR32, "smsubl", 1840 (sub i64:$Ra, (mul (i64 (sext i32:$Rn)), (sext i32:$Rm)))>; 1841 1842 def UMADDLxwwx : A64I_dp3_4operand<0b1, 0b001010, GPR64, i64, GPR32, "umaddl", 1843 (add i64:$Ra, (mul (i64 (zext i32:$Rn)), (zext i32:$Rm)))>; 1844 def UMSUBLxwwx : A64I_dp3_4operand<0b1, 0b001011, GPR64, i64, GPR32, "umsubl", 1845 (sub i64:$Ra, (mul (i64 (zext i32:$Rn)), (zext i32:$Rm)))>; 1846 1847 let isCommutable = 1, PostEncoderMethod = "fixMulHigh" in { 1848 def UMULHxxx : A64I_dp3<0b1, 0b001100, (outs GPR64:$Rd), 1849 (ins GPR64:$Rn, GPR64:$Rm), 1850 "umulh\t$Rd, $Rn, $Rm", 1851 [(set i64:$Rd, (mulhu i64:$Rn, i64:$Rm))], 1852 NoItinerary>; 1853 1854 def SMULHxxx : A64I_dp3<0b1, 0b000100, (outs GPR64:$Rd), 1855 (ins GPR64:$Rn, GPR64:$Rm), 1856 "smulh\t$Rd, $Rn, $Rm", 1857 [(set i64:$Rd, (mulhs i64:$Rn, i64:$Rm))], 1858 NoItinerary>; 1859 } 1860 1861 multiclass A64I_dp3_3operand<string asmop, A64I_dp3_4operand INST, 1862 Register ZR, dag pattern> { 1863 def : InstAlias<asmop # " $Rd, $Rn, $Rm", 1864 (INST INST.AccGPR:$Rd, INST.SrcGPR:$Rn, INST.SrcGPR:$Rm, ZR)>; 1865 1866 def : Pat<pattern, (INST $Rn, $Rm, ZR)>; 1867 } 1868 1869 defm : A64I_dp3_3operand<"mul", MADDwwww, WZR, (mul i32:$Rn, i32:$Rm)>; 1870 defm : A64I_dp3_3operand<"mul", MADDxxxx, XZR, (mul i64:$Rn, i64:$Rm)>; 1871 1872 defm : A64I_dp3_3operand<"mneg", MSUBwwww, WZR, 1873 (sub 0, (mul i32:$Rn, i32:$Rm))>; 1874 defm : A64I_dp3_3operand<"mneg", MSUBxxxx, XZR, 1875 (sub 0, (mul i64:$Rn, i64:$Rm))>; 1876 1877 defm : A64I_dp3_3operand<"smull", SMADDLxwwx, XZR, 1878 (mul (i64 (sext i32:$Rn)), (sext i32:$Rm))>; 1879 defm : A64I_dp3_3operand<"smnegl", SMSUBLxwwx, XZR, 1880 (sub 0, (mul (i64 (sext i32:$Rn)), (sext i32:$Rm)))>; 1881 1882 defm : A64I_dp3_3operand<"umull", UMADDLxwwx, XZR, 1883 (mul (i64 (zext i32:$Rn)), (zext i32:$Rm))>; 1884 defm : A64I_dp3_3operand<"umnegl", UMSUBLxwwx, XZR, 1885 (sub 0, (mul (i64 (zext i32:$Rn)), (zext i32:$Rm)))>; 1886 1887 1888 //===----------------------------------------------------------------------===// 1889 // Exception generation 1890 //===----------------------------------------------------------------------===// 1891 // Contains: SVC, HVC, SMC, BRK, HLT, DCPS1, DCPS2, DCPS3 1892 1893 def uimm16_asmoperand : AsmOperandClass { 1894 let Name = "UImm16"; 1895 let PredicateMethod = "isUImm<16>"; 1896 let RenderMethod = "addImmOperands"; 1897 let DiagnosticType = "UImm16"; 1898 } 1899 1900 def uimm16 : Operand<i32> { 1901 let ParserMatchClass = uimm16_asmoperand; 1902 } 1903 1904 class A64I_exceptImpl<bits<3> opc, bits<2> ll, string asmop> 1905 : A64I_exception<opc, 0b000, ll, (outs), (ins uimm16:$UImm16), 1906 !strconcat(asmop, "\t$UImm16"), [], NoItinerary> { 1907 let isBranch = 1; 1908 let isTerminator = 1; 1909 } 1910 1911 def SVCi : A64I_exceptImpl<0b000, 0b01, "svc">; 1912 def HVCi : A64I_exceptImpl<0b000, 0b10, "hvc">; 1913 def SMCi : A64I_exceptImpl<0b000, 0b11, "smc">; 1914 def BRKi : A64I_exceptImpl<0b001, 0b00, "brk">; 1915 def HLTi : A64I_exceptImpl<0b010, 0b00, "hlt">; 1916 1917 def DCPS1i : A64I_exceptImpl<0b101, 0b01, "dcps1">; 1918 def DCPS2i : A64I_exceptImpl<0b101, 0b10, "dcps2">; 1919 def DCPS3i : A64I_exceptImpl<0b101, 0b11, "dcps3">; 1920 1921 // The immediate is optional for the DCPS instructions, defaulting to 0. 1922 def : InstAlias<"dcps1", (DCPS1i 0)>; 1923 def : InstAlias<"dcps2", (DCPS2i 0)>; 1924 def : InstAlias<"dcps3", (DCPS3i 0)>; 1925 1926 //===----------------------------------------------------------------------===// 1927 // Extract (immediate) 1928 //===----------------------------------------------------------------------===// 1929 // Contains: EXTR + alias ROR 1930 1931 def EXTRwwwi : A64I_extract<0b0, 0b000, 0b0, 1932 (outs GPR32:$Rd), 1933 (ins GPR32:$Rn, GPR32:$Rm, bitfield32_imm:$LSB), 1934 "extr\t$Rd, $Rn, $Rm, $LSB", 1935 [(set i32:$Rd, 1936 (A64Extr i32:$Rn, i32:$Rm, imm:$LSB))], 1937 NoItinerary>; 1938 def EXTRxxxi : A64I_extract<0b1, 0b000, 0b1, 1939 (outs GPR64:$Rd), 1940 (ins GPR64:$Rn, GPR64:$Rm, bitfield64_imm:$LSB), 1941 "extr\t$Rd, $Rn, $Rm, $LSB", 1942 [(set i64:$Rd, 1943 (A64Extr i64:$Rn, i64:$Rm, imm:$LSB))], 1944 NoItinerary>; 1945 1946 def : InstAlias<"ror $Rd, $Rs, $LSB", 1947 (EXTRwwwi GPR32:$Rd, GPR32:$Rs, GPR32:$Rs, bitfield32_imm:$LSB)>; 1948 def : InstAlias<"ror $Rd, $Rs, $LSB", 1949 (EXTRxxxi GPR64:$Rd, GPR64:$Rs, GPR64:$Rs, bitfield64_imm:$LSB)>; 1950 1951 def : Pat<(rotr i32:$Rn, bitfield32_imm:$LSB), 1952 (EXTRwwwi $Rn, $Rn, bitfield32_imm:$LSB)>; 1953 def : Pat<(rotr i64:$Rn, bitfield64_imm:$LSB), 1954 (EXTRxxxi $Rn, $Rn, bitfield64_imm:$LSB)>; 1955 1956 //===----------------------------------------------------------------------===// 1957 // Floating-point compare instructions 1958 //===----------------------------------------------------------------------===// 1959 // Contains: FCMP, FCMPE 1960 1961 def fpzero_asmoperand : AsmOperandClass { 1962 let Name = "FPZero"; 1963 let ParserMethod = "ParseFPImmOperand"; 1964 let DiagnosticType = "FPZero"; 1965 } 1966 1967 def fpz32 : Operand<f32>, 1968 ComplexPattern<f32, 1, "SelectFPZeroOperand", [fpimm]> { 1969 let ParserMatchClass = fpzero_asmoperand; 1970 let PrintMethod = "printFPZeroOperand"; 1971 let DecoderMethod = "DecodeFPZeroOperand"; 1972 } 1973 1974 def fpz64 : Operand<f64>, 1975 ComplexPattern<f64, 1, "SelectFPZeroOperand", [fpimm]> { 1976 let ParserMatchClass = fpzero_asmoperand; 1977 let PrintMethod = "printFPZeroOperand"; 1978 let DecoderMethod = "DecodeFPZeroOperand"; 1979 } 1980 1981 multiclass A64I_fpcmpSignal<bits<2> type, bit imm, dag ins, dag pattern> { 1982 def _quiet : A64I_fpcmp<0b0, 0b0, type, 0b00, {0b0, imm, 0b0, 0b0, 0b0}, 1983 (outs), ins, "fcmp\t$Rn, $Rm", [pattern], 1984 NoItinerary> { 1985 let Defs = [NZCV]; 1986 } 1987 1988 def _sig : A64I_fpcmp<0b0, 0b0, type, 0b00, {0b1, imm, 0b0, 0b0, 0b0}, 1989 (outs), ins, "fcmpe\t$Rn, $Rm", [], NoItinerary> { 1990 let Defs = [NZCV]; 1991 } 1992 } 1993 1994 defm FCMPss : A64I_fpcmpSignal<0b00, 0b0, (ins FPR32:$Rn, FPR32:$Rm), 1995 (set NZCV, (A64cmp f32:$Rn, f32:$Rm))>; 1996 defm FCMPdd : A64I_fpcmpSignal<0b01, 0b0, (ins FPR64:$Rn, FPR64:$Rm), 1997 (set NZCV, (A64cmp f64:$Rn, f64:$Rm))>; 1998 1999 // What would be Rm should be written as 0; note that even though it's called 2000 // "$Rm" here to fit in with the InstrFormats, it's actually an immediate. 2001 defm FCMPsi : A64I_fpcmpSignal<0b00, 0b1, (ins FPR32:$Rn, fpz32:$Rm), 2002 (set NZCV, (A64cmp f32:$Rn, fpz32:$Rm))>; 2003 2004 defm FCMPdi : A64I_fpcmpSignal<0b01, 0b1, (ins FPR64:$Rn, fpz64:$Rm), 2005 (set NZCV, (A64cmp f64:$Rn, fpz64:$Rm))>; 2006 2007 2008 //===----------------------------------------------------------------------===// 2009 // Floating-point conditional compare instructions 2010 //===----------------------------------------------------------------------===// 2011 // Contains: FCCMP, FCCMPE 2012 2013 class A64I_fpccmpImpl<bits<2> type, bit op, RegisterClass FPR, string asmop> 2014 : A64I_fpccmp<0b0, 0b0, type, op, 2015 (outs), 2016 (ins FPR:$Rn, FPR:$Rm, uimm4:$NZCVImm, cond_code_op:$Cond), 2017 !strconcat(asmop, "\t$Rn, $Rm, $NZCVImm, $Cond"), 2018 [], NoItinerary> { 2019 let Defs = [NZCV]; 2020 } 2021 2022 def FCCMPss : A64I_fpccmpImpl<0b00, 0b0, FPR32, "fccmp">; 2023 def FCCMPEss : A64I_fpccmpImpl<0b00, 0b1, FPR32, "fccmpe">; 2024 def FCCMPdd : A64I_fpccmpImpl<0b01, 0b0, FPR64, "fccmp">; 2025 def FCCMPEdd : A64I_fpccmpImpl<0b01, 0b1, FPR64, "fccmpe">; 2026 2027 //===----------------------------------------------------------------------===// 2028 // Floating-point conditional select instructions 2029 //===----------------------------------------------------------------------===// 2030 // Contains: FCSEL 2031 2032 let Uses = [NZCV] in { 2033 def FCSELsssc : A64I_fpcondsel<0b0, 0b0, 0b00, (outs FPR32:$Rd), 2034 (ins FPR32:$Rn, FPR32:$Rm, cond_code_op:$Cond), 2035 "fcsel\t$Rd, $Rn, $Rm, $Cond", 2036 [(set f32:$Rd, 2037 (simple_select f32:$Rn, f32:$Rm))], 2038 NoItinerary>; 2039 2040 2041 def FCSELdddc : A64I_fpcondsel<0b0, 0b0, 0b01, (outs FPR64:$Rd), 2042 (ins FPR64:$Rn, FPR64:$Rm, cond_code_op:$Cond), 2043 "fcsel\t$Rd, $Rn, $Rm, $Cond", 2044 [(set f64:$Rd, 2045 (simple_select f64:$Rn, f64:$Rm))], 2046 NoItinerary>; 2047 } 2048 2049 //===----------------------------------------------------------------------===// 2050 // Floating-point data-processing (1 source) 2051 //===----------------------------------------------------------------------===// 2052 // Contains: FMOV, FABS, FNEG, FSQRT, FCVT, FRINT[NPMZAXI]. 2053 2054 def FPNoUnop : PatFrag<(ops node:$val), (fneg node:$val), 2055 [{ (void)N; return false; }]>; 2056 2057 // First we do the fairly trivial bunch with uniform "OP s, s" and "OP d, d" 2058 // syntax. Default to no pattern because most are odd enough not to have one. 2059 multiclass A64I_fpdp1sizes<bits<6> opcode, string asmstr, 2060 SDPatternOperator opnode = FPNoUnop> { 2061 def ss : A64I_fpdp1<0b0, 0b0, 0b00, opcode, (outs FPR32:$Rd), (ins FPR32:$Rn), 2062 !strconcat(asmstr, "\t$Rd, $Rn"), 2063 [(set f32:$Rd, (opnode f32:$Rn))], 2064 NoItinerary>; 2065 2066 def dd : A64I_fpdp1<0b0, 0b0, 0b01, opcode, (outs FPR64:$Rd), (ins FPR64:$Rn), 2067 !strconcat(asmstr, "\t$Rd, $Rn"), 2068 [(set f64:$Rd, (opnode f64:$Rn))], 2069 NoItinerary>; 2070 } 2071 2072 defm FMOV : A64I_fpdp1sizes<0b000000, "fmov">; 2073 defm FABS : A64I_fpdp1sizes<0b000001, "fabs", fabs>; 2074 defm FNEG : A64I_fpdp1sizes<0b000010, "fneg", fneg>; 2075 defm FSQRT : A64I_fpdp1sizes<0b000011, "fsqrt", fsqrt>; 2076 2077 defm FRINTN : A64I_fpdp1sizes<0b001000, "frintn">; 2078 defm FRINTP : A64I_fpdp1sizes<0b001001, "frintp", fceil>; 2079 defm FRINTM : A64I_fpdp1sizes<0b001010, "frintm", ffloor>; 2080 defm FRINTZ : A64I_fpdp1sizes<0b001011, "frintz", ftrunc>; 2081 defm FRINTA : A64I_fpdp1sizes<0b001100, "frinta">; 2082 defm FRINTX : A64I_fpdp1sizes<0b001110, "frintx", frint>; 2083 defm FRINTI : A64I_fpdp1sizes<0b001111, "frinti", fnearbyint>; 2084 2085 // The FCVT instrucitons have different source and destination register-types, 2086 // but the fields are uniform everywhere a D-register (say) crops up. Package 2087 // this information in a Record. 2088 class FCVTRegType<RegisterClass rc, bits<2> fld, ValueType vt> { 2089 RegisterClass Class = rc; 2090 ValueType VT = vt; 2091 bit t1 = fld{1}; 2092 bit t0 = fld{0}; 2093 } 2094 2095 def FCVT16 : FCVTRegType<FPR16, 0b11, f16>; 2096 def FCVT32 : FCVTRegType<FPR32, 0b00, f32>; 2097 def FCVT64 : FCVTRegType<FPR64, 0b01, f64>; 2098 2099 class A64I_fpdp1_fcvt<FCVTRegType DestReg, FCVTRegType SrcReg, SDNode opnode> 2100 : A64I_fpdp1<0b0, 0b0, {SrcReg.t1, SrcReg.t0}, 2101 {0,0,0,1, DestReg.t1, DestReg.t0}, 2102 (outs DestReg.Class:$Rd), (ins SrcReg.Class:$Rn), 2103 "fcvt\t$Rd, $Rn", 2104 [(set DestReg.VT:$Rd, (opnode SrcReg.VT:$Rn))], NoItinerary>; 2105 2106 def FCVTds : A64I_fpdp1_fcvt<FCVT64, FCVT32, fextend>; 2107 def FCVThs : A64I_fpdp1_fcvt<FCVT16, FCVT32, fround>; 2108 def FCVTsd : A64I_fpdp1_fcvt<FCVT32, FCVT64, fround>; 2109 def FCVThd : A64I_fpdp1_fcvt<FCVT16, FCVT64, fround>; 2110 def FCVTsh : A64I_fpdp1_fcvt<FCVT32, FCVT16, fextend>; 2111 def FCVTdh : A64I_fpdp1_fcvt<FCVT64, FCVT16, fextend>; 2112 2113 2114 //===----------------------------------------------------------------------===// 2115 // Floating-point data-processing (2 sources) instructions 2116 //===----------------------------------------------------------------------===// 2117 // Contains: FMUL, FDIV, FADD, FSUB, FMAX, FMIN, FMAXNM, FMINNM, FNMUL 2118 2119 def FPNoBinop : PatFrag<(ops node:$lhs, node:$rhs), (fadd node:$lhs, node:$rhs), 2120 [{ (void)N; return false; }]>; 2121 2122 multiclass A64I_fpdp2sizes<bits<4> opcode, string asmstr, 2123 SDPatternOperator opnode> { 2124 def sss : A64I_fpdp2<0b0, 0b0, 0b00, opcode, 2125 (outs FPR32:$Rd), 2126 (ins FPR32:$Rn, FPR32:$Rm), 2127 !strconcat(asmstr, "\t$Rd, $Rn, $Rm"), 2128 [(set f32:$Rd, (opnode f32:$Rn, f32:$Rm))], 2129 NoItinerary>; 2130 2131 def ddd : A64I_fpdp2<0b0, 0b0, 0b01, opcode, 2132 (outs FPR64:$Rd), 2133 (ins FPR64:$Rn, FPR64:$Rm), 2134 !strconcat(asmstr, "\t$Rd, $Rn, $Rm"), 2135 [(set f64:$Rd, (opnode f64:$Rn, f64:$Rm))], 2136 NoItinerary>; 2137 } 2138 2139 let isCommutable = 1 in { 2140 defm FMUL : A64I_fpdp2sizes<0b0000, "fmul", fmul>; 2141 defm FADD : A64I_fpdp2sizes<0b0010, "fadd", fadd>; 2142 2143 // No patterns for these. 2144 defm FMAX : A64I_fpdp2sizes<0b0100, "fmax", FPNoBinop>; 2145 defm FMIN : A64I_fpdp2sizes<0b0101, "fmin", FPNoBinop>; 2146 defm FMAXNM : A64I_fpdp2sizes<0b0110, "fmaxnm", FPNoBinop>; 2147 defm FMINNM : A64I_fpdp2sizes<0b0111, "fminnm", FPNoBinop>; 2148 2149 defm FNMUL : A64I_fpdp2sizes<0b1000, "fnmul", 2150 PatFrag<(ops node:$lhs, node:$rhs), 2151 (fneg (fmul node:$lhs, node:$rhs))> >; 2152 } 2153 2154 defm FDIV : A64I_fpdp2sizes<0b0001, "fdiv", fdiv>; 2155 defm FSUB : A64I_fpdp2sizes<0b0011, "fsub", fsub>; 2156 2157 //===----------------------------------------------------------------------===// 2158 // Floating-point data-processing (3 sources) instructions 2159 //===----------------------------------------------------------------------===// 2160 // Contains: FMADD, FMSUB, FNMADD, FNMSUB 2161 2162 def fmsub : PatFrag<(ops node:$Rn, node:$Rm, node:$Ra), 2163 (fma (fneg node:$Rn), node:$Rm, node:$Ra)>; 2164 def fnmadd : PatFrag<(ops node:$Rn, node:$Rm, node:$Ra), 2165 (fma node:$Rn, node:$Rm, (fneg node:$Ra))>; 2166 def fnmsub : PatFrag<(ops node:$Rn, node:$Rm, node:$Ra), 2167 (fma (fneg node:$Rn), node:$Rm, (fneg node:$Ra))>; 2168 2169 class A64I_fpdp3Impl<string asmop, RegisterClass FPR, ValueType VT, 2170 bits<2> type, bit o1, bit o0, SDPatternOperator fmakind> 2171 : A64I_fpdp3<0b0, 0b0, type, o1, o0, (outs FPR:$Rd), 2172 (ins FPR:$Rn, FPR:$Rm, FPR:$Ra), 2173 !strconcat(asmop,"\t$Rd, $Rn, $Rm, $Ra"), 2174 [(set VT:$Rd, (fmakind VT:$Rn, VT:$Rm, VT:$Ra))], 2175 NoItinerary>; 2176 2177 def FMADDssss : A64I_fpdp3Impl<"fmadd", FPR32, f32, 0b00, 0b0, 0b0, fma>; 2178 def FMSUBssss : A64I_fpdp3Impl<"fmsub", FPR32, f32, 0b00, 0b0, 0b1, fmsub>; 2179 def FNMADDssss : A64I_fpdp3Impl<"fnmadd", FPR32, f32, 0b00, 0b1, 0b0, fnmadd>; 2180 def FNMSUBssss : A64I_fpdp3Impl<"fnmsub", FPR32, f32, 0b00, 0b1, 0b1, fnmsub>; 2181 2182 def FMADDdddd : A64I_fpdp3Impl<"fmadd", FPR64, f64, 0b01, 0b0, 0b0, fma>; 2183 def FMSUBdddd : A64I_fpdp3Impl<"fmsub", FPR64, f64, 0b01, 0b0, 0b1, fmsub>; 2184 def FNMADDdddd : A64I_fpdp3Impl<"fnmadd", FPR64, f64, 0b01, 0b1, 0b0, fnmadd>; 2185 def FNMSUBdddd : A64I_fpdp3Impl<"fnmsub", FPR64, f64, 0b01, 0b1, 0b1, fnmsub>; 2186 2187 // Extra patterns for when we're allowed to optimise separate multiplication and 2188 // addition. 2189 let Predicates = [UseFusedMAC] in { 2190 def : Pat<(fadd FPR32:$Ra, (fmul FPR32:$Rn, FPR32:$Rm)), 2191 (FMADDssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>; 2192 def : Pat<(fsub FPR32:$Ra, (fmul FPR32:$Rn, FPR32:$Rm)), 2193 (FMSUBssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>; 2194 def : Pat<(fsub (fmul FPR32:$Rn, FPR32:$Rm), FPR32:$Ra), 2195 (FNMADDssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>; 2196 def : Pat<(fsub (fneg FPR32:$Ra), (fmul FPR32:$Rn, FPR32:$Rm)), 2197 (FNMSUBssss FPR32:$Rn, FPR32:$Rm, FPR32:$Ra)>; 2198 2199 def : Pat<(fadd FPR64:$Ra, (fmul FPR64:$Rn, FPR64:$Rm)), 2200 (FMADDdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>; 2201 def : Pat<(fsub FPR64:$Ra, (fmul FPR64:$Rn, FPR64:$Rm)), 2202 (FMSUBdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>; 2203 def : Pat<(fsub (fmul FPR64:$Rn, FPR64:$Rm), FPR64:$Ra), 2204 (FNMADDdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>; 2205 def : Pat<(fsub (fneg FPR64:$Ra), (fmul FPR64:$Rn, FPR64:$Rm)), 2206 (FNMSUBdddd FPR64:$Rn, FPR64:$Rm, FPR64:$Ra)>; 2207 } 2208 2209 2210 //===----------------------------------------------------------------------===// 2211 // Floating-point <-> fixed-point conversion instructions 2212 //===----------------------------------------------------------------------===// 2213 // Contains: FCVTZS, FCVTZU, SCVTF, UCVTF 2214 2215 // #1-#32 allowed, encoded as "64 - <specified imm> 2216 def fixedpos_asmoperand_i32 : AsmOperandClass { 2217 let Name = "CVTFixedPos32"; 2218 let RenderMethod = "addCVTFixedPosOperands"; 2219 let PredicateMethod = "isCVTFixedPos<32>"; 2220 let DiagnosticType = "CVTFixedPos32"; 2221 } 2222 2223 // Also encoded as "64 - <specified imm>" but #1-#64 allowed. 2224 def fixedpos_asmoperand_i64 : AsmOperandClass { 2225 let Name = "CVTFixedPos64"; 2226 let RenderMethod = "addCVTFixedPosOperands"; 2227 let PredicateMethod = "isCVTFixedPos<64>"; 2228 let DiagnosticType = "CVTFixedPos64"; 2229 } 2230 2231 // We need the cartesian product of f32/f64 i32/i64 operands for 2232 // conversions: 2233 // + Selection needs to use operands of correct floating type 2234 // + Assembly parsing and decoding depend on integer width 2235 class cvtfix_i32_op<ValueType FloatVT> 2236 : Operand<FloatVT>, 2237 ComplexPattern<FloatVT, 1, "SelectCVTFixedPosOperand<32>", [fpimm]> { 2238 let ParserMatchClass = fixedpos_asmoperand_i32; 2239 let DecoderMethod = "DecodeCVT32FixedPosOperand"; 2240 let PrintMethod = "printCVTFixedPosOperand"; 2241 } 2242 2243 class cvtfix_i64_op<ValueType FloatVT> 2244 : Operand<FloatVT>, 2245 ComplexPattern<FloatVT, 1, "SelectCVTFixedPosOperand<64>", [fpimm]> { 2246 let ParserMatchClass = fixedpos_asmoperand_i64; 2247 let PrintMethod = "printCVTFixedPosOperand"; 2248 } 2249 2250 // Because of the proliferation of weird operands, it's not really 2251 // worth going for a multiclass here. Oh well. 2252 2253 class A64I_fptofix<bit sf, bits<2> type, bits<3> opcode, 2254 RegisterClass GPR, RegisterClass FPR, 2255 ValueType DstTy, ValueType SrcTy, 2256 Operand scale_op, string asmop, SDNode cvtop> 2257 : A64I_fpfixed<sf, 0b0, type, 0b11, opcode, 2258 (outs GPR:$Rd), (ins FPR:$Rn, scale_op:$Scale), 2259 !strconcat(asmop, "\t$Rd, $Rn, $Scale"), 2260 [(set DstTy:$Rd, (cvtop (fmul SrcTy:$Rn, scale_op:$Scale)))], 2261 NoItinerary>; 2262 2263 def FCVTZSwsi : A64I_fptofix<0b0, 0b00, 0b000, GPR32, FPR32, i32, f32, 2264 cvtfix_i32_op<f32>, "fcvtzs", fp_to_sint>; 2265 def FCVTZSxsi : A64I_fptofix<0b1, 0b00, 0b000, GPR64, FPR32, i64, f32, 2266 cvtfix_i64_op<f32>, "fcvtzs", fp_to_sint>; 2267 def FCVTZUwsi : A64I_fptofix<0b0, 0b00, 0b001, GPR32, FPR32, i32, f32, 2268 cvtfix_i32_op<f32>, "fcvtzu", fp_to_uint>; 2269 def FCVTZUxsi : A64I_fptofix<0b1, 0b00, 0b001, GPR64, FPR32, i64, f32, 2270 cvtfix_i64_op<f32>, "fcvtzu", fp_to_uint>; 2271 2272 def FCVTZSwdi : A64I_fptofix<0b0, 0b01, 0b000, GPR32, FPR64, i32, f64, 2273 cvtfix_i32_op<f64>, "fcvtzs", fp_to_sint>; 2274 def FCVTZSxdi : A64I_fptofix<0b1, 0b01, 0b000, GPR64, FPR64, i64, f64, 2275 cvtfix_i64_op<f64>, "fcvtzs", fp_to_sint>; 2276 def FCVTZUwdi : A64I_fptofix<0b0, 0b01, 0b001, GPR32, FPR64, i32, f64, 2277 cvtfix_i32_op<f64>, "fcvtzu", fp_to_uint>; 2278 def FCVTZUxdi : A64I_fptofix<0b1, 0b01, 0b001, GPR64, FPR64, i64, f64, 2279 cvtfix_i64_op<f64>, "fcvtzu", fp_to_uint>; 2280 2281 2282 class A64I_fixtofp<bit sf, bits<2> type, bits<3> opcode, 2283 RegisterClass FPR, RegisterClass GPR, 2284 ValueType DstTy, ValueType SrcTy, 2285 Operand scale_op, string asmop, SDNode cvtop> 2286 : A64I_fpfixed<sf, 0b0, type, 0b00, opcode, 2287 (outs FPR:$Rd), (ins GPR:$Rn, scale_op:$Scale), 2288 !strconcat(asmop, "\t$Rd, $Rn, $Scale"), 2289 [(set DstTy:$Rd, (fdiv (cvtop SrcTy:$Rn), scale_op:$Scale))], 2290 NoItinerary>; 2291 2292 def SCVTFswi : A64I_fixtofp<0b0, 0b00, 0b010, FPR32, GPR32, f32, i32, 2293 cvtfix_i32_op<f32>, "scvtf", sint_to_fp>; 2294 def SCVTFsxi : A64I_fixtofp<0b1, 0b00, 0b010, FPR32, GPR64, f32, i64, 2295 cvtfix_i64_op<f32>, "scvtf", sint_to_fp>; 2296 def UCVTFswi : A64I_fixtofp<0b0, 0b00, 0b011, FPR32, GPR32, f32, i32, 2297 cvtfix_i32_op<f32>, "ucvtf", uint_to_fp>; 2298 def UCVTFsxi : A64I_fixtofp<0b1, 0b00, 0b011, FPR32, GPR64, f32, i64, 2299 cvtfix_i64_op<f32>, "ucvtf", uint_to_fp>; 2300 def SCVTFdwi : A64I_fixtofp<0b0, 0b01, 0b010, FPR64, GPR32, f64, i32, 2301 cvtfix_i32_op<f64>, "scvtf", sint_to_fp>; 2302 def SCVTFdxi : A64I_fixtofp<0b1, 0b01, 0b010, FPR64, GPR64, f64, i64, 2303 cvtfix_i64_op<f64>, "scvtf", sint_to_fp>; 2304 def UCVTFdwi : A64I_fixtofp<0b0, 0b01, 0b011, FPR64, GPR32, f64, i32, 2305 cvtfix_i32_op<f64>, "ucvtf", uint_to_fp>; 2306 def UCVTFdxi : A64I_fixtofp<0b1, 0b01, 0b011, FPR64, GPR64, f64, i64, 2307 cvtfix_i64_op<f64>, "ucvtf", uint_to_fp>; 2308 2309 //===----------------------------------------------------------------------===// 2310 // Floating-point <-> integer conversion instructions 2311 //===----------------------------------------------------------------------===// 2312 // Contains: FCVTZS, FCVTZU, SCVTF, UCVTF 2313 2314 class A64I_fpintI<bit sf, bits<2> type, bits<2> rmode, bits<3> opcode, 2315 RegisterClass DestPR, RegisterClass SrcPR, string asmop> 2316 : A64I_fpint<sf, 0b0, type, rmode, opcode, (outs DestPR:$Rd), (ins SrcPR:$Rn), 2317 !strconcat(asmop, "\t$Rd, $Rn"), [], NoItinerary>; 2318 2319 multiclass A64I_fptointRM<bits<2> rmode, bit o2, string asmop> { 2320 def Sws : A64I_fpintI<0b0, 0b00, rmode, {o2, 0, 0}, 2321 GPR32, FPR32, asmop # "s">; 2322 def Sxs : A64I_fpintI<0b1, 0b00, rmode, {o2, 0, 0}, 2323 GPR64, FPR32, asmop # "s">; 2324 def Uws : A64I_fpintI<0b0, 0b00, rmode, {o2, 0, 1}, 2325 GPR32, FPR32, asmop # "u">; 2326 def Uxs : A64I_fpintI<0b1, 0b00, rmode, {o2, 0, 1}, 2327 GPR64, FPR32, asmop # "u">; 2328 2329 def Swd : A64I_fpintI<0b0, 0b01, rmode, {o2, 0, 0}, 2330 GPR32, FPR64, asmop # "s">; 2331 def Sxd : A64I_fpintI<0b1, 0b01, rmode, {o2, 0, 0}, 2332 GPR64, FPR64, asmop # "s">; 2333 def Uwd : A64I_fpintI<0b0, 0b01, rmode, {o2, 0, 1}, 2334 GPR32, FPR64, asmop # "u">; 2335 def Uxd : A64I_fpintI<0b1, 0b01, rmode, {o2, 0, 1}, 2336 GPR64, FPR64, asmop # "u">; 2337 } 2338 2339 defm FCVTN : A64I_fptointRM<0b00, 0b0, "fcvtn">; 2340 defm FCVTP : A64I_fptointRM<0b01, 0b0, "fcvtp">; 2341 defm FCVTM : A64I_fptointRM<0b10, 0b0, "fcvtm">; 2342 defm FCVTZ : A64I_fptointRM<0b11, 0b0, "fcvtz">; 2343 defm FCVTA : A64I_fptointRM<0b00, 0b1, "fcvta">; 2344 2345 def : Pat<(i32 (fp_to_sint f32:$Rn)), (FCVTZSws $Rn)>; 2346 def : Pat<(i64 (fp_to_sint f32:$Rn)), (FCVTZSxs $Rn)>; 2347 def : Pat<(i32 (fp_to_uint f32:$Rn)), (FCVTZUws $Rn)>; 2348 def : Pat<(i64 (fp_to_uint f32:$Rn)), (FCVTZUxs $Rn)>; 2349 def : Pat<(i32 (fp_to_sint f64:$Rn)), (FCVTZSwd $Rn)>; 2350 def : Pat<(i64 (fp_to_sint f64:$Rn)), (FCVTZSxd $Rn)>; 2351 def : Pat<(i32 (fp_to_uint f64:$Rn)), (FCVTZUwd $Rn)>; 2352 def : Pat<(i64 (fp_to_uint f64:$Rn)), (FCVTZUxd $Rn)>; 2353 2354 multiclass A64I_inttofp<bit o0, string asmop> { 2355 def CVTFsw : A64I_fpintI<0b0, 0b00, 0b00, {0, 1, o0}, FPR32, GPR32, asmop>; 2356 def CVTFsx : A64I_fpintI<0b1, 0b00, 0b00, {0, 1, o0}, FPR32, GPR64, asmop>; 2357 def CVTFdw : A64I_fpintI<0b0, 0b01, 0b00, {0, 1, o0}, FPR64, GPR32, asmop>; 2358 def CVTFdx : A64I_fpintI<0b1, 0b01, 0b00, {0, 1, o0}, FPR64, GPR64, asmop>; 2359 } 2360 2361 defm S : A64I_inttofp<0b0, "scvtf">; 2362 defm U : A64I_inttofp<0b1, "ucvtf">; 2363 2364 def : Pat<(f32 (sint_to_fp i32:$Rn)), (SCVTFsw $Rn)>; 2365 def : Pat<(f32 (sint_to_fp i64:$Rn)), (SCVTFsx $Rn)>; 2366 def : Pat<(f64 (sint_to_fp i32:$Rn)), (SCVTFdw $Rn)>; 2367 def : Pat<(f64 (sint_to_fp i64:$Rn)), (SCVTFdx $Rn)>; 2368 def : Pat<(f32 (uint_to_fp i32:$Rn)), (UCVTFsw $Rn)>; 2369 def : Pat<(f32 (uint_to_fp i64:$Rn)), (UCVTFsx $Rn)>; 2370 def : Pat<(f64 (uint_to_fp i32:$Rn)), (UCVTFdw $Rn)>; 2371 def : Pat<(f64 (uint_to_fp i64:$Rn)), (UCVTFdx $Rn)>; 2372 2373 def FMOVws : A64I_fpintI<0b0, 0b00, 0b00, 0b110, GPR32, FPR32, "fmov">; 2374 def FMOVsw : A64I_fpintI<0b0, 0b00, 0b00, 0b111, FPR32, GPR32, "fmov">; 2375 def FMOVxd : A64I_fpintI<0b1, 0b01, 0b00, 0b110, GPR64, FPR64, "fmov">; 2376 def FMOVdx : A64I_fpintI<0b1, 0b01, 0b00, 0b111, FPR64, GPR64, "fmov">; 2377 2378 def : Pat<(i32 (bitconvert f32:$Rn)), (FMOVws $Rn)>; 2379 def : Pat<(f32 (bitconvert i32:$Rn)), (FMOVsw $Rn)>; 2380 def : Pat<(i64 (bitconvert f64:$Rn)), (FMOVxd $Rn)>; 2381 def : Pat<(f64 (bitconvert i64:$Rn)), (FMOVdx $Rn)>; 2382 2383 def lane1_asmoperand : AsmOperandClass { 2384 let Name = "Lane1"; 2385 let RenderMethod = "addImmOperands"; 2386 let DiagnosticType = "Lane1"; 2387 } 2388 2389 def lane1 : Operand<i32> { 2390 let ParserMatchClass = lane1_asmoperand; 2391 let PrintMethod = "printBareImmOperand"; 2392 } 2393 2394 let DecoderMethod = "DecodeFMOVLaneInstruction" in { 2395 def FMOVxv : A64I_fpint<0b1, 0b0, 0b10, 0b01, 0b110, 2396 (outs GPR64:$Rd), (ins VPR128:$Rn, lane1:$Lane), 2397 "fmov\t$Rd, $Rn.d[$Lane]", [], NoItinerary>; 2398 2399 def FMOVvx : A64I_fpint<0b1, 0b0, 0b10, 0b01, 0b111, 2400 (outs VPR128:$Rd), (ins GPR64:$Rn, lane1:$Lane), 2401 "fmov\t$Rd.d[$Lane], $Rn", [], NoItinerary>; 2402 } 2403 2404 def : InstAlias<"fmov $Rd, $Rn.2d[$Lane]", 2405 (FMOVxv GPR64:$Rd, VPR128:$Rn, lane1:$Lane), 0b0>; 2406 2407 def : InstAlias<"fmov $Rd.2d[$Lane], $Rn", 2408 (FMOVvx VPR128:$Rd, GPR64:$Rn, lane1:$Lane), 0b0>; 2409 2410 //===----------------------------------------------------------------------===// 2411 // Floating-point immediate instructions 2412 //===----------------------------------------------------------------------===// 2413 // Contains: FMOV 2414 2415 def fpimm_asmoperand : AsmOperandClass { 2416 let Name = "FMOVImm"; 2417 let ParserMethod = "ParseFPImmOperand"; 2418 let DiagnosticType = "FPImm"; 2419 } 2420 2421 // The MCOperand for these instructions are the encoded 8-bit values. 2422 def SDXF_fpimm : SDNodeXForm<fpimm, [{ 2423 uint32_t Imm8; 2424 A64Imms::isFPImm(N->getValueAPF(), Imm8); 2425 return CurDAG->getTargetConstant(Imm8, MVT::i32); 2426 }]>; 2427 2428 class fmov_operand<ValueType FT> 2429 : Operand<i32>, 2430 PatLeaf<(FT fpimm), [{ return A64Imms::isFPImm(N->getValueAPF()); }], 2431 SDXF_fpimm> { 2432 let PrintMethod = "printFPImmOperand"; 2433 let ParserMatchClass = fpimm_asmoperand; 2434 } 2435 2436 def fmov32_operand : fmov_operand<f32>; 2437 def fmov64_operand : fmov_operand<f64>; 2438 2439 class A64I_fpimm_impl<bits<2> type, RegisterClass Reg, ValueType VT, 2440 Operand fmov_operand> 2441 : A64I_fpimm<0b0, 0b0, type, 0b00000, 2442 (outs Reg:$Rd), 2443 (ins fmov_operand:$Imm8), 2444 "fmov\t$Rd, $Imm8", 2445 [(set VT:$Rd, fmov_operand:$Imm8)], 2446 NoItinerary>; 2447 2448 def FMOVsi : A64I_fpimm_impl<0b00, FPR32, f32, fmov32_operand>; 2449 def FMOVdi : A64I_fpimm_impl<0b01, FPR64, f64, fmov64_operand>; 2450 2451 //===----------------------------------------------------------------------===// 2452 // Load-register (literal) instructions 2453 //===----------------------------------------------------------------------===// 2454 // Contains: LDR, LDRSW, PRFM 2455 2456 def ldrlit_label_asmoperand : AsmOperandClass { 2457 let Name = "LoadLitLabel"; 2458 let RenderMethod = "addLabelOperands<19, 4>"; 2459 let DiagnosticType = "Label"; 2460 } 2461 2462 def ldrlit_label : Operand<i64> { 2463 let EncoderMethod = "getLoadLitLabelOpValue"; 2464 2465 // This label is a 19-bit offset from PC, scaled by the instruction-width: 4. 2466 let PrintMethod = "printLabelOperand<19, 4>"; 2467 let ParserMatchClass = ldrlit_label_asmoperand; 2468 let OperandType = "OPERAND_PCREL"; 2469 } 2470 2471 // Various instructions take an immediate value (which can always be used), 2472 // where some numbers have a symbolic name to make things easier. These operands 2473 // and the associated functions abstract away the differences. 2474 multiclass namedimm<string prefix, string mapper> { 2475 def _asmoperand : AsmOperandClass { 2476 let Name = "NamedImm" # prefix; 2477 let PredicateMethod = "isUImm"; 2478 let RenderMethod = "addImmOperands"; 2479 let ParserMethod = "ParseNamedImmOperand<" # mapper # ">"; 2480 let DiagnosticType = "NamedImm_" # prefix; 2481 } 2482 2483 def _op : Operand<i32> { 2484 let ParserMatchClass = !cast<AsmOperandClass>(prefix # "_asmoperand"); 2485 let PrintMethod = "printNamedImmOperand<" # mapper # ">"; 2486 let DecoderMethod = "DecodeNamedImmOperand<" # mapper # ">"; 2487 } 2488 } 2489 2490 defm prefetch : namedimm<"prefetch", "A64PRFM::PRFMMapper">; 2491 2492 class A64I_LDRlitSimple<bits<2> opc, bit v, RegisterClass OutReg, 2493 list<dag> patterns = []> 2494 : A64I_LDRlit<opc, v, (outs OutReg:$Rt), (ins ldrlit_label:$Imm19), 2495 "ldr\t$Rt, $Imm19", patterns, NoItinerary>; 2496 2497 let mayLoad = 1 in { 2498 def LDRw_lit : A64I_LDRlitSimple<0b00, 0b0, GPR32>; 2499 def LDRx_lit : A64I_LDRlitSimple<0b01, 0b0, GPR64>; 2500 } 2501 2502 def LDRs_lit : A64I_LDRlitSimple<0b00, 0b1, FPR32>; 2503 def LDRd_lit : A64I_LDRlitSimple<0b01, 0b1, FPR64>; 2504 2505 let mayLoad = 1 in { 2506 def LDRq_lit : A64I_LDRlitSimple<0b10, 0b1, FPR128>; 2507 2508 2509 def LDRSWx_lit : A64I_LDRlit<0b10, 0b0, 2510 (outs GPR64:$Rt), 2511 (ins ldrlit_label:$Imm19), 2512 "ldrsw\t$Rt, $Imm19", 2513 [], NoItinerary>; 2514 2515 def PRFM_lit : A64I_LDRlit<0b11, 0b0, 2516 (outs), (ins prefetch_op:$Rt, ldrlit_label:$Imm19), 2517 "prfm\t$Rt, $Imm19", 2518 [], NoItinerary>; 2519 } 2520 2521 //===----------------------------------------------------------------------===// 2522 // Load-store exclusive instructions 2523 //===----------------------------------------------------------------------===// 2524 // Contains: STXRB, STXRH, STXR, LDXRB, LDXRH, LDXR. STXP, LDXP, STLXRB, 2525 // STLXRH, STLXR, LDAXRB, LDAXRH, LDAXR, STLXP, LDAXP, STLRB, 2526 // STLRH, STLR, LDARB, LDARH, LDAR 2527 2528 // Since these instructions have the undefined register bits set to 1 in 2529 // their canonical form, we need a post encoder method to set those bits 2530 // to 1 when encoding these instructions. We do this using the 2531 // fixLoadStoreExclusive function. This function has template parameters: 2532 // 2533 // fixLoadStoreExclusive<int hasRs, int hasRt2> 2534 // 2535 // hasRs indicates that the instruction uses the Rs field, so we won't set 2536 // it to 1 (and the same for Rt2). We don't need template parameters for 2537 // the other register fiels since Rt and Rn are always used. 2538 2539 // This operand parses a GPR64xsp register, followed by an optional immediate 2540 // #0. 2541 def GPR64xsp0_asmoperand : AsmOperandClass { 2542 let Name = "GPR64xsp0"; 2543 let PredicateMethod = "isWrappedReg"; 2544 let RenderMethod = "addRegOperands"; 2545 let ParserMethod = "ParseLSXAddressOperand"; 2546 // Diagnostics are provided by ParserMethod 2547 } 2548 2549 def GPR64xsp0 : RegisterOperand<GPR64xsp> { 2550 let ParserMatchClass = GPR64xsp0_asmoperand; 2551 } 2552 2553 //===---------------------------------- 2554 // Store-exclusive (releasing & normal) 2555 //===---------------------------------- 2556 2557 class A64I_SRexs_impl<bits<2> size, bits<3> opcode, string asm, dag outs, 2558 dag ins, list<dag> pat, 2559 InstrItinClass itin> : 2560 A64I_LDSTex_stn <size, 2561 opcode{2}, 0, opcode{1}, opcode{0}, 2562 outs, ins, 2563 !strconcat(asm, "\t$Rs, $Rt, [$Rn]"), 2564 pat, itin> { 2565 let mayStore = 1; 2566 let PostEncoderMethod = "fixLoadStoreExclusive<1,0>"; 2567 } 2568 2569 multiclass A64I_SRex<string asmstr, bits<3> opcode, string prefix> { 2570 def _byte: A64I_SRexs_impl<0b00, opcode, !strconcat(asmstr, "b"), 2571 (outs GPR32:$Rs), (ins GPR32:$Rt, GPR64xsp0:$Rn), 2572 [], NoItinerary>; 2573 2574 def _hword: A64I_SRexs_impl<0b01, opcode, !strconcat(asmstr, "h"), 2575 (outs GPR32:$Rs), (ins GPR32:$Rt, GPR64xsp0:$Rn), 2576 [],NoItinerary>; 2577 2578 def _word: A64I_SRexs_impl<0b10, opcode, asmstr, 2579 (outs GPR32:$Rs), (ins GPR32:$Rt, GPR64xsp0:$Rn), 2580 [], NoItinerary>; 2581 2582 def _dword: A64I_SRexs_impl<0b11, opcode, asmstr, 2583 (outs GPR32:$Rs), (ins GPR64:$Rt, GPR64xsp0:$Rn), 2584 [], NoItinerary>; 2585 } 2586 2587 defm STXR : A64I_SRex<"stxr", 0b000, "STXR">; 2588 defm STLXR : A64I_SRex<"stlxr", 0b001, "STLXR">; 2589 2590 //===---------------------------------- 2591 // Loads 2592 //===---------------------------------- 2593 2594 class A64I_LRexs_impl<bits<2> size, bits<3> opcode, string asm, dag outs, 2595 dag ins, list<dag> pat, 2596 InstrItinClass itin> : 2597 A64I_LDSTex_tn <size, 2598 opcode{2}, 1, opcode{1}, opcode{0}, 2599 outs, ins, 2600 !strconcat(asm, "\t$Rt, [$Rn]"), 2601 pat, itin> { 2602 let mayLoad = 1; 2603 let PostEncoderMethod = "fixLoadStoreExclusive<0,0>"; 2604 } 2605 2606 multiclass A64I_LRex<string asmstr, bits<3> opcode> { 2607 def _byte: A64I_LRexs_impl<0b00, opcode, !strconcat(asmstr, "b"), 2608 (outs GPR32:$Rt), (ins GPR64xsp0:$Rn), 2609 [], NoItinerary>; 2610 2611 def _hword: A64I_LRexs_impl<0b01, opcode, !strconcat(asmstr, "h"), 2612 (outs GPR32:$Rt), (ins GPR64xsp0:$Rn), 2613 [], NoItinerary>; 2614 2615 def _word: A64I_LRexs_impl<0b10, opcode, asmstr, 2616 (outs GPR32:$Rt), (ins GPR64xsp0:$Rn), 2617 [], NoItinerary>; 2618 2619 def _dword: A64I_LRexs_impl<0b11, opcode, asmstr, 2620 (outs GPR64:$Rt), (ins GPR64xsp0:$Rn), 2621 [], NoItinerary>; 2622 } 2623 2624 defm LDXR : A64I_LRex<"ldxr", 0b000>; 2625 defm LDAXR : A64I_LRex<"ldaxr", 0b001>; 2626 defm LDAR : A64I_LRex<"ldar", 0b101>; 2627 2628 class acquiring_load<PatFrag base> 2629 : PatFrag<(ops node:$ptr), (base node:$ptr), [{ 2630 AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getOrdering(); 2631 return Ordering == Acquire || Ordering == SequentiallyConsistent; 2632 }]>; 2633 2634 def atomic_load_acquire_8 : acquiring_load<atomic_load_8>; 2635 def atomic_load_acquire_16 : acquiring_load<atomic_load_16>; 2636 def atomic_load_acquire_32 : acquiring_load<atomic_load_32>; 2637 def atomic_load_acquire_64 : acquiring_load<atomic_load_64>; 2638 2639 def : Pat<(atomic_load_acquire_8 i64:$Rn), (LDAR_byte $Rn)>; 2640 def : Pat<(atomic_load_acquire_16 i64:$Rn), (LDAR_hword $Rn)>; 2641 def : Pat<(atomic_load_acquire_32 i64:$Rn), (LDAR_word $Rn)>; 2642 def : Pat<(atomic_load_acquire_64 i64:$Rn), (LDAR_dword $Rn)>; 2643 2644 //===---------------------------------- 2645 // Store-release (no exclusivity) 2646 //===---------------------------------- 2647 2648 class A64I_SLexs_impl<bits<2> size, bits<3> opcode, string asm, dag outs, 2649 dag ins, list<dag> pat, 2650 InstrItinClass itin> : 2651 A64I_LDSTex_tn <size, 2652 opcode{2}, 0, opcode{1}, opcode{0}, 2653 outs, ins, 2654 !strconcat(asm, "\t$Rt, [$Rn]"), 2655 pat, itin> { 2656 let mayStore = 1; 2657 let PostEncoderMethod = "fixLoadStoreExclusive<0,0>"; 2658 } 2659 2660 class releasing_store<PatFrag base> 2661 : PatFrag<(ops node:$ptr, node:$val), (base node:$ptr, node:$val), [{ 2662 AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getOrdering(); 2663 return Ordering == Release || Ordering == SequentiallyConsistent; 2664 }]>; 2665 2666 def atomic_store_release_8 : releasing_store<atomic_store_8>; 2667 def atomic_store_release_16 : releasing_store<atomic_store_16>; 2668 def atomic_store_release_32 : releasing_store<atomic_store_32>; 2669 def atomic_store_release_64 : releasing_store<atomic_store_64>; 2670 2671 multiclass A64I_SLex<string asmstr, bits<3> opcode, string prefix> { 2672 def _byte: A64I_SLexs_impl<0b00, opcode, !strconcat(asmstr, "b"), 2673 (outs), (ins GPR32:$Rt, GPR64xsp0:$Rn), 2674 [(atomic_store_release_8 i64:$Rn, i32:$Rt)], 2675 NoItinerary>; 2676 2677 def _hword: A64I_SLexs_impl<0b01, opcode, !strconcat(asmstr, "h"), 2678 (outs), (ins GPR32:$Rt, GPR64xsp0:$Rn), 2679 [(atomic_store_release_16 i64:$Rn, i32:$Rt)], 2680 NoItinerary>; 2681 2682 def _word: A64I_SLexs_impl<0b10, opcode, asmstr, 2683 (outs), (ins GPR32:$Rt, GPR64xsp0:$Rn), 2684 [(atomic_store_release_32 i64:$Rn, i32:$Rt)], 2685 NoItinerary>; 2686 2687 def _dword: A64I_SLexs_impl<0b11, opcode, asmstr, 2688 (outs), (ins GPR64:$Rt, GPR64xsp0:$Rn), 2689 [(atomic_store_release_64 i64:$Rn, i64:$Rt)], 2690 NoItinerary>; 2691 } 2692 2693 defm STLR : A64I_SLex<"stlr", 0b101, "STLR">; 2694 2695 //===---------------------------------- 2696 // Store-exclusive pair (releasing & normal) 2697 //===---------------------------------- 2698 2699 class A64I_SPexs_impl<bits<2> size, bits<3> opcode, string asm, dag outs, 2700 dag ins, list<dag> pat, 2701 InstrItinClass itin> : 2702 A64I_LDSTex_stt2n <size, 2703 opcode{2}, 0, opcode{1}, opcode{0}, 2704 outs, ins, 2705 !strconcat(asm, "\t$Rs, $Rt, $Rt2, [$Rn]"), 2706 pat, itin> { 2707 let mayStore = 1; 2708 } 2709 2710 2711 multiclass A64I_SPex<string asmstr, bits<3> opcode> { 2712 def _word: A64I_SPexs_impl<0b10, opcode, asmstr, (outs), 2713 (ins GPR32:$Rs, GPR32:$Rt, GPR32:$Rt2, 2714 GPR64xsp0:$Rn), 2715 [], NoItinerary>; 2716 2717 def _dword: A64I_SPexs_impl<0b11, opcode, asmstr, (outs), 2718 (ins GPR32:$Rs, GPR64:$Rt, GPR64:$Rt2, 2719 GPR64xsp0:$Rn), 2720 [], NoItinerary>; 2721 } 2722 2723 defm STXP : A64I_SPex<"stxp", 0b010>; 2724 defm STLXP : A64I_SPex<"stlxp", 0b011>; 2725 2726 //===---------------------------------- 2727 // Load-exclusive pair (acquiring & normal) 2728 //===---------------------------------- 2729 2730 class A64I_LPexs_impl<bits<2> size, bits<3> opcode, string asm, dag outs, 2731 dag ins, list<dag> pat, 2732 InstrItinClass itin> : 2733 A64I_LDSTex_tt2n <size, 2734 opcode{2}, 1, opcode{1}, opcode{0}, 2735 outs, ins, 2736 !strconcat(asm, "\t$Rt, $Rt2, [$Rn]"), 2737 pat, itin>{ 2738 let mayLoad = 1; 2739 let DecoderMethod = "DecodeLoadPairExclusiveInstruction"; 2740 let PostEncoderMethod = "fixLoadStoreExclusive<0,1>"; 2741 } 2742 2743 multiclass A64I_LPex<string asmstr, bits<3> opcode> { 2744 def _word: A64I_LPexs_impl<0b10, opcode, asmstr, 2745 (outs GPR32:$Rt, GPR32:$Rt2), 2746 (ins GPR64xsp0:$Rn), 2747 [], NoItinerary>; 2748 2749 def _dword: A64I_LPexs_impl<0b11, opcode, asmstr, 2750 (outs GPR64:$Rt, GPR64:$Rt2), 2751 (ins GPR64xsp0:$Rn), 2752 [], NoItinerary>; 2753 } 2754 2755 defm LDXP : A64I_LPex<"ldxp", 0b010>; 2756 defm LDAXP : A64I_LPex<"ldaxp", 0b011>; 2757 2758 //===----------------------------------------------------------------------===// 2759 // Load-store register (unscaled immediate) instructions 2760 //===----------------------------------------------------------------------===// 2761 // Contains: LDURB, LDURH, LDRUSB, LDRUSH, LDRUSW, STUR, STURB, STURH and PRFUM 2762 // 2763 // and 2764 // 2765 //===----------------------------------------------------------------------===// 2766 // Load-store register (register offset) instructions 2767 //===----------------------------------------------------------------------===// 2768 // Contains: LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH and PRFM 2769 // 2770 // and 2771 // 2772 //===----------------------------------------------------------------------===// 2773 // Load-store register (unsigned immediate) instructions 2774 //===----------------------------------------------------------------------===// 2775 // Contains: LDRB, LDRH, LDRSB, LDRSH, LDRSW, STR, STRB, STRH and PRFM 2776 // 2777 // and 2778 // 2779 //===----------------------------------------------------------------------===// 2780 // Load-store register (immediate post-indexed) instructions 2781 //===----------------------------------------------------------------------===// 2782 // Contains: STRB, STRH, STR, LDRB, LDRH, LDR, LDRSB, LDRSH, LDRSW 2783 // 2784 // and 2785 // 2786 //===----------------------------------------------------------------------===// 2787 // Load-store register (immediate pre-indexed) instructions 2788 //===----------------------------------------------------------------------===// 2789 // Contains: STRB, STRH, STR, LDRB, LDRH, LDR, LDRSB, LDRSH, LDRSW 2790 2791 // Note that patterns are much later on in a completely separate section (they 2792 // need ADRPxi to be defined). 2793 2794 //===------------------------------- 2795 // 1. Various operands needed 2796 //===------------------------------- 2797 2798 //===------------------------------- 2799 // 1.1 Unsigned 12-bit immediate operands 2800 //===------------------------------- 2801 // The addressing mode for these instructions consists of an unsigned 12-bit 2802 // immediate which is scaled by the size of the memory access. 2803 // 2804 // We represent this in the MC layer by two operands: 2805 // 1. A base register. 2806 // 2. A 12-bit immediate: not multiplied by access size, so "LDR x0,[x0,#8]" 2807 // would have '1' in this field. 2808 // This means that separate functions are needed for converting representations 2809 // which *are* aware of the intended access size. 2810 2811 // Anything that creates an MCInst (Decoding, selection and AsmParsing) has to 2812 // know the access size via some means. An isolated operand does not have this 2813 // information unless told from here, which means we need separate tablegen 2814 // Operands for each access size. This multiclass takes care of instantiating 2815 // the correct template functions in the rest of the backend. 2816 2817 //===------------------------------- 2818 // 1.1 Unsigned 12-bit immediate operands 2819 //===------------------------------- 2820 2821 multiclass offsets_uimm12<int MemSize, string prefix> { 2822 def uimm12_asmoperand : AsmOperandClass { 2823 let Name = "OffsetUImm12_" # MemSize; 2824 let PredicateMethod = "isOffsetUImm12<" # MemSize # ">"; 2825 let RenderMethod = "addOffsetUImm12Operands<" # MemSize # ">"; 2826 let DiagnosticType = "LoadStoreUImm12_" # MemSize; 2827 } 2828 2829 // Pattern is really no more than an ImmLeaf, but predicated on MemSize which 2830 // complicates things beyond TableGen's ken. 2831 def uimm12 : Operand<i64>, 2832 ComplexPattern<i64, 1, "SelectOffsetUImm12<" # MemSize # ">"> { 2833 let ParserMatchClass 2834 = !cast<AsmOperandClass>(prefix # uimm12_asmoperand); 2835 2836 let PrintMethod = "printOffsetUImm12Operand<" # MemSize # ">"; 2837 let EncoderMethod = "getOffsetUImm12OpValue<" # MemSize # ">"; 2838 } 2839 } 2840 2841 defm byte_ : offsets_uimm12<1, "byte_">; 2842 defm hword_ : offsets_uimm12<2, "hword_">; 2843 defm word_ : offsets_uimm12<4, "word_">; 2844 defm dword_ : offsets_uimm12<8, "dword_">; 2845 defm qword_ : offsets_uimm12<16, "qword_">; 2846 2847 //===------------------------------- 2848 // 1.1 Signed 9-bit immediate operands 2849 //===------------------------------- 2850 2851 // The MCInst is expected to store the bit-wise encoding of the value, 2852 // which amounts to lopping off the extended sign bits. 2853 def SDXF_simm9 : SDNodeXForm<imm, [{ 2854 return CurDAG->getTargetConstant(N->getZExtValue() & 0x1ff, MVT::i32); 2855 }]>; 2856 2857 def simm9_asmoperand : AsmOperandClass { 2858 let Name = "SImm9"; 2859 let PredicateMethod = "isSImm<9>"; 2860 let RenderMethod = "addSImmOperands<9>"; 2861 let DiagnosticType = "LoadStoreSImm9"; 2862 } 2863 2864 def simm9 : Operand<i64>, 2865 ImmLeaf<i64, [{ return Imm >= -0x100 && Imm <= 0xff; }], 2866 SDXF_simm9> { 2867 let PrintMethod = "printOffsetSImm9Operand"; 2868 let ParserMatchClass = simm9_asmoperand; 2869 } 2870 2871 2872 //===------------------------------- 2873 // 1.3 Register offset extensions 2874 //===------------------------------- 2875 2876 // The assembly-syntax for these addressing-modes is: 2877 // [<Xn|SP>, <R><m> {, <extend> {<amount>}}] 2878 // 2879 // The essential semantics are: 2880 // + <amount> is a shift: #<log(transfer size)> or #0 2881 // + <R> can be W or X. 2882 // + If <R> is W, <extend> can be UXTW or SXTW 2883 // + If <R> is X, <extend> can be LSL or SXTX 2884 // 2885 // The trickiest of those constraints is that Rm can be either GPR32 or GPR64, 2886 // which will need separate instructions for LLVM type-consistency. We'll also 2887 // need separate operands, of course. 2888 multiclass regexts<int MemSize, int RmSize, RegisterClass GPR, 2889 string Rm, string prefix> { 2890 def regext_asmoperand : AsmOperandClass { 2891 let Name = "AddrRegExtend_" # MemSize # "_" # Rm; 2892 let PredicateMethod = "isAddrRegExtend<" # MemSize # "," # RmSize # ">"; 2893 let RenderMethod = "addAddrRegExtendOperands<" # MemSize # ">"; 2894 let DiagnosticType = "LoadStoreExtend" # RmSize # "_" # MemSize; 2895 } 2896 2897 def regext : Operand<i64> { 2898 let PrintMethod 2899 = "printAddrRegExtendOperand<" # MemSize # ", " # RmSize # ">"; 2900 2901 let DecoderMethod = "DecodeAddrRegExtendOperand"; 2902 let ParserMatchClass 2903 = !cast<AsmOperandClass>(prefix # regext_asmoperand); 2904 } 2905 } 2906 2907 multiclass regexts_wx<int MemSize, string prefix> { 2908 // Rm is an X-register if LSL or SXTX are specified as the shift. 2909 defm Xm_ : regexts<MemSize, 64, GPR64, "Xm", prefix # "Xm_">; 2910 2911 // Rm is a W-register if UXTW or SXTW are specified as the shift. 2912 defm Wm_ : regexts<MemSize, 32, GPR32, "Wm", prefix # "Wm_">; 2913 } 2914 2915 defm byte_ : regexts_wx<1, "byte_">; 2916 defm hword_ : regexts_wx<2, "hword_">; 2917 defm word_ : regexts_wx<4, "word_">; 2918 defm dword_ : regexts_wx<8, "dword_">; 2919 defm qword_ : regexts_wx<16, "qword_">; 2920 2921 2922 //===------------------------------ 2923 // 2. The instructions themselves. 2924 //===------------------------------ 2925 2926 // We have the following instructions to implement: 2927 // | | B | H | W | X | 2928 // |-----------------+-------+-------+-------+--------| 2929 // | unsigned str | STRB | STRH | STR | STR | 2930 // | unsigned ldr | LDRB | LDRH | LDR | LDR | 2931 // | signed ldr to W | LDRSB | LDRSH | - | - | 2932 // | signed ldr to X | LDRSB | LDRSH | LDRSW | (PRFM) | 2933 2934 // This will instantiate the LDR/STR instructions you'd expect to use for an 2935 // unsigned datatype (first two rows above) or floating-point register, which is 2936 // reasonably uniform across all access sizes. 2937 2938 2939 //===------------------------------ 2940 // 2.1 Regular instructions 2941 //===------------------------------ 2942 2943 // This class covers the basic unsigned or irrelevantly-signed loads and stores, 2944 // to general-purpose and floating-point registers. 2945 2946 class AddrParams<string prefix> { 2947 Operand uimm12 = !cast<Operand>(prefix # "_uimm12"); 2948 2949 Operand regextWm = !cast<Operand>(prefix # "_Wm_regext"); 2950 Operand regextXm = !cast<Operand>(prefix # "_Xm_regext"); 2951 } 2952 2953 def byte_addrparams : AddrParams<"byte">; 2954 def hword_addrparams : AddrParams<"hword">; 2955 def word_addrparams : AddrParams<"word">; 2956 def dword_addrparams : AddrParams<"dword">; 2957 def qword_addrparams : AddrParams<"qword">; 2958 2959 multiclass A64I_LDRSTR_unsigned<string prefix, bits<2> size, bit v, 2960 bit high_opc, string asmsuffix, 2961 RegisterClass GPR, AddrParams params> { 2962 // Unsigned immediate 2963 def _STR : A64I_LSunsigimm<size, v, {high_opc, 0b0}, 2964 (outs), (ins GPR:$Rt, GPR64xsp:$Rn, params.uimm12:$UImm12), 2965 "str" # asmsuffix # "\t$Rt, [$Rn, $UImm12]", 2966 [], NoItinerary> { 2967 let mayStore = 1; 2968 } 2969 def : InstAlias<"str" # asmsuffix # " $Rt, [$Rn]", 2970 (!cast<Instruction>(prefix # "_STR") GPR:$Rt, GPR64xsp:$Rn, 0)>; 2971 2972 def _LDR : A64I_LSunsigimm<size, v, {high_opc, 0b1}, 2973 (outs GPR:$Rt), (ins GPR64xsp:$Rn, params.uimm12:$UImm12), 2974 "ldr" # asmsuffix # "\t$Rt, [$Rn, $UImm12]", 2975 [], NoItinerary> { 2976 let mayLoad = 1; 2977 } 2978 def : InstAlias<"ldr" # asmsuffix # " $Rt, [$Rn]", 2979 (!cast<Instruction>(prefix # "_LDR") GPR:$Rt, GPR64xsp:$Rn, 0)>; 2980 2981 // Register offset (four of these: load/store and Wm/Xm). 2982 let mayLoad = 1 in { 2983 def _Wm_RegOffset_LDR : A64I_LSregoff<size, v, {high_opc, 0b1}, 0b0, 2984 (outs GPR:$Rt), 2985 (ins GPR64xsp:$Rn, GPR32:$Rm, params.regextWm:$Ext), 2986 "ldr" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]", 2987 [], NoItinerary>; 2988 2989 def _Xm_RegOffset_LDR : A64I_LSregoff<size, v, {high_opc, 0b1}, 0b1, 2990 (outs GPR:$Rt), 2991 (ins GPR64xsp:$Rn, GPR64:$Rm, params.regextXm:$Ext), 2992 "ldr" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]", 2993 [], NoItinerary>; 2994 } 2995 def : InstAlias<"ldr" # asmsuffix # " $Rt, [$Rn, $Rm]", 2996 (!cast<Instruction>(prefix # "_Xm_RegOffset_LDR") GPR:$Rt, GPR64xsp:$Rn, 2997 GPR64:$Rm, 2)>; 2998 2999 let mayStore = 1 in { 3000 def _Wm_RegOffset_STR : A64I_LSregoff<size, v, {high_opc, 0b0}, 0b0, 3001 (outs), (ins GPR:$Rt, GPR64xsp:$Rn, GPR32:$Rm, 3002 params.regextWm:$Ext), 3003 "str" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]", 3004 [], NoItinerary>; 3005 3006 def _Xm_RegOffset_STR : A64I_LSregoff<size, v, {high_opc, 0b0}, 0b1, 3007 (outs), (ins GPR:$Rt, GPR64xsp:$Rn, GPR64:$Rm, 3008 params.regextXm:$Ext), 3009 "str" # asmsuffix # "\t$Rt, [$Rn, $Rm, $Ext]", 3010 [], NoItinerary>; 3011 } 3012 def : InstAlias<"str" # asmsuffix # " $Rt, [$Rn, $Rm]", 3013 (!cast<Instruction>(prefix # "_Xm_RegOffset_STR") GPR:$Rt, GPR64xsp:$Rn, 3014 GPR64:$Rm, 2)>; 3015 3016 // Unaligned immediate 3017 def _STUR : A64I_LSunalimm<size, v, {high_opc, 0b0}, 3018 (outs), (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9), 3019 "stur" # asmsuffix # "\t$Rt, [$Rn, $SImm9]", 3020 [], NoItinerary> { 3021 let mayStore = 1; 3022 } 3023 def : InstAlias<"stur" # asmsuffix # " $Rt, [$Rn]", 3024 (!cast<Instruction>(prefix # "_STUR") GPR:$Rt, GPR64xsp:$Rn, 0)>; 3025 3026 def _LDUR : A64I_LSunalimm<size, v, {high_opc, 0b1}, 3027 (outs GPR:$Rt), (ins GPR64xsp:$Rn, simm9:$SImm9), 3028 "ldur" # asmsuffix # "\t$Rt, [$Rn, $SImm9]", 3029 [], NoItinerary> { 3030 let mayLoad = 1; 3031 } 3032 def : InstAlias<"ldur" # asmsuffix # " $Rt, [$Rn]", 3033 (!cast<Instruction>(prefix # "_LDUR") GPR:$Rt, GPR64xsp:$Rn, 0)>; 3034 3035 // Post-indexed 3036 def _PostInd_STR : A64I_LSpostind<size, v, {high_opc, 0b0}, 3037 (outs GPR64xsp:$Rn_wb), 3038 (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9), 3039 "str" # asmsuffix # "\t$Rt, [$Rn], $SImm9", 3040 [], NoItinerary> { 3041 let Constraints = "$Rn = $Rn_wb"; 3042 let mayStore = 1; 3043 3044 // Decoder only needed for unpredictability checking (FIXME). 3045 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3046 } 3047 3048 def _PostInd_LDR : A64I_LSpostind<size, v, {high_opc, 0b1}, 3049 (outs GPR:$Rt, GPR64xsp:$Rn_wb), 3050 (ins GPR64xsp:$Rn, simm9:$SImm9), 3051 "ldr" # asmsuffix # "\t$Rt, [$Rn], $SImm9", 3052 [], NoItinerary> { 3053 let mayLoad = 1; 3054 let Constraints = "$Rn = $Rn_wb"; 3055 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3056 } 3057 3058 // Pre-indexed 3059 def _PreInd_STR : A64I_LSpreind<size, v, {high_opc, 0b0}, 3060 (outs GPR64xsp:$Rn_wb), 3061 (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9), 3062 "str" # asmsuffix # "\t$Rt, [$Rn, $SImm9]!", 3063 [], NoItinerary> { 3064 let Constraints = "$Rn = $Rn_wb"; 3065 let mayStore = 1; 3066 3067 // Decoder only needed for unpredictability checking (FIXME). 3068 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3069 } 3070 3071 def _PreInd_LDR : A64I_LSpreind<size, v, {high_opc, 0b1}, 3072 (outs GPR:$Rt, GPR64xsp:$Rn_wb), 3073 (ins GPR64xsp:$Rn, simm9:$SImm9), 3074 "ldr" # asmsuffix # "\t$Rt, [$Rn, $SImm9]!", 3075 [], NoItinerary> { 3076 let mayLoad = 1; 3077 let Constraints = "$Rn = $Rn_wb"; 3078 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3079 } 3080 3081 } 3082 3083 // STRB/LDRB: First define the instructions 3084 defm LS8 3085 : A64I_LDRSTR_unsigned<"LS8", 0b00, 0b0, 0b0, "b", GPR32, byte_addrparams>; 3086 3087 // STRH/LDRH 3088 defm LS16 3089 : A64I_LDRSTR_unsigned<"LS16", 0b01, 0b0, 0b0, "h", GPR32, hword_addrparams>; 3090 3091 3092 // STR/LDR to/from a W register 3093 defm LS32 3094 : A64I_LDRSTR_unsigned<"LS32", 0b10, 0b0, 0b0, "", GPR32, word_addrparams>; 3095 3096 // STR/LDR to/from an X register 3097 defm LS64 3098 : A64I_LDRSTR_unsigned<"LS64", 0b11, 0b0, 0b0, "", GPR64, dword_addrparams>; 3099 3100 // STR/LDR to/from a B register 3101 defm LSFP8 3102 : A64I_LDRSTR_unsigned<"LSFP8", 0b00, 0b1, 0b0, "", FPR8, byte_addrparams>; 3103 3104 // STR/LDR to/from an H register 3105 defm LSFP16 3106 : A64I_LDRSTR_unsigned<"LSFP16", 0b01, 0b1, 0b0, "", FPR16, hword_addrparams>; 3107 3108 // STR/LDR to/from an S register 3109 defm LSFP32 3110 : A64I_LDRSTR_unsigned<"LSFP32", 0b10, 0b1, 0b0, "", FPR32, word_addrparams>; 3111 // STR/LDR to/from a D register 3112 defm LSFP64 3113 : A64I_LDRSTR_unsigned<"LSFP64", 0b11, 0b1, 0b0, "", FPR64, dword_addrparams>; 3114 // STR/LDR to/from a Q register 3115 defm LSFP128 3116 : A64I_LDRSTR_unsigned<"LSFP128", 0b00, 0b1, 0b1, "", FPR128, 3117 qword_addrparams>; 3118 3119 //===------------------------------ 3120 // 2.3 Signed loads 3121 //===------------------------------ 3122 3123 // Byte and half-word signed loads can both go into either an X or a W register, 3124 // so it's worth factoring out. Signed word loads don't fit because there is no 3125 // W version. 3126 multiclass A64I_LDR_signed<bits<2> size, string asmopcode, AddrParams params, 3127 string prefix> { 3128 // Unsigned offset 3129 def w : A64I_LSunsigimm<size, 0b0, 0b11, 3130 (outs GPR32:$Rt), 3131 (ins GPR64xsp:$Rn, params.uimm12:$UImm12), 3132 "ldrs" # asmopcode # "\t$Rt, [$Rn, $UImm12]", 3133 [], NoItinerary> { 3134 let mayLoad = 1; 3135 } 3136 def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn]", 3137 (!cast<Instruction>(prefix # w) GPR32:$Rt, GPR64xsp:$Rn, 0)>; 3138 3139 def x : A64I_LSunsigimm<size, 0b0, 0b10, 3140 (outs GPR64:$Rt), 3141 (ins GPR64xsp:$Rn, params.uimm12:$UImm12), 3142 "ldrs" # asmopcode # "\t$Rt, [$Rn, $UImm12]", 3143 [], NoItinerary> { 3144 let mayLoad = 1; 3145 } 3146 def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn]", 3147 (!cast<Instruction>(prefix # x) GPR64:$Rt, GPR64xsp:$Rn, 0)>; 3148 3149 // Register offset 3150 let mayLoad = 1 in { 3151 def w_Wm_RegOffset : A64I_LSregoff<size, 0b0, 0b11, 0b0, 3152 (outs GPR32:$Rt), 3153 (ins GPR64xsp:$Rn, GPR32:$Rm, params.regextWm:$Ext), 3154 "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]", 3155 [], NoItinerary>; 3156 3157 def w_Xm_RegOffset : A64I_LSregoff<size, 0b0, 0b11, 0b1, 3158 (outs GPR32:$Rt), 3159 (ins GPR64xsp:$Rn, GPR64:$Rm, params.regextXm:$Ext), 3160 "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]", 3161 [], NoItinerary>; 3162 3163 def x_Wm_RegOffset : A64I_LSregoff<size, 0b0, 0b10, 0b0, 3164 (outs GPR64:$Rt), 3165 (ins GPR64xsp:$Rn, GPR32:$Rm, params.regextWm:$Ext), 3166 "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]", 3167 [], NoItinerary>; 3168 3169 def x_Xm_RegOffset : A64I_LSregoff<size, 0b0, 0b10, 0b1, 3170 (outs GPR64:$Rt), 3171 (ins GPR64xsp:$Rn, GPR64:$Rm, params.regextXm:$Ext), 3172 "ldrs" # asmopcode # "\t$Rt, [$Rn, $Rm, $Ext]", 3173 [], NoItinerary>; 3174 } 3175 def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn, $Rm]", 3176 (!cast<Instruction>(prefix # "w_Xm_RegOffset") GPR32:$Rt, GPR64xsp:$Rn, 3177 GPR64:$Rm, 2)>; 3178 3179 def : InstAlias<"ldrs" # asmopcode # " $Rt, [$Rn, $Rm]", 3180 (!cast<Instruction>(prefix # "x_Xm_RegOffset") GPR64:$Rt, GPR64xsp:$Rn, 3181 GPR64:$Rm, 2)>; 3182 3183 3184 let mayLoad = 1 in { 3185 // Unaligned offset 3186 def w_U : A64I_LSunalimm<size, 0b0, 0b11, 3187 (outs GPR32:$Rt), 3188 (ins GPR64xsp:$Rn, simm9:$SImm9), 3189 "ldurs" # asmopcode # "\t$Rt, [$Rn, $SImm9]", 3190 [], NoItinerary>; 3191 3192 def x_U : A64I_LSunalimm<size, 0b0, 0b10, 3193 (outs GPR64:$Rt), 3194 (ins GPR64xsp:$Rn, simm9:$SImm9), 3195 "ldurs" # asmopcode # "\t$Rt, [$Rn, $SImm9]", 3196 [], NoItinerary>; 3197 3198 3199 // Post-indexed 3200 def w_PostInd : A64I_LSpostind<size, 0b0, 0b11, 3201 (outs GPR32:$Rt, GPR64xsp:$Rn_wb), 3202 (ins GPR64xsp:$Rn, simm9:$SImm9), 3203 "ldrs" # asmopcode # "\t$Rt, [$Rn], $SImm9", 3204 [], NoItinerary> { 3205 let Constraints = "$Rn = $Rn_wb"; 3206 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3207 } 3208 3209 def x_PostInd : A64I_LSpostind<size, 0b0, 0b10, 3210 (outs GPR64:$Rt, GPR64xsp:$Rn_wb), 3211 (ins GPR64xsp:$Rn, simm9:$SImm9), 3212 "ldrs" # asmopcode # "\t$Rt, [$Rn], $SImm9", 3213 [], NoItinerary> { 3214 let Constraints = "$Rn = $Rn_wb"; 3215 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3216 } 3217 3218 // Pre-indexed 3219 def w_PreInd : A64I_LSpreind<size, 0b0, 0b11, 3220 (outs GPR32:$Rt, GPR64xsp:$Rn_wb), 3221 (ins GPR64xsp:$Rn, simm9:$SImm9), 3222 "ldrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]!", 3223 [], NoItinerary> { 3224 let Constraints = "$Rn = $Rn_wb"; 3225 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3226 } 3227 3228 def x_PreInd : A64I_LSpreind<size, 0b0, 0b10, 3229 (outs GPR64:$Rt, GPR64xsp:$Rn_wb), 3230 (ins GPR64xsp:$Rn, simm9:$SImm9), 3231 "ldrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]!", 3232 [], NoItinerary> { 3233 let Constraints = "$Rn = $Rn_wb"; 3234 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3235 } 3236 } // let mayLoad = 1 3237 } 3238 3239 // LDRSB 3240 defm LDRSB : A64I_LDR_signed<0b00, "b", byte_addrparams, "LDRSB">; 3241 // LDRSH 3242 defm LDRSH : A64I_LDR_signed<0b01, "h", hword_addrparams, "LDRSH">; 3243 3244 // LDRSW: load a 32-bit register, sign-extending to 64-bits. 3245 def LDRSWx 3246 : A64I_LSunsigimm<0b10, 0b0, 0b10, 3247 (outs GPR64:$Rt), 3248 (ins GPR64xsp:$Rn, word_uimm12:$UImm12), 3249 "ldrsw\t$Rt, [$Rn, $UImm12]", 3250 [], NoItinerary> { 3251 let mayLoad = 1; 3252 } 3253 def : InstAlias<"ldrsw $Rt, [$Rn]", (LDRSWx GPR64:$Rt, GPR64xsp:$Rn, 0)>; 3254 3255 let mayLoad = 1 in { 3256 def LDRSWx_Wm_RegOffset : A64I_LSregoff<0b10, 0b0, 0b10, 0b0, 3257 (outs GPR64:$Rt), 3258 (ins GPR64xsp:$Rn, GPR32:$Rm, word_Wm_regext:$Ext), 3259 "ldrsw\t$Rt, [$Rn, $Rm, $Ext]", 3260 [], NoItinerary>; 3261 3262 def LDRSWx_Xm_RegOffset : A64I_LSregoff<0b10, 0b0, 0b10, 0b1, 3263 (outs GPR64:$Rt), 3264 (ins GPR64xsp:$Rn, GPR64:$Rm, word_Xm_regext:$Ext), 3265 "ldrsw\t$Rt, [$Rn, $Rm, $Ext]", 3266 [], NoItinerary>; 3267 } 3268 def : InstAlias<"ldrsw $Rt, [$Rn, $Rm]", 3269 (LDRSWx_Xm_RegOffset GPR64:$Rt, GPR64xsp:$Rn, GPR64:$Rm, 2)>; 3270 3271 3272 def LDURSWx 3273 : A64I_LSunalimm<0b10, 0b0, 0b10, 3274 (outs GPR64:$Rt), 3275 (ins GPR64xsp:$Rn, simm9:$SImm9), 3276 "ldursw\t$Rt, [$Rn, $SImm9]", 3277 [], NoItinerary> { 3278 let mayLoad = 1; 3279 } 3280 def : InstAlias<"ldursw $Rt, [$Rn]", (LDURSWx GPR64:$Rt, GPR64xsp:$Rn, 0)>; 3281 3282 def LDRSWx_PostInd 3283 : A64I_LSpostind<0b10, 0b0, 0b10, 3284 (outs GPR64:$Rt, GPR64xsp:$Rn_wb), 3285 (ins GPR64xsp:$Rn, simm9:$SImm9), 3286 "ldrsw\t$Rt, [$Rn], $SImm9", 3287 [], NoItinerary> { 3288 let mayLoad = 1; 3289 let Constraints = "$Rn = $Rn_wb"; 3290 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3291 } 3292 3293 def LDRSWx_PreInd : A64I_LSpreind<0b10, 0b0, 0b10, 3294 (outs GPR64:$Rt, GPR64xsp:$Rn_wb), 3295 (ins GPR64xsp:$Rn, simm9:$SImm9), 3296 "ldrsw\t$Rt, [$Rn, $SImm9]!", 3297 [], NoItinerary> { 3298 let mayLoad = 1; 3299 let Constraints = "$Rn = $Rn_wb"; 3300 let DecoderMethod = "DecodeSingleIndexedInstruction"; 3301 } 3302 3303 //===------------------------------ 3304 // 2.4 Prefetch operations 3305 //===------------------------------ 3306 3307 def PRFM : A64I_LSunsigimm<0b11, 0b0, 0b10, (outs), 3308 (ins prefetch_op:$Rt, GPR64xsp:$Rn, dword_uimm12:$UImm12), 3309 "prfm\t$Rt, [$Rn, $UImm12]", 3310 [], NoItinerary> { 3311 let mayLoad = 1; 3312 } 3313 def : InstAlias<"prfm $Rt, [$Rn]", 3314 (PRFM prefetch_op:$Rt, GPR64xsp:$Rn, 0)>; 3315 3316 let mayLoad = 1 in { 3317 def PRFM_Wm_RegOffset : A64I_LSregoff<0b11, 0b0, 0b10, 0b0, (outs), 3318 (ins prefetch_op:$Rt, GPR64xsp:$Rn, 3319 GPR32:$Rm, dword_Wm_regext:$Ext), 3320 "prfm\t$Rt, [$Rn, $Rm, $Ext]", 3321 [], NoItinerary>; 3322 def PRFM_Xm_RegOffset : A64I_LSregoff<0b11, 0b0, 0b10, 0b1, (outs), 3323 (ins prefetch_op:$Rt, GPR64xsp:$Rn, 3324 GPR64:$Rm, dword_Xm_regext:$Ext), 3325 "prfm\t$Rt, [$Rn, $Rm, $Ext]", 3326 [], NoItinerary>; 3327 } 3328 3329 def : InstAlias<"prfm $Rt, [$Rn, $Rm]", 3330 (PRFM_Xm_RegOffset prefetch_op:$Rt, GPR64xsp:$Rn, 3331 GPR64:$Rm, 2)>; 3332 3333 3334 def PRFUM : A64I_LSunalimm<0b11, 0b0, 0b10, (outs), 3335 (ins prefetch_op:$Rt, GPR64xsp:$Rn, simm9:$SImm9), 3336 "prfum\t$Rt, [$Rn, $SImm9]", 3337 [], NoItinerary> { 3338 let mayLoad = 1; 3339 } 3340 def : InstAlias<"prfum $Rt, [$Rn]", 3341 (PRFUM prefetch_op:$Rt, GPR64xsp:$Rn, 0)>; 3342 3343 //===----------------------------------------------------------------------===// 3344 // Load-store register (unprivileged) instructions 3345 //===----------------------------------------------------------------------===// 3346 // Contains: LDTRB, LDTRH, LDTRSB, LDTRSH, LDTRSW, STTR, STTRB and STTRH 3347 3348 // These instructions very much mirror the "unscaled immediate" loads, but since 3349 // there are no floating-point variants we need to split them out into their own 3350 // section to avoid instantiation of "ldtr d0, [sp]" etc. 3351 3352 multiclass A64I_LDTRSTTR<bits<2> size, string asmsuffix, RegisterClass GPR, 3353 string prefix> { 3354 def _UnPriv_STR : A64I_LSunpriv<size, 0b0, 0b00, 3355 (outs), (ins GPR:$Rt, GPR64xsp:$Rn, simm9:$SImm9), 3356 "sttr" # asmsuffix # "\t$Rt, [$Rn, $SImm9]", 3357 [], NoItinerary> { 3358 let mayStore = 1; 3359 } 3360 3361 def : InstAlias<"sttr" # asmsuffix # " $Rt, [$Rn]", 3362 (!cast<Instruction>(prefix # "_UnPriv_STR") GPR:$Rt, GPR64xsp:$Rn, 0)>; 3363 3364 def _UnPriv_LDR : A64I_LSunpriv<size, 0b0, 0b01, 3365 (outs GPR:$Rt), (ins GPR64xsp:$Rn, simm9:$SImm9), 3366 "ldtr" # asmsuffix # "\t$Rt, [$Rn, $SImm9]", 3367 [], NoItinerary> { 3368 let mayLoad = 1; 3369 } 3370 3371 def : InstAlias<"ldtr" # asmsuffix # " $Rt, [$Rn]", 3372 (!cast<Instruction>(prefix # "_UnPriv_LDR") GPR:$Rt, GPR64xsp:$Rn, 0)>; 3373 3374 } 3375 3376 // STTRB/LDTRB: First define the instructions 3377 defm LS8 : A64I_LDTRSTTR<0b00, "b", GPR32, "LS8">; 3378 3379 // STTRH/LDTRH 3380 defm LS16 : A64I_LDTRSTTR<0b01, "h", GPR32, "LS16">; 3381 3382 // STTR/LDTR to/from a W register 3383 defm LS32 : A64I_LDTRSTTR<0b10, "", GPR32, "LS32">; 3384 3385 // STTR/LDTR to/from an X register 3386 defm LS64 : A64I_LDTRSTTR<0b11, "", GPR64, "LS64">; 3387 3388 // Now a class for the signed instructions that can go to either 32 or 64 3389 // bits... 3390 multiclass A64I_LDTR_signed<bits<2> size, string asmopcode, string prefix> { 3391 let mayLoad = 1 in { 3392 def w : A64I_LSunpriv<size, 0b0, 0b11, 3393 (outs GPR32:$Rt), 3394 (ins GPR64xsp:$Rn, simm9:$SImm9), 3395 "ldtrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]", 3396 [], NoItinerary>; 3397 3398 def x : A64I_LSunpriv<size, 0b0, 0b10, 3399 (outs GPR64:$Rt), 3400 (ins GPR64xsp:$Rn, simm9:$SImm9), 3401 "ldtrs" # asmopcode # "\t$Rt, [$Rn, $SImm9]", 3402 [], NoItinerary>; 3403 } 3404 3405 def : InstAlias<"ldtrs" # asmopcode # " $Rt, [$Rn]", 3406 (!cast<Instruction>(prefix # "w") GPR32:$Rt, GPR64xsp:$Rn, 0)>; 3407 3408 def : InstAlias<"ldtrs" # asmopcode # " $Rt, [$Rn]", 3409 (!cast<Instruction>(prefix # "x") GPR64:$Rt, GPR64xsp:$Rn, 0)>; 3410 3411 } 3412 3413 // LDTRSB 3414 defm LDTRSB : A64I_LDTR_signed<0b00, "b", "LDTRSB">; 3415 // LDTRSH 3416 defm LDTRSH : A64I_LDTR_signed<0b01, "h", "LDTRSH">; 3417 3418 // And finally LDTRSW which only goes to 64 bits. 3419 def LDTRSWx : A64I_LSunpriv<0b10, 0b0, 0b10, 3420 (outs GPR64:$Rt), 3421 (ins GPR64xsp:$Rn, simm9:$SImm9), 3422 "ldtrsw\t$Rt, [$Rn, $SImm9]", 3423 [], NoItinerary> { 3424 let mayLoad = 1; 3425 } 3426 def : InstAlias<"ldtrsw $Rt, [$Rn]", (LDTRSWx GPR64:$Rt, GPR64xsp:$Rn, 0)>; 3427 3428 //===----------------------------------------------------------------------===// 3429 // Load-store register pair (offset) instructions 3430 //===----------------------------------------------------------------------===// 3431 // 3432 // and 3433 // 3434 //===----------------------------------------------------------------------===// 3435 // Load-store register pair (post-indexed) instructions 3436 //===----------------------------------------------------------------------===// 3437 // Contains: STP, LDP, LDPSW 3438 // 3439 // and 3440 // 3441 //===----------------------------------------------------------------------===// 3442 // Load-store register pair (pre-indexed) instructions 3443 //===----------------------------------------------------------------------===// 3444 // Contains: STP, LDP, LDPSW 3445 // 3446 // and 3447 // 3448 //===----------------------------------------------------------------------===// 3449 // Load-store non-temporal register pair (offset) instructions 3450 //===----------------------------------------------------------------------===// 3451 // Contains: STNP, LDNP 3452 3453 3454 // Anything that creates an MCInst (Decoding, selection and AsmParsing) has to 3455 // know the access size via some means. An isolated operand does not have this 3456 // information unless told from here, which means we need separate tablegen 3457 // Operands for each access size. This multiclass takes care of instantiating 3458 // the correct template functions in the rest of the backend. 3459 3460 multiclass offsets_simm7<string MemSize, string prefix> { 3461 // The bare signed 7-bit immediate is used in post-indexed instructions, but 3462 // because of the scaling performed a generic "simm7" operand isn't 3463 // appropriate here either. 3464 def simm7_asmoperand : AsmOperandClass { 3465 let Name = "SImm7_Scaled" # MemSize; 3466 let PredicateMethod = "isSImm7Scaled<" # MemSize # ">"; 3467 let RenderMethod = "addSImm7ScaledOperands<" # MemSize # ">"; 3468 let DiagnosticType = "LoadStoreSImm7_" # MemSize; 3469 } 3470 3471 def simm7 : Operand<i64> { 3472 let PrintMethod = "printSImm7ScaledOperand<" # MemSize # ">"; 3473 let ParserMatchClass = !cast<AsmOperandClass>(prefix # "simm7_asmoperand"); 3474 } 3475 } 3476 3477 defm word_ : offsets_simm7<"4", "word_">; 3478 defm dword_ : offsets_simm7<"8", "dword_">; 3479 defm qword_ : offsets_simm7<"16", "qword_">; 3480 3481 multiclass A64I_LSPsimple<bits<2> opc, bit v, RegisterClass SomeReg, 3482 Operand simm7, string prefix> { 3483 def _STR : A64I_LSPoffset<opc, v, 0b0, (outs), 3484 (ins SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn, simm7:$SImm7), 3485 "stp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary> { 3486 let mayStore = 1; 3487 let DecoderMethod = "DecodeLDSTPairInstruction"; 3488 } 3489 def : InstAlias<"stp $Rt, $Rt2, [$Rn]", 3490 (!cast<Instruction>(prefix # "_STR") SomeReg:$Rt, 3491 SomeReg:$Rt2, GPR64xsp:$Rn, 0)>; 3492 3493 def _LDR : A64I_LSPoffset<opc, v, 0b1, 3494 (outs SomeReg:$Rt, SomeReg:$Rt2), 3495 (ins GPR64xsp:$Rn, simm7:$SImm7), 3496 "ldp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary> { 3497 let mayLoad = 1; 3498 let DecoderMethod = "DecodeLDSTPairInstruction"; 3499 } 3500 def : InstAlias<"ldp $Rt, $Rt2, [$Rn]", 3501 (!cast<Instruction>(prefix # "_LDR") SomeReg:$Rt, 3502 SomeReg:$Rt2, GPR64xsp:$Rn, 0)>; 3503 3504 def _PostInd_STR : A64I_LSPpostind<opc, v, 0b0, 3505 (outs GPR64xsp:$Rn_wb), 3506 (ins SomeReg:$Rt, SomeReg:$Rt2, 3507 GPR64xsp:$Rn, 3508 simm7:$SImm7), 3509 "stp\t$Rt, $Rt2, [$Rn], $SImm7", 3510 [], NoItinerary> { 3511 let mayStore = 1; 3512 let Constraints = "$Rn = $Rn_wb"; 3513 3514 // Decoder only needed for unpredictability checking (FIXME). 3515 let DecoderMethod = "DecodeLDSTPairInstruction"; 3516 } 3517 3518 def _PostInd_LDR : A64I_LSPpostind<opc, v, 0b1, 3519 (outs SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn_wb), 3520 (ins GPR64xsp:$Rn, simm7:$SImm7), 3521 "ldp\t$Rt, $Rt2, [$Rn], $SImm7", 3522 [], NoItinerary> { 3523 let mayLoad = 1; 3524 let Constraints = "$Rn = $Rn_wb"; 3525 let DecoderMethod = "DecodeLDSTPairInstruction"; 3526 } 3527 3528 def _PreInd_STR : A64I_LSPpreind<opc, v, 0b0, (outs GPR64xsp:$Rn_wb), 3529 (ins SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn, simm7:$SImm7), 3530 "stp\t$Rt, $Rt2, [$Rn, $SImm7]!", 3531 [], NoItinerary> { 3532 let mayStore = 1; 3533 let Constraints = "$Rn = $Rn_wb"; 3534 let DecoderMethod = "DecodeLDSTPairInstruction"; 3535 } 3536 3537 def _PreInd_LDR : A64I_LSPpreind<opc, v, 0b1, 3538 (outs SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn_wb), 3539 (ins GPR64xsp:$Rn, simm7:$SImm7), 3540 "ldp\t$Rt, $Rt2, [$Rn, $SImm7]!", 3541 [], NoItinerary> { 3542 let mayLoad = 1; 3543 let Constraints = "$Rn = $Rn_wb"; 3544 let DecoderMethod = "DecodeLDSTPairInstruction"; 3545 } 3546 3547 def _NonTemp_STR : A64I_LSPnontemp<opc, v, 0b0, (outs), 3548 (ins SomeReg:$Rt, SomeReg:$Rt2, GPR64xsp:$Rn, simm7:$SImm7), 3549 "stnp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary> { 3550 let mayStore = 1; 3551 let DecoderMethod = "DecodeLDSTPairInstruction"; 3552 } 3553 def : InstAlias<"stnp $Rt, $Rt2, [$Rn]", 3554 (!cast<Instruction>(prefix # "_NonTemp_STR") SomeReg:$Rt, 3555 SomeReg:$Rt2, GPR64xsp:$Rn, 0)>; 3556 3557 def _NonTemp_LDR : A64I_LSPnontemp<opc, v, 0b1, 3558 (outs SomeReg:$Rt, SomeReg:$Rt2), 3559 (ins GPR64xsp:$Rn, simm7:$SImm7), 3560 "ldnp\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary> { 3561 let mayLoad = 1; 3562 let DecoderMethod = "DecodeLDSTPairInstruction"; 3563 } 3564 def : InstAlias<"ldnp $Rt, $Rt2, [$Rn]", 3565 (!cast<Instruction>(prefix # "_NonTemp_LDR") SomeReg:$Rt, 3566 SomeReg:$Rt2, GPR64xsp:$Rn, 0)>; 3567 3568 } 3569 3570 3571 defm LSPair32 : A64I_LSPsimple<0b00, 0b0, GPR32, word_simm7, "LSPair32">; 3572 defm LSPair64 : A64I_LSPsimple<0b10, 0b0, GPR64, dword_simm7, "LSPair64">; 3573 defm LSFPPair32 : A64I_LSPsimple<0b00, 0b1, FPR32, word_simm7, "LSFPPair32">; 3574 defm LSFPPair64 : A64I_LSPsimple<0b01, 0b1, FPR64, dword_simm7, "LSFPPair64">; 3575 defm LSFPPair128 : A64I_LSPsimple<0b10, 0b1, FPR128, qword_simm7, 3576 "LSFPPair128">; 3577 3578 3579 def LDPSWx : A64I_LSPoffset<0b01, 0b0, 0b1, 3580 (outs GPR64:$Rt, GPR64:$Rt2), 3581 (ins GPR64xsp:$Rn, word_simm7:$SImm7), 3582 "ldpsw\t$Rt, $Rt2, [$Rn, $SImm7]", [], NoItinerary> { 3583 let mayLoad = 1; 3584 let DecoderMethod = "DecodeLDSTPairInstruction"; 3585 } 3586 def : InstAlias<"ldpsw $Rt, $Rt2, [$Rn]", 3587 (LDPSWx GPR64:$Rt, GPR64:$Rt2, GPR64xsp:$Rn, 0)>; 3588 3589 def LDPSWx_PostInd : A64I_LSPpostind<0b01, 0b0, 0b1, 3590 (outs GPR64:$Rt, GPR64:$Rt2, GPR64:$Rn_wb), 3591 (ins GPR64xsp:$Rn, word_simm7:$SImm7), 3592 "ldpsw\t$Rt, $Rt2, [$Rn], $SImm7", 3593 [], NoItinerary> { 3594 let mayLoad = 1; 3595 let Constraints = "$Rn = $Rn_wb"; 3596 let DecoderMethod = "DecodeLDSTPairInstruction"; 3597 } 3598 3599 def LDPSWx_PreInd : A64I_LSPpreind<0b01, 0b0, 0b1, 3600 (outs GPR64:$Rt, GPR64:$Rt2, GPR64:$Rn_wb), 3601 (ins GPR64xsp:$Rn, word_simm7:$SImm7), 3602 "ldpsw\t$Rt, $Rt2, [$Rn, $SImm7]!", 3603 [], NoItinerary> { 3604 let mayLoad = 1; 3605 let Constraints = "$Rn = $Rn_wb"; 3606 let DecoderMethod = "DecodeLDSTPairInstruction"; 3607 } 3608 3609 //===----------------------------------------------------------------------===// 3610 // Logical (immediate) instructions 3611 //===----------------------------------------------------------------------===// 3612 // Contains: AND, ORR, EOR, ANDS, + aliases TST, MOV 3613 3614 multiclass logical_imm_operands<string prefix, string note, 3615 int size, ValueType VT> { 3616 def _asmoperand : AsmOperandClass { 3617 let Name = "LogicalImm" # note # size; 3618 let PredicateMethod = "isLogicalImm" # note # "<" # size # ">"; 3619 let RenderMethod = "addLogicalImmOperands<" # size # ">"; 3620 let DiagnosticType = "LogicalSecondSource"; 3621 } 3622 3623 def _operand 3624 : Operand<VT>, ComplexPattern<VT, 1, "SelectLogicalImm", [imm]> { 3625 let ParserMatchClass = !cast<AsmOperandClass>(prefix # "_asmoperand"); 3626 let PrintMethod = "printLogicalImmOperand<" # size # ">"; 3627 let DecoderMethod = "DecodeLogicalImmOperand<" # size # ">"; 3628 } 3629 } 3630 3631 defm logical_imm32 : logical_imm_operands<"logical_imm32", "", 32, i32>; 3632 defm logical_imm64 : logical_imm_operands<"logical_imm64", "", 64, i64>; 3633 3634 // The mov versions only differ in assembly parsing, where they 3635 // exclude values representable with either MOVZ or MOVN. 3636 defm logical_imm32_mov 3637 : logical_imm_operands<"logical_imm32_mov", "MOV", 32, i32>; 3638 defm logical_imm64_mov 3639 : logical_imm_operands<"logical_imm64_mov", "MOV", 64, i64>; 3640 3641 3642 multiclass A64I_logimmSizes<bits<2> opc, string asmop, SDNode opnode> { 3643 def wwi : A64I_logicalimm<0b0, opc, (outs GPR32wsp:$Rd), 3644 (ins GPR32:$Rn, logical_imm32_operand:$Imm), 3645 !strconcat(asmop, "\t$Rd, $Rn, $Imm"), 3646 [(set i32:$Rd, 3647 (opnode i32:$Rn, logical_imm32_operand:$Imm))], 3648 NoItinerary>; 3649 3650 def xxi : A64I_logicalimm<0b1, opc, (outs GPR64xsp:$Rd), 3651 (ins GPR64:$Rn, logical_imm64_operand:$Imm), 3652 !strconcat(asmop, "\t$Rd, $Rn, $Imm"), 3653 [(set i64:$Rd, 3654 (opnode i64:$Rn, logical_imm64_operand:$Imm))], 3655 NoItinerary>; 3656 } 3657 3658 defm AND : A64I_logimmSizes<0b00, "and", and>; 3659 defm ORR : A64I_logimmSizes<0b01, "orr", or>; 3660 defm EOR : A64I_logimmSizes<0b10, "eor", xor>; 3661 3662 let Defs = [NZCV] in { 3663 def ANDSwwi : A64I_logicalimm<0b0, 0b11, (outs GPR32:$Rd), 3664 (ins GPR32:$Rn, logical_imm32_operand:$Imm), 3665 "ands\t$Rd, $Rn, $Imm", 3666 [], NoItinerary>; 3667 3668 def ANDSxxi : A64I_logicalimm<0b1, 0b11, (outs GPR64:$Rd), 3669 (ins GPR64:$Rn, logical_imm64_operand:$Imm), 3670 "ands\t$Rd, $Rn, $Imm", 3671 [], NoItinerary>; 3672 } 3673 3674 3675 def : InstAlias<"tst $Rn, $Imm", 3676 (ANDSwwi WZR, GPR32:$Rn, logical_imm32_operand:$Imm)>; 3677 def : InstAlias<"tst $Rn, $Imm", 3678 (ANDSxxi XZR, GPR64:$Rn, logical_imm64_operand:$Imm)>; 3679 def : InstAlias<"mov $Rd, $Imm", 3680 (ORRwwi GPR32wsp:$Rd, WZR, logical_imm32_mov_operand:$Imm)>; 3681 def : InstAlias<"mov $Rd, $Imm", 3682 (ORRxxi GPR64xsp:$Rd, XZR, logical_imm64_mov_operand:$Imm)>; 3683 3684 //===----------------------------------------------------------------------===// 3685 // Logical (shifted register) instructions 3686 //===----------------------------------------------------------------------===// 3687 // Contains: AND, BIC, ORR, ORN, EOR, EON, ANDS, BICS + aliases TST, MVN, MOV 3688 3689 // Operand for optimizing (icmp (and LHS, RHS), 0, SomeCode). In theory "ANDS" 3690 // behaves differently for unsigned comparisons, so we defensively only allow 3691 // signed or n/a as the operand. In practice "unsigned greater than 0" is "not 3692 // equal to 0" and LLVM gives us this. 3693 def signed_cond : PatLeaf<(cond), [{ 3694 return !isUnsignedIntSetCC(N->get()); 3695 }]>; 3696 3697 3698 // These instructions share their "shift" operands with add/sub (shifted 3699 // register instructions). They are defined there. 3700 3701 // N.b. the commutable parameter is just !N. It will be first against the wall 3702 // when the revolution comes. 3703 multiclass logical_shifts<string prefix, bit sf, bits<2> opc, 3704 bit N, bit commutable, 3705 string asmop, SDPatternOperator opfrag, ValueType ty, 3706 RegisterClass GPR, list<Register> defs> { 3707 let isCommutable = commutable, Defs = defs in { 3708 def _lsl : A64I_logicalshift<sf, opc, 0b00, N, 3709 (outs GPR:$Rd), 3710 (ins GPR:$Rn, GPR:$Rm, 3711 !cast<Operand>("lsl_operand_" # ty):$Imm6), 3712 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"), 3713 [(set ty:$Rd, (opfrag ty:$Rn, (shl ty:$Rm, 3714 !cast<Operand>("lsl_operand_" # ty):$Imm6)) 3715 )], 3716 NoItinerary>; 3717 3718 def _lsr : A64I_logicalshift<sf, opc, 0b01, N, 3719 (outs GPR:$Rd), 3720 (ins GPR:$Rn, GPR:$Rm, 3721 !cast<Operand>("lsr_operand_" # ty):$Imm6), 3722 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"), 3723 [(set ty:$Rd, (opfrag ty:$Rn, (srl ty:$Rm, 3724 !cast<Operand>("lsr_operand_" # ty):$Imm6)) 3725 )], 3726 NoItinerary>; 3727 3728 def _asr : A64I_logicalshift<sf, opc, 0b10, N, 3729 (outs GPR:$Rd), 3730 (ins GPR:$Rn, GPR:$Rm, 3731 !cast<Operand>("asr_operand_" # ty):$Imm6), 3732 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"), 3733 [(set ty:$Rd, (opfrag ty:$Rn, (sra ty:$Rm, 3734 !cast<Operand>("asr_operand_" # ty):$Imm6)) 3735 )], 3736 NoItinerary>; 3737 3738 def _ror : A64I_logicalshift<sf, opc, 0b11, N, 3739 (outs GPR:$Rd), 3740 (ins GPR:$Rn, GPR:$Rm, 3741 !cast<Operand>("ror_operand_" # ty):$Imm6), 3742 !strconcat(asmop, "\t$Rd, $Rn, $Rm, $Imm6"), 3743 [(set ty:$Rd, (opfrag ty:$Rn, (rotr ty:$Rm, 3744 !cast<Operand>("ror_operand_" # ty):$Imm6)) 3745 )], 3746 NoItinerary>; 3747 } 3748 3749 def _noshift 3750 : InstAlias<!strconcat(asmop, " $Rd, $Rn, $Rm"), 3751 (!cast<Instruction>(prefix # "_lsl") GPR:$Rd, GPR:$Rn, 3752 GPR:$Rm, 0)>; 3753 3754 def : Pat<(opfrag ty:$Rn, ty:$Rm), 3755 (!cast<Instruction>(prefix # "_lsl") $Rn, $Rm, 0)>; 3756 } 3757 3758 multiclass logical_sizes<string prefix, bits<2> opc, bit N, bit commutable, 3759 string asmop, SDPatternOperator opfrag, 3760 list<Register> defs> { 3761 defm xxx : logical_shifts<prefix # "xxx", 0b1, opc, N, 3762 commutable, asmop, opfrag, i64, GPR64, defs>; 3763 defm www : logical_shifts<prefix # "www", 0b0, opc, N, 3764 commutable, asmop, opfrag, i32, GPR32, defs>; 3765 } 3766 3767 3768 defm AND : logical_sizes<"AND", 0b00, 0b0, 0b1, "and", and, []>; 3769 defm ORR : logical_sizes<"ORR", 0b01, 0b0, 0b1, "orr", or, []>; 3770 defm EOR : logical_sizes<"EOR", 0b10, 0b0, 0b1, "eor", xor, []>; 3771 defm ANDS : logical_sizes<"ANDS", 0b11, 0b0, 0b1, "ands", 3772 PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs), 3773 [{ (void)N; return false; }]>, 3774 [NZCV]>; 3775 3776 defm BIC : logical_sizes<"BIC", 0b00, 0b1, 0b0, "bic", 3777 PatFrag<(ops node:$lhs, node:$rhs), 3778 (and node:$lhs, (not node:$rhs))>, []>; 3779 defm ORN : logical_sizes<"ORN", 0b01, 0b1, 0b0, "orn", 3780 PatFrag<(ops node:$lhs, node:$rhs), 3781 (or node:$lhs, (not node:$rhs))>, []>; 3782 defm EON : logical_sizes<"EON", 0b10, 0b1, 0b0, "eon", 3783 PatFrag<(ops node:$lhs, node:$rhs), 3784 (xor node:$lhs, (not node:$rhs))>, []>; 3785 defm BICS : logical_sizes<"BICS", 0b11, 0b1, 0b0, "bics", 3786 PatFrag<(ops node:$lhs, node:$rhs), 3787 (and node:$lhs, (not node:$rhs)), 3788 [{ (void)N; return false; }]>, 3789 [NZCV]>; 3790 3791 multiclass tst_shifts<string prefix, bit sf, ValueType ty, RegisterClass GPR> { 3792 let isCommutable = 1, Rd = 0b11111, Defs = [NZCV] in { 3793 def _lsl : A64I_logicalshift<sf, 0b11, 0b00, 0b0, 3794 (outs), 3795 (ins GPR:$Rn, GPR:$Rm, 3796 !cast<Operand>("lsl_operand_" # ty):$Imm6), 3797 "tst\t$Rn, $Rm, $Imm6", 3798 [(set NZCV, (A64setcc (and ty:$Rn, (shl ty:$Rm, 3799 !cast<Operand>("lsl_operand_" # ty):$Imm6)), 3800 0, signed_cond))], 3801 NoItinerary>; 3802 3803 3804 def _lsr : A64I_logicalshift<sf, 0b11, 0b01, 0b0, 3805 (outs), 3806 (ins GPR:$Rn, GPR:$Rm, 3807 !cast<Operand>("lsr_operand_" # ty):$Imm6), 3808 "tst\t$Rn, $Rm, $Imm6", 3809 [(set NZCV, (A64setcc (and ty:$Rn, (srl ty:$Rm, 3810 !cast<Operand>("lsr_operand_" # ty):$Imm6)), 3811 0, signed_cond))], 3812 NoItinerary>; 3813 3814 def _asr : A64I_logicalshift<sf, 0b11, 0b10, 0b0, 3815 (outs), 3816 (ins GPR:$Rn, GPR:$Rm, 3817 !cast<Operand>("asr_operand_" # ty):$Imm6), 3818 "tst\t$Rn, $Rm, $Imm6", 3819 [(set NZCV, (A64setcc (and ty:$Rn, (sra ty:$Rm, 3820 !cast<Operand>("asr_operand_" # ty):$Imm6)), 3821 0, signed_cond))], 3822 NoItinerary>; 3823 3824 def _ror : A64I_logicalshift<sf, 0b11, 0b11, 0b0, 3825 (outs), 3826 (ins GPR:$Rn, GPR:$Rm, 3827 !cast<Operand>("ror_operand_" # ty):$Imm6), 3828 "tst\t$Rn, $Rm, $Imm6", 3829 [(set NZCV, (A64setcc (and ty:$Rn, (rotr ty:$Rm, 3830 !cast<Operand>("ror_operand_" # ty):$Imm6)), 3831 0, signed_cond))], 3832 NoItinerary>; 3833 } 3834 3835 def _noshift : InstAlias<"tst $Rn, $Rm", 3836 (!cast<Instruction>(prefix # "_lsl") GPR:$Rn, GPR:$Rm, 0)>; 3837 3838 def : Pat<(A64setcc (and ty:$Rn, ty:$Rm), 0, signed_cond), 3839 (!cast<Instruction>(prefix # "_lsl") $Rn, $Rm, 0)>; 3840 } 3841 3842 defm TSTxx : tst_shifts<"TSTxx", 0b1, i64, GPR64>; 3843 defm TSTww : tst_shifts<"TSTww", 0b0, i32, GPR32>; 3844 3845 3846 multiclass mvn_shifts<string prefix, bit sf, ValueType ty, RegisterClass GPR> { 3847 let isCommutable = 0, Rn = 0b11111 in { 3848 def _lsl : A64I_logicalshift<sf, 0b01, 0b00, 0b1, 3849 (outs GPR:$Rd), 3850 (ins GPR:$Rm, 3851 !cast<Operand>("lsl_operand_" # ty):$Imm6), 3852 "mvn\t$Rd, $Rm, $Imm6", 3853 [(set ty:$Rd, (not (shl ty:$Rm, 3854 !cast<Operand>("lsl_operand_" # ty):$Imm6)))], 3855 NoItinerary>; 3856 3857 3858 def _lsr : A64I_logicalshift<sf, 0b01, 0b01, 0b1, 3859 (outs GPR:$Rd), 3860 (ins GPR:$Rm, 3861 !cast<Operand>("lsr_operand_" # ty):$Imm6), 3862 "mvn\t$Rd, $Rm, $Imm6", 3863 [(set ty:$Rd, (not (srl ty:$Rm, 3864 !cast<Operand>("lsr_operand_" # ty):$Imm6)))], 3865 NoItinerary>; 3866 3867 def _asr : A64I_logicalshift<sf, 0b01, 0b10, 0b1, 3868 (outs GPR:$Rd), 3869 (ins GPR:$Rm, 3870 !cast<Operand>("asr_operand_" # ty):$Imm6), 3871 "mvn\t$Rd, $Rm, $Imm6", 3872 [(set ty:$Rd, (not (sra ty:$Rm, 3873 !cast<Operand>("asr_operand_" # ty):$Imm6)))], 3874 NoItinerary>; 3875 3876 def _ror : A64I_logicalshift<sf, 0b01, 0b11, 0b1, 3877 (outs GPR:$Rd), 3878 (ins GPR:$Rm, 3879 !cast<Operand>("ror_operand_" # ty):$Imm6), 3880 "mvn\t$Rd, $Rm, $Imm6", 3881 [(set ty:$Rd, (not (rotr ty:$Rm, 3882 !cast<Operand>("lsl_operand_" # ty):$Imm6)))], 3883 NoItinerary>; 3884 } 3885 3886 def _noshift : InstAlias<"mvn $Rn, $Rm", 3887 (!cast<Instruction>(prefix # "_lsl") GPR:$Rn, GPR:$Rm, 0)>; 3888 3889 def : Pat<(not ty:$Rm), 3890 (!cast<Instruction>(prefix # "_lsl") $Rm, 0)>; 3891 } 3892 3893 defm MVNxx : mvn_shifts<"MVNxx", 0b1, i64, GPR64>; 3894 defm MVNww : mvn_shifts<"MVNww", 0b0, i32, GPR32>; 3895 3896 def MOVxx :InstAlias<"mov $Rd, $Rm", (ORRxxx_lsl GPR64:$Rd, XZR, GPR64:$Rm, 0)>; 3897 def MOVww :InstAlias<"mov $Rd, $Rm", (ORRwww_lsl GPR32:$Rd, WZR, GPR32:$Rm, 0)>; 3898 3899 //===----------------------------------------------------------------------===// 3900 // Move wide (immediate) instructions 3901 //===----------------------------------------------------------------------===// 3902 // Contains: MOVN, MOVZ, MOVK + MOV aliases 3903 3904 // A wide variety of different relocations are needed for variants of these 3905 // instructions, so it turns out that we need a different operand for all of 3906 // them. 3907 multiclass movw_operands<string prefix, string instname, int width> { 3908 def _imm_asmoperand : AsmOperandClass { 3909 let Name = instname # width # "Shifted" # shift; 3910 let PredicateMethod = "is" # instname # width # "Imm"; 3911 let RenderMethod = "addMoveWideImmOperands"; 3912 let ParserMethod = "ParseImmWithLSLOperand"; 3913 let DiagnosticType = "MOVWUImm16"; 3914 } 3915 3916 def _imm : Operand<i64> { 3917 let ParserMatchClass = !cast<AsmOperandClass>(prefix # "_imm_asmoperand"); 3918 let PrintMethod = "printMoveWideImmOperand"; 3919 let EncoderMethod = "getMoveWideImmOpValue"; 3920 let DecoderMethod = "DecodeMoveWideImmOperand<" # width # ">"; 3921 3922 let MIOperandInfo = (ops uimm16:$UImm16, imm:$Shift); 3923 } 3924 } 3925 3926 defm movn32 : movw_operands<"movn32", "MOVN", 32>; 3927 defm movn64 : movw_operands<"movn64", "MOVN", 64>; 3928 defm movz32 : movw_operands<"movz32", "MOVZ", 32>; 3929 defm movz64 : movw_operands<"movz64", "MOVZ", 64>; 3930 defm movk32 : movw_operands<"movk32", "MOVK", 32>; 3931 defm movk64 : movw_operands<"movk64", "MOVK", 64>; 3932 3933 multiclass A64I_movwSizes<bits<2> opc, string asmop, dag ins32bit, 3934 dag ins64bit> { 3935 3936 def wii : A64I_movw<0b0, opc, (outs GPR32:$Rd), ins32bit, 3937 !strconcat(asmop, "\t$Rd, $FullImm"), 3938 [], NoItinerary> { 3939 bits<18> FullImm; 3940 let UImm16 = FullImm{15-0}; 3941 let Shift = FullImm{17-16}; 3942 } 3943 3944 def xii : A64I_movw<0b1, opc, (outs GPR64:$Rd), ins64bit, 3945 !strconcat(asmop, "\t$Rd, $FullImm"), 3946 [], NoItinerary> { 3947 bits<18> FullImm; 3948 let UImm16 = FullImm{15-0}; 3949 let Shift = FullImm{17-16}; 3950 } 3951 } 3952 3953 let isMoveImm = 1, isReMaterializable = 1, 3954 isAsCheapAsAMove = 1, hasSideEffects = 0 in { 3955 defm MOVN : A64I_movwSizes<0b00, "movn", 3956 (ins movn32_imm:$FullImm), 3957 (ins movn64_imm:$FullImm)>; 3958 3959 // Some relocations are able to convert between a MOVZ and a MOVN. If these 3960 // are applied the instruction must be emitted with the corresponding bits as 3961 // 0, which means a MOVZ needs to override that bit from the default. 3962 let PostEncoderMethod = "fixMOVZ" in 3963 defm MOVZ : A64I_movwSizes<0b10, "movz", 3964 (ins movz32_imm:$FullImm), 3965 (ins movz64_imm:$FullImm)>; 3966 } 3967 3968 let Constraints = "$src = $Rd" in 3969 defm MOVK : A64I_movwSizes<0b11, "movk", 3970 (ins GPR32:$src, movk32_imm:$FullImm), 3971 (ins GPR64:$src, movk64_imm:$FullImm)>; 3972 3973 3974 // And now the "MOV" aliases. These also need their own operands because what 3975 // they accept is completely different to what the base instructions accept. 3976 multiclass movalias_operand<string prefix, string basename, 3977 string immpredicate, int width> { 3978 def _asmoperand : AsmOperandClass { 3979 let Name = basename # width # "MovAlias"; 3980 let PredicateMethod 3981 = "isMoveWideMovAlias<" # width # ", A64Imms::" # immpredicate # ">"; 3982 let RenderMethod 3983 = "addMoveWideMovAliasOperands<" # width # ", " 3984 # "A64Imms::" # immpredicate # ">"; 3985 } 3986 3987 def _movimm : Operand<i64> { 3988 let ParserMatchClass = !cast<AsmOperandClass>(prefix # "_asmoperand"); 3989 3990 let MIOperandInfo = (ops uimm16:$UImm16, imm:$Shift); 3991 } 3992 } 3993 3994 defm movz32 : movalias_operand<"movz32", "MOVZ", "isMOVZImm", 32>; 3995 defm movz64 : movalias_operand<"movz64", "MOVZ", "isMOVZImm", 64>; 3996 defm movn32 : movalias_operand<"movn32", "MOVN", "isOnlyMOVNImm", 32>; 3997 defm movn64 : movalias_operand<"movn64", "MOVN", "isOnlyMOVNImm", 64>; 3998 3999 // FIXME: these are officially canonical aliases, but TableGen is too limited to 4000 // print them at the moment. I believe in this case an "AliasPredicate" method 4001 // will need to be implemented. to allow it, as well as the more generally 4002 // useful handling of non-register, non-constant operands. 4003 class movalias<Instruction INST, RegisterClass GPR, Operand operand> 4004 : InstAlias<"mov $Rd, $FullImm", (INST GPR:$Rd, operand:$FullImm)>; 4005 4006 def : movalias<MOVZwii, GPR32, movz32_movimm>; 4007 def : movalias<MOVZxii, GPR64, movz64_movimm>; 4008 def : movalias<MOVNwii, GPR32, movn32_movimm>; 4009 def : movalias<MOVNxii, GPR64, movn64_movimm>; 4010 4011 def movw_addressref_g0 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<0>">; 4012 def movw_addressref_g1 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<1>">; 4013 def movw_addressref_g2 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<2>">; 4014 def movw_addressref_g3 : ComplexPattern<i64, 2, "SelectMOVWAddressRef<3>">; 4015 4016 def : Pat<(A64WrapperLarge movw_addressref_g3:$G3, movw_addressref_g2:$G2, 4017 movw_addressref_g1:$G1, movw_addressref_g0:$G0), 4018 (MOVKxii (MOVKxii (MOVKxii (MOVZxii movw_addressref_g3:$G3), 4019 movw_addressref_g2:$G2), 4020 movw_addressref_g1:$G1), 4021 movw_addressref_g0:$G0)>; 4022 4023 //===----------------------------------------------------------------------===// 4024 // PC-relative addressing instructions 4025 //===----------------------------------------------------------------------===// 4026 // Contains: ADR, ADRP 4027 4028 def adr_label : Operand<i64> { 4029 let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_adr_prel>"; 4030 4031 // This label is a 21-bit offset from PC, unscaled 4032 let PrintMethod = "printLabelOperand<21, 1>"; 4033 let ParserMatchClass = label_asmoperand<21, 1>; 4034 let OperandType = "OPERAND_PCREL"; 4035 } 4036 4037 def adrp_label_asmoperand : AsmOperandClass { 4038 let Name = "AdrpLabel"; 4039 let RenderMethod = "addLabelOperands<21, 4096>"; 4040 let DiagnosticType = "Label"; 4041 } 4042 4043 def adrp_label : Operand<i64> { 4044 let EncoderMethod = "getAdrpLabelOpValue"; 4045 4046 // This label is a 21-bit offset from PC, scaled by the page-size: 4096. 4047 let PrintMethod = "printLabelOperand<21, 4096>"; 4048 let ParserMatchClass = adrp_label_asmoperand; 4049 let OperandType = "OPERAND_PCREL"; 4050 } 4051 4052 let hasSideEffects = 0 in { 4053 def ADRxi : A64I_PCADR<0b0, (outs GPR64:$Rd), (ins adr_label:$Label), 4054 "adr\t$Rd, $Label", [], NoItinerary>; 4055 4056 def ADRPxi : A64I_PCADR<0b1, (outs GPR64:$Rd), (ins adrp_label:$Label), 4057 "adrp\t$Rd, $Label", [], NoItinerary>; 4058 } 4059 4060 //===----------------------------------------------------------------------===// 4061 // System instructions 4062 //===----------------------------------------------------------------------===// 4063 // Contains: HINT, CLREX, DSB, DMB, ISB, MSR, SYS, SYSL, MRS 4064 // + aliases IC, DC, AT, TLBI, NOP, YIELD, WFE, WFI, SEV, SEVL 4065 4066 // Op1 and Op2 fields are sometimes simple 3-bit unsigned immediate values. 4067 def uimm3_asmoperand : AsmOperandClass { 4068 let Name = "UImm3"; 4069 let PredicateMethod = "isUImm<3>"; 4070 let RenderMethod = "addImmOperands"; 4071 let DiagnosticType = "UImm3"; 4072 } 4073 4074 def uimm3 : Operand<i32> { 4075 let ParserMatchClass = uimm3_asmoperand; 4076 } 4077 4078 // The HINT alias can accept a simple unsigned 7-bit immediate. 4079 def uimm7_asmoperand : AsmOperandClass { 4080 let Name = "UImm7"; 4081 let PredicateMethod = "isUImm<7>"; 4082 let RenderMethod = "addImmOperands"; 4083 let DiagnosticType = "UImm7"; 4084 } 4085 4086 def uimm7 : Operand<i32> { 4087 let ParserMatchClass = uimm7_asmoperand; 4088 } 4089 4090 // Multiclass namedimm is defined with the prefetch operands. Most of these fit 4091 // into the NamedImmMapper scheme well: they either accept a named operand or 4092 // any immediate under a particular value (which may be 0, implying no immediate 4093 // is allowed). 4094 defm dbarrier : namedimm<"dbarrier", "A64DB::DBarrierMapper">; 4095 defm isb : namedimm<"isb", "A64ISB::ISBMapper">; 4096 defm ic : namedimm<"ic", "A64IC::ICMapper">; 4097 defm dc : namedimm<"dc", "A64DC::DCMapper">; 4098 defm at : namedimm<"at", "A64AT::ATMapper">; 4099 defm tlbi : namedimm<"tlbi", "A64TLBI::TLBIMapper">; 4100 4101 // However, MRS and MSR are more complicated for a few reasons: 4102 // * There are ~1000 generic names S3_<op1>_<CRn>_<CRm>_<Op2> which have an 4103 // implementation-defined effect 4104 // * Most registers are shared, but some are read-only or write-only. 4105 // * There is a variant of MSR which accepts the same register name (SPSel), 4106 // but which would have a different encoding. 4107 4108 // In principle these could be resolved in with more complicated subclasses of 4109 // NamedImmMapper, however that imposes an overhead on other "named 4110 // immediates". Both in concrete terms with virtual tables and in unnecessary 4111 // abstraction. 4112 4113 // The solution adopted here is to take the MRS/MSR Mappers out of the usual 4114 // hierarchy (they're not derived from NamedImmMapper) and to add logic for 4115 // their special situation. 4116 def mrs_asmoperand : AsmOperandClass { 4117 let Name = "MRS"; 4118 let ParserMethod = "ParseSysRegOperand"; 4119 let DiagnosticType = "MRS"; 4120 } 4121 4122 def mrs_op : Operand<i32> { 4123 let ParserMatchClass = mrs_asmoperand; 4124 let PrintMethod = "printMRSOperand"; 4125 let DecoderMethod = "DecodeMRSOperand"; 4126 } 4127 4128 def msr_asmoperand : AsmOperandClass { 4129 let Name = "MSRWithReg"; 4130 4131 // Note that SPSel is valid for both this and the pstate operands, but with 4132 // different immediate encodings. This is why these operands provide a string 4133 // AArch64Operand rather than an immediate. The overlap is small enough that 4134 // it could be resolved with hackery now, but who can say in future? 4135 let ParserMethod = "ParseSysRegOperand"; 4136 let DiagnosticType = "MSR"; 4137 } 4138 4139 def msr_op : Operand<i32> { 4140 let ParserMatchClass = msr_asmoperand; 4141 let PrintMethod = "printMSROperand"; 4142 let DecoderMethod = "DecodeMSROperand"; 4143 } 4144 4145 def pstate_asmoperand : AsmOperandClass { 4146 let Name = "MSRPState"; 4147 // See comment above about parser. 4148 let ParserMethod = "ParseSysRegOperand"; 4149 let DiagnosticType = "MSR"; 4150 } 4151 4152 def pstate_op : Operand<i32> { 4153 let ParserMatchClass = pstate_asmoperand; 4154 let PrintMethod = "printNamedImmOperand<A64PState::PStateMapper>"; 4155 let DecoderMethod = "DecodeNamedImmOperand<A64PState::PStateMapper>"; 4156 } 4157 4158 // When <CRn> is specified, an assembler should accept something like "C4", not 4159 // the usual "#4" immediate. 4160 def CRx_asmoperand : AsmOperandClass { 4161 let Name = "CRx"; 4162 let PredicateMethod = "isUImm<4>"; 4163 let RenderMethod = "addImmOperands"; 4164 let ParserMethod = "ParseCRxOperand"; 4165 // Diagnostics are handled in all cases by ParseCRxOperand. 4166 } 4167 4168 def CRx : Operand<i32> { 4169 let ParserMatchClass = CRx_asmoperand; 4170 let PrintMethod = "printCRxOperand"; 4171 } 4172 4173 4174 // Finally, we can start defining the instructions. 4175 4176 // HINT is straightforward, with a few aliases. 4177 def HINTi : A64I_system<0b0, (outs), (ins uimm7:$UImm7), "hint\t$UImm7", 4178 [], NoItinerary> { 4179 bits<7> UImm7; 4180 let CRm = UImm7{6-3}; 4181 let Op2 = UImm7{2-0}; 4182 4183 let Op0 = 0b00; 4184 let Op1 = 0b011; 4185 let CRn = 0b0010; 4186 let Rt = 0b11111; 4187 } 4188 4189 def : InstAlias<"nop", (HINTi 0)>; 4190 def : InstAlias<"yield", (HINTi 1)>; 4191 def : InstAlias<"wfe", (HINTi 2)>; 4192 def : InstAlias<"wfi", (HINTi 3)>; 4193 def : InstAlias<"sev", (HINTi 4)>; 4194 def : InstAlias<"sevl", (HINTi 5)>; 4195 4196 // Quite a few instructions then follow a similar pattern of fixing common 4197 // fields in the bitpattern, we'll define a helper-class for them. 4198 class simple_sys<bits<2> op0, bits<3> op1, bits<4> crn, bits<3> op2, 4199 Operand operand, string asmop> 4200 : A64I_system<0b0, (outs), (ins operand:$CRm), !strconcat(asmop, "\t$CRm"), 4201 [], NoItinerary> { 4202 let Op0 = op0; 4203 let Op1 = op1; 4204 let CRn = crn; 4205 let Op2 = op2; 4206 let Rt = 0b11111; 4207 } 4208 4209 4210 def CLREXi : simple_sys<0b00, 0b011, 0b0011, 0b010, uimm4, "clrex">; 4211 def DSBi : simple_sys<0b00, 0b011, 0b0011, 0b100, dbarrier_op, "dsb">; 4212 def DMBi : simple_sys<0b00, 0b011, 0b0011, 0b101, dbarrier_op, "dmb">; 4213 def ISBi : simple_sys<0b00, 0b011, 0b0011, 0b110, isb_op, "isb">; 4214 4215 def : InstAlias<"clrex", (CLREXi 0b1111)>; 4216 def : InstAlias<"isb", (ISBi 0b1111)>; 4217 4218 // (DMBi 0xb) is a "DMB ISH" instruciton, appropriate for Linux SMP 4219 // configurations at least. 4220 def : Pat<(atomic_fence imm, imm), (DMBi 0xb)>; 4221 4222 // Any SYS bitpattern can be represented with a complex and opaque "SYS" 4223 // instruction. 4224 def SYSiccix : A64I_system<0b0, (outs), 4225 (ins uimm3:$Op1, CRx:$CRn, CRx:$CRm, 4226 uimm3:$Op2, GPR64:$Rt), 4227 "sys\t$Op1, $CRn, $CRm, $Op2, $Rt", 4228 [], NoItinerary> { 4229 let Op0 = 0b01; 4230 } 4231 4232 // You can skip the Xt argument whether it makes sense or not for the generic 4233 // SYS instruction. 4234 def : InstAlias<"sys $Op1, $CRn, $CRm, $Op2", 4235 (SYSiccix uimm3:$Op1, CRx:$CRn, CRx:$CRm, uimm3:$Op2, XZR)>; 4236 4237 4238 // But many have aliases, which obviously don't fit into 4239 class SYSalias<dag ins, string asmstring> 4240 : A64I_system<0b0, (outs), ins, asmstring, [], NoItinerary> { 4241 let isAsmParserOnly = 1; 4242 4243 bits<14> SysOp; 4244 let Op0 = 0b01; 4245 let Op1 = SysOp{13-11}; 4246 let CRn = SysOp{10-7}; 4247 let CRm = SysOp{6-3}; 4248 let Op2 = SysOp{2-0}; 4249 } 4250 4251 def ICix : SYSalias<(ins ic_op:$SysOp, GPR64:$Rt), "ic\t$SysOp, $Rt">; 4252 4253 def ICi : SYSalias<(ins ic_op:$SysOp), "ic\t$SysOp"> { 4254 let Rt = 0b11111; 4255 } 4256 4257 def DCix : SYSalias<(ins dc_op:$SysOp, GPR64:$Rt), "dc\t$SysOp, $Rt">; 4258 def ATix : SYSalias<(ins at_op:$SysOp, GPR64:$Rt), "at\t$SysOp, $Rt">; 4259 4260 def TLBIix : SYSalias<(ins tlbi_op:$SysOp, GPR64:$Rt), "tlbi\t$SysOp, $Rt">; 4261 4262 def TLBIi : SYSalias<(ins tlbi_op:$SysOp), "tlbi\t$SysOp"> { 4263 let Rt = 0b11111; 4264 } 4265 4266 4267 def SYSLxicci : A64I_system<0b1, (outs GPR64:$Rt), 4268 (ins uimm3:$Op1, CRx:$CRn, CRx:$CRm, uimm3:$Op2), 4269 "sysl\t$Rt, $Op1, $CRn, $CRm, $Op2", 4270 [], NoItinerary> { 4271 let Op0 = 0b01; 4272 } 4273 4274 // The instructions themselves are rather simple for MSR and MRS. 4275 def MSRix : A64I_system<0b0, (outs), (ins msr_op:$SysReg, GPR64:$Rt), 4276 "msr\t$SysReg, $Rt", [], NoItinerary> { 4277 bits<16> SysReg; 4278 let Op0 = SysReg{15-14}; 4279 let Op1 = SysReg{13-11}; 4280 let CRn = SysReg{10-7}; 4281 let CRm = SysReg{6-3}; 4282 let Op2 = SysReg{2-0}; 4283 } 4284 4285 def MRSxi : A64I_system<0b1, (outs GPR64:$Rt), (ins mrs_op:$SysReg), 4286 "mrs\t$Rt, $SysReg", [], NoItinerary> { 4287 bits<16> SysReg; 4288 let Op0 = SysReg{15-14}; 4289 let Op1 = SysReg{13-11}; 4290 let CRn = SysReg{10-7}; 4291 let CRm = SysReg{6-3}; 4292 let Op2 = SysReg{2-0}; 4293 } 4294 4295 def MSRii : A64I_system<0b0, (outs), (ins pstate_op:$PState, uimm4:$CRm), 4296 "msr\t$PState, $CRm", [], NoItinerary> { 4297 bits<6> PState; 4298 4299 let Op0 = 0b00; 4300 let Op1 = PState{5-3}; 4301 let CRn = 0b0100; 4302 let Op2 = PState{2-0}; 4303 let Rt = 0b11111; 4304 } 4305 4306 //===----------------------------------------------------------------------===// 4307 // Test & branch (immediate) instructions 4308 //===----------------------------------------------------------------------===// 4309 // Contains: TBZ, TBNZ 4310 4311 // The bit to test is a simple unsigned 6-bit immediate in the X-register 4312 // versions. 4313 def uimm6 : Operand<i64> { 4314 let ParserMatchClass = uimm6_asmoperand; 4315 } 4316 4317 def label_wid14_scal4_asmoperand : label_asmoperand<14, 4>; 4318 4319 def tbimm_target : Operand<OtherVT> { 4320 let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_tstbr>"; 4321 4322 // This label is a 14-bit offset from PC, scaled by the instruction-width: 4. 4323 let PrintMethod = "printLabelOperand<14, 4>"; 4324 let ParserMatchClass = label_wid14_scal4_asmoperand; 4325 4326 let OperandType = "OPERAND_PCREL"; 4327 } 4328 4329 def A64eq : ImmLeaf<i32, [{ return Imm == A64CC::EQ; }]>; 4330 def A64ne : ImmLeaf<i32, [{ return Imm == A64CC::NE; }]>; 4331 4332 // These instructions correspond to patterns involving "and" with a power of 4333 // two, which we need to be able to select. 4334 def tstb64_pat : ComplexPattern<i64, 1, "SelectTSTBOperand<64>">; 4335 def tstb32_pat : ComplexPattern<i32, 1, "SelectTSTBOperand<32>">; 4336 4337 let isBranch = 1, isTerminator = 1 in { 4338 def TBZxii : A64I_TBimm<0b0, (outs), 4339 (ins GPR64:$Rt, uimm6:$Imm, tbimm_target:$Label), 4340 "tbz\t$Rt, $Imm, $Label", 4341 [(A64br_cc (A64cmp (and i64:$Rt, tstb64_pat:$Imm), 0), 4342 A64eq, bb:$Label)], 4343 NoItinerary>; 4344 4345 def TBNZxii : A64I_TBimm<0b1, (outs), 4346 (ins GPR64:$Rt, uimm6:$Imm, tbimm_target:$Label), 4347 "tbnz\t$Rt, $Imm, $Label", 4348 [(A64br_cc (A64cmp (and i64:$Rt, tstb64_pat:$Imm), 0), 4349 A64ne, bb:$Label)], 4350 NoItinerary>; 4351 4352 4353 // Note, these instructions overlap with the above 64-bit patterns. This is 4354 // intentional, "tbz x3, #1, somewhere" and "tbz w3, #1, somewhere" would both 4355 // do the same thing and are both permitted assembly. They also both have 4356 // sensible DAG patterns. 4357 def TBZwii : A64I_TBimm<0b0, (outs), 4358 (ins GPR32:$Rt, uimm5:$Imm, tbimm_target:$Label), 4359 "tbz\t$Rt, $Imm, $Label", 4360 [(A64br_cc (A64cmp (and i32:$Rt, tstb32_pat:$Imm), 0), 4361 A64eq, bb:$Label)], 4362 NoItinerary> { 4363 let Imm{5} = 0b0; 4364 } 4365 4366 def TBNZwii : A64I_TBimm<0b1, (outs), 4367 (ins GPR32:$Rt, uimm5:$Imm, tbimm_target:$Label), 4368 "tbnz\t$Rt, $Imm, $Label", 4369 [(A64br_cc (A64cmp (and i32:$Rt, tstb32_pat:$Imm), 0), 4370 A64ne, bb:$Label)], 4371 NoItinerary> { 4372 let Imm{5} = 0b0; 4373 } 4374 } 4375 4376 //===----------------------------------------------------------------------===// 4377 // Unconditional branch (immediate) instructions 4378 //===----------------------------------------------------------------------===// 4379 // Contains: B, BL 4380 4381 def label_wid26_scal4_asmoperand : label_asmoperand<26, 4>; 4382 4383 def bimm_target : Operand<OtherVT> { 4384 let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_uncondbr>"; 4385 4386 // This label is a 26-bit offset from PC, scaled by the instruction-width: 4. 4387 let PrintMethod = "printLabelOperand<26, 4>"; 4388 let ParserMatchClass = label_wid26_scal4_asmoperand; 4389 4390 let OperandType = "OPERAND_PCREL"; 4391 } 4392 4393 def blimm_target : Operand<i64> { 4394 let EncoderMethod = "getLabelOpValue<AArch64::fixup_a64_call>"; 4395 4396 // This label is a 26-bit offset from PC, scaled by the instruction-width: 4. 4397 let PrintMethod = "printLabelOperand<26, 4>"; 4398 let ParserMatchClass = label_wid26_scal4_asmoperand; 4399 4400 let OperandType = "OPERAND_PCREL"; 4401 } 4402 4403 class A64I_BimmImpl<bit op, string asmop, list<dag> patterns, Operand lbl_type> 4404 : A64I_Bimm<op, (outs), (ins lbl_type:$Label), 4405 !strconcat(asmop, "\t$Label"), patterns, 4406 NoItinerary>; 4407 4408 let isBranch = 1 in { 4409 def Bimm : A64I_BimmImpl<0b0, "b", [(br bb:$Label)], bimm_target> { 4410 let isTerminator = 1; 4411 let isBarrier = 1; 4412 } 4413 4414 def BLimm : A64I_BimmImpl<0b1, "bl", 4415 [(AArch64Call tglobaladdr:$Label)], blimm_target> { 4416 let isCall = 1; 4417 let Defs = [X30]; 4418 } 4419 } 4420 4421 def : Pat<(AArch64Call texternalsym:$Label), (BLimm texternalsym:$Label)>; 4422 4423 //===----------------------------------------------------------------------===// 4424 // Unconditional branch (register) instructions 4425 //===----------------------------------------------------------------------===// 4426 // Contains: BR, BLR, RET, ERET, DRP. 4427 4428 // Most of the notional opcode fields in the A64I_Breg format are fixed in A64 4429 // at the moment. 4430 class A64I_BregImpl<bits<4> opc, 4431 dag outs, dag ins, string asmstr, list<dag> patterns, 4432 InstrItinClass itin = NoItinerary> 4433 : A64I_Breg<opc, 0b11111, 0b000000, 0b00000, 4434 outs, ins, asmstr, patterns, itin> { 4435 let isBranch = 1; 4436 let isIndirectBranch = 1; 4437 } 4438 4439 // Note that these are not marked isCall or isReturn because as far as LLVM is 4440 // concerned they're not. "ret" is just another jump unless it has been selected 4441 // by LLVM as the function's return. 4442 4443 let isBranch = 1 in { 4444 def BRx : A64I_BregImpl<0b0000,(outs), (ins GPR64:$Rn), 4445 "br\t$Rn", [(brind i64:$Rn)]> { 4446 let isBarrier = 1; 4447 let isTerminator = 1; 4448 } 4449 4450 def BLRx : A64I_BregImpl<0b0001, (outs), (ins GPR64:$Rn), 4451 "blr\t$Rn", [(AArch64Call i64:$Rn)]> { 4452 let isBarrier = 0; 4453 let isCall = 1; 4454 let Defs = [X30]; 4455 } 4456 4457 def RETx : A64I_BregImpl<0b0010, (outs), (ins GPR64:$Rn), 4458 "ret\t$Rn", []> { 4459 let isBarrier = 1; 4460 let isTerminator = 1; 4461 let isReturn = 1; 4462 } 4463 4464 // Create a separate pseudo-instruction for codegen to use so that we don't 4465 // flag x30 as used in every function. It'll be restored before the RET by the 4466 // epilogue if it's legitimately used. 4467 def RET : A64PseudoExpand<(outs), (ins), [(A64ret)], (RETx (ops X30))> { 4468 let isTerminator = 1; 4469 let isBarrier = 1; 4470 let isReturn = 1; 4471 } 4472 4473 def ERET : A64I_BregImpl<0b0100, (outs), (ins), "eret", []> { 4474 let Rn = 0b11111; 4475 let isBarrier = 1; 4476 let isTerminator = 1; 4477 let isReturn = 1; 4478 } 4479 4480 def DRPS : A64I_BregImpl<0b0101, (outs), (ins), "drps", []> { 4481 let Rn = 0b11111; 4482 let isBarrier = 1; 4483 } 4484 } 4485 4486 def RETAlias : InstAlias<"ret", (RETx X30)>; 4487 4488 4489 //===----------------------------------------------------------------------===// 4490 // Address generation patterns 4491 //===----------------------------------------------------------------------===// 4492 4493 // Primary method of address generation for the small/absolute memory model is 4494 // an ADRP/ADR pair: 4495 // ADRP x0, some_variable 4496 // ADD x0, x0, #:lo12:some_variable 4497 // 4498 // The load/store elision of the ADD is accomplished when selecting 4499 // addressing-modes. This just mops up the cases where that doesn't work and we 4500 // really need an address in some register. 4501 4502 // This wrapper applies a LO12 modifier to the address. Otherwise we could just 4503 // use the same address. 4504 4505 class ADRP_ADD<SDNode Wrapper, SDNode addrop> 4506 : Pat<(Wrapper addrop:$Hi, addrop:$Lo12, (i32 imm)), 4507 (ADDxxi_lsl0_s (ADRPxi addrop:$Hi), addrop:$Lo12)>; 4508 4509 def : ADRP_ADD<A64WrapperSmall, tblockaddress>; 4510 def : ADRP_ADD<A64WrapperSmall, texternalsym>; 4511 def : ADRP_ADD<A64WrapperSmall, tglobaladdr>; 4512 def : ADRP_ADD<A64WrapperSmall, tglobaltlsaddr>; 4513 def : ADRP_ADD<A64WrapperSmall, tjumptable>; 4514 4515 //===----------------------------------------------------------------------===// 4516 // GOT access patterns 4517 //===----------------------------------------------------------------------===// 4518 4519 class GOTLoadSmall<SDNode addrfrag> 4520 : Pat<(A64GOTLoad (A64WrapperSmall addrfrag:$Hi, addrfrag:$Lo12, 8)), 4521 (LS64_LDR (ADRPxi addrfrag:$Hi), addrfrag:$Lo12)>; 4522 4523 def : GOTLoadSmall<texternalsym>; 4524 def : GOTLoadSmall<tglobaladdr>; 4525 def : GOTLoadSmall<tglobaltlsaddr>; 4526 4527 //===----------------------------------------------------------------------===// 4528 // Tail call handling 4529 //===----------------------------------------------------------------------===// 4530 4531 let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [XSP] in { 4532 def TC_RETURNdi 4533 : PseudoInst<(outs), (ins i64imm:$dst, i32imm:$FPDiff), 4534 [(AArch64tcret tglobaladdr:$dst, (i32 timm:$FPDiff))]>; 4535 4536 def TC_RETURNxi 4537 : PseudoInst<(outs), (ins tcGPR64:$dst, i32imm:$FPDiff), 4538 [(AArch64tcret i64:$dst, (i32 timm:$FPDiff))]>; 4539 } 4540 4541 let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, 4542 Uses = [XSP] in { 4543 def TAIL_Bimm : A64PseudoExpand<(outs), (ins bimm_target:$Label), [], 4544 (Bimm bimm_target:$Label)>; 4545 4546 def TAIL_BRx : A64PseudoExpand<(outs), (ins tcGPR64:$Rd), [], 4547 (BRx GPR64:$Rd)>; 4548 } 4549 4550 4551 def : Pat<(AArch64tcret texternalsym:$dst, (i32 timm:$FPDiff)), 4552 (TC_RETURNdi texternalsym:$dst, imm:$FPDiff)>; 4553 4554 //===----------------------------------------------------------------------===// 4555 // Thread local storage 4556 //===----------------------------------------------------------------------===// 4557 4558 // This is a pseudo-instruction representing the ".tlsdesccall" directive in 4559 // assembly. Its effect is to insert an R_AARCH64_TLSDESC_CALL relocation at the 4560 // current location. It should always be immediately followed by a BLR 4561 // instruction, and is intended solely for relaxation by the linker. 4562 4563 def : Pat<(A64threadpointer), (MRSxi 0xde82)>; 4564 4565 def TLSDESCCALL : PseudoInst<(outs), (ins i64imm:$Lbl), []> { 4566 let hasSideEffects = 1; 4567 } 4568 4569 def TLSDESC_BLRx : PseudoInst<(outs), (ins GPR64:$Rn, i64imm:$Var), 4570 [(A64tlsdesc_blr i64:$Rn, tglobaltlsaddr:$Var)]> { 4571 let isCall = 1; 4572 let Defs = [X30]; 4573 } 4574 4575 def : Pat<(A64tlsdesc_blr i64:$Rn, texternalsym:$Var), 4576 (TLSDESC_BLRx $Rn, texternalsym:$Var)>; 4577 4578 //===----------------------------------------------------------------------===// 4579 // Bitfield patterns 4580 //===----------------------------------------------------------------------===// 4581 4582 def bfi32_lsb_to_immr : SDNodeXForm<imm, [{ 4583 return CurDAG->getTargetConstant((32 - N->getZExtValue()) % 32, MVT::i64); 4584 }]>; 4585 4586 def bfi64_lsb_to_immr : SDNodeXForm<imm, [{ 4587 return CurDAG->getTargetConstant((64 - N->getZExtValue()) % 64, MVT::i64); 4588 }]>; 4589 4590 def bfi_width_to_imms : SDNodeXForm<imm, [{ 4591 return CurDAG->getTargetConstant(N->getZExtValue() - 1, MVT::i64); 4592 }]>; 4593 4594 4595 // The simpler patterns deal with cases where no AND mask is actually needed 4596 // (either all bits are used or the low 32 bits are used). 4597 let AddedComplexity = 10 in { 4598 4599 def : Pat<(A64Bfi i64:$src, i64:$Rn, imm:$ImmR, imm:$ImmS), 4600 (BFIxxii $src, $Rn, 4601 (bfi64_lsb_to_immr (i64 imm:$ImmR)), 4602 (bfi_width_to_imms (i64 imm:$ImmS)))>; 4603 4604 def : Pat<(A64Bfi i32:$src, i32:$Rn, imm:$ImmR, imm:$ImmS), 4605 (BFIwwii $src, $Rn, 4606 (bfi32_lsb_to_immr (i64 imm:$ImmR)), 4607 (bfi_width_to_imms (i64 imm:$ImmS)))>; 4608 4609 4610 def : Pat<(and (A64Bfi i64:$src, i64:$Rn, imm:$ImmR, imm:$ImmS), 4611 (i64 4294967295)), 4612 (SUBREG_TO_REG (i64 0), 4613 (BFIwwii (EXTRACT_SUBREG $src, sub_32), 4614 (EXTRACT_SUBREG $Rn, sub_32), 4615 (bfi32_lsb_to_immr (i64 imm:$ImmR)), 4616 (bfi_width_to_imms (i64 imm:$ImmS))), 4617 sub_32)>; 4618 4619 } 4620 4621 //===----------------------------------------------------------------------===// 4622 // Miscellaneous patterns 4623 //===----------------------------------------------------------------------===// 4624 4625 // Truncation from 64 to 32-bits just involves renaming your register. 4626 def : Pat<(i32 (trunc i64:$val)), (EXTRACT_SUBREG $val, sub_32)>; 4627 4628 // Similarly, extension where we don't care about the high bits is 4629 // just a rename. 4630 def : Pat<(i64 (anyext i32:$val)), 4631 (INSERT_SUBREG (IMPLICIT_DEF), $val, sub_32)>; 4632 4633 // SELECT instructions providing f128 types need to be handled by a 4634 // pseudo-instruction since the eventual code will need to introduce basic 4635 // blocks and control flow. 4636 def F128CSEL : PseudoInst<(outs FPR128:$Rd), 4637 (ins FPR128:$Rn, FPR128:$Rm, cond_code_op:$Cond), 4638 [(set f128:$Rd, (simple_select f128:$Rn, f128:$Rm))]> { 4639 let Uses = [NZCV]; 4640 let usesCustomInserter = 1; 4641 } 4642 4643 //===----------------------------------------------------------------------===// 4644 // Load/store patterns 4645 //===----------------------------------------------------------------------===// 4646 4647 // There are lots of patterns here, because we need to allow at least three 4648 // parameters to vary independently. 4649 // 1. Instruction: "ldrb w9, [sp]", "ldrh w9, [sp]", ... 4650 // 2. LLVM source: zextloadi8, anyextloadi8, ... 4651 // 3. Address-generation: A64Wrapper, (add BASE, OFFSET), ... 4652 // 4653 // The biggest problem turns out to be the address-generation variable. At the 4654 // point of instantiation we need to produce two DAGs, one for the pattern and 4655 // one for the instruction. Doing this at the lowest level of classes doesn't 4656 // work. 4657 // 4658 // Consider the simple uimm12 addressing mode, and the desire to match both (add 4659 // GPR64xsp:$Rn, uimm12:$Offset) and GPR64xsp:$Rn, particularly on the 4660 // instruction side. We'd need to insert either "GPR64xsp" and "uimm12" or 4661 // "GPR64xsp" and "0" into an unknown dag. !subst is not capable of this 4662 // operation, and PatFrags are for selection not output. 4663 // 4664 // As a result, the address-generation patterns are the final 4665 // instantiations. However, we do still need to vary the operand for the address 4666 // further down (At the point we're deciding A64WrapperSmall, we don't know 4667 // the memory width of the operation). 4668 4669 //===------------------------------ 4670 // 1. Basic infrastructural defs 4671 //===------------------------------ 4672 4673 // First, some simple classes for !foreach and !subst to use: 4674 class Decls { 4675 dag pattern; 4676 } 4677 4678 def decls : Decls; 4679 def ALIGN; 4680 def INST; 4681 def OFFSET; 4682 def SHIFT; 4683 4684 // You can't use !subst on an actual immediate, but you *can* use it on an 4685 // operand record that happens to match a single immediate. So we do. 4686 def imm_eq0 : ImmLeaf<i64, [{ return Imm == 0; }]>; 4687 def imm_eq1 : ImmLeaf<i64, [{ return Imm == 1; }]>; 4688 def imm_eq2 : ImmLeaf<i64, [{ return Imm == 2; }]>; 4689 def imm_eq3 : ImmLeaf<i64, [{ return Imm == 3; }]>; 4690 def imm_eq4 : ImmLeaf<i64, [{ return Imm == 4; }]>; 4691 4692 // If the low bits of a pointer are known to be 0 then an "or" is just as good 4693 // as addition for computing an offset. This fragment forwards that check for 4694 // TableGen's use. 4695 def add_like_or : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs), 4696 [{ 4697 return CurDAG->isBaseWithConstantOffset(SDValue(N, 0)); 4698 }]>; 4699 4700 // Load/store (unsigned immediate) operations with relocations against global 4701 // symbols (for lo12) are only valid if those symbols have correct alignment 4702 // (since the immediate offset is divided by the access scale, it can't have a 4703 // remainder). 4704 // 4705 // The guaranteed alignment is provided as part of the WrapperSmall 4706 // operation, and checked against one of these. 4707 def any_align : ImmLeaf<i32, [{ (void)Imm; return true; }]>; 4708 def min_align2 : ImmLeaf<i32, [{ return Imm >= 2; }]>; 4709 def min_align4 : ImmLeaf<i32, [{ return Imm >= 4; }]>; 4710 def min_align8 : ImmLeaf<i32, [{ return Imm >= 8; }]>; 4711 def min_align16 : ImmLeaf<i32, [{ return Imm >= 16; }]>; 4712 4713 // "Normal" load/store instructions can be used on atomic operations, provided 4714 // the ordering parameter is at most "monotonic". Anything above that needs 4715 // special handling with acquire/release instructions. 4716 class simple_load<PatFrag base> 4717 : PatFrag<(ops node:$ptr), (base node:$ptr), [{ 4718 return cast<AtomicSDNode>(N)->getOrdering() <= Monotonic; 4719 }]>; 4720 4721 def atomic_load_simple_i8 : simple_load<atomic_load_8>; 4722 def atomic_load_simple_i16 : simple_load<atomic_load_16>; 4723 def atomic_load_simple_i32 : simple_load<atomic_load_32>; 4724 def atomic_load_simple_i64 : simple_load<atomic_load_64>; 4725 4726 class simple_store<PatFrag base> 4727 : PatFrag<(ops node:$ptr, node:$val), (base node:$ptr, node:$val), [{ 4728 return cast<AtomicSDNode>(N)->getOrdering() <= Monotonic; 4729 }]>; 4730 4731 def atomic_store_simple_i8 : simple_store<atomic_store_8>; 4732 def atomic_store_simple_i16 : simple_store<atomic_store_16>; 4733 def atomic_store_simple_i32 : simple_store<atomic_store_32>; 4734 def atomic_store_simple_i64 : simple_store<atomic_store_64>; 4735 4736 //===------------------------------ 4737 // 2. UImm12 and SImm9 4738 //===------------------------------ 4739 4740 // These instructions have two operands providing the address so they can be 4741 // treated similarly for most purposes. 4742 4743 //===------------------------------ 4744 // 2.1 Base patterns covering extend/truncate semantics 4745 //===------------------------------ 4746 4747 // Atomic patterns can be shared between integer operations of all sizes, a 4748 // quick multiclass here allows reuse. 4749 multiclass ls_atomic_pats<Instruction LOAD, Instruction STORE, dag Base, 4750 dag Offset, dag address, ValueType transty, 4751 ValueType sty> { 4752 def : Pat<(!cast<PatFrag>("atomic_load_simple_" # sty) address), 4753 (LOAD Base, Offset)>; 4754 4755 def : Pat<(!cast<PatFrag>("atomic_store_simple_" # sty) address, transty:$Rt), 4756 (STORE $Rt, Base, Offset)>; 4757 } 4758 4759 // Instructions accessing a memory chunk smaller than a register (or, in a 4760 // pinch, the same size) have a characteristic set of patterns they want to 4761 // match: extending loads and truncating stores. This class deals with the 4762 // sign-neutral version of those patterns. 4763 // 4764 // It will be instantiated across multiple addressing-modes. 4765 multiclass ls_small_pats<Instruction LOAD, Instruction STORE, 4766 dag Base, dag Offset, 4767 dag address, ValueType sty> 4768 : ls_atomic_pats<LOAD, STORE, Base, Offset, address, i32, sty> { 4769 def : Pat<(!cast<SDNode>(zextload # sty) address), (LOAD Base, Offset)>; 4770 4771 def : Pat<(!cast<SDNode>(extload # sty) address), (LOAD Base, Offset)>; 4772 4773 // For zero-extension to 64-bits we have to tell LLVM that the whole 64-bit 4774 // register was actually set. 4775 def : Pat<(i64 (!cast<SDNode>(zextload # sty) address)), 4776 (SUBREG_TO_REG (i64 0), (LOAD Base, Offset), sub_32)>; 4777 4778 def : Pat<(i64 (!cast<SDNode>(extload # sty) address)), 4779 (SUBREG_TO_REG (i64 0), (LOAD Base, Offset), sub_32)>; 4780 4781 def : Pat<(!cast<SDNode>(truncstore # sty) i32:$Rt, address), 4782 (STORE $Rt, Base, Offset)>; 4783 4784 // For truncating store from 64-bits, we have to manually tell LLVM to 4785 // ignore the high bits of the x register. 4786 def : Pat<(!cast<SDNode>(truncstore # sty) i64:$Rt, address), 4787 (STORE (EXTRACT_SUBREG $Rt, sub_32), Base, Offset)>; 4788 } 4789 4790 // Next come patterns for sign-extending loads. 4791 multiclass load_signed_pats<string T, string U, dag Base, dag Offset, 4792 dag address, ValueType sty> { 4793 def : Pat<(i32 (!cast<SDNode>("sextload" # sty) address)), 4794 (!cast<Instruction>("LDRS" # T # "w" # U) Base, Offset)>; 4795 4796 def : Pat<(i64 (!cast<SDNode>("sextload" # sty) address)), 4797 (!cast<Instruction>("LDRS" # T # "x" # U) Base, Offset)>; 4798 4799 } 4800 4801 // and finally "natural-width" loads and stores come next. 4802 multiclass ls_neutral_pats<Instruction LOAD, Instruction STORE, dag Base, 4803 dag Offset, dag address, ValueType sty> { 4804 def : Pat<(sty (load address)), (LOAD Base, Offset)>; 4805 def : Pat<(store sty:$Rt, address), (STORE $Rt, Base, Offset)>; 4806 } 4807 4808 // Integer operations also get atomic instructions to select for. 4809 multiclass ls_int_neutral_pats<Instruction LOAD, Instruction STORE, dag Base, 4810 dag Offset, dag address, ValueType sty> 4811 : ls_neutral_pats<LOAD, STORE, Base, Offset, address, sty>, 4812 ls_atomic_pats<LOAD, STORE, Base, Offset, address, sty, sty>; 4813 4814 //===------------------------------ 4815 // 2.2. Addressing-mode instantiations 4816 //===------------------------------ 4817 4818 multiclass uimm12_pats<dag address, dag Base, dag Offset> { 4819 defm : ls_small_pats<LS8_LDR, LS8_STR, Base, 4820 !foreach(decls.pattern, Offset, 4821 !subst(OFFSET, byte_uimm12, decls.pattern)), 4822 !foreach(decls.pattern, address, 4823 !subst(OFFSET, byte_uimm12, 4824 !subst(ALIGN, any_align, decls.pattern))), 4825 i8>; 4826 defm : ls_small_pats<LS16_LDR, LS16_STR, Base, 4827 !foreach(decls.pattern, Offset, 4828 !subst(OFFSET, hword_uimm12, decls.pattern)), 4829 !foreach(decls.pattern, address, 4830 !subst(OFFSET, hword_uimm12, 4831 !subst(ALIGN, min_align2, decls.pattern))), 4832 i16>; 4833 defm : ls_small_pats<LS32_LDR, LS32_STR, Base, 4834 !foreach(decls.pattern, Offset, 4835 !subst(OFFSET, word_uimm12, decls.pattern)), 4836 !foreach(decls.pattern, address, 4837 !subst(OFFSET, word_uimm12, 4838 !subst(ALIGN, min_align4, decls.pattern))), 4839 i32>; 4840 4841 defm : ls_int_neutral_pats<LS32_LDR, LS32_STR, Base, 4842 !foreach(decls.pattern, Offset, 4843 !subst(OFFSET, word_uimm12, decls.pattern)), 4844 !foreach(decls.pattern, address, 4845 !subst(OFFSET, word_uimm12, 4846 !subst(ALIGN, min_align4, decls.pattern))), 4847 i32>; 4848 4849 defm : ls_int_neutral_pats<LS64_LDR, LS64_STR, Base, 4850 !foreach(decls.pattern, Offset, 4851 !subst(OFFSET, dword_uimm12, decls.pattern)), 4852 !foreach(decls.pattern, address, 4853 !subst(OFFSET, dword_uimm12, 4854 !subst(ALIGN, min_align8, decls.pattern))), 4855 i64>; 4856 4857 defm : ls_neutral_pats<LSFP16_LDR, LSFP16_STR, Base, 4858 !foreach(decls.pattern, Offset, 4859 !subst(OFFSET, hword_uimm12, decls.pattern)), 4860 !foreach(decls.pattern, address, 4861 !subst(OFFSET, hword_uimm12, 4862 !subst(ALIGN, min_align2, decls.pattern))), 4863 f16>; 4864 4865 defm : ls_neutral_pats<LSFP32_LDR, LSFP32_STR, Base, 4866 !foreach(decls.pattern, Offset, 4867 !subst(OFFSET, word_uimm12, decls.pattern)), 4868 !foreach(decls.pattern, address, 4869 !subst(OFFSET, word_uimm12, 4870 !subst(ALIGN, min_align4, decls.pattern))), 4871 f32>; 4872 4873 defm : ls_neutral_pats<LSFP64_LDR, LSFP64_STR, Base, 4874 !foreach(decls.pattern, Offset, 4875 !subst(OFFSET, dword_uimm12, decls.pattern)), 4876 !foreach(decls.pattern, address, 4877 !subst(OFFSET, dword_uimm12, 4878 !subst(ALIGN, min_align8, decls.pattern))), 4879 f64>; 4880 4881 defm : ls_neutral_pats<LSFP128_LDR, LSFP128_STR, Base, 4882 !foreach(decls.pattern, Offset, 4883 !subst(OFFSET, qword_uimm12, decls.pattern)), 4884 !foreach(decls.pattern, address, 4885 !subst(OFFSET, qword_uimm12, 4886 !subst(ALIGN, min_align16, decls.pattern))), 4887 f128>; 4888 4889 defm : load_signed_pats<"B", "", Base, 4890 !foreach(decls.pattern, Offset, 4891 !subst(OFFSET, byte_uimm12, decls.pattern)), 4892 !foreach(decls.pattern, address, 4893 !subst(OFFSET, byte_uimm12, 4894 !subst(ALIGN, any_align, decls.pattern))), 4895 i8>; 4896 4897 defm : load_signed_pats<"H", "", Base, 4898 !foreach(decls.pattern, Offset, 4899 !subst(OFFSET, hword_uimm12, decls.pattern)), 4900 !foreach(decls.pattern, address, 4901 !subst(OFFSET, hword_uimm12, 4902 !subst(ALIGN, min_align2, decls.pattern))), 4903 i16>; 4904 4905 def : Pat<(sextloadi32 !foreach(decls.pattern, address, 4906 !subst(OFFSET, word_uimm12, 4907 !subst(ALIGN, min_align4, decls.pattern)))), 4908 (LDRSWx Base, !foreach(decls.pattern, Offset, 4909 !subst(OFFSET, word_uimm12, decls.pattern)))>; 4910 } 4911 4912 // Straightforward patterns of last resort: a pointer with or without an 4913 // appropriate offset. 4914 defm : uimm12_pats<(i64 i64:$Rn), (i64 i64:$Rn), (i64 0)>; 4915 defm : uimm12_pats<(add i64:$Rn, OFFSET:$UImm12), 4916 (i64 i64:$Rn), (i64 OFFSET:$UImm12)>; 4917 4918 // The offset could be hidden behind an "or", of course: 4919 defm : uimm12_pats<(add_like_or i64:$Rn, OFFSET:$UImm12), 4920 (i64 i64:$Rn), (i64 OFFSET:$UImm12)>; 4921 4922 // Global addresses under the small-absolute model should use these 4923 // instructions. There are ELF relocations specifically for it. 4924 defm : uimm12_pats<(A64WrapperSmall tglobaladdr:$Hi, tglobaladdr:$Lo12, ALIGN), 4925 (ADRPxi tglobaladdr:$Hi), (i64 tglobaladdr:$Lo12)>; 4926 4927 defm : uimm12_pats<(A64WrapperSmall tglobaltlsaddr:$Hi, tglobaltlsaddr:$Lo12, 4928 ALIGN), 4929 (ADRPxi tglobaltlsaddr:$Hi), (i64 tglobaltlsaddr:$Lo12)>; 4930 4931 // External symbols that make it this far should also get standard relocations. 4932 defm : uimm12_pats<(A64WrapperSmall texternalsym:$Hi, texternalsym:$Lo12, 4933 ALIGN), 4934 (ADRPxi texternalsym:$Hi), (i64 texternalsym:$Lo12)>; 4935 4936 defm : uimm12_pats<(A64WrapperSmall tconstpool:$Hi, tconstpool:$Lo12, ALIGN), 4937 (ADRPxi tconstpool:$Hi), (i64 tconstpool:$Lo12)>; 4938 4939 // We also want to use uimm12 instructions for local variables at the moment. 4940 def tframeindex_XFORM : SDNodeXForm<frameindex, [{ 4941 int FI = cast<FrameIndexSDNode>(N)->getIndex(); 4942 return CurDAG->getTargetFrameIndex(FI, MVT::i64); 4943 }]>; 4944 4945 defm : uimm12_pats<(i64 frameindex:$Rn), 4946 (tframeindex_XFORM tframeindex:$Rn), (i64 0)>; 4947 4948 // These can be much simpler than uimm12 because we don't to change the operand 4949 // type (e.g. LDURB and LDURH take the same operands). 4950 multiclass simm9_pats<dag address, dag Base, dag Offset> { 4951 defm : ls_small_pats<LS8_LDUR, LS8_STUR, Base, Offset, address, i8>; 4952 defm : ls_small_pats<LS16_LDUR, LS16_STUR, Base, Offset, address, i16>; 4953 4954 defm : ls_int_neutral_pats<LS32_LDUR, LS32_STUR, Base, Offset, address, i32>; 4955 defm : ls_int_neutral_pats<LS64_LDUR, LS64_STUR, Base, Offset, address, i64>; 4956 4957 defm : ls_neutral_pats<LSFP16_LDUR, LSFP16_STUR, Base, Offset, address, f16>; 4958 defm : ls_neutral_pats<LSFP32_LDUR, LSFP32_STUR, Base, Offset, address, f32>; 4959 defm : ls_neutral_pats<LSFP64_LDUR, LSFP64_STUR, Base, Offset, address, f64>; 4960 defm : ls_neutral_pats<LSFP128_LDUR, LSFP128_STUR, Base, Offset, address, 4961 f128>; 4962 4963 def : Pat<(i64 (zextloadi32 address)), 4964 (SUBREG_TO_REG (i64 0), (LS32_LDUR Base, Offset), sub_32)>; 4965 4966 def : Pat<(truncstorei32 i64:$Rt, address), 4967 (LS32_STUR (EXTRACT_SUBREG $Rt, sub_32), Base, Offset)>; 4968 4969 defm : load_signed_pats<"B", "_U", Base, Offset, address, i8>; 4970 defm : load_signed_pats<"H", "_U", Base, Offset, address, i16>; 4971 def : Pat<(sextloadi32 address), (LDURSWx Base, Offset)>; 4972 } 4973 4974 defm : simm9_pats<(add i64:$Rn, simm9:$SImm9), 4975 (i64 $Rn), (SDXF_simm9 simm9:$SImm9)>; 4976 4977 defm : simm9_pats<(add_like_or i64:$Rn, simm9:$SImm9), 4978 (i64 $Rn), (SDXF_simm9 simm9:$SImm9)>; 4979 4980 4981 //===------------------------------ 4982 // 3. Register offset patterns 4983 //===------------------------------ 4984 4985 // Atomic patterns can be shared between integer operations of all sizes, a 4986 // quick multiclass here allows reuse. 4987 multiclass ro_atomic_pats<Instruction LOAD, Instruction STORE, dag Base, 4988 dag Offset, dag Extend, dag address, 4989 ValueType transty, ValueType sty> { 4990 def : Pat<(!cast<PatFrag>("atomic_load_simple_" # sty) address), 4991 (LOAD Base, Offset, Extend)>; 4992 4993 def : Pat<(!cast<PatFrag>("atomic_store_simple_" # sty) address, transty:$Rt), 4994 (STORE $Rt, Base, Offset, Extend)>; 4995 } 4996 4997 // The register offset instructions take three operands giving the instruction, 4998 // and have an annoying split between instructions where Rm is 32-bit and 4999 // 64-bit. So we need a special hierarchy to describe them. Other than that the 5000 // same operations should be supported as for simm9 and uimm12 addressing. 5001 5002 multiclass ro_small_pats<Instruction LOAD, Instruction STORE, 5003 dag Base, dag Offset, dag Extend, 5004 dag address, ValueType sty> 5005 : ro_atomic_pats<LOAD, STORE, Base, Offset, Extend, address, i32, sty> { 5006 def : Pat<(!cast<SDNode>(zextload # sty) address), 5007 (LOAD Base, Offset, Extend)>; 5008 5009 def : Pat<(!cast<SDNode>(extload # sty) address), 5010 (LOAD Base, Offset, Extend)>; 5011 5012 // For zero-extension to 64-bits we have to tell LLVM that the whole 64-bit 5013 // register was actually set. 5014 def : Pat<(i64 (!cast<SDNode>(zextload # sty) address)), 5015 (SUBREG_TO_REG (i64 0), (LOAD Base, Offset, Extend), sub_32)>; 5016 5017 def : Pat<(i64 (!cast<SDNode>(extload # sty) address)), 5018 (SUBREG_TO_REG (i64 0), (LOAD Base, Offset, Extend), sub_32)>; 5019 5020 def : Pat<(!cast<SDNode>(truncstore # sty) i32:$Rt, address), 5021 (STORE $Rt, Base, Offset, Extend)>; 5022 5023 // For truncating store from 64-bits, we have to manually tell LLVM to 5024 // ignore the high bits of the x register. 5025 def : Pat<(!cast<SDNode>(truncstore # sty) i64:$Rt, address), 5026 (STORE (EXTRACT_SUBREG $Rt, sub_32), Base, Offset, Extend)>; 5027 5028 } 5029 5030 // Next come patterns for sign-extending loads. 5031 multiclass ro_signed_pats<string T, string Rm, dag Base, dag Offset, dag Extend, 5032 dag address, ValueType sty> { 5033 def : Pat<(i32 (!cast<SDNode>("sextload" # sty) address)), 5034 (!cast<Instruction>("LDRS" # T # "w_" # Rm # "_RegOffset") 5035 Base, Offset, Extend)>; 5036 5037 def : Pat<(i64 (!cast<SDNode>("sextload" # sty) address)), 5038 (!cast<Instruction>("LDRS" # T # "x_" # Rm # "_RegOffset") 5039 Base, Offset, Extend)>; 5040 } 5041 5042 // and finally "natural-width" loads and stores come next. 5043 multiclass ro_neutral_pats<Instruction LOAD, Instruction STORE, 5044 dag Base, dag Offset, dag Extend, dag address, 5045 ValueType sty> { 5046 def : Pat<(sty (load address)), (LOAD Base, Offset, Extend)>; 5047 def : Pat<(store sty:$Rt, address), 5048 (STORE $Rt, Base, Offset, Extend)>; 5049 } 5050 5051 multiclass ro_int_neutral_pats<Instruction LOAD, Instruction STORE, 5052 dag Base, dag Offset, dag Extend, dag address, 5053 ValueType sty> 5054 : ro_neutral_pats<LOAD, STORE, Base, Offset, Extend, address, sty>, 5055 ro_atomic_pats<LOAD, STORE, Base, Offset, Extend, address, sty, sty>; 5056 5057 multiclass regoff_pats<string Rm, dag address, dag Base, dag Offset, 5058 dag Extend> { 5059 defm : ro_small_pats<!cast<Instruction>("LS8_" # Rm # "_RegOffset_LDR"), 5060 !cast<Instruction>("LS8_" # Rm # "_RegOffset_STR"), 5061 Base, Offset, Extend, 5062 !foreach(decls.pattern, address, 5063 !subst(SHIFT, imm_eq0, decls.pattern)), 5064 i8>; 5065 defm : ro_small_pats<!cast<Instruction>("LS16_" # Rm # "_RegOffset_LDR"), 5066 !cast<Instruction>("LS16_" # Rm # "_RegOffset_STR"), 5067 Base, Offset, Extend, 5068 !foreach(decls.pattern, address, 5069 !subst(SHIFT, imm_eq1, decls.pattern)), 5070 i16>; 5071 defm : ro_small_pats<!cast<Instruction>("LS32_" # Rm # "_RegOffset_LDR"), 5072 !cast<Instruction>("LS32_" # Rm # "_RegOffset_STR"), 5073 Base, Offset, Extend, 5074 !foreach(decls.pattern, address, 5075 !subst(SHIFT, imm_eq2, decls.pattern)), 5076 i32>; 5077 5078 defm : ro_int_neutral_pats< 5079 !cast<Instruction>("LS32_" # Rm # "_RegOffset_LDR"), 5080 !cast<Instruction>("LS32_" # Rm # "_RegOffset_STR"), 5081 Base, Offset, Extend, 5082 !foreach(decls.pattern, address, 5083 !subst(SHIFT, imm_eq2, decls.pattern)), 5084 i32>; 5085 5086 defm : ro_int_neutral_pats< 5087 !cast<Instruction>("LS64_" # Rm # "_RegOffset_LDR"), 5088 !cast<Instruction>("LS64_" # Rm # "_RegOffset_STR"), 5089 Base, Offset, Extend, 5090 !foreach(decls.pattern, address, 5091 !subst(SHIFT, imm_eq3, decls.pattern)), 5092 i64>; 5093 5094 defm : ro_neutral_pats<!cast<Instruction>("LSFP16_" # Rm # "_RegOffset_LDR"), 5095 !cast<Instruction>("LSFP16_" # Rm # "_RegOffset_STR"), 5096 Base, Offset, Extend, 5097 !foreach(decls.pattern, address, 5098 !subst(SHIFT, imm_eq1, decls.pattern)), 5099 f16>; 5100 5101 defm : ro_neutral_pats<!cast<Instruction>("LSFP32_" # Rm # "_RegOffset_LDR"), 5102 !cast<Instruction>("LSFP32_" # Rm # "_RegOffset_STR"), 5103 Base, Offset, Extend, 5104 !foreach(decls.pattern, address, 5105 !subst(SHIFT, imm_eq2, decls.pattern)), 5106 f32>; 5107 5108 defm : ro_neutral_pats<!cast<Instruction>("LSFP64_" # Rm # "_RegOffset_LDR"), 5109 !cast<Instruction>("LSFP64_" # Rm # "_RegOffset_STR"), 5110 Base, Offset, Extend, 5111 !foreach(decls.pattern, address, 5112 !subst(SHIFT, imm_eq3, decls.pattern)), 5113 f64>; 5114 5115 defm : ro_neutral_pats<!cast<Instruction>("LSFP128_" # Rm # "_RegOffset_LDR"), 5116 !cast<Instruction>("LSFP128_" # Rm # "_RegOffset_STR"), 5117 Base, Offset, Extend, 5118 !foreach(decls.pattern, address, 5119 !subst(SHIFT, imm_eq4, decls.pattern)), 5120 f128>; 5121 5122 defm : ro_signed_pats<"B", Rm, Base, Offset, Extend, 5123 !foreach(decls.pattern, address, 5124 !subst(SHIFT, imm_eq0, decls.pattern)), 5125 i8>; 5126 5127 defm : ro_signed_pats<"H", Rm, Base, Offset, Extend, 5128 !foreach(decls.pattern, address, 5129 !subst(SHIFT, imm_eq1, decls.pattern)), 5130 i16>; 5131 5132 def : Pat<(sextloadi32 !foreach(decls.pattern, address, 5133 !subst(SHIFT, imm_eq2, decls.pattern))), 5134 (!cast<Instruction>("LDRSWx_" # Rm # "_RegOffset") 5135 Base, Offset, Extend)>; 5136 } 5137 5138 5139 // Finally we're in a position to tell LLVM exactly what addresses are reachable 5140 // using register-offset instructions. Essentially a base plus a possibly 5141 // extended, possibly shifted (by access size) offset. 5142 5143 defm : regoff_pats<"Wm", (add i64:$Rn, (sext i32:$Rm)), 5144 (i64 i64:$Rn), (i32 i32:$Rm), (i64 6)>; 5145 5146 defm : regoff_pats<"Wm", (add i64:$Rn, (shl (sext i32:$Rm), SHIFT)), 5147 (i64 i64:$Rn), (i32 i32:$Rm), (i64 7)>; 5148 5149 defm : regoff_pats<"Wm", (add i64:$Rn, (zext i32:$Rm)), 5150 (i64 i64:$Rn), (i32 i32:$Rm), (i64 2)>; 5151 5152 defm : regoff_pats<"Wm", (add i64:$Rn, (shl (zext i32:$Rm), SHIFT)), 5153 (i64 i64:$Rn), (i32 i32:$Rm), (i64 3)>; 5154 5155 defm : regoff_pats<"Xm", (add i64:$Rn, i64:$Rm), 5156 (i64 i64:$Rn), (i64 i64:$Rm), (i64 2)>; 5157 5158 defm : regoff_pats<"Xm", (add i64:$Rn, (shl i64:$Rm, SHIFT)), 5159 (i64 i64:$Rn), (i64 i64:$Rm), (i64 3)>; 5160 5161 //===----------------------------------------------------------------------===// 5162 // Advanced SIMD (NEON) Support 5163 // 5164 5165 include "AArch64InstrNEON.td"