| //=- AArch64InstrInfo.td - Describe the AArch64 Instructions -*- tablegen -*-=// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // AArch64 Instruction definitions. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| // ARM Instruction Predicate Definitions. |
| // |
| def HasV8_1a : Predicate<"Subtarget->hasV8_1aOps()">, |
| AssemblerPredicate<(all_of HasV8_1aOps), "armv8.1a">; |
| def HasV8_2a : Predicate<"Subtarget->hasV8_2aOps()">, |
| AssemblerPredicate<(all_of HasV8_2aOps), "armv8.2a">; |
| def HasV8_3a : Predicate<"Subtarget->hasV8_3aOps()">, |
| AssemblerPredicate<(all_of HasV8_3aOps), "armv8.3a">; |
| def HasV8_4a : Predicate<"Subtarget->hasV8_4aOps()">, |
| AssemblerPredicate<(all_of HasV8_4aOps), "armv8.4a">; |
| def HasV8_5a : Predicate<"Subtarget->hasV8_5aOps()">, |
| AssemblerPredicate<(all_of HasV8_5aOps), "armv8.5a">; |
| def HasV8_6a : Predicate<"Subtarget->hasV8_6aOps()">, |
| AssemblerPredicate<(all_of HasV8_6aOps), "armv8.6a">; |
| def HasV8_7a : Predicate<"Subtarget->hasV8_7aOps()">, |
| AssemblerPredicate<(all_of HasV8_7aOps), "armv8.7a">; |
| def HasV9_0a : Predicate<"Subtarget->hasV9_0aOps()">, |
| AssemblerPredicate<(all_of HasV9_0aOps), "armv9-a">; |
| def HasV9_1a : Predicate<"Subtarget->hasV9_1aOps()">, |
| AssemblerPredicate<(all_of HasV9_1aOps), "armv9.1a">; |
| def HasV9_2a : Predicate<"Subtarget->hasV9_2aOps()">, |
| AssemblerPredicate<(all_of HasV9_2aOps), "armv9.2a">; |
| def HasV8_0r : Predicate<"Subtarget->hasV8_0rOps()">, |
| AssemblerPredicate<(all_of HasV8_0rOps), "armv8-r">; |
| |
| def HasEL2VMSA : Predicate<"Subtarget->hasEL2VMSA()">, |
| AssemblerPredicate<(all_of FeatureEL2VMSA), "el2vmsa">; |
| |
| def HasEL3 : Predicate<"Subtarget->hasEL3()">, |
| AssemblerPredicate<(all_of FeatureEL3), "el3">; |
| |
| def HasVH : Predicate<"Subtarget->hasVH()">, |
| AssemblerPredicate<(all_of FeatureVH), "vh">; |
| |
| def HasLOR : Predicate<"Subtarget->hasLOR()">, |
| AssemblerPredicate<(all_of FeatureLOR), "lor">; |
| |
| def HasPAuth : Predicate<"Subtarget->hasPAuth()">, |
| AssemblerPredicate<(all_of FeaturePAuth), "pauth">; |
| |
| def HasJS : Predicate<"Subtarget->hasJS()">, |
| AssemblerPredicate<(all_of FeatureJS), "jsconv">; |
| |
| def HasCCIDX : Predicate<"Subtarget->hasCCIDX()">, |
| AssemblerPredicate<(all_of FeatureCCIDX), "ccidx">; |
| |
| def HasComplxNum : Predicate<"Subtarget->hasComplxNum()">, |
| AssemblerPredicate<(all_of FeatureComplxNum), "complxnum">; |
| |
| def HasNV : Predicate<"Subtarget->hasNV()">, |
| AssemblerPredicate<(all_of FeatureNV), "nv">; |
| |
| def HasMPAM : Predicate<"Subtarget->hasMPAM()">, |
| AssemblerPredicate<(all_of FeatureMPAM), "mpam">; |
| |
| def HasDIT : Predicate<"Subtarget->hasDIT()">, |
| AssemblerPredicate<(all_of FeatureDIT), "dit">; |
| |
| def HasTRACEV8_4 : Predicate<"Subtarget->hasTRACEV8_4()">, |
| AssemblerPredicate<(all_of FeatureTRACEV8_4), "tracev8.4">; |
| |
| def HasAM : Predicate<"Subtarget->hasAM()">, |
| AssemblerPredicate<(all_of FeatureAM), "am">; |
| |
| def HasSEL2 : Predicate<"Subtarget->hasSEL2()">, |
| AssemblerPredicate<(all_of FeatureSEL2), "sel2">; |
| |
| def HasTLB_RMI : Predicate<"Subtarget->hasTLB_RMI()">, |
| AssemblerPredicate<(all_of FeatureTLB_RMI), "tlb-rmi">; |
| |
| def HasFlagM : Predicate<"Subtarget->hasFlagM()">, |
| AssemblerPredicate<(all_of FeatureFlagM), "flagm">; |
| |
| def HasRCPC_IMMO : Predicate<"Subtarget->hasRCPCImm()">, |
| AssemblerPredicate<(all_of FeatureRCPC_IMMO), "rcpc-immo">; |
| |
| def HasFPARMv8 : Predicate<"Subtarget->hasFPARMv8()">, |
| AssemblerPredicate<(all_of FeatureFPARMv8), "fp-armv8">; |
| def HasNEON : Predicate<"Subtarget->hasNEON()">, |
| AssemblerPredicate<(all_of FeatureNEON), "neon">; |
| def HasCrypto : Predicate<"Subtarget->hasCrypto()">, |
| AssemblerPredicate<(all_of FeatureCrypto), "crypto">; |
| def HasSM4 : Predicate<"Subtarget->hasSM4()">, |
| AssemblerPredicate<(all_of FeatureSM4), "sm4">; |
| def HasSHA3 : Predicate<"Subtarget->hasSHA3()">, |
| AssemblerPredicate<(all_of FeatureSHA3), "sha3">; |
| def HasSHA2 : Predicate<"Subtarget->hasSHA2()">, |
| AssemblerPredicate<(all_of FeatureSHA2), "sha2">; |
| def HasAES : Predicate<"Subtarget->hasAES()">, |
| AssemblerPredicate<(all_of FeatureAES), "aes">; |
| def HasDotProd : Predicate<"Subtarget->hasDotProd()">, |
| AssemblerPredicate<(all_of FeatureDotProd), "dotprod">; |
| def HasCRC : Predicate<"Subtarget->hasCRC()">, |
| AssemblerPredicate<(all_of FeatureCRC), "crc">; |
| def HasLSE : Predicate<"Subtarget->hasLSE()">, |
| AssemblerPredicate<(all_of FeatureLSE), "lse">; |
| def HasNoLSE : Predicate<"!Subtarget->hasLSE()">; |
| def HasRAS : Predicate<"Subtarget->hasRAS()">, |
| AssemblerPredicate<(all_of FeatureRAS), "ras">; |
| def HasRDM : Predicate<"Subtarget->hasRDM()">, |
| AssemblerPredicate<(all_of FeatureRDM), "rdm">; |
| def HasPerfMon : Predicate<"Subtarget->hasPerfMon()">; |
| def HasFullFP16 : Predicate<"Subtarget->hasFullFP16()">, |
| AssemblerPredicate<(all_of FeatureFullFP16), "fullfp16">; |
| def HasFP16FML : Predicate<"Subtarget->hasFP16FML()">, |
| AssemblerPredicate<(all_of FeatureFP16FML), "fp16fml">; |
| def HasSPE : Predicate<"Subtarget->hasSPE()">, |
| AssemblerPredicate<(all_of FeatureSPE), "spe">; |
| def HasFuseAES : Predicate<"Subtarget->hasFuseAES()">, |
| AssemblerPredicate<(all_of FeatureFuseAES), |
| "fuse-aes">; |
| def HasSVE : Predicate<"Subtarget->hasSVE()">, |
| AssemblerPredicate<(all_of FeatureSVE), "sve">; |
| def HasSVE2 : Predicate<"Subtarget->hasSVE2()">, |
| AssemblerPredicate<(all_of FeatureSVE2), "sve2">; |
| def HasSVE2AES : Predicate<"Subtarget->hasSVE2AES()">, |
| AssemblerPredicate<(all_of FeatureSVE2AES), "sve2-aes">; |
| def HasSVE2SM4 : Predicate<"Subtarget->hasSVE2SM4()">, |
| AssemblerPredicate<(all_of FeatureSVE2SM4), "sve2-sm4">; |
| def HasSVE2SHA3 : Predicate<"Subtarget->hasSVE2SHA3()">, |
| AssemblerPredicate<(all_of FeatureSVE2SHA3), "sve2-sha3">; |
| def HasSVE2BitPerm : Predicate<"Subtarget->hasSVE2BitPerm()">, |
| AssemblerPredicate<(all_of FeatureSVE2BitPerm), "sve2-bitperm">; |
| def HasSME : Predicate<"Subtarget->hasSME()">, |
| AssemblerPredicate<(all_of FeatureSME), "sme">; |
| def HasSMEF64 : Predicate<"Subtarget->hasSMEF64()">, |
| AssemblerPredicate<(all_of FeatureSMEF64), "sme-f64">; |
| def HasSMEI64 : Predicate<"Subtarget->hasSMEI64()">, |
| AssemblerPredicate<(all_of FeatureSMEI64), "sme-i64">; |
| def HasStreamingSVE : Predicate<"Subtarget->hasStreamingSVE()">, |
| AssemblerPredicate<(all_of FeatureStreamingSVE), "streaming-sve">; |
| // A subset of SVE(2) instructions are legal in Streaming SVE execution mode, |
| // they should be enabled if either has been specified. |
| def HasSVEorStreamingSVE |
| : Predicate<"Subtarget->hasSVE() || Subtarget->hasStreamingSVE()">, |
| AssemblerPredicate<(any_of FeatureSVE, FeatureStreamingSVE), |
| "streaming-sve or sve">; |
| def HasSVE2orStreamingSVE |
| : Predicate<"Subtarget->hasSVE2() || Subtarget->hasStreamingSVE()">, |
| AssemblerPredicate<(any_of FeatureSVE2, FeatureStreamingSVE), |
| "streaming-sve or sve2">; |
| // A subset of NEON instructions are legal in Streaming SVE execution mode, |
| // they should be enabled if either has been specified. |
| def HasNEONorStreamingSVE |
| : Predicate<"Subtarget->hasNEON() || Subtarget->hasStreamingSVE()">, |
| AssemblerPredicate<(any_of FeatureNEON, FeatureStreamingSVE), |
| "streaming-sve or neon">; |
| def HasRCPC : Predicate<"Subtarget->hasRCPC()">, |
| AssemblerPredicate<(all_of FeatureRCPC), "rcpc">; |
| def HasAltNZCV : Predicate<"Subtarget->hasAlternativeNZCV()">, |
| AssemblerPredicate<(all_of FeatureAltFPCmp), "altnzcv">; |
| def HasFRInt3264 : Predicate<"Subtarget->hasFRInt3264()">, |
| AssemblerPredicate<(all_of FeatureFRInt3264), "frint3264">; |
| def HasSB : Predicate<"Subtarget->hasSB()">, |
| AssemblerPredicate<(all_of FeatureSB), "sb">; |
| def HasPredRes : Predicate<"Subtarget->hasPredRes()">, |
| AssemblerPredicate<(all_of FeaturePredRes), "predres">; |
| def HasCCDP : Predicate<"Subtarget->hasCCDP()">, |
| AssemblerPredicate<(all_of FeatureCacheDeepPersist), "ccdp">; |
| def HasBTI : Predicate<"Subtarget->hasBTI()">, |
| AssemblerPredicate<(all_of FeatureBranchTargetId), "bti">; |
| def HasMTE : Predicate<"Subtarget->hasMTE()">, |
| AssemblerPredicate<(all_of FeatureMTE), "mte">; |
| def HasTME : Predicate<"Subtarget->hasTME()">, |
| AssemblerPredicate<(all_of FeatureTME), "tme">; |
| def HasETE : Predicate<"Subtarget->hasETE()">, |
| AssemblerPredicate<(all_of FeatureETE), "ete">; |
| def HasTRBE : Predicate<"Subtarget->hasTRBE()">, |
| AssemblerPredicate<(all_of FeatureTRBE), "trbe">; |
| def HasBF16 : Predicate<"Subtarget->hasBF16()">, |
| AssemblerPredicate<(all_of FeatureBF16), "bf16">; |
| def HasMatMulInt8 : Predicate<"Subtarget->hasMatMulInt8()">, |
| AssemblerPredicate<(all_of FeatureMatMulInt8), "i8mm">; |
| def HasMatMulFP32 : Predicate<"Subtarget->hasMatMulFP32()">, |
| AssemblerPredicate<(all_of FeatureMatMulFP32), "f32mm">; |
| def HasMatMulFP64 : Predicate<"Subtarget->hasMatMulFP64()">, |
| AssemblerPredicate<(all_of FeatureMatMulFP64), "f64mm">; |
| def HasXS : Predicate<"Subtarget->hasXS()">, |
| AssemblerPredicate<(all_of FeatureXS), "xs">; |
| def HasWFxT : Predicate<"Subtarget->hasWFxT()">, |
| AssemblerPredicate<(all_of FeatureWFxT), "wfxt">; |
| def HasLS64 : Predicate<"Subtarget->hasLS64()">, |
| AssemblerPredicate<(all_of FeatureLS64), "ls64">; |
| def HasBRBE : Predicate<"Subtarget->hasBRBE()">, |
| AssemblerPredicate<(all_of FeatureBRBE), "brbe">; |
| def HasSPE_EEF : Predicate<"Subtarget->hasSPE_EEF()">, |
| AssemblerPredicate<(all_of FeatureSPE_EEF), "spe-eef">; |
| def IsLE : Predicate<"Subtarget->isLittleEndian()">; |
| def IsBE : Predicate<"!Subtarget->isLittleEndian()">; |
| def IsWindows : Predicate<"Subtarget->isTargetWindows()">; |
| def UseExperimentalZeroingPseudos |
| : Predicate<"Subtarget->useExperimentalZeroingPseudos()">; |
| def UseAlternateSExtLoadCVTF32 |
| : Predicate<"Subtarget->useAlternateSExtLoadCVTF32Pattern()">; |
| |
| def UseNegativeImmediates |
| : Predicate<"false">, AssemblerPredicate<(all_of (not FeatureNoNegativeImmediates)), |
| "NegativeImmediates">; |
| |
| def UseScalarIncVL : Predicate<"Subtarget->useScalarIncVL()">; |
| |
| def AArch64LocalRecover : SDNode<"ISD::LOCAL_RECOVER", |
| SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, |
| SDTCisInt<1>]>>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // AArch64-specific DAG Nodes. |
| // |
| |
| // SDTBinaryArithWithFlagsOut - RES1, FLAGS = op LHS, RHS |
| def SDTBinaryArithWithFlagsOut : SDTypeProfile<2, 2, |
| [SDTCisSameAs<0, 2>, |
| SDTCisSameAs<0, 3>, |
| SDTCisInt<0>, SDTCisVT<1, i32>]>; |
| |
| // SDTBinaryArithWithFlagsIn - RES1, FLAGS = op LHS, RHS, FLAGS |
| def SDTBinaryArithWithFlagsIn : SDTypeProfile<1, 3, |
| [SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>, |
| SDTCisInt<0>, |
| SDTCisVT<3, i32>]>; |
| |
| // SDTBinaryArithWithFlagsInOut - RES1, FLAGS = op LHS, RHS, FLAGS |
| def SDTBinaryArithWithFlagsInOut : SDTypeProfile<2, 3, |
| [SDTCisSameAs<0, 2>, |
| SDTCisSameAs<0, 3>, |
| SDTCisInt<0>, |
| SDTCisVT<1, i32>, |
| SDTCisVT<4, i32>]>; |
| |
| def SDT_AArch64Brcond : SDTypeProfile<0, 3, |
| [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>, |
| SDTCisVT<2, i32>]>; |
| def SDT_AArch64cbz : SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisVT<1, OtherVT>]>; |
| def SDT_AArch64tbz : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisInt<1>, |
| SDTCisVT<2, OtherVT>]>; |
| |
| |
| def SDT_AArch64CSel : SDTypeProfile<1, 4, |
| [SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>, |
| SDTCisInt<3>, |
| SDTCisVT<4, i32>]>; |
| def SDT_AArch64CCMP : SDTypeProfile<1, 5, |
| [SDTCisVT<0, i32>, |
| SDTCisInt<1>, |
| SDTCisSameAs<1, 2>, |
| SDTCisInt<3>, |
| SDTCisInt<4>, |
| SDTCisVT<5, i32>]>; |
| def SDT_AArch64FCCMP : SDTypeProfile<1, 5, |
| [SDTCisVT<0, i32>, |
| SDTCisFP<1>, |
| SDTCisSameAs<1, 2>, |
| SDTCisInt<3>, |
| SDTCisInt<4>, |
| SDTCisVT<5, i32>]>; |
| def SDT_AArch64FCmp : SDTypeProfile<0, 2, |
| [SDTCisFP<0>, |
| SDTCisSameAs<0, 1>]>; |
| def SDT_AArch64Dup : SDTypeProfile<1, 1, [SDTCisVec<0>]>; |
| def SDT_AArch64DupLane : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisInt<2>]>; |
| def SDT_AArch64Insr : SDTypeProfile<1, 2, [SDTCisVec<0>]>; |
| def SDT_AArch64Zip : SDTypeProfile<1, 2, [SDTCisVec<0>, |
| SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>]>; |
| def SDT_AArch64MOVIedit : SDTypeProfile<1, 1, [SDTCisInt<1>]>; |
| def SDT_AArch64MOVIshift : SDTypeProfile<1, 2, [SDTCisInt<1>, SDTCisInt<2>]>; |
| def SDT_AArch64vecimm : SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisSameAs<0,1>, |
| SDTCisInt<2>, SDTCisInt<3>]>; |
| def SDT_AArch64UnaryVec: SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisSameAs<0,1>]>; |
| def SDT_AArch64ExtVec: SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisSameAs<0,1>, |
| SDTCisSameAs<0,2>, SDTCisInt<3>]>; |
| def SDT_AArch64vshift : SDTypeProfile<1, 2, [SDTCisSameAs<0,1>, SDTCisInt<2>]>; |
| def SDT_AArch64Dot: SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisSameAs<0,1>, |
| SDTCisVec<2>, SDTCisSameAs<2,3>]>; |
| |
| def SDT_AArch64vshiftinsert : SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisInt<3>, |
| SDTCisSameAs<0,1>, |
| SDTCisSameAs<0,2>]>; |
| |
| def SDT_AArch64unvec : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisSameAs<0,1>]>; |
| def SDT_AArch64fcmpz : SDTypeProfile<1, 1, []>; |
| def SDT_AArch64fcmp : SDTypeProfile<1, 2, [SDTCisSameAs<1,2>]>; |
| def SDT_AArch64binvec : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0,1>, |
| SDTCisSameAs<0,2>]>; |
| def SDT_AArch64trivec : SDTypeProfile<1, 3, [SDTCisVec<0>, SDTCisSameAs<0,1>, |
| SDTCisSameAs<0,2>, |
| SDTCisSameAs<0,3>]>; |
| def SDT_AArch64TCRET : SDTypeProfile<0, 2, [SDTCisPtrTy<0>]>; |
| def SDT_AArch64PREFETCH : SDTypeProfile<0, 2, [SDTCisVT<0, i32>, SDTCisPtrTy<1>]>; |
| |
| def SDT_AArch64ITOF : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisSameAs<0,1>]>; |
| |
| def SDT_AArch64TLSDescCall : SDTypeProfile<0, -2, [SDTCisPtrTy<0>, |
| SDTCisPtrTy<1>]>; |
| |
| def SDT_AArch64uaddlp : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVec<1>]>; |
| |
| def SDT_AArch64ldp : SDTypeProfile<2, 1, [SDTCisVT<0, i64>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; |
| def SDT_AArch64stp : SDTypeProfile<0, 3, [SDTCisVT<0, i64>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; |
| def SDT_AArch64stnp : SDTypeProfile<0, 3, [SDTCisVT<0, v4i32>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; |
| |
| // Generates the general dynamic sequences, i.e. |
| // adrp x0, :tlsdesc:var |
| // ldr x1, [x0, #:tlsdesc_lo12:var] |
| // add x0, x0, #:tlsdesc_lo12:var |
| // .tlsdesccall var |
| // blr x1 |
| |
| // (the TPIDR_EL0 offset is put directly in X0, hence no "result" here) |
| // number of operands (the variable) |
| def SDT_AArch64TLSDescCallSeq : SDTypeProfile<0,1, |
| [SDTCisPtrTy<0>]>; |
| |
| def SDT_AArch64WrapperLarge : SDTypeProfile<1, 4, |
| [SDTCisVT<0, i64>, SDTCisVT<1, i32>, |
| SDTCisSameAs<1, 2>, SDTCisSameAs<1, 3>, |
| SDTCisSameAs<1, 4>]>; |
| |
| def SDT_AArch64TBL : SDTypeProfile<1, 2, [ |
| SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisInt<2> |
| ]>; |
| |
| // non-extending masked load fragment. |
| def nonext_masked_load : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (masked_ld node:$ptr, undef, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getExtensionType() == ISD::NON_EXTLOAD && |
| cast<MaskedLoadSDNode>(N)->isUnindexed() && |
| !cast<MaskedLoadSDNode>(N)->isNonTemporal(); |
| }]>; |
| // sign extending masked load fragments. |
| def asext_masked_load : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (masked_ld node:$ptr, undef, node:$pred, node:$def),[{ |
| return (cast<MaskedLoadSDNode>(N)->getExtensionType() == ISD::EXTLOAD || |
| cast<MaskedLoadSDNode>(N)->getExtensionType() == ISD::SEXTLOAD) && |
| cast<MaskedLoadSDNode>(N)->isUnindexed(); |
| }]>; |
| def asext_masked_load_i8 : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (asext_masked_load node:$ptr, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getMemoryVT().getScalarType() == MVT::i8; |
| }]>; |
| def asext_masked_load_i16 : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (asext_masked_load node:$ptr, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getMemoryVT().getScalarType() == MVT::i16; |
| }]>; |
| def asext_masked_load_i32 : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (asext_masked_load node:$ptr, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32; |
| }]>; |
| // zero extending masked load fragments. |
| def zext_masked_load : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (masked_ld node:$ptr, undef, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getExtensionType() == ISD::ZEXTLOAD && |
| cast<MaskedLoadSDNode>(N)->isUnindexed(); |
| }]>; |
| def zext_masked_load_i8 : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (zext_masked_load node:$ptr, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getMemoryVT().getScalarType() == MVT::i8; |
| }]>; |
| def zext_masked_load_i16 : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (zext_masked_load node:$ptr, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getMemoryVT().getScalarType() == MVT::i16; |
| }]>; |
| def zext_masked_load_i32 : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (zext_masked_load node:$ptr, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32; |
| }]>; |
| |
| def non_temporal_load : |
| PatFrag<(ops node:$ptr, node:$pred, node:$def), |
| (masked_ld node:$ptr, undef, node:$pred, node:$def), [{ |
| return cast<MaskedLoadSDNode>(N)->getExtensionType() == ISD::NON_EXTLOAD && |
| cast<MaskedLoadSDNode>(N)->isUnindexed() && |
| cast<MaskedLoadSDNode>(N)->isNonTemporal(); |
| }]>; |
| |
| // non-truncating masked store fragment. |
| def nontrunc_masked_store : |
| PatFrag<(ops node:$val, node:$ptr, node:$pred), |
| (masked_st node:$val, node:$ptr, undef, node:$pred), [{ |
| return !cast<MaskedStoreSDNode>(N)->isTruncatingStore() && |
| cast<MaskedStoreSDNode>(N)->isUnindexed() && |
| !cast<MaskedStoreSDNode>(N)->isNonTemporal(); |
| }]>; |
| // truncating masked store fragments. |
| def trunc_masked_store : |
| PatFrag<(ops node:$val, node:$ptr, node:$pred), |
| (masked_st node:$val, node:$ptr, undef, node:$pred), [{ |
| return cast<MaskedStoreSDNode>(N)->isTruncatingStore() && |
| cast<MaskedStoreSDNode>(N)->isUnindexed(); |
| }]>; |
| def trunc_masked_store_i8 : |
| PatFrag<(ops node:$val, node:$ptr, node:$pred), |
| (trunc_masked_store node:$val, node:$ptr, node:$pred), [{ |
| return cast<MaskedStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i8; |
| }]>; |
| def trunc_masked_store_i16 : |
| PatFrag<(ops node:$val, node:$ptr, node:$pred), |
| (trunc_masked_store node:$val, node:$ptr, node:$pred), [{ |
| return cast<MaskedStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i16; |
| }]>; |
| def trunc_masked_store_i32 : |
| PatFrag<(ops node:$val, node:$ptr, node:$pred), |
| (trunc_masked_store node:$val, node:$ptr, node:$pred), [{ |
| return cast<MaskedStoreSDNode>(N)->getMemoryVT().getScalarType() == MVT::i32; |
| }]>; |
| |
| def non_temporal_store : |
| PatFrag<(ops node:$val, node:$ptr, node:$pred), |
| (masked_st node:$val, node:$ptr, undef, node:$pred), [{ |
| return !cast<MaskedStoreSDNode>(N)->isTruncatingStore() && |
| cast<MaskedStoreSDNode>(N)->isUnindexed() && |
| cast<MaskedStoreSDNode>(N)->isNonTemporal(); |
| }]>; |
| |
| // top16Zero - answer true if the upper 16 bits of $src are 0, false otherwise |
| def top16Zero: PatLeaf<(i32 GPR32:$src), [{ |
| return SDValue(N,0)->getValueType(0) == MVT::i32 && |
| CurDAG->MaskedValueIsZero(SDValue(N,0), APInt::getHighBitsSet(32, 16)); |
| }]>; |
| |
| // top32Zero - answer true if the upper 32 bits of $src are 0, false otherwise |
| def top32Zero: PatLeaf<(i64 GPR64:$src), [{ |
| return SDValue(N,0)->getValueType(0) == MVT::i64 && |
| CurDAG->MaskedValueIsZero(SDValue(N,0), APInt::getHighBitsSet(64, 32)); |
| }]>; |
| |
| // Node definitions. |
| def AArch64adrp : SDNode<"AArch64ISD::ADRP", SDTIntUnaryOp, []>; |
| def AArch64adr : SDNode<"AArch64ISD::ADR", SDTIntUnaryOp, []>; |
| def AArch64addlow : SDNode<"AArch64ISD::ADDlow", SDTIntBinOp, []>; |
| def AArch64LOADgot : SDNode<"AArch64ISD::LOADgot", SDTIntUnaryOp>; |
| def AArch64callseq_start : SDNode<"ISD::CALLSEQ_START", |
| SDCallSeqStart<[ SDTCisVT<0, i32>, |
| SDTCisVT<1, i32> ]>, |
| [SDNPHasChain, SDNPOutGlue]>; |
| def AArch64callseq_end : SDNode<"ISD::CALLSEQ_END", |
| SDCallSeqEnd<[ SDTCisVT<0, i32>, |
| SDTCisVT<1, i32> ]>, |
| [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; |
| def AArch64call : SDNode<"AArch64ISD::CALL", |
| SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>, |
| [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, |
| SDNPVariadic]>; |
| |
| def AArch64call_rvmarker: SDNode<"AArch64ISD::CALL_RVMARKER", |
| SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>, |
| [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, |
| SDNPVariadic]>; |
| |
| def AArch64brcond : SDNode<"AArch64ISD::BRCOND", SDT_AArch64Brcond, |
| [SDNPHasChain]>; |
| def AArch64cbz : SDNode<"AArch64ISD::CBZ", SDT_AArch64cbz, |
| [SDNPHasChain]>; |
| def AArch64cbnz : SDNode<"AArch64ISD::CBNZ", SDT_AArch64cbz, |
| [SDNPHasChain]>; |
| def AArch64tbz : SDNode<"AArch64ISD::TBZ", SDT_AArch64tbz, |
| [SDNPHasChain]>; |
| def AArch64tbnz : SDNode<"AArch64ISD::TBNZ", SDT_AArch64tbz, |
| [SDNPHasChain]>; |
| |
| |
| def AArch64csel : SDNode<"AArch64ISD::CSEL", SDT_AArch64CSel>; |
| def AArch64csinv : SDNode<"AArch64ISD::CSINV", SDT_AArch64CSel>; |
| def AArch64csneg : SDNode<"AArch64ISD::CSNEG", SDT_AArch64CSel>; |
| def AArch64csinc : SDNode<"AArch64ISD::CSINC", SDT_AArch64CSel>; |
| def AArch64retflag : SDNode<"AArch64ISD::RET_FLAG", SDTNone, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| def AArch64adc : SDNode<"AArch64ISD::ADC", SDTBinaryArithWithFlagsIn >; |
| def AArch64sbc : SDNode<"AArch64ISD::SBC", SDTBinaryArithWithFlagsIn>; |
| def AArch64add_flag : SDNode<"AArch64ISD::ADDS", SDTBinaryArithWithFlagsOut, |
| [SDNPCommutative]>; |
| def AArch64sub_flag : SDNode<"AArch64ISD::SUBS", SDTBinaryArithWithFlagsOut>; |
| def AArch64and_flag : SDNode<"AArch64ISD::ANDS", SDTBinaryArithWithFlagsOut, |
| [SDNPCommutative]>; |
| def AArch64adc_flag : SDNode<"AArch64ISD::ADCS", SDTBinaryArithWithFlagsInOut>; |
| def AArch64sbc_flag : SDNode<"AArch64ISD::SBCS", SDTBinaryArithWithFlagsInOut>; |
| |
| def AArch64ccmp : SDNode<"AArch64ISD::CCMP", SDT_AArch64CCMP>; |
| def AArch64ccmn : SDNode<"AArch64ISD::CCMN", SDT_AArch64CCMP>; |
| def AArch64fccmp : SDNode<"AArch64ISD::FCCMP", SDT_AArch64FCCMP>; |
| |
| def AArch64threadpointer : SDNode<"AArch64ISD::THREAD_POINTER", SDTPtrLeaf>; |
| |
| def AArch64fcmp : SDNode<"AArch64ISD::FCMP", SDT_AArch64FCmp>; |
| def AArch64strict_fcmp : SDNode<"AArch64ISD::STRICT_FCMP", SDT_AArch64FCmp, |
| [SDNPHasChain]>; |
| def AArch64strict_fcmpe : SDNode<"AArch64ISD::STRICT_FCMPE", SDT_AArch64FCmp, |
| [SDNPHasChain]>; |
| def AArch64any_fcmp : PatFrags<(ops node:$lhs, node:$rhs), |
| [(AArch64strict_fcmp node:$lhs, node:$rhs), |
| (AArch64fcmp node:$lhs, node:$rhs)]>; |
| |
| def AArch64dup : SDNode<"AArch64ISD::DUP", SDT_AArch64Dup>; |
| def AArch64duplane8 : SDNode<"AArch64ISD::DUPLANE8", SDT_AArch64DupLane>; |
| def AArch64duplane16 : SDNode<"AArch64ISD::DUPLANE16", SDT_AArch64DupLane>; |
| def AArch64duplane32 : SDNode<"AArch64ISD::DUPLANE32", SDT_AArch64DupLane>; |
| def AArch64duplane64 : SDNode<"AArch64ISD::DUPLANE64", SDT_AArch64DupLane>; |
| |
| def AArch64insr : SDNode<"AArch64ISD::INSR", SDT_AArch64Insr>; |
| |
| def AArch64zip1 : SDNode<"AArch64ISD::ZIP1", SDT_AArch64Zip>; |
| def AArch64zip2 : SDNode<"AArch64ISD::ZIP2", SDT_AArch64Zip>; |
| def AArch64uzp1 : SDNode<"AArch64ISD::UZP1", SDT_AArch64Zip>; |
| def AArch64uzp2 : SDNode<"AArch64ISD::UZP2", SDT_AArch64Zip>; |
| def AArch64trn1 : SDNode<"AArch64ISD::TRN1", SDT_AArch64Zip>; |
| def AArch64trn2 : SDNode<"AArch64ISD::TRN2", SDT_AArch64Zip>; |
| |
| def AArch64movi_edit : SDNode<"AArch64ISD::MOVIedit", SDT_AArch64MOVIedit>; |
| def AArch64movi_shift : SDNode<"AArch64ISD::MOVIshift", SDT_AArch64MOVIshift>; |
| def AArch64movi_msl : SDNode<"AArch64ISD::MOVImsl", SDT_AArch64MOVIshift>; |
| def AArch64mvni_shift : SDNode<"AArch64ISD::MVNIshift", SDT_AArch64MOVIshift>; |
| def AArch64mvni_msl : SDNode<"AArch64ISD::MVNImsl", SDT_AArch64MOVIshift>; |
| def AArch64movi : SDNode<"AArch64ISD::MOVI", SDT_AArch64MOVIedit>; |
| def AArch64fmov : SDNode<"AArch64ISD::FMOV", SDT_AArch64MOVIedit>; |
| |
| def AArch64rev16 : SDNode<"AArch64ISD::REV16", SDT_AArch64UnaryVec>; |
| def AArch64rev32 : SDNode<"AArch64ISD::REV32", SDT_AArch64UnaryVec>; |
| def AArch64rev64 : SDNode<"AArch64ISD::REV64", SDT_AArch64UnaryVec>; |
| def AArch64ext : SDNode<"AArch64ISD::EXT", SDT_AArch64ExtVec>; |
| |
| def AArch64vashr : SDNode<"AArch64ISD::VASHR", SDT_AArch64vshift>; |
| def AArch64vlshr : SDNode<"AArch64ISD::VLSHR", SDT_AArch64vshift>; |
| def AArch64vshl : SDNode<"AArch64ISD::VSHL", SDT_AArch64vshift>; |
| def AArch64sqshli : SDNode<"AArch64ISD::SQSHL_I", SDT_AArch64vshift>; |
| def AArch64uqshli : SDNode<"AArch64ISD::UQSHL_I", SDT_AArch64vshift>; |
| def AArch64sqshlui : SDNode<"AArch64ISD::SQSHLU_I", SDT_AArch64vshift>; |
| def AArch64srshri : SDNode<"AArch64ISD::SRSHR_I", SDT_AArch64vshift>; |
| def AArch64urshri : SDNode<"AArch64ISD::URSHR_I", SDT_AArch64vshift>; |
| def AArch64vsli : SDNode<"AArch64ISD::VSLI", SDT_AArch64vshiftinsert>; |
| def AArch64vsri : SDNode<"AArch64ISD::VSRI", SDT_AArch64vshiftinsert>; |
| |
| def AArch64bit: SDNode<"AArch64ISD::BIT", SDT_AArch64trivec>; |
| def AArch64bsp: SDNode<"AArch64ISD::BSP", SDT_AArch64trivec>; |
| |
| def AArch64cmeq: SDNode<"AArch64ISD::CMEQ", SDT_AArch64binvec>; |
| def AArch64cmge: SDNode<"AArch64ISD::CMGE", SDT_AArch64binvec>; |
| def AArch64cmgt: SDNode<"AArch64ISD::CMGT", SDT_AArch64binvec>; |
| def AArch64cmhi: SDNode<"AArch64ISD::CMHI", SDT_AArch64binvec>; |
| def AArch64cmhs: SDNode<"AArch64ISD::CMHS", SDT_AArch64binvec>; |
| |
| def AArch64fcmeq: SDNode<"AArch64ISD::FCMEQ", SDT_AArch64fcmp>; |
| def AArch64fcmge: SDNode<"AArch64ISD::FCMGE", SDT_AArch64fcmp>; |
| def AArch64fcmgt: SDNode<"AArch64ISD::FCMGT", SDT_AArch64fcmp>; |
| |
| def AArch64cmeqz: SDNode<"AArch64ISD::CMEQz", SDT_AArch64unvec>; |
| def AArch64cmgez: SDNode<"AArch64ISD::CMGEz", SDT_AArch64unvec>; |
| def AArch64cmgtz: SDNode<"AArch64ISD::CMGTz", SDT_AArch64unvec>; |
| def AArch64cmlez: SDNode<"AArch64ISD::CMLEz", SDT_AArch64unvec>; |
| def AArch64cmltz: SDNode<"AArch64ISD::CMLTz", SDT_AArch64unvec>; |
| def AArch64cmtst : PatFrag<(ops node:$LHS, node:$RHS), |
| (vnot (AArch64cmeqz (and node:$LHS, node:$RHS)))>; |
| |
| def AArch64fcmeqz: SDNode<"AArch64ISD::FCMEQz", SDT_AArch64fcmpz>; |
| def AArch64fcmgez: SDNode<"AArch64ISD::FCMGEz", SDT_AArch64fcmpz>; |
| def AArch64fcmgtz: SDNode<"AArch64ISD::FCMGTz", SDT_AArch64fcmpz>; |
| def AArch64fcmlez: SDNode<"AArch64ISD::FCMLEz", SDT_AArch64fcmpz>; |
| def AArch64fcmltz: SDNode<"AArch64ISD::FCMLTz", SDT_AArch64fcmpz>; |
| |
| def AArch64bici: SDNode<"AArch64ISD::BICi", SDT_AArch64vecimm>; |
| def AArch64orri: SDNode<"AArch64ISD::ORRi", SDT_AArch64vecimm>; |
| |
| def AArch64tcret: SDNode<"AArch64ISD::TC_RETURN", SDT_AArch64TCRET, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| |
| def AArch64Prefetch : SDNode<"AArch64ISD::PREFETCH", SDT_AArch64PREFETCH, |
| [SDNPHasChain, SDNPSideEffect]>; |
| |
| def AArch64sitof: SDNode<"AArch64ISD::SITOF", SDT_AArch64ITOF>; |
| def AArch64uitof: SDNode<"AArch64ISD::UITOF", SDT_AArch64ITOF>; |
| |
| def AArch64tlsdesc_callseq : SDNode<"AArch64ISD::TLSDESC_CALLSEQ", |
| SDT_AArch64TLSDescCallSeq, |
| [SDNPInGlue, SDNPOutGlue, SDNPHasChain, |
| SDNPVariadic]>; |
| |
| |
| def AArch64WrapperLarge : SDNode<"AArch64ISD::WrapperLarge", |
| SDT_AArch64WrapperLarge>; |
| |
| def AArch64NvCast : SDNode<"AArch64ISD::NVCAST", SDTUnaryOp>; |
| |
| def SDT_AArch64mull : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisInt<1>, |
| SDTCisSameAs<1, 2>]>; |
| def AArch64smull : SDNode<"AArch64ISD::SMULL", SDT_AArch64mull>; |
| def AArch64umull : SDNode<"AArch64ISD::UMULL", SDT_AArch64mull>; |
| |
| def AArch64frecpe : SDNode<"AArch64ISD::FRECPE", SDTFPUnaryOp>; |
| def AArch64frecps : SDNode<"AArch64ISD::FRECPS", SDTFPBinOp>; |
| def AArch64frsqrte : SDNode<"AArch64ISD::FRSQRTE", SDTFPUnaryOp>; |
| def AArch64frsqrts : SDNode<"AArch64ISD::FRSQRTS", SDTFPBinOp>; |
| |
| def AArch64sdot : SDNode<"AArch64ISD::SDOT", SDT_AArch64Dot>; |
| def AArch64udot : SDNode<"AArch64ISD::UDOT", SDT_AArch64Dot>; |
| |
| def AArch64saddv : SDNode<"AArch64ISD::SADDV", SDT_AArch64UnaryVec>; |
| def AArch64uaddv : SDNode<"AArch64ISD::UADDV", SDT_AArch64UnaryVec>; |
| def AArch64sminv : SDNode<"AArch64ISD::SMINV", SDT_AArch64UnaryVec>; |
| def AArch64uminv : SDNode<"AArch64ISD::UMINV", SDT_AArch64UnaryVec>; |
| def AArch64smaxv : SDNode<"AArch64ISD::SMAXV", SDT_AArch64UnaryVec>; |
| def AArch64umaxv : SDNode<"AArch64ISD::UMAXV", SDT_AArch64UnaryVec>; |
| |
| def AArch64srhadd : SDNode<"AArch64ISD::SRHADD", SDT_AArch64binvec>; |
| def AArch64urhadd : SDNode<"AArch64ISD::URHADD", SDT_AArch64binvec>; |
| def AArch64shadd : SDNode<"AArch64ISD::SHADD", SDT_AArch64binvec>; |
| def AArch64uhadd : SDNode<"AArch64ISD::UHADD", SDT_AArch64binvec>; |
| |
| def AArch64uabd : PatFrags<(ops node:$lhs, node:$rhs), |
| [(abdu node:$lhs, node:$rhs), |
| (int_aarch64_neon_uabd node:$lhs, node:$rhs)]>; |
| def AArch64sabd : PatFrags<(ops node:$lhs, node:$rhs), |
| [(abds node:$lhs, node:$rhs), |
| (int_aarch64_neon_sabd node:$lhs, node:$rhs)]>; |
| |
| def AArch64uaddlp_n : SDNode<"AArch64ISD::UADDLP", SDT_AArch64uaddlp>; |
| def AArch64uaddlp : PatFrags<(ops node:$src), |
| [(AArch64uaddlp_n node:$src), |
| (int_aarch64_neon_uaddlp node:$src)]>; |
| |
| def SDT_AArch64SETTAG : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; |
| def AArch64stg : SDNode<"AArch64ISD::STG", SDT_AArch64SETTAG, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; |
| def AArch64stzg : SDNode<"AArch64ISD::STZG", SDT_AArch64SETTAG, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; |
| def AArch64st2g : SDNode<"AArch64ISD::ST2G", SDT_AArch64SETTAG, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; |
| def AArch64stz2g : SDNode<"AArch64ISD::STZ2G", SDT_AArch64SETTAG, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; |
| |
| def SDT_AArch64unpk : SDTypeProfile<1, 1, [ |
| SDTCisInt<0>, SDTCisInt<1>, SDTCisOpSmallerThanOp<1, 0> |
| ]>; |
| def AArch64sunpkhi : SDNode<"AArch64ISD::SUNPKHI", SDT_AArch64unpk>; |
| def AArch64sunpklo : SDNode<"AArch64ISD::SUNPKLO", SDT_AArch64unpk>; |
| def AArch64uunpkhi : SDNode<"AArch64ISD::UUNPKHI", SDT_AArch64unpk>; |
| def AArch64uunpklo : SDNode<"AArch64ISD::UUNPKLO", SDT_AArch64unpk>; |
| |
| def AArch64ldp : SDNode<"AArch64ISD::LDP", SDT_AArch64ldp, [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; |
| def AArch64stp : SDNode<"AArch64ISD::STP", SDT_AArch64stp, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; |
| def AArch64stnp : SDNode<"AArch64ISD::STNP", SDT_AArch64stnp, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; |
| |
| def AArch64tbl : SDNode<"AArch64ISD::TBL", SDT_AArch64TBL>; |
| def AArch64mrs : SDNode<"AArch64ISD::MRS", |
| SDTypeProfile<1, 1, [SDTCisVT<0, i64>, SDTCisVT<1, i32>]>, |
| [SDNPHasChain, SDNPOutGlue]>; |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| |
| // AArch64 Instruction Predicate Definitions. |
| // We could compute these on a per-module basis but doing so requires accessing |
| // the Function object through the <Target>Subtarget and objections were raised |
| // to that (see post-commit review comments for r301750). |
| let RecomputePerFunction = 1 in { |
| def ForCodeSize : Predicate<"shouldOptForSize(MF)">; |
| def NotForCodeSize : Predicate<"!shouldOptForSize(MF)">; |
| // Avoid generating STRQro if it is slow, unless we're optimizing for code size. |
| def UseSTRQro : Predicate<"!Subtarget->isSTRQroSlow() || shouldOptForSize(MF)">; |
| |
| def UseBTI : Predicate<[{ MF->getInfo<AArch64FunctionInfo>()->branchTargetEnforcement() }]>; |
| def NotUseBTI : Predicate<[{ !MF->getInfo<AArch64FunctionInfo>()->branchTargetEnforcement() }]>; |
| |
| def SLSBLRMitigation : Predicate<[{ MF->getSubtarget<AArch64Subtarget>().hardenSlsBlr() }]>; |
| def NoSLSBLRMitigation : Predicate<[{ !MF->getSubtarget<AArch64Subtarget>().hardenSlsBlr() }]>; |
| // Toggles patterns which aren't beneficial in GlobalISel when we aren't |
| // optimizing. This allows us to selectively use patterns without impacting |
| // SelectionDAG's behaviour. |
| // FIXME: One day there will probably be a nicer way to check for this, but |
| // today is not that day. |
| def OptimizedGISelOrOtherSelector : Predicate<"!MF->getFunction().hasOptNone() || MF->getProperties().hasProperty(MachineFunctionProperties::Property::FailedISel) || !MF->getProperties().hasProperty(MachineFunctionProperties::Property::Legalized)">; |
| } |
| |
| include "AArch64InstrFormats.td" |
| include "SVEInstrFormats.td" |
| include "SMEInstrFormats.td" |
| |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| // Miscellaneous instructions. |
| //===----------------------------------------------------------------------===// |
| |
| let Defs = [SP], Uses = [SP], hasSideEffects = 1, isCodeGenOnly = 1 in { |
| // We set Sched to empty list because we expect these instructions to simply get |
| // removed in most cases. |
| def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), |
| [(AArch64callseq_start timm:$amt1, timm:$amt2)]>, |
| Sched<[]>; |
| def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), |
| [(AArch64callseq_end timm:$amt1, timm:$amt2)]>, |
| Sched<[]>; |
| } // Defs = [SP], Uses = [SP], hasSideEffects = 1, isCodeGenOnly = 1 |
| |
| let isReMaterializable = 1, isCodeGenOnly = 1 in { |
| // FIXME: The following pseudo instructions are only needed because remat |
| // cannot handle multiple instructions. When that changes, they can be |
| // removed, along with the AArch64Wrapper node. |
| |
| let AddedComplexity = 10 in |
| def LOADgot : Pseudo<(outs GPR64common:$dst), (ins i64imm:$addr), |
| [(set GPR64common:$dst, (AArch64LOADgot tglobaladdr:$addr))]>, |
| Sched<[WriteLDAdr]>; |
| |
| // The MOVaddr instruction should match only when the add is not folded |
| // into a load or store address. |
| def MOVaddr |
| : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), |
| [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tglobaladdr:$hi), |
| tglobaladdr:$low))]>, |
| Sched<[WriteAdrAdr]>; |
| def MOVaddrJT |
| : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), |
| [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tjumptable:$hi), |
| tjumptable:$low))]>, |
| Sched<[WriteAdrAdr]>; |
| def MOVaddrCP |
| : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), |
| [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tconstpool:$hi), |
| tconstpool:$low))]>, |
| Sched<[WriteAdrAdr]>; |
| def MOVaddrBA |
| : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), |
| [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tblockaddress:$hi), |
| tblockaddress:$low))]>, |
| Sched<[WriteAdrAdr]>; |
| def MOVaddrTLS |
| : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), |
| [(set GPR64common:$dst, (AArch64addlow (AArch64adrp tglobaltlsaddr:$hi), |
| tglobaltlsaddr:$low))]>, |
| Sched<[WriteAdrAdr]>; |
| def MOVaddrEXT |
| : Pseudo<(outs GPR64common:$dst), (ins i64imm:$hi, i64imm:$low), |
| [(set GPR64common:$dst, (AArch64addlow (AArch64adrp texternalsym:$hi), |
| texternalsym:$low))]>, |
| Sched<[WriteAdrAdr]>; |
| // Normally AArch64addlow either gets folded into a following ldr/str, |
| // or together with an adrp into MOVaddr above. For cases with TLS, it |
| // might appear without either of them, so allow lowering it into a plain |
| // add. |
| def ADDlowTLS |
| : Pseudo<(outs GPR64sp:$dst), (ins GPR64sp:$src, i64imm:$low), |
| [(set GPR64sp:$dst, (AArch64addlow GPR64sp:$src, |
| tglobaltlsaddr:$low))]>, |
| Sched<[WriteAdr]>; |
| |
| } // isReMaterializable, isCodeGenOnly |
| |
| def : Pat<(AArch64LOADgot tglobaltlsaddr:$addr), |
| (LOADgot tglobaltlsaddr:$addr)>; |
| |
| def : Pat<(AArch64LOADgot texternalsym:$addr), |
| (LOADgot texternalsym:$addr)>; |
| |
| def : Pat<(AArch64LOADgot tconstpool:$addr), |
| (LOADgot tconstpool:$addr)>; |
| |
| // 32-bit jump table destination is actually only 2 instructions since we can |
| // use the table itself as a PC-relative base. But optimization occurs after |
| // branch relaxation so be pessimistic. |
| let Size = 12, Constraints = "@earlyclobber $dst,@earlyclobber $scratch", |
| isNotDuplicable = 1 in { |
| def JumpTableDest32 : Pseudo<(outs GPR64:$dst, GPR64sp:$scratch), |
| (ins GPR64:$table, GPR64:$entry, i32imm:$jti), []>, |
| Sched<[]>; |
| def JumpTableDest16 : Pseudo<(outs GPR64:$dst, GPR64sp:$scratch), |
| (ins GPR64:$table, GPR64:$entry, i32imm:$jti), []>, |
| Sched<[]>; |
| def JumpTableDest8 : Pseudo<(outs GPR64:$dst, GPR64sp:$scratch), |
| (ins GPR64:$table, GPR64:$entry, i32imm:$jti), []>, |
| Sched<[]>; |
| } |
| |
| // Space-consuming pseudo to aid testing of placement and reachability |
| // algorithms. Immediate operand is the number of bytes this "instruction" |
| // occupies; register operands can be used to enforce dependency and constrain |
| // the scheduler. |
| let hasSideEffects = 1, mayLoad = 1, mayStore = 1 in |
| def SPACE : Pseudo<(outs GPR64:$Rd), (ins i32imm:$size, GPR64:$Rn), |
| [(set GPR64:$Rd, (int_aarch64_space imm:$size, GPR64:$Rn))]>, |
| Sched<[]>; |
| |
| let hasSideEffects = 1, isCodeGenOnly = 1 in { |
| def SpeculationSafeValueX |
| : Pseudo<(outs GPR64:$dst), (ins GPR64:$src), []>, Sched<[]>; |
| def SpeculationSafeValueW |
| : Pseudo<(outs GPR32:$dst), (ins GPR32:$src), []>, Sched<[]>; |
| } |
| |
| // SpeculationBarrierEndBB must only be used after an unconditional control |
| // flow, i.e. after a terminator for which isBarrier is True. |
| let hasSideEffects = 1, isCodeGenOnly = 1, isTerminator = 1, isBarrier = 1 in { |
| def SpeculationBarrierISBDSBEndBB |
| : Pseudo<(outs), (ins), []>, Sched<[]>; |
| def SpeculationBarrierSBEndBB |
| : Pseudo<(outs), (ins), []>, Sched<[]>; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // System instructions. |
| //===----------------------------------------------------------------------===// |
| |
| def HINT : HintI<"hint">; |
| def : InstAlias<"nop", (HINT 0b000)>; |
| def : InstAlias<"yield",(HINT 0b001)>; |
| def : InstAlias<"wfe", (HINT 0b010)>; |
| def : InstAlias<"wfi", (HINT 0b011)>; |
| def : InstAlias<"sev", (HINT 0b100)>; |
| def : InstAlias<"sevl", (HINT 0b101)>; |
| def : InstAlias<"dgh", (HINT 0b110)>; |
| def : InstAlias<"esb", (HINT 0b10000)>, Requires<[HasRAS]>; |
| def : InstAlias<"csdb", (HINT 20)>; |
| // In order to be able to write readable assembly, LLVM should accept assembly |
| // inputs that use Branch Target Indentification mnemonics, even with BTI disabled. |
| // However, in order to be compatible with other assemblers (e.g. GAS), LLVM |
| // should not emit these mnemonics unless BTI is enabled. |
| def : InstAlias<"bti", (HINT 32), 0>; |
| def : InstAlias<"bti $op", (HINT btihint_op:$op), 0>; |
| def : InstAlias<"bti", (HINT 32)>, Requires<[HasBTI]>; |
| def : InstAlias<"bti $op", (HINT btihint_op:$op)>, Requires<[HasBTI]>; |
| |
| // v8.2a Statistical Profiling extension |
| def : InstAlias<"psb $op", (HINT psbhint_op:$op)>, Requires<[HasSPE]>; |
| |
| // As far as LLVM is concerned this writes to the system's exclusive monitors. |
| let mayLoad = 1, mayStore = 1 in |
| def CLREX : CRmSystemI<imm0_15, 0b010, "clrex">; |
| |
| // NOTE: ideally, this would have mayStore = 0, mayLoad = 0, but we cannot |
| // model patterns with sufficiently fine granularity. |
| let mayLoad = ?, mayStore = ? in { |
| def DMB : CRmSystemI<barrier_op, 0b101, "dmb", |
| [(int_aarch64_dmb (i32 imm32_0_15:$CRm))]>; |
| |
| def DSB : CRmSystemI<barrier_op, 0b100, "dsb", |
| [(int_aarch64_dsb (i32 imm32_0_15:$CRm))]>; |
| |
| def ISB : CRmSystemI<barrier_op, 0b110, "isb", |
| [(int_aarch64_isb (i32 imm32_0_15:$CRm))]>; |
| |
| def TSB : CRmSystemI<barrier_op, 0b010, "tsb", []> { |
| let CRm = 0b0010; |
| let Inst{12} = 0; |
| let Predicates = [HasTRACEV8_4]; |
| } |
| |
| def DSBnXS : CRmSystemI<barrier_nxs_op, 0b001, "dsb"> { |
| let CRm{1-0} = 0b11; |
| let Inst{9-8} = 0b10; |
| let Predicates = [HasXS]; |
| } |
| |
| let Predicates = [HasWFxT] in { |
| def WFET : RegInputSystemI<0b0000, 0b000, "wfet">; |
| def WFIT : RegInputSystemI<0b0000, 0b001, "wfit">; |
| } |
| |
| // Branch Record Buffer two-word mnemonic instructions |
| class BRBEI<bits<3> op2, string keyword> |
| : SimpleSystemI<0, (ins), "brb", keyword>, Sched<[WriteSys]> { |
| let Inst{31-8} = 0b110101010000100101110010; |
| let Inst{7-5} = op2; |
| let Predicates = [HasBRBE]; |
| } |
| def BRB_IALL: BRBEI<0b100, "\tiall">; |
| def BRB_INJ: BRBEI<0b101, "\tinj">; |
| |
| } |
| |
| // Allow uppercase and lowercase keyword arguments for BRB IALL and BRB INJ |
| def : TokenAlias<"INJ", "inj">; |
| def : TokenAlias<"IALL", "iall">; |
| |
| // ARMv8.2-A Dot Product |
| let Predicates = [HasDotProd] in { |
| defm SDOT : SIMDThreeSameVectorDot<0, 0, "sdot", AArch64sdot>; |
| defm UDOT : SIMDThreeSameVectorDot<1, 0, "udot", AArch64udot>; |
| defm SDOTlane : SIMDThreeSameVectorDotIndex<0, 0, 0b10, "sdot", AArch64sdot>; |
| defm UDOTlane : SIMDThreeSameVectorDotIndex<1, 0, 0b10, "udot", AArch64udot>; |
| } |
| |
| // ARMv8.6-A BFloat |
| let Predicates = [HasNEON, HasBF16] in { |
| defm BFDOT : SIMDThreeSameVectorBFDot<1, "bfdot">; |
| defm BF16DOTlane : SIMDThreeSameVectorBF16DotI<0, "bfdot">; |
| def BFMMLA : SIMDThreeSameVectorBF16MatrixMul<"bfmmla">; |
| def BFMLALB : SIMDBF16MLAL<0, "bfmlalb", int_aarch64_neon_bfmlalb>; |
| def BFMLALT : SIMDBF16MLAL<1, "bfmlalt", int_aarch64_neon_bfmlalt>; |
| def BFMLALBIdx : SIMDBF16MLALIndex<0, "bfmlalb", int_aarch64_neon_bfmlalb>; |
| def BFMLALTIdx : SIMDBF16MLALIndex<1, "bfmlalt", int_aarch64_neon_bfmlalt>; |
| def BFCVTN : SIMD_BFCVTN; |
| def BFCVTN2 : SIMD_BFCVTN2; |
| |
| // Vector-scalar BFDOT: |
| // The second source operand of the 64-bit variant of BF16DOTlane is a 128-bit |
| // register (the instruction uses a single 32-bit lane from it), so the pattern |
| // is a bit tricky. |
| def : Pat<(v2f32 (int_aarch64_neon_bfdot |
| (v2f32 V64:$Rd), (v4bf16 V64:$Rn), |
| (v4bf16 (bitconvert |
| (v2i32 (AArch64duplane32 |
| (v4i32 (bitconvert |
| (v8bf16 (insert_subvector undef, |
| (v4bf16 V64:$Rm), |
| (i64 0))))), |
| VectorIndexS:$idx)))))), |
| (BF16DOTlanev4bf16 (v2f32 V64:$Rd), (v4bf16 V64:$Rn), |
| (SUBREG_TO_REG (i32 0), V64:$Rm, dsub), |
| VectorIndexS:$idx)>; |
| } |
| |
| let Predicates = [HasNEONorStreamingSVE, HasBF16] in { |
| def BFCVT : BF16ToSinglePrecision<"bfcvt">; |
| } |
| |
| // ARMv8.6A AArch64 matrix multiplication |
| let Predicates = [HasMatMulInt8] in { |
| def SMMLA : SIMDThreeSameVectorMatMul<0, 0, "smmla", int_aarch64_neon_smmla>; |
| def UMMLA : SIMDThreeSameVectorMatMul<0, 1, "ummla", int_aarch64_neon_ummla>; |
| def USMMLA : SIMDThreeSameVectorMatMul<1, 0, "usmmla", int_aarch64_neon_usmmla>; |
| defm USDOT : SIMDThreeSameVectorDot<0, 1, "usdot", int_aarch64_neon_usdot>; |
| defm USDOTlane : SIMDThreeSameVectorDotIndex<0, 1, 0b10, "usdot", int_aarch64_neon_usdot>; |
| |
| // sudot lane has a pattern where usdot is expected (there is no sudot). |
| // The second operand is used in the dup operation to repeat the indexed |
| // element. |
| class BaseSIMDSUDOTIndex<bit Q, string dst_kind, string lhs_kind, |
| string rhs_kind, RegisterOperand RegType, |
| ValueType AccumType, ValueType InputType> |
| : BaseSIMDThreeSameVectorDotIndex<Q, 0, 1, 0b00, "sudot", dst_kind, |
| lhs_kind, rhs_kind, RegType, AccumType, |
| InputType, null_frag> { |
| let Pattern = [(set (AccumType RegType:$dst), |
| (AccumType (int_aarch64_neon_usdot (AccumType RegType:$Rd), |
| (InputType (bitconvert (AccumType |
| (AArch64duplane32 (v4i32 V128:$Rm), |
| VectorIndexS:$idx)))), |
| (InputType RegType:$Rn))))]; |
| } |
| |
| multiclass SIMDSUDOTIndex { |
| def v8i8 : BaseSIMDSUDOTIndex<0, ".2s", ".8b", ".4b", V64, v2i32, v8i8>; |
| def v16i8 : BaseSIMDSUDOTIndex<1, ".4s", ".16b", ".4b", V128, v4i32, v16i8>; |
| } |
| |
| defm SUDOTlane : SIMDSUDOTIndex; |
| |
| } |
| |
| // ARMv8.2-A FP16 Fused Multiply-Add Long |
| let Predicates = [HasNEON, HasFP16FML] in { |
| defm FMLAL : SIMDThreeSameVectorFML<0, 1, 0b001, "fmlal", int_aarch64_neon_fmlal>; |
| defm FMLSL : SIMDThreeSameVectorFML<0, 1, 0b101, "fmlsl", int_aarch64_neon_fmlsl>; |
| defm FMLAL2 : SIMDThreeSameVectorFML<1, 0, 0b001, "fmlal2", int_aarch64_neon_fmlal2>; |
| defm FMLSL2 : SIMDThreeSameVectorFML<1, 0, 0b101, "fmlsl2", int_aarch64_neon_fmlsl2>; |
| defm FMLALlane : SIMDThreeSameVectorFMLIndex<0, 0b0000, "fmlal", int_aarch64_neon_fmlal>; |
| defm FMLSLlane : SIMDThreeSameVectorFMLIndex<0, 0b0100, "fmlsl", int_aarch64_neon_fmlsl>; |
| defm FMLAL2lane : SIMDThreeSameVectorFMLIndex<1, 0b1000, "fmlal2", int_aarch64_neon_fmlal2>; |
| defm FMLSL2lane : SIMDThreeSameVectorFMLIndex<1, 0b1100, "fmlsl2", int_aarch64_neon_fmlsl2>; |
| } |
| |
| // Armv8.2-A Crypto extensions |
| let Predicates = [HasSHA3] in { |
| def SHA512H : CryptoRRRTied<0b0, 0b00, "sha512h">; |
| def SHA512H2 : CryptoRRRTied<0b0, 0b01, "sha512h2">; |
| def SHA512SU0 : CryptoRRTied_2D<0b0, 0b00, "sha512su0">; |
| def SHA512SU1 : CryptoRRRTied_2D<0b0, 0b10, "sha512su1">; |
| def RAX1 : CryptoRRR_2D<0b0,0b11, "rax1">; |
| def EOR3 : CryptoRRRR_16B<0b00, "eor3">; |
| def BCAX : CryptoRRRR_16B<0b01, "bcax">; |
| def XAR : CryptoRRRi6<"xar">; |
| |
| class SHA3_pattern<Instruction INST, Intrinsic OpNode, ValueType VecTy> |
| : Pat<(VecTy (OpNode (VecTy V128:$Vd), (VecTy V128:$Vn), (VecTy V128:$Vm))), |
| (INST (VecTy V128:$Vd), (VecTy V128:$Vn), (VecTy V128:$Vm))>; |
| |
| def : Pat<(v2i64 (int_aarch64_crypto_sha512su0 (v2i64 V128:$Vn), (v2i64 V128:$Vm))), |
| (SHA512SU0 (v2i64 V128:$Vn), (v2i64 V128:$Vm))>; |
| |
| def : SHA3_pattern<SHA512H, int_aarch64_crypto_sha512h, v2i64>; |
| def : SHA3_pattern<SHA512H2, int_aarch64_crypto_sha512h2, v2i64>; |
| def : SHA3_pattern<SHA512SU1, int_aarch64_crypto_sha512su1, v2i64>; |
| |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3u, v16i8>; |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3u, v8i16>; |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3u, v4i32>; |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3u, v2i64>; |
| |
| class EOR3_pattern<ValueType VecTy> |
| : Pat<(xor (xor (VecTy V128:$Vn), (VecTy V128:$Vm)), (VecTy V128:$Va)), |
| (EOR3 (VecTy V128:$Vn), (VecTy V128:$Vm), (VecTy V128:$Va))>; |
| |
| def : EOR3_pattern<v16i8>; |
| def : EOR3_pattern<v8i16>; |
| def : EOR3_pattern<v4i32>; |
| def : EOR3_pattern<v2i64>; |
| |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxu, v16i8>; |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxu, v8i16>; |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxu, v4i32>; |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxu, v2i64>; |
| |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3s, v16i8>; |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3s, v8i16>; |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3s, v4i32>; |
| def : SHA3_pattern<EOR3, int_aarch64_crypto_eor3s, v2i64>; |
| |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxs, v16i8>; |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxs, v8i16>; |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxs, v4i32>; |
| def : SHA3_pattern<BCAX, int_aarch64_crypto_bcaxs, v2i64>; |
| |
| def : Pat<(v2i64 (int_aarch64_crypto_rax1 (v2i64 V128:$Vn), (v2i64 V128:$Vm))), |
| (RAX1 (v2i64 V128:$Vn), (v2i64 V128:$Vm))>; |
| |
| def : Pat<(v2i64 (int_aarch64_crypto_xar (v2i64 V128:$Vn), (v2i64 V128:$Vm), (i64 timm0_63:$imm))), |
| (XAR (v2i64 V128:$Vn), (v2i64 V128:$Vm), (timm0_63:$imm))>; |
| |
| |
| } // HasSHA3 |
| |
| let Predicates = [HasSM4] in { |
| def SM3TT1A : CryptoRRRi2Tied<0b0, 0b00, "sm3tt1a">; |
| def SM3TT1B : CryptoRRRi2Tied<0b0, 0b01, "sm3tt1b">; |
| def SM3TT2A : CryptoRRRi2Tied<0b0, 0b10, "sm3tt2a">; |
| def SM3TT2B : CryptoRRRi2Tied<0b0, 0b11, "sm3tt2b">; |
| def SM3SS1 : CryptoRRRR_4S<0b10, "sm3ss1">; |
| def SM3PARTW1 : CryptoRRRTied_4S<0b1, 0b00, "sm3partw1">; |
| def SM3PARTW2 : CryptoRRRTied_4S<0b1, 0b01, "sm3partw2">; |
| def SM4ENCKEY : CryptoRRR_4S<0b1, 0b10, "sm4ekey">; |
| def SM4E : CryptoRRTied_4S<0b0, 0b01, "sm4e">; |
| |
| def : Pat<(v4i32 (int_aarch64_crypto_sm3ss1 (v4i32 V128:$Vn), (v4i32 V128:$Vm), (v4i32 V128:$Va))), |
| (SM3SS1 (v4i32 V128:$Vn), (v4i32 V128:$Vm), (v4i32 V128:$Va))>; |
| |
| class SM3PARTW_pattern<Instruction INST, Intrinsic OpNode> |
| : Pat<(v4i32 (OpNode (v4i32 V128:$Vd), (v4i32 V128:$Vn), (v4i32 V128:$Vm))), |
| (INST (v4i32 V128:$Vd), (v4i32 V128:$Vn), (v4i32 V128:$Vm))>; |
| |
| class SM3TT_pattern<Instruction INST, Intrinsic OpNode> |
| : Pat<(v4i32 (OpNode (v4i32 V128:$Vd), (v4i32 V128:$Vn), (v4i32 V128:$Vm), (i64 VectorIndexS_timm:$imm) )), |
| (INST (v4i32 V128:$Vd), (v4i32 V128:$Vn), (v4i32 V128:$Vm), (VectorIndexS_timm:$imm))>; |
| |
| class SM4_pattern<Instruction INST, Intrinsic OpNode> |
| : Pat<(v4i32 (OpNode (v4i32 V128:$Vn), (v4i32 V128:$Vm))), |
| (INST (v4i32 V128:$Vn), (v4i32 V128:$Vm))>; |
| |
| def : SM3PARTW_pattern<SM3PARTW1, int_aarch64_crypto_sm3partw1>; |
| def : SM3PARTW_pattern<SM3PARTW2, int_aarch64_crypto_sm3partw2>; |
| |
| def : SM3TT_pattern<SM3TT1A, int_aarch64_crypto_sm3tt1a>; |
| def : SM3TT_pattern<SM3TT1B, int_aarch64_crypto_sm3tt1b>; |
| def : SM3TT_pattern<SM3TT2A, int_aarch64_crypto_sm3tt2a>; |
| def : SM3TT_pattern<SM3TT2B, int_aarch64_crypto_sm3tt2b>; |
| |
| def : SM4_pattern<SM4ENCKEY, int_aarch64_crypto_sm4ekey>; |
| def : SM4_pattern<SM4E, int_aarch64_crypto_sm4e>; |
| } // HasSM4 |
| |
| let Predicates = [HasRCPC] in { |
| // v8.3 Release Consistent Processor Consistent support, optional in v8.2. |
| def LDAPRB : RCPCLoad<0b00, "ldaprb", GPR32>; |
| def LDAPRH : RCPCLoad<0b01, "ldaprh", GPR32>; |
| def LDAPRW : RCPCLoad<0b10, "ldapr", GPR32>; |
| def LDAPRX : RCPCLoad<0b11, "ldapr", GPR64>; |
| } |
| |
| // v8.3a complex add and multiply-accumulate. No predicate here, that is done |
| // inside the multiclass as the FP16 versions need different predicates. |
| defm FCMLA : SIMDThreeSameVectorTiedComplexHSD<1, 0b110, complexrotateop, |
| "fcmla", null_frag>; |
| defm FCADD : SIMDThreeSameVectorComplexHSD<1, 0b111, complexrotateopodd, |
| "fcadd", null_frag>; |
| defm FCMLA : SIMDIndexedTiedComplexHSD<0, 1, complexrotateop, "fcmla">; |
| |
| let Predicates = [HasComplxNum, HasNEON, HasFullFP16] in { |
| def : Pat<(v4f16 (int_aarch64_neon_vcadd_rot90 (v4f16 V64:$Rn), (v4f16 V64:$Rm))), |
| (FCADDv4f16 (v4f16 V64:$Rn), (v4f16 V64:$Rm), (i32 0))>; |
| def : Pat<(v4f16 (int_aarch64_neon_vcadd_rot270 (v4f16 V64:$Rn), (v4f16 V64:$Rm))), |
| (FCADDv4f16 (v4f16 V64:$Rn), (v4f16 V64:$Rm), (i32 1))>; |
| def : Pat<(v8f16 (int_aarch64_neon_vcadd_rot90 (v8f16 V128:$Rn), (v8f16 V128:$Rm))), |
| (FCADDv8f16 (v8f16 V128:$Rn), (v8f16 V128:$Rm), (i32 0))>; |
| def : Pat<(v8f16 (int_aarch64_neon_vcadd_rot270 (v8f16 V128:$Rn), (v8f16 V128:$Rm))), |
| (FCADDv8f16 (v8f16 V128:$Rn), (v8f16 V128:$Rm), (i32 1))>; |
| } |
| |
| let Predicates = [HasComplxNum, HasNEON] in { |
| def : Pat<(v2f32 (int_aarch64_neon_vcadd_rot90 (v2f32 V64:$Rn), (v2f32 V64:$Rm))), |
| (FCADDv2f32 (v2f32 V64:$Rn), (v2f32 V64:$Rm), (i32 0))>; |
| def : Pat<(v2f32 (int_aarch64_neon_vcadd_rot270 (v2f32 V64:$Rn), (v2f32 V64:$Rm))), |
| (FCADDv2f32 (v2f32 V64:$Rn), (v2f32 V64:$Rm), (i32 1))>; |
| foreach Ty = [v4f32, v2f64] in { |
| def : Pat<(Ty (int_aarch64_neon_vcadd_rot90 (Ty V128:$Rn), (Ty V128:$Rm))), |
| (!cast<Instruction>("FCADD"#Ty) (Ty V128:$Rn), (Ty V128:$Rm), (i32 0))>; |
| def : Pat<(Ty (int_aarch64_neon_vcadd_rot270 (Ty V128:$Rn), (Ty V128:$Rm))), |
| (!cast<Instruction>("FCADD"#Ty) (Ty V128:$Rn), (Ty V128:$Rm), (i32 1))>; |
| } |
| } |
| |
| multiclass FCMLA_PATS<ValueType ty, DAGOperand Reg> { |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot0 (ty Reg:$Rd), (ty Reg:$Rn), (ty Reg:$Rm))), |
| (!cast<Instruction>("FCMLA" # ty) $Rd, $Rn, $Rm, 0)>; |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot90 (ty Reg:$Rd), (ty Reg:$Rn), (ty Reg:$Rm))), |
| (!cast<Instruction>("FCMLA" # ty) $Rd, $Rn, $Rm, 1)>; |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot180 (ty Reg:$Rd), (ty Reg:$Rn), (ty Reg:$Rm))), |
| (!cast<Instruction>("FCMLA" # ty) $Rd, $Rn, $Rm, 2)>; |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot270 (ty Reg:$Rd), (ty Reg:$Rn), (ty Reg:$Rm))), |
| (!cast<Instruction>("FCMLA" # ty) $Rd, $Rn, $Rm, 3)>; |
| } |
| |
| multiclass FCMLA_LANE_PATS<ValueType ty, DAGOperand Reg, dag RHSDup> { |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot0 (ty Reg:$Rd), (ty Reg:$Rn), RHSDup)), |
| (!cast<Instruction>("FCMLA" # ty # "_indexed") $Rd, $Rn, $Rm, VectorIndexS:$idx, 0)>; |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot90 (ty Reg:$Rd), (ty Reg:$Rn), RHSDup)), |
| (!cast<Instruction>("FCMLA" # ty # "_indexed") $Rd, $Rn, $Rm, VectorIndexS:$idx, 1)>; |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot180 (ty Reg:$Rd), (ty Reg:$Rn), RHSDup)), |
| (!cast<Instruction>("FCMLA" # ty # "_indexed") $Rd, $Rn, $Rm, VectorIndexS:$idx, 2)>; |
| def : Pat<(ty (int_aarch64_neon_vcmla_rot270 (ty Reg:$Rd), (ty Reg:$Rn), RHSDup)), |
| (!cast<Instruction>("FCMLA" # ty # "_indexed") $Rd, $Rn, $Rm, VectorIndexS:$idx, 3)>; |
| } |
| |
| |
| let Predicates = [HasComplxNum, HasNEON, HasFullFP16] in { |
| defm : FCMLA_PATS<v4f16, V64>; |
| defm : FCMLA_PATS<v8f16, V128>; |
| |
| defm : FCMLA_LANE_PATS<v4f16, V64, |
| (v4f16 (bitconvert (v2i32 (AArch64duplane32 (v4i32 V128:$Rm), VectorIndexD:$idx))))>; |
| defm : FCMLA_LANE_PATS<v8f16, V128, |
| (v8f16 (bitconvert (v4i32 (AArch64duplane32 (v4i32 V128:$Rm), VectorIndexS:$idx))))>; |
| } |
| let Predicates = [HasComplxNum, HasNEON] in { |
| defm : FCMLA_PATS<v2f32, V64>; |
| defm : FCMLA_PATS<v4f32, V128>; |
| defm : FCMLA_PATS<v2f64, V128>; |
| |
| defm : FCMLA_LANE_PATS<v4f32, V128, |
| (v4f32 (bitconvert (v2i64 (AArch64duplane64 (v2i64 V128:$Rm), VectorIndexD:$idx))))>; |
| } |
| |
| // v8.3a Pointer Authentication |
| // These instructions inhabit part of the hint space and so can be used for |
| // armv8 targets. Keeping the old HINT mnemonic when compiling without PA is |
| // important for compatibility with other assemblers (e.g. GAS) when building |
| // software compatible with both CPUs that do or don't implement PA. |
| let Uses = [LR], Defs = [LR] in { |
| def PACIAZ : SystemNoOperands<0b000, "hint\t#24">; |
| def PACIBZ : SystemNoOperands<0b010, "hint\t#26">; |
| let isAuthenticated = 1 in { |
| def AUTIAZ : SystemNoOperands<0b100, "hint\t#28">; |
| def AUTIBZ : SystemNoOperands<0b110, "hint\t#30">; |
| } |
| } |
| let Uses = [LR, SP], Defs = [LR] in { |
| def PACIASP : SystemNoOperands<0b001, "hint\t#25">; |
| def PACIBSP : SystemNoOperands<0b011, "hint\t#27">; |
| let isAuthenticated = 1 in { |
| def AUTIASP : SystemNoOperands<0b101, "hint\t#29">; |
| def AUTIBSP : SystemNoOperands<0b111, "hint\t#31">; |
| } |
| } |
| let Uses = [X16, X17], Defs = [X17], CRm = 0b0001 in { |
| def PACIA1716 : SystemNoOperands<0b000, "hint\t#8">; |
| def PACIB1716 : SystemNoOperands<0b010, "hint\t#10">; |
| let isAuthenticated = 1 in { |
| def AUTIA1716 : SystemNoOperands<0b100, "hint\t#12">; |
| def AUTIB1716 : SystemNoOperands<0b110, "hint\t#14">; |
| } |
| } |
| |
| let Uses = [LR], Defs = [LR], CRm = 0b0000 in { |
| def XPACLRI : SystemNoOperands<0b111, "hint\t#7">; |
| } |
| |
| // In order to be able to write readable assembly, LLVM should accept assembly |
| // inputs that use pointer authentication mnemonics, even with PA disabled. |
| // However, in order to be compatible with other assemblers (e.g. GAS), LLVM |
| // should not emit these mnemonics unless PA is enabled. |
| def : InstAlias<"paciaz", (PACIAZ), 0>; |
| def : InstAlias<"pacibz", (PACIBZ), 0>; |
| def : InstAlias<"autiaz", (AUTIAZ), 0>; |
| def : InstAlias<"autibz", (AUTIBZ), 0>; |
| def : InstAlias<"paciasp", (PACIASP), 0>; |
| def : InstAlias<"pacibsp", (PACIBSP), 0>; |
| def : InstAlias<"autiasp", (AUTIASP), 0>; |
| def : InstAlias<"autibsp", (AUTIBSP), 0>; |
| def : InstAlias<"pacia1716", (PACIA1716), 0>; |
| def : InstAlias<"pacib1716", (PACIB1716), 0>; |
| def : InstAlias<"autia1716", (AUTIA1716), 0>; |
| def : InstAlias<"autib1716", (AUTIB1716), 0>; |
| def : InstAlias<"xpaclri", (XPACLRI), 0>; |
| |
| // These pointer authentication instructions require armv8.3a |
| let Predicates = [HasPAuth] in { |
| |
| // When PA is enabled, a better mnemonic should be emitted. |
| def : InstAlias<"paciaz", (PACIAZ), 1>; |
| def : InstAlias<"pacibz", (PACIBZ), 1>; |
| def : InstAlias<"autiaz", (AUTIAZ), 1>; |
| def : InstAlias<"autibz", (AUTIBZ), 1>; |
| def : InstAlias<"paciasp", (PACIASP), 1>; |
| def : InstAlias<"pacibsp", (PACIBSP), 1>; |
| def : InstAlias<"autiasp", (AUTIASP), 1>; |
| def : InstAlias<"autibsp", (AUTIBSP), 1>; |
| def : InstAlias<"pacia1716", (PACIA1716), 1>; |
| def : InstAlias<"pacib1716", (PACIB1716), 1>; |
| def : InstAlias<"autia1716", (AUTIA1716), 1>; |
| def : InstAlias<"autib1716", (AUTIB1716), 1>; |
| def : InstAlias<"xpaclri", (XPACLRI), 1>; |
| |
| multiclass SignAuth<bits<3> prefix, bits<3> prefix_z, string asm, |
| SDPatternOperator op> { |
| def IA : SignAuthOneData<prefix, 0b00, !strconcat(asm, "ia"), op>; |
| def IB : SignAuthOneData<prefix, 0b01, !strconcat(asm, "ib"), op>; |
| def DA : SignAuthOneData<prefix, 0b10, !strconcat(asm, "da"), op>; |
| def DB : SignAuthOneData<prefix, 0b11, !strconcat(asm, "db"), op>; |
| def IZA : SignAuthZero<prefix_z, 0b00, !strconcat(asm, "iza"), op>; |
| def DZA : SignAuthZero<prefix_z, 0b10, !strconcat(asm, "dza"), op>; |
| def IZB : SignAuthZero<prefix_z, 0b01, !strconcat(asm, "izb"), op>; |
| def DZB : SignAuthZero<prefix_z, 0b11, !strconcat(asm, "dzb"), op>; |
| } |
| |
| defm PAC : SignAuth<0b000, 0b010, "pac", int_ptrauth_sign>; |
| defm AUT : SignAuth<0b001, 0b011, "aut", null_frag>; |
| |
| def XPACI : ClearAuth<0, "xpaci">; |
| def XPACD : ClearAuth<1, "xpacd">; |
| |
| def PACGA : SignAuthTwoOperand<0b1100, "pacga", int_ptrauth_sign_generic>; |
| |
| // Combined Instructions |
| let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { |
| def BRAA : AuthBranchTwoOperands<0, 0, "braa">; |
| def BRAB : AuthBranchTwoOperands<0, 1, "brab">; |
| } |
| let isCall = 1, Defs = [LR], Uses = [SP] in { |
| def BLRAA : AuthBranchTwoOperands<1, 0, "blraa">; |
| def BLRAB : AuthBranchTwoOperands<1, 1, "blrab">; |
| } |
| |
| let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { |
| def BRAAZ : AuthOneOperand<0b000, 0, "braaz">; |
| def BRABZ : AuthOneOperand<0b000, 1, "brabz">; |
| } |
| let isCall = 1, Defs = [LR], Uses = [SP] in { |
| def BLRAAZ : AuthOneOperand<0b001, 0, "blraaz">; |
| def BLRABZ : AuthOneOperand<0b001, 1, "blrabz">; |
| } |
| |
| let isReturn = 1, isTerminator = 1, isBarrier = 1 in { |
| def RETAA : AuthReturn<0b010, 0, "retaa">; |
| def RETAB : AuthReturn<0b010, 1, "retab">; |
| def ERETAA : AuthReturn<0b100, 0, "eretaa">; |
| def ERETAB : AuthReturn<0b100, 1, "eretab">; |
| } |
| |
| defm LDRAA : AuthLoad<0, "ldraa", simm10Scaled>; |
| defm LDRAB : AuthLoad<1, "ldrab", simm10Scaled>; |
| |
| } |
| |
| // v8.3a floating point conversion for javascript |
| let Predicates = [HasJS, HasFPARMv8], Defs = [NZCV] in |
| def FJCVTZS : BaseFPToIntegerUnscaled<0b01, 0b11, 0b110, FPR64, GPR32, |
| "fjcvtzs", |
| [(set GPR32:$Rd, |
| (int_aarch64_fjcvtzs FPR64:$Rn))]> { |
| let Inst{31} = 0; |
| } // HasJS, HasFPARMv8 |
| |
| // v8.4 Flag manipulation instructions |
| let Predicates = [HasFlagM], Defs = [NZCV], Uses = [NZCV] in { |
| def CFINV : SimpleSystemI<0, (ins), "cfinv", "">, Sched<[WriteSys]> { |
| let Inst{20-5} = 0b0000001000000000; |
| } |
| def SETF8 : BaseFlagManipulation<0, 0, (ins GPR32:$Rn), "setf8", "{\t$Rn}">; |
| def SETF16 : BaseFlagManipulation<0, 1, (ins GPR32:$Rn), "setf16", "{\t$Rn}">; |
| def RMIF : FlagRotate<(ins GPR64:$Rn, uimm6:$imm, imm0_15:$mask), "rmif", |
| "{\t$Rn, $imm, $mask}">; |
| } // HasFlagM |
| |
| // v8.5 flag manipulation instructions |
| let Predicates = [HasAltNZCV], Uses = [NZCV], Defs = [NZCV] in { |
| |
| def XAFLAG : PstateWriteSimple<(ins), "xaflag", "">, Sched<[WriteSys]> { |
| let Inst{18-16} = 0b000; |
| let Inst{11-8} = 0b0000; |
| let Unpredictable{11-8} = 0b1111; |
| let Inst{7-5} = 0b001; |
| } |
| |
| def AXFLAG : PstateWriteSimple<(ins), "axflag", "">, Sched<[WriteSys]> { |
| let Inst{18-16} = 0b000; |
| let Inst{11-8} = 0b0000; |
| let Unpredictable{11-8} = 0b1111; |
| let Inst{7-5} = 0b010; |
| } |
| } // HasAltNZCV |
| |
| |
| // Armv8.5-A speculation barrier |
| def SB : SimpleSystemI<0, (ins), "sb", "">, Sched<[]> { |
| let Inst{20-5} = 0b0001100110000111; |
| let Unpredictable{11-8} = 0b1111; |
| let Predicates = [HasSB]; |
| let hasSideEffects = 1; |
| } |
| |
| def : InstAlias<"clrex", (CLREX 0xf)>; |
| def : InstAlias<"isb", (ISB 0xf)>; |
| def : InstAlias<"ssbb", (DSB 0)>; |
| def : InstAlias<"pssbb", (DSB 4)>; |
| def : InstAlias<"dfb", (DSB 0b1100)>, Requires<[HasV8_0r]>; |
| |
| def MRS : MRSI; |
| def MSR : MSRI; |
| def MSRpstateImm1 : MSRpstateImm0_1; |
| def MSRpstateImm4 : MSRpstateImm0_15; |
| |
| def : Pat<(AArch64mrs imm:$id), |
| (MRS imm:$id)>; |
| |
| // The thread pointer (on Linux, at least, where this has been implemented) is |
| // TPIDR_EL0. |
| def MOVbaseTLS : Pseudo<(outs GPR64:$dst), (ins), |
| [(set GPR64:$dst, AArch64threadpointer)]>, Sched<[WriteSys]>; |
| |
| let Uses = [ X9 ], Defs = [ X16, X17, LR, NZCV ] in { |
| def HWASAN_CHECK_MEMACCESS : Pseudo< |
| (outs), (ins GPR64noip:$ptr, i32imm:$accessinfo), |
| [(int_hwasan_check_memaccess X9, GPR64noip:$ptr, (i32 timm:$accessinfo))]>, |
| Sched<[]>; |
| } |
| |
| let Uses = [ X20 ], Defs = [ X16, X17, LR, NZCV ] in { |
| def HWASAN_CHECK_MEMACCESS_SHORTGRANULES : Pseudo< |
| (outs), (ins GPR64noip:$ptr, i32imm:$accessinfo), |
| [(int_hwasan_check_memaccess_shortgranules X20, GPR64noip:$ptr, (i32 timm:$accessinfo))]>, |
| Sched<[]>; |
| } |
| |
| // The cycle counter PMC register is PMCCNTR_EL0. |
| let Predicates = [HasPerfMon] in |
| def : Pat<(readcyclecounter), (MRS 0xdce8)>; |
| |
| // FPCR register |
| def : Pat<(i64 (int_aarch64_get_fpcr)), (MRS 0xda20)>; |
| def : Pat<(int_aarch64_set_fpcr i64:$val), (MSR 0xda20, GPR64:$val)>; |
| |
| // Generic system instructions |
| def SYSxt : SystemXtI<0, "sys">; |
| def SYSLxt : SystemLXtI<1, "sysl">; |
| |
| def : InstAlias<"sys $op1, $Cn, $Cm, $op2", |
| (SYSxt imm0_7:$op1, sys_cr_op:$Cn, |
| sys_cr_op:$Cm, imm0_7:$op2, XZR)>; |
| |
| |
| let Predicates = [HasTME] in { |
| |
| def TSTART : TMSystemI<0b0000, "tstart", |
| [(set GPR64:$Rt, (int_aarch64_tstart))]>; |
| |
| def TCOMMIT : TMSystemINoOperand<0b0000, "tcommit", [(int_aarch64_tcommit)]>; |
| |
| def TCANCEL : TMSystemException<0b011, "tcancel", |
| [(int_aarch64_tcancel timm64_0_65535:$imm)]>; |
| |
| def TTEST : TMSystemI<0b0001, "ttest", [(set GPR64:$Rt, (int_aarch64_ttest))]> { |
| let mayLoad = 0; |
| let mayStore = 0; |
| } |
| } // HasTME |
| |
| //===----------------------------------------------------------------------===// |
| // Move immediate instructions. |
| //===----------------------------------------------------------------------===// |
| |
| defm MOVK : InsertImmediate<0b11, "movk">; |
| defm MOVN : MoveImmediate<0b00, "movn">; |
| |
| let PostEncoderMethod = "fixMOVZ" in |
| defm MOVZ : MoveImmediate<0b10, "movz">; |
| |
| // First group of aliases covers an implicit "lsl #0". |
| def : InstAlias<"movk $dst, $imm", (MOVKWi GPR32:$dst, timm32_0_65535:$imm, 0), 0>; |
| def : InstAlias<"movk $dst, $imm", (MOVKXi GPR64:$dst, timm32_0_65535:$imm, 0), 0>; |
| def : InstAlias<"movn $dst, $imm", (MOVNWi GPR32:$dst, timm32_0_65535:$imm, 0)>; |
| def : InstAlias<"movn $dst, $imm", (MOVNXi GPR64:$dst, timm32_0_65535:$imm, 0)>; |
| def : InstAlias<"movz $dst, $imm", (MOVZWi GPR32:$dst, timm32_0_65535:$imm, 0)>; |
| def : InstAlias<"movz $dst, $imm", (MOVZXi GPR64:$dst, timm32_0_65535:$imm, 0)>; |
| |
| // Next, we have various ELF relocations with the ":XYZ_g0:sym" syntax. |
| def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movw_symbol_g3:$sym, 48)>; |
| def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movw_symbol_g2:$sym, 32)>; |
| def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movw_symbol_g1:$sym, 16)>; |
| def : InstAlias<"movz $Rd, $sym", (MOVZXi GPR64:$Rd, movw_symbol_g0:$sym, 0)>; |
| |
| def : InstAlias<"movn $Rd, $sym", (MOVNXi GPR64:$Rd, movw_symbol_g3:$sym, 48)>; |
| def : InstAlias<"movn $Rd, $sym", (MOVNXi GPR64:$Rd, movw_symbol_g2:$sym, 32)>; |
| def : InstAlias<"movn $Rd, $sym", (MOVNXi GPR64:$Rd, movw_symbol_g1:$sym, 16)>; |
| def : InstAlias<"movn $Rd, $sym", (MOVNXi GPR64:$Rd, movw_symbol_g0:$sym, 0)>; |
| |
| def : InstAlias<"movk $Rd, $sym", (MOVKXi GPR64:$Rd, movw_symbol_g3:$sym, 48), 0>; |
| def : InstAlias<"movk $Rd, $sym", (MOVKXi GPR64:$Rd, movw_symbol_g2:$sym, 32), 0>; |
| def : InstAlias<"movk $Rd, $sym", (MOVKXi GPR64:$Rd, movw_symbol_g1:$sym, 16), 0>; |
| def : InstAlias<"movk $Rd, $sym", (MOVKXi GPR64:$Rd, movw_symbol_g0:$sym, 0), 0>; |
| |
| def : InstAlias<"movz $Rd, $sym", (MOVZWi GPR32:$Rd, movw_symbol_g1:$sym, 16)>; |
| def : InstAlias<"movz $Rd, $sym", (MOVZWi GPR32:$Rd, movw_symbol_g0:$sym, 0)>; |
| |
| def : InstAlias<"movn $Rd, $sym", (MOVNWi GPR32:$Rd, movw_symbol_g1:$sym, 16)>; |
| def : InstAlias<"movn $Rd, $sym", (MOVNWi GPR32:$Rd, movw_symbol_g0:$sym, 0)>; |
| |
| def : InstAlias<"movk $Rd, $sym", (MOVKWi GPR32:$Rd, movw_symbol_g1:$sym, 16), 0>; |
| def : InstAlias<"movk $Rd, $sym", (MOVKWi GPR32:$Rd, movw_symbol_g0:$sym, 0), 0>; |
| |
| // Final group of aliases covers true "mov $Rd, $imm" cases. |
| multiclass movw_mov_alias<string basename,Instruction INST, RegisterClass GPR, |
| int width, int shift> { |
| def _asmoperand : AsmOperandClass { |
| let Name = basename # width # "_lsl" # shift # "MovAlias"; |
| let PredicateMethod = "is" # basename # "MovAlias<" # width # ", " |
| # shift # ">"; |
| let RenderMethod = "add" # basename # "MovAliasOperands<" # shift # ">"; |
| } |
| |
| def _movimm : Operand<i32> { |
| let ParserMatchClass = !cast<AsmOperandClass>(NAME # "_asmoperand"); |
| } |
| |
| def : InstAlias<"mov $Rd, $imm", |
| (INST GPR:$Rd, !cast<Operand>(NAME # "_movimm"):$imm, shift)>; |
| } |
| |
| defm : movw_mov_alias<"MOVZ", MOVZWi, GPR32, 32, 0>; |
| defm : movw_mov_alias<"MOVZ", MOVZWi, GPR32, 32, 16>; |
| |
| defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 0>; |
| defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 16>; |
| defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 32>; |
| defm : movw_mov_alias<"MOVZ", MOVZXi, GPR64, 64, 48>; |
| |
| defm : movw_mov_alias<"MOVN", MOVNWi, GPR32, 32, 0>; |
| defm : movw_mov_alias<"MOVN", MOVNWi, GPR32, 32, 16>; |
| |
| defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 0>; |
| defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 16>; |
| defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 32>; |
| defm : movw_mov_alias<"MOVN", MOVNXi, GPR64, 64, 48>; |
| |
| let isReMaterializable = 1, isCodeGenOnly = 1, isMoveImm = 1, |
| isAsCheapAsAMove = 1 in { |
| // FIXME: The following pseudo instructions are only needed because remat |
| // cannot handle multiple instructions. When that changes, we can select |
| // directly to the real instructions and get rid of these pseudos. |
| |
| def MOVi32imm |
| : Pseudo<(outs GPR32:$dst), (ins i32imm:$src), |
| [(set GPR32:$dst, imm:$src)]>, |
| Sched<[WriteImm]>; |
| def MOVi64imm |
| : Pseudo<(outs GPR64:$dst), (ins i64imm:$src), |
| [(set GPR64:$dst, imm:$src)]>, |
| Sched<[WriteImm]>; |
| } // isReMaterializable, isCodeGenOnly |
| |
| // If possible, we want to use MOVi32imm even for 64-bit moves. This gives the |
| // eventual expansion code fewer bits to worry about getting right. Marshalling |
| // the types is a little tricky though: |
| def i64imm_32bit : ImmLeaf<i64, [{ |
| return (Imm & 0xffffffffULL) == static_cast<uint64_t>(Imm); |
| }]>; |
| |
| def s64imm_32bit : ImmLeaf<i64, [{ |
| int64_t Imm64 = static_cast<int64_t>(Imm); |
| return Imm64 >= std::numeric_limits<int32_t>::min() && |
| Imm64 <= std::numeric_limits<int32_t>::max(); |
| }]>; |
| |
| def trunc_imm : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant(N->getZExtValue(), SDLoc(N), MVT::i32); |
| }]>; |
| |
| def gi_trunc_imm : GICustomOperandRenderer<"renderTruncImm">, |
| GISDNodeXFormEquiv<trunc_imm>; |
| |
| let Predicates = [OptimizedGISelOrOtherSelector] in { |
| // The SUBREG_TO_REG isn't eliminated at -O0, which can result in pointless |
| // copies. |
| def : Pat<(i64 i64imm_32bit:$src), |
| (SUBREG_TO_REG (i64 0), (MOVi32imm (trunc_imm imm:$src)), sub_32)>; |
| } |
| |
| // Materialize FP constants via MOVi32imm/MOVi64imm (MachO large code model). |
| def bitcast_fpimm_to_i32 : SDNodeXForm<fpimm, [{ |
| return CurDAG->getTargetConstant( |
| N->getValueAPF().bitcastToAPInt().getZExtValue(), SDLoc(N), MVT::i32); |
| }]>; |
| |
| def bitcast_fpimm_to_i64 : SDNodeXForm<fpimm, [{ |
| return CurDAG->getTargetConstant( |
| N->getValueAPF().bitcastToAPInt().getZExtValue(), SDLoc(N), MVT::i64); |
| }]>; |
| |
| |
| def : Pat<(f32 fpimm:$in), |
| (COPY_TO_REGCLASS (MOVi32imm (bitcast_fpimm_to_i32 f32:$in)), FPR32)>; |
| def : Pat<(f64 fpimm:$in), |
| (COPY_TO_REGCLASS (MOVi64imm (bitcast_fpimm_to_i64 f64:$in)), FPR64)>; |
| |
| |
| // Deal with the various forms of (ELF) large addressing with MOVZ/MOVK |
| // sequences. |
| def : Pat<(AArch64WrapperLarge tglobaladdr:$g3, tglobaladdr:$g2, |
| tglobaladdr:$g1, tglobaladdr:$g0), |
| (MOVKXi (MOVKXi (MOVKXi (MOVZXi tglobaladdr:$g0, 0), |
| tglobaladdr:$g1, 16), |
| tglobaladdr:$g2, 32), |
| tglobaladdr:$g3, 48)>; |
| |
| def : Pat<(AArch64WrapperLarge tblockaddress:$g3, tblockaddress:$g2, |
| tblockaddress:$g1, tblockaddress:$g0), |
| (MOVKXi (MOVKXi (MOVKXi (MOVZXi tblockaddress:$g0, 0), |
| tblockaddress:$g1, 16), |
| tblockaddress:$g2, 32), |
| tblockaddress:$g3, 48)>; |
| |
| def : Pat<(AArch64WrapperLarge tconstpool:$g3, tconstpool:$g2, |
| tconstpool:$g1, tconstpool:$g0), |
| (MOVKXi (MOVKXi (MOVKXi (MOVZXi tconstpool:$g0, 0), |
| tconstpool:$g1, 16), |
| tconstpool:$g2, 32), |
| tconstpool:$g3, 48)>; |
| |
| def : Pat<(AArch64WrapperLarge tjumptable:$g3, tjumptable:$g2, |
| tjumptable:$g1, tjumptable:$g0), |
| (MOVKXi (MOVKXi (MOVKXi (MOVZXi tjumptable:$g0, 0), |
| tjumptable:$g1, 16), |
| tjumptable:$g2, 32), |
| tjumptable:$g3, 48)>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Arithmetic instructions. |
| //===----------------------------------------------------------------------===// |
| |
| // Add/subtract with carry. |
| defm ADC : AddSubCarry<0, "adc", "adcs", AArch64adc, AArch64adc_flag>; |
| defm SBC : AddSubCarry<1, "sbc", "sbcs", AArch64sbc, AArch64sbc_flag>; |
| |
| def : InstAlias<"ngc $dst, $src", (SBCWr GPR32:$dst, WZR, GPR32:$src)>; |
| def : InstAlias<"ngc $dst, $src", (SBCXr GPR64:$dst, XZR, GPR64:$src)>; |
| def : InstAlias<"ngcs $dst, $src", (SBCSWr GPR32:$dst, WZR, GPR32:$src)>; |
| def : InstAlias<"ngcs $dst, $src", (SBCSXr GPR64:$dst, XZR, GPR64:$src)>; |
| |
| // Add/subtract |
| defm ADD : AddSub<0, "add", "sub", add>; |
| defm SUB : AddSub<1, "sub", "add">; |
| |
| def : InstAlias<"mov $dst, $src", |
| (ADDWri GPR32sponly:$dst, GPR32sp:$src, 0, 0)>; |
| def : InstAlias<"mov $dst, $src", |
| (ADDWri GPR32sp:$dst, GPR32sponly:$src, 0, 0)>; |
| def : InstAlias<"mov $dst, $src", |
| (ADDXri GPR64sponly:$dst, GPR64sp:$src, 0, 0)>; |
| def : InstAlias<"mov $dst, $src", |
| (ADDXri GPR64sp:$dst, GPR64sponly:$src, 0, 0)>; |
| |
| defm ADDS : AddSubS<0, "adds", AArch64add_flag, "cmn", "subs", "cmp">; |
| defm SUBS : AddSubS<1, "subs", AArch64sub_flag, "cmp", "adds", "cmn">; |
| |
| // Use SUBS instead of SUB to enable CSE between SUBS and SUB. |
| def : Pat<(sub GPR32sp:$Rn, addsub_shifted_imm32:$imm), |
| (SUBSWri GPR32sp:$Rn, addsub_shifted_imm32:$imm)>; |
| def : Pat<(sub GPR64sp:$Rn, addsub_shifted_imm64:$imm), |
| (SUBSXri GPR64sp:$Rn, addsub_shifted_imm64:$imm)>; |
| def : Pat<(sub GPR32:$Rn, GPR32:$Rm), |
| (SUBSWrr GPR32:$Rn, GPR32:$Rm)>; |
| def : Pat<(sub GPR64:$Rn, GPR64:$Rm), |
| (SUBSXrr GPR64:$Rn, GPR64:$Rm)>; |
| def : Pat<(sub GPR32:$Rn, arith_shifted_reg32:$Rm), |
| (SUBSWrs GPR32:$Rn, arith_shifted_reg32:$Rm)>; |
| def : Pat<(sub GPR64:$Rn, arith_shifted_reg64:$Rm), |
| (SUBSXrs GPR64:$Rn, arith_shifted_reg64:$Rm)>; |
| let AddedComplexity = 1 in { |
| def : Pat<(sub GPR32sp:$R2, arith_extended_reg32_i32:$R3), |
| (SUBSWrx GPR32sp:$R2, arith_extended_reg32_i32:$R3)>; |
| def : Pat<(sub GPR64sp:$R2, arith_extended_reg32to64_i64:$R3), |
| (SUBSXrx GPR64sp:$R2, arith_extended_reg32to64_i64:$R3)>; |
| } |
| |
| // Because of the immediate format for add/sub-imm instructions, the |
| // expression (add x, -1) must be transformed to (SUB{W,X}ri x, 1). |
| // These patterns capture that transformation. |
| let AddedComplexity = 1 in { |
| def : Pat<(add GPR32:$Rn, neg_addsub_shifted_imm32:$imm), |
| (SUBSWri GPR32:$Rn, neg_addsub_shifted_imm32:$imm)>; |
| def : Pat<(add GPR64:$Rn, neg_addsub_shifted_imm64:$imm), |
| (SUBSXri GPR64:$Rn, neg_addsub_shifted_imm64:$imm)>; |
| def : Pat<(sub GPR32:$Rn, neg_addsub_shifted_imm32:$imm), |
| (ADDWri GPR32:$Rn, neg_addsub_shifted_imm32:$imm)>; |
| def : Pat<(sub GPR64:$Rn, neg_addsub_shifted_imm64:$imm), |
| (ADDXri GPR64:$Rn, neg_addsub_shifted_imm64:$imm)>; |
| } |
| |
| // Because of the immediate format for add/sub-imm instructions, the |
| // expression (add x, -1) must be transformed to (SUB{W,X}ri x, 1). |
| // These patterns capture that transformation. |
| let AddedComplexity = 1 in { |
| def : Pat<(AArch64add_flag GPR32:$Rn, neg_addsub_shifted_imm32:$imm), |
| (SUBSWri GPR32:$Rn, neg_addsub_shifted_imm32:$imm)>; |
| def : Pat<(AArch64add_flag GPR64:$Rn, neg_addsub_shifted_imm64:$imm), |
| (SUBSXri GPR64:$Rn, neg_addsub_shifted_imm64:$imm)>; |
| def : Pat<(AArch64sub_flag GPR32:$Rn, neg_addsub_shifted_imm32:$imm), |
| (ADDSWri GPR32:$Rn, neg_addsub_shifted_imm32:$imm)>; |
| def : Pat<(AArch64sub_flag GPR64:$Rn, neg_addsub_shifted_imm64:$imm), |
| (ADDSXri GPR64:$Rn, neg_addsub_shifted_imm64:$imm)>; |
| } |
| |
| def : InstAlias<"neg $dst, $src", (SUBWrs GPR32:$dst, WZR, GPR32:$src, 0), 3>; |
| def : InstAlias<"neg $dst, $src", (SUBXrs GPR64:$dst, XZR, GPR64:$src, 0), 3>; |
| def : InstAlias<"neg $dst, $src$shift", |
| (SUBWrs GPR32:$dst, WZR, GPR32:$src, arith_shift32:$shift), 2>; |
| def : InstAlias<"neg $dst, $src$shift", |
| (SUBXrs GPR64:$dst, XZR, GPR64:$src, arith_shift64:$shift), 2>; |
| |
| def : InstAlias<"negs $dst, $src", (SUBSWrs GPR32:$dst, WZR, GPR32:$src, 0), 3>; |
| def : InstAlias<"negs $dst, $src", (SUBSXrs GPR64:$dst, XZR, GPR64:$src, 0), 3>; |
| def : InstAlias<"negs $dst, $src$shift", |
| (SUBSWrs GPR32:$dst, WZR, GPR32:$src, arith_shift32:$shift), 2>; |
| def : InstAlias<"negs $dst, $src$shift", |
| (SUBSXrs GPR64:$dst, XZR, GPR64:$src, arith_shift64:$shift), 2>; |
| |
| |
| // Unsigned/Signed divide |
| defm UDIV : Div<0, "udiv", udiv>; |
| defm SDIV : Div<1, "sdiv", sdiv>; |
| |
| def : Pat<(int_aarch64_udiv GPR32:$Rn, GPR32:$Rm), (UDIVWr GPR32:$Rn, GPR32:$Rm)>; |
| def : Pat<(int_aarch64_udiv GPR64:$Rn, GPR64:$Rm), (UDIVXr GPR64:$Rn, GPR64:$Rm)>; |
| def : Pat<(int_aarch64_sdiv GPR32:$Rn, GPR32:$Rm), (SDIVWr GPR32:$Rn, GPR32:$Rm)>; |
| def : Pat<(int_aarch64_sdiv GPR64:$Rn, GPR64:$Rm), (SDIVXr GPR64:$Rn, GPR64:$Rm)>; |
| |
| // Variable shift |
| defm ASRV : Shift<0b10, "asr", sra>; |
| defm LSLV : Shift<0b00, "lsl", shl>; |
| defm LSRV : Shift<0b01, "lsr", srl>; |
| defm RORV : Shift<0b11, "ror", rotr>; |
| |
| def : ShiftAlias<"asrv", ASRVWr, GPR32>; |
| def : ShiftAlias<"asrv", ASRVXr, GPR64>; |
| def : ShiftAlias<"lslv", LSLVWr, GPR32>; |
| def : ShiftAlias<"lslv", LSLVXr, GPR64>; |
| def : ShiftAlias<"lsrv", LSRVWr, GPR32>; |
| def : ShiftAlias<"lsrv", LSRVXr, GPR64>; |
| def : ShiftAlias<"rorv", RORVWr, GPR32>; |
| def : ShiftAlias<"rorv", RORVXr, GPR64>; |
| |
| // Multiply-add |
| let AddedComplexity = 5 in { |
| defm MADD : MulAccum<0, "madd">; |
| defm MSUB : MulAccum<1, "msub">; |
| |
| def : Pat<(i32 (mul GPR32:$Rn, GPR32:$Rm)), |
| (MADDWrrr GPR32:$Rn, GPR32:$Rm, WZR)>; |
| def : Pat<(i64 (mul GPR64:$Rn, GPR64:$Rm)), |
| (MADDXrrr GPR64:$Rn, GPR64:$Rm, XZR)>; |
| |
| def : Pat<(i32 (ineg (mul GPR32:$Rn, GPR32:$Rm))), |
| (MSUBWrrr GPR32:$Rn, GPR32:$Rm, WZR)>; |
| def : Pat<(i64 (ineg (mul GPR64:$Rn, GPR64:$Rm))), |
| (MSUBXrrr GPR64:$Rn, GPR64:$Rm, XZR)>; |
| def : Pat<(i32 (mul (ineg GPR32:$Rn), GPR32:$Rm)), |
| (MSUBWrrr GPR32:$Rn, GPR32:$Rm, WZR)>; |
| def : Pat<(i64 (mul (ineg GPR64:$Rn), GPR64:$Rm)), |
| (MSUBXrrr GPR64:$Rn, GPR64:$Rm, XZR)>; |
| } // AddedComplexity = 5 |
| |
| let AddedComplexity = 5 in { |
| def SMADDLrrr : WideMulAccum<0, 0b001, "smaddl", add, sext>; |
| def SMSUBLrrr : WideMulAccum<1, 0b001, "smsubl", sub, sext>; |
| def UMADDLrrr : WideMulAccum<0, 0b101, "umaddl", add, zext>; |
| def UMSUBLrrr : WideMulAccum<1, 0b101, "umsubl", sub, zext>; |
| |
| def : Pat<(i64 (mul (sext_inreg GPR64:$Rn, i32), (sext_inreg GPR64:$Rm, i32))), |
| (SMADDLrrr (EXTRACT_SUBREG $Rn, sub_32), (EXTRACT_SUBREG $Rm, sub_32), XZR)>; |
| def : Pat<(i64 (mul (sext_inreg GPR64:$Rn, i32), (sext GPR32:$Rm))), |
| (SMADDLrrr (EXTRACT_SUBREG $Rn, sub_32), $Rm, XZR)>; |
| def : Pat<(i64 (mul (sext GPR32:$Rn), (sext GPR32:$Rm))), |
| (SMADDLrrr GPR32:$Rn, GPR32:$Rm, XZR)>; |
| def : Pat<(i64 (mul (and GPR64:$Rn, 0xFFFFFFFF), (and GPR64:$Rm, 0xFFFFFFFF))), |
| (UMADDLrrr (EXTRACT_SUBREG $Rn, sub_32), (EXTRACT_SUBREG $Rm, sub_32), XZR)>; |
| def : Pat<(i64 (mul (and GPR64:$Rn, 0xFFFFFFFF), (zext GPR32:$Rm))), |
| (UMADDLrrr (EXTRACT_SUBREG $Rn, sub_32), $Rm, XZR)>; |
| def : Pat<(i64 (mul (zext GPR32:$Rn), (zext GPR32:$Rm))), |
| (UMADDLrrr GPR32:$Rn, GPR32:$Rm, XZR)>; |
| |
| def : Pat<(i64 (ineg (mul (sext GPR32:$Rn), (sext GPR32:$Rm)))), |
| (SMSUBLrrr GPR32:$Rn, GPR32:$Rm, XZR)>; |
| def : Pat<(i64 (ineg (mul (zext GPR32:$Rn), (zext GPR32:$Rm)))), |
| (UMSUBLrrr GPR32:$Rn, GPR32:$Rm, XZR)>; |
| |
| def : Pat<(i64 (mul (sext GPR32:$Rn), (s64imm_32bit:$C))), |
| (SMADDLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), XZR)>; |
| def : Pat<(i64 (mul (zext GPR32:$Rn), (i64imm_32bit:$C))), |
| (UMADDLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), XZR)>; |
| def : Pat<(i64 (mul (sext_inreg GPR64:$Rn, i32), (s64imm_32bit:$C))), |
| (SMADDLrrr (i32 (EXTRACT_SUBREG GPR64:$Rn, sub_32)), |
| (MOVi32imm (trunc_imm imm:$C)), XZR)>; |
| |
| def : Pat<(i64 (ineg (mul (sext GPR32:$Rn), (s64imm_32bit:$C)))), |
| (SMSUBLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), XZR)>; |
| def : Pat<(i64 (ineg (mul (zext GPR32:$Rn), (i64imm_32bit:$C)))), |
| (UMSUBLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), XZR)>; |
| def : Pat<(i64 (ineg (mul (sext_inreg GPR64:$Rn, i32), (s64imm_32bit:$C)))), |
| (SMSUBLrrr (i32 (EXTRACT_SUBREG GPR64:$Rn, sub_32)), |
| (MOVi32imm (trunc_imm imm:$C)), XZR)>; |
| |
| def : Pat<(i64 (add (mul (sext GPR32:$Rn), (s64imm_32bit:$C)), GPR64:$Ra)), |
| (SMADDLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), GPR64:$Ra)>; |
| def : Pat<(i64 (add (mul (zext GPR32:$Rn), (i64imm_32bit:$C)), GPR64:$Ra)), |
| (UMADDLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), GPR64:$Ra)>; |
| def : Pat<(i64 (add (mul (sext_inreg GPR64:$Rn, i32), (s64imm_32bit:$C)), |
| GPR64:$Ra)), |
| (SMADDLrrr (i32 (EXTRACT_SUBREG GPR64:$Rn, sub_32)), |
| (MOVi32imm (trunc_imm imm:$C)), GPR64:$Ra)>; |
| |
| def : Pat<(i64 (sub GPR64:$Ra, (mul (sext GPR32:$Rn), (s64imm_32bit:$C)))), |
| (SMSUBLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), GPR64:$Ra)>; |
| def : Pat<(i64 (sub GPR64:$Ra, (mul (zext GPR32:$Rn), (i64imm_32bit:$C)))), |
| (UMSUBLrrr GPR32:$Rn, (MOVi32imm (trunc_imm imm:$C)), GPR64:$Ra)>; |
| def : Pat<(i64 (sub GPR64:$Ra, (mul (sext_inreg GPR64:$Rn, i32), |
| (s64imm_32bit:$C)))), |
| (SMSUBLrrr (i32 (EXTRACT_SUBREG GPR64:$Rn, sub_32)), |
| (MOVi32imm (trunc_imm imm:$C)), GPR64:$Ra)>; |
| } // AddedComplexity = 5 |
| |
| def : MulAccumWAlias<"mul", MADDWrrr>; |
| def : MulAccumXAlias<"mul", MADDXrrr>; |
| def : MulAccumWAlias<"mneg", MSUBWrrr>; |
| def : MulAccumXAlias<"mneg", MSUBXrrr>; |
| def : WideMulAccumAlias<"smull", SMADDLrrr>; |
| def : WideMulAccumAlias<"smnegl", SMSUBLrrr>; |
| def : WideMulAccumAlias<"umull", UMADDLrrr>; |
| def : WideMulAccumAlias<"umnegl", UMSUBLrrr>; |
| |
| // Multiply-high |
| def SMULHrr : MulHi<0b010, "smulh", mulhs>; |
| def UMULHrr : MulHi<0b110, "umulh", mulhu>; |
| |
| // CRC32 |
| def CRC32Brr : BaseCRC32<0, 0b00, 0, GPR32, int_aarch64_crc32b, "crc32b">; |
| def CRC32Hrr : BaseCRC32<0, 0b01, 0, GPR32, int_aarch64_crc32h, "crc32h">; |
| def CRC32Wrr : BaseCRC32<0, 0b10, 0, GPR32, int_aarch64_crc32w, "crc32w">; |
| def CRC32Xrr : BaseCRC32<1, 0b11, 0, GPR64, int_aarch64_crc32x, "crc32x">; |
| |
| def CRC32CBrr : BaseCRC32<0, 0b00, 1, GPR32, int_aarch64_crc32cb, "crc32cb">; |
| def CRC32CHrr : BaseCRC32<0, 0b01, 1, GPR32, int_aarch64_crc32ch, "crc32ch">; |
| def CRC32CWrr : BaseCRC32<0, 0b10, 1, GPR32, int_aarch64_crc32cw, "crc32cw">; |
| def CRC32CXrr : BaseCRC32<1, 0b11, 1, GPR64, int_aarch64_crc32cx, "crc32cx">; |
| |
| // v8.1 atomic CAS |
| defm CAS : CompareAndSwap<0, 0, "">; |
| defm CASA : CompareAndSwap<1, 0, "a">; |
| defm CASL : CompareAndSwap<0, 1, "l">; |
| defm CASAL : CompareAndSwap<1, 1, "al">; |
| |
| // v8.1 atomic CASP |
| defm CASP : CompareAndSwapPair<0, 0, "">; |
| defm CASPA : CompareAndSwapPair<1, 0, "a">; |
| defm CASPL : CompareAndSwapPair<0, 1, "l">; |
| defm CASPAL : CompareAndSwapPair<1, 1, "al">; |
| |
| // v8.1 atomic SWP |
| defm SWP : Swap<0, 0, "">; |
| defm SWPA : Swap<1, 0, "a">; |
| defm SWPL : Swap<0, 1, "l">; |
| defm SWPAL : Swap<1, 1, "al">; |
| |
| // v8.1 atomic LD<OP>(register). Performs load and then ST<OP>(register) |
| defm LDADD : LDOPregister<0b000, "add", 0, 0, "">; |
| defm LDADDA : LDOPregister<0b000, "add", 1, 0, "a">; |
| defm LDADDL : LDOPregister<0b000, "add", 0, 1, "l">; |
| defm LDADDAL : LDOPregister<0b000, "add", 1, 1, "al">; |
| |
| defm LDCLR : LDOPregister<0b001, "clr", 0, 0, "">; |
| defm LDCLRA : LDOPregister<0b001, "clr", 1, 0, "a">; |
| defm LDCLRL : LDOPregister<0b001, "clr", 0, 1, "l">; |
| defm LDCLRAL : LDOPregister<0b001, "clr", 1, 1, "al">; |
| |
| defm LDEOR : LDOPregister<0b010, "eor", 0, 0, "">; |
| defm LDEORA : LDOPregister<0b010, "eor", 1, 0, "a">; |
| defm LDEORL : LDOPregister<0b010, "eor", 0, 1, "l">; |
| defm LDEORAL : LDOPregister<0b010, "eor", 1, 1, "al">; |
| |
| defm LDSET : LDOPregister<0b011, "set", 0, 0, "">; |
| defm LDSETA : LDOPregister<0b011, "set", 1, 0, "a">; |
| defm LDSETL : LDOPregister<0b011, "set", 0, 1, "l">; |
| defm LDSETAL : LDOPregister<0b011, "set", 1, 1, "al">; |
| |
| defm LDSMAX : LDOPregister<0b100, "smax", 0, 0, "">; |
| defm LDSMAXA : LDOPregister<0b100, "smax", 1, 0, "a">; |
| defm LDSMAXL : LDOPregister<0b100, "smax", 0, 1, "l">; |
| defm LDSMAXAL : LDOPregister<0b100, "smax", 1, 1, "al">; |
| |
| defm LDSMIN : LDOPregister<0b101, "smin", 0, 0, "">; |
| defm LDSMINA : LDOPregister<0b101, "smin", 1, 0, "a">; |
| defm LDSMINL : LDOPregister<0b101, "smin", 0, 1, "l">; |
| defm LDSMINAL : LDOPregister<0b101, "smin", 1, 1, "al">; |
| |
| defm LDUMAX : LDOPregister<0b110, "umax", 0, 0, "">; |
| defm LDUMAXA : LDOPregister<0b110, "umax", 1, 0, "a">; |
| defm LDUMAXL : LDOPregister<0b110, "umax", 0, 1, "l">; |
| defm LDUMAXAL : LDOPregister<0b110, "umax", 1, 1, "al">; |
| |
| defm LDUMIN : LDOPregister<0b111, "umin", 0, 0, "">; |
| defm LDUMINA : LDOPregister<0b111, "umin", 1, 0, "a">; |
| defm LDUMINL : LDOPregister<0b111, "umin", 0, 1, "l">; |
| defm LDUMINAL : LDOPregister<0b111, "umin", 1, 1, "al">; |
| |
| // v8.1 atomic ST<OP>(register) as aliases to "LD<OP>(register) when Rt=xZR" |
| defm : STOPregister<"stadd","LDADD">; // STADDx |
| defm : STOPregister<"stclr","LDCLR">; // STCLRx |
| defm : STOPregister<"steor","LDEOR">; // STEORx |
| defm : STOPregister<"stset","LDSET">; // STSETx |
| defm : STOPregister<"stsmax","LDSMAX">;// STSMAXx |
| defm : STOPregister<"stsmin","LDSMIN">;// STSMINx |
| defm : STOPregister<"stumax","LDUMAX">;// STUMAXx |
| defm : STOPregister<"stumin","LDUMIN">;// STUMINx |
| |
| // v8.5 Memory Tagging Extension |
| let Predicates = [HasMTE] in { |
| |
| def IRG : BaseTwoOperand<0b0100, GPR64sp, "irg", int_aarch64_irg, GPR64sp, GPR64>, |
| Sched<[]>{ |
| let Inst{31} = 1; |
| } |
| def GMI : BaseTwoOperand<0b0101, GPR64, "gmi", int_aarch64_gmi, GPR64sp>, Sched<[]>{ |
| let Inst{31} = 1; |
| let isNotDuplicable = 1; |
| } |
| def ADDG : AddSubG<0, "addg", null_frag>; |
| def SUBG : AddSubG<1, "subg", null_frag>; |
| |
| def : InstAlias<"irg $dst, $src", (IRG GPR64sp:$dst, GPR64sp:$src, XZR), 1>; |
| |
| def SUBP : SUBP<0, "subp", int_aarch64_subp>, Sched<[]>; |
| def SUBPS : SUBP<1, "subps", null_frag>, Sched<[]>{ |
| let Defs = [NZCV]; |
| } |
| |
| def : InstAlias<"cmpp $lhs, $rhs", (SUBPS XZR, GPR64sp:$lhs, GPR64sp:$rhs), 0>; |
| |
| def LDG : MemTagLoad<"ldg", "\t$Rt, [$Rn, $offset]">; |
| |
| def : Pat<(int_aarch64_addg (am_indexedu6s128 GPR64sp:$Rn, uimm6s16:$imm6), imm0_15:$imm4), |
| (ADDG GPR64sp:$Rn, imm0_63:$imm6, imm0_15:$imm4)>; |
| def : Pat<(int_aarch64_ldg GPR64:$Rt, (am_indexeds9s128 GPR64sp:$Rn, simm9s16:$offset)), |
| (LDG GPR64:$Rt, GPR64sp:$Rn, simm9s16:$offset)>; |
| |
| def : InstAlias<"ldg $Rt, [$Rn]", (LDG GPR64:$Rt, GPR64sp:$Rn, 0), 1>; |
| |
| def LDGM : MemTagVector<1, "ldgm", "\t$Rt, [$Rn]", |
| (outs GPR64:$Rt), (ins GPR64sp:$Rn)>; |
| def STGM : MemTagVector<0, "stgm", "\t$Rt, [$Rn]", |
| (outs), (ins GPR64:$Rt, GPR64sp:$Rn)>; |
| def STZGM : MemTagVector<0, "stzgm", "\t$Rt, [$Rn]", |
| (outs), (ins GPR64:$Rt, GPR64sp:$Rn)> { |
| let Inst{23} = 0; |
| } |
| |
| defm STG : MemTagStore<0b00, "stg">; |
| defm STZG : MemTagStore<0b01, "stzg">; |
| defm ST2G : MemTagStore<0b10, "st2g">; |
| defm STZ2G : MemTagStore<0b11, "stz2g">; |
| |
| def : Pat<(AArch64stg GPR64sp:$Rn, (am_indexeds9s128 GPR64sp:$Rm, simm9s16:$imm)), |
| (STGOffset $Rn, $Rm, $imm)>; |
| def : Pat<(AArch64stzg GPR64sp:$Rn, (am_indexeds9s128 GPR64sp:$Rm, simm9s16:$imm)), |
| (STZGOffset $Rn, $Rm, $imm)>; |
| def : Pat<(AArch64st2g GPR64sp:$Rn, (am_indexeds9s128 GPR64sp:$Rm, simm9s16:$imm)), |
| (ST2GOffset $Rn, $Rm, $imm)>; |
| def : Pat<(AArch64stz2g GPR64sp:$Rn, (am_indexeds9s128 GPR64sp:$Rm, simm9s16:$imm)), |
| (STZ2GOffset $Rn, $Rm, $imm)>; |
| |
| defm STGP : StorePairOffset <0b01, 0, GPR64z, simm7s16, "stgp">; |
| def STGPpre : StorePairPreIdx <0b01, 0, GPR64z, simm7s16, "stgp">; |
| def STGPpost : StorePairPostIdx<0b01, 0, GPR64z, simm7s16, "stgp">; |
| |
| def : Pat<(int_aarch64_stg GPR64:$Rt, (am_indexeds9s128 GPR64sp:$Rn, simm9s16:$offset)), |
| (STGOffset GPR64:$Rt, GPR64sp:$Rn, simm9s16:$offset)>; |
| |
| def : Pat<(int_aarch64_stgp (am_indexed7s128 GPR64sp:$Rn, simm7s16:$imm), GPR64:$Rt, GPR64:$Rt2), |
| (STGPi $Rt, $Rt2, $Rn, $imm)>; |
| |
| def IRGstack |
| : Pseudo<(outs GPR64sp:$Rd), (ins GPR64sp:$Rsp, GPR64:$Rm), []>, |
| Sched<[]>; |
| def TAGPstack |
| : Pseudo<(outs GPR64sp:$Rd), (ins GPR64sp:$Rn, uimm6s16:$imm6, GPR64sp:$Rm, imm0_15:$imm4), []>, |
| Sched<[]>; |
| |
| // Explicit SP in the first operand prevents ShrinkWrap optimization |
| // from leaving this instruction out of the stack frame. When IRGstack |
| // is transformed into IRG, this operand is replaced with the actual |
| // register / expression for the tagged base pointer of the current function. |
| def : Pat<(int_aarch64_irg_sp i64:$Rm), (IRGstack SP, i64:$Rm)>; |
| |
| // Large STG to be expanded into a loop. $sz is the size, $Rn is start address. |
| // $Rn_wback is one past the end of the range. $Rm is the loop counter. |
| let isCodeGenOnly=1, mayStore=1 in { |
| def STGloop_wback |
| : Pseudo<(outs GPR64common:$Rm, GPR64sp:$Rn_wback), (ins i64imm:$sz, GPR64sp:$Rn), |
| [], "$Rn = $Rn_wback,@earlyclobber $Rn_wback,@earlyclobber $Rm" >, |
| Sched<[WriteAdr, WriteST]>; |
| |
| def STZGloop_wback |
| : Pseudo<(outs GPR64common:$Rm, GPR64sp:$Rn_wback), (ins i64imm:$sz, GPR64sp:$Rn), |
| [], "$Rn = $Rn_wback,@earlyclobber $Rn_wback,@earlyclobber $Rm" >, |
| Sched<[WriteAdr, WriteST]>; |
| |
| // A variant of the above where $Rn2 is an independent register not tied to the input register $Rn. |
| // Their purpose is to use a FrameIndex operand as $Rn (which of course can not be written back). |
| def STGloop |
| : Pseudo<(outs GPR64common:$Rm, GPR64sp:$Rn2), (ins i64imm:$sz, GPR64sp:$Rn), |
| [], "@earlyclobber $Rn2,@earlyclobber $Rm" >, |
| Sched<[WriteAdr, WriteST]>; |
| |
| def STZGloop |
| : Pseudo<(outs GPR64common:$Rm, GPR64sp:$Rn2), (ins i64imm:$sz, GPR64sp:$Rn), |
| [], "@earlyclobber $Rn2,@earlyclobber $Rm" >, |
| Sched<[WriteAdr, WriteST]>; |
| } |
| |
| } // Predicates = [HasMTE] |
| |
| //===----------------------------------------------------------------------===// |
| // Logical instructions. |
| //===----------------------------------------------------------------------===// |
| |
| // (immediate) |
| defm ANDS : LogicalImmS<0b11, "ands", AArch64and_flag, "bics">; |
| defm AND : LogicalImm<0b00, "and", and, "bic">; |
| defm EOR : LogicalImm<0b10, "eor", xor, "eon">; |
| defm ORR : LogicalImm<0b01, "orr", or, "orn">; |
| |
| // FIXME: these aliases *are* canonical sometimes (when movz can't be |
| // used). Actually, it seems to be working right now, but putting logical_immXX |
| // here is a bit dodgy on the AsmParser side too. |
| def : InstAlias<"mov $dst, $imm", (ORRWri GPR32sp:$dst, WZR, |
| logical_imm32:$imm), 0>; |
| def : InstAlias<"mov $dst, $imm", (ORRXri GPR64sp:$dst, XZR, |
| logical_imm64:$imm), 0>; |
| |
| |
| // (register) |
| defm ANDS : LogicalRegS<0b11, 0, "ands", AArch64and_flag>; |
| defm BICS : LogicalRegS<0b11, 1, "bics", |
| BinOpFrag<(AArch64and_flag node:$LHS, (not node:$RHS))>>; |
| defm AND : LogicalReg<0b00, 0, "and", and>; |
| defm BIC : LogicalReg<0b00, 1, "bic", |
| BinOpFrag<(and node:$LHS, (not node:$RHS))>>; |
| defm EON : LogicalReg<0b10, 1, "eon", |
| BinOpFrag<(not (xor node:$LHS, node:$RHS))>>; |
| defm EOR : LogicalReg<0b10, 0, "eor", xor>; |
| defm ORN : LogicalReg<0b01, 1, "orn", |
| BinOpFrag<(or node:$LHS, (not node:$RHS))>>; |
| defm ORR : LogicalReg<0b01, 0, "orr", or>; |
| |
| def : InstAlias<"mov $dst, $src", (ORRWrs GPR32:$dst, WZR, GPR32:$src, 0), 2>; |
| def : InstAlias<"mov $dst, $src", (ORRXrs GPR64:$dst, XZR, GPR64:$src, 0), 2>; |
| |
| def : InstAlias<"mvn $Wd, $Wm", (ORNWrs GPR32:$Wd, WZR, GPR32:$Wm, 0), 3>; |
| def : InstAlias<"mvn $Xd, $Xm", (ORNXrs GPR64:$Xd, XZR, GPR64:$Xm, 0), 3>; |
| |
| def : InstAlias<"mvn $Wd, $Wm$sh", |
| (ORNWrs GPR32:$Wd, WZR, GPR32:$Wm, logical_shift32:$sh), 2>; |
| def : InstAlias<"mvn $Xd, $Xm$sh", |
| (ORNXrs GPR64:$Xd, XZR, GPR64:$Xm, logical_shift64:$sh), 2>; |
| |
| def : InstAlias<"tst $src1, $src2", |
| (ANDSWri WZR, GPR32:$src1, logical_imm32:$src2), 2>; |
| def : InstAlias<"tst $src1, $src2", |
| (ANDSXri XZR, GPR64:$src1, logical_imm64:$src2), 2>; |
| |
| def : InstAlias<"tst $src1, $src2", |
| (ANDSWrs WZR, GPR32:$src1, GPR32:$src2, 0), 3>; |
| def : InstAlias<"tst $src1, $src2", |
| (ANDSXrs XZR, GPR64:$src1, GPR64:$src2, 0), 3>; |
| |
| def : InstAlias<"tst $src1, $src2$sh", |
| (ANDSWrs WZR, GPR32:$src1, GPR32:$src2, logical_shift32:$sh), 2>; |
| def : InstAlias<"tst $src1, $src2$sh", |
| (ANDSXrs XZR, GPR64:$src1, GPR64:$src2, logical_shift64:$sh), 2>; |
| |
| |
| def : Pat<(not GPR32:$Wm), (ORNWrr WZR, GPR32:$Wm)>; |
| def : Pat<(not GPR64:$Xm), (ORNXrr XZR, GPR64:$Xm)>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // One operand data processing instructions. |
| //===----------------------------------------------------------------------===// |
| |
| defm CLS : OneOperandData<0b101, "cls">; |
| defm CLZ : OneOperandData<0b100, "clz", ctlz>; |
| defm RBIT : OneOperandData<0b000, "rbit", bitreverse>; |
| |
| def REV16Wr : OneWRegData<0b001, "rev16", |
| UnOpFrag<(rotr (bswap node:$LHS), (i64 16))>>; |
| def REV16Xr : OneXRegData<0b001, "rev16", null_frag>; |
| |
| def : Pat<(cttz GPR32:$Rn), |
| (CLZWr (RBITWr GPR32:$Rn))>; |
| def : Pat<(cttz GPR64:$Rn), |
| (CLZXr (RBITXr GPR64:$Rn))>; |
| def : Pat<(ctlz (or (shl (xor (sra GPR32:$Rn, (i64 31)), GPR32:$Rn), (i64 1)), |
| (i32 1))), |
| (CLSWr GPR32:$Rn)>; |
| def : Pat<(ctlz (or (shl (xor (sra GPR64:$Rn, (i64 63)), GPR64:$Rn), (i64 1)), |
| (i64 1))), |
| (CLSXr GPR64:$Rn)>; |
| def : Pat<(int_aarch64_cls GPR32:$Rn), (CLSWr GPR32:$Rn)>; |
| def : Pat<(int_aarch64_cls64 GPR64:$Rm), (EXTRACT_SUBREG (CLSXr GPR64:$Rm), sub_32)>; |
| |
| // Unlike the other one operand instructions, the instructions with the "rev" |
| // mnemonic do *not* just different in the size bit, but actually use different |
| // opcode bits for the different sizes. |
| def REVWr : OneWRegData<0b010, "rev", bswap>; |
| def REVXr : OneXRegData<0b011, "rev", bswap>; |
| def REV32Xr : OneXRegData<0b010, "rev32", |
| UnOpFrag<(rotr (bswap node:$LHS), (i64 32))>>; |
| |
| def : InstAlias<"rev64 $Rd, $Rn", (REVXr GPR64:$Rd, GPR64:$Rn), 0>; |
| |
| // The bswap commutes with the rotr so we want a pattern for both possible |
| // orders. |
| def : Pat<(bswap (rotr GPR32:$Rn, (i64 16))), (REV16Wr GPR32:$Rn)>; |
| def : Pat<(bswap (rotr GPR64:$Rn, (i64 32))), (REV32Xr GPR64:$Rn)>; |
| |
| // Match (srl (bswap x), C) -> revC if the upper bswap bits are known zero. |
| def : Pat<(srl (bswap top16Zero:$Rn), (i64 16)), (REV16Wr GPR32:$Rn)>; |
| def : Pat<(srl (bswap top32Zero:$Rn), (i64 32)), (REV32Xr GPR64:$Rn)>; |
| |
| //===----------------------------------------------------------------------===// |
| // Bitfield immediate extraction instruction. |
| //===----------------------------------------------------------------------===// |
| let hasSideEffects = 0 in |
| defm EXTR : ExtractImm<"extr">; |
| def : InstAlias<"ror $dst, $src, $shift", |
| (EXTRWrri GPR32:$dst, GPR32:$src, GPR32:$src, imm0_31:$shift)>; |
| def : InstAlias<"ror $dst, $src, $shift", |
| (EXTRXrri GPR64:$dst, GPR64:$src, GPR64:$src, imm0_63:$shift)>; |
| |
| def : Pat<(rotr GPR32:$Rn, (i64 imm0_31:$imm)), |
| (EXTRWrri GPR32:$Rn, GPR32:$Rn, imm0_31:$imm)>; |
| def : Pat<(rotr GPR64:$Rn, (i64 imm0_63:$imm)), |
| (EXTRXrri GPR64:$Rn, GPR64:$Rn, imm0_63:$imm)>; |
| |
| //===----------------------------------------------------------------------===// |
| // Other bitfield immediate instructions. |
| //===----------------------------------------------------------------------===// |
| let hasSideEffects = 0 in { |
| defm BFM : BitfieldImmWith2RegArgs<0b01, "bfm">; |
| defm SBFM : BitfieldImm<0b00, "sbfm">; |
| defm UBFM : BitfieldImm<0b10, "ubfm">; |
| } |
| |
| def i32shift_a : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = (32 - N->getZExtValue()) & 0x1f; |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| def i32shift_b : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = 31 - N->getZExtValue(); |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| // min(7, 31 - shift_amt) |
| def i32shift_sext_i8 : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = 31 - N->getZExtValue(); |
| enc = enc > 7 ? 7 : enc; |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| // min(15, 31 - shift_amt) |
| def i32shift_sext_i16 : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = 31 - N->getZExtValue(); |
| enc = enc > 15 ? 15 : enc; |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| def i64shift_a : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = (64 - N->getZExtValue()) & 0x3f; |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| def i64shift_b : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = 63 - N->getZExtValue(); |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| // min(7, 63 - shift_amt) |
| def i64shift_sext_i8 : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = 63 - N->getZExtValue(); |
| enc = enc > 7 ? 7 : enc; |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| // min(15, 63 - shift_amt) |
| def i64shift_sext_i16 : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = 63 - N->getZExtValue(); |
| enc = enc > 15 ? 15 : enc; |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| // min(31, 63 - shift_amt) |
| def i64shift_sext_i32 : Operand<i64>, SDNodeXForm<imm, [{ |
| uint64_t enc = 63 - N->getZExtValue(); |
| enc = enc > 31 ? 31 : enc; |
| return CurDAG->getTargetConstant(enc, SDLoc(N), MVT::i64); |
| }]>; |
| |
| def : Pat<(shl GPR32:$Rn, (i64 imm0_31:$imm)), |
| (UBFMWri GPR32:$Rn, (i64 (i32shift_a imm0_31:$imm)), |
| (i64 (i32shift_b imm0_31:$imm)))>; |
| def : Pat<(shl GPR64:$Rn, (i64 imm0_63:$imm)), |
| (UBFMXri GPR64:$Rn, (i64 (i64shift_a imm0_63:$imm)), |
| (i64 (i64shift_b imm0_63:$imm)))>; |
| |
| let AddedComplexity = 10 in { |
| def : Pat<(sra GPR32:$Rn, (i64 imm0_31:$imm)), |
| (SBFMWri GPR32:$Rn, imm0_31:$imm, 31)>; |
| def : Pat<(sra GPR64:$Rn, (i64 imm0_63:$imm)), |
| (SBFMXri GPR64:$Rn, imm0_63:$imm, 63)>; |
| } |
| |
| def : InstAlias<"asr $dst, $src, $shift", |
| (SBFMWri GPR32:$dst, GPR32:$src, imm0_31:$shift, 31)>; |
| def : InstAlias<"asr $dst, $src, $shift", |
| (SBFMXri GPR64:$dst, GPR64:$src, imm0_63:$shift, 63)>; |
| def : InstAlias<"sxtb $dst, $src", (SBFMWri GPR32:$dst, GPR32:$src, 0, 7)>; |
| def : InstAlias<"sxtb $dst, $src", (SBFMXri GPR64:$dst, GPR64:$src, 0, 7)>; |
| def : InstAlias<"sxth $dst, $src", (SBFMWri GPR32:$dst, GPR32:$src, 0, 15)>; |
| def : InstAlias<"sxth $dst, $src", (SBFMXri GPR64:$dst, GPR64:$src, 0, 15)>; |
| def : InstAlias<"sxtw $dst, $src", (SBFMXri GPR64:$dst, GPR64:$src, 0, 31)>; |
| |
| def : Pat<(srl GPR32:$Rn, (i64 imm0_31:$imm)), |
| (UBFMWri GPR32:$Rn, imm0_31:$imm, 31)>; |
| def : Pat<(srl GPR64:$Rn, (i64 imm0_63:$imm)), |
| (UBFMXri GPR64:$Rn, imm0_63:$imm, 63)>; |
| |
| def : InstAlias<"lsr $dst, $src, $shift", |
| (UBFMWri GPR32:$dst, GPR32:$src, imm0_31:$shift, 31)>; |
| def : InstAlias<
|