mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-28 04:33:05 +00:00
ddf89566a9
1. Legalize now always promotes truncstore of i1 to i8. 2. Remove patterns and gunk related to truncstore i1 from targets. 3. Rename the StoreXAction stuff to TruncStoreAction in TLI. 4. Make the TLI TruncStoreAction table a 2d table to handle from/to conversions. 5. Mark a wide variety of invalid truncstores as such in various targets, e.g. X86 currently doesn't support truncstore of any of its integer types. 6. Add legalize support for truncstores with invalid value input types. 7. Add a dag combine transform to turn store(truncate) into truncstore when safe. The later allows us to compile CodeGen/X86/storetrunc-fp.ll to: _foo: fldt 20(%esp) fldt 4(%esp) faddp %st(1) movl 36(%esp), %eax fstps (%eax) ret instead of: _foo: subl $4, %esp fldt 24(%esp) fldt 8(%esp) faddp %st(1) fstps (%esp) movl 40(%esp), %eax movss (%esp), %xmm0 movss %xmm0, (%eax) addl $4, %esp ret git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@46140 91177308-0d34-0410-b5e6-96231b3b80d8
777 lines
32 KiB
TableGen
777 lines
32 KiB
TableGen
//===- SparcInstrInfo.td - Target Description for Sparc 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 Sparc instructions in TableGen format.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction format superclass
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
include "SparcInstrFormats.td"
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Feature predicates.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// HasV9 - This predicate is true when the target processor supports V9
|
|
// instructions. Note that the machine may be running in 32-bit mode.
|
|
def HasV9 : Predicate<"Subtarget.isV9()">;
|
|
|
|
// HasNoV9 - This predicate is true when the target doesn't have V9
|
|
// instructions. Use of this is just a hack for the isel not having proper
|
|
// costs for V8 instructions that are more expensive than their V9 ones.
|
|
def HasNoV9 : Predicate<"!Subtarget.isV9()">;
|
|
|
|
// HasVIS - This is true when the target processor has VIS extensions.
|
|
def HasVIS : Predicate<"Subtarget.isVIS()">;
|
|
|
|
// UseDeprecatedInsts - This predicate is true when the target processor is a
|
|
// V8, or when it is V9 but the V8 deprecated instructions are efficient enough
|
|
// to use when appropriate. In either of these cases, the instruction selector
|
|
// will pick deprecated instructions.
|
|
def UseDeprecatedInsts : Predicate<"Subtarget.useDeprecatedV8Instructions()">;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Pattern Stuff
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
def simm11 : PatLeaf<(imm), [{
|
|
// simm11 predicate - True if the imm fits in a 11-bit sign extended field.
|
|
return (((int)N->getValue() << (32-11)) >> (32-11)) == (int)N->getValue();
|
|
}]>;
|
|
|
|
def simm13 : PatLeaf<(imm), [{
|
|
// simm13 predicate - True if the imm fits in a 13-bit sign extended field.
|
|
return (((int)N->getValue() << (32-13)) >> (32-13)) == (int)N->getValue();
|
|
}]>;
|
|
|
|
def LO10 : SDNodeXForm<imm, [{
|
|
return CurDAG->getTargetConstant((unsigned)N->getValue() & 1023, MVT::i32);
|
|
}]>;
|
|
|
|
def HI22 : SDNodeXForm<imm, [{
|
|
// Transformation function: shift the immediate value down into the low bits.
|
|
return CurDAG->getTargetConstant((unsigned)N->getValue() >> 10, MVT::i32);
|
|
}]>;
|
|
|
|
def SETHIimm : PatLeaf<(imm), [{
|
|
return (((unsigned)N->getValue() >> 10) << 10) == (unsigned)N->getValue();
|
|
}], HI22>;
|
|
|
|
// Addressing modes.
|
|
def ADDRrr : ComplexPattern<i32, 2, "SelectADDRrr", [], []>;
|
|
def ADDRri : ComplexPattern<i32, 2, "SelectADDRri", [frameindex], []>;
|
|
|
|
// Address operands
|
|
def MEMrr : Operand<i32> {
|
|
let PrintMethod = "printMemOperand";
|
|
let MIOperandInfo = (ops IntRegs, IntRegs);
|
|
}
|
|
def MEMri : Operand<i32> {
|
|
let PrintMethod = "printMemOperand";
|
|
let MIOperandInfo = (ops IntRegs, i32imm);
|
|
}
|
|
|
|
// Branch targets have OtherVT type.
|
|
def brtarget : Operand<OtherVT>;
|
|
def calltarget : Operand<i32>;
|
|
|
|
// Operand for printing out a condition code.
|
|
let PrintMethod = "printCCOperand" in
|
|
def CCOp : Operand<i32>;
|
|
|
|
def SDTSPcmpfcc :
|
|
SDTypeProfile<0, 2, [SDTCisFP<0>, SDTCisSameAs<0, 1>]>;
|
|
def SDTSPbrcc :
|
|
SDTypeProfile<0, 2, [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>]>;
|
|
def SDTSPselectcc :
|
|
SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisVT<3, i32>]>;
|
|
def SDTSPFTOI :
|
|
SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisFP<1>]>;
|
|
def SDTSPITOF :
|
|
SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, f32>]>;
|
|
|
|
def SPcmpicc : SDNode<"SPISD::CMPICC", SDTIntBinOp, [SDNPOutFlag]>;
|
|
def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutFlag]>;
|
|
def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInFlag]>;
|
|
def SPbrfcc : SDNode<"SPISD::BRFCC", SDTSPbrcc, [SDNPHasChain, SDNPInFlag]>;
|
|
|
|
def SPhi : SDNode<"SPISD::Hi", SDTIntUnaryOp>;
|
|
def SPlo : SDNode<"SPISD::Lo", SDTIntUnaryOp>;
|
|
|
|
def SPftoi : SDNode<"SPISD::FTOI", SDTSPFTOI>;
|
|
def SPitof : SDNode<"SPISD::ITOF", SDTSPITOF>;
|
|
|
|
def SPselecticc : SDNode<"SPISD::SELECT_ICC", SDTSPselectcc, [SDNPInFlag]>;
|
|
def SPselectfcc : SDNode<"SPISD::SELECT_FCC", SDTSPselectcc, [SDNPInFlag]>;
|
|
|
|
// These are target-independent nodes, but have target-specific formats.
|
|
def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
|
|
def SDT_SPCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
|
|
SDTCisVT<1, i32> ]>;
|
|
|
|
def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_SPCallSeqStart,
|
|
[SDNPHasChain, SDNPOutFlag]>;
|
|
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SPCallSeqEnd,
|
|
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
|
|
|
|
def SDT_SPCall : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
|
|
def call : SDNode<"SPISD::CALL", SDT_SPCall,
|
|
[SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
|
|
|
|
def SDT_SPRetFlag : SDTypeProfile<0, 0, []>;
|
|
def retflag : SDNode<"SPISD::RET_FLAG", SDT_SPRetFlag,
|
|
[SDNPHasChain, SDNPOptInFlag]>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SPARC Flag Conditions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Note that these values must be kept in sync with the CCOp::CondCode enum
|
|
// values.
|
|
class ICC_VAL<int N> : PatLeaf<(i32 N)>;
|
|
def ICC_NE : ICC_VAL< 9>; // Not Equal
|
|
def ICC_E : ICC_VAL< 1>; // Equal
|
|
def ICC_G : ICC_VAL<10>; // Greater
|
|
def ICC_LE : ICC_VAL< 2>; // Less or Equal
|
|
def ICC_GE : ICC_VAL<11>; // Greater or Equal
|
|
def ICC_L : ICC_VAL< 3>; // Less
|
|
def ICC_GU : ICC_VAL<12>; // Greater Unsigned
|
|
def ICC_LEU : ICC_VAL< 4>; // Less or Equal Unsigned
|
|
def ICC_CC : ICC_VAL<13>; // Carry Clear/Great or Equal Unsigned
|
|
def ICC_CS : ICC_VAL< 5>; // Carry Set/Less Unsigned
|
|
def ICC_POS : ICC_VAL<14>; // Positive
|
|
def ICC_NEG : ICC_VAL< 6>; // Negative
|
|
def ICC_VC : ICC_VAL<15>; // Overflow Clear
|
|
def ICC_VS : ICC_VAL< 7>; // Overflow Set
|
|
|
|
class FCC_VAL<int N> : PatLeaf<(i32 N)>;
|
|
def FCC_U : FCC_VAL<23>; // Unordered
|
|
def FCC_G : FCC_VAL<22>; // Greater
|
|
def FCC_UG : FCC_VAL<21>; // Unordered or Greater
|
|
def FCC_L : FCC_VAL<20>; // Less
|
|
def FCC_UL : FCC_VAL<19>; // Unordered or Less
|
|
def FCC_LG : FCC_VAL<18>; // Less or Greater
|
|
def FCC_NE : FCC_VAL<17>; // Not Equal
|
|
def FCC_E : FCC_VAL<25>; // Equal
|
|
def FCC_UE : FCC_VAL<24>; // Unordered or Equal
|
|
def FCC_GE : FCC_VAL<25>; // Greater or Equal
|
|
def FCC_UGE : FCC_VAL<26>; // Unordered or Greater or Equal
|
|
def FCC_LE : FCC_VAL<27>; // Less or Equal
|
|
def FCC_ULE : FCC_VAL<28>; // Unordered or Less or Equal
|
|
def FCC_O : FCC_VAL<29>; // Ordered
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instruction Class Templates
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
/// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot.
|
|
multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> {
|
|
def rr : F3_1<2, Op3Val,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
|
!strconcat(OpcStr, " $b, $c, $dst"),
|
|
[(set IntRegs:$dst, (OpNode IntRegs:$b, IntRegs:$c))]>;
|
|
def ri : F3_2<2, Op3Val,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
|
|
!strconcat(OpcStr, " $b, $c, $dst"),
|
|
[(set IntRegs:$dst, (OpNode IntRegs:$b, simm13:$c))]>;
|
|
}
|
|
|
|
/// F3_12np multiclass - Define a normal F3_1/F3_2 pattern in one shot, with no
|
|
/// pattern.
|
|
multiclass F3_12np<string OpcStr, bits<6> Op3Val> {
|
|
def rr : F3_1<2, Op3Val,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
|
!strconcat(OpcStr, " $b, $c, $dst"), []>;
|
|
def ri : F3_2<2, Op3Val,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
|
|
!strconcat(OpcStr, " $b, $c, $dst"), []>;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Instructions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Pseudo instructions.
|
|
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
|
|
: InstSP<outs, ins, asmstr, pattern>;
|
|
|
|
let Defs = [O6], Uses = [O6] in {
|
|
def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt),
|
|
"!ADJCALLSTACKDOWN $amt",
|
|
[(callseq_start imm:$amt)]>;
|
|
def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
|
|
"!ADJCALLSTACKUP $amt1",
|
|
[(callseq_end imm:$amt1, imm:$amt2)]>;
|
|
}
|
|
|
|
let isImplicitDef = 1 in {
|
|
def IMPLICIT_DEF_Int : Pseudo<(outs IntRegs:$dst), (ins),
|
|
"!IMPLICIT_DEF $dst",
|
|
[(set IntRegs:$dst, (undef))]>;
|
|
def IMPLICIT_DEF_FP : Pseudo<(outs FPRegs:$dst), (ins), "!IMPLICIT_DEF $dst",
|
|
[(set FPRegs:$dst, (undef))]>;
|
|
def IMPLICIT_DEF_DFP : Pseudo<(outs DFPRegs:$dst), (ins), "!IMPLICIT_DEF $dst",
|
|
[(set DFPRegs:$dst, (undef))]>;
|
|
}
|
|
|
|
// FpMOVD/FpNEGD/FpABSD - These are lowered to single-precision ops by the
|
|
// fpmover pass.
|
|
let Predicates = [HasNoV9] in { // Only emit these in V8 mode.
|
|
def FpMOVD : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
|
"!FpMOVD $src, $dst", []>;
|
|
def FpNEGD : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
|
"!FpNEGD $src, $dst",
|
|
[(set DFPRegs:$dst, (fneg DFPRegs:$src))]>;
|
|
def FpABSD : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
|
"!FpABSD $src, $dst",
|
|
[(set DFPRegs:$dst, (fabs DFPRegs:$src))]>;
|
|
}
|
|
|
|
// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded by the
|
|
// scheduler into a branch sequence. This has to handle all permutations of
|
|
// selection between i32/f32/f64 on ICC and FCC.
|
|
let usesCustomDAGSchedInserter = 1 in { // Expanded by the scheduler.
|
|
def SELECT_CC_Int_ICC
|
|
: Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, IntRegs:$F, i32imm:$Cond),
|
|
"; SELECT_CC_Int_ICC PSEUDO!",
|
|
[(set IntRegs:$dst, (SPselecticc IntRegs:$T, IntRegs:$F,
|
|
imm:$Cond))]>;
|
|
def SELECT_CC_Int_FCC
|
|
: Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, IntRegs:$F, i32imm:$Cond),
|
|
"; SELECT_CC_Int_FCC PSEUDO!",
|
|
[(set IntRegs:$dst, (SPselectfcc IntRegs:$T, IntRegs:$F,
|
|
imm:$Cond))]>;
|
|
def SELECT_CC_FP_ICC
|
|
: Pseudo<(outs FPRegs:$dst), (ins FPRegs:$T, FPRegs:$F, i32imm:$Cond),
|
|
"; SELECT_CC_FP_ICC PSEUDO!",
|
|
[(set FPRegs:$dst, (SPselecticc FPRegs:$T, FPRegs:$F,
|
|
imm:$Cond))]>;
|
|
def SELECT_CC_FP_FCC
|
|
: Pseudo<(outs FPRegs:$dst), (ins FPRegs:$T, FPRegs:$F, i32imm:$Cond),
|
|
"; SELECT_CC_FP_FCC PSEUDO!",
|
|
[(set FPRegs:$dst, (SPselectfcc FPRegs:$T, FPRegs:$F,
|
|
imm:$Cond))]>;
|
|
def SELECT_CC_DFP_ICC
|
|
: Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
|
"; SELECT_CC_DFP_ICC PSEUDO!",
|
|
[(set DFPRegs:$dst, (SPselecticc DFPRegs:$T, DFPRegs:$F,
|
|
imm:$Cond))]>;
|
|
def SELECT_CC_DFP_FCC
|
|
: Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
|
|
"; SELECT_CC_DFP_FCC PSEUDO!",
|
|
[(set DFPRegs:$dst, (SPselectfcc DFPRegs:$T, DFPRegs:$F,
|
|
imm:$Cond))]>;
|
|
}
|
|
|
|
|
|
// Section A.3 - Synthetic Instructions, p. 85
|
|
// special cases of JMPL:
|
|
let isReturn = 1, isTerminator = 1, hasDelaySlot = 1 in {
|
|
let rd = O7.Num, rs1 = G0.Num, simm13 = 8 in
|
|
def RETL: F3_2<2, 0b111000, (outs), (ins), "retl", [(retflag)]>;
|
|
}
|
|
|
|
// Section B.1 - Load Integer Instructions, p. 90
|
|
def LDSBrr : F3_1<3, 0b001001,
|
|
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
|
"ldsb [$addr], $dst",
|
|
[(set IntRegs:$dst, (sextloadi8 ADDRrr:$addr))]>;
|
|
def LDSBri : F3_2<3, 0b001001,
|
|
(outs IntRegs:$dst), (ins MEMri:$addr),
|
|
"ldsb [$addr], $dst",
|
|
[(set IntRegs:$dst, (sextloadi8 ADDRri:$addr))]>;
|
|
def LDSHrr : F3_1<3, 0b001010,
|
|
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
|
"ldsh [$addr], $dst",
|
|
[(set IntRegs:$dst, (sextloadi16 ADDRrr:$addr))]>;
|
|
def LDSHri : F3_2<3, 0b001010,
|
|
(outs IntRegs:$dst), (ins MEMri:$addr),
|
|
"ldsh [$addr], $dst",
|
|
[(set IntRegs:$dst, (sextloadi16 ADDRri:$addr))]>;
|
|
def LDUBrr : F3_1<3, 0b000001,
|
|
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
|
"ldub [$addr], $dst",
|
|
[(set IntRegs:$dst, (zextloadi8 ADDRrr:$addr))]>;
|
|
def LDUBri : F3_2<3, 0b000001,
|
|
(outs IntRegs:$dst), (ins MEMri:$addr),
|
|
"ldub [$addr], $dst",
|
|
[(set IntRegs:$dst, (zextloadi8 ADDRri:$addr))]>;
|
|
def LDUHrr : F3_1<3, 0b000010,
|
|
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
|
"lduh [$addr], $dst",
|
|
[(set IntRegs:$dst, (zextloadi16 ADDRrr:$addr))]>;
|
|
def LDUHri : F3_2<3, 0b000010,
|
|
(outs IntRegs:$dst), (ins MEMri:$addr),
|
|
"lduh [$addr], $dst",
|
|
[(set IntRegs:$dst, (zextloadi16 ADDRri:$addr))]>;
|
|
def LDrr : F3_1<3, 0b000000,
|
|
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
|
"ld [$addr], $dst",
|
|
[(set IntRegs:$dst, (load ADDRrr:$addr))]>;
|
|
def LDri : F3_2<3, 0b000000,
|
|
(outs IntRegs:$dst), (ins MEMri:$addr),
|
|
"ld [$addr], $dst",
|
|
[(set IntRegs:$dst, (load ADDRri:$addr))]>;
|
|
|
|
// Section B.2 - Load Floating-point Instructions, p. 92
|
|
def LDFrr : F3_1<3, 0b100000,
|
|
(outs FPRegs:$dst), (ins MEMrr:$addr),
|
|
"ld [$addr], $dst",
|
|
[(set FPRegs:$dst, (load ADDRrr:$addr))]>;
|
|
def LDFri : F3_2<3, 0b100000,
|
|
(outs FPRegs:$dst), (ins MEMri:$addr),
|
|
"ld [$addr], $dst",
|
|
[(set FPRegs:$dst, (load ADDRri:$addr))]>;
|
|
def LDDFrr : F3_1<3, 0b100011,
|
|
(outs DFPRegs:$dst), (ins MEMrr:$addr),
|
|
"ldd [$addr], $dst",
|
|
[(set DFPRegs:$dst, (load ADDRrr:$addr))]>;
|
|
def LDDFri : F3_2<3, 0b100011,
|
|
(outs DFPRegs:$dst), (ins MEMri:$addr),
|
|
"ldd [$addr], $dst",
|
|
[(set DFPRegs:$dst, (load ADDRri:$addr))]>;
|
|
|
|
// Section B.4 - Store Integer Instructions, p. 95
|
|
def STBrr : F3_1<3, 0b000101,
|
|
(outs), (ins MEMrr:$addr, IntRegs:$src),
|
|
"stb $src, [$addr]",
|
|
[(truncstorei8 IntRegs:$src, ADDRrr:$addr)]>;
|
|
def STBri : F3_2<3, 0b000101,
|
|
(outs), (ins MEMri:$addr, IntRegs:$src),
|
|
"stb $src, [$addr]",
|
|
[(truncstorei8 IntRegs:$src, ADDRri:$addr)]>;
|
|
def STHrr : F3_1<3, 0b000110,
|
|
(outs), (ins MEMrr:$addr, IntRegs:$src),
|
|
"sth $src, [$addr]",
|
|
[(truncstorei16 IntRegs:$src, ADDRrr:$addr)]>;
|
|
def STHri : F3_2<3, 0b000110,
|
|
(outs), (ins MEMri:$addr, IntRegs:$src),
|
|
"sth $src, [$addr]",
|
|
[(truncstorei16 IntRegs:$src, ADDRri:$addr)]>;
|
|
def STrr : F3_1<3, 0b000100,
|
|
(outs), (ins MEMrr:$addr, IntRegs:$src),
|
|
"st $src, [$addr]",
|
|
[(store IntRegs:$src, ADDRrr:$addr)]>;
|
|
def STri : F3_2<3, 0b000100,
|
|
(outs), (ins MEMri:$addr, IntRegs:$src),
|
|
"st $src, [$addr]",
|
|
[(store IntRegs:$src, ADDRri:$addr)]>;
|
|
|
|
// Section B.5 - Store Floating-point Instructions, p. 97
|
|
def STFrr : F3_1<3, 0b100100,
|
|
(outs), (ins MEMrr:$addr, FPRegs:$src),
|
|
"st $src, [$addr]",
|
|
[(store FPRegs:$src, ADDRrr:$addr)]>;
|
|
def STFri : F3_2<3, 0b100100,
|
|
(outs), (ins MEMri:$addr, FPRegs:$src),
|
|
"st $src, [$addr]",
|
|
[(store FPRegs:$src, ADDRri:$addr)]>;
|
|
def STDFrr : F3_1<3, 0b100111,
|
|
(outs), (ins MEMrr:$addr, DFPRegs:$src),
|
|
"std $src, [$addr]",
|
|
[(store DFPRegs:$src, ADDRrr:$addr)]>;
|
|
def STDFri : F3_2<3, 0b100111,
|
|
(outs), (ins MEMri:$addr, DFPRegs:$src),
|
|
"std $src, [$addr]",
|
|
[(store DFPRegs:$src, ADDRri:$addr)]>;
|
|
|
|
// Section B.9 - SETHI Instruction, p. 104
|
|
def SETHIi: F2_1<0b100,
|
|
(outs IntRegs:$dst), (ins i32imm:$src),
|
|
"sethi $src, $dst",
|
|
[(set IntRegs:$dst, SETHIimm:$src)]>;
|
|
|
|
// Section B.10 - NOP Instruction, p. 105
|
|
// (It's a special case of SETHI)
|
|
let rd = 0, imm22 = 0 in
|
|
def NOP : F2_1<0b100, (outs), (ins), "nop", []>;
|
|
|
|
// Section B.11 - Logical Instructions, p. 106
|
|
defm AND : F3_12<"and", 0b000001, and>;
|
|
|
|
def ANDNrr : F3_1<2, 0b000101,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
|
"andn $b, $c, $dst",
|
|
[(set IntRegs:$dst, (and IntRegs:$b, (not IntRegs:$c)))]>;
|
|
def ANDNri : F3_2<2, 0b000101,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
|
|
"andn $b, $c, $dst", []>;
|
|
|
|
defm OR : F3_12<"or", 0b000010, or>;
|
|
|
|
def ORNrr : F3_1<2, 0b000110,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
|
"orn $b, $c, $dst",
|
|
[(set IntRegs:$dst, (or IntRegs:$b, (not IntRegs:$c)))]>;
|
|
def ORNri : F3_2<2, 0b000110,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
|
|
"orn $b, $c, $dst", []>;
|
|
defm XOR : F3_12<"xor", 0b000011, xor>;
|
|
|
|
def XNORrr : F3_1<2, 0b000111,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
|
"xnor $b, $c, $dst",
|
|
[(set IntRegs:$dst, (not (xor IntRegs:$b, IntRegs:$c)))]>;
|
|
def XNORri : F3_2<2, 0b000111,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
|
|
"xnor $b, $c, $dst", []>;
|
|
|
|
// Section B.12 - Shift Instructions, p. 107
|
|
defm SLL : F3_12<"sll", 0b100101, shl>;
|
|
defm SRL : F3_12<"srl", 0b100110, srl>;
|
|
defm SRA : F3_12<"sra", 0b100111, sra>;
|
|
|
|
// Section B.13 - Add Instructions, p. 108
|
|
defm ADD : F3_12<"add", 0b000000, add>;
|
|
|
|
// "LEA" forms of add (patterns to make tblgen happy)
|
|
def LEA_ADDri : F3_2<2, 0b000000,
|
|
(outs IntRegs:$dst), (ins MEMri:$addr),
|
|
"add ${addr:arith}, $dst",
|
|
[(set IntRegs:$dst, ADDRri:$addr)]>;
|
|
|
|
defm ADDCC : F3_12<"addcc", 0b010000, addc>;
|
|
defm ADDX : F3_12<"addx", 0b001000, adde>;
|
|
|
|
// Section B.15 - Subtract Instructions, p. 110
|
|
defm SUB : F3_12 <"sub" , 0b000100, sub>;
|
|
defm SUBX : F3_12 <"subx" , 0b001100, sube>;
|
|
defm SUBCC : F3_12 <"subcc", 0b010100, SPcmpicc>;
|
|
|
|
def SUBXCCrr: F3_1<2, 0b011100,
|
|
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
|
"subxcc $b, $c, $dst", []>;
|
|
|
|
// Section B.18 - Multiply Instructions, p. 113
|
|
defm UMUL : F3_12np<"umul", 0b001010>;
|
|
defm SMUL : F3_12 <"smul", 0b001011, mul>;
|
|
|
|
|
|
// Section B.19 - Divide Instructions, p. 115
|
|
defm UDIV : F3_12np<"udiv", 0b001110>;
|
|
defm SDIV : F3_12np<"sdiv", 0b001111>;
|
|
|
|
// Section B.20 - SAVE and RESTORE, p. 117
|
|
defm SAVE : F3_12np<"save" , 0b111100>;
|
|
defm RESTORE : F3_12np<"restore", 0b111101>;
|
|
|
|
// Section B.21 - Branch on Integer Condition Codes Instructions, p. 119
|
|
|
|
// conditional branch class:
|
|
class BranchSP<bits<4> cc, dag ins, string asmstr, list<dag> pattern>
|
|
: F2_2<cc, 0b010, (outs), ins, asmstr, pattern> {
|
|
let isBranch = 1;
|
|
let isTerminator = 1;
|
|
let hasDelaySlot = 1;
|
|
}
|
|
|
|
let isBarrier = 1 in
|
|
def BA : BranchSP<0b1000, (ins brtarget:$dst),
|
|
"ba $dst",
|
|
[(br bb:$dst)]>;
|
|
|
|
// FIXME: the encoding for the JIT should look at the condition field.
|
|
def BCOND : BranchSP<0, (ins brtarget:$dst, CCOp:$cc),
|
|
"b$cc $dst",
|
|
[(SPbricc bb:$dst, imm:$cc)]>;
|
|
|
|
|
|
// Section B.22 - Branch on Floating-point Condition Codes Instructions, p. 121
|
|
|
|
// floating-point conditional branch class:
|
|
class FPBranchSP<bits<4> cc, dag ins, string asmstr, list<dag> pattern>
|
|
: F2_2<cc, 0b110, (outs), ins, asmstr, pattern> {
|
|
let isBranch = 1;
|
|
let isTerminator = 1;
|
|
let hasDelaySlot = 1;
|
|
}
|
|
|
|
// FIXME: the encoding for the JIT should look at the condition field.
|
|
def FBCOND : FPBranchSP<0, (ins brtarget:$dst, CCOp:$cc),
|
|
"fb$cc $dst",
|
|
[(SPbrfcc bb:$dst, imm:$cc)]>;
|
|
|
|
|
|
// Section B.24 - Call and Link Instruction, p. 125
|
|
// This is the only Format 1 instruction
|
|
let Uses = [O0, O1, O2, O3, O4, O5],
|
|
hasDelaySlot = 1, isCall = 1,
|
|
Defs = [O0, O1, O2, O3, O4, O5, O7, G1, G2, G3, G4, G5, G6, G7,
|
|
D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15] in {
|
|
def CALL : InstSP<(outs), (ins calltarget:$dst),
|
|
"call $dst", []> {
|
|
bits<30> disp;
|
|
let op = 1;
|
|
let Inst{29-0} = disp;
|
|
}
|
|
|
|
// indirect calls
|
|
def JMPLrr : F3_1<2, 0b111000,
|
|
(outs), (ins MEMrr:$ptr),
|
|
"call $ptr",
|
|
[(call ADDRrr:$ptr)]>;
|
|
def JMPLri : F3_2<2, 0b111000,
|
|
(outs), (ins MEMri:$ptr),
|
|
"call $ptr",
|
|
[(call ADDRri:$ptr)]>;
|
|
}
|
|
|
|
// Section B.28 - Read State Register Instructions
|
|
def RDY : F3_1<2, 0b101000,
|
|
(outs IntRegs:$dst), (ins),
|
|
"rd %y, $dst", []>;
|
|
|
|
// Section B.29 - Write State Register Instructions
|
|
def WRYrr : F3_1<2, 0b110000,
|
|
(outs), (ins IntRegs:$b, IntRegs:$c),
|
|
"wr $b, $c, %y", []>;
|
|
def WRYri : F3_2<2, 0b110000,
|
|
(outs), (ins IntRegs:$b, i32imm:$c),
|
|
"wr $b, $c, %y", []>;
|
|
|
|
// Convert Integer to Floating-point Instructions, p. 141
|
|
def FITOS : F3_3<2, 0b110100, 0b011000100,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src),
|
|
"fitos $src, $dst",
|
|
[(set FPRegs:$dst, (SPitof FPRegs:$src))]>;
|
|
def FITOD : F3_3<2, 0b110100, 0b011001000,
|
|
(outs DFPRegs:$dst), (ins FPRegs:$src),
|
|
"fitod $src, $dst",
|
|
[(set DFPRegs:$dst, (SPitof FPRegs:$src))]>;
|
|
|
|
// Convert Floating-point to Integer Instructions, p. 142
|
|
def FSTOI : F3_3<2, 0b110100, 0b011010001,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src),
|
|
"fstoi $src, $dst",
|
|
[(set FPRegs:$dst, (SPftoi FPRegs:$src))]>;
|
|
def FDTOI : F3_3<2, 0b110100, 0b011010010,
|
|
(outs FPRegs:$dst), (ins DFPRegs:$src),
|
|
"fdtoi $src, $dst",
|
|
[(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>;
|
|
|
|
// Convert between Floating-point Formats Instructions, p. 143
|
|
def FSTOD : F3_3<2, 0b110100, 0b011001001,
|
|
(outs DFPRegs:$dst), (ins FPRegs:$src),
|
|
"fstod $src, $dst",
|
|
[(set DFPRegs:$dst, (fextend FPRegs:$src))]>;
|
|
def FDTOS : F3_3<2, 0b110100, 0b011000110,
|
|
(outs FPRegs:$dst), (ins DFPRegs:$src),
|
|
"fdtos $src, $dst",
|
|
[(set FPRegs:$dst, (fround DFPRegs:$src))]>;
|
|
|
|
// Floating-point Move Instructions, p. 144
|
|
def FMOVS : F3_3<2, 0b110100, 0b000000001,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src),
|
|
"fmovs $src, $dst", []>;
|
|
def FNEGS : F3_3<2, 0b110100, 0b000000101,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src),
|
|
"fnegs $src, $dst",
|
|
[(set FPRegs:$dst, (fneg FPRegs:$src))]>;
|
|
def FABSS : F3_3<2, 0b110100, 0b000001001,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src),
|
|
"fabss $src, $dst",
|
|
[(set FPRegs:$dst, (fabs FPRegs:$src))]>;
|
|
|
|
|
|
// Floating-point Square Root Instructions, p.145
|
|
def FSQRTS : F3_3<2, 0b110100, 0b000101001,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src),
|
|
"fsqrts $src, $dst",
|
|
[(set FPRegs:$dst, (fsqrt FPRegs:$src))]>;
|
|
def FSQRTD : F3_3<2, 0b110100, 0b000101010,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
|
"fsqrtd $src, $dst",
|
|
[(set DFPRegs:$dst, (fsqrt DFPRegs:$src))]>;
|
|
|
|
|
|
|
|
// Floating-point Add and Subtract Instructions, p. 146
|
|
def FADDS : F3_3<2, 0b110100, 0b001000001,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
|
"fadds $src1, $src2, $dst",
|
|
[(set FPRegs:$dst, (fadd FPRegs:$src1, FPRegs:$src2))]>;
|
|
def FADDD : F3_3<2, 0b110100, 0b001000010,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
|
"faddd $src1, $src2, $dst",
|
|
[(set DFPRegs:$dst, (fadd DFPRegs:$src1, DFPRegs:$src2))]>;
|
|
def FSUBS : F3_3<2, 0b110100, 0b001000101,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
|
"fsubs $src1, $src2, $dst",
|
|
[(set FPRegs:$dst, (fsub FPRegs:$src1, FPRegs:$src2))]>;
|
|
def FSUBD : F3_3<2, 0b110100, 0b001000110,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
|
"fsubd $src1, $src2, $dst",
|
|
[(set DFPRegs:$dst, (fsub DFPRegs:$src1, DFPRegs:$src2))]>;
|
|
|
|
// Floating-point Multiply and Divide Instructions, p. 147
|
|
def FMULS : F3_3<2, 0b110100, 0b001001001,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
|
"fmuls $src1, $src2, $dst",
|
|
[(set FPRegs:$dst, (fmul FPRegs:$src1, FPRegs:$src2))]>;
|
|
def FMULD : F3_3<2, 0b110100, 0b001001010,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
|
"fmuld $src1, $src2, $dst",
|
|
[(set DFPRegs:$dst, (fmul DFPRegs:$src1, DFPRegs:$src2))]>;
|
|
def FSMULD : F3_3<2, 0b110100, 0b001101001,
|
|
(outs DFPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
|
"fsmuld $src1, $src2, $dst",
|
|
[(set DFPRegs:$dst, (fmul (fextend FPRegs:$src1),
|
|
(fextend FPRegs:$src2)))]>;
|
|
def FDIVS : F3_3<2, 0b110100, 0b001001101,
|
|
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
|
"fdivs $src1, $src2, $dst",
|
|
[(set FPRegs:$dst, (fdiv FPRegs:$src1, FPRegs:$src2))]>;
|
|
def FDIVD : F3_3<2, 0b110100, 0b001001110,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
|
"fdivd $src1, $src2, $dst",
|
|
[(set DFPRegs:$dst, (fdiv DFPRegs:$src1, DFPRegs:$src2))]>;
|
|
|
|
// Floating-point Compare Instructions, p. 148
|
|
// Note: the 2nd template arg is different for these guys.
|
|
// Note 2: the result of a FCMP is not available until the 2nd cycle
|
|
// after the instr is retired, but there is no interlock. This behavior
|
|
// is modelled with a forced noop after the instruction.
|
|
def FCMPS : F3_3<2, 0b110101, 0b001010001,
|
|
(outs), (ins FPRegs:$src1, FPRegs:$src2),
|
|
"fcmps $src1, $src2\n\tnop",
|
|
[(SPcmpfcc FPRegs:$src1, FPRegs:$src2)]>;
|
|
def FCMPD : F3_3<2, 0b110101, 0b001010010,
|
|
(outs), (ins DFPRegs:$src1, DFPRegs:$src2),
|
|
"fcmpd $src1, $src2\n\tnop",
|
|
[(SPcmpfcc DFPRegs:$src1, DFPRegs:$src2)]>;
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// V9 Instructions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// V9 Conditional Moves.
|
|
let Predicates = [HasV9], isTwoAddress = 1 in {
|
|
// Move Integer Register on Condition (MOVcc) p. 194 of the V9 manual.
|
|
// FIXME: Add instruction encodings for the JIT some day.
|
|
def MOVICCrr
|
|
: Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, IntRegs:$F, CCOp:$cc),
|
|
"mov$cc %icc, $F, $dst",
|
|
[(set IntRegs:$dst,
|
|
(SPselecticc IntRegs:$F, IntRegs:$T, imm:$cc))]>;
|
|
def MOVICCri
|
|
: Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, i32imm:$F, CCOp:$cc),
|
|
"mov$cc %icc, $F, $dst",
|
|
[(set IntRegs:$dst,
|
|
(SPselecticc simm11:$F, IntRegs:$T, imm:$cc))]>;
|
|
|
|
def MOVFCCrr
|
|
: Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, IntRegs:$F, CCOp:$cc),
|
|
"mov$cc %fcc0, $F, $dst",
|
|
[(set IntRegs:$dst,
|
|
(SPselectfcc IntRegs:$F, IntRegs:$T, imm:$cc))]>;
|
|
def MOVFCCri
|
|
: Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, i32imm:$F, CCOp:$cc),
|
|
"mov$cc %fcc0, $F, $dst",
|
|
[(set IntRegs:$dst,
|
|
(SPselectfcc simm11:$F, IntRegs:$T, imm:$cc))]>;
|
|
|
|
def FMOVS_ICC
|
|
: Pseudo<(outs FPRegs:$dst), (ins FPRegs:$T, FPRegs:$F, CCOp:$cc),
|
|
"fmovs$cc %icc, $F, $dst",
|
|
[(set FPRegs:$dst,
|
|
(SPselecticc FPRegs:$F, FPRegs:$T, imm:$cc))]>;
|
|
def FMOVD_ICC
|
|
: Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, CCOp:$cc),
|
|
"fmovd$cc %icc, $F, $dst",
|
|
[(set DFPRegs:$dst,
|
|
(SPselecticc DFPRegs:$F, DFPRegs:$T, imm:$cc))]>;
|
|
def FMOVS_FCC
|
|
: Pseudo<(outs FPRegs:$dst), (ins FPRegs:$T, FPRegs:$F, CCOp:$cc),
|
|
"fmovs$cc %fcc0, $F, $dst",
|
|
[(set FPRegs:$dst,
|
|
(SPselectfcc FPRegs:$F, FPRegs:$T, imm:$cc))]>;
|
|
def FMOVD_FCC
|
|
: Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, CCOp:$cc),
|
|
"fmovd$cc %fcc0, $F, $dst",
|
|
[(set DFPRegs:$dst,
|
|
(SPselectfcc DFPRegs:$F, DFPRegs:$T, imm:$cc))]>;
|
|
|
|
}
|
|
|
|
// Floating-Point Move Instructions, p. 164 of the V9 manual.
|
|
let Predicates = [HasV9] in {
|
|
def FMOVD : F3_3<2, 0b110100, 0b000000010,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
|
"fmovd $src, $dst", []>;
|
|
def FNEGD : F3_3<2, 0b110100, 0b000000110,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
|
"fnegd $src, $dst",
|
|
[(set DFPRegs:$dst, (fneg DFPRegs:$src))]>;
|
|
def FABSD : F3_3<2, 0b110100, 0b000001010,
|
|
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
|
"fabsd $src, $dst",
|
|
[(set DFPRegs:$dst, (fabs DFPRegs:$src))]>;
|
|
}
|
|
|
|
// POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear
|
|
// the top 32-bits before using it. To do this clearing, we use a SLLri X,0.
|
|
def POPCrr : F3_1<2, 0b101110,
|
|
(outs IntRegs:$dst), (ins IntRegs:$src),
|
|
"popc $src, $dst", []>, Requires<[HasV9]>;
|
|
def : Pat<(ctpop IntRegs:$src),
|
|
(POPCrr (SLLri IntRegs:$src, 0))>;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Non-Instruction Patterns
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Small immediates.
|
|
def : Pat<(i32 simm13:$val),
|
|
(ORri G0, imm:$val)>;
|
|
// Arbitrary immediates.
|
|
def : Pat<(i32 imm:$val),
|
|
(ORri (SETHIi (HI22 imm:$val)), (LO10 imm:$val))>;
|
|
|
|
// subc
|
|
def : Pat<(subc IntRegs:$b, IntRegs:$c),
|
|
(SUBCCrr IntRegs:$b, IntRegs:$c)>;
|
|
def : Pat<(subc IntRegs:$b, simm13:$val),
|
|
(SUBCCri IntRegs:$b, imm:$val)>;
|
|
|
|
// Global addresses, constant pool entries
|
|
def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>;
|
|
def : Pat<(SPlo tglobaladdr:$in), (ORri G0, tglobaladdr:$in)>;
|
|
def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>;
|
|
def : Pat<(SPlo tconstpool:$in), (ORri G0, tconstpool:$in)>;
|
|
|
|
// Add reg, lo. This is used when taking the addr of a global/constpool entry.
|
|
def : Pat<(add IntRegs:$r, (SPlo tglobaladdr:$in)),
|
|
(ADDri IntRegs:$r, tglobaladdr:$in)>;
|
|
def : Pat<(add IntRegs:$r, (SPlo tconstpool:$in)),
|
|
(ADDri IntRegs:$r, tconstpool:$in)>;
|
|
|
|
// Calls:
|
|
def : Pat<(call tglobaladdr:$dst),
|
|
(CALL tglobaladdr:$dst)>;
|
|
def : Pat<(call texternalsym:$dst),
|
|
(CALL texternalsym:$dst)>;
|
|
|
|
def : Pat<(ret), (RETL)>;
|
|
|
|
// Map integer extload's to zextloads.
|
|
def : Pat<(i32 (extloadi1 ADDRrr:$src)), (LDUBrr ADDRrr:$src)>;
|
|
def : Pat<(i32 (extloadi1 ADDRri:$src)), (LDUBri ADDRri:$src)>;
|
|
def : Pat<(i32 (extloadi8 ADDRrr:$src)), (LDUBrr ADDRrr:$src)>;
|
|
def : Pat<(i32 (extloadi8 ADDRri:$src)), (LDUBri ADDRri:$src)>;
|
|
def : Pat<(i32 (extloadi16 ADDRrr:$src)), (LDUHrr ADDRrr:$src)>;
|
|
def : Pat<(i32 (extloadi16 ADDRri:$src)), (LDUHri ADDRri:$src)>;
|
|
|
|
// zextload bool -> zextload byte
|
|
def : Pat<(i32 (zextloadi1 ADDRrr:$src)), (LDUBrr ADDRrr:$src)>;
|
|
def : Pat<(i32 (zextloadi1 ADDRri:$src)), (LDUBri ADDRri:$src)>;
|