| //===- ARMInstrInfo.td - Target Description for ARM Target -*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file describes the ARM instructions in TableGen format. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| // ARM specific DAG Nodes. |
| // |
| |
| // Type profiles. |
| def SDT_ARMCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>, |
| SDTCisVT<1, i32> ]>; |
| def SDT_ARMCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, SDTCisVT<1, i32> ]>; |
| def SDT_ARMStructByVal : SDTypeProfile<0, 4, |
| [SDTCisVT<0, i32>, SDTCisVT<1, i32>, |
| SDTCisVT<2, i32>, SDTCisVT<3, i32>]>; |
| |
| def SDT_ARMSaveCallPC : SDTypeProfile<0, 1, []>; |
| |
| def SDT_ARMcall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; |
| |
| def SDT_ARMCMov : SDTypeProfile<1, 3, |
| [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, |
| SDTCisVT<3, i32>]>; |
| |
| def SDT_ARMBrcond : SDTypeProfile<0, 2, |
| [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>]>; |
| |
| def SDT_ARMBrJT : SDTypeProfile<0, 2, |
| [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; |
| |
| def SDT_ARMBr2JT : SDTypeProfile<0, 3, |
| [SDTCisPtrTy<0>, SDTCisVT<1, i32>, |
| SDTCisVT<2, i32>]>; |
| |
| def SDT_ARMBCC_i64 : SDTypeProfile<0, 6, |
| [SDTCisVT<0, i32>, |
| SDTCisVT<1, i32>, SDTCisVT<2, i32>, |
| SDTCisVT<3, i32>, SDTCisVT<4, i32>, |
| SDTCisVT<5, OtherVT>]>; |
| |
| def SDT_ARMAnd : SDTypeProfile<1, 2, |
| [SDTCisVT<0, i32>, SDTCisVT<1, i32>, |
| SDTCisVT<2, i32>]>; |
| |
| def SDT_ARMCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; |
| |
| def SDT_ARMPICAdd : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>, |
| SDTCisPtrTy<1>, SDTCisVT<2, i32>]>; |
| |
| def SDT_ARMThreadPointer : SDTypeProfile<1, 0, [SDTCisPtrTy<0>]>; |
| def SDT_ARMEH_SJLJ_Setjmp : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisPtrTy<1>, |
| SDTCisInt<2>]>; |
| def SDT_ARMEH_SJLJ_Longjmp: SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisInt<1>]>; |
| def SDT_ARMEH_SJLJ_SetupDispatch: SDTypeProfile<0, 0, []>; |
| |
| def SDT_ARMMEMBARRIER : SDTypeProfile<0, 1, [SDTCisInt<0>]>; |
| |
| def SDT_ARMPREFETCH : SDTypeProfile<0, 3, [SDTCisPtrTy<0>, SDTCisSameAs<1, 2>, |
| SDTCisInt<1>]>; |
| |
| def SDT_ARMTCRET : SDTypeProfile<0, 2, [SDTCisPtrTy<0>]>; |
| |
| def SDT_ARMBFI : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, |
| SDTCisVT<2, i32>, SDTCisVT<3, i32>]>; |
| |
| def SDT_WIN__DBZCHK : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>; |
| |
| def SDT_ARMMEMCPY : SDTypeProfile<2, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>, |
| SDTCisVT<2, i32>, SDTCisVT<3, i32>, |
| SDTCisVT<4, i32>]>; |
| |
| def SDTBinaryArithWithFlags : SDTypeProfile<2, 2, |
| [SDTCisSameAs<0, 2>, |
| SDTCisSameAs<0, 3>, |
| SDTCisInt<0>, SDTCisVT<1, i32>]>; |
| |
| // SDTBinaryArithWithFlagsInOut - RES1, CPSR = op LHS, RHS, CPSR |
| def SDTBinaryArithWithFlagsInOut : SDTypeProfile<2, 3, |
| [SDTCisSameAs<0, 2>, |
| SDTCisSameAs<0, 3>, |
| SDTCisInt<0>, |
| SDTCisVT<1, i32>, |
| SDTCisVT<4, i32>]>; |
| |
| def SDT_LongMac : SDTypeProfile<2, 4, [SDTCisVT<0, i32>, |
| SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>, |
| SDTCisSameAs<0, 3>, |
| SDTCisSameAs<0, 4>, |
| SDTCisSameAs<0, 5>]>; |
| |
| // ARMlsll, ARMlsrl, ARMasrl |
| def SDT_ARMIntShiftParts : SDTypeProfile<2, 3, [SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>, |
| SDTCisSameAs<0, 3>, |
| SDTCisInt<0>, |
| SDTCisInt<4>]>; |
| |
| def ARMSmlald : SDNode<"ARMISD::SMLALD", SDT_LongMac>; |
| def ARMSmlaldx : SDNode<"ARMISD::SMLALDX", SDT_LongMac>; |
| def ARMSmlsld : SDNode<"ARMISD::SMLSLD", SDT_LongMac>; |
| def ARMSmlsldx : SDNode<"ARMISD::SMLSLDX", SDT_LongMac>; |
| |
| def SDT_ARMCSel : SDTypeProfile<1, 3, |
| [SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>, |
| SDTCisInt<3>, |
| SDTCisVT<3, i32>]>; |
| |
| def ARMcsinv : SDNode<"ARMISD::CSINV", SDT_ARMCSel, [SDNPOptInGlue]>; |
| def ARMcsneg : SDNode<"ARMISD::CSNEG", SDT_ARMCSel, [SDNPOptInGlue]>; |
| def ARMcsinc : SDNode<"ARMISD::CSINC", SDT_ARMCSel, [SDNPOptInGlue]>; |
| |
| def SDT_MulHSR : SDTypeProfile<1, 3, [SDTCisVT<0,i32>, |
| SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>, |
| SDTCisSameAs<0, 3>]>; |
| |
| def ARMsmmlar : SDNode<"ARMISD::SMMLAR", SDT_MulHSR>; |
| def ARMsmmlsr : SDNode<"ARMISD::SMMLSR", SDT_MulHSR>; |
| |
| // Node definitions. |
| def ARMWrapper : SDNode<"ARMISD::Wrapper", SDTIntUnaryOp>; |
| def ARMWrapperPIC : SDNode<"ARMISD::WrapperPIC", SDTIntUnaryOp>; |
| def ARMWrapperJT : SDNode<"ARMISD::WrapperJT", SDTIntUnaryOp>; |
| |
| def ARMcallseq_start : SDNode<"ISD::CALLSEQ_START", SDT_ARMCallSeqStart, |
| [SDNPHasChain, SDNPSideEffect, SDNPOutGlue]>; |
| def ARMcallseq_end : SDNode<"ISD::CALLSEQ_END", SDT_ARMCallSeqEnd, |
| [SDNPHasChain, SDNPSideEffect, |
| SDNPOptInGlue, SDNPOutGlue]>; |
| def ARMcopystructbyval : SDNode<"ARMISD::COPY_STRUCT_BYVAL" , |
| SDT_ARMStructByVal, |
| [SDNPHasChain, SDNPInGlue, SDNPOutGlue, |
| SDNPMayStore, SDNPMayLoad]>; |
| |
| def ARMcall : SDNode<"ARMISD::CALL", SDT_ARMcall, |
| [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, |
| SDNPVariadic]>; |
| def ARMcall_pred : SDNode<"ARMISD::CALL_PRED", SDT_ARMcall, |
| [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, |
| SDNPVariadic]>; |
| def ARMcall_nolink : SDNode<"ARMISD::CALL_NOLINK", SDT_ARMcall, |
| [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, |
| SDNPVariadic]>; |
| |
| def ARMretflag : SDNode<"ARMISD::RET_FLAG", SDTNone, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| def ARMseretflag : SDNode<"ARMISD::SERET_FLAG", SDTNone, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| def ARMintretflag : SDNode<"ARMISD::INTRET_FLAG", SDT_ARMcall, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| def ARMcmov : SDNode<"ARMISD::CMOV", SDT_ARMCMov, |
| [SDNPInGlue]>; |
| def ARMsubs : SDNode<"ARMISD::SUBS", SDTIntBinOp, [SDNPOutGlue]>; |
| |
| def ARMssat : SDNode<"ARMISD::SSAT", SDTIntSatNoShOp, []>; |
| |
| def ARMusat : SDNode<"ARMISD::USAT", SDTIntSatNoShOp, []>; |
| |
| def ARMbrcond : SDNode<"ARMISD::BRCOND", SDT_ARMBrcond, |
| [SDNPHasChain, SDNPInGlue, SDNPOutGlue]>; |
| |
| def ARMbrjt : SDNode<"ARMISD::BR_JT", SDT_ARMBrJT, |
| [SDNPHasChain]>; |
| def ARMbr2jt : SDNode<"ARMISD::BR2_JT", SDT_ARMBr2JT, |
| [SDNPHasChain]>; |
| |
| def ARMBcci64 : SDNode<"ARMISD::BCC_i64", SDT_ARMBCC_i64, |
| [SDNPHasChain]>; |
| |
| def ARMcmp : SDNode<"ARMISD::CMP", SDT_ARMCmp, |
| [SDNPOutGlue]>; |
| |
| def ARMcmn : SDNode<"ARMISD::CMN", SDT_ARMCmp, |
| [SDNPOutGlue]>; |
| |
| def ARMcmpZ : SDNode<"ARMISD::CMPZ", SDT_ARMCmp, |
| [SDNPOutGlue, SDNPCommutative]>; |
| |
| def ARMpic_add : SDNode<"ARMISD::PIC_ADD", SDT_ARMPICAdd>; |
| |
| def ARMasrl : SDNode<"ARMISD::ASRL", SDT_ARMIntShiftParts, []>; |
| def ARMlsrl : SDNode<"ARMISD::LSRL", SDT_ARMIntShiftParts, []>; |
| def ARMlsll : SDNode<"ARMISD::LSLL", SDT_ARMIntShiftParts, []>; |
| |
| def ARMsrl_flag : SDNode<"ARMISD::SRL_FLAG", SDTIntUnaryOp, [SDNPOutGlue]>; |
| def ARMsra_flag : SDNode<"ARMISD::SRA_FLAG", SDTIntUnaryOp, [SDNPOutGlue]>; |
| def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInGlue ]>; |
| |
| def ARMaddc : SDNode<"ARMISD::ADDC", SDTBinaryArithWithFlags, |
| [SDNPCommutative]>; |
| def ARMsubc : SDNode<"ARMISD::SUBC", SDTBinaryArithWithFlags>; |
| def ARMlsls : SDNode<"ARMISD::LSLS", SDTBinaryArithWithFlags>; |
| def ARMadde : SDNode<"ARMISD::ADDE", SDTBinaryArithWithFlagsInOut>; |
| def ARMsube : SDNode<"ARMISD::SUBE", SDTBinaryArithWithFlagsInOut>; |
| |
| def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>; |
| def ARMeh_sjlj_setjmp: SDNode<"ARMISD::EH_SJLJ_SETJMP", |
| SDT_ARMEH_SJLJ_Setjmp, |
| [SDNPHasChain, SDNPSideEffect]>; |
| def ARMeh_sjlj_longjmp: SDNode<"ARMISD::EH_SJLJ_LONGJMP", |
| SDT_ARMEH_SJLJ_Longjmp, |
| [SDNPHasChain, SDNPSideEffect]>; |
| def ARMeh_sjlj_setup_dispatch: SDNode<"ARMISD::EH_SJLJ_SETUP_DISPATCH", |
| SDT_ARMEH_SJLJ_SetupDispatch, |
| [SDNPHasChain, SDNPSideEffect]>; |
| |
| def ARMMemBarrierMCR : SDNode<"ARMISD::MEMBARRIER_MCR", SDT_ARMMEMBARRIER, |
| [SDNPHasChain, SDNPSideEffect]>; |
| def ARMPreload : SDNode<"ARMISD::PRELOAD", SDT_ARMPREFETCH, |
| [SDNPHasChain, SDNPMayLoad, SDNPMayStore]>; |
| |
| def ARMtcret : SDNode<"ARMISD::TC_RETURN", SDT_ARMTCRET, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| |
| def ARMbfi : SDNode<"ARMISD::BFI", SDT_ARMBFI>; |
| |
| def ARMmemcopy : SDNode<"ARMISD::MEMCPY", SDT_ARMMEMCPY, |
| [SDNPHasChain, SDNPInGlue, SDNPOutGlue, |
| SDNPMayStore, SDNPMayLoad]>; |
| |
| def ARMsmulwb : SDNode<"ARMISD::SMULWB", SDTIntBinOp, []>; |
| def ARMsmulwt : SDNode<"ARMISD::SMULWT", SDTIntBinOp, []>; |
| def ARMsmlalbb : SDNode<"ARMISD::SMLALBB", SDT_LongMac, []>; |
| def ARMsmlalbt : SDNode<"ARMISD::SMLALBT", SDT_LongMac, []>; |
| def ARMsmlaltb : SDNode<"ARMISD::SMLALTB", SDT_LongMac, []>; |
| def ARMsmlaltt : SDNode<"ARMISD::SMLALTT", SDT_LongMac, []>; |
| |
| def ARMqadd8b : SDNode<"ARMISD::QADD8b", SDT_ARMAnd, []>; |
| def ARMqsub8b : SDNode<"ARMISD::QSUB8b", SDT_ARMAnd, []>; |
| def ARMqadd16b : SDNode<"ARMISD::QADD16b", SDT_ARMAnd, []>; |
| def ARMqsub16b : SDNode<"ARMISD::QSUB16b", SDT_ARMAnd, []>; |
| |
| def ARMuqadd8b : SDNode<"ARMISD::UQADD8b", SDT_ARMAnd, []>; |
| def ARMuqsub8b : SDNode<"ARMISD::UQSUB8b", SDT_ARMAnd, []>; |
| def ARMuqadd16b : SDNode<"ARMISD::UQADD16b", SDT_ARMAnd, []>; |
| def ARMuqsub16b : SDNode<"ARMISD::UQSUB16b", SDT_ARMAnd, []>; |
| |
| def SDT_ARMldrd : SDTypeProfile<2, 1, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; |
| def ARMldrd : SDNode<"ARMISD::LDRD", SDT_ARMldrd, [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; |
| |
| def SDT_ARMstrd : SDTypeProfile<0, 3, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; |
| def ARMstrd : SDNode<"ARMISD::STRD", SDT_ARMstrd, [SDNPHasChain, SDNPMayStore, SDNPMemOperand]>; |
| |
| // Vector operations shared between NEON and MVE |
| |
| def ARMvdup : SDNode<"ARMISD::VDUP", SDTypeProfile<1, 1, [SDTCisVec<0>]>>; |
| |
| // VDUPLANE can produce a quad-register result from a double-register source, |
| // so the result is not constrained to match the source. |
| def ARMvduplane : SDNode<"ARMISD::VDUPLANE", |
| SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisVec<1>, |
| SDTCisVT<2, i32>]>>; |
| |
| def SDTARMVIDUP : SDTypeProfile<2, 2, [SDTCisVec<0>, SDTCisVT<1, i32>, |
| SDTCisVT<2, i32>, SDTCisVT<3, i32>]>; |
| def ARMvidup : SDNode<"ARMISD::VIDUP", SDTARMVIDUP>; |
| |
| def SDTARMVSHUF : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisSameAs<0, 1>]>; |
| def ARMvrev64 : SDNode<"ARMISD::VREV64", SDTARMVSHUF>; |
| def ARMvrev32 : SDNode<"ARMISD::VREV32", SDTARMVSHUF>; |
| def ARMvrev16 : SDNode<"ARMISD::VREV16", SDTARMVSHUF>; |
| |
| def SDTARMVGETLN : SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisVec<1>, |
| SDTCisVT<2, i32>]>; |
| def ARMvgetlaneu : SDNode<"ARMISD::VGETLANEu", SDTARMVGETLN>; |
| def ARMvgetlanes : SDNode<"ARMISD::VGETLANEs", SDTARMVGETLN>; |
| |
| def SDTARMVMOVIMM : SDTypeProfile<1, 1, [SDTCisVec<0>, SDTCisVT<1, i32>]>; |
| def ARMvmovImm : SDNode<"ARMISD::VMOVIMM", SDTARMVMOVIMM>; |
| def ARMvmvnImm : SDNode<"ARMISD::VMVNIMM", SDTARMVMOVIMM>; |
| def ARMvmovFPImm : SDNode<"ARMISD::VMOVFPIMM", SDTARMVMOVIMM>; |
| |
| def SDTARMVORRIMM : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisSameAs<0, 1>, |
| SDTCisVT<2, i32>]>; |
| def ARMvorrImm : SDNode<"ARMISD::VORRIMM", SDTARMVORRIMM>; |
| def ARMvbicImm : SDNode<"ARMISD::VBICIMM", SDTARMVORRIMM>; |
| |
| def SDTARMVSHIMM : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>, |
| SDTCisVT<2, i32>]>; |
| def SDTARMVSH : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>, |
| SDTCisSameAs<0, 2>,]>; |
| def ARMvshlImm : SDNode<"ARMISD::VSHLIMM", SDTARMVSHIMM>; |
| def ARMvshrsImm : SDNode<"ARMISD::VSHRsIMM", SDTARMVSHIMM>; |
| def ARMvshruImm : SDNode<"ARMISD::VSHRuIMM", SDTARMVSHIMM>; |
| def ARMvshls : SDNode<"ARMISD::VSHLs", SDTARMVSH>; |
| def ARMvshlu : SDNode<"ARMISD::VSHLu", SDTARMVSH>; |
| |
| def SDTARMVMULL : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisInt<1>, |
| SDTCisSameAs<1, 2>]>; |
| def ARMvmulls : SDNode<"ARMISD::VMULLs", SDTARMVMULL>; |
| def ARMvmullu : SDNode<"ARMISD::VMULLu", SDTARMVMULL>; |
| |
| def SDTARMVCMP : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<1, 2>, |
| SDTCisInt<3>]>; |
| def SDTARMVCMPZ : SDTypeProfile<1, 2, [SDTCisInt<2>]>; |
| |
| def ARMvcmp : SDNode<"ARMISD::VCMP", SDTARMVCMP>; |
| def ARMvcmpz : SDNode<"ARMISD::VCMPZ", SDTARMVCMPZ>; |
| |
| // 'VECTOR_REG_CAST' is an operation that reinterprets the contents of a |
| // vector register as a different vector type, without changing the contents of |
| // the register. It differs from 'bitconvert' in that bitconvert reinterprets |
| // the _memory_ storage format of the vector, whereas VECTOR_REG_CAST |
| // reinterprets the _register_ format - and in big-endian, the memory and |
| // register formats are different, so they are different operations. |
| // |
| // For example, 'VECTOR_REG_CAST' between v8i16 and v16i8 will map the LSB of |
| // the zeroth i16 lane to the zeroth i8 lane, regardless of system endianness, |
| // whereas 'bitconvert' will map it to the high byte in big-endian mode, |
| // because that's what (MVE) VSTRH.16 followed by VLDRB.8 would do. So the |
| // bitconvert would have to emit a VREV16.8 instruction, whereas the |
| // VECTOR_REG_CAST emits no code at all if the vector is already in a register. |
| def ARMVectorRegCastImpl : SDNode<"ARMISD::VECTOR_REG_CAST", SDTUnaryOp>; |
| |
| // In little-endian, VECTOR_REG_CAST is often turned into bitconvert during |
| // lowering (because in that situation they're identical). So an isel pattern |
| // that needs to match something that's _logically_ a VECTOR_REG_CAST must |
| // _physically_ match a different node type depending on endianness. |
| // |
| // This 'PatFrags' instance is a centralized facility to make that easy. It |
| // matches VECTOR_REG_CAST in either endianness, and also bitconvert in the |
| // endianness where it's equivalent. |
| def ARMVectorRegCast: PatFrags< |
| (ops node:$x), [(ARMVectorRegCastImpl node:$x), (bitconvert node:$x)], [{ |
| // Reject a match against bitconvert (aka ISD::BITCAST) if big-endian |
| return !(CurDAG->getDataLayout().isBigEndian() && |
| N->getOpcode() == ISD::BITCAST); |
| }]>; |
| |
| //===----------------------------------------------------------------------===// |
| // ARM Flag Definitions. |
| |
| class RegConstraint<string C> { |
| string Constraints = C; |
| } |
| |
| // ARMCC condition codes. See ARMCC::CondCodes |
| def ARMCCeq : PatLeaf<(i32 0)>; |
| def ARMCCne : PatLeaf<(i32 1)>; |
| def ARMCChs : PatLeaf<(i32 2)>; |
| def ARMCClo : PatLeaf<(i32 3)>; |
| def ARMCCmi : PatLeaf<(i32 4)>; |
| def ARMCCpl : PatLeaf<(i32 5)>; |
| def ARMCCvs : PatLeaf<(i32 6)>; |
| def ARMCCvc : PatLeaf<(i32 7)>; |
| def ARMCChi : PatLeaf<(i32 8)>; |
| def ARMCCls : PatLeaf<(i32 9)>; |
| def ARMCCge : PatLeaf<(i32 10)>; |
| def ARMCClt : PatLeaf<(i32 11)>; |
| def ARMCCgt : PatLeaf<(i32 12)>; |
| def ARMCCle : PatLeaf<(i32 13)>; |
| def ARMCCal : PatLeaf<(i32 14)>; |
| |
| // VCC predicates. See ARMVCC::VPTCodes |
| def ARMVCCNone : PatLeaf<(i32 0)>; |
| def ARMVCCThen : PatLeaf<(i32 1)>; |
| def ARMVCCElse : PatLeaf<(i32 2)>; |
| |
| //===----------------------------------------------------------------------===// |
| // ARM specific transformation functions and pattern fragments. |
| // |
| |
| // imm_neg_XFORM - Return the negation of an i32 immediate value. |
| def imm_neg_XFORM : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant(-(int)N->getZExtValue(), SDLoc(N), MVT::i32); |
| }]>; |
| |
| // imm_not_XFORM - Return the complement of a i32 immediate value. |
| def imm_not_XFORM : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant(~(int)N->getZExtValue(), SDLoc(N), MVT::i32); |
| }]>; |
| |
| // asr_imm_XFORM - Returns a shift immediate with bit {5} set to 1 |
| def asr_imm_XFORM : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant(0x20 | N->getZExtValue(), SDLoc(N), MVT:: i32); |
| }]>; |
| |
| /// imm16_31 predicate - True if the 32-bit immediate is in the range [16,31]. |
| def imm16_31 : ImmLeaf<i32, [{ |
| return (int32_t)Imm >= 16 && (int32_t)Imm < 32; |
| }]>; |
| |
| // sext_16_node predicate - True if the SDNode is sign-extended 16 or more bits. |
| def sext_16_node : PatLeaf<(i32 GPR:$a), [{ |
| return CurDAG->ComputeNumSignBits(SDValue(N,0)) >= 17; |
| }]>; |
| |
| def sext_bottom_16 : PatFrag<(ops node:$a), |
| (sext_inreg node:$a, i16)>; |
| def sext_top_16 : PatFrag<(ops node:$a), |
| (i32 (sra node:$a, (i32 16)))>; |
| |
| def bb_mul : PatFrag<(ops node:$a, node:$b), |
| (mul (sext_bottom_16 node:$a), (sext_bottom_16 node:$b))>; |
| def bt_mul : PatFrag<(ops node:$a, node:$b), |
| (mul (sext_bottom_16 node:$a), (sra node:$b, (i32 16)))>; |
| def tb_mul : PatFrag<(ops node:$a, node:$b), |
| (mul (sra node:$a, (i32 16)), (sext_bottom_16 node:$b))>; |
| def tt_mul : PatFrag<(ops node:$a, node:$b), |
| (mul (sra node:$a, (i32 16)), (sra node:$b, (i32 16)))>; |
| |
| /// Split a 32-bit immediate into two 16 bit parts. |
| def hi16 : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() >> 16, SDLoc(N), |
| MVT::i32); |
| }]>; |
| |
| def lo16AllZero : PatLeaf<(i32 imm), [{ |
| // Returns true if all low 16-bits are 0. |
| return (((uint32_t)N->getZExtValue()) & 0xFFFFUL) == 0; |
| }], hi16>; |
| |
| // top16Zero - answer true if the upper 16 bits of $src are 0, false otherwise |
| def top16Zero: PatLeaf<(i32 GPR:$src), [{ |
| return !SDValue(N,0)->getValueType(0).isVector() && |
| CurDAG->MaskedValueIsZero(SDValue(N,0), APInt::getHighBitsSet(32, 16)); |
| }]>; |
| |
| class BinOpFrag<dag res> : PatFrag<(ops node:$LHS, node:$RHS), res>; |
| class UnOpFrag <dag res> : PatFrag<(ops node:$Src), res>; |
| |
| // An 'and' node with a single use. |
| def and_su : PatFrag<(ops node:$lhs, node:$rhs), (and node:$lhs, node:$rhs), [{ |
| return N->hasOneUse(); |
| }]>; |
| |
| // An 'xor' node with a single use. |
| def xor_su : PatFrag<(ops node:$lhs, node:$rhs), (xor node:$lhs, node:$rhs), [{ |
| return N->hasOneUse(); |
| }]>; |
| |
| // An 'fmul' node with a single use. |
| def fmul_su : PatFrag<(ops node:$lhs, node:$rhs), (fmul node:$lhs, node:$rhs),[{ |
| return N->hasOneUse(); |
| }]>; |
| |
| // An 'fadd' node which checks for single non-hazardous use. |
| def fadd_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fadd node:$lhs, node:$rhs),[{ |
| return hasNoVMLxHazardUse(N); |
| }]>; |
| |
| // An 'fsub' node which checks for single non-hazardous use. |
| def fsub_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fsub node:$lhs, node:$rhs),[{ |
| return hasNoVMLxHazardUse(N); |
| }]>; |
| |
| def imm_even : ImmLeaf<i32, [{ return (Imm & 1) == 0; }]>; |
| def imm_odd : ImmLeaf<i32, [{ return (Imm & 1) == 1; }]>; |
| |
| def asr_imm : ImmLeaf<i32, [{ return Imm > 0 && Imm <= 32; }], asr_imm_XFORM>; |
| |
| //===----------------------------------------------------------------------===// |
| // NEON/MVE pattern fragments |
| // |
| |
| // Extract D sub-registers of Q registers. |
| def DSubReg_i8_reg : SDNodeXForm<imm, [{ |
| assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); |
| return CurDAG->getTargetConstant(ARM::dsub_0 + N->getZExtValue()/8, SDLoc(N), |
| MVT::i32); |
| }]>; |
| def DSubReg_i16_reg : SDNodeXForm<imm, [{ |
| assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); |
| return CurDAG->getTargetConstant(ARM::dsub_0 + N->getZExtValue()/4, SDLoc(N), |
| MVT::i32); |
| }]>; |
| def DSubReg_i32_reg : SDNodeXForm<imm, [{ |
| assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); |
| return CurDAG->getTargetConstant(ARM::dsub_0 + N->getZExtValue()/2, SDLoc(N), |
| MVT::i32); |
| }]>; |
| def DSubReg_f64_reg : SDNodeXForm<imm, [{ |
| assert(ARM::dsub_7 == ARM::dsub_0+7 && "Unexpected subreg numbering"); |
| return CurDAG->getTargetConstant(ARM::dsub_0 + N->getZExtValue(), SDLoc(N), |
| MVT::i32); |
| }]>; |
| |
| // Extract S sub-registers of Q/D registers. |
| def SSubReg_f32_reg : SDNodeXForm<imm, [{ |
| assert(ARM::ssub_3 == ARM::ssub_0+3 && "Unexpected subreg numbering"); |
| return CurDAG->getTargetConstant(ARM::ssub_0 + N->getZExtValue(), SDLoc(N), |
| MVT::i32); |
| }]>; |
| |
| // Extract S sub-registers of Q/D registers containing a given f16/bf16 lane. |
| def SSubReg_f16_reg : SDNodeXForm<imm, [{ |
| assert(ARM::ssub_3 == ARM::ssub_0+3 && "Unexpected subreg numbering"); |
| return CurDAG->getTargetConstant(ARM::ssub_0 + N->getZExtValue()/2, SDLoc(N), |
| MVT::i32); |
| }]>; |
| |
| // Translate lane numbers from Q registers to D subregs. |
| def SubReg_i8_lane : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant(N->getZExtValue() & 7, SDLoc(N), MVT::i32); |
| }]>; |
| def SubReg_i16_lane : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant(N->getZExtValue() & 3, SDLoc(N), MVT::i32); |
| }]>; |
| def SubReg_i32_lane : SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant(N->getZExtValue() & 1, SDLoc(N), MVT::i32); |
| }]>; |
| |
| |
| def ARMimmAllZerosV: PatLeaf<(bitconvert (v4i32 (ARMvmovImm (i32 0))))>; |
| def ARMimmAllZerosD: PatLeaf<(bitconvert (v2i32 (ARMvmovImm (i32 0))))>; |
| def ARMimmAllOnesV: PatLeaf<(bitconvert (v16i8 (ARMvmovImm (i32 0xEFF))))>; |
| def ARMimmAllOnesD: PatLeaf<(bitconvert (v8i8 (ARMvmovImm (i32 0xEFF))))>; |
| |
| def ARMimmOneV: PatLeaf<(ARMvmovImm (i32 timm)), [{ |
| ConstantSDNode *ConstVal = cast<ConstantSDNode>(N->getOperand(0)); |
| unsigned EltBits = 0; |
| uint64_t EltVal = ARM_AM::decodeVMOVModImm(ConstVal->getZExtValue(), EltBits); |
| return (EltBits == N->getValueType(0).getScalarSizeInBits() && EltVal == 0x01); |
| }]>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Operand Definitions. |
| // |
| |
| // Immediate operands with a shared generic asm render method. |
| class ImmAsmOperand<int Low, int High> : AsmOperandClass { |
| let RenderMethod = "addImmOperands"; |
| let PredicateMethod = "isImmediate<" # Low # "," # High # ">"; |
| let DiagnosticString = "operand must be an immediate in the range [" # Low # "," # High # "]"; |
| } |
| |
| class ImmAsmOperandMinusOne<int Low, int High> : AsmOperandClass { |
| let PredicateMethod = "isImmediate<" # Low # "," # High # ">"; |
| let DiagnosticType = "ImmRange" # Low # "_" # High; |
| let DiagnosticString = "operand must be an immediate in the range [" # Low # "," # High # "]"; |
| } |
| |
| // Operands that are part of a memory addressing mode. |
| class MemOperand : Operand<i32> { let OperandType = "OPERAND_MEMORY"; } |
| |
| // Branch target. |
| // FIXME: rename brtarget to t2_brtarget |
| def brtarget : Operand<OtherVT> { |
| let EncoderMethod = "getBranchTargetOpValue"; |
| let OperandType = "OPERAND_PCREL"; |
| let DecoderMethod = "DecodeT2BROperand"; |
| } |
| |
| // Branches targeting ARM-mode must be divisible by 4 if they're a raw |
| // immediate. |
| def ARMBranchTarget : AsmOperandClass { |
| let Name = "ARMBranchTarget"; |
| } |
| |
| // Branches targeting Thumb-mode must be divisible by 2 if they're a raw |
| // immediate. |
| def ThumbBranchTarget : AsmOperandClass { |
| let Name = "ThumbBranchTarget"; |
| } |
| |
| def arm_br_target : Operand<OtherVT> { |
| let ParserMatchClass = ARMBranchTarget; |
| let EncoderMethod = "getARMBranchTargetOpValue"; |
| let OperandType = "OPERAND_PCREL"; |
| } |
| |
| // Call target for ARM. Handles conditional/unconditional |
| // FIXME: rename bl_target to t2_bltarget? |
| def arm_bl_target : Operand<i32> { |
| let ParserMatchClass = ARMBranchTarget; |
| let EncoderMethod = "getARMBLTargetOpValue"; |
| let OperandType = "OPERAND_PCREL"; |
| } |
| |
| // Target for BLX *from* ARM mode. |
| def arm_blx_target : Operand<i32> { |
| let ParserMatchClass = ThumbBranchTarget; |
| let EncoderMethod = "getARMBLXTargetOpValue"; |
| let OperandType = "OPERAND_PCREL"; |
| } |
| |
| // A list of registers separated by comma. Used by load/store multiple. |
| def RegListAsmOperand : AsmOperandClass { let Name = "RegList"; } |
| def reglist : Operand<i32> { |
| let EncoderMethod = "getRegisterListOpValue"; |
| let ParserMatchClass = RegListAsmOperand; |
| let PrintMethod = "printRegisterList"; |
| let DecoderMethod = "DecodeRegListOperand"; |
| } |
| |
| // A list of general purpose registers and APSR separated by comma. |
| // Used by CLRM |
| def RegListWithAPSRAsmOperand : AsmOperandClass { let Name = "RegListWithAPSR"; } |
| def reglist_with_apsr : Operand<i32> { |
| let EncoderMethod = "getRegisterListOpValue"; |
| let ParserMatchClass = RegListWithAPSRAsmOperand; |
| let PrintMethod = "printRegisterList"; |
| let DecoderMethod = "DecodeRegListOperand"; |
| } |
| |
| def GPRPairOp : RegisterOperand<GPRPair, "printGPRPairOperand">; |
| |
| def DPRRegListAsmOperand : AsmOperandClass { |
| let Name = "DPRRegList"; |
| let DiagnosticType = "DPR_RegList"; |
| } |
| def dpr_reglist : Operand<i32> { |
| let EncoderMethod = "getRegisterListOpValue"; |
| let ParserMatchClass = DPRRegListAsmOperand; |
| let PrintMethod = "printRegisterList"; |
| let DecoderMethod = "DecodeDPRRegListOperand"; |
| } |
| |
| def SPRRegListAsmOperand : AsmOperandClass { |
| let Name = "SPRRegList"; |
| let DiagnosticString = "operand must be a list of registers in range [s0, s31]"; |
| } |
| def spr_reglist : Operand<i32> { |
| let EncoderMethod = "getRegisterListOpValue"; |
| let ParserMatchClass = SPRRegListAsmOperand; |
| let PrintMethod = "printRegisterList"; |
| let DecoderMethod = "DecodeSPRRegListOperand"; |
| } |
| |
| def FPSRegListWithVPRAsmOperand : AsmOperandClass { let Name = |
| "FPSRegListWithVPR"; } |
| def fp_sreglist_with_vpr : Operand<i32> { |
| let EncoderMethod = "getRegisterListOpValue"; |
| let ParserMatchClass = FPSRegListWithVPRAsmOperand; |
| let PrintMethod = "printRegisterList"; |
| } |
| def FPDRegListWithVPRAsmOperand : AsmOperandClass { let Name = |
| "FPDRegListWithVPR"; } |
| def fp_dreglist_with_vpr : Operand<i32> { |
| let EncoderMethod = "getRegisterListOpValue"; |
| let ParserMatchClass = FPDRegListWithVPRAsmOperand; |
| let PrintMethod = "printRegisterList"; |
| } |
| |
| // An operand for the CONSTPOOL_ENTRY pseudo-instruction. |
| def cpinst_operand : Operand<i32> { |
| let PrintMethod = "printCPInstOperand"; |
| } |
| |
| // Local PC labels. |
| def pclabel : Operand<i32> { |
| let PrintMethod = "printPCLabel"; |
| } |
| |
| // ADR instruction labels. |
| def AdrLabelAsmOperand : AsmOperandClass { let Name = "AdrLabel"; } |
| def adrlabel : Operand<i32> { |
| let EncoderMethod = "getAdrLabelOpValue"; |
| let ParserMatchClass = AdrLabelAsmOperand; |
| let PrintMethod = "printAdrLabelOperand<0>"; |
| } |
| |
| def neon_vcvt_imm32 : Operand<i32> { |
| let EncoderMethod = "getNEONVcvtImm32OpValue"; |
| let DecoderMethod = "DecodeVCVTImmOperand"; |
| } |
| |
| // rot_imm: An integer that encodes a rotate amount. Must be 8, 16, or 24. |
| def rot_imm_XFORM: SDNodeXForm<imm, [{ |
| switch (N->getZExtValue()){ |
| default: llvm_unreachable(nullptr); |
| case 0: return CurDAG->getTargetConstant(0, SDLoc(N), MVT::i32); |
| case 8: return CurDAG->getTargetConstant(1, SDLoc(N), MVT::i32); |
| case 16: return CurDAG->getTargetConstant(2, SDLoc(N), MVT::i32); |
| case 24: return CurDAG->getTargetConstant(3, SDLoc(N), MVT::i32); |
| } |
| }]>; |
| def RotImmAsmOperand : AsmOperandClass { |
| let Name = "RotImm"; |
| let ParserMethod = "parseRotImm"; |
| } |
| def rot_imm : Operand<i32>, PatLeaf<(i32 imm), [{ |
| int32_t v = N->getZExtValue(); |
| return v == 8 || v == 16 || v == 24; }], |
| rot_imm_XFORM> { |
| let PrintMethod = "printRotImmOperand"; |
| let ParserMatchClass = RotImmAsmOperand; |
| } |
| |
| // Power-of-two operand for MVE VIDUP and friends, which encode |
| // {1,2,4,8} as its log to base 2, i.e. as {0,1,2,3} respectively |
| def MVE_VIDUP_imm_asmoperand : AsmOperandClass { |
| let Name = "VIDUP_imm"; |
| let PredicateMethod = "isPowerTwoInRange<1,8>"; |
| let RenderMethod = "addPowerTwoOperands"; |
| let DiagnosticString = "vector increment immediate must be 1, 2, 4 or 8"; |
| } |
| def MVE_VIDUP_imm : Operand<i32> { |
| let EncoderMethod = "getPowerTwoOpValue"; |
| let DecoderMethod = "DecodePowerTwoOperand<0,3>"; |
| let ParserMatchClass = MVE_VIDUP_imm_asmoperand; |
| } |
| |
| // Pair vector indexing |
| class MVEPairVectorIndexOperand<string start, string end> : AsmOperandClass { |
| let Name = "MVEPairVectorIndex"#start; |
| let RenderMethod = "addMVEPairVectorIndexOperands"; |
| let PredicateMethod = "isMVEPairVectorIndex<"#start#", "#end#">"; |
| } |
| |
| class MVEPairVectorIndex<string opval> : Operand<i32> { |
| let PrintMethod = "printVectorIndex"; |
| let EncoderMethod = "getMVEPairVectorIndexOpValue<"#opval#">"; |
| let DecoderMethod = "DecodeMVEPairVectorIndexOperand<"#opval#">"; |
| let MIOperandInfo = (ops i32imm); |
| } |
| |
| def MVEPairVectorIndex0 : MVEPairVectorIndex<"0"> { |
| let ParserMatchClass = MVEPairVectorIndexOperand<"0", "1">; |
| } |
| |
| def MVEPairVectorIndex2 : MVEPairVectorIndex<"2"> { |
| let ParserMatchClass = MVEPairVectorIndexOperand<"2", "3">; |
| } |
| |
| // Vector indexing |
| class MVEVectorIndexOperand<int NumLanes> : AsmOperandClass { |
| let Name = "MVEVectorIndex"#NumLanes; |
| let RenderMethod = "addMVEVectorIndexOperands"; |
| let PredicateMethod = "isVectorIndexInRange<"#NumLanes#">"; |
| } |
| |
| class MVEVectorIndex<int NumLanes> : Operand<i32> { |
| let PrintMethod = "printVectorIndex"; |
| let ParserMatchClass = MVEVectorIndexOperand<NumLanes>; |
| let MIOperandInfo = (ops i32imm); |
| } |
| |
| // shift_imm: An integer that encodes a shift amount and the type of shift |
| // (asr or lsl). The 6-bit immediate encodes as: |
| // {5} 0 ==> lsl |
| // 1 asr |
| // {4-0} imm5 shift amount. |
| // asr #32 encoded as imm5 == 0. |
| def ShifterImmAsmOperand : AsmOperandClass { |
| let Name = "ShifterImm"; |
| let ParserMethod = "parseShifterImm"; |
| } |
| def shift_imm : Operand<i32> { |
| let PrintMethod = "printShiftImmOperand"; |
| let ParserMatchClass = ShifterImmAsmOperand; |
| } |
| |
| // shifter_operand operands: so_reg_reg, so_reg_imm, and mod_imm. |
| def ShiftedRegAsmOperand : AsmOperandClass { let Name = "RegShiftedReg"; } |
| def so_reg_reg : Operand<i32>, // reg reg imm |
| ComplexPattern<i32, 3, "SelectRegShifterOperand", |
| [shl, srl, sra, rotr]> { |
| let EncoderMethod = "getSORegRegOpValue"; |
| let PrintMethod = "printSORegRegOperand"; |
| let DecoderMethod = "DecodeSORegRegOperand"; |
| let ParserMatchClass = ShiftedRegAsmOperand; |
| let MIOperandInfo = (ops GPRnopc, GPRnopc, i32imm); |
| } |
| |
| def ShiftedImmAsmOperand : AsmOperandClass { let Name = "RegShiftedImm"; } |
| def so_reg_imm : Operand<i32>, // reg imm |
| ComplexPattern<i32, 2, "SelectImmShifterOperand", |
| [shl, srl, sra, rotr]> { |
| let EncoderMethod = "getSORegImmOpValue"; |
| let PrintMethod = "printSORegImmOperand"; |
| let DecoderMethod = "DecodeSORegImmOperand"; |
| let ParserMatchClass = ShiftedImmAsmOperand; |
| let MIOperandInfo = (ops GPR, i32imm); |
| } |
| |
| // FIXME: Does this need to be distinct from so_reg? |
| def shift_so_reg_reg : Operand<i32>, // reg reg imm |
| ComplexPattern<i32, 3, "SelectShiftRegShifterOperand", |
| [shl,srl,sra,rotr]> { |
| let EncoderMethod = "getSORegRegOpValue"; |
| let PrintMethod = "printSORegRegOperand"; |
| let DecoderMethod = "DecodeSORegRegOperand"; |
| let ParserMatchClass = ShiftedRegAsmOperand; |
| let MIOperandInfo = (ops GPR, GPR, i32imm); |
| } |
| |
| // FIXME: Does this need to be distinct from so_reg? |
| def shift_so_reg_imm : Operand<i32>, // reg reg imm |
| ComplexPattern<i32, 2, "SelectShiftImmShifterOperand", |
| [shl,srl,sra,rotr]> { |
| let EncoderMethod = "getSORegImmOpValue"; |
| let PrintMethod = "printSORegImmOperand"; |
| let DecoderMethod = "DecodeSORegImmOperand"; |
| let ParserMatchClass = ShiftedImmAsmOperand; |
| let MIOperandInfo = (ops GPR, i32imm); |
| } |
| |
| // mod_imm: match a 32-bit immediate operand, which can be encoded into |
| // a 12-bit immediate; an 8-bit integer and a 4-bit rotator (See ARMARM |
| // - "Modified Immediate Constants"). Within the MC layer we keep this |
| // immediate in its encoded form. |
| def ModImmAsmOperand: AsmOperandClass { |
| let Name = "ModImm"; |
| let ParserMethod = "parseModImm"; |
| } |
| def mod_imm : Operand<i32>, ImmLeaf<i32, [{ |
| return ARM_AM::getSOImmVal(Imm) != -1; |
| }]> { |
| let EncoderMethod = "getModImmOpValue"; |
| let PrintMethod = "printModImmOperand"; |
| let ParserMatchClass = ModImmAsmOperand; |
| } |
| |
| // Note: the patterns mod_imm_not and mod_imm_neg do not require an encoder |
| // method and such, as they are only used on aliases (Pat<> and InstAlias<>). |
| // The actual parsing, encoding, decoding are handled by the destination |
| // instructions, which use mod_imm. |
| |
| def ModImmNotAsmOperand : AsmOperandClass { let Name = "ModImmNot"; } |
| def mod_imm_not : Operand<i32>, PatLeaf<(imm), [{ |
| return ARM_AM::getSOImmVal(~(uint32_t)N->getZExtValue()) != -1; |
| }], imm_not_XFORM> { |
| let ParserMatchClass = ModImmNotAsmOperand; |
| } |
| |
| def ModImmNegAsmOperand : AsmOperandClass { let Name = "ModImmNeg"; } |
| def mod_imm_neg : Operand<i32>, PatLeaf<(imm), [{ |
| unsigned Value = -(unsigned)N->getZExtValue(); |
| return Value && ARM_AM::getSOImmVal(Value) != -1; |
| }], imm_neg_XFORM> { |
| let ParserMatchClass = ModImmNegAsmOperand; |
| } |
| |
| /// arm_i32imm - True for +V6T2, or when isSOImmTwoParVal() |
| def arm_i32imm : IntImmLeaf<i32, [{ |
| if (Subtarget->useMovt()) |
| return true; |
| if (ARM_AM::isSOImmTwoPartVal(Imm.getZExtValue())) |
| return true; |
| return ARM_AM::isSOImmTwoPartValNeg(Imm.getZExtValue()); |
| }]>; |
| |
| /// imm0_1 predicate - Immediate in the range [0,1]. |
| def Imm0_1AsmOperand: ImmAsmOperand<0,1> { let Name = "Imm0_1"; } |
| def imm0_1 : Operand<i32> { let ParserMatchClass = Imm0_1AsmOperand; } |
| |
| /// imm0_3 predicate - Immediate in the range [0,3]. |
| def Imm0_3AsmOperand: ImmAsmOperand<0,3> { let Name = "Imm0_3"; } |
| def imm0_3 : Operand<i32> { let ParserMatchClass = Imm0_3AsmOperand; } |
| |
| /// imm0_7 predicate - Immediate in the range [0,7]. |
| def Imm0_7AsmOperand: ImmAsmOperand<0,7> { |
| let Name = "Imm0_7"; |
| } |
| def imm0_7 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 0 && Imm < 8; |
| }]> { |
| let ParserMatchClass = Imm0_7AsmOperand; |
| } |
| |
| /// imm8_255 predicate - Immediate in the range [8,255]. |
| def Imm8_255AsmOperand: ImmAsmOperand<8,255> { let Name = "Imm8_255"; } |
| def imm8_255 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 8 && Imm < 256; |
| }]> { |
| let ParserMatchClass = Imm8_255AsmOperand; |
| } |
| |
| /// imm8 predicate - Immediate is exactly 8. |
| def Imm8AsmOperand: ImmAsmOperand<8,8> { let Name = "Imm8"; } |
| def imm8 : Operand<i32>, ImmLeaf<i32, [{ return Imm == 8; }]> { |
| let ParserMatchClass = Imm8AsmOperand; |
| } |
| |
| /// imm16 predicate - Immediate is exactly 16. |
| def Imm16AsmOperand: ImmAsmOperand<16,16> { let Name = "Imm16"; } |
| def imm16 : Operand<i32>, ImmLeaf<i32, [{ return Imm == 16; }]> { |
| let ParserMatchClass = Imm16AsmOperand; |
| } |
| |
| /// imm32 predicate - Immediate is exactly 32. |
| def Imm32AsmOperand: ImmAsmOperand<32,32> { let Name = "Imm32"; } |
| def imm32 : Operand<i32>, ImmLeaf<i32, [{ return Imm == 32; }]> { |
| let ParserMatchClass = Imm32AsmOperand; |
| } |
| |
| def imm8_or_16 : ImmLeaf<i32, [{ return Imm == 8 || Imm == 16;}]>; |
| |
| /// imm1_7 predicate - Immediate in the range [1,7]. |
| def Imm1_7AsmOperand: ImmAsmOperand<1,7> { let Name = "Imm1_7"; } |
| def imm1_7 : Operand<i32>, ImmLeaf<i32, [{ return Imm > 0 && Imm < 8; }]> { |
| let ParserMatchClass = Imm1_7AsmOperand; |
| } |
| |
| /// imm1_15 predicate - Immediate in the range [1,15]. |
| def Imm1_15AsmOperand: ImmAsmOperand<1,15> { let Name = "Imm1_15"; } |
| def imm1_15 : Operand<i32>, ImmLeaf<i32, [{ return Imm > 0 && Imm < 16; }]> { |
| let ParserMatchClass = Imm1_15AsmOperand; |
| } |
| |
| /// imm1_31 predicate - Immediate in the range [1,31]. |
| def Imm1_31AsmOperand: ImmAsmOperand<1,31> { let Name = "Imm1_31"; } |
| def imm1_31 : Operand<i32>, ImmLeaf<i32, [{ return Imm > 0 && Imm < 32; }]> { |
| let ParserMatchClass = Imm1_31AsmOperand; |
| } |
| |
| /// imm0_15 predicate - Immediate in the range [0,15]. |
| def Imm0_15AsmOperand: ImmAsmOperand<0,15> { |
| let Name = "Imm0_15"; |
| } |
| def imm0_15 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 0 && Imm < 16; |
| }]> { |
| let ParserMatchClass = Imm0_15AsmOperand; |
| } |
| |
| /// imm0_31 predicate - True if the 32-bit immediate is in the range [0,31]. |
| def Imm0_31AsmOperand: ImmAsmOperand<0,31> { let Name = "Imm0_31"; } |
| def imm0_31 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 0 && Imm < 32; |
| }]> { |
| let ParserMatchClass = Imm0_31AsmOperand; |
| } |
| |
| /// imm0_32 predicate - True if the 32-bit immediate is in the range [0,32]. |
| def Imm0_32AsmOperand: ImmAsmOperand<0,32> { let Name = "Imm0_32"; } |
| def imm0_32 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 0 && Imm < 33; |
| }]> { |
| let ParserMatchClass = Imm0_32AsmOperand; |
| } |
| |
| /// imm0_63 predicate - True if the 32-bit immediate is in the range [0,63]. |
| def Imm0_63AsmOperand: ImmAsmOperand<0,63> { let Name = "Imm0_63"; } |
| def imm0_63 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 0 && Imm < 64; |
| }]> { |
| let ParserMatchClass = Imm0_63AsmOperand; |
| } |
| |
| /// imm0_239 predicate - Immediate in the range [0,239]. |
| def Imm0_239AsmOperand : ImmAsmOperand<0,239> { |
| let Name = "Imm0_239"; |
| } |
| def imm0_239 : Operand<i32>, ImmLeaf<i32, [{ return Imm >= 0 && Imm < 240; }]> { |
| let ParserMatchClass = Imm0_239AsmOperand; |
| } |
| |
| /// imm0_255 predicate - Immediate in the range [0,255]. |
| def Imm0_255AsmOperand : ImmAsmOperand<0,255> { let Name = "Imm0_255"; } |
| def imm0_255 : Operand<i32>, ImmLeaf<i32, [{ return Imm >= 0 && Imm < 256; }]> { |
| let ParserMatchClass = Imm0_255AsmOperand; |
| } |
| |
| /// imm0_65535 - An immediate is in the range [0,65535]. |
| def Imm0_65535AsmOperand: ImmAsmOperand<0,65535> { let Name = "Imm0_65535"; } |
| def imm0_65535 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 0 && Imm < 65536; |
| }]> { |
| let ParserMatchClass = Imm0_65535AsmOperand; |
| } |
| |
| // imm0_65535_neg - An immediate whose negative value is in the range [0.65535]. |
| def imm0_65535_neg : Operand<i32>, ImmLeaf<i32, [{ |
| return -Imm >= 0 && -Imm < 65536; |
| }]>; |
| |
| // imm0_65535_expr - For movt/movw - 16-bit immediate that can also reference |
| // a relocatable expression. |
| // |
| // FIXME: This really needs a Thumb version separate from the ARM version. |
| // While the range is the same, and can thus use the same match class, |
| // the encoding is different so it should have a different encoder method. |
| def Imm0_65535ExprAsmOperand: AsmOperandClass { |
| let Name = "Imm0_65535Expr"; |
| let RenderMethod = "addImmOperands"; |
| let DiagnosticString = "operand must be an immediate in the range [0,0xffff] or a relocatable expression"; |
| } |
| |
| def imm0_65535_expr : Operand<i32> { |
| let EncoderMethod = "getHiLo16ImmOpValue"; |
| let ParserMatchClass = Imm0_65535ExprAsmOperand; |
| } |
| |
| def Imm256_65535ExprAsmOperand: ImmAsmOperand<256,65535> { let Name = "Imm256_65535Expr"; } |
| def imm256_65535_expr : Operand<i32> { |
| let ParserMatchClass = Imm256_65535ExprAsmOperand; |
| } |
| |
| /// imm24b - True if the 32-bit immediate is encodable in 24 bits. |
| def Imm24bitAsmOperand: ImmAsmOperand<0,0xffffff> { |
| let Name = "Imm24bit"; |
| let DiagnosticString = "operand must be an immediate in the range [0,0xffffff]"; |
| } |
| def imm24b : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm >= 0 && Imm <= 0xffffff; |
| }]> { |
| let ParserMatchClass = Imm24bitAsmOperand; |
| } |
| |
| |
| /// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield |
| /// e.g., 0xf000ffff |
| def BitfieldAsmOperand : AsmOperandClass { |
| let Name = "Bitfield"; |
| let ParserMethod = "parseBitfield"; |
| } |
| |
| def bf_inv_mask_imm : Operand<i32>, |
| PatLeaf<(imm), [{ |
| return ARM::isBitFieldInvertedMask(N->getZExtValue()); |
| }] > { |
| let EncoderMethod = "getBitfieldInvertedMaskOpValue"; |
| let PrintMethod = "printBitfieldInvMaskImmOperand"; |
| let DecoderMethod = "DecodeBitfieldMaskOperand"; |
| let ParserMatchClass = BitfieldAsmOperand; |
| let GISelPredicateCode = [{ |
| // There's better methods of implementing this check. IntImmLeaf<> would be |
| // equivalent and have less boilerplate but we need a test for C++ |
| // predicates and this one causes new rules to be imported into GlobalISel |
| // without requiring additional features first. |
| const auto &MO = MI.getOperand(1); |
| if (!MO.isCImm()) |
| return false; |
| return ARM::isBitFieldInvertedMask(MO.getCImm()->getZExtValue()); |
| }]; |
| } |
| |
| def imm1_32_XFORM: SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant((int)N->getZExtValue() - 1, SDLoc(N), |
| MVT::i32); |
| }]>; |
| def Imm1_32AsmOperand: ImmAsmOperandMinusOne<1,32> { |
| let Name = "Imm1_32"; |
| } |
| def imm1_32 : Operand<i32>, PatLeaf<(imm), [{ |
| uint64_t Imm = N->getZExtValue(); |
| return Imm > 0 && Imm <= 32; |
| }], |
| imm1_32_XFORM> { |
| let PrintMethod = "printImmPlusOneOperand"; |
| let ParserMatchClass = Imm1_32AsmOperand; |
| } |
| |
| def imm1_16_XFORM: SDNodeXForm<imm, [{ |
| return CurDAG->getTargetConstant((int)N->getZExtValue() - 1, SDLoc(N), |
| MVT::i32); |
| }]>; |
| def Imm1_16AsmOperand: ImmAsmOperandMinusOne<1,16> { let Name = "Imm1_16"; } |
| def imm1_16 : Operand<i32>, ImmLeaf<i32, [{ |
| return Imm > 0 && Imm <= 16; |
| }], |
| imm1_16_XFORM> { |
| let PrintMethod = "printImmPlusOneOperand"; |
| let ParserMatchClass = Imm1_16AsmOperand; |
| } |
| |
| def MVEShiftImm1_7AsmOperand: ImmAsmOperand<1,7> { |
| let Name = "MVEShiftImm1_7"; |
| // Reason we're doing this is because instruction vshll.s8 t1 encoding |
| // accepts 1,7 but the t2 encoding accepts 8. By doing this we can get a |
| // better diagnostic message if someone uses bigger immediate than the t1/t2 |
| // encodings allow. |
| let DiagnosticString = "operand must be an immediate in the range [1,8]"; |
| } |
| def mve_shift_imm1_7 : Operand<i32>, |
| // SelectImmediateInRange / isScaledConstantInRange uses a |
| // half-open interval, so the parameters <1,8> mean 1-7 inclusive |
| ComplexPattern<i32, 1, "SelectImmediateInRange<1,8>", [], []> { |
| let ParserMatchClass = MVEShiftImm1_7AsmOperand; |
| let EncoderMethod = "getMVEShiftImmOpValue"; |
| } |
| |
| def MVEShiftImm1_15AsmOperand: ImmAsmOperand<1,15> { |
| let Name = "MVEShiftImm1_15"; |
| // Reason we're doing this is because instruction vshll.s16 t1 encoding |
| // accepts 1,15 but the t2 encoding accepts 16. By doing this we can get a |
| // better diagnostic message if someone uses bigger immediate than the t1/t2 |
| // encodings allow. |
| let DiagnosticString = "operand must be an immediate in the range [1,16]"; |
| } |
| def mve_shift_imm1_15 : Operand<i32>, |
| // SelectImmediateInRange / isScaledConstantInRange uses a |
| // half-open interval, so the parameters <1,16> mean 1-15 inclusive |
| ComplexPattern<i32, 1, "SelectImmediateInRange<1,16>", [], []> { |
| let ParserMatchClass = MVEShiftImm1_15AsmOperand; |
| let EncoderMethod = "getMVEShiftImmOpValue"; |
| } |
| |
| // Define ARM specific addressing modes. |
| // addrmode_imm12 := reg +/- imm12 |
| // |
| def MemImm12OffsetAsmOperand : AsmOperandClass { let Name = "MemImm12Offset"; } |
| class AddrMode_Imm12 : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrModeImm12", []> { |
| // 12-bit immediate operand. Note that instructions using this encode |
| // #0 and #-0 differently. We flag #-0 as the magic value INT32_MIN. All other |
| // immediate values are as normal. |
| |
| let EncoderMethod = "getAddrModeImm12OpValue"; |
| let DecoderMethod = "DecodeAddrModeImm12Operand"; |
| let ParserMatchClass = MemImm12OffsetAsmOperand; |
| let MIOperandInfo = (ops GPR:$base, i32imm:$offsimm); |
| } |
| |
| def addrmode_imm12 : AddrMode_Imm12 { |
| let PrintMethod = "printAddrModeImm12Operand<false>"; |
| } |
| |
| def addrmode_imm12_pre : AddrMode_Imm12 { |
| let PrintMethod = "printAddrModeImm12Operand<true>"; |
| } |
| |
| // ldst_so_reg := reg +/- reg shop imm |
| // |
| def MemRegOffsetAsmOperand : AsmOperandClass { let Name = "MemRegOffset"; } |
| def ldst_so_reg : MemOperand, |
| ComplexPattern<i32, 3, "SelectLdStSOReg", []> { |
| let EncoderMethod = "getLdStSORegOpValue"; |
| // FIXME: Simplify the printer |
| let PrintMethod = "printAddrMode2Operand"; |
| let DecoderMethod = "DecodeSORegMemOperand"; |
| let ParserMatchClass = MemRegOffsetAsmOperand; |
| let MIOperandInfo = (ops GPR:$base, GPRnopc:$offsreg, i32imm:$shift); |
| } |
| |
| // postidx_imm8 := +/- [0,255] |
| // |
| // 9 bit value: |
| // {8} 1 is imm8 is non-negative. 0 otherwise. |
| // {7-0} [0,255] imm8 value. |
| def PostIdxImm8AsmOperand : AsmOperandClass { let Name = "PostIdxImm8"; } |
| def postidx_imm8 : MemOperand { |
| let PrintMethod = "printPostIdxImm8Operand"; |
| let ParserMatchClass = PostIdxImm8AsmOperand; |
| let MIOperandInfo = (ops i32imm); |
| } |
| |
| // postidx_imm8s4 := +/- [0,1020] |
| // |
| // 9 bit value: |
| // {8} 1 is imm8 is non-negative. 0 otherwise. |
| // {7-0} [0,255] imm8 value, scaled by 4. |
| def PostIdxImm8s4AsmOperand : AsmOperandClass { let Name = "PostIdxImm8s4"; } |
| def postidx_imm8s4 : MemOperand { |
| let PrintMethod = "printPostIdxImm8s4Operand"; |
| let ParserMatchClass = PostIdxImm8s4AsmOperand; |
| let MIOperandInfo = (ops i32imm); |
| } |
| |
| |
| // postidx_reg := +/- reg |
| // |
| def PostIdxRegAsmOperand : AsmOperandClass { |
| let Name = "PostIdxReg"; |
| let ParserMethod = "parsePostIdxReg"; |
| } |
| def postidx_reg : MemOperand { |
| let EncoderMethod = "getPostIdxRegOpValue"; |
| let DecoderMethod = "DecodePostIdxReg"; |
| let PrintMethod = "printPostIdxRegOperand"; |
| let ParserMatchClass = PostIdxRegAsmOperand; |
| let MIOperandInfo = (ops GPRnopc, i32imm); |
| } |
| |
| def PostIdxRegShiftedAsmOperand : AsmOperandClass { |
| let Name = "PostIdxRegShifted"; |
| let ParserMethod = "parsePostIdxReg"; |
| } |
| def am2offset_reg : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode2OffsetReg", |
| [], [SDNPWantRoot]> { |
| let EncoderMethod = "getAddrMode2OffsetOpValue"; |
| let PrintMethod = "printAddrMode2OffsetOperand"; |
| // When using this for assembly, it's always as a post-index offset. |
| let ParserMatchClass = PostIdxRegShiftedAsmOperand; |
| let MIOperandInfo = (ops GPRnopc, i32imm); |
| } |
| |
| // FIXME: am2offset_imm should only need the immediate, not the GPR. Having |
| // the GPR is purely vestigal at this point. |
| def AM2OffsetImmAsmOperand : AsmOperandClass { let Name = "AM2OffsetImm"; } |
| def am2offset_imm : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode2OffsetImm", |
| [], [SDNPWantRoot]> { |
| let EncoderMethod = "getAddrMode2OffsetOpValue"; |
| let PrintMethod = "printAddrMode2OffsetOperand"; |
| let ParserMatchClass = AM2OffsetImmAsmOperand; |
| let MIOperandInfo = (ops GPRnopc, i32imm); |
| } |
| |
| |
| // addrmode3 := reg +/- reg |
| // addrmode3 := reg +/- imm8 |
| // |
| // FIXME: split into imm vs. reg versions. |
| def AddrMode3AsmOperand : AsmOperandClass { let Name = "AddrMode3"; } |
| class AddrMode3 : MemOperand, |
| ComplexPattern<i32, 3, "SelectAddrMode3", []> { |
| let EncoderMethod = "getAddrMode3OpValue"; |
| let ParserMatchClass = AddrMode3AsmOperand; |
| let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm); |
| } |
| |
| def addrmode3 : AddrMode3 |
| { |
| let PrintMethod = "printAddrMode3Operand<false>"; |
| } |
| |
| def addrmode3_pre : AddrMode3 |
| { |
| let PrintMethod = "printAddrMode3Operand<true>"; |
| } |
| |
| // FIXME: split into imm vs. reg versions. |
| // FIXME: parser method to handle +/- register. |
| def AM3OffsetAsmOperand : AsmOperandClass { |
| let Name = "AM3Offset"; |
| let ParserMethod = "parseAM3Offset"; |
| } |
| def am3offset : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode3Offset", |
| [], [SDNPWantRoot]> { |
| let EncoderMethod = "getAddrMode3OffsetOpValue"; |
| let PrintMethod = "printAddrMode3OffsetOperand"; |
| let ParserMatchClass = AM3OffsetAsmOperand; |
| let MIOperandInfo = (ops GPR, i32imm); |
| } |
| |
| // ldstm_mode := {ia, ib, da, db} |
| // |
| def ldstm_mode : OptionalDefOperand<OtherVT, (ops i32), (ops (i32 1))> { |
| let EncoderMethod = "getLdStmModeOpValue"; |
| let PrintMethod = "printLdStmModeOperand"; |
| } |
| |
| // addrmode5 := reg +/- imm8*4 |
| // |
| def AddrMode5AsmOperand : AsmOperandClass { let Name = "AddrMode5"; } |
| class AddrMode5 : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode5", []> { |
| let EncoderMethod = "getAddrMode5OpValue"; |
| let DecoderMethod = "DecodeAddrMode5Operand"; |
| let ParserMatchClass = AddrMode5AsmOperand; |
| let MIOperandInfo = (ops GPR:$base, i32imm); |
| } |
| |
| def addrmode5 : AddrMode5 { |
| let PrintMethod = "printAddrMode5Operand<false>"; |
| } |
| |
| def addrmode5_pre : AddrMode5 { |
| let PrintMethod = "printAddrMode5Operand<true>"; |
| } |
| |
| // addrmode5fp16 := reg +/- imm8*2 |
| // |
| def AddrMode5FP16AsmOperand : AsmOperandClass { let Name = "AddrMode5FP16"; } |
| class AddrMode5FP16 : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode5FP16", []> { |
| let EncoderMethod = "getAddrMode5FP16OpValue"; |
| let DecoderMethod = "DecodeAddrMode5FP16Operand"; |
| let ParserMatchClass = AddrMode5FP16AsmOperand; |
| let MIOperandInfo = (ops GPR:$base, i32imm); |
| } |
| |
| def addrmode5fp16 : AddrMode5FP16 { |
| let PrintMethod = "printAddrMode5FP16Operand<false>"; |
| } |
| |
| // addrmode6 := reg with optional alignment |
| // |
| def AddrMode6AsmOperand : AsmOperandClass { let Name = "AlignedMemory"; } |
| def addrmode6 : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{ |
| let PrintMethod = "printAddrMode6Operand"; |
| let MIOperandInfo = (ops GPR:$addr, i32imm:$align); |
| let EncoderMethod = "getAddrMode6AddressOpValue"; |
| let DecoderMethod = "DecodeAddrMode6Operand"; |
| let ParserMatchClass = AddrMode6AsmOperand; |
| } |
| |
| def am6offset : MemOperand, |
| ComplexPattern<i32, 1, "SelectAddrMode6Offset", |
| [], [SDNPWantRoot]> { |
| let PrintMethod = "printAddrMode6OffsetOperand"; |
| let MIOperandInfo = (ops GPR); |
| let EncoderMethod = "getAddrMode6OffsetOpValue"; |
| let DecoderMethod = "DecodeGPRRegisterClass"; |
| } |
| |
| // Special version of addrmode6 to handle alignment encoding for VST1/VLD1 |
| // (single element from one lane) for size 32. |
| def addrmode6oneL32 : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{ |
| let PrintMethod = "printAddrMode6Operand"; |
| let MIOperandInfo = (ops GPR:$addr, i32imm); |
| let EncoderMethod = "getAddrMode6OneLane32AddressOpValue"; |
| } |
| |
| // Base class for addrmode6 with specific alignment restrictions. |
| class AddrMode6Align : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{ |
| let PrintMethod = "printAddrMode6Operand"; |
| let MIOperandInfo = (ops GPR:$addr, i32imm:$align); |
| let EncoderMethod = "getAddrMode6AddressOpValue"; |
| let DecoderMethod = "DecodeAddrMode6Operand"; |
| } |
| |
| // Special version of addrmode6 to handle no allowed alignment encoding for |
| // VLD/VST instructions and checking the alignment is not specified. |
| def AddrMode6AlignNoneAsmOperand : AsmOperandClass { |
| let Name = "AlignedMemoryNone"; |
| let DiagnosticString = "alignment must be omitted"; |
| } |
| def addrmode6alignNone : AddrMode6Align { |
| // The alignment specifier can only be omitted. |
| let ParserMatchClass = AddrMode6AlignNoneAsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 16-bit alignment encoding for |
| // VLD/VST instructions and checking the alignment value. |
| def AddrMode6Align16AsmOperand : AsmOperandClass { |
| let Name = "AlignedMemory16"; |
| let DiagnosticString = "alignment must be 16 or omitted"; |
| } |
| def addrmode6align16 : AddrMode6Align { |
| // The alignment specifier can only be 16 or omitted. |
| let ParserMatchClass = AddrMode6Align16AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 32-bit alignment encoding for |
| // VLD/VST instructions and checking the alignment value. |
| def AddrMode6Align32AsmOperand : AsmOperandClass { |
| let Name = "AlignedMemory32"; |
| let DiagnosticString = "alignment must be 32 or omitted"; |
| } |
| def addrmode6align32 : AddrMode6Align { |
| // The alignment specifier can only be 32 or omitted. |
| let ParserMatchClass = AddrMode6Align32AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 64-bit alignment encoding for |
| // VLD/VST instructions and checking the alignment value. |
| def AddrMode6Align64AsmOperand : AsmOperandClass { |
| let Name = "AlignedMemory64"; |
| let DiagnosticString = "alignment must be 64 or omitted"; |
| } |
| def addrmode6align64 : AddrMode6Align { |
| // The alignment specifier can only be 64 or omitted. |
| let ParserMatchClass = AddrMode6Align64AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 64-bit or 128-bit alignment encoding |
| // for VLD/VST instructions and checking the alignment value. |
| def AddrMode6Align64or128AsmOperand : AsmOperandClass { |
| let Name = "AlignedMemory64or128"; |
| let DiagnosticString = "alignment must be 64, 128 or omitted"; |
| } |
| def addrmode6align64or128 : AddrMode6Align { |
| // The alignment specifier can only be 64, 128 or omitted. |
| let ParserMatchClass = AddrMode6Align64or128AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 64-bit, 128-bit or 256-bit alignment |
| // encoding for VLD/VST instructions and checking the alignment value. |
| def AddrMode6Align64or128or256AsmOperand : AsmOperandClass { |
| let Name = "AlignedMemory64or128or256"; |
| let DiagnosticString = "alignment must be 64, 128, 256 or omitted"; |
| } |
| def addrmode6align64or128or256 : AddrMode6Align { |
| // The alignment specifier can only be 64, 128, 256 or omitted. |
| let ParserMatchClass = AddrMode6Align64or128or256AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle alignment encoding for VLD-dup |
| // instructions, specifically VLD4-dup. |
| def addrmode6dup : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{ |
| let PrintMethod = "printAddrMode6Operand"; |
| let MIOperandInfo = (ops GPR:$addr, i32imm); |
| let EncoderMethod = "getAddrMode6DupAddressOpValue"; |
| // FIXME: This is close, but not quite right. The alignment specifier is |
| // different. |
| let ParserMatchClass = AddrMode6AsmOperand; |
| } |
| |
| // Base class for addrmode6dup with specific alignment restrictions. |
| class AddrMode6DupAlign : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{ |
| let PrintMethod = "printAddrMode6Operand"; |
| let MIOperandInfo = (ops GPR:$addr, i32imm); |
| let EncoderMethod = "getAddrMode6DupAddressOpValue"; |
| } |
| |
| // Special version of addrmode6 to handle no allowed alignment encoding for |
| // VLD-dup instruction and checking the alignment is not specified. |
| def AddrMode6dupAlignNoneAsmOperand : AsmOperandClass { |
| let Name = "DupAlignedMemoryNone"; |
| let DiagnosticString = "alignment must be omitted"; |
| } |
| def addrmode6dupalignNone : AddrMode6DupAlign { |
| // The alignment specifier can only be omitted. |
| let ParserMatchClass = AddrMode6dupAlignNoneAsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 16-bit alignment encoding for VLD-dup |
| // instruction and checking the alignment value. |
| def AddrMode6dupAlign16AsmOperand : AsmOperandClass { |
| let Name = "DupAlignedMemory16"; |
| let DiagnosticString = "alignment must be 16 or omitted"; |
| } |
| def addrmode6dupalign16 : AddrMode6DupAlign { |
| // The alignment specifier can only be 16 or omitted. |
| let ParserMatchClass = AddrMode6dupAlign16AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 32-bit alignment encoding for VLD-dup |
| // instruction and checking the alignment value. |
| def AddrMode6dupAlign32AsmOperand : AsmOperandClass { |
| let Name = "DupAlignedMemory32"; |
| let DiagnosticString = "alignment must be 32 or omitted"; |
| } |
| def addrmode6dupalign32 : AddrMode6DupAlign { |
| // The alignment specifier can only be 32 or omitted. |
| let ParserMatchClass = AddrMode6dupAlign32AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 64-bit alignment encoding for VLD |
| // instructions and checking the alignment value. |
| def AddrMode6dupAlign64AsmOperand : AsmOperandClass { |
| let Name = "DupAlignedMemory64"; |
| let DiagnosticString = "alignment must be 64 or omitted"; |
| } |
| def addrmode6dupalign64 : AddrMode6DupAlign { |
| // The alignment specifier can only be 64 or omitted. |
| let ParserMatchClass = AddrMode6dupAlign64AsmOperand; |
| } |
| |
| // Special version of addrmode6 to handle 64-bit or 128-bit alignment encoding |
| // for VLD instructions and checking the alignment value. |
| def AddrMode6dupAlign64or128AsmOperand : AsmOperandClass { |
| let Name = "DupAlignedMemory64or128"; |
| let DiagnosticString = "alignment must be 64, 128 or omitted"; |
| } |
| def addrmode6dupalign64or128 : AddrMode6DupAlign { |
| // The alignment specifier can only be 64, 128 or omitted. |
| let ParserMatchClass = AddrMode6dupAlign64or128AsmOperand; |
| } |
| |
| // addrmodepc := pc + reg |
| // |
| def addrmodepc : MemOperand, |
| ComplexPattern<i32, 2, "SelectAddrModePC", []> { |
| let PrintMethod = "printAddrModePCOperand"; |
| let MIOperandInfo = (ops GPR, i32imm); |
| } |
| |
| // addr_offset_none := reg |
| // |
| def MemNoOffsetAsmOperand : AsmOperandClass { let Name = "MemNoOffset"; } |
| def addr_offset_none : MemOperand, |
| ComplexPattern<i32, 1, "SelectAddrOffsetNone", []> { |
| let PrintMethod = "printAddrMode7Operand"; |
| let DecoderMethod = "DecodeAddrMode7Operand"; |
| let ParserMatchClass = MemNoOffsetAsmOperand; |
| let MIOperandInfo = (ops GPR:$base); |
| } |
| |
| // t_addr_offset_none := reg [r0-r7] |
| def MemNoOffsetTAsmOperand : AsmOperandClass { let Name = "MemNoOffsetT"; } |
| def t_addr_offset_none : MemOperand { |
| let PrintMethod = "printAddrMode7Operand"; |
| let DecoderMethod = "DecodetGPRRegisterClass"; |
| let ParserMatchClass = MemNoOffsetTAsmOperand; |
| let MIOperandInfo = (ops tGPR:$base); |
| } |
| |
| def nohash_imm : Operand<i32> { |
| let PrintMethod = "printNoHashImmediate"; |
| } |
| |
| def CoprocNumAsmOperand : AsmOperandClass { |
| let Name = "CoprocNum"; |
| let ParserMethod = "parseCoprocNumOperand"; |
| } |
| def p_imm : Operand<i32> { |
| let PrintMethod = "printPImmediate"; |
| let ParserMatchClass = CoprocNumAsmOperand; |
| let DecoderMethod = "DecodeCoprocessor"; |
| } |
| |
| def CoprocRegAsmOperand : AsmOperandClass { |
| let Name = "CoprocReg"; |
| let ParserMethod = "parseCoprocRegOperand"; |
| } |
| def c_imm : Operand<i32> { |
| let PrintMethod = "printCImmediate"; |
| let ParserMatchClass = CoprocRegAsmOperand; |
| } |
| def CoprocOptionAsmOperand : AsmOperandClass { |
| let Name = "CoprocOption"; |
| let ParserMethod = "parseCoprocOptionOperand"; |
| } |
| def coproc_option_imm : Operand<i32> { |
| let PrintMethod = "printCoprocOptionImm"; |
| let ParserMatchClass = CoprocOptionAsmOperand; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| |
| include "ARMInstrFormats.td" |
| |
| //===----------------------------------------------------------------------===// |
| // Multiclass helpers... |
| // |
| |
| /// AsI1_bin_irs - Defines a set of (op r, {mod_imm|r|so_reg}) patterns for a |
| /// binop that produces a value. |
| let TwoOperandAliasConstraint = "$Rn = $Rd" in |
| multiclass AsI1_bin_irs<bits<4> opcod, string opc, |
| InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, |
| SDPatternOperator opnode, bit Commutable = 0> { |
| // The register-immediate version is re-materializable. This is useful |
| // in particular for taking the address of a local. |
| let isReMaterializable = 1 in { |
| def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, mod_imm:$imm), DPFrm, |
| iii, opc, "\t$Rd, $Rn, $imm", |
| [(set GPR:$Rd, (opnode GPR:$Rn, mod_imm:$imm))]>, |
| Sched<[WriteALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> imm; |
| let Inst{25} = 1; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-0} = imm; |
| } |
| } |
| def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm, |
| iir, opc, "\t$Rd, $Rn, $Rm", |
| [(set GPR:$Rd, (opnode GPR:$Rn, GPR:$Rm))]>, |
| Sched<[WriteALU, ReadALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<4> Rm; |
| let Inst{25} = 0; |
| let isCommutable = Commutable; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-4} = 0b00000000; |
| let Inst{3-0} = Rm; |
| } |
| |
| def rsi : AsI1<opcod, (outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm, |
| iis, opc, "\t$Rd, $Rn, $shift", |
| [(set GPR:$Rd, (opnode GPR:$Rn, so_reg_imm:$shift))]>, |
| Sched<[WriteALUsi, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-5} = shift{11-5}; |
| let Inst{4} = 0; |
| let Inst{3-0} = shift{3-0}; |
| } |
| |
| def rsr : AsI1<opcod, (outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm, |
| iis, opc, "\t$Rd, $Rn, $shift", |
| [(set GPR:$Rd, (opnode GPR:$Rn, so_reg_reg:$shift))]>, |
| Sched<[WriteALUsr, ReadALUsr]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-8} = shift{11-8}; |
| let Inst{7} = 0; |
| let Inst{6-5} = shift{6-5}; |
| let Inst{4} = 1; |
| let Inst{3-0} = shift{3-0}; |
| } |
| } |
| |
| /// AsI1_rbin_irs - Same as AsI1_bin_irs except the order of operands are |
| /// reversed. The 'rr' form is only defined for the disassembler; for codegen |
| /// it is equivalent to the AsI1_bin_irs counterpart. |
| let TwoOperandAliasConstraint = "$Rn = $Rd" in |
| multiclass AsI1_rbin_irs<bits<4> opcod, string opc, |
| InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, |
| SDNode opnode> { |
| // The register-immediate version is re-materializable. This is useful |
| // in particular for taking the address of a local. |
| let isReMaterializable = 1 in { |
| def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, mod_imm:$imm), DPFrm, |
| iii, opc, "\t$Rd, $Rn, $imm", |
| [(set GPR:$Rd, (opnode mod_imm:$imm, GPR:$Rn))]>, |
| Sched<[WriteALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> imm; |
| let Inst{25} = 1; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-0} = imm; |
| } |
| } |
| def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm, |
| iir, opc, "\t$Rd, $Rn, $Rm", |
| [/* pattern left blank */]>, |
| Sched<[WriteALU, ReadALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<4> Rm; |
| let Inst{11-4} = 0b00000000; |
| let Inst{25} = 0; |
| let Inst{3-0} = Rm; |
| let Inst{15-12} = Rd; |
| let Inst{19-16} = Rn; |
| } |
| |
| def rsi : AsI1<opcod, (outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm, |
| iis, opc, "\t$Rd, $Rn, $shift", |
| [(set GPR:$Rd, (opnode so_reg_imm:$shift, GPR:$Rn))]>, |
| Sched<[WriteALUsi, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-5} = shift{11-5}; |
| let Inst{4} = 0; |
| let Inst{3-0} = shift{3-0}; |
| } |
| |
| def rsr : AsI1<opcod, (outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_reg:$shift), DPSoRegRegFrm, |
| iis, opc, "\t$Rd, $Rn, $shift", |
| [(set GPR:$Rd, (opnode so_reg_reg:$shift, GPR:$Rn))]>, |
| Sched<[WriteALUsr, ReadALUsr]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-8} = shift{11-8}; |
| let Inst{7} = 0; |
| let Inst{6-5} = shift{6-5}; |
| let Inst{4} = 1; |
| let Inst{3-0} = shift{3-0}; |
| } |
| } |
| |
| /// AsI1_bin_s_irs - Same as AsI1_bin_irs except it sets the 's' bit by default. |
| /// |
| /// These opcodes will be converted to the real non-S opcodes by |
| /// AdjustInstrPostInstrSelection after giving them an optional CPSR operand. |
| let hasPostISelHook = 1, Defs = [CPSR] in { |
| multiclass AsI1_bin_s_irs<InstrItinClass iii, InstrItinClass iir, |
| InstrItinClass iis, SDNode opnode, |
| bit Commutable = 0> { |
| def ri : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, mod_imm:$imm, pred:$p), |
| 4, iii, |
| [(set GPR:$Rd, CPSR, (opnode GPR:$Rn, mod_imm:$imm))]>, |
| Sched<[WriteALU, ReadALU]>; |
| |
| def rr : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm, pred:$p), |
| 4, iir, |
| [(set GPR:$Rd, CPSR, (opnode GPR:$Rn, GPR:$Rm))]>, |
| Sched<[WriteALU, ReadALU, ReadALU]> { |
| let isCommutable = Commutable; |
| } |
| def rsi : ARMPseudoInst<(outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_imm:$shift, pred:$p), |
| 4, iis, |
| [(set GPR:$Rd, CPSR, (opnode GPR:$Rn, |
| so_reg_imm:$shift))]>, |
| Sched<[WriteALUsi, ReadALU]>; |
| |
| def rsr : ARMPseudoInst<(outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_reg:$shift, pred:$p), |
| 4, iis, |
| [(set GPR:$Rd, CPSR, (opnode GPR:$Rn, |
| so_reg_reg:$shift))]>, |
| Sched<[WriteALUSsr, ReadALUsr]>; |
| } |
| } |
| |
| /// AsI1_rbin_s_is - Same as AsI1_bin_s_irs, except selection DAG |
| /// operands are reversed. |
| let hasPostISelHook = 1, Defs = [CPSR] in { |
| multiclass AsI1_rbin_s_is<InstrItinClass iii, |
| InstrItinClass iis, SDNode opnode> { |
| def ri : ARMPseudoInst<(outs GPR:$Rd), (ins GPR:$Rn, mod_imm:$imm, pred:$p), |
| 4, iii, |
| [(set GPR:$Rd, CPSR, (opnode mod_imm:$imm, GPR:$Rn))]>, |
| Sched<[WriteALU, ReadALU]>; |
| |
| def rsi : ARMPseudoInst<(outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_imm:$shift, pred:$p), |
| 4, iis, |
| [(set GPR:$Rd, CPSR, (opnode so_reg_imm:$shift, |
| GPR:$Rn))]>, |
| Sched<[WriteALUsi, ReadALU]>; |
| |
| def rsr : ARMPseudoInst<(outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_reg:$shift, pred:$p), |
| 4, iis, |
| [(set GPR:$Rd, CPSR, (opnode so_reg_reg:$shift, |
| GPR:$Rn))]>, |
| Sched<[WriteALUSsr, ReadALUsr]>; |
| } |
| } |
| |
| /// AI1_cmp_irs - Defines a set of (op r, {mod_imm|r|so_reg}) cmp / test |
| /// patterns. Similar to AsI1_bin_irs except the instruction does not produce |
| /// a explicit result, only implicitly set CPSR. |
| let isCompare = 1, Defs = [CPSR] in { |
| multiclass AI1_cmp_irs<bits<4> opcod, string opc, |
| InstrItinClass iii, InstrItinClass iir, InstrItinClass iis, |
| SDPatternOperator opnode, bit Commutable = 0, |
| string rrDecoderMethod = ""> { |
| def ri : AI1<opcod, (outs), (ins GPR:$Rn, mod_imm:$imm), DPFrm, iii, |
| opc, "\t$Rn, $imm", |
| [(opnode GPR:$Rn, mod_imm:$imm)]>, |
| Sched<[WriteCMP, ReadALU]> { |
| bits<4> Rn; |
| bits<12> imm; |
| let Inst{25} = 1; |
| let Inst{20} = 1; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = 0b0000; |
| let Inst{11-0} = imm; |
| |
| let Unpredictable{15-12} = 0b1111; |
| } |
| def rr : AI1<opcod, (outs), (ins GPR:$Rn, GPR:$Rm), DPFrm, iir, |
| opc, "\t$Rn, $Rm", |
| [(opnode GPR:$Rn, GPR:$Rm)]>, |
| Sched<[WriteCMP, ReadALU, ReadALU]> { |
| bits<4> Rn; |
| bits<4> Rm; |
| let isCommutable = Commutable; |
| let Inst{25} = 0; |
| let Inst{20} = 1; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = 0b0000; |
| let Inst{11-4} = 0b00000000; |
| let Inst{3-0} = Rm; |
| let DecoderMethod = rrDecoderMethod; |
| |
| let Unpredictable{15-12} = 0b1111; |
| } |
| def rsi : AI1<opcod, (outs), |
| (ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm, iis, |
| opc, "\t$Rn, $shift", |
| [(opnode GPR:$Rn, so_reg_imm:$shift)]>, |
| Sched<[WriteCMPsi, ReadALU]> { |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{20} = 1; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = 0b0000; |
| let Inst{11-5} = shift{11-5}; |
| let Inst{4} = 0; |
| let Inst{3-0} = shift{3-0}; |
| |
| let Unpredictable{15-12} = 0b1111; |
| } |
| def rsr : AI1<opcod, (outs), |
| (ins GPRnopc:$Rn, so_reg_reg:$shift), DPSoRegRegFrm, iis, |
| opc, "\t$Rn, $shift", |
| [(opnode GPRnopc:$Rn, so_reg_reg:$shift)]>, |
| Sched<[WriteCMPsr, ReadALU]> { |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{20} = 1; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = 0b0000; |
| let Inst{11-8} = shift{11-8}; |
| let Inst{7} = 0; |
| let Inst{6-5} = shift{6-5}; |
| let Inst{4} = 1; |
| let Inst{3-0} = shift{3-0}; |
| |
| let Unpredictable{15-12} = 0b1111; |
| } |
| |
| } |
| } |
| |
| /// AI_ext_rrot - A unary operation with two forms: one whose operand is a |
| /// register and one whose operand is a register rotated by 8/16/24. |
| /// FIXME: Remove the 'r' variant. Its rot_imm is zero. |
| class AI_ext_rrot<bits<8> opcod, string opc, PatFrag opnode> |
| : AExtI<opcod, (outs GPRnopc:$Rd), (ins GPRnopc:$Rm, rot_imm:$rot), |
| IIC_iEXTr, opc, "\t$Rd, $Rm$rot", |
| [(set GPRnopc:$Rd, (opnode (rotr GPRnopc:$Rm, rot_imm:$rot)))]>, |
| Requires<[IsARM, HasV6]>, Sched<[WriteALUsi]> { |
| bits<4> Rd; |
| bits<4> Rm; |
| bits<2> rot; |
| let Inst{19-16} = 0b1111; |
| let Inst{15-12} = Rd; |
| let Inst{11-10} = rot; |
| let Inst{3-0} = Rm; |
| } |
| |
| class AI_ext_rrot_np<bits<8> opcod, string opc> |
| : AExtI<opcod, (outs GPRnopc:$Rd), (ins GPRnopc:$Rm, rot_imm:$rot), |
| IIC_iEXTr, opc, "\t$Rd, $Rm$rot", []>, |
| Requires<[IsARM, HasV6]>, Sched<[WriteALUsi]> { |
| bits<2> rot; |
| let Inst{19-16} = 0b1111; |
| let Inst{11-10} = rot; |
| } |
| |
| /// AI_exta_rrot - A binary operation with two forms: one whose operand is a |
| /// register and one whose operand is a register rotated by 8/16/24. |
| class AI_exta_rrot<bits<8> opcod, string opc, PatFrag opnode> |
| : AExtI<opcod, (outs GPRnopc:$Rd), (ins GPR:$Rn, GPRnopc:$Rm, rot_imm:$rot), |
| IIC_iEXTAr, opc, "\t$Rd, $Rn, $Rm$rot", |
| [(set GPRnopc:$Rd, (opnode GPR:$Rn, |
| (rotr GPRnopc:$Rm, rot_imm:$rot)))]>, |
| Requires<[IsARM, HasV6]>, Sched<[WriteALUsr]> { |
| bits<4> Rd; |
| bits<4> Rm; |
| bits<4> Rn; |
| bits<2> rot; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-10} = rot; |
| let Inst{9-4} = 0b000111; |
| let Inst{3-0} = Rm; |
| } |
| |
| class AI_exta_rrot_np<bits<8> opcod, string opc> |
| : AExtI<opcod, (outs GPRnopc:$Rd), (ins GPR:$Rn, GPRnopc:$Rm, rot_imm:$rot), |
| IIC_iEXTAr, opc, "\t$Rd, $Rn, $Rm$rot", []>, |
| Requires<[IsARM, HasV6]>, Sched<[WriteALUsr]> { |
| bits<4> Rn; |
| bits<2> rot; |
| let Inst{19-16} = Rn; |
| let Inst{11-10} = rot; |
| } |
| |
| /// AI1_adde_sube_irs - Define instructions and patterns for adde and sube. |
| let TwoOperandAliasConstraint = "$Rn = $Rd" in |
| multiclass AI1_adde_sube_irs<bits<4> opcod, string opc, SDNode opnode, |
| bit Commutable = 0> { |
| let hasPostISelHook = 1, Defs = [CPSR], Uses = [CPSR] in { |
| def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, mod_imm:$imm), |
| DPFrm, IIC_iALUi, opc, "\t$Rd, $Rn, $imm", |
| [(set GPR:$Rd, CPSR, (opnode GPR:$Rn, mod_imm:$imm, CPSR))]>, |
| Requires<[IsARM]>, |
| Sched<[WriteALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> imm; |
| let Inst{25} = 1; |
| let Inst{15-12} = Rd; |
| let Inst{19-16} = Rn; |
| let Inst{11-0} = imm; |
| } |
| def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), |
| DPFrm, IIC_iALUr, opc, "\t$Rd, $Rn, $Rm", |
| [(set GPR:$Rd, CPSR, (opnode GPR:$Rn, GPR:$Rm, CPSR))]>, |
| Requires<[IsARM]>, |
| Sched<[WriteALU, ReadALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<4> Rm; |
| let Inst{11-4} = 0b00000000; |
| let Inst{25} = 0; |
| let isCommutable = Commutable; |
| let Inst{3-0} = Rm; |
| let Inst{15-12} = Rd; |
| let Inst{19-16} = Rn; |
| } |
| def rsi : AsI1<opcod, (outs GPR:$Rd), |
| (ins GPR:$Rn, so_reg_imm:$shift), |
| DPSoRegImmFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift", |
| [(set GPR:$Rd, CPSR, (opnode GPR:$Rn, so_reg_imm:$shift, CPSR))]>, |
| Requires<[IsARM]>, |
| Sched<[WriteALUsi, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-5} = shift{11-5}; |
| let Inst{4} = 0; |
| let Inst{3-0} = shift{3-0}; |
| } |
| def rsr : AsI1<opcod, (outs GPRnopc:$Rd), |
| (ins GPRnopc:$Rn, so_reg_reg:$shift), |
| DPSoRegRegFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift", |
| [(set GPRnopc:$Rd, CPSR, |
| (opnode GPRnopc:$Rn, so_reg_reg:$shift, CPSR))]>, |
| Requires<[IsARM]>, |
| Sched<[WriteALUsr, ReadALUsr]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-8} = shift{11-8}; |
| let Inst{7} = 0; |
| let Inst{6-5} = shift{6-5}; |
| let Inst{4} = 1; |
| let Inst{3-0} = shift{3-0}; |
| } |
| } |
| } |
| |
| /// AI1_rsc_irs - Define instructions and patterns for rsc |
| let TwoOperandAliasConstraint = "$Rn = $Rd" in |
| multiclass AI1_rsc_irs<bits<4> opcod, string opc, SDNode opnode> { |
| let hasPostISelHook = 1, Defs = [CPSR], Uses = [CPSR] in { |
| def ri : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, mod_imm:$imm), |
| DPFrm, IIC_iALUi, opc, "\t$Rd, $Rn, $imm", |
| [(set GPR:$Rd, CPSR, (opnode mod_imm:$imm, GPR:$Rn, CPSR))]>, |
| Requires<[IsARM]>, |
| Sched<[WriteALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> imm; |
| let Inst{25} = 1; |
| let Inst{15-12} = Rd; |
| let Inst{19-16} = Rn; |
| let Inst{11-0} = imm; |
| } |
| def rr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), |
| DPFrm, IIC_iALUr, opc, "\t$Rd, $Rn, $Rm", |
| [/* pattern left blank */]>, |
| Sched<[WriteALU, ReadALU, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<4> Rm; |
| let Inst{11-4} = 0b00000000; |
| let Inst{25} = 0; |
| let Inst{3-0} = Rm; |
| let Inst{15-12} = Rd; |
| let Inst{19-16} = Rn; |
| } |
| def rsi : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_imm:$shift), |
| DPSoRegImmFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift", |
| [(set GPR:$Rd, CPSR, (opnode so_reg_imm:$shift, GPR:$Rn, CPSR))]>, |
| Requires<[IsARM]>, |
| Sched<[WriteALUsi, ReadALU]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-5} = shift{11-5}; |
| let Inst{4} = 0; |
| let Inst{3-0} = shift{3-0}; |
| } |
| def rsr : AsI1<opcod, (outs GPR:$Rd), (ins GPR:$Rn, so_reg_reg:$shift), |
| DPSoRegRegFrm, IIC_iALUsr, opc, "\t$Rd, $Rn, $shift", |
| [(set GPR:$Rd, CPSR, (opnode so_reg_reg:$shift, GPR:$Rn, CPSR))]>, |
| Requires<[IsARM]>, |
| Sched<[WriteALUsr, ReadALUsr]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<12> shift; |
| let Inst{25} = 0; |
| let Inst{19-16} = Rn; |
| let Inst{15-12} = Rd; |
| let Inst{11-8} = shift{11-8}; |
| let Inst{7} = 0; |
| let Inst{6-5} = shift{6-5}; |
| let Inst{4} = 1; |
| let Inst{3-0} = shift{3-0}; |
| } |
| } |
| } |
| |
| let canFoldAsLoad = 1, isReMaterializable = 1 in { |
| multiclass AI_ldr1<bit isByte, string opc, InstrItinClass iii, |
| InstrItinClass iir, PatFrag opnode> { |
| // Note: We use the complex addrmode_imm12 rather than just an input |
| // GPR and a constrained immediate so that we can use this to match |
| // frame index references and avoid matching constant pool references. |
| def i12: AI2ldst<0b010, 1, isByte, (outs GPR:$Rt), (ins addrmode_imm12:$addr), |
| AddrMode_i12, LdFrm, iii, opc, "\t$Rt, $addr", |
| [(set GPR:$Rt, (opnode addrmode_imm12:$addr))]> { |
| bits<4> Rt; |
| bits<17> addr; |
| let Inst{23} = addr{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = addr{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = addr{11-0}; // imm12 |
| } |
| def rs : AI2ldst<0b011, 1, isByte, (outs GPR:$Rt), (ins ldst_so_reg:$shift), |
| AddrModeNone, LdFrm, iir, opc, "\t$Rt, $shift", |
| [(set GPR:$Rt, (opnode ldst_so_reg:$shift))]> { |
| bits<4> Rt; |
| bits<17> shift; |
| let shift{4} = 0; // Inst{4} = 0 |
| let Inst{23} = shift{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = shift{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = shift{11-0}; |
| } |
| } |
| } |
| |
| let canFoldAsLoad = 1, isReMaterializable = 1 in { |
| multiclass AI_ldr1nopc<bit isByte, string opc, InstrItinClass iii, |
| InstrItinClass iir, PatFrag opnode> { |
| // Note: We use the complex addrmode_imm12 rather than just an input |
| // GPR and a constrained immediate so that we can use this to match |
| // frame index references and avoid matching constant pool references. |
| def i12: AI2ldst<0b010, 1, isByte, (outs GPRnopc:$Rt), |
| (ins addrmode_imm12:$addr), |
| AddrMode_i12, LdFrm, iii, opc, "\t$Rt, $addr", |
| [(set GPRnopc:$Rt, (opnode addrmode_imm12:$addr))]> { |
| bits<4> Rt; |
| bits<17> addr; |
| let Inst{23} = addr{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = addr{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = addr{11-0}; // imm12 |
| } |
| def rs : AI2ldst<0b011, 1, isByte, (outs GPRnopc:$Rt), |
| (ins ldst_so_reg:$shift), |
| AddrModeNone, LdFrm, iir, opc, "\t$Rt, $shift", |
| [(set GPRnopc:$Rt, (opnode ldst_so_reg:$shift))]> { |
| bits<4> Rt; |
| bits<17> shift; |
| let shift{4} = 0; // Inst{4} = 0 |
| let Inst{23} = shift{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = shift{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = shift{11-0}; |
| } |
| } |
| } |
| |
| |
| multiclass AI_str1<bit isByte, string opc, InstrItinClass iii, |
| InstrItinClass iir, PatFrag opnode> { |
| // Note: We use the complex addrmode_imm12 rather than just an input |
| // GPR and a constrained immediate so that we can use this to match |
| // frame index references and avoid matching constant pool references. |
| def i12 : AI2ldst<0b010, 0, isByte, (outs), |
| (ins GPR:$Rt, addrmode_imm12:$addr), |
| AddrMode_i12, StFrm, iii, opc, "\t$Rt, $addr", |
| [(opnode GPR:$Rt, addrmode_imm12:$addr)]> { |
| bits<4> Rt; |
| bits<17> addr; |
| let Inst{23} = addr{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = addr{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = addr{11-0}; // imm12 |
| } |
| def rs : AI2ldst<0b011, 0, isByte, (outs), (ins GPR:$Rt, ldst_so_reg:$shift), |
| AddrModeNone, StFrm, iir, opc, "\t$Rt, $shift", |
| [(opnode GPR:$Rt, ldst_so_reg:$shift)]> { |
| bits<4> Rt; |
| bits<17> shift; |
| let shift{4} = 0; // Inst{4} = 0 |
| let Inst{23} = shift{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = shift{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = shift{11-0}; |
| } |
| } |
| |
| multiclass AI_str1nopc<bit isByte, string opc, InstrItinClass iii, |
| InstrItinClass iir, PatFrag opnode> { |
| // Note: We use the complex addrmode_imm12 rather than just an input |
| // GPR and a constrained immediate so that we can use this to match |
| // frame index references and avoid matching constant pool references. |
| def i12 : AI2ldst<0b010, 0, isByte, (outs), |
| (ins GPRnopc:$Rt, addrmode_imm12:$addr), |
| AddrMode_i12, StFrm, iii, opc, "\t$Rt, $addr", |
| [(opnode GPRnopc:$Rt, addrmode_imm12:$addr)]> { |
| bits<4> Rt; |
| bits<17> addr; |
| let Inst{23} = addr{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = addr{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = addr{11-0}; // imm12 |
| } |
| def rs : AI2ldst<0b011, 0, isByte, (outs), |
| (ins GPRnopc:$Rt, ldst_so_reg:$shift), |
| AddrModeNone, StFrm, iir, opc, "\t$Rt, $shift", |
| [(opnode GPRnopc:$Rt, ldst_so_reg:$shift)]> { |
| bits<4> Rt; |
| bits<17> shift; |
| let shift{4} = 0; // Inst{4} = 0 |
| let Inst{23} = shift{12}; // U (add = ('U' == 1)) |
| let Inst{19-16} = shift{16-13}; // Rn |
| let Inst{15-12} = Rt; |
| let Inst{11-0} = shift{11-0}; |
| } |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Instructions |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| // Miscellaneous Instructions. |
| // |
| |
| /// CONSTPOOL_ENTRY - This instruction represents a floating constant pool in |
| /// the function. The first operand is the ID# for this instruction, the second |
| /// is the index into the MachineConstantPool that this is, the third is the |
| /// size in bytes of this constant pool entry. |
| let hasSideEffects = 0, isNotDuplicable = 1, hasNoSchedulingInfo = 1 in |
| def CONSTPOOL_ENTRY : |
| PseudoInst<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, |
| i32imm:$size), NoItinerary, []>; |
| |
| /// A jumptable consisting of direct 32-bit addresses of the destination basic |
| /// blocks (either absolute, or relative to the start of the jump-table in PIC |
| /// mode). Used mostly in ARM and Thumb-1 modes. |
| def JUMPTABLE_ADDRS : |
| PseudoInst<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, |
| i32imm:$size), NoItinerary, []>; |
| |
| /// A jumptable consisting of 32-bit jump instructions. Used for Thumb-2 tables |
| /// that cannot be optimised to use TBB or TBH. |
| def JUMPTABLE_INSTS : |
| PseudoInst<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, |
| i32imm:$size), NoItinerary, []>; |
| |
| /// A jumptable consisting of 8-bit unsigned integers representing offsets from |
| /// a TBB instruction. |
| def JUMPTABLE_TBB : |
| PseudoInst<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, |
| i32imm:$size), NoItinerary, []>; |
| |
| /// A jumptable consisting of 16-bit unsigned integers representing offsets from |
| /// a TBH instruction. |
| def JUMPTABLE_TBH : |
| PseudoInst<(outs), (ins cpinst_operand:$instid, cpinst_operand:$cpidx, |
| i32imm:$size), NoItinerary, []>; |
| |
| |
| // FIXME: Marking these as hasSideEffects is necessary to prevent machine DCE |
| // from removing one half of the matched pairs. That breaks PEI, which assumes |
| // these will always be in pairs, and asserts if it finds otherwise. Better way? |
| let Defs = [SP], Uses = [SP], hasSideEffects = 1 in { |
| def ADJCALLSTACKUP : |
| PseudoInst<(outs), (ins i32imm:$amt1, i32imm:$amt2, pred:$p), NoItinerary, |
| [(ARMcallseq_end timm:$amt1, timm:$amt2)]>; |
| |
| def ADJCALLSTACKDOWN : |
| PseudoInst<(outs), (ins i32imm:$amt, i32imm:$amt2, pred:$p), NoItinerary, |
| [(ARMcallseq_start timm:$amt, timm:$amt2)]>; |
| } |
| |
| def HINT : AI<(outs), (ins imm0_239:$imm), MiscFrm, NoItinerary, |
| "hint", "\t$imm", [(int_arm_hint imm0_239:$imm)]>, |
| Requires<[IsARM, HasV6]> { |
| bits<8> imm; |
| let Inst{27-8} = 0b00110010000011110000; |
| let Inst{7-0} = imm; |
| let DecoderMethod = "DecodeHINTInstruction"; |
| } |
| |
| def : InstAlias<"nop$p", (HINT 0, pred:$p)>, Requires<[IsARM, HasV6K]>; |
| def : InstAlias<"yield$p", (HINT 1, pred:$p)>, Requires<[IsARM, HasV6K]>; |
| def : InstAlias<"wfe$p", (HINT 2, pred:$p)>, Requires<[IsARM, HasV6K]>; |
| def : InstAlias<"wfi$p", (HINT 3, pred:$p)>, Requires<[IsARM, HasV6K]>; |
| def : InstAlias<"sev$p", (HINT 4, pred:$p)>, Requires<[IsARM, HasV6K]>; |
| def : InstAlias<"sevl$p", (HINT 5, pred:$p)>, Requires<[IsARM, HasV8]>; |
| def : InstAlias<"esb$p", (HINT 16, pred:$p)>, Requires<[IsARM, HasRAS]>; |
| def : InstAlias<"csdb$p", (HINT 20, pred:$p)>, Requires<[IsARM, HasV6K]>; |
| |
| def SEL : AI<(outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), DPFrm, NoItinerary, "sel", |
| "\t$Rd, $Rn, $Rm", |
| [(set GPR:$Rd, (int_arm_sel GPR:$Rn, GPR:$Rm))]>, |
| Requires<[IsARM, HasV6]> { |
| bits<4> Rd; |
| bits<4> Rn; |
| bits<4> Rm; |
| let Inst{3-0} = Rm; |
| let Inst{15-12} = Rd; |
| let Inst{19-16} = Rn; |
| let Inst{27-20} = 0b01101000; |
| let Inst{7-4} = 0b1011; |
| let Inst{11-8} = 0b1111; |
| let Unpredictable{11-8} = 0b1111; |
| } |
| |
| // The 16-bit operand $val can be used by a debugger to store more information |
| // about the breakpoint. |
| def BKPT : AInoP<(outs), (ins imm0_65535:$val), MiscFrm, NoItinerary, |
| "bkpt", "\t$val", []>, Requires<[IsARM]> { |
| bits<16> val; |
| let Inst{3-0} = val{3-0}; |
| let Inst{19-8} = val{15-4}; |
| let Inst{27-20} = 0b00010010; |
| let Inst{31-28} = 0xe; // AL |
| let Inst{7-4} = 0b0111; |
| } |
| // default immediate for breakpoint mnemonic |
| def : InstAlias<"bkpt", (BKPT 0), 0>, Requires<[IsARM]>; |
| |
| def HLT : AInoP<(outs), (ins imm0_65535:$val), MiscFrm, NoItinerary, |
| "hlt", "\t$val", []>, Requires<[IsARM, HasV8]> { |
| bits<16> val; |
| let Inst{3-0} = val{3-0}; |
| let Inst{19-8} = val{15-4}; |
| let Inst{27-20} = 0b00010000; |
| let Inst{31-28} = 0xe; // AL |
| let Inst{7-4} = 0b0111; |
| } |
| |
| // Change Processor State |
| // FIXME: We should use InstAlias to handle the optional operands. |
| class CPS<dag iops, string asm_ops> |
| : AXI<(outs), iops, MiscFrm, NoItinerary, !strconcat("cps", asm_ops), |
| []>, Requires<[IsARM]> { |
| bits<2> imod; |
| bits<3> iflags; |
| bits<5> mode; |
| bit M; |
| |
| let Inst{31-28} = 0b1111; |
| let Inst{27-20} = 0b00010000; |
| let Inst{19-18} = imod; |
| let Inst{17} = M; // Enabled if mode is set; |
| let Inst{16-9} = 0b00000000; |
| let Inst{8-6} = iflags; |
| let Inst{5} = 0; |
| let Inst{4-0} = mode; |
| } |
| |
| let DecoderMethod = "DecodeCPSInstruction" in { |
| let M = 1 in |
| def CPS3p : CPS<(ins imod_op:$imod, iflags_op:$iflags, imm0_31:$mode), |
| "$imod\t$iflags, $mode">; |
| let mode = 0, M = 0 in |
| def CPS2p : CPS<(ins imod_op:$imod, iflags_op:$iflags), "$imod\t$iflags">; |
| |
| let imod = 0, iflags = 0, M = 1 in |
| def CPS1p : CPS<(ins imm0_31:$mode), "\t$mode">; |
| } |
| |
| // Preload signals the memory system of possible future data/instruction access. |
| multiclass APreLoad<bits<1> read, bits<1> data, string opc> { |
| |
| def i12 : AXIM<(outs), (ins addrmode_imm12:$addr), AddrMode_i12, MiscFrm, |
| IIC_Preload, !strconcat(opc, "\t$addr"), |
| [(ARMPreload addrmode_imm12:$addr, (i32 read), (i32 data))]>, |
| Sched<[WritePreLd]> { |
| bits<4> Rt; |
| bits<17> addr; |
| let Inst{31-26} = 0b111101; |
| let Inst{25} = 0; // 0 for immediate form |
| let Inst{24} = data; |
| let Inst{23} = addr{12}; // U (add = ('U' == 1)) |
| let Inst{22} = read; |
| let Inst{21-20} = 0b01; |
| let Inst{19-16} = addr{16-13}; // Rn |
| let Inst{15-12} = 0b1111; |
| let Inst{11-0} = addr{11-0}; // imm12 |
| } |
| |
| def rs : AXI<(outs), (ins ldst_so_reg:$shift), MiscFrm, IIC_Preload, |
| !strconcat(opc, "\t$shift"), |
| [(ARMPreload ldst_so_reg:$shift, (i32 read), (i32 data))]>, |
| Sched<[WritePreLd]> { |
| bits<17> shift; |
| let Inst{31-26} = 0b111101; |
| let Inst{25} = 1; // 1 for register form |
| let Inst{24} = data; |
| let Inst{23} = shift{12}; // U (add = ('U' == 1)) |
| let Inst{22} = read; |
| let Inst{21-20} = 0b01; |
| let Inst{19-16} = shift{16-13}; // Rn |
| let Inst{15-12} = 0b1111; |
| let Inst{11-0} = shift{11-0}; |
| let Inst{4} = 0; |
| } |
| } |
| |
| defm PLD : APreLoad<1, 1, "pld">, Requires<[IsARM]>; |
| defm PLDW : APreLoad<0, 1, "pldw">, Requires<[IsARM,HasV7,HasMP]>; |
| defm PLI : APreLoad<1, 0, "pli">, Requires<[IsARM,HasV7]>; |
| |
| def SETEND : AXI<(outs), (ins setend_op:$end), MiscFrm, NoItinerary, |
| "setend\t$end", []>, Requires<[IsARM]>, Deprecated<HasV8Ops> { |
| bits<1> end; |
| let Inst{31-10} = 0b1111000100000001000000; |
| let Inst{9} = end; |
| let Inst{8-0} = 0; |
| } |
| |
| def DBG : AI<(outs), (ins imm0_15:$opt), MiscFrm, NoItinerary, "dbg", "\t$opt", |
| [(int_arm_dbg imm0_15:$opt)]>, Requires<[IsARM, HasV7]> { |
| bits<4> opt; |
| let Inst{27-4} = 0b001100100000111100001111; |
| let Inst{3-0} = opt; |
| } |
| |
| // A8.8.247 UDF - Undefined (Encoding A1) |
| def UDF : AInoP<(outs), (ins imm0_65535:$imm16), MiscFrm, NoItinerary, |
| "udf", "\t$imm16", [(int_arm_undefined imm0_65535:$imm16)]> { |
| bits<16> imm16; |
| let Inst{31-28} = 0b1110; // AL |
| let Inst{27-25} = 0b011; |
| let Inst{24-20} = 0b11111; |
| let Inst{19-8} = imm16{15-4}; |
| let Inst{7-4} = 0b1111; |
| let Inst{3-0} = imm16{3-0}; |
| } |
| |
| /* |
| * A5.4 Permanently UNDEFINED instructions. |
| * |
| * For most targets use UDF #65006, for which the OS will generate SIGTRAP. |
| * Other UDF encodings generate SIGILL. |
| * |
| * NaCl's OS instead chooses an ARM UDF encoding that's also a UDF in Thumb. |
| * Encoding A1: |
| * 1110 0111 1111 iiii iiii iiii 1111 iiii |
| * Encoding T1: |
| * 1101 1110 iiii iiii |
| * It uses the following encoding: |
| * 1110 0111 1111 1110 1101 1110 1111 0000 |
| * - In ARM: UDF #60896; |
| * - In Thumb: UDF #254 followed by a branch-to-self. |
| */ |
| let isBarrier = 1, isTerminator = 1 in |
| def TRAPNaCl : AXI<(outs), (ins), MiscFrm, NoItinerary, |
| "trap", [(trap)]>, |
| Requires<[IsARM,UseNaClTrap]> { |
| let Inst = 0xe7fedef0; |
| } |
| let isBarrier = 1, isTerminator = 1 in |
| def TRAP : AXI<(outs), (ins), MiscFrm, NoItinerary, |
| "trap", [(trap)]>, |
| Requires<[IsARM,DontUseNaClTrap]> { |
| let Inst = 0xe7ffdefe; |
| } |
| |
| def : Pat<(debugtrap), (BKPT 0)>, Requires<[IsARM, HasV5T]>; |
| def : Pat<(debugtrap), (UDF 254)>, Requires<[IsARM, NoV5T]>; |
| |
| // Address computation and loads and stores in PIC mode. |
| let isNotDuplicable = 1 in { |
| def PICADD : ARMPseudoInst<(outs GPR:$dst), (ins GPR:$a, pclabel:$cp, pred:$p), |
| 4, IIC_iALUr, |
| [(set GPR:$dst, (ARMpic_add GPR:$a, imm:$cp))]>, |
| Sched<[WriteALU, ReadALU]>; |
| |
| let AddedComplexity = 10 in { |
| def PICLDR : ARMPseudoInst<(outs GPR:$dst), (ins addrmodepc:$addr, pred:$p), |
| 4, IIC_iLoad_r, |
| [(set GPR:$dst, (load addrmodepc:$addr))]>; |
| |
| def PICLDRH : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), |
| 4, IIC_iLoad_bh_r, |
| [(set GPR:$Rt, (zextloadi16 addrmodepc:$addr))]>; |
| |
| def PICLDRB : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), |
| 4, IIC_iLoad_bh_r, |
| [(set GPR:$Rt, (zextloadi8 addrmodepc:$addr))]>; |
| |
| def PICLDRSH : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), |
| 4, IIC_iLoad_bh_r, |
| [(set GPR:$Rt, (sextloadi16 addrmodepc:$addr))]>; |
| |
| def PICLDRSB : ARMPseudoInst<(outs GPR:$Rt), (ins addrmodepc:$addr, pred:$p), |
| 4, IIC_iLoad_bh_r, |
| [(set GPR:$Rt, (sextloadi8 addrmodepc:$addr))]>; |
| } |
| let AddedComplexity = 10 in { |
| def PICSTR : ARMPseudoInst<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), |
| 4, IIC_iStore_r, [(store GPR:$src, addrmodepc:$addr)]>; |
| |
| def PICSTRH : ARMPseudoInst<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), |
| 4, IIC_iStore_bh_r, [(truncstorei16 GPR:$src, |
| addrmodepc:$addr)]>; |
| |
| def PICSTRB : ARMPseudoInst<(outs), (ins GPR:$src, addrmodepc:$addr, pred:$p), |
| 4, IIC_iStore_bh_r, [(truncstorei8 GPR:$src, addrmodepc:$addr)]>; |
| } |
| } // isNotDuplicable = 1 |
| |
| |
| // LEApcrel - Load a pc-relative address into a register without offending the |
| // assembler. |
| let hasSideEffects = 0, isReMaterializable = 1 in |
| // The 'adr' mnemonic encodes differently if the label is before or after |
| // the instruction. The {24-21} opcode bits are set by the fixup, as we don't |
| // know until then which form of the instruction will be used. |
| def ADR : AI1<{0,?,?,0}, (outs GPR:$Rd), (ins adrlabel:$label), |
| MiscFrm, IIC_iALUi, "adr", "\t$Rd, $label", []>, |
| Sched<[WriteALU, ReadALU]> { |
| bits<4> Rd; |
| bits<14> label; |
| |