| //===-- M68kInstrInfo.td - Main M68k Instruction Definition -*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// This file describes the M68k instruction set, defining the instructions |
| /// and properties of the instructions which are needed for code generation, |
| /// machine code emission, and analysis. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| include "M68kInstrFormats.td" |
| |
| //===----------------------------------------------------------------------===// |
| // Profiles |
| //===----------------------------------------------------------------------===// |
| |
| def MxSDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; |
| def MxSDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; |
| |
| def MxSDT_Call : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>; |
| |
| def MxSDT_Ret : SDTypeProfile<0, -1, [ |
| /* ADJ */ SDTCisVT<0, i32> |
| ]>; |
| |
| def MxSDT_TCRet : SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisVT<1, i32>]>; |
| |
| def MxSDT_Wrapper : SDTypeProfile<1, 1, [SDTCisSameAs<0, 1>, SDTCisPtrTy<0>]>; |
| |
| def MxSDT_UnArithCCROut : SDTypeProfile<2, 1, [ |
| /* RES */ SDTCisInt<0>, |
| /* CCR */ SDTCisVT<1, i8>, |
| /* OPD */ SDTCisSameAs<0, 2> |
| ]>; |
| |
| // RES, CCR <- op LHS, RHS |
| def MxSDT_BiArithCCROut : SDTypeProfile<2, 2, [ |
| /* RES */ SDTCisInt<0>, |
| /* CCR */ SDTCisVT<1, i8>, |
| /* LHS */ SDTCisSameAs<0, 2>, |
| /* RHS */ SDTCisSameAs<0, 3> |
| ]>; |
| |
| // RES, CCR <- op LHS, RHS, CCR |
| def MxSDT_BiArithCCRInOut : SDTypeProfile<2, 3, [ |
| /* RES 1 */ SDTCisInt<0>, |
| /* CCR */ SDTCisVT<1, i8>, |
| /* LHS */ SDTCisSameAs<0, 2>, |
| /* RHS */ SDTCisSameAs<0, 3>, |
| /* CCR */ SDTCisSameAs<1, 4> |
| ]>; |
| |
| // RES1, RES2, CCR <- op LHS, RHS |
| def MxSDT_2BiArithCCROut : SDTypeProfile<3, 2, [ |
| /* RES 1 */ SDTCisInt<0>, |
| /* RES 2 */ SDTCisSameAs<0, 1>, |
| /* CCR */ SDTCisVT<1, i8>, |
| /* LHS */ SDTCisSameAs<0, 2>, |
| /* RHS */ SDTCisSameAs<0, 3> |
| ]>; |
| |
| def MxSDT_CmpTest : SDTypeProfile<1, 2, [ |
| /* CCR */ SDTCisVT<0, i8>, |
| /* Ops */ SDTCisSameAs<1, 2> |
| ]>; |
| |
| def MxSDT_Cmov : SDTypeProfile<1, 4, [ |
| /* ARG */ SDTCisSameAs<0, 1>, |
| /* ARG */ SDTCisSameAs<1, 2>, |
| /* Cond */ SDTCisVT<3, i8>, |
| /* CCR */ SDTCisVT<4, i8> |
| ]>; |
| |
| def MxSDT_BrCond : SDTypeProfile<0, 3, [ |
| /* Dest */ SDTCisVT<0, OtherVT>, |
| /* Cond */ SDTCisVT<1, i8>, |
| /* CCR */ SDTCisVT<2, i8> |
| ]>; |
| |
| def MxSDT_SetCC : SDTypeProfile<1, 2, [ |
| /* BOOL */ SDTCisVT<0, i8>, |
| /* Cond */ SDTCisVT<1, i8>, |
| /* CCR */ SDTCisVT<2, i8> |
| ]>; |
| |
| def MxSDT_SetCC_C : SDTypeProfile<1, 2, [ |
| /* BOOL */ SDTCisInt<0>, |
| /* Cond */ SDTCisVT<1, i8>, |
| /* CCR */ SDTCisVT<2, i8> |
| ]>; |
| |
| |
| def MxSDT_SEG_ALLOCA : SDTypeProfile<1, 1,[ |
| /* MEM */ SDTCisVT<0, iPTR>, |
| /* SIZE */ SDTCisVT<1, iPTR> |
| ]>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Nodes |
| //===----------------------------------------------------------------------===// |
| |
| def MxCallSeqStart : SDNode<"ISD::CALLSEQ_START", MxSDT_CallSeqStart, |
| [SDNPHasChain, SDNPOutGlue]>; |
| |
| def MxCallSeqEnd : SDNode<"ISD::CALLSEQ_END", MxSDT_CallSeqEnd, |
| [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; |
| |
| def MxCall : SDNode<"M68kISD::CALL", MxSDT_Call, |
| [SDNPHasChain, SDNPOutGlue, |
| SDNPOptInGlue, SDNPVariadic]>; |
| |
| def MxRet : SDNode<"M68kISD::RET", MxSDT_Ret, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| |
| def MxTCRet : SDNode<"M68kISD::TC_RETURN", MxSDT_TCRet, |
| [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; |
| |
| def MxWrapper : SDNode<"M68kISD::Wrapper", MxSDT_Wrapper>; |
| def MxWrapperPC : SDNode<"M68kISD::WrapperPC", MxSDT_Wrapper>; |
| |
| def MxAdd : SDNode<"M68kISD::ADD", MxSDT_BiArithCCROut, [SDNPCommutative]>; |
| def MxSub : SDNode<"M68kISD::SUB", MxSDT_BiArithCCROut>; |
| def MxOr : SDNode<"M68kISD::OR", MxSDT_BiArithCCROut, [SDNPCommutative]>; |
| def MxXor : SDNode<"M68kISD::XOR", MxSDT_BiArithCCROut, [SDNPCommutative]>; |
| def MxAnd : SDNode<"M68kISD::AND", MxSDT_BiArithCCROut, [SDNPCommutative]>; |
| |
| def MxAddX : SDNode<"M68kISD::ADDX", MxSDT_BiArithCCRInOut>; |
| def MxSubX : SDNode<"M68kISD::SUBX", MxSDT_BiArithCCRInOut>; |
| |
| def MxSMul : SDNode<"M68kISD::SMUL", MxSDT_BiArithCCROut, [SDNPCommutative]>; |
| def MxUMul : SDNode<"M68kISD::UMUL", MxSDT_2BiArithCCROut, [SDNPCommutative]>; |
| |
| def MxCmp : SDNode<"M68kISD::CMP", MxSDT_CmpTest>; |
| def MxBtst : SDNode<"M68kISD::BTST", MxSDT_CmpTest>; |
| |
| def MxCmov : SDNode<"M68kISD::CMOV", MxSDT_Cmov>; |
| def MxBrCond : SDNode<"M68kISD::BRCOND", MxSDT_BrCond, [SDNPHasChain]>; |
| def MxSetCC : SDNode<"M68kISD::SETCC", MxSDT_SetCC>; |
| def MxSetCC_C : SDNode<"M68kISD::SETCC_CARRY", MxSDT_SetCC_C>; |
| |
| |
| def MxSegAlloca : SDNode<"M68kISD::SEG_ALLOCA", MxSDT_SEG_ALLOCA, |
| [SDNPHasChain]>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Operands |
| //===----------------------------------------------------------------------===// |
| |
| /// Size is the size of the data, either bits of a register or number of bits |
| /// addressed in memory. Size id is a letter that identifies size. |
| class MxSize<int num, string id, string full> { |
| int Num = num; |
| string Id = id; |
| string Full = full; |
| } |
| |
| def MxSize8 : MxSize<8, "b", "byte">; |
| def MxSize16 : MxSize<16, "w", "word">; |
| def MxSize32 : MxSize<32, "l", "long">; |
| |
| class MxOpClass<string name, |
| list<AsmOperandClass> superClasses = []> : AsmOperandClass { |
| let Name = name; |
| let ParserMethod = "parseMemOp"; |
| let SuperClasses = superClasses; |
| } |
| |
| def MxRegClass : MxOpClass<"Reg">; |
| // Splitting asm register class to avoid ambiguous on operands' |
| // MatchClassKind. For instance, without this separation, |
| // both ADD32dd and ADD32dr has {MCK_RegClass, MCK_RegClass} for |
| // their operands, which makes AsmParser unable to pick the correct |
| // one in a deterministic way. |
| let RenderMethod = "addRegOperands", SuperClasses = [MxRegClass]in { |
| def MxARegClass : MxOpClass<"AReg">; |
| def MxDRegClass : MxOpClass<"DReg">; |
| } |
| |
| class MxOperand<ValueType vt, MxSize size, string letter, RegisterClass rc, dag pat = (null_frag)> { |
| ValueType VT = vt; |
| string Letter = letter; |
| MxSize Size = size; |
| RegisterClass RC = rc; |
| dag Pat = pat; |
| } |
| |
| class MxRegOp<ValueType vt, |
| RegisterClass rc, |
| MxSize size, |
| string letter, |
| string pm = "printOperand"> |
| : RegisterOperand<rc, pm>, |
| MxOperand<vt, size, letter, rc> { |
| let ParserMatchClass = MxRegClass; |
| } |
| |
| // REGISTER DIRECT. The operand is in the data register specified by |
| // the effective address register field. |
| def MxXRD16 : MxRegOp<i16, XR16, MxSize16, "r">; |
| def MxXRD32 : MxRegOp<i32, XR32, MxSize32, "r">; |
| |
| def MxXRD16_TC : MxRegOp<i16, XR16_TC, MxSize16, "r">; |
| def MxXRD32_TC : MxRegOp<i32, XR32_TC, MxSize32, "r">; |
| |
| // DATA REGISTER DIRECT. The operand is in the data register specified by |
| // the effective address register field. |
| let ParserMatchClass = MxDRegClass in { |
| def MxDRD8 : MxRegOp<i8, DR8, MxSize8, "d">; |
| def MxDRD16 : MxRegOp<i16, DR16, MxSize16, "d">; |
| def MxDRD32 : MxRegOp<i32, DR32, MxSize32, "d">; |
| |
| def MxDRD16_TC : MxRegOp<i16, DR16_TC, MxSize16, "d">; |
| def MxDRD32_TC : MxRegOp<i32, DR32_TC, MxSize32, "d">; |
| } |
| |
| // ADDRESS REGISTER DIRECT. The operand is in the address register specified by |
| // the effective address register field. |
| let ParserMatchClass = MxARegClass in { |
| def MxARD16 : MxRegOp<i16, AR16, MxSize16, "a">; |
| def MxARD32 : MxRegOp<i32, AR32, MxSize32, "a">; |
| |
| def MxARD16_TC : MxRegOp<i16, AR16_TC, MxSize16, "a">; |
| def MxARD32_TC : MxRegOp<i32, AR32_TC, MxSize32, "a">; |
| } |
| |
| class MxMemOp<dag ops, MxSize size, string letter, |
| string printMethod = "printOperand", |
| AsmOperandClass parserMatchClass = ImmAsmOperand> |
| : Operand<iPTR>, MxOperand<iPTR, size, letter, ?> { |
| let PrintMethod = printMethod; |
| let MIOperandInfo = ops; |
| let ParserMatchClass = parserMatchClass; |
| let OperandType = "OPERAND_MEMORY"; |
| } |
| |
| // ADDRESS REGISTER INDIRECT. The address of the operand is in the address |
| // register specified by the register field. The reference is classified as |
| // a data reference with the exception of the jump and jump-to-subroutine |
| // instructions. |
| def MxARI : MxOpClass<"ARI">; |
| def MxARI8 : MxMemOp<(ops AR32), MxSize8, "j", "printARI8Mem", MxARI>; |
| def MxARI16 : MxMemOp<(ops AR32), MxSize16, "j", "printARI16Mem", MxARI>; |
| def MxARI32 : MxMemOp<(ops AR32), MxSize32, "j", "printARI32Mem", MxARI>; |
| |
| def MxARI8_TC : MxMemOp<(ops AR32_TC), MxSize8, "j", "printARI8Mem", MxARI>; |
| def MxARI16_TC : MxMemOp<(ops AR32_TC), MxSize16, "j", "printARI16Mem", MxARI>; |
| def MxARI32_TC : MxMemOp<(ops AR32_TC), MxSize32, "j", "printARI32Mem", MxARI>; |
| |
| // ADDRESS REGISTER INDIRECT WITH POSTINCREMENT. The address of the operand is |
| // in the address register specified by the register field. After the operand |
| // address is used, it is incremented by one, two, or four depending upon whether |
| // the size of the operand is byte, word, or long word. If the address register |
| // is the stack pointer and the operand size is byte, the address is incremented |
| // by two rather than one to keep the stack pointer on a word boundary. |
| // The reference is classified as a data reference. |
| def MxARIPI : MxOpClass<"ARIPI">; |
| def MxARIPI8 : MxMemOp<(ops AR32), MxSize8, "o", "printARIPI8Mem", MxARIPI>; |
| def MxARIPI16 : MxMemOp<(ops AR32), MxSize16, "o", "printARIPI16Mem", MxARIPI>; |
| def MxARIPI32 : MxMemOp<(ops AR32), MxSize32, "o", "printARIPI32Mem", MxARIPI>; |
| |
| def MxARIPI8_TC : MxMemOp<(ops AR32_TC), MxSize8, "o", "printARIPI8Mem", MxARIPI>; |
| def MxARIPI16_TC : MxMemOp<(ops AR32_TC), MxSize16, "o", "printARIPI16Mem", MxARIPI>; |
| def MxARIPI32_TC : MxMemOp<(ops AR32_TC), MxSize32, "o", "printARIPI32Mem", MxARIPI>; |
| |
| // ADDRESS REGISTER INDIRECT WITH PREDECREMENT. The address of the operand is in |
| // the address register specified by the register field. Before the operand |
| // address is used, it is decremented by one, two, or four depending upon whether |
| // the operand size is byte, word, or long word. If the address register is |
| // the stack pointer and the operand size is byte, the address is decremented by |
| // two rather than one to keep the stack pointer on a word boundary. |
| // The reference is classified as a data reference. |
| def MxARIPD : MxOpClass<"ARIPD">; |
| def MxARIPD8 : MxMemOp<(ops AR32), MxSize8, "e", "printARIPD8Mem", MxARIPD>; |
| def MxARIPD16 : MxMemOp<(ops AR32), MxSize16, "e", "printARIPD16Mem", MxARIPD>; |
| def MxARIPD32 : MxMemOp<(ops AR32), MxSize32, "e", "printARIPD32Mem", MxARIPD>; |
| |
| def MxARIPD8_TC : MxMemOp<(ops AR32_TC), MxSize8, "e", "printARIPD8Mem", MxARIPD>; |
| def MxARIPD16_TC : MxMemOp<(ops AR32_TC), MxSize16, "e", "printARIPD16Mem", MxARIPD>; |
| def MxARIPD32_TC : MxMemOp<(ops AR32_TC), MxSize32, "e", "printARIPD32Mem", MxARIPD>; |
| |
| // ADDRESS REGISTER INDIRECT WITH DISPLACEMENT. This addressing mode requires one |
| // word of extension. The address of the operand is the sum of the address in |
| // the address register and the sign-extended 16-bit displacement integer in the |
| // extension word. The reference is classified as a data reference with the |
| // exception of the jump and jump-to-subroutine instructions. |
| def MxARID : MxOpClass<"ARID">; |
| def MxARID8 : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize8, "p", "printARID8Mem", MxARID>; |
| def MxARID16 : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize16, "p", "printARID16Mem", MxARID>; |
| def MxARID32 : MxMemOp<(ops i16imm:$disp, AR32:$reg), MxSize32, "p", "printARID32Mem", MxARID>; |
| |
| def MxARID8_TC : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize8, "p", "printARID8Mem", MxARID>; |
| def MxARID16_TC : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize16, "p", "printARID16Mem", MxARID>; |
| def MxARID32_TC : MxMemOp<(ops i16imm:$disp, AR32_TC:$reg), MxSize32, "p", "printARID32Mem", MxARID>; |
| |
| // ADDRESS REGISTER INDIRECT WITH INDEX. This addressing mode requires one word |
| // of extension. The address of the operand is the sum of the address in the |
| // address register, the signextended displacement integer in the low order eight |
| // bits of the extension word, and the contents of the index register. |
| // The reference is classified as a data reference with the exception of the |
| // jump and jump-to-subroutine instructions |
| def MxARII : MxOpClass<"ARII">; |
| def MxARII8 : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index), |
| MxSize8, "f", "printARII8Mem", MxARII>; |
| def MxARII16 : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index), |
| MxSize16, "f", "printARII16Mem", MxARII>; |
| def MxARII32 : MxMemOp<(ops i8imm:$disp, AR32:$reg, XR32:$index), |
| MxSize32, "f", "printARII32Mem", MxARII>; |
| |
| def MxARII8_TC : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index), |
| MxSize8, "f", "printARII8Mem", MxARII>; |
| def MxARII16_TC : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index), |
| MxSize16, "f", "printARII16Mem", MxARII>; |
| def MxARII32_TC : MxMemOp<(ops i8imm:$disp, AR32_TC:$reg, XR32_TC:$index), |
| MxSize32, "f", "printARII32Mem", MxARII>; |
| |
| // ABSOLUTE SHORT ADDRESS. This addressing mode requires one word of extension. |
| // The address of the operand is the extension word. The 16-bit address is sign |
| // extended before it is used. The reference is classified as a data reference |
| // with the exception of the jump and jump-tosubroutine instructions. |
| def MxAddr : MxOpClass<"Addr">; |
| let RenderMethod = "addAddrOperands" in { |
| // This hierarchy ensures Addr8 will always be parsed |
| // before other larger-width variants. |
| def MxAddr32 : MxOpClass<"Addr32", [MxAddr]>; |
| def MxAddr16 : MxOpClass<"Addr16", [MxAddr32]>; |
| def MxAddr8 : MxOpClass<"Addr8", [MxAddr16]>; |
| } |
| |
| def MxAS8 : MxMemOp<(ops OtherVT), MxSize8, "B", "printAS8Mem", MxAddr8>; |
| def MxAS16 : MxMemOp<(ops OtherVT), MxSize16, "B", "printAS16Mem", MxAddr16>; |
| def MxAS32 : MxMemOp<(ops OtherVT), MxSize32, "B", "printAS32Mem", MxAddr32>; |
| |
| // ABSOLUTE LONG ADDRESS. This addressing mode requires two words of extension. |
| // The address of the operand is developed by the concatenation of the extension |
| // words. The high order part of the address is the first extension word; the low |
| // order part of the address is the second extension word. The reference is |
| // classified as a data reference with the exception of the jump and jump |
| // to-subroutine instructions. |
| def MxAL8 : MxMemOp<(ops OtherVT), MxSize8, "b", "printAL8Mem", MxAddr8>; |
| def MxAL16 : MxMemOp<(ops OtherVT), MxSize16, "b", "printAL16Mem", MxAddr16>; |
| def MxAL32 : MxMemOp<(ops OtherVT), MxSize32, "b", "printAL32Mem", MxAddr32>; |
| |
| def MxPCD : MxOpClass<"PCD">; |
| def MxPCI : MxOpClass<"PCI">; |
| |
| let OperandType = "OPERAND_PCREL" in { |
| // PROGRAM COUNTER WITH DISPLACEMENT. This addressing mode requires one word of |
| // extension. The address of the operand is the sum of the address in the program |
| // counter and the Sign-extended 16-bit displacement integer in the extension |
| // word. The value in the program counter is the address of the extension word. |
| // The reference is classified as a program reference. |
| def MxPCD8 : MxMemOp<(ops i16imm), MxSize8, "q", "printPCD8Mem", MxPCD>; |
| def MxPCD16 : MxMemOp<(ops i16imm), MxSize16, "q", "printPCD16Mem", MxPCD>; |
| def MxPCD32 : MxMemOp<(ops i16imm), MxSize32, "q", "printPCD32Mem", MxPCD>; |
| |
| // PROGRAM COUNTER WITH INDEX. This addressing mode requires one word of |
| // extension. The address is the sum of the address in the program counter, the |
| // sign-extended displacement integer in the lower eight bits of the extension |
| // word, and the contents of the index register. The value in the program |
| // counter is the address of the extension word. This reference is classified as |
| // a program reference. |
| def MxPCI8 : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize8, "k", "printPCI8Mem", MxPCI>; |
| def MxPCI16 : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize16, "k", "printPCI16Mem", MxPCI>; |
| def MxPCI32 : MxMemOp<(ops i8imm:$disp, XR32:$index), MxSize32, "k", "printPCI32Mem", MxPCI>; |
| } // OPERAND_PCREL |
| |
| def MxImm : AsmOperandClass { |
| let Name = "MxImm"; |
| let PredicateMethod = "isImm"; |
| let RenderMethod = "addImmOperands"; |
| let ParserMethod = "parseImm"; |
| } |
| |
| class MxOp<ValueType vt, MxSize size, string letter> |
| : Operand<vt>, |
| MxOperand<vt, size, letter, ?> { |
| let ParserMatchClass = MxImm; |
| } |
| |
| let OperandType = "OPERAND_IMMEDIATE", |
| PrintMethod = "printImmediate" in { |
| // IMMEDIATE DATA. This addressing mode requires either one or two words of |
| // extension depending on the size of the operation. |
| // Byte Operation - operand is low order byte of extension word |
| // Word Operation - operand is extension word |
| // Long Word Operation - operand is in the two extension words, |
| // high order 16 bits are in the first |
| // extension word, low order 16 bits are |
| // in the second extension word. |
| def Mxi8imm : MxOp<i8, MxSize8, "i">; |
| def Mxi16imm : MxOp<i16, MxSize16, "i">; |
| def Mxi32imm : MxOp<i32, MxSize32, "i">; |
| } // OPERAND_IMMEDIATE |
| |
| class MxBrTargetOperand<int N> : Operand<OtherVT> { |
| let OperandType = "OPERAND_PCREL"; |
| let PrintMethod = "printPCRelImm"; |
| let ParserMatchClass = !cast<AsmOperandClass>("MxAddr"#N); |
| } |
| // Branch targets have OtherVT type and print as pc-relative values. |
| def MxBrTarget8 : MxBrTargetOperand<8>; |
| def MxBrTarget16 : MxBrTargetOperand<16>; |
| def MxBrTarget32 : MxBrTargetOperand<32>; |
| |
| // Used with MOVEM |
| def MxMoveMaskClass : MxOpClass<"MoveMask">; |
| def MxMoveMask : MxOp<i16, MxSize16, "m"> { |
| let OperandType = "OPERAND_IMMEDIATE"; |
| let PrintMethod = "printMoveMask"; |
| let ParserMatchClass = MxMoveMaskClass; |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Predicates |
| //===----------------------------------------------------------------------===// |
| |
| def SmallCode : Predicate<"TM.getCodeModel() == CodeModel::Small">; |
| def KernelCode : Predicate<"TM.getCodeModel() == CodeModel::Kernel">; |
| def FarData : Predicate<"TM.getCodeModel() != CodeModel::Small &&" |
| "TM.getCodeModel() != CodeModel::Kernel">; |
| def NearData : Predicate<"TM.getCodeModel() == CodeModel::Small ||" |
| "TM.getCodeModel() == CodeModel::Kernel">; |
| def IsPIC : Predicate<"TM.isPositionIndependent()">; |
| def IsNotPIC : Predicate<"!TM.isPositionIndependent()">; |
| |
| def AtLeastM68000 : Predicate<"Subtarget->atLeastM68000()">; |
| def AtLeastM68010 : Predicate<"Subtarget->atLeastM68010()">; |
| def AtLeastM68020 : Predicate<"Subtarget->atLeastM68020()">; |
| def AtLeastM68030 : Predicate<"Subtarget->atLeastM68030()">; |
| def AtLeastM68040 : Predicate<"Subtarget->atLeastM68040()">; |
| |
| //===----------------------------------------------------------------------===// |
| // Condition Codes |
| // |
| // These MUST be kept in sync with codes enum in M68kInstrInfo.h |
| //===----------------------------------------------------------------------===// |
| |
| def MxCONDt : PatLeaf<(i8 0)>; // True |
| def MxCONDf : PatLeaf<(i8 1)>; // False |
| def MxCONDhi : PatLeaf<(i8 2)>; // High |
| def MxCONDls : PatLeaf<(i8 3)>; // Less or Same |
| def MxCONDcc : PatLeaf<(i8 4)>; // Carry Clear |
| def MxCONDcs : PatLeaf<(i8 5)>; // Carry Set |
| def MxCONDne : PatLeaf<(i8 6)>; // Not Equal |
| def MxCONDeq : PatLeaf<(i8 7)>; // Equal |
| def MxCONDvc : PatLeaf<(i8 8)>; // Overflow Clear |
| def MxCONDvs : PatLeaf<(i8 9)>; // Overflow Set |
| def MxCONDpl : PatLeaf<(i8 10)>; // Plus |
| def MxCONDmi : PatLeaf<(i8 11)>; // Minus |
| def MxCONDge : PatLeaf<(i8 12)>; // Greater or Equal |
| def MxCONDlt : PatLeaf<(i8 13)>; // Less Than |
| def MxCONDgt : PatLeaf<(i8 14)>; // Greater Than |
| def MxCONDle : PatLeaf<(i8 15)>; // Less or Equal |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Complex Patterns |
| //===----------------------------------------------------------------------===// |
| |
| // NOTE Though this CP is not strictly necessarily it will simplify instruciton |
| // definitions |
| def MxCP_ARI : ComplexPattern<iPTR, 1, "SelectARI", |
| [], [SDNPWantParent]>; |
| |
| def MxCP_ARIPI : ComplexPattern<iPTR, 1, "SelectARIPI", |
| [], [SDNPWantParent]>; |
| |
| def MxCP_ARIPD : ComplexPattern<iPTR, 1, "SelectARIPD", |
| [], [SDNPWantParent]>; |
| |
| def MxCP_ARID : ComplexPattern<iPTR, 2, "SelectARID", |
| [add, sub, mul, or, shl, frameindex], |
| [SDNPWantParent]>; |
| |
| def MxCP_ARII : ComplexPattern<iPTR, 3, "SelectARII", |
| [add, sub, mul, or, shl, frameindex], |
| [SDNPWantParent]>; |
| |
| def MxCP_AL : ComplexPattern<iPTR, 1, "SelectAL", |
| [add, sub, mul, or, shl], |
| [SDNPWantParent]>; |
| |
| def MxCP_PCD : ComplexPattern<iPTR, 1, "SelectPCD", |
| [add, sub, mul, or, shl], |
| [SDNPWantParent]>; |
| |
| def MxCP_PCI : ComplexPattern<iPTR, 2, "SelectPCI", |
| [add, sub, mul, or, shl], [SDNPWantParent]>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Pattern Fragments |
| //===----------------------------------------------------------------------===// |
| |
| def MximmSExt8 : PatLeaf<(i8 imm)>; |
| def MximmSExt16 : PatLeaf<(i16 imm)>; |
| def MximmSExt32 : PatLeaf<(i32 imm)>; |
| |
| // Used for Shifts and Rotations, since M68k immediates in these instructions |
| // are 1 <= i <= 8. Generally, if immediate is bigger than 8 it will be moved |
| // to a register and then an operation is performed. |
| // |
| // TODO Need to evaluate whether splitting one big shift(or rotate) |
| // into a few smaller is faster than doing a move, if so do custom lowering |
| def Mximm8_1to8 : ImmLeaf<i8, [{ return Imm >= 1 && Imm <= 8; }]>; |
| def Mximm16_1to8 : ImmLeaf<i16, [{ return Imm >= 1 && Imm <= 8; }]>; |
| def Mximm32_1to8 : ImmLeaf<i32, [{ return Imm >= 1 && Imm <= 8; }]>; |
| |
| // Helper fragments for loads. |
| // It's always safe to treat a anyext i16 load as a i32 load if the i16 is |
| // known to be 32-bit aligned or better. Ditto for i8 to i16. |
| def Mxloadi16 : PatFrag<(ops node:$ptr), (i16 (unindexedload node:$ptr)), [{ |
| LoadSDNode *LD = cast<LoadSDNode>(N); |
| ISD::LoadExtType ExtType = LD->getExtensionType(); |
| if (ExtType == ISD::NON_EXTLOAD) |
| return true; |
| if (ExtType == ISD::EXTLOAD) |
| return LD->getAlign() >= 2 && !LD->isSimple(); |
| return false; |
| }]>; |
| |
| def Mxloadi32 : PatFrag<(ops node:$ptr), (i32 (unindexedload node:$ptr)), [{ |
| LoadSDNode *LD = cast<LoadSDNode>(N); |
| ISD::LoadExtType ExtType = LD->getExtensionType(); |
| if (ExtType == ISD::NON_EXTLOAD) |
| return true; |
| if (ExtType == ISD::EXTLOAD) |
| return LD->getAlign() >= 4 && !LD->isSimple(); |
| return false; |
| }]>; |
| |
| def Mxloadi8 : PatFrag<(ops node:$ptr), (i8 (load node:$ptr))>; |
| |
| def MxSExtLoadi16i8 : PatFrag<(ops node:$ptr), (i16 (sextloadi8 node:$ptr))>; |
| def MxSExtLoadi32i8 : PatFrag<(ops node:$ptr), (i32 (sextloadi8 node:$ptr))>; |
| def MxSExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (sextloadi16 node:$ptr))>; |
| |
| def MxZExtLoadi8i1 : PatFrag<(ops node:$ptr), (i8 (zextloadi1 node:$ptr))>; |
| def MxZExtLoadi16i1 : PatFrag<(ops node:$ptr), (i16 (zextloadi1 node:$ptr))>; |
| def MxZExtLoadi32i1 : PatFrag<(ops node:$ptr), (i32 (zextloadi1 node:$ptr))>; |
| def MxZExtLoadi16i8 : PatFrag<(ops node:$ptr), (i16 (zextloadi8 node:$ptr))>; |
| def MxZExtLoadi32i8 : PatFrag<(ops node:$ptr), (i32 (zextloadi8 node:$ptr))>; |
| def MxZExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (zextloadi16 node:$ptr))>; |
| |
| def MxExtLoadi8i1 : PatFrag<(ops node:$ptr), (i8 (extloadi1 node:$ptr))>; |
| def MxExtLoadi16i1 : PatFrag<(ops node:$ptr), (i16 (extloadi1 node:$ptr))>; |
| def MxExtLoadi32i1 : PatFrag<(ops node:$ptr), (i32 (extloadi1 node:$ptr))>; |
| def MxExtLoadi16i8 : PatFrag<(ops node:$ptr), (i16 (extloadi8 node:$ptr))>; |
| def MxExtLoadi32i8 : PatFrag<(ops node:$ptr), (i32 (extloadi8 node:$ptr))>; |
| def MxExtLoadi32i16 : PatFrag<(ops node:$ptr), (i32 (extloadi16 node:$ptr))>; |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Type Fixtures |
| // |
| // Type Fixtures are ValueType related information sets that usually go together |
| //===----------------------------------------------------------------------===// |
| |
| // TODO make it folded like MxType8.F.Op nad MxType8.F.Pat |
| // TODO move strings into META subclass |
| // vt: Type of data this fixture refers to |
| // prefix: Prefix used to identify type |
| // postfix: Prefix used to qualify type |
| class MxType<ValueType vt, string prefix, string postfix, |
| // rLet: Register letter |
| // rOp: Supported any register operand |
| string rLet, MxOperand rOp, |
| // jOp: Supported ARI operand |
| // jPat: What ARI pattern to use |
| MxOperand jOp, ComplexPattern jPat, |
| // oOp: Supported ARIPI operand |
| // oPat: What ARIPI pattern is used |
| MxOperand oOp, ComplexPattern oPat, |
| // eOp: Supported ARIPD operand |
| // ePat: What ARIPD pattern is used |
| MxOperand eOp, ComplexPattern ePat, |
| // pOp: Supported ARID operand |
| // pPat: What ARID pattern is used |
| MxOperand pOp, ComplexPattern pPat, |
| // fOp: Supported ARII operand |
| // fPat: What ARII pattern is used |
| MxOperand fOp, ComplexPattern fPat, |
| // bOp: Supported absolute operand |
| // bPat: What absolute pattern is used |
| MxOperand bOp, ComplexPattern bPat, |
| // qOp: Supported PCD operand |
| // qPat: What PCD pattern is used |
| MxOperand qOp, ComplexPattern qPat, |
| // kOp: Supported PCI operand |
| // kPat: What PCI pattern is used |
| MxOperand kOp, ComplexPattern kPat, |
| // iOp: Supported immediate operand |
| // iPat: What immediate pattern is used |
| MxOperand iOp, PatFrag iPat, |
| // load: What load operation is used with MEM |
| PatFrag load> { |
| int Size = vt.Size; |
| ValueType VT = vt; |
| string Prefix = prefix; |
| string Postfix = postfix; |
| |
| string RLet = rLet; |
| MxOperand ROp = rOp; |
| |
| MxOperand JOp = jOp; |
| ComplexPattern JPat = jPat; |
| |
| MxOperand OOp = oOp; |
| ComplexPattern OPat = oPat; |
| |
| MxOperand EOp = eOp; |
| ComplexPattern EPat = ePat; |
| |
| MxOperand POp = pOp; |
| ComplexPattern PPat = pPat; |
| |
| MxOperand FOp = fOp; |
| ComplexPattern FPat = fPat; |
| |
| MxOperand BOp = bOp; |
| ComplexPattern BPat = bPat; |
| |
| MxOperand QOp = qOp; |
| ComplexPattern QPat = qPat; |
| |
| MxOperand KOp = kOp; |
| ComplexPattern KPat = kPat; |
| |
| MxOperand IOp = iOp; |
| PatFrag IPat = iPat; |
| |
| PatFrag Load = load; |
| } |
| |
| // Provides an alternative way to access the MxOperand and |
| // patterns w.r.t a specific addressing mode. |
| class MxOpBundle<int size, MxOperand op, ComplexPattern pat> { |
| int Size = size; |
| MxOperand Op = op; |
| ComplexPattern Pat = pat; |
| } |
| |
| class MxImmOpBundle<int size, MxOperand op, PatFrag pat> |
| : MxOpBundle<size, op, ?> { |
| PatFrag ImmPat = pat; |
| } |
| |
| // TODO: We can use MxOp<S>AddrMode_<AM> in more places to |
| // replace MxType-based operand factoring. |
| foreach size = [8, 16, 32] in { |
| // Dn |
| def MxOp#size#AddrMode_d |
| : MxOpBundle<size, !cast<MxOperand>("MxDRD"#size), ?>; |
| |
| // (An) |
| def MxOp#size#AddrMode_j |
| : MxOpBundle<size, !cast<MxOperand>("MxARI"#size), MxCP_ARI>; |
| |
| // (An)+ |
| def MxOp#size#AddrMode_o |
| : MxOpBundle<size, !cast<MxOperand>("MxARIPI"#size), MxCP_ARIPI>; |
| |
| // -(An) |
| def MxOp#size#AddrMode_e |
| : MxOpBundle<size, !cast<MxOperand>("MxARIPD"#size), MxCP_ARIPD>; |
| |
| // (i,An) |
| def MxOp#size#AddrMode_p |
| : MxOpBundle<size, !cast<MxOperand>("MxARID"#size), MxCP_ARID>; |
| |
| // (i,An,Xn) |
| def MxOp#size#AddrMode_f |
| : MxOpBundle<size, !cast<MxOperand>("MxARII"#size), MxCP_ARII>; |
| |
| // (ABS).L |
| def MxOp#size#AddrMode_b |
| : MxOpBundle<size, !cast<MxOperand>("MxAL"#size), MxCP_AL>; |
| |
| // (i,PC) |
| def MxOp#size#AddrMode_q |
| : MxOpBundle<size, !cast<MxOperand>("MxPCD"#size), MxCP_PCD>; |
| |
| // (i,PC,Xn) |
| def MxOp#size#AddrMode_k |
| : MxOpBundle<size, !cast<MxOperand>("MxPCI"#size), MxCP_PCI>; |
| |
| // #imm |
| def MxOp#size#AddrMode_i |
| : MxImmOpBundle<size, !cast<MxOperand>("Mxi"#size#"imm"), |
| !cast<PatFrag>("MximmSExt"#size)>; |
| } // foreach size = [8, 16, 32] |
| |
| foreach size = [16, 32] in { |
| // An |
| def MxOp#size#AddrMode_a |
| : MxOpBundle<size, !cast<MxOperand>("MxARD"#size), ?>; |
| |
| // Xn |
| def MxOp#size#AddrMode_r |
| : MxOpBundle<size, !cast<MxOperand>("MxXRD"#size), ?>; |
| } // foreach size = [16, 32] |
| |
| class MxType8Class<string rLet, MxOperand reg> |
| : MxType<i8, "b", "", rLet, reg, |
| MxARI8, MxCP_ARI, |
| MxARIPI8, MxCP_ARIPI, |
| MxARIPD8, MxCP_ARIPD, |
| MxARID8, MxCP_ARID, |
| MxARII8, MxCP_ARII, |
| MxAL8, MxCP_AL, |
| MxPCD8, MxCP_PCD, |
| MxPCI8, MxCP_PCI, |
| Mxi8imm, MximmSExt8, |
| Mxloadi8>; |
| |
| def MxType8 : MxType8Class<?,?>; |
| |
| class MxType16Class<string rLet, MxOperand reg> |
| : MxType<i16, "w", "", rLet, reg, |
| MxARI16, MxCP_ARI, |
| MxARIPI16, MxCP_ARIPI, |
| MxARIPD16, MxCP_ARIPD, |
| MxARID16, MxCP_ARID, |
| MxARII16, MxCP_ARII, |
| MxAL16, MxCP_AL, |
| MxPCD16, MxCP_PCD, |
| MxPCI16, MxCP_PCI, |
| Mxi16imm, MximmSExt16, |
| Mxloadi16>; |
| |
| def MxType16 : MxType16Class<?,?>; |
| |
| class MxType32Class<string rLet, MxOperand reg> |
| : MxType<i32, "l", "", rLet, reg, |
| MxARI32, MxCP_ARI, |
| MxARIPI32, MxCP_ARIPI, |
| MxARIPD32, MxCP_ARIPD, |
| MxARID32, MxCP_ARID, |
| MxARII32, MxCP_ARII, |
| MxAL32, MxCP_AL, |
| MxPCD32, MxCP_PCD, |
| MxPCI32, MxCP_PCI, |
| Mxi32imm, MximmSExt32, |
| Mxloadi32>; |
| |
| def MxType32 : MxType32Class<?,?>; |
| |
| |
| def MxType8d : MxType8Class<"d", MxDRD8>; |
| |
| def MxType16d : MxType16Class<"d", MxDRD16>; |
| def MxType16a : MxType16Class<"a", MxARD16>; |
| def MxType16r : MxType16Class<"r", MxXRD16>; |
| def MxType32d : MxType32Class<"d", MxDRD32>; |
| def MxType32a : MxType32Class<"a", MxARD32>; |
| def MxType32r : MxType32Class<"r", MxXRD32>; |
| |
| let Postfix = "_TC" in { |
| def MxType16d_TC : MxType16Class<"d", MxDRD16_TC>; |
| def MxType16a_TC : MxType16Class<"a", MxARD16_TC>; |
| def MxType16r_TC : MxType16Class<"r", MxXRD16_TC>; |
| def MxType32d_TC : MxType32Class<"d", MxDRD32_TC>; |
| def MxType32a_TC : MxType32Class<"a", MxARD32_TC>; |
| def MxType32r_TC : MxType32Class<"r", MxXRD32_TC>; |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Subsystems |
| //===----------------------------------------------------------------------===// |
| |
| include "M68kInstrData.td" |
| include "M68kInstrShiftRotate.td" |
| include "M68kInstrBits.td" |
| include "M68kInstrArithmetic.td" |
| include "M68kInstrControl.td" |
| include "M68kInstrAtomics.td" |
| |
| include "M68kInstrCompiler.td" |