// TODO: 2-address instructions. Mark ops as needing matching input/output regs.
var AMD64ops = []opData{
// fp ops
- {name: "ADDSS", reg: fp21, asm: "ADDSS"}, // fp32 add
- {name: "ADDSD", reg: fp21, asm: "ADDSD"}, // fp64 add
- {name: "SUBSS", reg: fp21x15, asm: "SUBSS"}, // fp32 sub
- {name: "SUBSD", reg: fp21x15, asm: "SUBSD"}, // fp64 sub
- {name: "MULSS", reg: fp21, asm: "MULSS"}, // fp32 mul
- {name: "MULSD", reg: fp21, asm: "MULSD"}, // fp64 mul
- {name: "DIVSS", reg: fp21x15, asm: "DIVSS"}, // fp32 div
- {name: "DIVSD", reg: fp21x15, asm: "DIVSD"}, // fp64 div
-
- {name: "MOVSSload", reg: fpload, asm: "MOVSS", aux: "SymOff"}, // fp32 load
- {name: "MOVSDload", reg: fpload, asm: "MOVSD", aux: "SymOff"}, // fp64 load
+ {name: "ADDSS", argLength: 2, reg: fp21, asm: "ADDSS"}, // fp32 add
+ {name: "ADDSD", argLength: 2, reg: fp21, asm: "ADDSD"}, // fp64 add
+ {name: "SUBSS", argLength: 2, reg: fp21x15, asm: "SUBSS"}, // fp32 sub
+ {name: "SUBSD", argLength: 2, reg: fp21x15, asm: "SUBSD"}, // fp64 sub
+ {name: "MULSS", argLength: 2, reg: fp21, asm: "MULSS"}, // fp32 mul
+ {name: "MULSD", argLength: 2, reg: fp21, asm: "MULSD"}, // fp64 mul
+ {name: "DIVSS", argLength: 2, reg: fp21x15, asm: "DIVSS"}, // fp32 div
+ {name: "DIVSD", argLength: 2, reg: fp21x15, asm: "DIVSD"}, // fp64 div
+
+ {name: "MOVSSload", argLength: 2, reg: fpload, asm: "MOVSS", aux: "SymOff"}, // fp32 load
+ {name: "MOVSDload", argLength: 2, reg: fpload, asm: "MOVSD", aux: "SymOff"}, // fp64 load
{name: "MOVSSconst", reg: fp01, asm: "MOVSS", aux: "Float", rematerializeable: true}, // fp32 constant
{name: "MOVSDconst", reg: fp01, asm: "MOVSD", aux: "Float", rematerializeable: true}, // fp64 constant
- {name: "MOVSSloadidx4", reg: fploadidx, asm: "MOVSS", aux: "SymOff"}, // fp32 load
- {name: "MOVSDloadidx8", reg: fploadidx, asm: "MOVSD", aux: "SymOff"}, // fp64 load
+ {name: "MOVSSloadidx4", argLength: 3, reg: fploadidx, asm: "MOVSS", aux: "SymOff"}, // fp32 load
+ {name: "MOVSDloadidx8", argLength: 3, reg: fploadidx, asm: "MOVSD", aux: "SymOff"}, // fp64 load
- {name: "MOVSSstore", reg: fpstore, asm: "MOVSS", aux: "SymOff"}, // fp32 store
- {name: "MOVSDstore", reg: fpstore, asm: "MOVSD", aux: "SymOff"}, // fp64 store
- {name: "MOVSSstoreidx4", reg: fpstoreidx, asm: "MOVSS", aux: "SymOff"}, // fp32 indexed by 4i store
- {name: "MOVSDstoreidx8", reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by 8i store
+ {name: "MOVSSstore", argLength: 3, reg: fpstore, asm: "MOVSS", aux: "SymOff"}, // fp32 store
+ {name: "MOVSDstore", argLength: 3, reg: fpstore, asm: "MOVSD", aux: "SymOff"}, // fp64 store
+ {name: "MOVSSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "MOVSS", aux: "SymOff"}, // fp32 indexed by 4i store
+ {name: "MOVSDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by 8i store
// binary ops
- {name: "ADDQ", reg: gp21, asm: "ADDQ"}, // arg0 + arg1
- {name: "ADDL", reg: gp21, asm: "ADDL"}, // arg0 + arg1
- {name: "ADDW", reg: gp21, asm: "ADDW"}, // arg0 + arg1
- {name: "ADDB", reg: gp21, asm: "ADDB"}, // arg0 + arg1
- {name: "ADDQconst", reg: gp11, asm: "ADDQ", aux: "Int64", typ: "UInt64"}, // arg0 + auxint
- {name: "ADDLconst", reg: gp11, asm: "ADDL", aux: "Int32"}, // arg0 + auxint
- {name: "ADDWconst", reg: gp11, asm: "ADDW", aux: "Int16"}, // arg0 + auxint
- {name: "ADDBconst", reg: gp11, asm: "ADDB", aux: "Int8"}, // arg0 + auxint
-
- {name: "SUBQ", reg: gp21, asm: "SUBQ"}, // arg0 - arg1
- {name: "SUBL", reg: gp21, asm: "SUBL"}, // arg0 - arg1
- {name: "SUBW", reg: gp21, asm: "SUBW"}, // arg0 - arg1
- {name: "SUBB", reg: gp21, asm: "SUBB"}, // arg0 - arg1
- {name: "SUBQconst", reg: gp11, asm: "SUBQ", aux: "Int64"}, // arg0 - auxint
- {name: "SUBLconst", reg: gp11, asm: "SUBL", aux: "Int32"}, // arg0 - auxint
- {name: "SUBWconst", reg: gp11, asm: "SUBW", aux: "Int16"}, // arg0 - auxint
- {name: "SUBBconst", reg: gp11, asm: "SUBB", aux: "Int8"}, // arg0 - auxint
-
- {name: "MULQ", reg: gp21, asm: "IMULQ"}, // arg0 * arg1
- {name: "MULL", reg: gp21, asm: "IMULL"}, // arg0 * arg1
- {name: "MULW", reg: gp21, asm: "IMULW"}, // arg0 * arg1
- {name: "MULB", reg: gp21, asm: "IMULW"}, // arg0 * arg1
- {name: "MULQconst", reg: gp11, asm: "IMULQ", aux: "Int64"}, // arg0 * auxint
- {name: "MULLconst", reg: gp11, asm: "IMULL", aux: "Int32"}, // arg0 * auxint
- {name: "MULWconst", reg: gp11, asm: "IMULW", aux: "Int16"}, // arg0 * auxint
- {name: "MULBconst", reg: gp11, asm: "IMULW", aux: "Int8"}, // arg0 * auxint
-
- {name: "HMULQ", reg: gp11hmul, asm: "IMULQ"}, // (arg0 * arg1) >> width
- {name: "HMULL", reg: gp11hmul, asm: "IMULL"}, // (arg0 * arg1) >> width
- {name: "HMULW", reg: gp11hmul, asm: "IMULW"}, // (arg0 * arg1) >> width
- {name: "HMULB", reg: gp11hmul, asm: "IMULB"}, // (arg0 * arg1) >> width
- {name: "HMULQU", reg: gp11hmul, asm: "MULQ"}, // (arg0 * arg1) >> width
- {name: "HMULLU", reg: gp11hmul, asm: "MULL"}, // (arg0 * arg1) >> width
- {name: "HMULWU", reg: gp11hmul, asm: "MULW"}, // (arg0 * arg1) >> width
- {name: "HMULBU", reg: gp11hmul, asm: "MULB"}, // (arg0 * arg1) >> width
-
- {name: "AVGQU", reg: gp21}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits
-
- {name: "DIVQ", reg: gp11div, asm: "IDIVQ"}, // arg0 / arg1
- {name: "DIVL", reg: gp11div, asm: "IDIVL"}, // arg0 / arg1
- {name: "DIVW", reg: gp11div, asm: "IDIVW"}, // arg0 / arg1
- {name: "DIVQU", reg: gp11div, asm: "DIVQ"}, // arg0 / arg1
- {name: "DIVLU", reg: gp11div, asm: "DIVL"}, // arg0 / arg1
- {name: "DIVWU", reg: gp11div, asm: "DIVW"}, // arg0 / arg1
-
- {name: "MODQ", reg: gp11mod, asm: "IDIVQ"}, // arg0 % arg1
- {name: "MODL", reg: gp11mod, asm: "IDIVL"}, // arg0 % arg1
- {name: "MODW", reg: gp11mod, asm: "IDIVW"}, // arg0 % arg1
- {name: "MODQU", reg: gp11mod, asm: "DIVQ"}, // arg0 % arg1
- {name: "MODLU", reg: gp11mod, asm: "DIVL"}, // arg0 % arg1
- {name: "MODWU", reg: gp11mod, asm: "DIVW"}, // arg0 % arg1
-
- {name: "ANDQ", reg: gp21, asm: "ANDQ"}, // arg0 & arg1
- {name: "ANDL", reg: gp21, asm: "ANDL"}, // arg0 & arg1
- {name: "ANDW", reg: gp21, asm: "ANDW"}, // arg0 & arg1
- {name: "ANDB", reg: gp21, asm: "ANDB"}, // arg0 & arg1
- {name: "ANDQconst", reg: gp11, asm: "ANDQ", aux: "Int64"}, // arg0 & auxint
- {name: "ANDLconst", reg: gp11, asm: "ANDL", aux: "Int32"}, // arg0 & auxint
- {name: "ANDWconst", reg: gp11, asm: "ANDW", aux: "Int16"}, // arg0 & auxint
- {name: "ANDBconst", reg: gp11, asm: "ANDB", aux: "Int8"}, // arg0 & auxint
-
- {name: "ORQ", reg: gp21, asm: "ORQ"}, // arg0 | arg1
- {name: "ORL", reg: gp21, asm: "ORL"}, // arg0 | arg1
- {name: "ORW", reg: gp21, asm: "ORW"}, // arg0 | arg1
- {name: "ORB", reg: gp21, asm: "ORB"}, // arg0 | arg1
- {name: "ORQconst", reg: gp11, asm: "ORQ", aux: "Int64"}, // arg0 | auxint
- {name: "ORLconst", reg: gp11, asm: "ORL", aux: "Int32"}, // arg0 | auxint
- {name: "ORWconst", reg: gp11, asm: "ORW", aux: "Int16"}, // arg0 | auxint
- {name: "ORBconst", reg: gp11, asm: "ORB", aux: "Int8"}, // arg0 | auxint
-
- {name: "XORQ", reg: gp21, asm: "XORQ"}, // arg0 ^ arg1
- {name: "XORL", reg: gp21, asm: "XORL"}, // arg0 ^ arg1
- {name: "XORW", reg: gp21, asm: "XORW"}, // arg0 ^ arg1
- {name: "XORB", reg: gp21, asm: "XORB"}, // arg0 ^ arg1
- {name: "XORQconst", reg: gp11, asm: "XORQ", aux: "Int64"}, // arg0 ^ auxint
- {name: "XORLconst", reg: gp11, asm: "XORL", aux: "Int32"}, // arg0 ^ auxint
- {name: "XORWconst", reg: gp11, asm: "XORW", aux: "Int16"}, // arg0 ^ auxint
- {name: "XORBconst", reg: gp11, asm: "XORB", aux: "Int8"}, // arg0 ^ auxint
-
- {name: "CMPQ", reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1
- {name: "CMPL", reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1
- {name: "CMPW", reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1
- {name: "CMPB", reg: gp2flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to arg1
- {name: "CMPQconst", reg: gp1flags, asm: "CMPQ", typ: "Flags", aux: "Int64"}, // arg0 compare to auxint
- {name: "CMPLconst", reg: gp1flags, asm: "CMPL", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint
- {name: "CMPWconst", reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int16"}, // arg0 compare to auxint
- {name: "CMPBconst", reg: gp1flags, asm: "CMPB", typ: "Flags", aux: "Int8"}, // arg0 compare to auxint
-
- {name: "UCOMISS", reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32
- {name: "UCOMISD", reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64
-
- {name: "TESTQ", reg: gp2flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0
- {name: "TESTL", reg: gp2flags, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0
- {name: "TESTW", reg: gp2flags, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0
- {name: "TESTB", reg: gp2flags, asm: "TESTB", typ: "Flags"}, // (arg0 & arg1) compare to 0
- {name: "TESTQconst", reg: gp1flags, asm: "TESTQ", typ: "Flags", aux: "Int64"}, // (arg0 & auxint) compare to 0
- {name: "TESTLconst", reg: gp1flags, asm: "TESTL", typ: "Flags", aux: "Int32"}, // (arg0 & auxint) compare to 0
- {name: "TESTWconst", reg: gp1flags, asm: "TESTW", typ: "Flags", aux: "Int16"}, // (arg0 & auxint) compare to 0
- {name: "TESTBconst", reg: gp1flags, asm: "TESTB", typ: "Flags", aux: "Int8"}, // (arg0 & auxint) compare to 0
-
- {name: "SHLQ", reg: gp21shift, asm: "SHLQ"}, // arg0 << arg1, shift amount is mod 64
- {name: "SHLL", reg: gp21shift, asm: "SHLL"}, // arg0 << arg1, shift amount is mod 32
- {name: "SHLW", reg: gp21shift, asm: "SHLW"}, // arg0 << arg1, shift amount is mod 32
- {name: "SHLB", reg: gp21shift, asm: "SHLB"}, // arg0 << arg1, shift amount is mod 32
- {name: "SHLQconst", reg: gp11, asm: "SHLQ", aux: "Int64"}, // arg0 << auxint, shift amount 0-63
- {name: "SHLLconst", reg: gp11, asm: "SHLL", aux: "Int32"}, // arg0 << auxint, shift amount 0-31
- {name: "SHLWconst", reg: gp11, asm: "SHLW", aux: "Int16"}, // arg0 << auxint, shift amount 0-31
- {name: "SHLBconst", reg: gp11, asm: "SHLB", aux: "Int8"}, // arg0 << auxint, shift amount 0-31
+ {name: "ADDQ", argLength: 2, reg: gp21, asm: "ADDQ"}, // arg0 + arg1
+ {name: "ADDL", argLength: 2, reg: gp21, asm: "ADDL"}, // arg0 + arg1
+ {name: "ADDW", argLength: 2, reg: gp21, asm: "ADDW"}, // arg0 + arg1
+ {name: "ADDB", argLength: 2, reg: gp21, asm: "ADDB"}, // arg0 + arg1
+ {name: "ADDQconst", argLength: 1, reg: gp11, asm: "ADDQ", aux: "Int64", typ: "UInt64"}, // arg0 + auxint
+ {name: "ADDLconst", argLength: 1, reg: gp11, asm: "ADDL", aux: "Int32"}, // arg0 + auxint
+ {name: "ADDWconst", argLength: 1, reg: gp11, asm: "ADDW", aux: "Int16"}, // arg0 + auxint
+ {name: "ADDBconst", argLength: 1, reg: gp11, asm: "ADDB", aux: "Int8"}, // arg0 + auxint
+
+ {name: "SUBQ", argLength: 2, reg: gp21, asm: "SUBQ"}, // arg0 - arg1
+ {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL"}, // arg0 - arg1
+ {name: "SUBW", argLength: 2, reg: gp21, asm: "SUBW"}, // arg0 - arg1
+ {name: "SUBB", argLength: 2, reg: gp21, asm: "SUBB"}, // arg0 - arg1
+ {name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int64"}, // arg0 - auxint
+ {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32"}, // arg0 - auxint
+ {name: "SUBWconst", argLength: 1, reg: gp11, asm: "SUBW", aux: "Int16"}, // arg0 - auxint
+ {name: "SUBBconst", argLength: 1, reg: gp11, asm: "SUBB", aux: "Int8"}, // arg0 - auxint
+
+ {name: "MULQ", argLength: 2, reg: gp21, asm: "IMULQ"}, // arg0 * arg1
+ {name: "MULL", argLength: 2, reg: gp21, asm: "IMULL"}, // arg0 * arg1
+ {name: "MULW", argLength: 2, reg: gp21, asm: "IMULW"}, // arg0 * arg1
+ {name: "MULB", argLength: 2, reg: gp21, asm: "IMULW"}, // arg0 * arg1
+ {name: "MULQconst", argLength: 1, reg: gp11, asm: "IMULQ", aux: "Int64"}, // arg0 * auxint
+ {name: "MULLconst", argLength: 1, reg: gp11, asm: "IMULL", aux: "Int32"}, // arg0 * auxint
+ {name: "MULWconst", argLength: 1, reg: gp11, asm: "IMULW", aux: "Int16"}, // arg0 * auxint
+ {name: "MULBconst", argLength: 1, reg: gp11, asm: "IMULW", aux: "Int8"}, // arg0 * auxint
+
+ {name: "HMULQ", argLength: 2, reg: gp11hmul, asm: "IMULQ"}, // (arg0 * arg1) >> width
+ {name: "HMULL", argLength: 2, reg: gp11hmul, asm: "IMULL"}, // (arg0 * arg1) >> width
+ {name: "HMULW", argLength: 2, reg: gp11hmul, asm: "IMULW"}, // (arg0 * arg1) >> width
+ {name: "HMULB", argLength: 2, reg: gp11hmul, asm: "IMULB"}, // (arg0 * arg1) >> width
+ {name: "HMULQU", argLength: 2, reg: gp11hmul, asm: "MULQ"}, // (arg0 * arg1) >> width
+ {name: "HMULLU", argLength: 2, reg: gp11hmul, asm: "MULL"}, // (arg0 * arg1) >> width
+ {name: "HMULWU", argLength: 2, reg: gp11hmul, asm: "MULW"}, // (arg0 * arg1) >> width
+ {name: "HMULBU", argLength: 2, reg: gp11hmul, asm: "MULB"}, // (arg0 * arg1) >> width
+
+ {name: "AVGQU", argLength: 2, reg: gp21}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits
+
+ {name: "DIVQ", argLength: 2, reg: gp11div, asm: "IDIVQ"}, // arg0 / arg1
+ {name: "DIVL", argLength: 2, reg: gp11div, asm: "IDIVL"}, // arg0 / arg1
+ {name: "DIVW", argLength: 2, reg: gp11div, asm: "IDIVW"}, // arg0 / arg1
+ {name: "DIVQU", argLength: 2, reg: gp11div, asm: "DIVQ"}, // arg0 / arg1
+ {name: "DIVLU", argLength: 2, reg: gp11div, asm: "DIVL"}, // arg0 / arg1
+ {name: "DIVWU", argLength: 2, reg: gp11div, asm: "DIVW"}, // arg0 / arg1
+
+ {name: "MODQ", argLength: 2, reg: gp11mod, asm: "IDIVQ"}, // arg0 % arg1
+ {name: "MODL", argLength: 2, reg: gp11mod, asm: "IDIVL"}, // arg0 % arg1
+ {name: "MODW", argLength: 2, reg: gp11mod, asm: "IDIVW"}, // arg0 % arg1
+ {name: "MODQU", argLength: 2, reg: gp11mod, asm: "DIVQ"}, // arg0 % arg1
+ {name: "MODLU", argLength: 2, reg: gp11mod, asm: "DIVL"}, // arg0 % arg1
+ {name: "MODWU", argLength: 2, reg: gp11mod, asm: "DIVW"}, // arg0 % arg1
+
+ {name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ"}, // arg0 & arg1
+ {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL"}, // arg0 & arg1
+ {name: "ANDW", argLength: 2, reg: gp21, asm: "ANDW"}, // arg0 & arg1
+ {name: "ANDB", argLength: 2, reg: gp21, asm: "ANDB"}, // arg0 & arg1
+ {name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int64"}, // arg0 & auxint
+ {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32"}, // arg0 & auxint
+ {name: "ANDWconst", argLength: 1, reg: gp11, asm: "ANDW", aux: "Int16"}, // arg0 & auxint
+ {name: "ANDBconst", argLength: 1, reg: gp11, asm: "ANDB", aux: "Int8"}, // arg0 & auxint
+
+ {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ"}, // arg0 | arg1
+ {name: "ORL", argLength: 2, reg: gp21, asm: "ORL"}, // arg0 | arg1
+ {name: "ORW", argLength: 2, reg: gp21, asm: "ORW"}, // arg0 | arg1
+ {name: "ORB", argLength: 2, reg: gp21, asm: "ORB"}, // arg0 | arg1
+ {name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int64"}, // arg0 | auxint
+ {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32"}, // arg0 | auxint
+ {name: "ORWconst", argLength: 1, reg: gp11, asm: "ORW", aux: "Int16"}, // arg0 | auxint
+ {name: "ORBconst", argLength: 1, reg: gp11, asm: "ORB", aux: "Int8"}, // arg0 | auxint
+
+ {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ"}, // arg0 ^ arg1
+ {name: "XORL", argLength: 2, reg: gp21, asm: "XORL"}, // arg0 ^ arg1
+ {name: "XORW", argLength: 2, reg: gp21, asm: "XORW"}, // arg0 ^ arg1
+ {name: "XORB", argLength: 2, reg: gp21, asm: "XORB"}, // arg0 ^ arg1
+ {name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int64"}, // arg0 ^ auxint
+ {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32"}, // arg0 ^ auxint
+ {name: "XORWconst", argLength: 1, reg: gp11, asm: "XORW", aux: "Int16"}, // arg0 ^ auxint
+ {name: "XORBconst", argLength: 1, reg: gp11, asm: "XORB", aux: "Int8"}, // arg0 ^ auxint
+
+ {name: "CMPQ", argLength: 2, reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPL", argLength: 2, reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPW", argLength: 2, reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPB", argLength: 2, reg: gp2flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to arg1
+ {name: "CMPQconst", argLength: 1, reg: gp1flags, asm: "CMPQ", typ: "Flags", aux: "Int64"}, // arg0 compare to auxint
+ {name: "CMPLconst", argLength: 1, reg: gp1flags, asm: "CMPL", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint
+ {name: "CMPWconst", argLength: 1, reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int16"}, // arg0 compare to auxint
+ {name: "CMPBconst", argLength: 1, reg: gp1flags, asm: "CMPB", typ: "Flags", aux: "Int8"}, // arg0 compare to auxint
+
+ {name: "UCOMISS", argLength: 2, reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32
+ {name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64
+
+ {name: "TESTQ", argLength: 2, reg: gp2flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0
+ {name: "TESTL", argLength: 2, reg: gp2flags, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0
+ {name: "TESTW", argLength: 2, reg: gp2flags, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0
+ {name: "TESTB", argLength: 2, reg: gp2flags, asm: "TESTB", typ: "Flags"}, // (arg0 & arg1) compare to 0
+ {name: "TESTQconst", argLength: 1, reg: gp1flags, asm: "TESTQ", typ: "Flags", aux: "Int64"}, // (arg0 & auxint) compare to 0
+ {name: "TESTLconst", argLength: 1, reg: gp1flags, asm: "TESTL", typ: "Flags", aux: "Int32"}, // (arg0 & auxint) compare to 0
+ {name: "TESTWconst", argLength: 1, reg: gp1flags, asm: "TESTW", typ: "Flags", aux: "Int16"}, // (arg0 & auxint) compare to 0
+ {name: "TESTBconst", argLength: 1, reg: gp1flags, asm: "TESTB", typ: "Flags", aux: "Int8"}, // (arg0 & auxint) compare to 0
+
+ {name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ"}, // arg0 << arg1, shift amount is mod 64
+ {name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL"}, // arg0 << arg1, shift amount is mod 32
+ {name: "SHLW", argLength: 2, reg: gp21shift, asm: "SHLW"}, // arg0 << arg1, shift amount is mod 32
+ {name: "SHLB", argLength: 2, reg: gp21shift, asm: "SHLB"}, // arg0 << arg1, shift amount is mod 32
+ {name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int64"}, // arg0 << auxint, shift amount 0-63
+ {name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int32"}, // arg0 << auxint, shift amount 0-31
+ {name: "SHLWconst", argLength: 1, reg: gp11, asm: "SHLW", aux: "Int16"}, // arg0 << auxint, shift amount 0-31
+ {name: "SHLBconst", argLength: 1, reg: gp11, asm: "SHLB", aux: "Int8"}, // arg0 << auxint, shift amount 0-31
// Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!
- {name: "SHRQ", reg: gp21shift, asm: "SHRQ"}, // unsigned arg0 >> arg1, shift amount is mod 64
- {name: "SHRL", reg: gp21shift, asm: "SHRL"}, // unsigned arg0 >> arg1, shift amount is mod 32
- {name: "SHRW", reg: gp21shift, asm: "SHRW"}, // unsigned arg0 >> arg1, shift amount is mod 32
- {name: "SHRB", reg: gp21shift, asm: "SHRB"}, // unsigned arg0 >> arg1, shift amount is mod 32
- {name: "SHRQconst", reg: gp11, asm: "SHRQ", aux: "Int64"}, // unsigned arg0 >> auxint, shift amount 0-63
- {name: "SHRLconst", reg: gp11, asm: "SHRL", aux: "Int32"}, // unsigned arg0 >> auxint, shift amount 0-31
- {name: "SHRWconst", reg: gp11, asm: "SHRW", aux: "Int16"}, // unsigned arg0 >> auxint, shift amount 0-31
- {name: "SHRBconst", reg: gp11, asm: "SHRB", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-31
-
- {name: "SARQ", reg: gp21shift, asm: "SARQ"}, // signed arg0 >> arg1, shift amount is mod 64
- {name: "SARL", reg: gp21shift, asm: "SARL"}, // signed arg0 >> arg1, shift amount is mod 32
- {name: "SARW", reg: gp21shift, asm: "SARW"}, // signed arg0 >> arg1, shift amount is mod 32
- {name: "SARB", reg: gp21shift, asm: "SARB"}, // signed arg0 >> arg1, shift amount is mod 32
- {name: "SARQconst", reg: gp11, asm: "SARQ", aux: "Int64"}, // signed arg0 >> auxint, shift amount 0-63
- {name: "SARLconst", reg: gp11, asm: "SARL", aux: "Int32"}, // signed arg0 >> auxint, shift amount 0-31
- {name: "SARWconst", reg: gp11, asm: "SARW", aux: "Int16"}, // signed arg0 >> auxint, shift amount 0-31
- {name: "SARBconst", reg: gp11, asm: "SARB", aux: "Int8"}, // signed arg0 >> auxint, shift amount 0-31
-
- {name: "ROLQconst", reg: gp11, asm: "ROLQ", aux: "Int64"}, // arg0 rotate left auxint, rotate amount 0-63
- {name: "ROLLconst", reg: gp11, asm: "ROLL", aux: "Int32"}, // arg0 rotate left auxint, rotate amount 0-31
- {name: "ROLWconst", reg: gp11, asm: "ROLW", aux: "Int16"}, // arg0 rotate left auxint, rotate amount 0-15
- {name: "ROLBconst", reg: gp11, asm: "ROLB", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-7
+ {name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ"}, // unsigned arg0 >> arg1, shift amount is mod 64
+ {name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL"}, // unsigned arg0 >> arg1, shift amount is mod 32
+ {name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW"}, // unsigned arg0 >> arg1, shift amount is mod 32
+ {name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB"}, // unsigned arg0 >> arg1, shift amount is mod 32
+ {name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int64"}, // unsigned arg0 >> auxint, shift amount 0-63
+ {name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int32"}, // unsigned arg0 >> auxint, shift amount 0-31
+ {name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int16"}, // unsigned arg0 >> auxint, shift amount 0-31
+ {name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-31
+
+ {name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ"}, // signed arg0 >> arg1, shift amount is mod 64
+ {name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL"}, // signed arg0 >> arg1, shift amount is mod 32
+ {name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW"}, // signed arg0 >> arg1, shift amount is mod 32
+ {name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB"}, // signed arg0 >> arg1, shift amount is mod 32
+ {name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int64"}, // signed arg0 >> auxint, shift amount 0-63
+ {name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int32"}, // signed arg0 >> auxint, shift amount 0-31
+ {name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int16"}, // signed arg0 >> auxint, shift amount 0-31
+ {name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8"}, // signed arg0 >> auxint, shift amount 0-31
+
+ {name: "ROLQconst", argLength: 1, reg: gp11, asm: "ROLQ", aux: "Int64"}, // arg0 rotate left auxint, rotate amount 0-63
+ {name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int32"}, // arg0 rotate left auxint, rotate amount 0-31
+ {name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int16"}, // arg0 rotate left auxint, rotate amount 0-15
+ {name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-7
// unary ops
- {name: "NEGQ", reg: gp11, asm: "NEGQ"}, // -arg0
- {name: "NEGL", reg: gp11, asm: "NEGL"}, // -arg0
- {name: "NEGW", reg: gp11, asm: "NEGW"}, // -arg0
- {name: "NEGB", reg: gp11, asm: "NEGB"}, // -arg0
+ {name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ"}, // -arg0
+ {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL"}, // -arg0
+ {name: "NEGW", argLength: 1, reg: gp11, asm: "NEGW"}, // -arg0
+ {name: "NEGB", argLength: 1, reg: gp11, asm: "NEGB"}, // -arg0
- {name: "NOTQ", reg: gp11, asm: "NOTQ"}, // ^arg0
- {name: "NOTL", reg: gp11, asm: "NOTL"}, // ^arg0
- {name: "NOTW", reg: gp11, asm: "NOTW"}, // ^arg0
- {name: "NOTB", reg: gp11, asm: "NOTB"}, // ^arg0
+ {name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ"}, // ^arg0
+ {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL"}, // ^arg0
+ {name: "NOTW", argLength: 1, reg: gp11, asm: "NOTW"}, // ^arg0
+ {name: "NOTB", argLength: 1, reg: gp11, asm: "NOTB"}, // ^arg0
- {name: "SQRTSD", reg: fp11, asm: "SQRTSD"}, // sqrt(arg0)
+ {name: "SQRTSD", argLength: 1, reg: fp11, asm: "SQRTSD"}, // sqrt(arg0)
- {name: "SBBQcarrymask", reg: flagsgp, asm: "SBBQ"}, // (int64)(-1) if carry is set, 0 if carry is clear.
- {name: "SBBLcarrymask", reg: flagsgp, asm: "SBBL"}, // (int32)(-1) if carry is set, 0 if carry is clear.
+ {name: "SBBQcarrymask", argLength: 1, reg: flagsgp, asm: "SBBQ"}, // (int64)(-1) if carry is set, 0 if carry is clear.
+ {name: "SBBLcarrymask", argLength: 1, reg: flagsgp, asm: "SBBL"}, // (int32)(-1) if carry is set, 0 if carry is clear.
// Note: SBBW and SBBB are subsumed by SBBL
- {name: "SETEQ", reg: readflags, asm: "SETEQ"}, // extract == condition from arg0
- {name: "SETNE", reg: readflags, asm: "SETNE"}, // extract != condition from arg0
- {name: "SETL", reg: readflags, asm: "SETLT"}, // extract signed < condition from arg0
- {name: "SETLE", reg: readflags, asm: "SETLE"}, // extract signed <= condition from arg0
- {name: "SETG", reg: readflags, asm: "SETGT"}, // extract signed > condition from arg0
- {name: "SETGE", reg: readflags, asm: "SETGE"}, // extract signed >= condition from arg0
- {name: "SETB", reg: readflags, asm: "SETCS"}, // extract unsigned < condition from arg0
- {name: "SETBE", reg: readflags, asm: "SETLS"}, // extract unsigned <= condition from arg0
- {name: "SETA", reg: readflags, asm: "SETHI"}, // extract unsigned > condition from arg0
- {name: "SETAE", reg: readflags, asm: "SETCC"}, // extract unsigned >= condition from arg0
+ {name: "SETEQ", argLength: 1, reg: readflags, asm: "SETEQ"}, // extract == condition from arg0
+ {name: "SETNE", argLength: 1, reg: readflags, asm: "SETNE"}, // extract != condition from arg0
+ {name: "SETL", argLength: 1, reg: readflags, asm: "SETLT"}, // extract signed < condition from arg0
+ {name: "SETLE", argLength: 1, reg: readflags, asm: "SETLE"}, // extract signed <= condition from arg0
+ {name: "SETG", argLength: 1, reg: readflags, asm: "SETGT"}, // extract signed > condition from arg0
+ {name: "SETGE", argLength: 1, reg: readflags, asm: "SETGE"}, // extract signed >= condition from arg0
+ {name: "SETB", argLength: 1, reg: readflags, asm: "SETCS"}, // extract unsigned < condition from arg0
+ {name: "SETBE", argLength: 1, reg: readflags, asm: "SETLS"}, // extract unsigned <= condition from arg0
+ {name: "SETA", argLength: 1, reg: readflags, asm: "SETHI"}, // extract unsigned > condition from arg0
+ {name: "SETAE", argLength: 1, reg: readflags, asm: "SETCC"}, // extract unsigned >= condition from arg0
// Need different opcodes for floating point conditions because
// any comparison involving a NaN is always FALSE and thus
// the patterns for inverting conditions cannot be used.
- {name: "SETEQF", reg: flagsgpax, asm: "SETEQ"}, // extract == condition from arg0
- {name: "SETNEF", reg: flagsgpax, asm: "SETNE"}, // extract != condition from arg0
- {name: "SETORD", reg: flagsgp, asm: "SETPC"}, // extract "ordered" (No Nan present) condition from arg0
- {name: "SETNAN", reg: flagsgp, asm: "SETPS"}, // extract "unordered" (Nan present) condition from arg0
+ {name: "SETEQF", argLength: 1, reg: flagsgpax, asm: "SETEQ"}, // extract == condition from arg0
+ {name: "SETNEF", argLength: 1, reg: flagsgpax, asm: "SETNE"}, // extract != condition from arg0
+ {name: "SETORD", argLength: 1, reg: flagsgp, asm: "SETPC"}, // extract "ordered" (No Nan present) condition from arg0
+ {name: "SETNAN", argLength: 1, reg: flagsgp, asm: "SETPS"}, // extract "unordered" (Nan present) condition from arg0
- {name: "SETGF", reg: flagsgp, asm: "SETHI"}, // extract floating > condition from arg0
- {name: "SETGEF", reg: flagsgp, asm: "SETCC"}, // extract floating >= condition from arg0
+ {name: "SETGF", argLength: 1, reg: flagsgp, asm: "SETHI"}, // extract floating > condition from arg0
+ {name: "SETGEF", argLength: 1, reg: flagsgp, asm: "SETCC"}, // extract floating >= condition from arg0
- {name: "MOVBQSX", reg: gp11nf, asm: "MOVBQSX"}, // sign extend arg0 from int8 to int64
- {name: "MOVBQZX", reg: gp11nf, asm: "MOVBQZX"}, // zero extend arg0 from int8 to int64
- {name: "MOVWQSX", reg: gp11nf, asm: "MOVWQSX"}, // sign extend arg0 from int16 to int64
- {name: "MOVWQZX", reg: gp11nf, asm: "MOVWQZX"}, // zero extend arg0 from int16 to int64
- {name: "MOVLQSX", reg: gp11nf, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
- {name: "MOVLQZX", reg: gp11nf, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64
+ {name: "MOVBQSX", argLength: 1, reg: gp11nf, asm: "MOVBQSX"}, // sign extend arg0 from int8 to int64
+ {name: "MOVBQZX", argLength: 1, reg: gp11nf, asm: "MOVBQZX"}, // zero extend arg0 from int8 to int64
+ {name: "MOVWQSX", argLength: 1, reg: gp11nf, asm: "MOVWQSX"}, // sign extend arg0 from int16 to int64
+ {name: "MOVWQZX", argLength: 1, reg: gp11nf, asm: "MOVWQZX"}, // zero extend arg0 from int16 to int64
+ {name: "MOVLQSX", argLength: 1, reg: gp11nf, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
+ {name: "MOVLQZX", argLength: 1, reg: gp11nf, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64
{name: "MOVBconst", reg: gp01, asm: "MOVB", typ: "UInt8", aux: "Int8", rematerializeable: true}, // 8 low bits of auxint
{name: "MOVWconst", reg: gp01, asm: "MOVW", typ: "UInt16", aux: "Int16", rematerializeable: true}, // 16 low bits of auxint
{name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint
{name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
- {name: "CVTTSD2SL", reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32
- {name: "CVTTSD2SQ", reg: fpgp, asm: "CVTTSD2SQ"}, // convert float64 to int64
- {name: "CVTTSS2SL", reg: fpgp, asm: "CVTTSS2SL"}, // convert float32 to int32
- {name: "CVTTSS2SQ", reg: fpgp, asm: "CVTTSS2SQ"}, // convert float32 to int64
- {name: "CVTSL2SS", reg: gpfp, asm: "CVTSL2SS"}, // convert int32 to float32
- {name: "CVTSL2SD", reg: gpfp, asm: "CVTSL2SD"}, // convert int32 to float64
- {name: "CVTSQ2SS", reg: gpfp, asm: "CVTSQ2SS"}, // convert int64 to float32
- {name: "CVTSQ2SD", reg: gpfp, asm: "CVTSQ2SD"}, // convert int64 to float64
- {name: "CVTSD2SS", reg: fp11, asm: "CVTSD2SS"}, // convert float64 to float32
- {name: "CVTSS2SD", reg: fp11, asm: "CVTSS2SD"}, // convert float32 to float64
-
- {name: "PXOR", reg: fp21, asm: "PXOR"}, // exclusive or, applied to X regs for float negation.
-
- {name: "LEAQ", reg: gp11sb, aux: "SymOff", rematerializeable: true}, // arg0 + auxint + offset encoded in aux
- {name: "LEAQ1", reg: gp21sb, aux: "SymOff"}, // arg0 + arg1 + auxint + aux
- {name: "LEAQ2", reg: gp21sb, aux: "SymOff"}, // arg0 + 2*arg1 + auxint + aux
- {name: "LEAQ4", reg: gp21sb, aux: "SymOff"}, // arg0 + 4*arg1 + auxint + aux
- {name: "LEAQ8", reg: gp21sb, aux: "SymOff"}, // arg0 + 8*arg1 + auxint + aux
+ {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32
+ {name: "CVTTSD2SQ", argLength: 1, reg: fpgp, asm: "CVTTSD2SQ"}, // convert float64 to int64
+ {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL"}, // convert float32 to int32
+ {name: "CVTTSS2SQ", argLength: 1, reg: fpgp, asm: "CVTTSS2SQ"}, // convert float32 to int64
+ {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS"}, // convert int32 to float32
+ {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD"}, // convert int32 to float64
+ {name: "CVTSQ2SS", argLength: 1, reg: gpfp, asm: "CVTSQ2SS"}, // convert int64 to float32
+ {name: "CVTSQ2SD", argLength: 1, reg: gpfp, asm: "CVTSQ2SD"}, // convert int64 to float64
+ {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS"}, // convert float64 to float32
+ {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD"}, // convert float32 to float64
+
+ {name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR"}, // exclusive or, applied to X regs for float negation.
+
+ {name: "LEAQ", argLength: 1, reg: gp11sb, aux: "SymOff", rematerializeable: true}, // arg0 + auxint + offset encoded in aux
+ {name: "LEAQ1", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + arg1 + auxint + aux
+ {name: "LEAQ2", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + 2*arg1 + auxint + aux
+ {name: "LEAQ4", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + 4*arg1 + auxint + aux
+ {name: "LEAQ8", argLength: 2, reg: gp21sb, aux: "SymOff"}, // arg0 + 8*arg1 + auxint + aux
// Note: LEAQ{1,2,4,8} must not have OpSB as either argument.
// auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address
- {name: "MOVBload", reg: gpload, asm: "MOVB", aux: "SymOff", typ: "UInt8"}, // load byte from arg0+auxint+aux. arg1=mem
- {name: "MOVBQSXload", reg: gpload, asm: "MOVBQSX", aux: "SymOff"}, // ditto, extend to int64
- {name: "MOVBQZXload", reg: gpload, asm: "MOVBQZX", aux: "SymOff"}, // ditto, extend to uint64
- {name: "MOVWload", reg: gpload, asm: "MOVW", aux: "SymOff", typ: "UInt16"}, // load 2 bytes from arg0+auxint+aux. arg1=mem
- {name: "MOVWQSXload", reg: gpload, asm: "MOVWQSX", aux: "SymOff"}, // ditto, extend to int64
- {name: "MOVWQZXload", reg: gpload, asm: "MOVWQZX", aux: "SymOff"}, // ditto, extend to uint64
- {name: "MOVLload", reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32"}, // load 4 bytes from arg0+auxint+aux. arg1=mem
- {name: "MOVLQSXload", reg: gpload, asm: "MOVLQSX", aux: "SymOff"}, // ditto, extend to int64
- {name: "MOVLQZXload", reg: gpload, asm: "MOVLQZX", aux: "SymOff"}, // ditto, extend to uint64
- {name: "MOVQload", reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64"}, // load 8 bytes from arg0+auxint+aux. arg1=mem
- {name: "MOVBstore", reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVWstore", reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVLstore", reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVQstore", reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
- {name: "MOVOload", reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128"}, // load 16 bytes from arg0+auxint+aux. arg1=mem
- {name: "MOVOstore", reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem"}, // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
+ {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", typ: "UInt8"}, // load byte from arg0+auxint+aux. arg1=mem
+ {name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff"}, // ditto, extend to int64
+ {name: "MOVBQZXload", argLength: 2, reg: gpload, asm: "MOVBQZX", aux: "SymOff"}, // ditto, extend to uint64
+ {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW", aux: "SymOff", typ: "UInt16"}, // load 2 bytes from arg0+auxint+aux. arg1=mem
+ {name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff"}, // ditto, extend to int64
+ {name: "MOVWQZXload", argLength: 2, reg: gpload, asm: "MOVWQZX", aux: "SymOff"}, // ditto, extend to uint64
+ {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32"}, // load 4 bytes from arg0+auxint+aux. arg1=mem
+ {name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff"}, // ditto, extend to int64
+ {name: "MOVLQZXload", argLength: 2, reg: gpload, asm: "MOVLQZX", aux: "SymOff"}, // ditto, extend to uint64
+ {name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64"}, // load 8 bytes from arg0+auxint+aux. arg1=mem
+ {name: "MOVBstore", argLength: 3, reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem
+ {name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem
+ {name: "MOVLstore", argLength: 3, reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem
+ {name: "MOVQstore", argLength: 3, reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem
+ {name: "MOVOload", argLength: 2, reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128"}, // load 16 bytes from arg0+auxint+aux. arg1=mem
+ {name: "MOVOstore", argLength: 3, reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem"}, // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
// indexed loads/stores
- {name: "MOVBloadidx1", reg: gploadidx, asm: "MOVB", aux: "SymOff"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem
- {name: "MOVWloadidx2", reg: gploadidx, asm: "MOVW", aux: "SymOff"}, // load 2 bytes from arg0+2*arg1+auxint+aux. arg2=mem
- {name: "MOVLloadidx4", reg: gploadidx, asm: "MOVL", aux: "SymOff"}, // load 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem
- {name: "MOVQloadidx8", reg: gploadidx, asm: "MOVQ", aux: "SymOff"}, // load 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem
+ {name: "MOVBloadidx1", argLength: 3, reg: gploadidx, asm: "MOVB", aux: "SymOff"}, // load a byte from arg0+arg1+auxint+aux. arg2=mem
+ {name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVW", aux: "SymOff"}, // load 2 bytes from arg0+2*arg1+auxint+aux. arg2=mem
+ {name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", aux: "SymOff"}, // load 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem
+ {name: "MOVQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVQ", aux: "SymOff"}, // load 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem
// TODO: sign-extending indexed loads
- {name: "MOVBstoreidx1", reg: gpstoreidx, asm: "MOVB", aux: "SymOff"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
- {name: "MOVWstoreidx2", reg: gpstoreidx, asm: "MOVW", aux: "SymOff"}, // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem
- {name: "MOVLstoreidx4", reg: gpstoreidx, asm: "MOVL", aux: "SymOff"}, // store 4 bytes in arg2 to arg0+4*arg1+auxint+aux. arg3=mem
- {name: "MOVQstoreidx8", reg: gpstoreidx, asm: "MOVQ", aux: "SymOff"}, // store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem
+ {name: "MOVBstoreidx1", argLength: 4, reg: gpstoreidx, asm: "MOVB", aux: "SymOff"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem
+ {name: "MOVWstoreidx2", argLength: 4, reg: gpstoreidx, asm: "MOVW", aux: "SymOff"}, // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem
+ {name: "MOVLstoreidx4", argLength: 4, reg: gpstoreidx, asm: "MOVL", aux: "SymOff"}, // store 4 bytes in arg2 to arg0+4*arg1+auxint+aux. arg3=mem
+ {name: "MOVQstoreidx8", argLength: 4, reg: gpstoreidx, asm: "MOVQ", aux: "SymOff"}, // store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem
// TODO: add size-mismatched indexed loads, like MOVBstoreidx4.
// For storeconst ops, the AuxInt field encodes both
// the value to store and an address offset of the store.
// Cast AuxInt to a ValAndOff to extract Val and Off fields.
- {name: "MOVBstoreconst", reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux. arg1=mem
- {name: "MOVWstoreconst", reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ...
- {name: "MOVLstoreconst", reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ...
- {name: "MOVQstoreconst", reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ...
+ {name: "MOVBstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux. arg1=mem
+ {name: "MOVWstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ...
+ {name: "MOVLstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ...
+ {name: "MOVQstoreconst", argLength: 2, reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ...
- {name: "MOVBstoreconstidx1", reg: gpstoreconstidx, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+1*arg1+ValAndOff(AuxInt).Off()+aux. arg2=mem
- {name: "MOVWstoreconstidx2", reg: gpstoreconstidx, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ... 2*arg1 ...
- {name: "MOVLstoreconstidx4", reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ... 4*arg1 ...
- {name: "MOVQstoreconstidx8", reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ... 8*arg1 ...
+ {name: "MOVBstoreconstidx1", argLength: 3, reg: gpstoreconstidx, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+1*arg1+ValAndOff(AuxInt).Off()+aux. arg2=mem
+ {name: "MOVWstoreconstidx2", argLength: 3, reg: gpstoreconstidx, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ... 2*arg1 ...
+ {name: "MOVLstoreconstidx4", argLength: 3, reg: gpstoreconstidx, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ... 4*arg1 ...
+ {name: "MOVQstoreconstidx8", argLength: 3, reg: gpstoreconstidx, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ... 8*arg1 ...
// arg0 = (duff-adjusted) pointer to start of memory to zero
// arg1 = value to store (will always be zero)
// auxint = offset into duffzero code to start executing
// returns mem
{
- name: "DUFFZERO",
- aux: "Int64",
+ name: "DUFFZERO",
+ aux: "Int64",
+ argLength: 3,
reg: regInfo{
inputs: []regMask{buildReg("DI"), buildReg("X0")},
clobbers: buildReg("DI FLAGS"),
// arg3 = mem
// returns mem
{
- name: "REPSTOSQ",
+ name: "REPSTOSQ",
+ argLength: 4,
reg: regInfo{
inputs: []regMask{buildReg("DI"), buildReg("CX"), buildReg("AX")},
clobbers: buildReg("DI CX FLAGS"),
},
},
- {name: "CALLstatic", reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
- {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}, aux: "Int64"}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
- {name: "CALLdefer", reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call deferproc. arg0=mem, auxint=argsize, returns mem
- {name: "CALLgo", reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call newproc. arg0=mem, auxint=argsize, returns mem
- {name: "CALLinter", reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64"}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
+ {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
+ {name: "CALLclosure", argLength: 3, reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}, aux: "Int64"}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
+ {name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call deferproc. arg0=mem, auxint=argsize, returns mem
+ {name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call newproc. arg0=mem, auxint=argsize, returns mem
+ {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64"}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
// arg0 = destination pointer
// arg1 = source pointer
// auxint = offset from duffcopy symbol to call
// returns memory
{
- name: "DUFFCOPY",
- aux: "Int64",
+ name: "DUFFCOPY",
+ aux: "Int64",
+ argLength: 3,
reg: regInfo{
inputs: []regMask{buildReg("DI"), buildReg("SI")},
clobbers: buildReg("DI SI X0 FLAGS"), // uses X0 as a temporary
// arg3 = mem
// returns memory
{
- name: "REPMOVSQ",
+ name: "REPMOVSQ",
+ argLength: 4,
reg: regInfo{
inputs: []regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")},
clobbers: buildReg("DI SI CX"),
// then we do (SETL (InvertFlags (CMPQ b a))) instead.
// Rewrites will convert this to (SETG (CMPQ b a)).
// InvertFlags is a pseudo-op which can't appear in assembly output.
- {name: "InvertFlags"}, // reverse direction of arg0
+ {name: "InvertFlags", argLength: 1}, // reverse direction of arg0
// Pseudo-ops
- {name: "LoweredGetG", reg: gp01}, // arg0=mem
+ {name: "LoweredGetG", argLength: 1, reg: gp01}, // arg0=mem
// Scheduler ensures LoweredGetClosurePtr occurs only in entry block,
// and sorts it to the very beginning of the block to prevent other
// use of DX (the closure pointer)
{name: "LoweredGetClosurePtr", reg: regInfo{outputs: []regMask{buildReg("DX")}}},
//arg0=ptr,arg1=mem, returns void. Faults if ptr is nil.
- {name: "LoweredNilCheck", reg: regInfo{inputs: []regMask{gpsp}, clobbers: flags}},
+ {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpsp}, clobbers: flags}},
// MOVQconvert converts between pointers and integers.
// We have a special op for this so as to not confuse GC
// (particularly stack maps). It takes a memory arg so it
// gets correctly ordered with respect to GC safepoints.
// arg0=ptr/int arg1=mem, output=int/ptr
- {name: "MOVQconvert", reg: gp11nf, asm: "MOVQ"},
+ {name: "MOVQconvert", argLength: 2, reg: gp11nf, asm: "MOVQ"},
// Constant flag values. For any comparison, there are 5 possible
// outcomes: the three from the signed total order (<,==,>) and the
// 2-input arithmetic
// Types must be consistent with Go typing. Add, for example, must take two values
// of the same type and produces that same type.
- {name: "Add8", commutative: true}, // arg0 + arg1
- {name: "Add16", commutative: true},
- {name: "Add32", commutative: true},
- {name: "Add64", commutative: true},
- {name: "AddPtr"}, // For address calculations. arg0 is a pointer and arg1 is an int.
- {name: "Add32F"},
- {name: "Add64F"},
+ {name: "Add8", argLength: 2, commutative: true}, // arg0 + arg1
+ {name: "Add16", argLength: 2, commutative: true},
+ {name: "Add32", argLength: 2, commutative: true},
+ {name: "Add64", argLength: 2, commutative: true},
+ {name: "AddPtr", argLength: 2}, // For address calculations. arg0 is a pointer and arg1 is an int.
+ {name: "Add32F", argLength: 2},
+ {name: "Add64F", argLength: 2},
// TODO: Add64C, Add128C
- {name: "Sub8"}, // arg0 - arg1
- {name: "Sub16"},
- {name: "Sub32"},
- {name: "Sub64"},
- {name: "SubPtr"},
- {name: "Sub32F"},
- {name: "Sub64F"},
-
- {name: "Mul8", commutative: true}, // arg0 * arg1
- {name: "Mul16", commutative: true},
- {name: "Mul32", commutative: true},
- {name: "Mul64", commutative: true},
- {name: "Mul32F"},
- {name: "Mul64F"},
-
- {name: "Div32F"}, // arg0 / arg1
- {name: "Div64F"},
-
- {name: "Hmul8"}, // (arg0 * arg1) >> width
- {name: "Hmul8u"},
- {name: "Hmul16"},
- {name: "Hmul16u"},
- {name: "Hmul32"},
- {name: "Hmul32u"},
- {name: "Hmul64"},
- {name: "Hmul64u"},
+ {name: "Sub8", argLength: 2}, // arg0 - arg1
+ {name: "Sub16", argLength: 2},
+ {name: "Sub32", argLength: 2},
+ {name: "Sub64", argLength: 2},
+ {name: "SubPtr", argLength: 2},
+ {name: "Sub32F", argLength: 2},
+ {name: "Sub64F", argLength: 2},
+
+ {name: "Mul8", argLength: 2, commutative: true}, // arg0 * arg1
+ {name: "Mul16", argLength: 2, commutative: true},
+ {name: "Mul32", argLength: 2, commutative: true},
+ {name: "Mul64", argLength: 2, commutative: true},
+ {name: "Mul32F", argLength: 2},
+ {name: "Mul64F", argLength: 2},
+
+ {name: "Div32F", argLength: 2}, // arg0 / arg1
+ {name: "Div64F", argLength: 2},
+
+ {name: "Hmul8", argLength: 2}, // (arg0 * arg1) >> width
+ {name: "Hmul8u", argLength: 2},
+ {name: "Hmul16", argLength: 2},
+ {name: "Hmul16u", argLength: 2},
+ {name: "Hmul32", argLength: 2},
+ {name: "Hmul32u", argLength: 2},
+ {name: "Hmul64", argLength: 2},
+ {name: "Hmul64u", argLength: 2},
// Weird special instruction for strength reduction of divides.
- {name: "Avg64u"}, // (uint64(arg0) + uint64(arg1)) / 2, correct to all 64 bits.
-
- {name: "Div8"}, // arg0 / arg1
- {name: "Div8u"},
- {name: "Div16"},
- {name: "Div16u"},
- {name: "Div32"},
- {name: "Div32u"},
- {name: "Div64"},
- {name: "Div64u"},
-
- {name: "Mod8"}, // arg0 % arg1
- {name: "Mod8u"},
- {name: "Mod16"},
- {name: "Mod16u"},
- {name: "Mod32"},
- {name: "Mod32u"},
- {name: "Mod64"},
- {name: "Mod64u"},
-
- {name: "And8", commutative: true}, // arg0 & arg1
- {name: "And16", commutative: true},
- {name: "And32", commutative: true},
- {name: "And64", commutative: true},
-
- {name: "Or8", commutative: true}, // arg0 | arg1
- {name: "Or16", commutative: true},
- {name: "Or32", commutative: true},
- {name: "Or64", commutative: true},
-
- {name: "Xor8", commutative: true}, // arg0 ^ arg1
- {name: "Xor16", commutative: true},
- {name: "Xor32", commutative: true},
- {name: "Xor64", commutative: true},
+ {name: "Avg64u", argLength: 2}, // (uint64(arg0) + uint64(arg1)) / 2, correct to all 64 bits.
+
+ {name: "Div8", argLength: 2}, // arg0 / arg1
+ {name: "Div8u", argLength: 2},
+ {name: "Div16", argLength: 2},
+ {name: "Div16u", argLength: 2},
+ {name: "Div32", argLength: 2},
+ {name: "Div32u", argLength: 2},
+ {name: "Div64", argLength: 2},
+ {name: "Div64u", argLength: 2},
+
+ {name: "Mod8", argLength: 2}, // arg0 % arg1
+ {name: "Mod8u", argLength: 2},
+ {name: "Mod16", argLength: 2},
+ {name: "Mod16u", argLength: 2},
+ {name: "Mod32", argLength: 2},
+ {name: "Mod32u", argLength: 2},
+ {name: "Mod64", argLength: 2},
+ {name: "Mod64u", argLength: 2},
+
+ {name: "And8", argLength: 2, commutative: true}, // arg0 & arg1
+ {name: "And16", argLength: 2, commutative: true},
+ {name: "And32", argLength: 2, commutative: true},
+ {name: "And64", argLength: 2, commutative: true},
+
+ {name: "Or8", argLength: 2, commutative: true}, // arg0 | arg1
+ {name: "Or16", argLength: 2, commutative: true},
+ {name: "Or32", argLength: 2, commutative: true},
+ {name: "Or64", argLength: 2, commutative: true},
+
+ {name: "Xor8", argLength: 2, commutative: true}, // arg0 ^ arg1
+ {name: "Xor16", argLength: 2, commutative: true},
+ {name: "Xor32", argLength: 2, commutative: true},
+ {name: "Xor64", argLength: 2, commutative: true},
// For shifts, AxB means the shifted value has A bits and the shift amount has B bits.
- {name: "Lsh8x8"}, // arg0 << arg1
- {name: "Lsh8x16"},
- {name: "Lsh8x32"},
- {name: "Lsh8x64"},
- {name: "Lsh16x8"},
- {name: "Lsh16x16"},
- {name: "Lsh16x32"},
- {name: "Lsh16x64"},
- {name: "Lsh32x8"},
- {name: "Lsh32x16"},
- {name: "Lsh32x32"},
- {name: "Lsh32x64"},
- {name: "Lsh64x8"},
- {name: "Lsh64x16"},
- {name: "Lsh64x32"},
- {name: "Lsh64x64"},
-
- {name: "Rsh8x8"}, // arg0 >> arg1, signed
- {name: "Rsh8x16"},
- {name: "Rsh8x32"},
- {name: "Rsh8x64"},
- {name: "Rsh16x8"},
- {name: "Rsh16x16"},
- {name: "Rsh16x32"},
- {name: "Rsh16x64"},
- {name: "Rsh32x8"},
- {name: "Rsh32x16"},
- {name: "Rsh32x32"},
- {name: "Rsh32x64"},
- {name: "Rsh64x8"},
- {name: "Rsh64x16"},
- {name: "Rsh64x32"},
- {name: "Rsh64x64"},
-
- {name: "Rsh8Ux8"}, // arg0 >> arg1, unsigned
- {name: "Rsh8Ux16"},
- {name: "Rsh8Ux32"},
- {name: "Rsh8Ux64"},
- {name: "Rsh16Ux8"},
- {name: "Rsh16Ux16"},
- {name: "Rsh16Ux32"},
- {name: "Rsh16Ux64"},
- {name: "Rsh32Ux8"},
- {name: "Rsh32Ux16"},
- {name: "Rsh32Ux32"},
- {name: "Rsh32Ux64"},
- {name: "Rsh64Ux8"},
- {name: "Rsh64Ux16"},
- {name: "Rsh64Ux32"},
- {name: "Rsh64Ux64"},
+ {name: "Lsh8x8", argLength: 2}, // arg0 << arg1
+ {name: "Lsh8x16", argLength: 2},
+ {name: "Lsh8x32", argLength: 2},
+ {name: "Lsh8x64", argLength: 2},
+ {name: "Lsh16x8", argLength: 2},
+ {name: "Lsh16x16", argLength: 2},
+ {name: "Lsh16x32", argLength: 2},
+ {name: "Lsh16x64", argLength: 2},
+ {name: "Lsh32x8", argLength: 2},
+ {name: "Lsh32x16", argLength: 2},
+ {name: "Lsh32x32", argLength: 2},
+ {name: "Lsh32x64", argLength: 2},
+ {name: "Lsh64x8", argLength: 2},
+ {name: "Lsh64x16", argLength: 2},
+ {name: "Lsh64x32", argLength: 2},
+ {name: "Lsh64x64", argLength: 2},
+
+ {name: "Rsh8x8", argLength: 2}, // arg0 >> arg1, signed
+ {name: "Rsh8x16", argLength: 2},
+ {name: "Rsh8x32", argLength: 2},
+ {name: "Rsh8x64", argLength: 2},
+ {name: "Rsh16x8", argLength: 2},
+ {name: "Rsh16x16", argLength: 2},
+ {name: "Rsh16x32", argLength: 2},
+ {name: "Rsh16x64", argLength: 2},
+ {name: "Rsh32x8", argLength: 2},
+ {name: "Rsh32x16", argLength: 2},
+ {name: "Rsh32x32", argLength: 2},
+ {name: "Rsh32x64", argLength: 2},
+ {name: "Rsh64x8", argLength: 2},
+ {name: "Rsh64x16", argLength: 2},
+ {name: "Rsh64x32", argLength: 2},
+ {name: "Rsh64x64", argLength: 2},
+
+ {name: "Rsh8Ux8", argLength: 2}, // arg0 >> arg1, unsigned
+ {name: "Rsh8Ux16", argLength: 2},
+ {name: "Rsh8Ux32", argLength: 2},
+ {name: "Rsh8Ux64", argLength: 2},
+ {name: "Rsh16Ux8", argLength: 2},
+ {name: "Rsh16Ux16", argLength: 2},
+ {name: "Rsh16Ux32", argLength: 2},
+ {name: "Rsh16Ux64", argLength: 2},
+ {name: "Rsh32Ux8", argLength: 2},
+ {name: "Rsh32Ux16", argLength: 2},
+ {name: "Rsh32Ux32", argLength: 2},
+ {name: "Rsh32Ux64", argLength: 2},
+ {name: "Rsh64Ux8", argLength: 2},
+ {name: "Rsh64Ux16", argLength: 2},
+ {name: "Rsh64Ux32", argLength: 2},
+ {name: "Rsh64Ux64", argLength: 2},
// (Left) rotates replace pattern matches in the front end
// of (arg0 << arg1) ^ (arg0 >> (A-arg1))
// for rotates is hashing and crypto code with constant
// distance, rotate instructions are only substituted
// when arg1 is a constant between 1 and A-1, inclusive.
- {name: "Lrot8", aux: "Int64"},
- {name: "Lrot16", aux: "Int64"},
- {name: "Lrot32", aux: "Int64"},
- {name: "Lrot64", aux: "Int64"},
+ {name: "Lrot8", argLength: 1, aux: "Int64"},
+ {name: "Lrot16", argLength: 1, aux: "Int64"},
+ {name: "Lrot32", argLength: 1, aux: "Int64"},
+ {name: "Lrot64", argLength: 1, aux: "Int64"},
// 2-input comparisons
- {name: "Eq8", commutative: true}, // arg0 == arg1
- {name: "Eq16", commutative: true},
- {name: "Eq32", commutative: true},
- {name: "Eq64", commutative: true},
- {name: "EqPtr", commutative: true},
- {name: "EqInter"}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "EqSlice"}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "Eq32F"},
- {name: "Eq64F"},
-
- {name: "Neq8", commutative: true}, // arg0 != arg1
- {name: "Neq16", commutative: true},
- {name: "Neq32", commutative: true},
- {name: "Neq64", commutative: true},
- {name: "NeqPtr", commutative: true},
- {name: "NeqInter"}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "NeqSlice"}, // arg0 or arg1 is nil; other cases handled by frontend
- {name: "Neq32F"},
- {name: "Neq64F"},
-
- {name: "Less8"}, // arg0 < arg1
- {name: "Less8U"},
- {name: "Less16"},
- {name: "Less16U"},
- {name: "Less32"},
- {name: "Less32U"},
- {name: "Less64"},
- {name: "Less64U"},
- {name: "Less32F"},
- {name: "Less64F"},
-
- {name: "Leq8"}, // arg0 <= arg1
- {name: "Leq8U"},
- {name: "Leq16"},
- {name: "Leq16U"},
- {name: "Leq32"},
- {name: "Leq32U"},
- {name: "Leq64"},
- {name: "Leq64U"},
- {name: "Leq32F"},
- {name: "Leq64F"},
-
- {name: "Greater8"}, // arg0 > arg1
- {name: "Greater8U"},
- {name: "Greater16"},
- {name: "Greater16U"},
- {name: "Greater32"},
- {name: "Greater32U"},
- {name: "Greater64"},
- {name: "Greater64U"},
- {name: "Greater32F"},
- {name: "Greater64F"},
-
- {name: "Geq8"}, // arg0 <= arg1
- {name: "Geq8U"},
- {name: "Geq16"},
- {name: "Geq16U"},
- {name: "Geq32"},
- {name: "Geq32U"},
- {name: "Geq64"},
- {name: "Geq64U"},
- {name: "Geq32F"},
- {name: "Geq64F"},
+ {name: "Eq8", argLength: 2, commutative: true}, // arg0 == arg1
+ {name: "Eq16", argLength: 2, commutative: true},
+ {name: "Eq32", argLength: 2, commutative: true},
+ {name: "Eq64", argLength: 2, commutative: true},
+ {name: "EqPtr", argLength: 2, commutative: true},
+ {name: "EqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+ {name: "EqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+ {name: "Eq32F", argLength: 2},
+ {name: "Eq64F", argLength: 2},
+
+ {name: "Neq8", argLength: 2, commutative: true}, // arg0 != arg1
+ {name: "Neq16", argLength: 2, commutative: true},
+ {name: "Neq32", argLength: 2, commutative: true},
+ {name: "Neq64", argLength: 2, commutative: true},
+ {name: "NeqPtr", argLength: 2, commutative: true},
+ {name: "NeqInter", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+ {name: "NeqSlice", argLength: 2}, // arg0 or arg1 is nil; other cases handled by frontend
+ {name: "Neq32F", argLength: 2},
+ {name: "Neq64F", argLength: 2},
+
+ {name: "Less8", argLength: 2}, // arg0 < arg1
+ {name: "Less8U", argLength: 2},
+ {name: "Less16", argLength: 2},
+ {name: "Less16U", argLength: 2},
+ {name: "Less32", argLength: 2},
+ {name: "Less32U", argLength: 2},
+ {name: "Less64", argLength: 2},
+ {name: "Less64U", argLength: 2},
+ {name: "Less32F", argLength: 2},
+ {name: "Less64F", argLength: 2},
+
+ {name: "Leq8", argLength: 2}, // arg0 <= arg1
+ {name: "Leq8U", argLength: 2},
+ {name: "Leq16", argLength: 2},
+ {name: "Leq16U", argLength: 2},
+ {name: "Leq32", argLength: 2},
+ {name: "Leq32U", argLength: 2},
+ {name: "Leq64", argLength: 2},
+ {name: "Leq64U", argLength: 2},
+ {name: "Leq32F", argLength: 2},
+ {name: "Leq64F", argLength: 2},
+
+ {name: "Greater8", argLength: 2}, // arg0 > arg1
+ {name: "Greater8U", argLength: 2},
+ {name: "Greater16", argLength: 2},
+ {name: "Greater16U", argLength: 2},
+ {name: "Greater32", argLength: 2},
+ {name: "Greater32U", argLength: 2},
+ {name: "Greater64", argLength: 2},
+ {name: "Greater64U", argLength: 2},
+ {name: "Greater32F", argLength: 2},
+ {name: "Greater64F", argLength: 2},
+
+ {name: "Geq8", argLength: 2}, // arg0 <= arg1
+ {name: "Geq8U", argLength: 2},
+ {name: "Geq16", argLength: 2},
+ {name: "Geq16U", argLength: 2},
+ {name: "Geq32", argLength: 2},
+ {name: "Geq32U", argLength: 2},
+ {name: "Geq64", argLength: 2},
+ {name: "Geq64U", argLength: 2},
+ {name: "Geq32F", argLength: 2},
+ {name: "Geq64F", argLength: 2},
// 1-input ops
- {name: "Not"}, // !arg0
-
- {name: "Neg8"}, // -arg0
- {name: "Neg16"},
- {name: "Neg32"},
- {name: "Neg64"},
- {name: "Neg32F"},
- {name: "Neg64F"},
-
- {name: "Com8"}, // ^arg0
- {name: "Com16"},
- {name: "Com32"},
- {name: "Com64"},
-
- {name: "Sqrt"}, // sqrt(arg0), float64 only
-
- // Data movement
- {name: "Phi", variableLength: true}, // select an argument based on which predecessor block we came from
- {name: "Copy"}, // output = arg0
+ {name: "Not", argLength: 1}, // !arg0
+
+ {name: "Neg8", argLength: 1}, // -arg0
+ {name: "Neg16", argLength: 1},
+ {name: "Neg32", argLength: 1},
+ {name: "Neg64", argLength: 1},
+ {name: "Neg32F", argLength: 1},
+ {name: "Neg64F", argLength: 1},
+
+ {name: "Com8", argLength: 1}, // ^arg0
+ {name: "Com16", argLength: 1},
+ {name: "Com32", argLength: 1},
+ {name: "Com64", argLength: 1},
+
+ {name: "Sqrt", argLength: 1}, // sqrt(arg0), float64 only
+
+ // Data movement, max argument length for Phi is indefinite so just pick
+ // a really large number
+ {name: "Phi", argLength: -1}, // select an argument based on which predecessor block we came from
+ {name: "Copy", argLength: 1}, // output = arg0
// Convert converts between pointers and integers.
// We have a special op for this so as to not confuse GC
// (particularly stack maps). It takes a memory arg so it
// gets correctly ordered with respect to GC safepoints.
// arg0=ptr/int arg1=mem, output=int/ptr
- {name: "Convert"},
+ {name: "Convert", argLength: 2},
// constants. Constant values are stored in the aux or
// auxint fields.
// on whether it is a global or stack variable). The Aux field identifies the
// variable. It will be either an *ExternSymbol (with arg0=SB), *ArgSymbol (arg0=SP),
// or *AutoSymbol (arg0=SP).
- {name: "Addr", aux: "Sym"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable.
+ {name: "Addr", argLength: 1, aux: "Sym"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable.
{name: "SP"}, // stack pointer
{name: "SB", typ: "Uintptr"}, // static base pointer (a.k.a. globals pointer)
{name: "Func", aux: "Sym"}, // entry address of a function
// Memory operations
- {name: "Load"}, // Load from arg0. arg1=memory
- {name: "Store", typ: "Mem", aux: "Int64"}, // Store arg1 to arg0. arg2=memory, auxint=size. Returns memory.
- {name: "Move", aux: "Int64"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory.
- {name: "Zero", aux: "Int64"}, // arg0=destptr, arg1=mem, auxint=size. Returns memory.
+ {name: "Load", argLength: 2}, // Load from arg0. arg1=memory
+ {name: "Store", argLength: 3, typ: "Mem", aux: "Int64"}, // Store arg1 to arg0. arg2=memory, auxint=size. Returns memory.
+ {name: "Move", argLength: 3, aux: "Int64"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory.
+ {name: "Zero", argLength: 2, aux: "Int64"}, // arg0=destptr, arg1=mem, auxint=size. Returns memory.
// Function calls. Arguments to the call have already been written to the stack.
// Return values appear on the stack. The method receiver, if any, is treated
// as a phantom first argument.
- {name: "ClosureCall", aux: "Int64"}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory.
- {name: "StaticCall", aux: "SymOff"}, // call function aux.(*gc.Sym), arg0=memory. auxint=arg size. Returns memory.
- {name: "DeferCall", aux: "Int64"}, // defer call. arg0=memory, auxint=arg size. Returns memory.
- {name: "GoCall", aux: "Int64"}, // go call. arg0=memory, auxint=arg size. Returns memory.
- {name: "InterCall", aux: "Int64"}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory.
+ {name: "ClosureCall", argLength: 3, aux: "Int64"}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory.
+ {name: "StaticCall", argLength: 1, aux: "SymOff"}, // call function aux.(*gc.Sym), arg0=memory. auxint=arg size. Returns memory.
+ {name: "DeferCall", argLength: 1, aux: "Int64"}, // defer call. arg0=memory, auxint=arg size. Returns memory.
+ {name: "GoCall", argLength: 1, aux: "Int64"}, // go call. arg0=memory, auxint=arg size. Returns memory.
+ {name: "InterCall", argLength: 2, aux: "Int64"}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory.
// Conversions: signed extensions, zero (unsigned) extensions, truncations
- {name: "SignExt8to16", typ: "Int16"},
- {name: "SignExt8to32"},
- {name: "SignExt8to64"},
- {name: "SignExt16to32"},
- {name: "SignExt16to64"},
- {name: "SignExt32to64"},
- {name: "ZeroExt8to16", typ: "UInt16"},
- {name: "ZeroExt8to32"},
- {name: "ZeroExt8to64"},
- {name: "ZeroExt16to32"},
- {name: "ZeroExt16to64"},
- {name: "ZeroExt32to64"},
- {name: "Trunc16to8"},
- {name: "Trunc32to8"},
- {name: "Trunc32to16"},
- {name: "Trunc64to8"},
- {name: "Trunc64to16"},
- {name: "Trunc64to32"},
-
- {name: "Cvt32to32F"},
- {name: "Cvt32to64F"},
- {name: "Cvt64to32F"},
- {name: "Cvt64to64F"},
- {name: "Cvt32Fto32"},
- {name: "Cvt32Fto64"},
- {name: "Cvt64Fto32"},
- {name: "Cvt64Fto64"},
- {name: "Cvt32Fto64F"},
- {name: "Cvt64Fto32F"},
+ {name: "SignExt8to16", argLength: 1, typ: "Int16"},
+ {name: "SignExt8to32", argLength: 1},
+ {name: "SignExt8to64", argLength: 1},
+ {name: "SignExt16to32", argLength: 1},
+ {name: "SignExt16to64", argLength: 1},
+ {name: "SignExt32to64", argLength: 1},
+ {name: "ZeroExt8to16", argLength: 1, typ: "UInt16"},
+ {name: "ZeroExt8to32", argLength: 1},
+ {name: "ZeroExt8to64", argLength: 1},
+ {name: "ZeroExt16to32", argLength: 1},
+ {name: "ZeroExt16to64", argLength: 1},
+ {name: "ZeroExt32to64", argLength: 1},
+ {name: "Trunc16to8", argLength: 1},
+ {name: "Trunc32to8", argLength: 1},
+ {name: "Trunc32to16", argLength: 1},
+ {name: "Trunc64to8", argLength: 1},
+ {name: "Trunc64to16", argLength: 1},
+ {name: "Trunc64to32", argLength: 1},
+
+ {name: "Cvt32to32F", argLength: 1},
+ {name: "Cvt32to64F", argLength: 1},
+ {name: "Cvt64to32F", argLength: 1},
+ {name: "Cvt64to64F", argLength: 1},
+ {name: "Cvt32Fto32", argLength: 1},
+ {name: "Cvt32Fto64", argLength: 1},
+ {name: "Cvt64Fto32", argLength: 1},
+ {name: "Cvt64Fto64", argLength: 1},
+ {name: "Cvt32Fto64F", argLength: 1},
+ {name: "Cvt64Fto32F", argLength: 1},
// Automatically inserted safety checks
- {name: "IsNonNil", typ: "Bool"}, // arg0 != nil
- {name: "IsInBounds", typ: "Bool"}, // 0 <= arg0 < arg1
- {name: "IsSliceInBounds", typ: "Bool"}, // 0 <= arg0 <= arg1
- {name: "NilCheck", typ: "Void"}, // arg0=ptr, arg1=mem. Panics if arg0 is nil, returns void.
+ {name: "IsNonNil", argLength: 1, typ: "Bool"}, // arg0 != nil
+ {name: "IsInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 < arg1
+ {name: "IsSliceInBounds", argLength: 2, typ: "Bool"}, // 0 <= arg0 <= arg1
+ {name: "NilCheck", argLength: 2, typ: "Void"}, // arg0=ptr, arg1=mem. Panics if arg0 is nil, returns void.
// Pseudo-ops
- {name: "GetG"}, // runtime.getg() (read g pointer). arg0=mem
- {name: "GetClosurePtr"}, // get closure pointer from dedicated register
+ {name: "GetG", argLength: 1}, // runtime.getg() (read g pointer). arg0=mem
+ {name: "GetClosurePtr"}, // get closure pointer from dedicated register
// Indexing operations
- {name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]
- {name: "PtrIndex"}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
- {name: "OffPtr", aux: "Int64"}, // arg0 + auxint (arg0 and result are pointers)
+ {name: "ArrayIndex", argLength: 2}, // arg0=array, arg1=index. Returns a[i]
+ {name: "PtrIndex", argLength: 2}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
+ {name: "OffPtr", argLength: 1, aux: "Int64"}, // arg0 + auxint (arg0 and result are pointers)
// Slices
- {name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap
- {name: "SlicePtr", typ: "BytePtr"}, // ptr(arg0)
- {name: "SliceLen"}, // len(arg0)
- {name: "SliceCap"}, // cap(arg0)
+ {name: "SliceMake", argLength: 3}, // arg0=ptr, arg1=len, arg2=cap
+ {name: "SlicePtr", argLength: 1, typ: "BytePtr"}, // ptr(arg0)
+ {name: "SliceLen", argLength: 1}, // len(arg0)
+ {name: "SliceCap", argLength: 1}, // cap(arg0)
// Complex (part/whole)
- {name: "ComplexMake"}, // arg0=real, arg1=imag
- {name: "ComplexReal"}, // real(arg0)
- {name: "ComplexImag"}, // imag(arg0)
+ {name: "ComplexMake", argLength: 2}, // arg0=real, arg1=imag
+ {name: "ComplexReal", argLength: 1}, // real(arg0)
+ {name: "ComplexImag", argLength: 1}, // imag(arg0)
// Strings
- {name: "StringMake"}, // arg0=ptr, arg1=len
- {name: "StringPtr"}, // ptr(arg0)
- {name: "StringLen"}, // len(arg0)
+ {name: "StringMake", argLength: 2}, // arg0=ptr, arg1=len
+ {name: "StringPtr", argLength: 1}, // ptr(arg0)
+ {name: "StringLen", argLength: 1}, // len(arg0)
// Interfaces
- {name: "IMake"}, // arg0=itab, arg1=data
- {name: "ITab", typ: "BytePtr"}, // arg0=interface, returns itable field
- {name: "IData"}, // arg0=interface, returns data field
+ {name: "IMake", argLength: 2}, // arg0=itab, arg1=data
+ {name: "ITab", argLength: 1, typ: "BytePtr"}, // arg0=interface, returns itable field
+ {name: "IData", argLength: 1}, // arg0=interface, returns data field
// Structs
- {name: "StructMake0"}, // Returns struct with 0 fields.
- {name: "StructMake1"}, // arg0=field0. Returns struct.
- {name: "StructMake2"}, // arg0,arg1=field0,field1. Returns struct.
- {name: "StructMake3"}, // arg0..2=field0..2. Returns struct.
- {name: "StructMake4"}, // arg0..3=field0..3. Returns struct.
- {name: "StructSelect", aux: "Int64"}, // arg0=struct, auxint=field index. Returns the auxint'th field.
+ {name: "StructMake0"}, // Returns struct with 0 fields.
+ {name: "StructMake1", argLength: 1}, // arg0=field0. Returns struct.
+ {name: "StructMake2", argLength: 2}, // arg0,arg1=field0,field1. Returns struct.
+ {name: "StructMake3", argLength: 3}, // arg0..2=field0..2. Returns struct.
+ {name: "StructMake4", argLength: 4}, // arg0..3=field0..3. Returns struct.
+ {name: "StructSelect", argLength: 1, aux: "Int64"}, // arg0=struct, auxint=field index. Returns the auxint'th field.
// Spill&restore ops for the register allocator. These are
// semantically identical to OpCopy; they do not take/return
// stores like regular memory ops do. We can get away without memory
// args because we know there is no aliasing of spill slots on the stack.
- {name: "StoreReg"},
- {name: "LoadReg"},
+ {name: "StoreReg", argLength: 1},
+ {name: "LoadReg", argLength: 1},
// Used during ssa construction. Like Copy, but the arg has not been specified yet.
{name: "FwdRef"},
// Unknown value. Used for Values whose values don't matter because they are dead code.
{name: "Unknown"},
- {name: "VarDef", aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem
- {name: "VarKill", aux: "Sym"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
- {name: "VarLive", aux: "Sym"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
+ {name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem
+ {name: "VarKill", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
+ {name: "VarLive", argLength: 1, aux: "Sym"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
}
// kind control successors implicit exit