//===-- LanaiInstrInfo.td - Target Description for Lanai Target -----------===// // // 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 Lanai instructions in TableGen format. // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Instruction format superclass //===----------------------------------------------------------------------===// include "LanaiInstrFormats.td" // -------------------------------------------------- // // Instruction Operands and Patterns // -------------------------------------------------- // // These are target-independent nodes, but have target-specific formats. def SDT_LanaiCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def SDT_LanaiCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def SDT_LanaiCall : SDTypeProfile<0, -1, [SDTCisVT<0, i32>]>; def SDT_LanaiSetFlag : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; def SDT_LanaiSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>]>; def SDT_LanaiSetCC : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def SDT_LanaiBrCC : SDTypeProfile<0, 2, [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>]>; def SDT_LanaiAdjDynAlloc : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVT<1, i32>]>; def Call : SDNode<"LanaiISD::CALL", SDT_LanaiCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; def RetFlag : SDNode<"LanaiISD::RET_FLAG", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; def CallSeqStart : SDNode<"ISD::CALLSEQ_START", SDT_LanaiCallSeqStart, [SDNPHasChain, SDNPOutGlue]>; def CallSeqEnd : SDNode<"ISD::CALLSEQ_END", SDT_LanaiCallSeqEnd, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; def LanaiSetFlag : SDNode<"LanaiISD::SET_FLAG", SDT_LanaiSetFlag, [SDNPOutGlue]>; def LanaiSubbF : SDNode<"LanaiISD::SUBBF", SDT_LanaiSetFlag, [SDNPOutGlue, SDNPInGlue]>; def LanaiBrCC : SDNode<"LanaiISD::BR_CC", SDT_LanaiBrCC, [SDNPHasChain, SDNPInGlue]>; def LanaiSelectCC : SDNode<"LanaiISD::SELECT_CC", SDT_LanaiSelectCC, [SDNPInGlue]>; def LanaiSetCC : SDNode<"LanaiISD::SETCC", SDT_LanaiSetCC, [SDNPInGlue]>; def LanaiHi : SDNode<"LanaiISD::HI", SDTIntUnaryOp>; def LanaiLo : SDNode<"LanaiISD::LO", SDTIntUnaryOp>; def LanaiSmall : SDNode<"LanaiISD::SMALL", SDTIntUnaryOp>; def LanaiAdjDynAlloc : SDNode<"LanaiISD::ADJDYNALLOC", SDT_LanaiAdjDynAlloc>; // Extract bits 0-15 (low-end) of an immediate value. def LO16 : SDNodeXForm<imm, [{ return CurDAG->getTargetConstant((uint64_t)N->getZExtValue() & 0xffff, SDLoc(N), MVT::i32); }]>; // Extract bits 16-31 (high-end) of an immediate value. // Transformation function: shift the immediate value down into the low bits. def HI16 : SDNodeXForm<imm, [{ return CurDAG->getTargetConstant((uint64_t)N->getZExtValue() >> 16, SDLoc(N), MVT::i32); }]>; def NEG : SDNodeXForm<imm, [{ return CurDAG->getTargetConstant(-N->getSExtValue(), SDLoc(N), MVT::i32); }]>; def LO21 : SDNodeXForm<imm, [{ return CurDAG->getTargetConstant((uint64_t)N->getZExtValue() & 0x1fffff, SDLoc(N), MVT::i32); }]>; // Branch targets def BrTargetAsmOperand : AsmOperandClass { let Name = "BrTarget"; } def BrTarget : Operand<OtherVT> { let ParserMatchClass = BrTargetAsmOperand; let EncoderMethod = "getBranchTargetOpValue"; let DecoderMethod = "decodeBranch"; } def CallTargetAsmOperand : AsmOperandClass { let Name = "CallTarget"; } def CallTarget : Operand<i32> { let ParserMatchClass = CallTargetAsmOperand; let EncoderMethod = "getBranchTargetOpValue"; let DecoderMethod = "decodeBranch"; } def ImmShiftAsmOperand : AsmOperandClass { let Name = "ImmShift"; } def immShift : Operand<i32>, PatLeaf<(imm), [{ int Imm = N->getSExtValue(); return Imm >= -31 && Imm <= 31;}]> { let ParserMatchClass = ImmShiftAsmOperand; let DecoderMethod = "decodeShiftImm"; } def Imm10AsmOperand : AsmOperandClass { let Name = "Imm10"; } def imm10 : Operand<i32>, PatLeaf<(imm), [{ return isInt<10>(N->getSExtValue()); }]> { let ParserMatchClass = Imm10AsmOperand; } def LoImm16AsmOperand : AsmOperandClass { let Name = "LoImm16"; } def i32lo16z : Operand<i32>, PatLeaf<(i32 imm), [{ // i32lo16 predicate - true if the 32-bit immediate has only rightmost 16 // bits set. return ((N->getZExtValue() & 0xFFFFUL) == N->getZExtValue());}], LO16> { let ParserMatchClass = LoImm16AsmOperand; } def i32neg16 : Operand<i32>, PatLeaf<(i32 imm), [{ // i32neg16 predicate - true if the 32-bit immediate is negative and can // be represented by a 16 bit integer. int Imm = N->getSExtValue(); return (Imm < 0) && (isInt<16>(Imm));}], LO16> { let ParserMatchClass = LoImm16AsmOperand; } def i32lo16s : Operand<i32>, PatLeaf<(i32 imm), [{ // i32lo16 predicate - true if the 32-bit immediate has only rightmost 16 // bits set. return ((int64_t)(N->getSExtValue() & 0xFFFFUL) == N->getSExtValue());}], LO16> { let ParserMatchClass = LoImm16AsmOperand; } def LoImm16AndAsmOperand : AsmOperandClass { let Name = "LoImm16And"; } def i32lo16and : Operand<i32>, PatLeaf<(i32 imm), [{ // i32lo16 predicate - true if the 32-bit immediate has the rightmost 16 // bits set and the leftmost 16 bits 1's. return (N->getZExtValue() >= 0xFFFF0000UL);}], LO16> { let ParserMatchClass = LoImm16AndAsmOperand; let PrintMethod = "printLo16AndImmOperand"; } def HiImm16AsmOperand : AsmOperandClass { let Name = "HiImm16"; } def i32hi16 : Operand<i32>, PatLeaf<(i32 imm), [{ // i32hi16 predicate - true if the 32-bit immediate has only leftmost 16 // bits set. return ((N->getZExtValue() & 0xFFFF0000UL) == N->getZExtValue());}], HI16> { let ParserMatchClass = HiImm16AsmOperand; let PrintMethod = "printHi16ImmOperand"; } def HiImm16AndAsmOperand : AsmOperandClass { let Name = "HiImm16And"; } def i32hi16and : Operand<i32>, PatLeaf<(i32 imm), [{ // i32lo16 predicate - true if the 32-bit immediate has the leftmost 16 // bits set and the rightmost 16 bits 1's. return ((N->getZExtValue() & 0xFFFFUL) == 0xFFFFUL);}], HI16> { let ParserMatchClass = HiImm16AndAsmOperand; let PrintMethod = "printHi16AndImmOperand"; } def LoImm21AsmOperand : AsmOperandClass { let Name = "LoImm21"; } def i32lo21 : Operand<i32>, PatLeaf<(i32 imm), [{ // i32lo21 predicate - true if the 32-bit immediate has only rightmost 21 // bits set. return ((N->getZExtValue() & 0x1FFFFFUL) == N->getZExtValue());}], LO21> { let ParserMatchClass = LoImm21AsmOperand; } def AluOp : Operand<i32> { let PrintMethod = "printAluOperand"; } // Addressing modes. def ADDRrr : ComplexPattern<i32, 3, "selectAddrRr", [], []>; def ADDRri : ComplexPattern<i32, 3, "selectAddrRi", [frameindex], []>; def ADDRsls : ComplexPattern<i32, 1, "selectAddrSls", [frameindex], []>; def ADDRspls : ComplexPattern<i32, 3, "selectAddrSpls", [frameindex], []>; // Address operands def MemRegImmAsmOperand : AsmOperandClass { let Name = "MemRegImm"; let ParserMethod = "parseMemoryOperand"; } def MEMri : Operand<i32> { let DecoderMethod = "decodeRiMemoryValue"; let EncoderMethod = "getRiMemoryOpValue"; let MIOperandInfo = (ops GPR:$base, i32lo16s:$offset, AluOp:$Opcode); let ParserMatchClass = MemRegImmAsmOperand; let PrintMethod = "printMemRiOperand"; } def MemRegRegAsmOperand : AsmOperandClass { let Name = "MemRegReg"; let ParserMethod = "parseMemoryOperand"; } def MEMrr : Operand<i32> { let DecoderMethod = "decodeRrMemoryValue"; let EncoderMethod = "getRrMemoryOpValue"; let MIOperandInfo = (ops GPR:$Op1, GPR:$Op2, AluOp:$Opcode); let ParserMatchClass = MemRegRegAsmOperand; let PrintMethod = "printMemRrOperand"; } def MemImmAsmOperand : AsmOperandClass { let Name = "MemImm"; let ParserMethod = "parseMemoryOperand"; } def MEMi : Operand<i32> { let MIOperandInfo = (ops i32lo21:$offset); let ParserMatchClass = MemImmAsmOperand; let PrintMethod = "printMemImmOperand"; } def MemSplsAsmOperand : AsmOperandClass { let Name = "MemSpls"; let ParserMethod = "parseMemoryOperand"; } def MEMspls : Operand<i32> { let DecoderMethod = "decodeSplsValue"; let EncoderMethod = "getSplsOpValue"; let MIOperandInfo = (ops GPR:$base, imm10:$offset, AluOp:$Opcode); let ParserMatchClass = MemSplsAsmOperand; let PrintMethod = "printMemSplsOperand"; } def CCOp : Operand<i32> { let PrintMethod = "printCCOperand"; } // Predicate operand. Default to 0 = true. def CondCodeOperand : AsmOperandClass { let Name = "CondCode"; } def pred : PredicateOperand<i32, (ops i32imm), (ops (i32 0))> { let PrintMethod = "printPredicateOperand"; let ParserMatchClass = CondCodeOperand; let DecoderMethod = "decodePredicateOperand"; } let hasSideEffects = 0, Inst = 0x00000001 in def NOP : InstLanai<(outs), (ins), "nop", []>; // Special NOPs to change logging level in vlanai. let hasSideEffects = 0, Inst = 0x00000002 in def LOG0 : InstLanai<(outs), (ins), "log_0", []>; let hasSideEffects = 0, Inst = 0x00000003 in def LOG1 : InstLanai<(outs), (ins), "log_1", []>; let hasSideEffects = 0, Inst = 0x00000004 in def LOG2 : InstLanai<(outs), (ins), "log_2", []>; let hasSideEffects = 0, Inst = 0x00000005 in def LOG3 : InstLanai<(outs), (ins), "log_3", []>; let hasSideEffects = 0, Inst = 0x00000006 in def LOG4 : InstLanai<(outs), (ins), "log_4", []>; // Map an SPLS instruction onto itself. All other instructions will be mapped // onto -1. Used to identify SPLS instructions. def splsIdempotent : InstrMapping { let FilterClass = "InstSPLS"; let RowFields = ["AsmString"]; let ColFields = ["PostEncoderMethod"]; let KeyCol = ["adjustPqBitsSpls"]; let ValueCols = [["adjustPqBitsSpls"]]; } // -------------------------------------------------- // // ALU instructions // -------------------------------------------------- // multiclass ALUbase<bits<3> subOp, string AsmStr, PatLeaf LoExt, PatLeaf HiExt, list<dag> loPattern, list<dag> hiPattern> { // Register Immediate let H = 0 in def LO : InstRI<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, LoExt:$imm16), !strconcat(AsmStr, "\t$Rs1, $imm16, $Rd"), loPattern>; let H = 1 in def HI : InstRI<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, HiExt:$imm16), !strconcat(AsmStr, "\t$Rs1, $imm16, $Rd"), hiPattern>; } multiclass ALUarith<bits<3> subOp, string AsmStr, SDNode OpNode, PatLeaf LoExt, PatLeaf HiExt> { defm I_ : ALUbase<subOp, AsmStr, LoExt, HiExt, [], []>; // Register Register let JJJJJ = 0 in def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, pred:$DDDI), !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"), [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>; } multiclass ALUlogic<bits<3> subOp, string AsmStr, SDNode OpNode, PatLeaf LoExt, PatLeaf HiExt> { defm I_ : ALUbase<subOp, AsmStr, LoExt, HiExt, [(set GPR:$Rd, (OpNode GPR:$Rs1, LoExt:$imm16))], [(set GPR:$Rd, (OpNode GPR:$Rs1, HiExt:$imm16))]>; // Register Register let JJJJJ = 0 in def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, pred:$DDDI), !strconcat(AsmStr, "$DDDI\t$Rs1, $Rs2, $Rd"), [(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>; } // Non flag setting ALU operations let isAsCheapAsAMove = 1, F = 0 in { let isCommutable = 1 in { defm ADD_ : ALUarith<0b000, "add", add, i32lo16z, i32hi16>; } defm SUB_ : ALUarith<0b010, "sub", sub, i32lo16z, i32hi16>; let isCommutable = 1 in { defm AND_ : ALUlogic<0b100, "and", and, i32lo16and, i32hi16and>; defm OR_ : ALUlogic<0b101, "or", or, i32lo16z, i32hi16>; defm XOR_ : ALUlogic<0b110, "xor", xor, i32lo16z, i32hi16>; } } def : Pat<(add GPR:$Rs1, i32lo16z:$imm), (ADD_I_LO GPR:$Rs1, i32lo16z:$imm)>; def : Pat<(sub GPR:$Rs1, i32lo16z:$imm), (SUB_I_LO GPR:$Rs1, i32lo16z:$imm)>; def : Pat<(add GPR:$Rs1, i32hi16:$imm), (ADD_I_HI GPR:$Rs1, i32hi16:$imm)>; def : Pat<(sub GPR:$Rs1, i32hi16:$imm), (SUB_I_HI GPR:$Rs1, i32hi16:$imm)>; def : Pat<(i32 i32lo16and:$imm), (AND_I_LO (i32 R1), i32lo16and:$imm)>; def : Pat<(i32 i32hi16and:$imm), (AND_I_HI (i32 R1), i32hi16and:$imm)>; // Change add/sub with negative number to sub/add def : Pat<(add GPR:$Rs1, i32neg16:$imm), (SUB_I_LO GPR:$Rs1, (NEG $imm))>; def : Pat<(sub GPR:$Rs1, i32neg16:$imm), (ADD_I_LO GPR:$Rs1, (NEG $imm))>; // Flag (incl. carry) setting addition and subtraction let F = 1, Defs = [SR] in { defm ADD_F_ : ALUarith<0b000, "add.f", addc, i32lo16z, i32hi16>; defm SUB_F_ : ALUarith<0b010, "sub.f", subc, i32lo16z, i32hi16>; } def : Pat<(addc GPR:$Rs1, i32lo16z:$imm), (ADD_F_I_LO GPR:$Rs1, i32lo16z:$imm)>; def : Pat<(subc GPR:$Rs1, i32lo16z:$imm), (SUB_F_I_LO GPR:$Rs1, i32lo16z:$imm)>; def : Pat<(addc GPR:$Rs1, i32hi16:$imm), (ADD_F_I_HI GPR:$Rs1, i32hi16:$imm)>; def : Pat<(subc GPR:$Rs1, i32hi16:$imm), (SUB_F_I_HI GPR:$Rs1, i32hi16:$imm)>; // Carry using addition and subtraction let F = 0, Uses = [SR] in { defm ADDC_ : ALUarith<0b001, "addc", adde, i32lo16z, i32hi16>; defm SUBB_ : ALUarith<0b011, "subb", sube, i32lo16z, i32hi16>; } def : Pat<(adde GPR:$Rs1, i32lo16z:$imm), (ADDC_I_LO GPR:$Rs1, i32lo16z:$imm)>; def : Pat<(sube GPR:$Rs1, i32lo16z:$imm), (SUBB_I_LO GPR:$Rs1, i32lo16z:$imm)>; def : Pat<(adde GPR:$Rs1, i32hi16:$imm), (ADDC_I_HI GPR:$Rs1, i32hi16:$imm)>; def : Pat<(sube GPR:$Rs1, i32hi16:$imm), (SUBB_I_HI GPR:$Rs1, i32hi16:$imm)>; // Flag setting ALU operations let isAsCheapAsAMove = 1, F = 1, Defs = [SR] in { let isCommutable = 1 in { defm AND_F_ : ALUlogic<0b100, "and.f", and, i32lo16and, i32hi16and>; defm OR_F_ : ALUlogic<0b101, "or.f", or, i32lo16z, i32hi16>; defm XOR_F_ : ALUlogic<0b110, "xor.f", xor, i32lo16z, i32hi16>; } } let isAsCheapAsAMove = 1, F = 1, Defs = [SR], Uses = [SR] in { defm ADDC_F_ : ALUarith<0b001, "addc.f", adde, i32lo16z, i32hi16>; defm SUBB_F_ : ALUarith<0b011, "subb.f", sube, i32lo16z, i32hi16>; } def : Pat<(LanaiSubbF GPR:$Rs1, GPR:$Rs2), (SUBB_F_R GPR:$Rs1, GPR:$Rs2)>; def : Pat<(LanaiSubbF GPR:$Rs1, i32lo16z:$imm), (SUBB_F_I_LO GPR:$Rs1, i32lo16z:$imm)>; def : Pat<(LanaiSubbF GPR:$Rs1, i32hi16:$imm), (SUBB_F_I_HI GPR:$Rs1, i32hi16:$imm)>; def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0, 0)>; let isAsCheapAsAMove = 1, Rs1 = R0.Num, isCodeGenOnly = 1, H = 1, F = 0, isReMaterializable = 1 in def MOVHI : InstRI<0b000, (outs GPR:$Rd), (ins i32hi16:$imm16), "mov\t$imm16, $Rd", [(set GPR:$Rd, i32hi16:$imm16)]>; def : InstAlias<"mov $imm16, $dst", (ADD_I_LO GPR:$dst, R0, i32lo16z:$imm16)>; def : InstAlias<"mov $imm16, $dst", (ADD_I_HI GPR:$dst, R0, i32hi16:$imm16)>; def : InstAlias<"mov $imm16, $dst", (AND_I_LO GPR:$dst, R1, i32lo16and:$imm16)>; def : InstAlias<"mov $imm16, $dst", (AND_I_HI GPR:$dst, R1, i32hi16and:$imm16)>; // Shift instructions class ShiftRI<string AsmStr, list<dag> Pattern> : InstRI<0b111, (outs GPR:$Rd), (ins GPR:$Rs1, immShift:$imm16), !strconcat(AsmStr, "\t$Rs1, $imm16, $Rd"), Pattern> { let isReMaterializable = 1; } let F = 0 in { let H = 0 in def SL_I : ShiftRI<"sh", [(set GPR:$Rd, (shl GPR:$Rs1, immShift:$imm16))]>; let H = 1 in def SA_I : ShiftRI<"sha", []>; } def : Pat<(srl GPR:$Rs1, immShift:$imm), (SL_I GPR:$Rs1, (NEG $imm))>; def : Pat<(sra GPR:$Rs1, immShift:$imm), (SA_I GPR:$Rs1, (NEG $imm))>; let F = 1, Defs = [SR] in { let H = 0 in def SL_F_I : ShiftRI<"sh.f", []>; let H = 1 in def SA_F_I : ShiftRI<"sha.f", []>; } class ShiftRR<string AsmStr, list<dag> Pattern> : InstRR<0b111, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, pred:$DDDI), AsmStr, Pattern>; let F = 0 in { let JJJJJ = 0b10000 in def SHL_R : ShiftRR<"sh$DDDI\t$Rs1, $Rs2, $Rd", [(set GPR:$Rd, (shl GPR:$Rs1, GPR:$Rs2))]>; let isCodeGenOnly = 1 in { let JJJJJ = 0b10000 in def SRL_R : ShiftRR<"sh$DDDI\t$Rs1, $Rs2, $Rd", []>; } let JJJJJ = 0b11000 in def SRA_R : ShiftRR<"sha$DDDI\t$Rs1, $Rs2, $Rd", []>; } let F = 1, Defs = [SR] in { let JJJJJ = 0b10000 in def SHL_F_R : ShiftRR<"sh.f$DDDI\t$Rs1, $Rs2, $Rd", []>; let isCodeGenOnly = 1 in { let JJJJJ = 0b10000 in def SRL_F_R : ShiftRR<"sh.f$DDDI\t$Rs1, $Rs2, $Rd", []>; } let JJJJJ = 0b11000 in def SRA_F_R : ShiftRR<"sha.f$DDDI\t$Rs1, $Rs2, $Rd", []>; } // Expand shift-right operations def : Pat<(srl GPR:$Rs1, GPR:$Rs2), (SRL_R GPR:$Rs1, (SUB_R R0, GPR:$Rs2))>; def : Pat<(sra GPR:$Rs1, GPR:$Rs2), (SRA_R GPR:$Rs1, (SUB_R R0, GPR:$Rs2))>; // -------------------------------------------------- // // LOAD instructions // -------------------------------------------------- // class LoadRR<string OpcString, PatFrag OpNode, ValueType Ty> : InstRRM<0b0, (outs GPR:$Rd), (ins MEMrr:$src), !strconcat(OpcString, "\t$src, $Rd"), [(set (Ty GPR:$Rd), (OpNode ADDRrr:$src))]>, Sched<[WriteLD]> { bits<20> src; let Rs1 = src{19-15}; let Rs2 = src{14-10}; let P = src{9}; let Q = src{8}; let BBB = src{7-5}; let JJJJJ = src{4-0}; let mayLoad = 1; } class LoadRI<string OpcString, PatFrag OpNode, ValueType Ty> : InstRM<0b0, (outs GPR:$Rd), (ins MEMri:$src), !strconcat(OpcString, "\t$src, $Rd"), [(set (Ty GPR:$Rd), (OpNode ADDRri:$src))]>, Sched<[WriteLD]> { bits<23> src; let Itinerary = IIC_LD; let Rs1 = src{22-18}; let P = src{17}; let Q = src{16}; let imm16 = src{15-0}; let isReMaterializable = 1; let mayLoad = 1; } let E = 0 in { let YL = 0b01 in { // uld is used here and ld in the alias as the alias is printed out first if // an alias exist def LDW_RI : LoadRI<"uld", load, i32>; def LDW_RR : LoadRR<"ld", load, i32>; } } def : InstAlias<"ld $src, $dst", (LDW_RI GPR:$dst, MEMri:$src)>; let E = 1 in { let YL = 0b01 in { def LDWz_RR : LoadRR<"uld", zextloadi32, i32>; } } let E = 1 in { let YL = 0b00 in def LDHz_RR : LoadRR<"uld.h", zextloadi16, i32>; let YL = 0b10 in def LDBz_RR : LoadRR<"uld.b", zextloadi8, i32>; } let E = 0 in { let YL = 0b00 in def LDHs_RR : LoadRR<"ld.h", sextloadi16, i32>; let YL = 0b10 in def LDBs_RR : LoadRR<"ld.b", sextloadi8, i32>; } def LDADDR : InstSLS<0x0, (outs GPR:$Rd), (ins MEMi:$src), "ld\t$src, $Rd", [(set (i32 GPR:$Rd), (load ADDRsls:$src))]>, Sched<[WriteLD]> { bits<21> src; let Itinerary = IIC_LD; let msb = src{20-16}; let lsb = src{15-0}; let isReMaterializable = 1; let mayLoad = 1; } class LoadSPLS<string asmstring, PatFrag opNode> : InstSPLS<(outs GPR:$Rd), (ins MEMspls:$src), !strconcat(asmstring, "\t$src, $Rd"), [(set (i32 GPR:$Rd), (opNode ADDRspls:$src))]>, Sched<[WriteLDSW]> { bits<17> src; let Itinerary = IIC_LDSW; let Rs1 = src{16-12}; let P = src{11}; let Q = src{10}; let imm10 = src{9-0}; let mayLoad = 1; let isReMaterializable = 1; } let Y = 0, S = 0, E = 1 in def LDHz_RI : LoadSPLS<"uld.h", zextloadi16>; let Y = 0, S = 0, E = 0 in def LDHs_RI : LoadSPLS<"ld.h", sextloadi16>; let Y = 1, S = 0, E = 1 in def LDBz_RI : LoadSPLS<"uld.b", zextloadi8>; let Y = 1, S = 0, E = 0 in def LDBs_RI : LoadSPLS<"ld.b", sextloadi8>; def SLI : InstSLI<(outs GPR:$Rd), (ins i32lo21:$imm), "mov\t$imm, $Rd", [(set GPR:$Rd, i32lo21:$imm)]> { bits<21> imm; let msb = imm{20-16}; let lsb = imm{15-0}; let isReMaterializable = 1; let isAsCheapAsAMove = 1; } // -------------------------------------------------- // // STORE instructions // -------------------------------------------------- // class StoreRR<string OpcString, PatFrag OpNode, ValueType Ty> : InstRRM<0b1, (outs), (ins GPR:$Rd, MEMrr:$dst), !strconcat(OpcString, "\t$Rd, $dst"), [(OpNode (Ty GPR:$Rd), ADDRrr:$dst)]>, Sched<[WriteST]> { bits<20> dst; let Itinerary = IIC_ST; let Rs1 = dst{19-15}; let Rs2 = dst{14-10}; let P = dst{9}; let Q = dst{8}; let BBB = dst{7-5}; let JJJJJ = dst{4-0}; let mayStore = 1; } class StoreRI<string OpcString, PatFrag OpNode, ValueType Ty> : InstRM<0b1, (outs), (ins GPR:$Rd, MEMri:$dst), !strconcat(OpcString, "\t$Rd, $dst"), [(OpNode (Ty GPR:$Rd), ADDRri:$dst)]>, Sched<[WriteST]> { bits<23> dst; let Itinerary = IIC_ST; let Rs1 = dst{22-18}; let P = dst{17}; let Q = dst{16}; let imm16 = dst{15-0}; let mayStore = 1; } let YL = 0b01, E = 0 in { def SW_RR : StoreRR<"st", store, i32>; def SW_RI : StoreRI<"st", store, i32>; } let E = 0 in { let YL = 0b00 in def STH_RR : StoreRR<"st.h", truncstorei16, i32>; let YL = 0b10 in def STB_RR : StoreRR<"st.b", truncstorei8, i32>; } def STADDR : InstSLS<0x1, (outs), (ins GPR:$Rd, MEMi:$dst), "st\t$Rd, $dst", [(store (i32 GPR:$Rd), ADDRsls:$dst)]>, Sched<[WriteST]> { bits<21> dst; let Itinerary = IIC_ST; let msb = dst{20-16}; let lsb = dst{15-0}; let mayStore = 1; } class StoreSPLS<string asmstring, PatFrag opNode> : InstSPLS<(outs), (ins GPR:$Rd, MEMspls:$dst), !strconcat(asmstring, "\t$Rd, $dst"), [(opNode (i32 GPR:$Rd), ADDRspls:$dst)]>, Sched<[WriteSTSW]> { bits<17> dst; let Itinerary = IIC_STSW; let Rs1 = dst{16-12}; let P = dst{11}; let Q = dst{10}; let imm10 = dst{9-0}; let mayStore = 1; } let Y = 0, S = 1, E = 0 in def STH_RI : StoreSPLS<"st.h", truncstorei16>; let Y = 1, S = 1, E = 0 in def STB_RI : StoreSPLS<"st.b", truncstorei8>; // -------------------------------------------------- // // BRANCH instructions // -------------------------------------------------- // let isBranch = 1, isBarrier = 1, isTerminator = 1, hasDelaySlot = 1 in { def BT : InstBR<(outs), (ins BrTarget:$addr), "bt\t$addr", [(br bb:$addr)]> { let DDDI = 0b0000; } let Uses = [SR] in def BRCC : InstBR<(outs), (ins BrTarget:$addr, CCOp:$DDDI), "b$DDDI\t$addr", [(LanaiBrCC bb:$addr, imm:$DDDI)]>; let isIndirectBranch = 1 in { def JR : InstRR<0b101, (outs), (ins GPR:$Rs2), "bt\t$Rs2", [(brind GPR:$Rs2)]> { let Rs1 = R0.Num; let Rd = R2.Num; let F = 0; let JJJJJ = 0; let DDDI = 0; } } } // -------------------------------------------------- // // Condition/SF instructions // -------------------------------------------------- // // Instructions to set flags used in lowering comparisons. multiclass SF<bits<3> op2Val, string AsmStr> { let F = 1, Rd = R0.Num, JJJJJ = 0, Defs = [SR], DDDI = 0 in def _RR : InstRR<op2Val, (outs), (ins GPR:$Rs1, GPR:$Rs2), !strconcat(AsmStr, "\t$Rs1, $Rs2, %r0"), [(LanaiSetFlag (i32 GPR:$Rs1), (i32 GPR:$Rs2))]>; let F = 1, Rd = R0.Num, H = 0, Defs = [SR] in def _RI_LO : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32lo16z:$imm16), !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"), [(LanaiSetFlag (i32 GPR:$Rs1), i32lo16z:$imm16)]>; let F = 1, Rd = R0.Num, H = 1, Defs = [SR] in def _RI_HI : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32hi16:$imm16), !strconcat(AsmStr, "\t$Rs1, $imm16, %r0"), [(LanaiSetFlag (i32 GPR:$Rs1), i32hi16:$imm16)]>; } let isCodeGenOnly = 1, isCompare = 1 in { defm SFSUB_F : SF<0b010, "sub.f">; } // Jump and link let isCall = 1, hasDelaySlot = 1, isCodeGenOnly = 1, Uses = [SP], Defs = [RCA] in { def CALL : Pseudo<(outs), (ins CallTarget:$addr), "", []>; def CALLR : Pseudo<(outs), (ins GPR:$Rs1), "", [(Call GPR:$Rs1)]>; } let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1, Uses = [RCA] in { def RET : InstRM<0b0, (outs), (ins), "ld\t-4[%fp], %pc ! return", [(RetFlag)]> { let Rd = PC.Num; let Rs1 = FP.Num; let P = 1; let Q = 0; let imm16 = -4; // Post encoding is not needed for RET. let PostEncoderMethod = ""; } } // ADJCALLSTACKDOWN/UP implicitly use/def SP because they may be expanded into // a stack adjustment and the codegen must know that they may modify the stack // pointer before prolog-epilog rewriting occurs. // Pessimistically assume ADJCALLSTACKDOWN / ADJCALLSTACKUP will become // sub / add which can clobber SP. let Defs = [SP], Uses = [SP] in { def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), "#ADJCALLSTACKDOWN $amt1 $amt2", [(CallSeqStart timm:$amt1, timm:$amt2)]>; def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), "#ADJCALLSTACKUP $amt1 $amt2", [(CallSeqEnd timm:$amt1, timm:$amt2)]>; } let Defs = [SP], Uses = [SP] in { def ADJDYNALLOC : Pseudo<(outs GPR:$dst), (ins GPR:$src), "#ADJDYNALLOC $dst $src", [(set GPR:$dst, (LanaiAdjDynAlloc GPR:$src))]>; } let Uses = [SR] in { def SCC : InstSCC<(outs GPR:$Rs1), (ins CCOp:$DDDI), "s$DDDI\t$Rs1", [(set (i32 GPR:$Rs1), (LanaiSetCC imm:$DDDI))]>; } // Select with hardware support let Uses = [SR], isSelect = 1 in { def SELECT : InstRR<0b111, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI), "sel.$DDDI $Rs1, $Rs2, $Rd", [(set (i32 GPR:$Rd), (LanaiSelectCC (i32 GPR:$Rs1), (i32 GPR:$Rs2), (imm:$DDDI)))]> { let JJJJJ = 0; let F = 0; } } let isBranch = 1, isBarrier = 1, isTerminator = 1, hasDelaySlot = 1, isIndirectBranch = 1, Uses = [SR] in { def BRIND_CC : InstRR<0b101, (outs), (ins GPR:$Rs1, CCOp:$DDDI), "b$DDDI\t$Rs1", []> { let F = 0; let JJJJJ = 0; let Rd = PC.Num; let Rs2 = R0.Num; } def BRIND_CCA : InstRR<0b101, (outs), (ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI), "b${DDDI}\t$Rs1 add $Rs2", []> { let F = 0; let Rd = PC.Num; let JJJJJ = 0; } } // TODO: This only considers the case where BROFF is an immediate and not where // it is a register. Add support for register relative branching. let isBranch = 1, isBarrier = 1, isTerminator = 1, hasDelaySlot = 1, Rs1 = 0, Uses = [SR] in def BRR : InstBRR<(outs), (ins i16imm:$imm16, CCOp:$DDDI), "b${DDDI}.r\t$imm16", []>; let F = 0 in { // Population Count (POPC) def POPC: InstSpecial<0b001, (outs GPR:$Rd), (ins GPR:$Rs1), "popc\t$Rs1, $Rd", [(set GPR:$Rd, (ctpop GPR:$Rs1))]>; // Count Leading Zeros (LEADZ) def LEADZ: InstSpecial<0b010, (outs GPR:$Rd), (ins GPR:$Rs1), "leadz\t$Rs1, $Rd", [(set GPR:$Rd, (ctlz GPR:$Rs1))]>; // Count Trailing Zeros (TRAILZ) def TRAILZ : InstSpecial<0b011, (outs GPR:$Rd), (ins GPR:$Rs1), "trailz\t$Rs1, $Rd", [(set GPR:$Rd, (cttz GPR:$Rs1))]>; } //===----------------------------------------------------------------------===// // Non-Instruction Patterns //===----------------------------------------------------------------------===// // unsigned 16-bit immediate def : Pat<(i32 i32lo16z:$imm), (OR_I_LO (i32 R0), imm:$imm)>; // arbitrary immediate def : Pat<(i32 imm:$imm), (OR_I_LO (MOVHI (HI16 imm:$imm)), (LO16 imm:$imm))>; // Calls def : Pat<(Call tglobaladdr:$dst), (CALL tglobaladdr:$dst)>; def : Pat<(Call texternalsym:$dst), (CALL texternalsym:$dst)>; // Loads def : Pat<(extloadi8 ADDRspls:$src), (i32 (LDBz_RI ADDRspls:$src))>; def : Pat<(extloadi16 ADDRspls:$src), (i32 (LDHz_RI ADDRspls:$src))>; // Loads up to 32-bits are already atomic. // TODO: This is a workaround for a particular failing case and should be // handled more generally. def : Pat<(atomic_load_8 ADDRspls:$src), (i32 (LDBz_RI ADDRspls:$src))>; // GlobalAddress, ExternalSymbol, Jumptable, ConstantPool def : Pat<(LanaiHi tglobaladdr:$dst), (MOVHI tglobaladdr:$dst)>; def : Pat<(LanaiLo tglobaladdr:$dst), (OR_I_LO (i32 R0), tglobaladdr:$dst)>; def : Pat<(LanaiSmall tglobaladdr:$dst), (SLI tglobaladdr:$dst)>; def : Pat<(LanaiHi texternalsym:$dst), (MOVHI texternalsym:$dst)>; def : Pat<(LanaiLo texternalsym:$dst), (OR_I_LO (i32 R0), texternalsym:$dst)>; def : Pat<(LanaiSmall texternalsym:$dst), (SLI texternalsym:$dst)>; def : Pat<(LanaiHi tblockaddress:$dst), (MOVHI tblockaddress:$dst)>; def : Pat<(LanaiLo tblockaddress:$dst), (OR_I_LO (i32 R0), tblockaddress:$dst)>; def : Pat<(LanaiSmall tblockaddress:$dst), (SLI tblockaddress:$dst)>; def : Pat<(LanaiHi tjumptable:$dst), (MOVHI tjumptable:$dst)>; def : Pat<(LanaiLo tjumptable:$dst), (OR_I_LO (i32 R0), tjumptable:$dst)>; def : Pat<(LanaiSmall tjumptable:$dst), (SLI tjumptable:$dst)>; def : Pat<(LanaiHi tconstpool:$dst), (MOVHI tconstpool:$dst)>; def : Pat<(LanaiLo tconstpool:$dst), (OR_I_LO (i32 R0), tconstpool:$dst)>; def : Pat<(LanaiSmall tconstpool:$dst), (SLI tconstpool:$dst)>; def : Pat<(or GPR:$hi, (LanaiLo tglobaladdr:$lo)), (OR_I_LO GPR:$hi, tglobaladdr:$lo)>; def : Pat<(or R0, (LanaiSmall tglobaladdr:$small)), (SLI tglobaladdr:$small)>; def : Pat<(or GPR:$hi, (LanaiLo texternalsym:$lo)), (OR_I_LO GPR:$hi, texternalsym:$lo)>; def : Pat<(or R0, (LanaiSmall texternalsym:$small)), (SLI texternalsym:$small)>; def : Pat<(or GPR:$hi, (LanaiLo tblockaddress:$lo)), (OR_I_LO GPR:$hi, tblockaddress:$lo)>; def : Pat<(or R0, (LanaiSmall tblockaddress:$small)), (SLI tblockaddress:$small)>; def : Pat<(or GPR:$hi, (LanaiLo tjumptable:$lo)), (OR_I_LO GPR:$hi, tjumptable:$lo)>; def : Pat<(or R0, (LanaiSmall tjumptable:$small)), (SLI tjumptable:$small)>; def : Pat<(or GPR:$hi, (LanaiLo tconstpool:$lo)), (OR_I_LO GPR:$hi, tconstpool:$lo)>; def : Pat<(or R0, (LanaiSmall tconstpool:$small)), (SLI tconstpool:$small)>;