//===-- CSKYInstrInfo.td - Target Description for CSKY -----*- 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 CSKY instructions in TableGen format. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // CSKY specific DAG Nodes. //===----------------------------------------------------------------------===// // Target-dependent nodes. def CSKY_RET : SDNode<"CSKYISD::RET", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; //===----------------------------------------------------------------------===// // Operand and SDNode transformation definitions. //===----------------------------------------------------------------------===// class ImmAsmOperand : AsmOperandClass { let Name = prefix # "Imm" # width # suffix; let RenderMethod = "addImmOperands"; let DiagnosticType = !strconcat("Invalid", Name); } class SImmAsmOperand : ImmAsmOperand<"S", width, suffix> { } class UImmAsmOperand : ImmAsmOperand<"U", width, suffix> { } class OImmAsmOperand : ImmAsmOperand<"O", width, suffix> { } class oimm : Operand, ImmLeaf(Imm - 1);"> { let EncoderMethod = "getOImmOpValue"; let ParserMatchClass = OImmAsmOperand; } class uimm : Operand, ImmLeaf(Imm);"> { let EncoderMethod = "getImmOpValue<"#shift#">"; let ParserMatchClass = !if(!ne(shift, 0), UImmAsmOperand, UImmAsmOperand); } class simm : Operand, ImmLeaf(Imm);"> { let EncoderMethod = "getImmOpValue<"#shift#">"; let ParserMatchClass = SImmAsmOperand; } def nimm_XFORM : SDNodeXFormgetTargetConstant(~N->getSExtValue(), SDLoc(N), MVT::i32); }]>; class nimm : Operand, ImmLeaf(~Imm);", nimm_XFORM> { let ParserMatchClass = UImmAsmOperand; } def uimm32_hi16 : SDNodeXFormgetTargetConstant((N->getZExtValue() >> 16) & 0xFFFF, SDLoc(N), MVT::i32); }]>; def uimm16_16_xform : Operand, ImmLeaf(Imm);", uimm32_hi16> { let ParserMatchClass = UImmAsmOperand<16>; } def uimm_shift : Operand, ImmLeaf(Imm);"> { let EncoderMethod = "getImmShiftOpValue"; let ParserMatchClass = UImmAsmOperand<2>; } def CSKYSymbol : AsmOperandClass { let Name = "CSKYSymbol"; let RenderMethod = "addImmOperands"; let DiagnosticType = "InvalidCSKYSymbol"; let ParserMethod = "parseCSKYSymbol"; } def br_symbol : Operand { let EncoderMethod = "getBranchSymbolOpValue"; let ParserMatchClass = CSKYSymbol; } def call_symbol : Operand { let ParserMatchClass = CSKYSymbol; let EncoderMethod = "getCallSymbolOpValue"; } def Constpool : AsmOperandClass { let Name = "ConstpoolSymbol"; let RenderMethod = "addImmOperands"; let DiagnosticType = "InvalidConstpool"; let ParserMethod = "parseConstpoolSymbol"; } def constpool_symbol : Operand { let ParserMatchClass = Constpool; let EncoderMethod = "getConstpoolSymbolOpValue"; } def bare_symbol : Operand { let ParserMatchClass = CSKYSymbol; let EncoderMethod = "getBareSymbolOpValue"; } def oimm12 : oimm<12>; def oimm16 : oimm<16>; def nimm12 : nimm<12>; def uimm5 : uimm<5>; def uimm12 : uimm<12>; def uimm12_1 : uimm<12, 1>; def uimm12_2 : uimm<12, 2>; def uimm16 : uimm<16>; //===----------------------------------------------------------------------===// // Instruction Formats //===----------------------------------------------------------------------===// include "CSKYInstrFormats.td" //===----------------------------------------------------------------------===// // Instruction definitions. //===----------------------------------------------------------------------===// class TriOpFrag : PatFrag<(ops node: $LHS, node:$MHS, node:$RHS), res>; class BinOpFrag : PatFrag<(ops node:$LHS, node:$RHS), res>; class UnOpFrag : PatFrag<(ops node:$Src), res>; //===----------------------------------------------------------------------===// // Basic ALU instructions. //===----------------------------------------------------------------------===// def ADDI32 : I_12<0x0, "addi32", add, oimm12>; def SUBI32 : I_12<0x1, "subi32", sub, oimm12>; def ORI32 : I_16_ZX<"ori32", uimm16, [(set GPR:$rz, (or GPR:$rx, uimm16:$imm16))]>; def XORI32 : I_12<0x4, "xori32", xor, uimm12>; def ANDI32 : I_12<0x2, "andi32", and, uimm12>; def ANDNI32 : I_12<0x3, "andni32", and, nimm12>; def LSLI32 : I_5_XZ<0x12, 0x1, "lsli32", (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5), [(set GPR:$rz, (shl GPR:$rx, uimm5:$imm5))]>; def LSRI32 : I_5_XZ<0x12, 0x2, "lsri32", (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5), [(set GPR:$rz, (srl GPR:$rx, uimm5:$imm5))]>; def ASRI32 : I_5_XZ<0x12, 0x4, "asri32", (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5), [(set GPR:$rz, (sra GPR:$rx, uimm5:$imm5))]>; def ROTLI32 : I_5_XZ<0x12, 0x8, "rotli32", (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5), [(set GPR:$rz, (rotl GPR:$rx, uimm5:$imm5))]>; def ADDU32 : R_YXZ_SP_F1<0x0, 0x1, BinOpFrag<(add node:$LHS, node:$RHS)>, "addu32", 1>; def SUBU32 : R_YXZ_SP_F1<0x0, 0x4, BinOpFrag<(sub node:$LHS, node:$RHS)>, "subu32">; def MULT32 : R_YXZ_SP_F1<0x21, 0x1, BinOpFrag<(mul node:$LHS, node:$RHS)>, "mult32", 1>; def AND32 : R_YXZ_SP_F1<0x8, 0x1, BinOpFrag<(and node:$LHS, node:$RHS)>, "and32", 1>; def ANDN32 : R_YXZ_SP_F1<0x8, 0x2, BinOpFrag<(and node:$LHS, (not node:$RHS))>, "andn32">; def OR32: R_YXZ_SP_F1<0x9, 0x1, BinOpFrag<(or node:$LHS, node:$RHS)>, "or32", 1>; def XOR32 : R_YXZ_SP_F1<0x9, 0x2, BinOpFrag<(xor node:$LHS, node:$RHS)>, "xor32", 1>; def NOR32 : R_YXZ_SP_F1<0x9, 0x4, BinOpFrag<(not (or node:$LHS, node:$RHS))>, "nor32", 1>; def NOT32 : R_XXZ<0b001001, 0b00100, (outs GPR:$rz), (ins GPR:$rx), "not32", [(set GPR:$rz, (not GPR:$rx))]>; def LSL32 : R_YXZ_SP_F1<0x10, 0x1, BinOpFrag<(shl node:$LHS, node:$RHS)>, "lsl32">; def LSR32 : R_YXZ_SP_F1<0x10, 0x2, BinOpFrag<(srl node:$LHS, node:$RHS)>, "lsr32">; def ASR32 : R_YXZ_SP_F1<0x10, 0x4, BinOpFrag<(sra node:$LHS, node:$RHS)>, "asr32">; def ROTL32 : R_YXZ_SP_F1<0x10, 0x8, BinOpFrag<(rotl node:$LHS, (and node:$RHS, 0x1f))>, "rotl32">; // TODO: Shift series instr. with carry. def IXH32 : R_YXZ_SP_F1<0x2, 0x1, BinOpFrag<(add node:$LHS, (shl node:$RHS, (i32 1)))>, "ixh32">; def IXW32 : R_YXZ_SP_F1<0x2, 0x2, BinOpFrag<(add node:$LHS, (shl node:$RHS, (i32 2)))>, "ixw32">; def IXD32 : R_YXZ_SP_F1<0x2, 0x4, BinOpFrag<(add node:$LHS, (shl node:$RHS, (i32 3)))>, "ixd32">; let isCommutable = 1 in def ADDC32 : R_YXZ<0x31, 0x0, 0x2, (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, GPR:$ry, CARRY:$cin), "addc32", []>; def SUBC32 : R_YXZ<0x31, 0x0, 0x8, (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, GPR:$ry, CARRY:$cin), "subc32", []>; // TODO: incf32. def DIVS32 : R_YXZ_SP_F1<0x20, 0x2, BinOpFrag<(sdiv node:$LHS, node:$RHS)>, "divs32">; def DIVU32 : R_YXZ_SP_F1<0x20, 0x1, BinOpFrag<(udiv node:$LHS, node:$RHS)>, "divu32">; def DECGT32 : I_5_XZ<0x4, 0x1, "decgt32", (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, uimm5:$imm5), []>; def DECLT32 : I_5_XZ<0x4, 0x2, "declt32", (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, uimm5:$imm5), []>; def DECNE32 : I_5_XZ<0x4, 0x4, "decne32", (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, uimm5:$imm5), []>; // TODO: s/zext. def ZEXT32 : I_5_XZ_U<0x15, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "zext32",[]>; def SEXT32 : I_5_XZ_U<0x16, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "sext32", []>; //===----------------------------------------------------------------------===// // Load & Store instructions. //===----------------------------------------------------------------------===// def LD32B : I_LD; def LD32H : I_LD; def LD32W : I_LD; def LD32BS : I_LD; def LD32HS : I_LD; // TODO: LDM and STM. def ST32B : I_ST; def ST32H : I_ST; def ST32W : I_ST; def LDR32B : I_LDR<0x0, "ldr32.b">; def LDR32BS : I_LDR<0x4, "ldr32.bs">; def LDR32H : I_LDR<0x1, "ldr32.h">; def LDR32HS : I_LDR<0x5, "ldr32.hs">; def LDR32W : I_LDR<0x2, "ldr32.w">; def STR32B : I_STR<0x0, "str32.b">; def STR32H : I_STR<0x1, "str32.h">; def STR32W : I_STR<0x2, "str32.w">; //TODO: SPILL_CARRY and RESTORE_CARRY. //===----------------------------------------------------------------------===// // Compare instructions. //===----------------------------------------------------------------------===// def CMPNEI32 : I_16_X<0x1A, "cmpnei32", uimm16>; def CMPHSI32 : I_16_X<0x18, "cmphsi32", oimm16>; def CMPLTI32 : I_16_X<0x19, "cmplti32", oimm16>; def CMPNE32 : R_YX<0x1, 0x4, "cmpne32">; def CMPHS32 : R_YX<0x1, 0x1, "cmphs32">; def CMPLT32 : R_YX<0x1, 0x2, "cmplt32">; // TODO: setc and clrc. // TODO: test32 and tstnbz. //===----------------------------------------------------------------------===// // Data move instructions. //===----------------------------------------------------------------------===// def MOVT32 : R_ZX<0x3, 0x2, "movt32", []>; def MOVF32 : R_ZX<0x3, 0x1, "movf32", []>; def MOVI32 : I_16_MOV<0x10, "movi32", uimm16>; def MOVIH32 : I_16_MOV<0x11, "movih32", uimm16_16_xform>; def MVC32 : R_Z_1<0x1, 0x8, "mvc32">; def MOV32 : R_XZ<0x12, 0x1, "mov32">; // TODO: ISEL Pseudo. def MVCV32 : R_Z_1<0x1, 0x10, "mvcv32">; // TODO: clrf and clrt. def CLRF32 : R_Z_2<0xB, 0x1, "clrf32", []>; def CLRT32 : R_Z_2<0xB, 0x2, "clrt32", []>; //===----------------------------------------------------------------------===// // Branch and call instructions. //===----------------------------------------------------------------------===// let isBranch = 1, isTerminator = 1 in { let isBarrier = 1, isPredicable = 1 in def BR32 : I_16_L<0x0, (outs), (ins br_symbol:$imm16), "br32\t$imm16", [(br bb:$imm16)]>; def BT32 : I_16_L<0x3, (outs), (ins CARRY:$ca, br_symbol:$imm16), "bt32\t$imm16", [(brcond CARRY:$ca, bb:$imm16)]>; def BF32 : I_16_L<0x2, (outs), (ins CARRY:$ca, br_symbol:$imm16), "bf32\t$imm16", []>; } def BEZ32 : I_16_X_L<0x8, "bez32", br_symbol>; def BNEZ32 : I_16_X_L<0x9, "bnez32", br_symbol>; def BHZ32 : I_16_X_L<0xA, "bhz32", br_symbol>; def BLSZ32 : I_16_X_L<0xB, "blsz32", br_symbol>; def BLZ32 : I_16_X_L<0xC, "blz32", br_symbol>; def BHSZ32 : I_16_X_L<0xD, "bhsz32", br_symbol>; let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in { def JMP32 : I_16_JX<0x6, "jmp32", [(brind GPR:$rx)]>; // jmp to register def JMPI32 : I_16_L<0x16, (outs), (ins constpool_symbol:$imm16), "jmpi32\t$imm16", []>; } let isCall = 1, Defs = [ R15 ] in def JSR32 : I_16_JX<0x7, "jsr32", []>; let isCall = 1, Defs = [ R15 ] , mayLoad = 1 in def JSRI32: I_16_L<0x17, (outs), (ins constpool_symbol:$imm16), "jsri32\t$imm16", []>; def BSR32 : J<0x38, (outs), (ins call_symbol:$offset), "bsr32", []>; def BSR32_BR : J<0x38, (outs), (ins call_symbol:$offset), "bsr32", []>{ let isCodeGenOnly = 1; let isBranch = 1; let isTerminator = 1; let isBarrier = 1; let isPredicable = 1; let Defs = [ R15 ]; } def RTS32 : I_16_RET<0x6, 0xF, "rts32", [(CSKY_RET)]>; def RTE32 : I_16_RET_I<0, 0, "rte32", []>; //===----------------------------------------------------------------------===// // Symbol address instructions. //===----------------------------------------------------------------------===// def GRS32 : I_18_Z_L<0x3, "grs32\t$rz, $offset", (outs GPR:$rz), (ins bare_symbol:$offset), []>; let mayLoad = 1, mayStore = 0 in { def LRW32 : I_16_Z_L<0x14, "lrw32", (ins constpool_symbol:$imm16), []>; let isCodeGenOnly = 1 in def LRW32_Gen : I_16_Z_L<0x14, "lrw32", (ins bare_symbol:$src1, constpool_symbol:$imm16), []>; } // TODO: Atomic and fence instructions. // TODO: Other operations. // TODO: Special instructions. // TODO: Pseudo for assembly.