forked from OSchip/llvm-project
882 lines
31 KiB
TableGen
882 lines
31 KiB
TableGen
//===-- LanaiInstrInfo.td - Target Description for Lanai Target -----------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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>]>;
|
|
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 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 immZExt21 : PatLeaf<(imm),
|
|
[{return isUInt<21>(N->getZExtValue()); }], LO21>;
|
|
|
|
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";
|
|
}
|
|
|
|
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, SDNode OpNode,
|
|
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, OpNode, LoExt, HiExt, [], []>;
|
|
|
|
// Register Register
|
|
let JJJJJ = 0, DDDI = 0 in
|
|
def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2),
|
|
!strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
|
|
[(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
|
|
// RR Conditional
|
|
let JJJJJ = 0, Uses = [SR] in
|
|
def R_CC : InstRR<subOp, (outs GPR:$Rd),
|
|
(ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
|
|
!strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
|
|
[]>;
|
|
}
|
|
|
|
multiclass ALUlogic<bits<3> subOp, string AsmStr, SDNode OpNode,
|
|
PatLeaf LoExt, PatLeaf HiExt> {
|
|
defm I_ : ALUbase<subOp, AsmStr, OpNode, LoExt, HiExt,
|
|
[(set GPR:$Rd, (OpNode GPR:$Rs1, LoExt:$imm16))],
|
|
[(set GPR:$Rd, (OpNode GPR:$Rs1, HiExt:$imm16))]>;
|
|
|
|
// Register Register
|
|
let JJJJJ = 0, DDDI = 0 in
|
|
def R : InstRR<subOp, (outs GPR:$Rd), (ins GPR:$Rs1, GPR:$Rs2),
|
|
!strconcat(AsmStr, "\t$Rs1, $Rs2, $Rd"),
|
|
[(set GPR:$Rd, (OpNode GPR:$Rs1, GPR:$Rs2))]>;
|
|
// RR Conditional
|
|
let JJJJJ = 0, Uses = [SR] in
|
|
def R_CC : InstRR<subOp, (outs GPR:$Rd),
|
|
(ins GPR:$Rs1, GPR:$Rs2, CCOp:$DDDI),
|
|
!strconcat(AsmStr, ".$DDDI\t$Rs1, $Rs2, $Rd"),
|
|
[]>;
|
|
}
|
|
|
|
// Non flag setting ALU operations
|
|
let isAsCheapAsAMove = 1, F = 0 in {
|
|
let isCommutable = 1 in {
|
|
defm ADD_ : ALUarith<0b000, "add", add, i32lo16s, i32hi16>;
|
|
}
|
|
defm SUB_ : ALUarith<0b010, "sub", sub, i32lo16s, 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, i32lo16s, 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, i32lo16s, i32hi16>;
|
|
defm SUB_F_ : ALUarith<0b010, "sub.f", subc, i32lo16s, 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, i32lo16s, i32hi16>;
|
|
defm SUBB_ : ALUarith<0b011, "subb", sube, i32lo16s, 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 {
|
|
defm ADDC_F_ : ALUarith<0b001, "addc.f", adde, i32lo16s, i32hi16>;
|
|
defm SUBB_F_ : ALUarith<0b011, "subb.f", sube, i32lo16s, i32hi16>;
|
|
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, i32lo16s, i32hi16>;
|
|
}
|
|
}
|
|
|
|
def : InstAlias<"mov $src, $dst", (ADD_R GPR:$dst, GPR:$src, R0)>;
|
|
|
|
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, i32lo16s:$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), AsmStr, Pattern> {
|
|
let DDDI = 0;
|
|
}
|
|
|
|
let F = 0 in {
|
|
let JJJJJ = 0b10000 in
|
|
def SHL_R : ShiftRR<"sh\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\t$Rs1, $Rs2, $Rd", []>;
|
|
}
|
|
let JJJJJ = 0b11000 in
|
|
def SRA_R : ShiftRR<"sha\t$Rs1, $Rs2, $Rd", []>;
|
|
}
|
|
|
|
let F = 1, Defs = [SR] in {
|
|
let JJJJJ = 0b10000 in
|
|
def SHL_F_R : ShiftRR<"sh.f\t$Rs1, $Rs2, $Rd", []>;
|
|
let isCodeGenOnly = 1 in {
|
|
let JJJJJ = 0b10000 in
|
|
def SRL_F_R : ShiftRR<"sh.f\t$Rs1, $Rs2, $Rd", []>;
|
|
}
|
|
let JJJJJ = 0b11000 in
|
|
def SRA_F_R : ShiftRR<"sha.f\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};
|
|
}
|
|
|
|
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 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;
|
|
}
|
|
|
|
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<[WriteLD]> {
|
|
bits<17> src;
|
|
let Itinerary = IIC_LD;
|
|
let Rs1 = src{16-12};
|
|
let P = src{11};
|
|
let Q = src{10};
|
|
let imm10 = src{9-0};
|
|
}
|
|
|
|
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 Itinerary = IIC_LD;
|
|
let msb = imm{20-16};
|
|
let lsb = imm{15-0};
|
|
let isReMaterializable = 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};
|
|
}
|
|
|
|
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 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};
|
|
}
|
|
|
|
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<[WriteST]> {
|
|
bits<17> dst;
|
|
|
|
let Itinerary = IIC_ST;
|
|
let Rs1 = dst{16-12};
|
|
let P = dst{11};
|
|
let Q = dst{10};
|
|
let imm10 = dst{9-0};
|
|
}
|
|
|
|
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 : InstRI<op2Val, (outs), (ins GPR:$Rs1, i32lo16s:$imm16),
|
|
!strconcat(AsmStr, "\t$Rs1, $imm16, %r0"),
|
|
[(LanaiSetFlag (i32 GPR:$Rs1), i32lo16s:$imm16)]>;
|
|
}
|
|
let isCodeGenOnly = 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:$amt),
|
|
"#ADJCALLSTACKDOWN $amt",
|
|
[(CallSeqStart timm:$amt)]>;
|
|
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))]>;
|
|
}
|
|
|
|
// SCC's output is already 1-bit so and'ing with 1 is redundant.
|
|
def : Pat<(and (LanaiSetCC imm:$DDDI), 1), (SCC 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))]>;
|
|
let isCodeGenOnly = 1 in
|
|
def LEADZUNDEF: InstSpecial<0b010, (outs GPR:$Rd), (ins GPR:$Rs1),
|
|
"leadz\t$Rs1, $Rd",
|
|
[(set GPR:$Rd, (ctlz_zero_undef 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))]>;
|
|
let isCodeGenOnly = 1 in
|
|
def TRAILZUNDEF : InstSpecial<0b011, (outs GPR:$Rd), (ins GPR:$Rs1),
|
|
"trailz\t$Rs1, $Rd",
|
|
[(set GPR:$Rd,
|
|
(cttz_zero_undef GPR:$Rs1))]>;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Non-Instruction Patterns
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// signed 16-bit immediate
|
|
def : Pat<(i32 i32lo16s:$imm), (MOVHI imm:$imm)>;
|
|
|
|
// i32 0 and R0 can be used interchangeably.
|
|
def : Pat<(i32 0), (i32 R0)>;
|
|
// i32 -1 and R1 can be used interchangeably.
|
|
def : Pat<(i32 -1), (i32 R1)>;
|
|
|
|
// 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))>;
|
|
|
|
// 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)>;
|