diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 669d5b01b9ffc7..c46b92fd0d1141 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -1109,10 +1109,7 @@ func trimRightUnicode(s []byte, cutset string) []byte { func trimSpaceUnicode(s []byte) []byte { for len(s) > 0 { - r, n := rune(s[0]), 1 - if r >= utf8.RuneSelf { - r, n = utf8.DecodeRune(s) - } + r, n := utf8.DecodeRune(s) if !stringslite.IsSpace(r) { break } diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go index 4e6f54370d7037..c312cafebe7217 100644 --- a/src/cmd/compile/internal/amd64/ssa.go +++ b/src/cmd/compile/internal/amd64/ssa.go @@ -892,24 +892,34 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Reg = v.Args[2].Reg() memIdx(&p.To, v) ssagen.AddAux(&p.To, v) - case ssa.OpAMD64ADDQconstmodify, ssa.OpAMD64ADDLconstmodify: + case ssa.OpAMD64ADDQconstmodify, ssa.OpAMD64ADDLconstmodify, + ssa.OpAMD64ADDWconstmodify, ssa.OpAMD64ADDBconstmodify: sc := v.AuxValAndOff() off := sc.Off64() val := sc.Val() if val == 1 || val == -1 { var asm obj.As - if v.Op == ssa.OpAMD64ADDQconstmodify { - if val == 1 { - asm = x86.AINCQ - } else { + switch v.Op { + case ssa.OpAMD64ADDQconstmodify: + asm = x86.AINCQ + if val == -1 { asm = x86.ADECQ } - } else { - if val == 1 { - asm = x86.AINCL - } else { + case ssa.OpAMD64ADDLconstmodify: + asm = x86.AINCL + if val == -1 { asm = x86.ADECL } + case ssa.OpAMD64ADDWconstmodify: + asm = x86.AINCW + if val == -1 { + asm = x86.ADECW + } + default: + asm = x86.AINCB + if val == -1 { + asm = x86.ADECB + } } p := s.Prog(asm) p.To.Type = obj.TYPE_MEM @@ -920,6 +930,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { fallthrough case ssa.OpAMD64ANDQconstmodify, ssa.OpAMD64ANDLconstmodify, ssa.OpAMD64ORQconstmodify, ssa.OpAMD64ORLconstmodify, ssa.OpAMD64XORQconstmodify, ssa.OpAMD64XORLconstmodify, + ssa.OpAMD64ANDWconstmodify, ssa.OpAMD64ANDBconstmodify, ssa.OpAMD64ORWconstmodify, ssa.OpAMD64ORBconstmodify, + ssa.OpAMD64XORWconstmodify, ssa.OpAMD64XORBconstmodify, ssa.OpAMD64BTSQconstmodify, ssa.OpAMD64BTRQconstmodify, ssa.OpAMD64BTCQconstmodify: sc := v.AuxValAndOff() off := sc.Off64() @@ -960,7 +972,11 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpAMD64ADDLconstmodifyidx1, ssa.OpAMD64ADDLconstmodifyidx4, ssa.OpAMD64ADDLconstmodifyidx8, ssa.OpAMD64ADDQconstmodifyidx1, ssa.OpAMD64ADDQconstmodifyidx8, ssa.OpAMD64ANDLconstmodifyidx1, ssa.OpAMD64ANDLconstmodifyidx4, ssa.OpAMD64ANDLconstmodifyidx8, ssa.OpAMD64ANDQconstmodifyidx1, ssa.OpAMD64ANDQconstmodifyidx8, ssa.OpAMD64ORLconstmodifyidx1, ssa.OpAMD64ORLconstmodifyidx4, ssa.OpAMD64ORLconstmodifyidx8, ssa.OpAMD64ORQconstmodifyidx1, ssa.OpAMD64ORQconstmodifyidx8, - ssa.OpAMD64XORLconstmodifyidx1, ssa.OpAMD64XORLconstmodifyidx4, ssa.OpAMD64XORLconstmodifyidx8, ssa.OpAMD64XORQconstmodifyidx1, ssa.OpAMD64XORQconstmodifyidx8: + ssa.OpAMD64XORLconstmodifyidx1, ssa.OpAMD64XORLconstmodifyidx4, ssa.OpAMD64XORLconstmodifyidx8, ssa.OpAMD64XORQconstmodifyidx1, ssa.OpAMD64XORQconstmodifyidx8, + ssa.OpAMD64ADDWconstmodifyidx1, ssa.OpAMD64ADDWconstmodifyidx2, ssa.OpAMD64ADDBconstmodifyidx1, + ssa.OpAMD64ANDWconstmodifyidx1, ssa.OpAMD64ANDWconstmodifyidx2, ssa.OpAMD64ANDBconstmodifyidx1, + ssa.OpAMD64ORWconstmodifyidx1, ssa.OpAMD64ORWconstmodifyidx2, ssa.OpAMD64ORBconstmodifyidx1, + ssa.OpAMD64XORWconstmodifyidx1, ssa.OpAMD64XORWconstmodifyidx2, ssa.OpAMD64XORBconstmodifyidx1: p := s.Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST sc := v.AuxValAndOff() @@ -978,6 +994,18 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case p.As == x86.AADDL && p.From.Offset == -1: p.As = x86.ADECL p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDW && p.From.Offset == 1: + p.As = x86.AINCW + p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDW && p.From.Offset == -1: + p.As = x86.ADECW + p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDB && p.From.Offset == 1: + p.As = x86.AINCB + p.From.Type = obj.TYPE_NONE + case p.As == x86.AADDB && p.From.Offset == -1: + p.As = x86.ADECB + p.From.Type = obj.TYPE_NONE } memIdx(&p.To, v) ssagen.AddAux2(&p.To, v, sc.Off64()) @@ -1251,7 +1279,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { } if x != y { width := v.Type.Size() - if width == 8 && isGPReg(y) && ssa.ZeroUpper32Bits(arg, 3) { + if width == 8 && isGPReg(y) && ssa.ZeroUpper32Bits(arg) { // The source was naturally zext-ed from 32 to 64 bits, // but we are asked to do a full 64-bit copy. // Save the REX prefix byte in I-CACHE by using a 32-bit move, @@ -1288,6 +1316,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Reg = r ssagen.AddrAuto(&p.To, v) case ssa.OpAMD64LoweredHasCPUFeature: + // If this load changes width, update zeroUpperBits in AMD64Ops.go. p := s.Prog(x86.AMOVBLZX) p.From.Type = obj.TYPE_MEM ssagen.AddAux(&p.From, v) @@ -1669,6 +1698,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // LOCK CMPXCHGQ tmp, (addr) : note that AX is implicit old value to compare against // JNE loop // : result in AX + // + // If the width written to AX changes, update zeroUpperBits in AMD64Ops.go. mov := x86.AMOVQ op := x86.AANDQ cmpxchg := x86.ACMPXCHGQ diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index c75e0e5e65b764..394c9336af42c6 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -1042,6 +1042,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // LDAXR (Rarg0), Rout // STLXR Rarg1, (Rarg0), Rtmp // CBNZ Rtmp, -2(PC) + // + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. var ld, st obj.As switch v.Op { case ssa.OpARM64LoweredAtomicExchange8: @@ -1076,6 +1078,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpARM64LoweredAtomicExchange64Variant, ssa.OpARM64LoweredAtomicExchange32Variant, ssa.OpARM64LoweredAtomicExchange8Variant: + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. var swap obj.As switch v.Op { case ssa.OpARM64LoweredAtomicExchange8Variant: @@ -1163,6 +1166,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // STLXR Rarg2, (Rarg0), Rtmp // CBNZ Rtmp, -4(PC) // CSET EQ, Rout + // + // If Rout stops being written only by CSET, update zeroUpperBits in ARM64Ops.go. ld := arm64.ALDAXR st := arm64.ASTLXR cmp := arm64.ACMP @@ -1212,6 +1217,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // CASAL Rtmp, (Rarg0), Rarg2 // CMP Rarg1, Rtmp // CSET EQ, Rout + // + // If Rout stops being written only by CSET, update zeroUpperBits in ARM64Ops.go. cas := arm64.ACASALD cmp := arm64.ACMP mov := arm64.AMOVD @@ -1263,6 +1270,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { // AND/OR Rarg1, Rout, tmp1 // STLXR[BW] tmp1, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) + // + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. ld := arm64.ALDAXR st := arm64.ASTLXR if v.Op == ssa.OpARM64LoweredAtomicAnd32 || v.Op == ssa.OpARM64LoweredAtomicOr32 { @@ -1303,6 +1312,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpARM64LoweredAtomicAnd8Variant, ssa.OpARM64LoweredAtomicAnd32Variant, ssa.OpARM64LoweredAtomicAnd64Variant: + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. atomic_clear := arm64.ALDCLRALD if v.Op == ssa.OpARM64LoweredAtomicAnd32Variant { atomic_clear = arm64.ALDCLRALW @@ -1332,6 +1342,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { case ssa.OpARM64LoweredAtomicOr8Variant, ssa.OpARM64LoweredAtomicOr32Variant, ssa.OpARM64LoweredAtomicOr64Variant: + // If the width written to Rout changes, update zeroUpperBits in ARM64Ops.go. atomic_or := arm64.ALDORALD if v.Op == ssa.OpARM64LoweredAtomicOr32Variant { atomic_or = arm64.ALDORALW @@ -1870,6 +1881,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { ssa.OpARM64LessThanNoov, ssa.OpARM64GreaterEqualNoov: // generate boolean values using CSET + // + // If the result stops being a 0/1-producing CSET, update zeroUpperBits in ARM64Ops.go. p := s.Prog(arm64.ACSET) p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset condCode := condBits[v.Op] diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64.rules b/src/cmd/compile/internal/ssa/_gen/AMD64.rules index 4988af6626d85f..0026b5d5f5ad08 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64.rules @@ -1019,6 +1019,10 @@ ((ADD|AND|OR|XOR)Qconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) ((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd32(off2) => ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) +((ADD|AND|OR|XOR)Wconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd32(off2) => + ((ADD|AND|OR|XOR)Wconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) +((ADD|AND|OR|XOR)Bconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) && ValAndOff(valoff1).canAdd32(off2) => + ((ADD|AND|OR|XOR)Bconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) ((ADD|SUB|AND|OR|XOR)Qmodify [off1] {sym} (ADDQconst [off2] base) val mem) && is32Bit(int64(off1)+int64(off2)) => ((ADD|SUB|AND|OR|XOR)Qmodify [off1+off2] {sym} base val mem) ((ADD|SUB|AND|OR|XOR)Lmodify [off1] {sym} (ADDQconst [off2] base) val mem) && is32Bit(int64(off1)+int64(off2)) => @@ -1076,6 +1080,12 @@ ((ADD|AND|OR|XOR)Lconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) && ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) => ((ADD|AND|OR|XOR)Lconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) +((ADD|AND|OR|XOR)Wconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + && ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) => + ((ADD|AND|OR|XOR)Wconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) +((ADD|AND|OR|XOR)Bconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + && ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) => + ((ADD|AND|OR|XOR)Bconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) ((ADD|SUB|AND|OR|XOR)Qmodify [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && is32Bit(int64(off1)+int64(off2)) && canMergeSym(sym1, sym2) => ((ADD|SUB|AND|OR|XOR)Qmodify [off1+off2] {mergeSym(sym1,sym2)} base val mem) @@ -1474,6 +1484,17 @@ (MOVLstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Lconst [c] l:(MOVLload [off] {sym} ptr2 mem)) mem) && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && clobber(l, a) => ((ADD|AND|OR|XOR)Lconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) +// Sub-word read-modify-write. The narrow store keeps only the low 8/16 bits of +// the 32-bit result, so ADDB/ADDW etc. with the same constant is equivalent. +// The constant is restricted to an 8-bit immediate: it keeps every form we emit +// encodable as imm8 (or INC/DEC), which also avoids the 16-bit immediates that +// cause length-changing-prefix stalls. +(MOVWstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Lconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) => + ((ADD|AND|OR|XOR)Wconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) +(MOVBstore [off] {sym} ptr a:((ADD|AND|OR|XOR)Lconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + && isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) => + ((ADD|AND|OR|XOR)Bconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) // float <-> int register moves, with no conversion. // These come up when compiling math.{Float{32,64}bits,Float{32,64}frombits}. diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go index fc06f3e40cdc0f..bf0818f2df2d96 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/AMD64Ops.go @@ -362,24 +362,26 @@ func init() { // constmodify versions compute *(arg0+ValAndOff(AuxInt).Off().aux) OP= ValAndOff(AuxInt).Val(), arg1 = mem // x==L operations zero the upper 4 bytes of the destination register (not meaningful for constmodify versions). {name: "ADDQ", argLength: 2, reg: gp21sp, asm: "ADDQ", commutative: true, clobberFlags: true, earlyOk: true}, - {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true, earlyOk: true}, + {name: "ADDL", argLength: 2, reg: gp21sp, asm: "ADDL", commutative: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ADDQconst", argLength: 1, reg: gp11sp, asm: "ADDQ", aux: "Int32", typ: "UInt64", clobberFlags: true, earlyOk: true}, - {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", clobberFlags: true, earlyOk: true}, + {name: "ADDLconst", argLength: 1, reg: gp11sp, asm: "ADDL", aux: "Int32", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ADDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ADDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDWconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDBconstmodify", argLength: 2, reg: gpstoreconst, asm: "ADDB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "SUBQ", argLength: 2, reg: gp21sp2, asm: "SUBQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SUBL", argLength: 2, reg: gp21, asm: "SUBL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SUBQconst", argLength: 1, reg: gp11, asm: "SUBQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SUBLconst", argLength: 1, reg: gp11, asm: "SUBL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "MULQ", argLength: 2, reg: gp21, asm: "IMULQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "MULL", argLength: 2, reg: gp21, asm: "IMULL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "MULQconst", argLength: 1, reg: gp11, asm: "IMUL3Q", aux: "Int32", clobberFlags: true, earlyOk: true}, - {name: "MULLconst", argLength: 1, reg: gp11, asm: "IMUL3L", aux: "Int32", clobberFlags: true, earlyOk: true}, + {name: "MULLconst", argLength: 1, reg: gp11, asm: "IMUL3L", aux: "Int32", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // Let x = arg0*arg1 (full 32x32->64 unsigned multiply). Returns uint32(x), and flags set to overflow if uint32(x) != x. - {name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true}, + {name: "MULLU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt32,Flags)", asm: "MULL", commutative: true, clobberFlags: true, zeroUpperBits: 32}, // Let x = arg0*arg1 (full 64x64->128 unsigned multiply). Returns uint64(x), and flags set to overflow if uint64(x) != x. {name: "MULQU", argLength: 2, reg: regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{ax, regMask{}}, clobbers: dx}, typ: "(UInt64,Flags)", asm: "MULQ", commutative: true, clobberFlags: true}, @@ -390,9 +392,9 @@ func init() { // This is because they have asymmetric register requirements. // There are rewrite rules to try to place arguments in preferable slots. {name: "HMULQ", argLength: 2, reg: gp21hmul, asm: "IMULQ", clobberFlags: true, earlyOk: true}, - {name: "HMULL", argLength: 2, reg: gp21hmul, asm: "IMULL", clobberFlags: true, earlyOk: true}, + {name: "HMULL", argLength: 2, reg: gp21hmul, asm: "IMULL", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "HMULQU", argLength: 2, reg: gp21hmul, asm: "MULQ", clobberFlags: true, earlyOk: true}, - {name: "HMULLU", argLength: 2, reg: gp21hmul, asm: "MULL", clobberFlags: true, earlyOk: true}, + {name: "HMULLU", argLength: 2, reg: gp21hmul, asm: "MULL", clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // (arg0 + arg1) / 2 as unsigned, all 64 result bits {name: "AVGQU", argLength: 2, reg: gp21, commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, @@ -400,19 +402,19 @@ func init() { // DIVx[U] computes [arg0 / arg1, arg0 % arg1] // For signed versions, AuxInt non-zero means that the divisor has been proved to be not -1. {name: "DIVQ", argLength: 2, reg: gp11div, typ: "(Int64,Int64)", asm: "IDIVQ", aux: "Bool", clobberFlags: true}, - {name: "DIVL", argLength: 2, reg: gp11div, typ: "(Int32,Int32)", asm: "IDIVL", aux: "Bool", clobberFlags: true}, + {name: "DIVL", argLength: 2, reg: gp11div, typ: "(Int32,Int32)", asm: "IDIVL", aux: "Bool", clobberFlags: true, zeroUpperBits: 32}, {name: "DIVW", argLength: 2, reg: gp11div, typ: "(Int16,Int16)", asm: "IDIVW", aux: "Bool", clobberFlags: true}, {name: "DIVQU", argLength: 2, reg: gp11div, typ: "(UInt64,UInt64)", asm: "DIVQ", clobberFlags: true}, - {name: "DIVLU", argLength: 2, reg: gp11div, typ: "(UInt32,UInt32)", asm: "DIVL", clobberFlags: true}, + {name: "DIVLU", argLength: 2, reg: gp11div, typ: "(UInt32,UInt32)", asm: "DIVL", clobberFlags: true, zeroUpperBits: 32}, {name: "DIVWU", argLength: 2, reg: gp11div, typ: "(UInt16,UInt16)", asm: "DIVW", clobberFlags: true}, // computes -arg0, flags set for 0-arg0. - {name: "NEGLflags", argLength: 1, reg: gp11flags, typ: "(UInt32,Flags)", asm: "NEGL", resultInArg0: true}, + {name: "NEGLflags", argLength: 1, reg: gp11flags, typ: "(UInt32,Flags)", asm: "NEGL", resultInArg0: true, zeroUpperBits: 32}, // compute arg0+auxint. flags set for arg0+auxint. // NOTE: we pretend the CF/OF flags are undefined for these instructions, // so we can use INC/DEC instead of ADDQconst if auxint is +/-1. (INC/DEC don't modify CF.) {name: "ADDQconstflags", argLength: 1, reg: gp11flags, aux: "Int32", asm: "ADDQ", resultInArg0: true}, - {name: "ADDLconstflags", argLength: 1, reg: gp11flags, aux: "Int32", asm: "ADDL", resultInArg0: true}, + {name: "ADDLconstflags", argLength: 1, reg: gp11flags, aux: "Int32", asm: "ADDL", resultInArg0: true, zeroUpperBits: 32}, // The following 4 add opcodes return the low 64 bits of the sum in the first result and // the carry (the 65th bit) in the carry flag. @@ -439,25 +441,31 @@ func init() { {name: "DIVQU2", argLength: 3, reg: regInfo{inputs: []regMask{dx, ax, gpsp}, outputs: []regMask{ax, dx}}, asm: "DIVQ", clobberFlags: true}, // arg0:arg1 / arg2 (128-bit divided by 64-bit), returns (q, r) {name: "ANDQ", argLength: 2, reg: gp21, asm: "ANDQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & arg1 - {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & arg1 + {name: "ANDL", argLength: 2, reg: gp21, asm: "ANDL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 & arg1 {name: "ANDQconst", argLength: 1, reg: gp11, asm: "ANDQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & auxint - {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 & auxint + {name: "ANDLconst", argLength: 1, reg: gp11, asm: "ANDL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 & auxint {name: "ANDQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ANDLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ANDWconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ANDBconstmodify", argLength: 2, reg: gpstoreconst, asm: "ANDB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // and ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ORQ", argLength: 2, reg: gp21, asm: "ORQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | arg1 - {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | arg1 + {name: "ORL", argLength: 2, reg: gp21, asm: "ORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 | arg1 {name: "ORQconst", argLength: 1, reg: gp11, asm: "ORQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | auxint - {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 | auxint + {name: "ORLconst", argLength: 1, reg: gp11, asm: "ORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 | auxint {name: "ORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "ORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ORWconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "ORBconstmodify", argLength: 2, reg: gpstoreconst, asm: "ORB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // or ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "XORQ", argLength: 2, reg: gp21, asm: "XORQ", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ arg1 - {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ arg1 + {name: "XORL", argLength: 2, reg: gp21, asm: "XORL", commutative: true, resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 ^ arg1 {name: "XORQconst", argLength: 1, reg: gp11, asm: "XORQ", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ auxint - {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true}, // arg0 ^ auxint + {name: "XORLconst", argLength: 1, reg: gp11, asm: "XORL", aux: "Int32", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // arg0 ^ auxint {name: "XORQconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORQ", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem {name: "XORLconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORL", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "XORWconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORW", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem + {name: "XORBconstmodify", argLength: 2, reg: gpstoreconst, asm: "XORB", aux: "SymValAndOff", clobberFlags: true, faultOnNilArg0: true, symEffect: "Read,Write", addrSinkArg0: true}, // xor ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux, arg1=mem // CMPx: compare arg0 to arg1. {name: "CMPQ", argLength: 2, reg: gp2flags, asm: "CMPQ", typ: "Flags"}, @@ -507,19 +515,19 @@ func init() { {name: "UCOMISD", argLength: 2, reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // bit test/set/clear operations - {name: "BTL", argLength: 2, reg: gp2flags, asm: "BTL", typ: "Flags"}, // test whether bit arg0%32 in arg1 is set - {name: "BTQ", argLength: 2, reg: gp2flags, asm: "BTQ", typ: "Flags"}, // test whether bit arg0%64 in arg1 is set - {name: "BTCL", argLength: 2, reg: gp21, asm: "BTCL", resultInArg0: true, clobberFlags: true, earlyOk: true}, // complement bit arg1%32 in arg0 - {name: "BTCQ", argLength: 2, reg: gp21, asm: "BTCQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // complement bit arg1%64 in arg0 - {name: "BTRL", argLength: 2, reg: gp21, asm: "BTRL", resultInArg0: true, clobberFlags: true, earlyOk: true}, // reset bit arg1%32 in arg0 - {name: "BTRQ", argLength: 2, reg: gp21, asm: "BTRQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // reset bit arg1%64 in arg0 - {name: "BTSL", argLength: 2, reg: gp21, asm: "BTSL", resultInArg0: true, clobberFlags: true, earlyOk: true}, // set bit arg1%32 in arg0 - {name: "BTSQ", argLength: 2, reg: gp21, asm: "BTSQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // set bit arg1%64 in arg0 - {name: "BTLconst", argLength: 1, reg: gp1flags, asm: "BTL", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 32 - {name: "BTQconst", argLength: 1, reg: gp1flags, asm: "BTQ", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 64 - {name: "BTCQconst", argLength: 1, reg: gp11, asm: "BTCQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // complement bit auxint in arg0, 31 <= auxint < 64 - {name: "BTRQconst", argLength: 1, reg: gp11, asm: "BTRQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // reset bit auxint in arg0, 31 <= auxint < 64 - {name: "BTSQconst", argLength: 1, reg: gp11, asm: "BTSQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // set bit auxint in arg0, 31 <= auxint < 64 + {name: "BTL", argLength: 2, reg: gp2flags, asm: "BTL", typ: "Flags"}, // test whether bit arg0%32 in arg1 is set + {name: "BTQ", argLength: 2, reg: gp2flags, asm: "BTQ", typ: "Flags"}, // test whether bit arg0%64 in arg1 is set + {name: "BTCL", argLength: 2, reg: gp21, asm: "BTCL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // complement bit arg1%32 in arg0 + {name: "BTCQ", argLength: 2, reg: gp21, asm: "BTCQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // complement bit arg1%64 in arg0 + {name: "BTRL", argLength: 2, reg: gp21, asm: "BTRL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // reset bit arg1%32 in arg0 + {name: "BTRQ", argLength: 2, reg: gp21, asm: "BTRQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // reset bit arg1%64 in arg0 + {name: "BTSL", argLength: 2, reg: gp21, asm: "BTSL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, // set bit arg1%32 in arg0 + {name: "BTSQ", argLength: 2, reg: gp21, asm: "BTSQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, // set bit arg1%64 in arg0 + {name: "BTLconst", argLength: 1, reg: gp1flags, asm: "BTL", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 32 + {name: "BTQconst", argLength: 1, reg: gp1flags, asm: "BTQ", typ: "Flags", aux: "Int8", earlyOk: true}, // test whether bit auxint in arg0 is set, 0 <= auxint < 64 + {name: "BTCQconst", argLength: 1, reg: gp11, asm: "BTCQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // complement bit auxint in arg0, 31 <= auxint < 64 + {name: "BTRQconst", argLength: 1, reg: gp11, asm: "BTRQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // reset bit auxint in arg0, 31 <= auxint < 64 + {name: "BTSQconst", argLength: 1, reg: gp11, asm: "BTSQ", resultInArg0: true, clobberFlags: true, aux: "Int8", earlyOk: true}, // set bit auxint in arg0, 31 <= auxint < 64 // BT[SRC]Qconstmodify // @@ -560,25 +568,25 @@ func init() { // (Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount!) // For *const versions, use auxint instead of arg1 as the shift amount. auxint must be in the range 0 to (Q=63,L=31,W=15,B=7) inclusive. {name: "SHLQ", argLength: 2, reg: gp21shift, asm: "SHLQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHLL", argLength: 2, reg: gp21shift, asm: "SHLL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHLQconst", argLength: 1, reg: gp11, asm: "SHLQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHLLconst", argLength: 1, reg: gp11, asm: "SHLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHRQ", argLength: 2, reg: gp21shift, asm: "SHRQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHRL", argLength: 2, reg: gp21shift, asm: "SHRL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHRW", argLength: 2, reg: gp21shift, asm: "SHRW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SHRB", argLength: 2, reg: gp21shift, asm: "SHRB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SHRQconst", argLength: 1, reg: gp11, asm: "SHRQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SHRLconst", argLength: 1, reg: gp11, asm: "SHRL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SHRWconst", argLength: 1, reg: gp11, asm: "SHRW", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SHRBconst", argLength: 1, reg: gp11, asm: "SHRB", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARQ", argLength: 2, reg: gp21shift, asm: "SARQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SARL", argLength: 2, reg: gp21shift, asm: "SARL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SARW", argLength: 2, reg: gp21shift, asm: "SARW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARB", argLength: 2, reg: gp21shift, asm: "SARB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARQconst", argLength: 1, reg: gp11, asm: "SARQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "SARLconst", argLength: 1, reg: gp11, asm: "SARL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "SARWconst", argLength: 1, reg: gp11, asm: "SARW", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "SARBconst", argLength: 1, reg: gp11, asm: "SARB", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, @@ -589,15 +597,15 @@ func init() { // x==L versions zero the upper 32 bits of the destination register. // x==W and x==B versions leave the upper bits unspecified. {name: "ROLQ", argLength: 2, reg: gp21shift, asm: "ROLQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "ROLL", argLength: 2, reg: gp21shift, asm: "ROLL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ROLW", argLength: 2, reg: gp21shift, asm: "ROLW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "ROLB", argLength: 2, reg: gp21shift, asm: "ROLB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "RORQ", argLength: 2, reg: gp21shift, asm: "RORQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "RORL", argLength: 2, reg: gp21shift, asm: "RORL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "RORL", argLength: 2, reg: gp21shift, asm: "RORL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "RORW", argLength: 2, reg: gp21shift, asm: "RORW", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "RORB", argLength: 2, reg: gp21shift, asm: "RORB", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "ROLQconst", argLength: 1, reg: gp11, asm: "ROLQ", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "ROLLconst", argLength: 1, reg: gp11, asm: "ROLL", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "ROLWconst", argLength: 1, reg: gp11, asm: "ROLW", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, {name: "ROLBconst", argLength: 1, reg: gp11, asm: "ROLB", aux: "Int8", resultInArg0: true, clobberFlags: true, earlyOk: true}, @@ -605,44 +613,44 @@ func init() { // L = int32, Q = int64 // x==L operations zero the upper 4 bytes of the destination register. // computes arg0 op *(arg1+auxint+aux), arg2=mem - {name: "ADDLload", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ADDLload", argLength: 3, reg: gp21load, asm: "ADDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ADDQload", argLength: 3, reg: gp21load, asm: "ADDQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, {name: "SUBQload", argLength: 3, reg: gp21load, asm: "SUBQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLload", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLload", argLength: 3, reg: gp21load, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "SUBLload", argLength: 3, reg: gp21load, asm: "SUBL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ANDLload", argLength: 3, reg: gp21load, asm: "ANDL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ANDQload", argLength: 3, reg: gp21load, asm: "ANDQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, {name: "ORQload", argLength: 3, reg: gp21load, asm: "ORQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLload", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ORLload", argLength: 3, reg: gp21load, asm: "ORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "XORQload", argLength: 3, reg: gp21load, asm: "XORQ", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true}, + {name: "XORLload", argLength: 3, reg: gp21load, asm: "XORL", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, // integer indexed load/op combo // L = int32, Q = int64 // L operations zero the upper 4 bytes of the destination register. // computes arg0 op *(arg1+scale*arg2+auxint+aux), arg3=mem - {name: "ADDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ADDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ADDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ADDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ADDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ADDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ADDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ADDQloadidx1", argLength: 4, reg: gp21loadidx, asm: "ADDQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "ADDQloadidx8", argLength: 4, reg: gp21loadidx, asm: "ADDQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLloadidx1", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLloadidx4", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "SUBLloadidx8", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "SUBLloadidx1", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "SUBLloadidx4", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "SUBLloadidx8", argLength: 4, reg: gp21loadidx, asm: "SUBL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "SUBQloadidx1", argLength: 4, reg: gp21loadidx, asm: "SUBQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "SUBQloadidx8", argLength: 4, reg: gp21loadidx, asm: "SUBQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ANDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ANDLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ANDLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ANDLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ANDL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ANDQloadidx1", argLength: 4, reg: gp21loadidx, asm: "ANDQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "ANDQloadidx8", argLength: 4, reg: gp21loadidx, asm: "ANDQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "ORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "ORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "ORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "ORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "ORQloadidx1", argLength: 4, reg: gp21loadidx, asm: "ORQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "ORQloadidx8", argLength: 4, reg: gp21loadidx, asm: "ORQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, - {name: "XORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, + {name: "XORLloadidx1", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "XORLloadidx4", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 4, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, + {name: "XORLloadidx8", argLength: 4, reg: gp21loadidx, asm: "XORL", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true, zeroUpperBits: 32}, {name: "XORQloadidx1", argLength: 4, reg: gp21loadidx, asm: "XORQ", scale: 1, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, {name: "XORQloadidx8", argLength: 4, reg: gp21loadidx, asm: "XORQ", scale: 8, aux: "SymOff", resultInArg0: true, clobberFlags: true, symEffect: "Read", addrSinkArg1: true}, @@ -701,24 +709,36 @@ func init() { {name: "ADDLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ADDL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ADDLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ADDL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ADDLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "ADDL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ADDW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "ADDW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ADDBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ADDB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ANDLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ANDL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ANDLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ANDL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ANDLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "ANDL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ANDWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ANDW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ANDWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "ANDW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ANDBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ANDB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ORLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ORL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ORLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "ORL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "ORLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "ORL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ORWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ORW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ORWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "ORW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "ORBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "ORB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "XORLconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "XORL", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "XORLconstmodifyidx4", argLength: 3, reg: gpstoreconstidx, asm: "XORL", scale: 4, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, {name: "XORLconstmodifyidx8", argLength: 3, reg: gpstoreconstidx, asm: "XORL", scale: 8, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "XORWconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "XORW", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "XORWconstmodifyidx2", argLength: 3, reg: gpstoreconstidx, asm: "XORW", scale: 2, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, + {name: "XORBconstmodifyidx1", argLength: 3, reg: gpstoreconstidx, asm: "XORB", scale: 1, aux: "SymValAndOff", typ: "Mem", clobberFlags: true, symEffect: "Read,Write", addrSinkArg0: true}, // {NEG,NOT}x: unary ops // computes [NEG:-,NOT:^]arg0 // L = int32, Q = int64 // L operations zero the upper 4 bytes of the destination register. {name: "NEGQ", argLength: 1, reg: gp11, asm: "NEGQ", resultInArg0: true, clobberFlags: true, earlyOk: true}, - {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true, earlyOk: true}, + {name: "NEGL", argLength: 1, reg: gp11, asm: "NEGL", resultInArg0: true, clobberFlags: true, earlyOk: true, zeroUpperBits: 32}, {name: "NOTQ", argLength: 1, reg: gp11, asm: "NOTQ", resultInArg0: true, earlyOk: true}, - {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, earlyOk: true}, + {name: "NOTL", argLength: 1, reg: gp11, asm: "NOTL", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, // BS{F,R}Q returns a tuple [result, flags] // result is undefined if the input is zero. @@ -742,16 +762,16 @@ func init() { {name: "CMOVQCC", argLength: 3, reg: gp21, asm: "CMOVQCC", resultInArg0: true, earlyOk: true}, {name: "CMOVQCS", argLength: 3, reg: gp21, asm: "CMOVQCS", resultInArg0: true, earlyOk: true}, - {name: "CMOVLEQ", argLength: 3, reg: gp21, asm: "CMOVLEQ", resultInArg0: true, earlyOk: true}, - {name: "CMOVLNE", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLLT", argLength: 3, reg: gp21, asm: "CMOVLLT", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGT", argLength: 3, reg: gp21, asm: "CMOVLGT", resultInArg0: true, earlyOk: true}, - {name: "CMOVLLE", argLength: 3, reg: gp21, asm: "CMOVLLE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGE", argLength: 3, reg: gp21, asm: "CMOVLGE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLLS", argLength: 3, reg: gp21, asm: "CMOVLLS", resultInArg0: true, earlyOk: true}, - {name: "CMOVLHI", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true}, - {name: "CMOVLCC", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true}, - {name: "CMOVLCS", argLength: 3, reg: gp21, asm: "CMOVLCS", resultInArg0: true, earlyOk: true}, + {name: "CMOVLEQ", argLength: 3, reg: gp21, asm: "CMOVLEQ", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLNE", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLLT", argLength: 3, reg: gp21, asm: "CMOVLLT", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGT", argLength: 3, reg: gp21, asm: "CMOVLGT", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLLE", argLength: 3, reg: gp21, asm: "CMOVLLE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGE", argLength: 3, reg: gp21, asm: "CMOVLGE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLLS", argLength: 3, reg: gp21, asm: "CMOVLLS", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLHI", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLCC", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLCS", argLength: 3, reg: gp21, asm: "CMOVLCS", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, {name: "CMOVWEQ", argLength: 3, reg: gp21, asm: "CMOVWEQ", resultInArg0: true, earlyOk: true}, {name: "CMOVWNE", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true, earlyOk: true}, @@ -772,10 +792,10 @@ func init() { {name: "CMOVQNEF", argLength: 3, reg: gp21, asm: "CMOVQNE", resultInArg0: true, earlyOk: true}, {name: "CMOVQGTF", argLength: 3, reg: gp21, asm: "CMOVQHI", resultInArg0: true, earlyOk: true}, {name: "CMOVQGEF", argLength: 3, reg: gp21, asm: "CMOVQCC", resultInArg0: true, earlyOk: true}, - {name: "CMOVLEQF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, needIntTemp: true, earlyOk: true}, - {name: "CMOVLNEF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGTF", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true}, - {name: "CMOVLGEF", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true}, + {name: "CMOVLEQF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, needIntTemp: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLNEF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGTF", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, + {name: "CMOVLGEF", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, {name: "CMOVWEQF", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true, needIntTemp: true, earlyOk: true}, {name: "CMOVWNEF", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true, earlyOk: true}, {name: "CMOVWGTF", argLength: 3, reg: gp21, asm: "CMOVWHI", resultInArg0: true, earlyOk: true}, @@ -785,13 +805,13 @@ func init() { // Q: abcdefgh -> hgfedcba // L: abcdefgh -> 0000hgfe (L zeros the upper 4 bytes) {name: "BSWAPQ", argLength: 1, reg: gp11, asm: "BSWAPQ", resultInArg0: true, earlyOk: true}, - {name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, earlyOk: true}, + {name: "BSWAPL", argLength: 1, reg: gp11, asm: "BSWAPL", resultInArg0: true, earlyOk: true, zeroUpperBits: 32}, // POPCNTx counts the number of set bits in the low-order (L=32,Q=64) bits of arg0. // POPCNTx instructions are only guaranteed to be available if GOAMD64>=v2. // For GOAMD64 condition from arg0 {name: "SETGEF", argLength: 1, reg: flagsgp, asm: "SETCC", earlyOk: true}, // extract floating >= condition from arg0 - {name: "MOVBQSX", argLength: 1, reg: gp11, asm: "MOVBQSX", earlyOk: true}, // sign extend arg0 from int8 to int64 - {name: "MOVBQZX", argLength: 1, reg: gp11, asm: "MOVBLZX", earlyOk: true}, // zero extend arg0 from int8 to int64 - {name: "MOVWQSX", argLength: 1, reg: gp11, asm: "MOVWQSX", earlyOk: true}, // sign extend arg0 from int16 to int64 - {name: "MOVWQZX", argLength: 1, reg: gp11, asm: "MOVWLZX", earlyOk: true}, // zero extend arg0 from int16 to int64 - {name: "MOVLQSX", argLength: 1, reg: gp11, asm: "MOVLQSX", earlyOk: true}, // sign extend arg0 from int32 to int64 - {name: "MOVLQZX", argLength: 1, reg: gp11, asm: "MOVL", earlyOk: true}, // zero extend arg0 from int32 to int64 - - {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true, earlyOk: true}, // 32 low bits of auxint (upper 32 are zeroed) - {name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true, earlyOk: true}, // auxint - - {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL", earlyOk: true}, // convert float64 to int32 - {name: "CVTTSD2SQ", argLength: 1, reg: fpgp, asm: "CVTTSD2SQ", earlyOk: true}, // convert float64 to int64 - {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL", earlyOk: true}, // convert float32 to int32 - {name: "CVTTSS2SQ", argLength: 1, reg: fpgp, asm: "CVTTSS2SQ", earlyOk: true}, // convert float32 to int64 - {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS", earlyOk: true}, // convert int32 to float32 - {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD", earlyOk: true}, // convert int32 to float64 - {name: "CVTSQ2SS", argLength: 1, reg: gpfp, asm: "CVTSQ2SS", earlyOk: true}, // convert int64 to float32 - {name: "CVTSQ2SD", argLength: 1, reg: gpfp, asm: "CVTSQ2SD", earlyOk: true}, // convert int64 to float64 - {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS", earlyOk: true}, // convert float64 to float32 - {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD", earlyOk: true}, // convert float32 to float64 + {name: "MOVBQSX", argLength: 1, reg: gp11, asm: "MOVBQSX", earlyOk: true}, // sign extend arg0 from int8 to int64 + {name: "MOVBQZX", argLength: 1, reg: gp11, asm: "MOVBLZX", earlyOk: true, zeroUpperBits: 56}, // zero extend arg0 from int8 to int64 + {name: "MOVWQSX", argLength: 1, reg: gp11, asm: "MOVWQSX", earlyOk: true}, // sign extend arg0 from int16 to int64 + {name: "MOVWQZX", argLength: 1, reg: gp11, asm: "MOVWLZX", earlyOk: true, zeroUpperBits: 48}, // zero extend arg0 from int16 to int64 + {name: "MOVLQSX", argLength: 1, reg: gp11, asm: "MOVLQSX", earlyOk: true}, // sign extend arg0 from int32 to int64 + {name: "MOVLQZX", argLength: 1, reg: gp11, asm: "MOVL", earlyOk: true, zeroUpperBits: 32}, // zero extend arg0 from int32 to int64 + + {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true, earlyOk: true, zeroUpperBits: 32}, // 32 low bits of auxint (upper 32 are zeroed) + {name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true, earlyOk: true}, // auxint + + {name: "CVTTSD2SL", argLength: 1, reg: fpgp, asm: "CVTTSD2SL", earlyOk: true, zeroUpperBits: 32}, // convert float64 to int32 + {name: "CVTTSD2SQ", argLength: 1, reg: fpgp, asm: "CVTTSD2SQ", earlyOk: true}, // convert float64 to int64 + {name: "CVTTSS2SL", argLength: 1, reg: fpgp, asm: "CVTTSS2SL", earlyOk: true, zeroUpperBits: 32}, // convert float32 to int32 + {name: "CVTTSS2SQ", argLength: 1, reg: fpgp, asm: "CVTTSS2SQ", earlyOk: true}, // convert float32 to int64 + {name: "CVTSL2SS", argLength: 1, reg: gpfp, asm: "CVTSL2SS", earlyOk: true}, // convert int32 to float32 + {name: "CVTSL2SD", argLength: 1, reg: gpfp, asm: "CVTSL2SD", earlyOk: true}, // convert int32 to float64 + {name: "CVTSQ2SS", argLength: 1, reg: gpfp, asm: "CVTSQ2SS", earlyOk: true}, // convert int64 to float32 + {name: "CVTSQ2SD", argLength: 1, reg: gpfp, asm: "CVTSQ2SD", earlyOk: true}, // convert int64 to float64 + {name: "CVTSD2SS", argLength: 1, reg: fp11, asm: "CVTSD2SS", earlyOk: true}, // convert float64 to float32 + {name: "CVTSS2SD", argLength: 1, reg: fp11, asm: "CVTSS2SD", earlyOk: true}, // convert float32 to float64 // Move values between int and float registers, with no conversion. // TODO: should we have generic versions of these? - {name: "MOVQi2f", argLength: 1, reg: gpfp, typ: "Float64", earlyOk: true}, // move 64 bits from int to float reg - {name: "MOVQf2i", argLength: 1, reg: fpgp, typ: "UInt64", earlyOk: true}, // move 64 bits from float to int reg - {name: "MOVLi2f", argLength: 1, reg: gpfp, typ: "Float32", earlyOk: true}, // move 32 bits from int to float reg - {name: "MOVLf2i", argLength: 1, reg: fpgp, typ: "UInt32", earlyOk: true}, // move 32 bits from float to int reg, zero extend + {name: "MOVQi2f", argLength: 1, reg: gpfp, typ: "Float64", earlyOk: true}, // move 64 bits from int to float reg + {name: "MOVQf2i", argLength: 1, reg: fpgp, typ: "UInt64", earlyOk: true}, // move 64 bits from float to int reg + {name: "MOVLi2f", argLength: 1, reg: gpfp, typ: "Float32", earlyOk: true}, // move 32 bits from int to float reg + {name: "MOVLf2i", argLength: 1, reg: fpgp, typ: "UInt32", earlyOk: true, zeroUpperBits: 32}, // move 32 bits from float to int reg, zero extend {name: "PXOR", argLength: 2, reg: fp21, asm: "PXOR", commutative: true, resultInArg0: true, earlyOk: true}, // exclusive or, applied to X regs (for float negation). {name: "POR", argLength: 2, reg: fp21, asm: "POR", commutative: true, resultInArg0: true, earlyOk: true}, // inclusive or, applied to X regs (for float min/max). - {name: "LEAQ", argLength: 1, reg: gp11sb, asm: "LEAQ", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux - {name: "LEAL", argLength: 1, reg: gp11sb, asm: "LEAL", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux - {name: "LEAW", argLength: 1, reg: gp11sb, asm: "LEAW", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux + {name: "LEAQ", argLength: 1, reg: gp11sb, asm: "LEAQ", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux + {name: "LEAL", argLength: 1, reg: gp11sb, asm: "LEAL", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + auxint + offset encoded in aux + {name: "LEAW", argLength: 1, reg: gp11sb, asm: "LEAW", aux: "SymOff", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxint + offset encoded in aux // LEAxn computes arg0 + n*arg1 + auxint + aux // x==L zeroes the upper 4 bytes. - {name: "LEAQ1", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux - {name: "LEAL1", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux - {name: "LEAW1", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux - {name: "LEAQ2", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux - {name: "LEAL2", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux - {name: "LEAW2", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux - {name: "LEAQ4", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux - {name: "LEAL4", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux - {name: "LEAW4", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux - {name: "LEAQ8", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux - {name: "LEAL8", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux - {name: "LEAW8", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux + {name: "LEAQ1", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux + {name: "LEAL1", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + arg1 + auxint + aux + {name: "LEAW1", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 1, commutative: true, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + arg1 + auxint + aux + {name: "LEAQ2", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux + {name: "LEAL2", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + 2*arg1 + auxint + aux + {name: "LEAW2", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 2, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 2*arg1 + auxint + aux + {name: "LEAQ4", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux + {name: "LEAL4", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + 4*arg1 + auxint + aux + {name: "LEAW4", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 4, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 4*arg1 + auxint + aux + {name: "LEAQ8", argLength: 2, reg: gp21sb, asm: "LEAQ", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux + {name: "LEAL8", argLength: 2, reg: gp21sb, asm: "LEAL", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true, zeroUpperBits: 32}, // arg0 + 8*arg1 + auxint + aux + {name: "LEAW8", argLength: 2, reg: gp21sb, asm: "LEAW", scale: 8, aux: "SymOff", symEffect: "Addr", earlyOk: true}, // arg0 + 8*arg1 + auxint + aux // Note: LEAx{1,2,4,8} must not have OpSB as either argument. // MOVxload: loads // Load (Q=8,L=4,W=2,B=1) bytes from (arg0+auxint+aux), arg1=mem. // "+auxint+aux" == add auxint and the offset of the symbol in aux (if any) to the effective address // Standard versions zero extend the result. SX versions sign extend the result. - {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, + {name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVBLZX", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 56}, {name: "MOVBQSXload", argLength: 2, reg: gpload, asm: "MOVBQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, - {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, + {name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVWLZX", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 48}, {name: "MOVWQSXload", argLength: 2, reg: gpload, asm: "MOVWQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, - {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, + {name: "MOVLload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, {name: "MOVLQSXload", argLength: 2, reg: gpload, asm: "MOVLQSX", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, {name: "MOVQload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, @@ -955,12 +975,12 @@ func init() { // MOVxloadidx: indexed loads // load (Q=8,L=4,W=2,B=1) bytes from (arg0+scale*arg1+auxint+aux), arg2=mem. // Results are zero-extended. (TODO: sign-extending indexed loads) - {name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", scale: 1, aux: "SymOff", typ: "UInt8", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, - {name: "MOVWloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWLZX", scale: 1, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, - {name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVWLZX", scale: 2, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true}, - {name: "MOVLloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, - {name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, - {name: "MOVLloadidx8", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, + {name: "MOVBloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBLZX", scale: 1, aux: "SymOff", typ: "UInt8", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 56}, + {name: "MOVWloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVWLZX", scale: 1, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 48}, + {name: "MOVWloadidx2", argLength: 3, reg: gploadidx, asm: "MOVWLZX", scale: 2, aux: "SymOff", typ: "UInt16", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 48}, + {name: "MOVLloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 32}, + {name: "MOVLloadidx4", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, + {name: "MOVLloadidx8", argLength: 3, reg: gploadidx, asm: "MOVL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, {name: "MOVQloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVQ", scale: 1, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, {name: "MOVQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVQ", scale: 8, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true}, @@ -1141,7 +1161,7 @@ func init() { // Returns a pointer to a write barrier buffer in R11. {name: "LoweredWB", argLength: 1, reg: regInfo{clobbers: callerSave.minus(gp.union(g)), outputs: []regMask{buildReg("R11")}}, clobberFlags: true, aux: "Int64"}, - {name: "LoweredHasCPUFeature", argLength: 0, reg: gp01, rematerializeable: true, typ: "UInt64", aux: "Sym", symEffect: "None"}, + {name: "LoweredHasCPUFeature", argLength: 0, reg: gp01, rematerializeable: true, typ: "UInt64", aux: "Sym", symEffect: "None", zeroUpperBits: 56}, // LoweredPanicBoundsRR takes x and y, two values that caused a bounds check to fail. // the RC and CR versions are used when one of the arguments is a constant. CC is used @@ -1170,7 +1190,7 @@ func init() { // so they can be properly ordered with other loads. // load from arg0+auxint+aux. arg1=mem. {name: "MOVBatomicload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, - {name: "MOVLatomicload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, + {name: "MOVLatomicload", argLength: 2, reg: gpload, asm: "MOVL", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read", zeroUpperBits: 32}, {name: "MOVQatomicload", argLength: 2, reg: gpload, asm: "MOVQ", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // Atomic stores and exchanges. Stores use XCHG to get the right memory ordering semantics. @@ -1178,14 +1198,14 @@ func init() { // These ops return a tuple of . // Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)! {name: "XCHGB", argLength: 3, reg: gpstorexchg, asm: "XCHGB", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, - {name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, + {name: "XCHGL", argLength: 3, reg: gpstorexchg, asm: "XCHGL", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr", zeroUpperBits: 32}, {name: "XCHGQ", argLength: 3, reg: gpstorexchg, asm: "XCHGQ", aux: "SymOff", resultInArg0: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, // Atomic adds. // *(arg1+auxint+aux) += arg0. arg2=mem. // Returns a tuple of . // Note: arg0 and arg1 are backwards compared to MOVLstore (to facilitate resultInArg0)! - {name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, + {name: "XADDLlock", argLength: 3, reg: gpstorexchg, asm: "XADDL", typ: "(UInt32,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr", zeroUpperBits: 32}, {name: "XADDQlock", argLength: 3, reg: gpstorexchg, asm: "XADDQ", typ: "(UInt64,Mem)", aux: "SymOff", resultInArg0: true, clobberFlags: true, faultOnNilArg1: true, hasSideEffects: true, symEffect: "RdWr"}, {name: "AddTupleFirst32", argLength: 2}, // arg1=tuple . Returns . {name: "AddTupleFirst64", argLength: 2}, // arg1=tuple . Returns . @@ -1225,9 +1245,9 @@ func init() { // *(arg0+auxint+aux) op= arg1. arg2=mem. // New style that returns a tuple of . {name: "LoweredAtomicAnd64", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ANDQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicAnd32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ANDL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicAnd32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ANDL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, {name: "LoweredAtomicOr64", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ORQ", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicOr32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ORL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicOr32", argLength: 3, reg: atomicLogic, resultNotInArgs: true, asm: "ORL", aux: "SymOff", clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, symEffect: "RdWr", unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, // Prefetch instructions // Do prefetch arg0 address. arg0=addr, arg1=memory. Instruction variant selects locality hint @@ -1235,16 +1255,22 @@ func init() { {name: "PrefetchNTA", argLength: 2, reg: prefreg, asm: "PREFETCHNTA", hasSideEffects: true}, // CPUID feature: BMI1. - {name: "ANDNQ", argLength: 2, reg: gp21, asm: "ANDNQ", clobberFlags: true}, // arg0 &^ arg1 - {name: "ANDNL", argLength: 2, reg: gp21, asm: "ANDNL", clobberFlags: true}, // arg0 &^ arg1 - {name: "BLSIQ", argLength: 1, reg: gp11, asm: "BLSIQ", clobberFlags: true}, // arg0 & -arg0 - {name: "BLSIL", argLength: 1, reg: gp11, asm: "BLSIL", clobberFlags: true}, // arg0 & -arg0 - {name: "BLSMSKQ", argLength: 1, reg: gp11, asm: "BLSMSKQ", clobberFlags: true}, // arg0 ^ (arg0 - 1) - {name: "BLSMSKL", argLength: 1, reg: gp11, asm: "BLSMSKL", clobberFlags: true}, // arg0 ^ (arg0 - 1) - {name: "BLSRQ", argLength: 1, reg: gp11flags, asm: "BLSRQ", typ: "(UInt64,Flags)"}, // arg0 & (arg0 - 1) - {name: "BLSRL", argLength: 1, reg: gp11flags, asm: "BLSRL", typ: "(UInt32,Flags)"}, // arg0 & (arg0 - 1) + {name: "ANDNQ", argLength: 2, reg: gp21, asm: "ANDNQ", clobberFlags: true}, // arg0 &^ arg1 + {name: "ANDNL", argLength: 2, reg: gp21, asm: "ANDNL", clobberFlags: true, zeroUpperBits: 32}, // arg0 &^ arg1 + {name: "BLSIQ", argLength: 1, reg: gp11, asm: "BLSIQ", clobberFlags: true}, // arg0 & -arg0 + {name: "BLSIL", argLength: 1, reg: gp11, asm: "BLSIL", clobberFlags: true, zeroUpperBits: 32}, // arg0 & -arg0 + {name: "BLSMSKQ", argLength: 1, reg: gp11, asm: "BLSMSKQ", clobberFlags: true}, // arg0 ^ (arg0 - 1) + {name: "BLSMSKL", argLength: 1, reg: gp11, asm: "BLSMSKL", clobberFlags: true, zeroUpperBits: 32}, // arg0 ^ (arg0 - 1) + {name: "BLSRQ", argLength: 1, reg: gp11flags, asm: "BLSRQ", typ: "(UInt64,Flags)"}, // arg0 & (arg0 - 1) + {name: "BLSRL", argLength: 1, reg: gp11flags, asm: "BLSRL", typ: "(UInt32,Flags)", zeroUpperBits: 32}, // arg0 & (arg0 - 1) // count the number of trailing zero bits, prefer TZCNTQ over BSFQ, as TZCNTQ(0)==64 // and BSFQ(0) is undefined. Same for TZCNTL(0)==32 + // + // TZCNT/LZCNT deliberately carry no zeroUpperBits: their result is + // bounded only as long as every rule producing them stays gated on + // GOAMD64 >= 3. On older parts their REP BSF/BSR encodings silently + // decode as legacy BSF/BSR, which leave the destination unmodified + // on zero input — a guarantee too easy to break silently. {name: "TZCNTQ", argLength: 1, reg: gp11, asm: "TZCNTQ", clobberFlags: true}, {name: "TZCNTL", argLength: 1, reg: gp11, asm: "TZCNTL", clobberFlags: true}, @@ -1255,17 +1281,17 @@ func init() { // CPUID feature: MOVBE // MOVBEWload does not satisfy zero extended, so only use MOVBEWstore - {name: "MOVBEWstore", argLength: 3, reg: gpstore, asm: "MOVBEW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem - {name: "MOVBELload", argLength: 2, reg: gpload, asm: "MOVBEL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load and swap 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend. - {name: "MOVBELstore", argLength: 3, reg: gpstore, asm: "MOVBEL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem - {name: "MOVBEQload", argLength: 2, reg: gpload, asm: "MOVBEQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+auxint+aux. arg1=mem - {name: "MOVBEQstore", argLength: 3, reg: gpstore, asm: "MOVBEQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVBEWstore", argLength: 3, reg: gpstore, asm: "MOVBEW", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVBELload", argLength: 2, reg: gpload, asm: "MOVBEL", aux: "SymOff", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+auxint+aux. arg1=mem. Zero extend. + {name: "MOVBELstore", argLength: 3, reg: gpstore, asm: "MOVBEL", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVBEQload", argLength: 2, reg: gpload, asm: "MOVBEQ", aux: "SymOff", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+auxint+aux. arg1=mem + {name: "MOVBEQstore", argLength: 3, reg: gpstore, asm: "MOVBEQ", aux: "SymOff", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // swap and store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem // indexed MOVBE loads - {name: "MOVBELloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, // load and swap 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. - {name: "MOVBELloadidx4", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, // load and swap 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem. Zero extend. - {name: "MOVBELloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true}, // load and swap 4 bytes from arg0+8*arg1+auxint+aux. arg2=mem. Zero extend. - {name: "MOVBEQloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEQ", scale: 1, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, // load and swap 8 bytes from arg0+arg1+auxint+aux. arg2=mem - {name: "MOVBEQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEQ", scale: 8, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem + {name: "MOVBELloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEL", scale: 1, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+arg1+auxint+aux. arg2=mem. Zero extend. + {name: "MOVBELloadidx4", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 4, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+4*arg1+auxint+aux. arg2=mem. Zero extend. + {name: "MOVBELloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEL", scale: 8, aux: "SymOff", typ: "UInt32", symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load and swap 4 bytes from arg0+8*arg1+auxint+aux. arg2=mem. Zero extend. + {name: "MOVBEQloadidx1", argLength: 3, reg: gploadidx, commutative: true, asm: "MOVBEQ", scale: 1, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true, addrSinkArg1: true}, // load and swap 8 bytes from arg0+arg1+auxint+aux. arg2=mem + {name: "MOVBEQloadidx8", argLength: 3, reg: gploadidx, asm: "MOVBEQ", scale: 8, aux: "SymOff", typ: "UInt64", symEffect: "Read", addrSinkArg0: true}, // load and swap 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem // indexed MOVBE stores {name: "MOVBEWstoreidx1", argLength: 4, reg: gpstoreidx, commutative: true, asm: "MOVBEW", scale: 1, aux: "SymOff", symEffect: "Write", addrSinkArg0: true, addrSinkArg1: true}, // swap and store 2 bytes in arg2 to arg0+arg1+auxint+aux. arg3=mem {name: "MOVBEWstoreidx2", argLength: 4, reg: gpstoreidx, asm: "MOVBEW", scale: 2, aux: "SymOff", symEffect: "Write", addrSinkArg0: true}, // swap and store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem @@ -1276,35 +1302,35 @@ func init() { {name: "MOVBEQstoreidx8", argLength: 4, reg: gpstoreidx, asm: "MOVBEQ", scale: 8, aux: "SymOff", symEffect: "Write", addrSinkArg0: true}, // swap and store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem // CPUID feature: BMI2. - {name: "SARXQ", argLength: 2, reg: gp21, asm: "SARXQ"}, // signed arg0 >> arg1, shift amount is mod 64 - {name: "SARXL", argLength: 2, reg: gp21, asm: "SARXL"}, // signed int32(arg0) >> arg1, shift amount is mod 32 - {name: "SHLXQ", argLength: 2, reg: gp21, asm: "SHLXQ"}, // arg0 << arg1, shift amount is mod 64 - {name: "SHLXL", argLength: 2, reg: gp21, asm: "SHLXL"}, // arg0 << arg1, shift amount is mod 32 - {name: "SHRXQ", argLength: 2, reg: gp21, asm: "SHRXQ"}, // unsigned arg0 >> arg1, shift amount is mod 64 - {name: "SHRXL", argLength: 2, reg: gp21, asm: "SHRXL"}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32 - - {name: "SARXLload", argLength: 3, reg: gp21shxload, asm: "SARXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 - {name: "SARXQload", argLength: 3, reg: gp21shxload, asm: "SARXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 - {name: "SHLXLload", argLength: 3, reg: gp21shxload, asm: "SHLXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 32 - {name: "SHLXQload", argLength: 3, reg: gp21shxload, asm: "SHLXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 64 - {name: "SHRXLload", argLength: 3, reg: gp21shxload, asm: "SHRXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 - {name: "SHRXQload", argLength: 3, reg: gp21shxload, asm: "SHRXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 - - {name: "SARXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SARXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SARXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SARXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 - {name: "SARXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 - {name: "SHLXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 - {name: "SHLXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+4*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 - {name: "SHLXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 - {name: "SHLXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 - {name: "SHLXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 - {name: "SHRXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SHRXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SHRXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 - {name: "SHRXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 - {name: "SHRXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SARXQ", argLength: 2, reg: gp21, asm: "SARXQ"}, // signed arg0 >> arg1, shift amount is mod 64 + {name: "SARXL", argLength: 2, reg: gp21, asm: "SARXL", zeroUpperBits: 32}, // signed int32(arg0) >> arg1, shift amount is mod 32 + {name: "SHLXQ", argLength: 2, reg: gp21, asm: "SHLXQ"}, // arg0 << arg1, shift amount is mod 64 + {name: "SHLXL", argLength: 2, reg: gp21, asm: "SHLXL", zeroUpperBits: 32}, // arg0 << arg1, shift amount is mod 32 + {name: "SHRXQ", argLength: 2, reg: gp21, asm: "SHRXQ"}, // unsigned arg0 >> arg1, shift amount is mod 64 + {name: "SHRXL", argLength: 2, reg: gp21, asm: "SHRXL", zeroUpperBits: 32}, // unsigned uint32(arg0) >> arg1, shift amount is mod 32 + + {name: "SARXLload", argLength: 3, reg: gp21shxload, asm: "SARXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 + {name: "SARXQload", argLength: 3, reg: gp21shxload, asm: "SARXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 + {name: "SHLXLload", argLength: 3, reg: gp21shxload, asm: "SHLXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 32 + {name: "SHLXQload", argLength: 3, reg: gp21shxload, asm: "SHLXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+auxint+aux) << arg1, arg2=mem, shift amount is mod 64 + {name: "SHRXLload", argLength: 3, reg: gp21shxload, asm: "SHRXL", aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 32 + {name: "SHRXQload", argLength: 3, reg: gp21shxload, asm: "SHRXQ", aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+auxint+aux) >> arg1, arg2=mem, shift amount is mod 64 + + {name: "SARXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SARXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SARXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SARXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SARXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SARXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // signed *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SHLXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 + {name: "SHLXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+4*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 + {name: "SHLXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 32 + {name: "SHLXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+1*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 + {name: "SHLXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHLXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // *(arg0+8*arg1+auxint+aux) << arg2, arg3=mem, shift amount is mod 64 + {name: "SHRXLloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 1, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SHRXLloadidx4", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 4, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+4*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SHRXLloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXL", scale: 8, aux: "SymOff", typ: "Uint32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 32 + {name: "SHRXQloadidx1", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 1, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+1*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 + {name: "SHRXQloadidx8", argLength: 4, reg: gp21shxloadidx, asm: "SHRXQ", scale: 8, aux: "SymOff", typ: "Uint64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // unsigned *(arg0+8*arg1+auxint+aux) >> arg2, arg3=mem, shift amount is mod 64 // Unpack bytes, low 64-bits. // @@ -1358,7 +1384,7 @@ func init() { // Input treated as [16]uint8. Output is [16]bit (uint16 bitmap). // // output[i] = (input[i] >> 7) & 1 - {name: "PMOVMSKB", argLength: 1, reg: fpgp, asm: "PMOVMSKB"}, + {name: "PMOVMSKB", argLength: 1, reg: fpgp, asm: "PMOVMSKB", zeroUpperBits: 48}, // SIMD ops {name: "VMOVDQUload128", argLength: 2, reg: vload, asm: "VMOVDQU", aux: "SymOff", faultOnNilArg0: true, symEffect: "Read"}, // load from arg0+auxint+aux, arg1 = mem @@ -1425,12 +1451,12 @@ func init() { {name: "VPMOVVec64x8ToM", argLength: 1, reg: wk, asm: "VPMOVQ2M"}, // AVX1/2 moves from int-vector to bitmask (extracting sign bits) - {name: "VPMOVMSKB128", argLength: 1, reg: vgp, asm: "VPMOVMSKB"}, - {name: "VPMOVMSKB256", argLength: 1, reg: vgp, asm: "VPMOVMSKB"}, - {name: "VMOVMSKPS128", argLength: 1, reg: vgp, asm: "VMOVMSKPS"}, - {name: "VMOVMSKPS256", argLength: 1, reg: vgp, asm: "VMOVMSKPS"}, - {name: "VMOVMSKPD128", argLength: 1, reg: vgp, asm: "VMOVMSKPD"}, - {name: "VMOVMSKPD256", argLength: 1, reg: vgp, asm: "VMOVMSKPD"}, + {name: "VPMOVMSKB128", argLength: 1, reg: vgp, asm: "VPMOVMSKB", zeroUpperBits: 48}, + {name: "VPMOVMSKB256", argLength: 1, reg: vgp, asm: "VPMOVMSKB", zeroUpperBits: 32}, + {name: "VMOVMSKPS128", argLength: 1, reg: vgp, asm: "VMOVMSKPS", zeroUpperBits: 56}, + {name: "VMOVMSKPS256", argLength: 1, reg: vgp, asm: "VMOVMSKPS", zeroUpperBits: 56}, + {name: "VMOVMSKPD128", argLength: 1, reg: vgp, asm: "VMOVMSKPD", zeroUpperBits: 56}, + {name: "VMOVMSKPD256", argLength: 1, reg: vgp, asm: "VMOVMSKPD", zeroUpperBits: 56}, // X15 is the zero register up to 128-bit. For larger values, we zero it on the fly. {name: "Zero128", argLength: 0, reg: x15only, zeroWidth: true, fixedReg: true}, @@ -1477,9 +1503,9 @@ func init() { {name: "KMOVWk", argLength: 1, reg: gpk, asm: "KMOVW"}, {name: "KMOVBk", argLength: 1, reg: gpk, asm: "KMOVB"}, {name: "KMOVQi", argLength: 1, reg: kgp, asm: "KMOVQ"}, - {name: "KMOVDi", argLength: 1, reg: kgp, asm: "KMOVD"}, - {name: "KMOVWi", argLength: 1, reg: kgp, asm: "KMOVW"}, - {name: "KMOVBi", argLength: 1, reg: kgp, asm: "KMOVB"}, + {name: "KMOVDi", argLength: 1, reg: kgp, asm: "KMOVD", zeroUpperBits: 32}, + {name: "KMOVWi", argLength: 1, reg: kgp, asm: "KMOVW", zeroUpperBits: 48}, + {name: "KMOVBi", argLength: 1, reg: kgp, asm: "KMOVB", zeroUpperBits: 56}, // Mask logical operations {name: "KANDB", argLength: 2, reg: k2k, asm: "KANDB", typ: "Mask"}, diff --git a/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules b/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules index 9bdb5f8d803bdb..04070889aa876f 100644 --- a/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules +++ b/src/cmd/compile/internal/ssa/_gen/AMD64latelower.rules @@ -8,6 +8,6 @@ (SHR(Q|L) x y) && buildcfg.GOAMD64 >= 3 => (SHRX(Q|L) x y) // See comments in ARM64latelower.rules for why these are here. -(MOVLQZX x) && ZeroUpper32Bits(x,3) => x -(MOVWQZX x) && ZeroUpper48Bits(x,3) => x -(MOVBQZX x) && ZeroUpper56Bits(x,3) => x +(MOVLQZX x) && ZeroUpper32Bits(x) => x +(MOVWQZX x) && ZeroUpper48Bits(x) => x +(MOVBQZX x) && ZeroUpper56Bits(x) => x diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64.rules b/src/cmd/compile/internal/ssa/_gen/ARM64.rules index 8189f1583b9627..b5a50f1081dd7a 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64.rules @@ -657,10 +657,10 @@ // against 128 (=2^7) is a bit-7 test, for both compare widths and both // signednesses: with the value in [0,255] the signed and unsigned orderings // against 128 coincide. -((UGE|ULT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) -((UGE|ULT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) -((GE|LT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) -((GE|LT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x, 3) => ((TBNZ|TBZ) [7] x yes no) +((UGE|ULT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) +((UGE|ULT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) +((GE|LT) (CMPWconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) +((GE|LT) (CMPconst [128] x) yes no) && ZeroUpper56Bits(x) => ((TBNZ|TBZ) [7] x yes no) // fold offset into address (ADDconst [off1] (MOVDaddr [off2] {sym} ptr)) && is32Bit(off1+int64(off2)) => diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go index 0da3151acd3e7c..4c29e410f19ea9 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/ARM64Ops.go @@ -195,32 +195,32 @@ func init() { ) ops := []opData{ // binary ops - {name: "ADCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "ADCS", commutative: true}, // arg0+arg1+carry, set flags. - {name: "ADCzerocarry", argLength: 1, reg: gp0flags1, typ: "UInt64", asm: "ADC", earlyOk: true}, // ZR+ZR+carry - {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true, earlyOk: true}, // arg0 + arg1 - {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64", earlyOk: true}, // arg0 + auxInt - {name: "ADDSconstflags", argLength: 1, reg: gp11flags, typ: "(UInt64,Flags)", asm: "ADDS", aux: "Int64"}, // arg0+auxint, set flags. - {name: "ADDSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "ADDS", commutative: true}, // arg0+arg1, set flags. - {name: "SUB", argLength: 2, reg: gp21, asm: "SUB", earlyOk: true}, // arg0 - arg1 - {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64", earlyOk: true}, // arg0 - auxInt - {name: "SBCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "SBCS"}, // arg0-(arg1+borrowing), set flags. - {name: "SUBSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "SUBS"}, // arg0 - arg1, set flags. - {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, earlyOk: true}, // arg0 * arg1 - {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, earlyOk: true}, // arg0 * arg1, 32-bit - {name: "MNEG", argLength: 2, reg: gp21, asm: "MNEG", commutative: true, earlyOk: true}, // -arg0 * arg1 - {name: "MNEGW", argLength: 2, reg: gp21, asm: "MNEGW", commutative: true, earlyOk: true}, // -arg0 * arg1, 32-bit - {name: "MULH", argLength: 2, reg: gp21, asm: "SMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, signed - {name: "UMULH", argLength: 2, reg: gp21, asm: "UMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, unsigned - {name: "MULL", argLength: 2, reg: gp21, asm: "SMULL", commutative: true, earlyOk: true}, // arg0 * arg1, signed, 32-bit mult results in 64-bit - {name: "UMULL", argLength: 2, reg: gp21, asm: "UMULL", commutative: true, earlyOk: true}, // arg0 * arg1, unsigned, 32-bit mult results in 64-bit - {name: "DIV", argLength: 2, reg: gp21, asm: "SDIV", earlyOk: true}, // arg0 / arg1, signed - {name: "UDIV", argLength: 2, reg: gp21, asm: "UDIV", earlyOk: true}, // arg0 / arg1, unsigned - {name: "DIVW", argLength: 2, reg: gp21, asm: "SDIVW", earlyOk: true}, // arg0 / arg1, signed, 32 bit - {name: "UDIVW", argLength: 2, reg: gp21, asm: "UDIVW", earlyOk: true}, // arg0 / arg1, unsigned, 32 bit - {name: "MOD", argLength: 2, reg: gp21, asm: "REM", earlyOk: true}, // arg0 % arg1, signed - {name: "UMOD", argLength: 2, reg: gp21, asm: "UREM", earlyOk: true}, // arg0 % arg1, unsigned - {name: "MODW", argLength: 2, reg: gp21, asm: "REMW", earlyOk: true}, // arg0 % arg1, signed, 32 bit - {name: "UMODW", argLength: 2, reg: gp21, asm: "UREMW", earlyOk: true}, // arg0 % arg1, unsigned, 32 bit + {name: "ADCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "ADCS", commutative: true}, // arg0+arg1+carry, set flags. + {name: "ADCzerocarry", argLength: 1, reg: gp0flags1, typ: "UInt64", asm: "ADC", earlyOk: true, zeroUpperBits: 56}, // ZR+ZR+carry + {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true, earlyOk: true}, // arg0 + arg1 + {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int64", earlyOk: true}, // arg0 + auxInt + {name: "ADDSconstflags", argLength: 1, reg: gp11flags, typ: "(UInt64,Flags)", asm: "ADDS", aux: "Int64"}, // arg0+auxint, set flags. + {name: "ADDSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "ADDS", commutative: true}, // arg0+arg1, set flags. + {name: "SUB", argLength: 2, reg: gp21, asm: "SUB", earlyOk: true}, // arg0 - arg1 + {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int64", earlyOk: true}, // arg0 - auxInt + {name: "SBCSflags", argLength: 3, reg: gp2flags1flags, typ: "(UInt64,Flags)", asm: "SBCS"}, // arg0-(arg1+borrowing), set flags. + {name: "SUBSflags", argLength: 2, reg: gp21flags, typ: "(UInt64,Flags)", asm: "SUBS"}, // arg0 - arg1, set flags. + {name: "MUL", argLength: 2, reg: gp21, asm: "MUL", commutative: true, earlyOk: true}, // arg0 * arg1 + {name: "MULW", argLength: 2, reg: gp21, asm: "MULW", commutative: true, earlyOk: true, zeroUpperBits: 32}, // arg0 * arg1, 32-bit + {name: "MNEG", argLength: 2, reg: gp21, asm: "MNEG", commutative: true, earlyOk: true}, // -arg0 * arg1 + {name: "MNEGW", argLength: 2, reg: gp21, asm: "MNEGW", commutative: true, earlyOk: true, zeroUpperBits: 32}, // -arg0 * arg1, 32-bit + {name: "MULH", argLength: 2, reg: gp21, asm: "SMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, signed + {name: "UMULH", argLength: 2, reg: gp21, asm: "UMULH", commutative: true, earlyOk: true}, // (arg0 * arg1) >> 64, unsigned + {name: "MULL", argLength: 2, reg: gp21, asm: "SMULL", commutative: true, earlyOk: true}, // arg0 * arg1, signed, 32-bit mult results in 64-bit + {name: "UMULL", argLength: 2, reg: gp21, asm: "UMULL", commutative: true, earlyOk: true}, // arg0 * arg1, unsigned, 32-bit mult results in 64-bit + {name: "DIV", argLength: 2, reg: gp21, asm: "SDIV", earlyOk: true}, // arg0 / arg1, signed + {name: "UDIV", argLength: 2, reg: gp21, asm: "UDIV", earlyOk: true}, // arg0 / arg1, unsigned + {name: "DIVW", argLength: 2, reg: gp21, asm: "SDIVW", earlyOk: true, zeroUpperBits: 32}, // arg0 / arg1, signed, 32 bit + {name: "UDIVW", argLength: 2, reg: gp21, asm: "UDIVW", earlyOk: true, zeroUpperBits: 32}, // arg0 / arg1, unsigned, 32 bit + {name: "MOD", argLength: 2, reg: gp21, asm: "REM", earlyOk: true}, // arg0 % arg1, signed + {name: "UMOD", argLength: 2, reg: gp21, asm: "UREM", earlyOk: true}, // arg0 % arg1, unsigned + {name: "MODW", argLength: 2, reg: gp21, asm: "REMW", earlyOk: true, zeroUpperBits: 32}, // arg0 % arg1, signed, 32 bit + {name: "UMODW", argLength: 2, reg: gp21, asm: "UREMW", earlyOk: true, zeroUpperBits: 32}, // arg0 % arg1, unsigned, 32 bit {name: "FADDS", argLength: 2, reg: fp21, asm: "FADDS", commutative: true, earlyOk: true}, // arg0 + arg1 {name: "FADDD", argLength: 2, reg: fp21, asm: "FADDD", commutative: true, earlyOk: true}, // arg0 + arg1 @@ -259,45 +259,45 @@ func init() { {name: "FMAXD", argLength: 2, reg: fp21, asm: "FMAXD", earlyOk: true}, // max(arg0, arg1) {name: "FMAXS", argLength: 2, reg: fp21, asm: "FMAXS", earlyOk: true}, // max(arg0, arg1) {name: "REV", argLength: 1, reg: gp11, asm: "REV", earlyOk: true}, // byte reverse, 64-bit - {name: "REVW", argLength: 1, reg: gp11, asm: "REVW", earlyOk: true}, // byte reverse, 32-bit + {name: "REVW", argLength: 1, reg: gp11, asm: "REVW", earlyOk: true, zeroUpperBits: 32}, // byte reverse, 32-bit {name: "REV16", argLength: 1, reg: gp11, asm: "REV16", earlyOk: true}, // byte reverse in each 16-bit halfword, 64-bit - {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W", earlyOk: true}, // byte reverse in each 16-bit halfword, 32-bit + {name: "REV16W", argLength: 1, reg: gp11, asm: "REV16W", earlyOk: true, zeroUpperBits: 32}, // byte reverse in each 16-bit halfword, 32-bit {name: "RBIT", argLength: 1, reg: gp11, asm: "RBIT", earlyOk: true}, // bit reverse, 64-bit - {name: "RBITW", argLength: 1, reg: gp11, asm: "RBITW", earlyOk: true}, // bit reverse, 32-bit - {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ", earlyOk: true}, // count leading zero, 64-bit - {name: "CLZW", argLength: 1, reg: gp11, asm: "CLZW", earlyOk: true}, // count leading zero, 32-bit + {name: "RBITW", argLength: 1, reg: gp11, asm: "RBITW", earlyOk: true, zeroUpperBits: 32}, // bit reverse, 32-bit + {name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ", earlyOk: true, zeroUpperBits: 56}, // count leading zero, 64-bit + {name: "CLZW", argLength: 1, reg: gp11, asm: "CLZW", earlyOk: true, zeroUpperBits: 56}, // count leading zero, 32-bit {name: "VCNT", argLength: 1, reg: fp11, asm: "VCNT", earlyOk: true}, // count set bits for each 8-bit unit and store the result in each 8-bit unit {name: "VUADDLV", argLength: 1, reg: fp11, asm: "VUADDLV", earlyOk: true}, // unsigned sum of eight bytes in a 64-bit value, zero extended to 64-bit. {name: "LoweredRound32F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true, earlyOk: true}, {name: "LoweredRound64F", argLength: 1, reg: fp11, resultInArg0: true, zeroWidth: true, earlyOk: true}, // 3-operand, the addend comes first - {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", earlyOk: true}, // +arg0 + (arg1 * arg2) - {name: "FMADDD", argLength: 3, reg: fp31, asm: "FMADDD", earlyOk: true}, // +arg0 + (arg1 * arg2) - {name: "FNMADDS", argLength: 3, reg: fp31, asm: "FNMADDS", earlyOk: true}, // -arg0 - (arg1 * arg2) - {name: "FNMADDD", argLength: 3, reg: fp31, asm: "FNMADDD", earlyOk: true}, // -arg0 - (arg1 * arg2) - {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", earlyOk: true}, // +arg0 - (arg1 * arg2) - {name: "FMSUBD", argLength: 3, reg: fp31, asm: "FMSUBD", earlyOk: true}, // +arg0 - (arg1 * arg2) - {name: "FNMSUBS", argLength: 3, reg: fp31, asm: "FNMSUBS", earlyOk: true}, // -arg0 + (arg1 * arg2) - {name: "FNMSUBD", argLength: 3, reg: fp31, asm: "FNMSUBD", earlyOk: true}, // -arg0 + (arg1 * arg2) - {name: "MADD", argLength: 3, reg: gp31, asm: "MADD", earlyOk: true}, // +arg0 + (arg1 * arg2) - {name: "MADDW", argLength: 3, reg: gp31, asm: "MADDW", earlyOk: true}, // +arg0 + (arg1 * arg2), 32-bit - {name: "MSUB", argLength: 3, reg: gp31, asm: "MSUB", earlyOk: true}, // +arg0 - (arg1 * arg2) - {name: "MSUBW", argLength: 3, reg: gp31, asm: "MSUBW", earlyOk: true}, // +arg0 - (arg1 * arg2), 32-bit + {name: "FMADDS", argLength: 3, reg: fp31, asm: "FMADDS", earlyOk: true}, // +arg0 + (arg1 * arg2) + {name: "FMADDD", argLength: 3, reg: fp31, asm: "FMADDD", earlyOk: true}, // +arg0 + (arg1 * arg2) + {name: "FNMADDS", argLength: 3, reg: fp31, asm: "FNMADDS", earlyOk: true}, // -arg0 - (arg1 * arg2) + {name: "FNMADDD", argLength: 3, reg: fp31, asm: "FNMADDD", earlyOk: true}, // -arg0 - (arg1 * arg2) + {name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS", earlyOk: true}, // +arg0 - (arg1 * arg2) + {name: "FMSUBD", argLength: 3, reg: fp31, asm: "FMSUBD", earlyOk: true}, // +arg0 - (arg1 * arg2) + {name: "FNMSUBS", argLength: 3, reg: fp31, asm: "FNMSUBS", earlyOk: true}, // -arg0 + (arg1 * arg2) + {name: "FNMSUBD", argLength: 3, reg: fp31, asm: "FNMSUBD", earlyOk: true}, // -arg0 + (arg1 * arg2) + {name: "MADD", argLength: 3, reg: gp31, asm: "MADD", earlyOk: true}, // +arg0 + (arg1 * arg2) + {name: "MADDW", argLength: 3, reg: gp31, asm: "MADDW", earlyOk: true, zeroUpperBits: 32}, // +arg0 + (arg1 * arg2), 32-bit + {name: "MSUB", argLength: 3, reg: gp31, asm: "MSUB", earlyOk: true}, // +arg0 - (arg1 * arg2) + {name: "MSUBW", argLength: 3, reg: gp31, asm: "MSUBW", earlyOk: true, zeroUpperBits: 32}, // +arg0 - (arg1 * arg2), 32-bit // shifts - {name: "SLL", argLength: 2, reg: gp21, asm: "LSL", earlyOk: true}, // arg0 << arg1, shift amount is mod 64 - {name: "SLLconst", argLength: 1, reg: gp11, asm: "LSL", aux: "Int64", earlyOk: true}, // arg0 << auxInt, auxInt should be in the range 0 to 63. - {name: "SRL", argLength: 2, reg: gp21, asm: "LSR", earlyOk: true}, // arg0 >> arg1, unsigned, shift amount is mod 64 - {name: "SRLconst", argLength: 1, reg: gp11, asm: "LSR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, unsigned, auxInt should be in the range 0 to 63. - {name: "SRA", argLength: 2, reg: gp21, asm: "ASR", earlyOk: true}, // arg0 >> arg1, signed, shift amount is mod 64 - {name: "SRAconst", argLength: 1, reg: gp11, asm: "ASR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, signed, auxInt should be in the range 0 to 63. - {name: "ROR", argLength: 2, reg: gp21, asm: "ROR", earlyOk: true}, // arg0 right rotate by (arg1 mod 64) bits - {name: "RORW", argLength: 2, reg: gp21, asm: "RORW", earlyOk: true}, // arg0 right rotate by (arg1 mod 32) bits - {name: "RORconst", argLength: 1, reg: gp11, asm: "ROR", aux: "Int64", earlyOk: true}, // arg0 right rotate by auxInt bits, auxInt should be in the range 0 to 63. - {name: "RORWconst", argLength: 1, reg: gp11, asm: "RORW", aux: "Int64", earlyOk: true}, // uint32(arg0) right rotate by auxInt bits, auxInt should be in the range 0 to 31. - {name: "EXTRconst", argLength: 2, reg: gp21, asm: "EXTR", aux: "Int64", earlyOk: true}, // extract 64 bits from arg0:arg1 starting at lsb auxInt, auxInt should be in the range 0 to 63. - {name: "EXTRWconst", argLength: 2, reg: gp21, asm: "EXTRW", aux: "Int64", earlyOk: true}, // extract 32 bits from arg0[31:0]:arg1[31:0] starting at lsb auxInt and zero top 32 bits, auxInt should be in the range 0 to 31. + {name: "SLL", argLength: 2, reg: gp21, asm: "LSL", earlyOk: true}, // arg0 << arg1, shift amount is mod 64 + {name: "SLLconst", argLength: 1, reg: gp11, asm: "LSL", aux: "Int64", earlyOk: true}, // arg0 << auxInt, auxInt should be in the range 0 to 63. + {name: "SRL", argLength: 2, reg: gp21, asm: "LSR", earlyOk: true}, // arg0 >> arg1, unsigned, shift amount is mod 64 + {name: "SRLconst", argLength: 1, reg: gp11, asm: "LSR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, unsigned, auxInt should be in the range 0 to 63. + {name: "SRA", argLength: 2, reg: gp21, asm: "ASR", earlyOk: true}, // arg0 >> arg1, signed, shift amount is mod 64 + {name: "SRAconst", argLength: 1, reg: gp11, asm: "ASR", aux: "Int64", earlyOk: true}, // arg0 >> auxInt, signed, auxInt should be in the range 0 to 63. + {name: "ROR", argLength: 2, reg: gp21, asm: "ROR", earlyOk: true}, // arg0 right rotate by (arg1 mod 64) bits + {name: "RORW", argLength: 2, reg: gp21, asm: "RORW", earlyOk: true, zeroUpperBits: 32}, // arg0 right rotate by (arg1 mod 32) bits + {name: "RORconst", argLength: 1, reg: gp11, asm: "ROR", aux: "Int64", earlyOk: true}, // arg0 right rotate by auxInt bits, auxInt should be in the range 0 to 63. + {name: "RORWconst", argLength: 1, reg: gp11, asm: "RORW", aux: "Int64", earlyOk: true, zeroUpperBits: 32}, // uint32(arg0) right rotate by auxInt bits, auxInt should be in the range 0 to 31. + {name: "EXTRconst", argLength: 2, reg: gp21, asm: "EXTR", aux: "Int64", earlyOk: true}, // extract 64 bits from arg0:arg1 starting at lsb auxInt, auxInt should be in the range 0 to 63. + {name: "EXTRWconst", argLength: 2, reg: gp21, asm: "EXTRW", aux: "Int64", earlyOk: true, zeroUpperBits: 32}, // extract 32 bits from arg0[31:0]:arg1[31:0] starting at lsb auxInt and zero top 32 bits, auxInt should be in the range 0 to 31. // comparisons {name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1 @@ -388,16 +388,16 @@ func init() { {name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP").union(buildReg("SB"))}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true, symEffect: "Addr", earlyOk: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB - {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. - {name: "FMOVQload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVQ", typ: "Vec128", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 56}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVHUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVHU", typ: "UInt16", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 48}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVWload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVW", typ: "Int32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVWUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVWU", typ: "UInt32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "MOVDload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVD", typ: "UInt64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVSload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVS", typ: "Float32", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVDload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVD", typ: "Float64", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. + {name: "FMOVQload", argLength: 2, reg: fpload, aux: "SymOff", asm: "FMOVQ", typ: "Vec128", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // load from arg0 + auxInt + aux. arg1=mem. // LDP instructions load the contents of two adjacent locations in memory into registers. // Address to start loading is addr = arg0 + auxInt + aux. @@ -405,32 +405,32 @@ func init() { // y := *(*T)(addr+sizeof(T)) // arg1=mem // Returns the tuple . - {name: "LDP", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDP", typ: "(UInt64,UInt64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int64 (gp reg destination) - {name: "LDPW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPW", typ: "(UInt32,UInt32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int32 (gp reg destination) unsigned extension - {name: "LDPSW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPSW", typ: "(Int32,Int32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int32 (gp reg destination) signed extension - {name: "FLDPD", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPD", typ: "(Float64,Float64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float64 (fp reg destination) - {name: "FLDPS", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPS", typ: "(Float32,Float32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float32 (fp reg destination) - {name: "FLDPQ", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPQ", typ: "(Vec128,Vec128)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=vec128 (fp reg destination) + {name: "LDP", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDP", typ: "(UInt64,UInt64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int64 (gp reg destination) + {name: "LDPW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPW", typ: "(UInt32,UInt32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true, zeroUpperBits: 32}, // T=int32 (gp reg destination) unsigned extension + {name: "LDPSW", argLength: 2, reg: gpload2, aux: "SymOff", asm: "LDPSW", typ: "(Int32,Int32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=int32 (gp reg destination) signed extension + {name: "FLDPD", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPD", typ: "(Float64,Float64)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float64 (fp reg destination) + {name: "FLDPS", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPS", typ: "(Float32,Float32)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=float32 (fp reg destination) + {name: "FLDPQ", argLength: 2, reg: fpload2, aux: "SymOff", asm: "FLDPQ", typ: "(Vec128,Vec128)", faultOnNilArg0: true, symEffect: "Read", addrSinkArg0: true}, // T=vec128 (fp reg destination) // register indexed load - {name: "MOVDloadidx", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit dword from arg0 + arg1, arg2 = mem. - {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVWUloadidx", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true, addrSinkArg1: true}, // load 16-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true, addrSinkArg1: true}, // load 16-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB", typ: "Int8", addrSinkArg0: true, addrSinkArg1: true}, // load 8-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. - {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU", typ: "UInt8", addrSinkArg0: true, addrSinkArg1: true}, // load 8-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. - {name: "FMOVSloadidx", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit float from arg0 + arg1, arg2=mem. - {name: "FMOVDloadidx", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit float from arg0 + arg1, arg2=mem. + {name: "MOVDloadidx", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit dword from arg0 + arg1, arg2 = mem. + {name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVWUloadidx", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 32}, // load 32-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "MOVHloadidx", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true, addrSinkArg1: true}, // load 16-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVHUloadidx", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 48}, // load 16-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "MOVBloadidx", argLength: 3, reg: gp2load, asm: "MOVB", typ: "Int8", addrSinkArg0: true, addrSinkArg1: true}, // load 8-bit word from arg0 + arg1, sign-extended to 64-bit, arg2=mem. + {name: "MOVBUloadidx", argLength: 3, reg: gp2load, asm: "MOVBU", typ: "UInt8", addrSinkArg0: true, addrSinkArg1: true, zeroUpperBits: 56}, // load 8-bit word from arg0 + arg1, zero-extended to 64-bit, arg2=mem. + {name: "FMOVSloadidx", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true, addrSinkArg1: true}, // load 32-bit float from arg0 + arg1, arg2=mem. + {name: "FMOVDloadidx", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true, addrSinkArg1: true}, // load 64-bit float from arg0 + arg1, arg2=mem. // shifted register indexed load - {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. - {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. - {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. - {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. - {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. - {name: "FMOVSloadidx4", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true}, // load 32-bit float from arg0 + arg1*4, arg2 = mem. - {name: "FMOVDloadidx8", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true}, // load 64-bit float from arg0 + arg1*8, arg2 = mem. + {name: "MOVHloadidx2", argLength: 3, reg: gp2load, asm: "MOVH", typ: "Int16", addrSinkArg0: true}, // load 16-bit half-word from arg0 + arg1*2, sign-extended to 64-bit, arg2=mem. + {name: "MOVHUloadidx2", argLength: 3, reg: gp2load, asm: "MOVHU", typ: "UInt16", addrSinkArg0: true, zeroUpperBits: 48}, // load 16-bit half-word from arg0 + arg1*2, zero-extended to 64-bit, arg2=mem. + {name: "MOVWloadidx4", argLength: 3, reg: gp2load, asm: "MOVW", typ: "Int32", addrSinkArg0: true}, // load 32-bit word from arg0 + arg1*4, sign-extended to 64-bit, arg2=mem. + {name: "MOVWUloadidx4", argLength: 3, reg: gp2load, asm: "MOVWU", typ: "UInt32", addrSinkArg0: true, zeroUpperBits: 32}, // load 32-bit word from arg0 + arg1*4, zero-extended to 64-bit, arg2=mem. + {name: "MOVDloadidx8", argLength: 3, reg: gp2load, asm: "MOVD", typ: "UInt64", addrSinkArg0: true}, // load 64-bit double-word from arg0 + arg1*8, arg2 = mem. + {name: "FMOVSloadidx4", argLength: 3, reg: fp2load, asm: "FMOVS", typ: "Float32", addrSinkArg0: true}, // load 32-bit float from arg0 + arg1*4, arg2 = mem. + {name: "FMOVDloadidx8", argLength: 3, reg: fp2load, asm: "FMOVD", typ: "Float64", addrSinkArg0: true}, // load 64-bit float from arg0 + arg1*8, arg2 = mem. {name: "MOVBstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVB", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // store 1 byte of arg1 to arg0 + auxInt + aux. arg2=mem. {name: "MOVHstore", argLength: 3, reg: gpstore, aux: "SymOff", asm: "MOVH", typ: "Mem", faultOnNilArg0: true, symEffect: "Write", addrSinkArg0: true}, // store 2 bytes of arg1 to arg0 + auxInt + aux. arg2=mem. @@ -466,40 +466,40 @@ func init() { {name: "FMOVSstoreidx4", argLength: 4, reg: fpstoreidx, asm: "FMOVS", typ: "Mem", addrSinkArg0: true}, // store 32-bit float of arg2 to arg0 + arg1*4, arg3=mem. {name: "FMOVDstoreidx8", argLength: 4, reg: fpstoreidx, asm: "FMOVD", typ: "Mem", addrSinkArg0: true}, // store 64-bit float of arg2 to arg0 + arg1*8, arg3=mem. - {name: "FMOVDgpfp", argLength: 1, reg: gpfp, asm: "FMOVD", earlyOk: true}, // move int64 to float64 (no conversion) - {name: "FMOVDfpgp", argLength: 1, reg: fpgp, asm: "FMOVD", earlyOk: true}, // move float64 to int64 (no conversion) - {name: "FMOVSgpfp", argLength: 1, reg: gpfp, asm: "FMOVS", earlyOk: true}, // move 32bits from int to float reg (no conversion) - {name: "FMOVSfpgp", argLength: 1, reg: fpgp, asm: "FMOVS", earlyOk: true}, // move 32bits from float to int reg, zero extend (no conversion) + {name: "FMOVDgpfp", argLength: 1, reg: gpfp, asm: "FMOVD", earlyOk: true}, // move int64 to float64 (no conversion) + {name: "FMOVDfpgp", argLength: 1, reg: fpgp, asm: "FMOVD", earlyOk: true}, // move float64 to int64 (no conversion) + {name: "FMOVSgpfp", argLength: 1, reg: gpfp, asm: "FMOVS", earlyOk: true}, // move 32bits from int to float reg (no conversion) + {name: "FMOVSfpgp", argLength: 1, reg: fpgp, asm: "FMOVS", earlyOk: true, zeroUpperBits: 32}, // move 32bits from float to int reg, zero extend (no conversion) // conversions - {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", earlyOk: true}, // move from arg0, sign-extended from byte - {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU", earlyOk: true}, // move from arg0, unsign-extended from byte - {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", earlyOk: true}, // move from arg0, sign-extended from half - {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU", earlyOk: true}, // move from arg0, unsign-extended from half - {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", earlyOk: true}, // move from arg0, sign-extended from word - {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU", earlyOk: true}, // move from arg0, unsign-extended from word - {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOVD", earlyOk: true}, // move from arg0 + {name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVB", earlyOk: true}, // move from arg0, sign-extended from byte + {name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU", earlyOk: true, zeroUpperBits: 56}, // move from arg0, unsign-extended from byte + {name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVH", earlyOk: true}, // move from arg0, sign-extended from half + {name: "MOVHUreg", argLength: 1, reg: gp11, asm: "MOVHU", earlyOk: true, zeroUpperBits: 48}, // move from arg0, unsign-extended from half + {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", earlyOk: true}, // move from arg0, sign-extended from word + {name: "MOVWUreg", argLength: 1, reg: gp11, asm: "MOVWU", earlyOk: true, zeroUpperBits: 32}, // move from arg0, unsign-extended from word + {name: "MOVDreg", argLength: 1, reg: gp11, asm: "MOVD", earlyOk: true}, // move from arg0 {name: "MOVDnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true, earlyOk: true}, // nop, return arg0 in same register - {name: "SCVTFWS", argLength: 1, reg: gpfp, asm: "SCVTFWS", earlyOk: true}, // int32 -> float32 - {name: "SCVTFWD", argLength: 1, reg: gpfp, asm: "SCVTFWD", earlyOk: true}, // int32 -> float64 - {name: "UCVTFWS", argLength: 1, reg: gpfp, asm: "UCVTFWS", earlyOk: true}, // uint32 -> float32 - {name: "UCVTFWD", argLength: 1, reg: gpfp, asm: "UCVTFWD", earlyOk: true}, // uint32 -> float64 - {name: "SCVTFS", argLength: 1, reg: gpfp, asm: "SCVTFS", earlyOk: true}, // int64 -> float32 - {name: "SCVTFD", argLength: 1, reg: gpfp, asm: "SCVTFD", earlyOk: true}, // int64 -> float64 - {name: "UCVTFS", argLength: 1, reg: gpfp, asm: "UCVTFS", earlyOk: true}, // uint64 -> float32 - {name: "UCVTFD", argLength: 1, reg: gpfp, asm: "UCVTFD", earlyOk: true}, // uint64 -> float64 - {name: "FCVTZSSW", argLength: 1, reg: fpgp, asm: "FCVTZSSW", earlyOk: true}, // float32 -> int32 - {name: "FCVTZSDW", argLength: 1, reg: fpgp, asm: "FCVTZSDW", earlyOk: true}, // float64 -> int32 - {name: "FCVTZUSW", argLength: 1, reg: fpgp, asm: "FCVTZUSW", earlyOk: true}, // float32 -> uint32 - {name: "FCVTZUDW", argLength: 1, reg: fpgp, asm: "FCVTZUDW", earlyOk: true}, // float64 -> uint32 - {name: "FCVTZSS", argLength: 1, reg: fpgp, asm: "FCVTZSS", earlyOk: true}, // float32 -> int64 - {name: "FCVTZSD", argLength: 1, reg: fpgp, asm: "FCVTZSD", earlyOk: true}, // float64 -> int64 - {name: "FCVTZUS", argLength: 1, reg: fpgp, asm: "FCVTZUS", earlyOk: true}, // float32 -> uint64 - {name: "FCVTZUD", argLength: 1, reg: fpgp, asm: "FCVTZUD", earlyOk: true}, // float64 -> uint64 - {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", earlyOk: true}, // float32 -> float64 - {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", earlyOk: true}, // float64 -> float32 + {name: "SCVTFWS", argLength: 1, reg: gpfp, asm: "SCVTFWS", earlyOk: true}, // int32 -> float32 + {name: "SCVTFWD", argLength: 1, reg: gpfp, asm: "SCVTFWD", earlyOk: true}, // int32 -> float64 + {name: "UCVTFWS", argLength: 1, reg: gpfp, asm: "UCVTFWS", earlyOk: true}, // uint32 -> float32 + {name: "UCVTFWD", argLength: 1, reg: gpfp, asm: "UCVTFWD", earlyOk: true}, // uint32 -> float64 + {name: "SCVTFS", argLength: 1, reg: gpfp, asm: "SCVTFS", earlyOk: true}, // int64 -> float32 + {name: "SCVTFD", argLength: 1, reg: gpfp, asm: "SCVTFD", earlyOk: true}, // int64 -> float64 + {name: "UCVTFS", argLength: 1, reg: gpfp, asm: "UCVTFS", earlyOk: true}, // uint64 -> float32 + {name: "UCVTFD", argLength: 1, reg: gpfp, asm: "UCVTFD", earlyOk: true}, // uint64 -> float64 + {name: "FCVTZSSW", argLength: 1, reg: fpgp, asm: "FCVTZSSW", earlyOk: true, zeroUpperBits: 32}, // float32 -> int32 + {name: "FCVTZSDW", argLength: 1, reg: fpgp, asm: "FCVTZSDW", earlyOk: true, zeroUpperBits: 32}, // float64 -> int32 + {name: "FCVTZUSW", argLength: 1, reg: fpgp, asm: "FCVTZUSW", earlyOk: true, zeroUpperBits: 32}, // float32 -> uint32 + {name: "FCVTZUDW", argLength: 1, reg: fpgp, asm: "FCVTZUDW", earlyOk: true, zeroUpperBits: 32}, // float64 -> uint32 + {name: "FCVTZSS", argLength: 1, reg: fpgp, asm: "FCVTZSS", earlyOk: true}, // float32 -> int64 + {name: "FCVTZSD", argLength: 1, reg: fpgp, asm: "FCVTZSD", earlyOk: true}, // float64 -> int64 + {name: "FCVTZUS", argLength: 1, reg: fpgp, asm: "FCVTZUS", earlyOk: true}, // float32 -> uint64 + {name: "FCVTZUD", argLength: 1, reg: fpgp, asm: "FCVTZUD", earlyOk: true}, // float64 -> uint64 + {name: "FCVTSD", argLength: 1, reg: fp11, asm: "FCVTSD", earlyOk: true}, // float32 -> float64 + {name: "FCVTDS", argLength: 1, reg: fp11, asm: "FCVTDS", earlyOk: true}, // float64 -> float32 // 64-bit floating-point round to integers in 64-bit FP format {name: "FRINTAD", argLength: 1, reg: fp11, asm: "FRINTAD", earlyOk: true}, // Round (ties Away from zero; 0.5 -> 1, -0.5 -> -1) @@ -550,26 +550,26 @@ func init() { {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}, nilCheck: true, faultOnNilArg0: true}, // panic if arg0 is nil. arg1=mem. {name: "LoweredMemEq", argLength: 4, reg: regInfo{inputs: []regMask{buildReg("R0"), buildReg("R1"), buildReg("R2")}, outputs: []regMask{buildReg("R0")}, clobbers: callerSave}, typ: "Bool", faultOnNilArg0: true, faultOnNilArg1: true, clobberFlags: true, call: true}, // arg0, arg1 - pointers to memory, arg2=size, arg3=mem. - {name: "Equal", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode x==y false otherwise. - {name: "NotEqual", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode x!=y false otherwise. - {name: "LessThan", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode signed xy false otherwise. - {name: "GreaterEqual", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode signed x>=y false otherwise. - {name: "LessThanU", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode unsigned xy false otherwise. - {name: "GreaterEqualU", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode unsigned x>=y false otherwise. - {name: "LessThanF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point xy false otherwise. - {name: "GreaterEqualF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x>=y false otherwise. - {name: "NotLessThanF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x>=y || x is unordered with y, false otherwise. - {name: "NotLessEqualF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x>y || x is unordered with y, false otherwise. - {name: "NotGreaterThanF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x<=y || x is unordered with y, false otherwise. - {name: "NotGreaterEqualF", argLength: 1, reg: readflags, earlyOk: true}, // bool, true flags encode floating-point x=y but without honoring overflow, false otherwise. + {name: "Equal", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode x==y false otherwise. + {name: "NotEqual", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode x!=y false otherwise. + {name: "LessThan", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode signed xy false otherwise. + {name: "GreaterEqual", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode signed x>=y false otherwise. + {name: "LessThanU", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode unsigned xy false otherwise. + {name: "GreaterEqualU", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode unsigned x>=y false otherwise. + {name: "LessThanF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point xy false otherwise. + {name: "GreaterEqualF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x>=y false otherwise. + {name: "NotLessThanF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x>=y || x is unordered with y, false otherwise. + {name: "NotLessEqualF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x>y || x is unordered with y, false otherwise. + {name: "NotGreaterThanF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x<=y || x is unordered with y, false otherwise. + {name: "NotGreaterEqualF", argLength: 1, reg: readflags, earlyOk: true, zeroUpperBits: 56}, // bool, true flags encode floating-point x=y but without honoring overflow, false otherwise. // medium zeroing // arg0 = address of memory to zero @@ -676,8 +676,8 @@ func init() { // load from arg0. arg1=mem. auxint must be zero. // returns so they can be properly ordered with other loads. {name: "LDAR", argLength: 2, reg: gpload, asm: "LDAR", faultOnNilArg0: true}, - {name: "LDARB", argLength: 2, reg: gpload, asm: "LDARB", faultOnNilArg0: true}, - {name: "LDARW", argLength: 2, reg: gpload, asm: "LDARW", faultOnNilArg0: true}, + {name: "LDARB", argLength: 2, reg: gpload, asm: "LDARB", faultOnNilArg0: true, zeroUpperBits: 56}, + {name: "LDARW", argLength: 2, reg: gpload, asm: "LDARW", faultOnNilArg0: true, zeroUpperBits: 32}, // atomic stores. // store arg1 to arg0. arg2=mem. returns memory. auxint must be zero. @@ -691,15 +691,15 @@ func init() { // STLXR Rarg1, (Rarg0), Rtmp // CBNZ Rtmp, -2(PC) {name: "LoweredAtomicExchange64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicExchange8", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicExchange32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 32}, + {name: "LoweredAtomicExchange8", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic exchange variant. // store arg1 to arg0. arg2=mem. returns . auxint must be zero. // SWPALD Rarg1, (Rarg0), Rout {name: "LoweredAtomicExchange64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicExchange32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicExchange8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicExchange32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, zeroUpperBits: 32}, + {name: "LoweredAtomicExchange8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic add. // *arg0 += arg1. arg2=mem. returns . auxint must be zero. @@ -707,6 +707,8 @@ func init() { // ADD Rarg1, Rout // STLXR Rout, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) + // Unlike the other 32-bit atomics, no zeroUpperBits: the final write + // to Rout is the 64-bit ADD. {name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, {name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, @@ -731,8 +733,8 @@ func init() { // STLXR Rarg2, (Rarg0), Rtmp // CBNZ Rtmp, -4(PC) // CSET EQ, Rout - {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicCas64", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, + {name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic compare and swap variant. // arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero. @@ -746,8 +748,8 @@ func init() { // CASAL Rtmp, (Rarg0), Rarg2 // CMP Rarg1, Rtmp // CSET EQ, Rout - {name: "LoweredAtomicCas64Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicCas32Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, + {name: "LoweredAtomicCas64Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, + {name: "LoweredAtomicCas32Variant", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, // atomic and/or. // *arg0 &= (|=) arg1. arg2=mem. returns . auxint must be zero. @@ -755,12 +757,12 @@ func init() { // AND/OR Rarg1, Rout, tempReg // STLXR tempReg, (Rarg0), Rtmp // CBNZ Rtmp, -3(PC) - {name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 56}, + {name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 56}, {name: "LoweredAtomicAnd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, {name: "LoweredAtomicOr64", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicAnd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, - {name: "LoweredAtomicOr32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true}, + {name: "LoweredAtomicAnd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, + {name: "LoweredAtomicOr32", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, needIntTemp: true, zeroUpperBits: 32}, // atomic and/or variant. // *arg0 &= (|=) arg1. arg2=mem. returns . auxint must be zero. @@ -769,12 +771,12 @@ func init() { // LDANDALB Rtemp, (Rarg0), Rout // OR: // LDORALB Rarg1, (Rarg0), Rout - {name: "LoweredAtomicAnd8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicOr8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicAnd8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 56}, + {name: "LoweredAtomicOr8Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, zeroUpperBits: 56}, {name: "LoweredAtomicAnd64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, {name: "LoweredAtomicOr64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, - {name: "LoweredAtomicAnd32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true}, - {name: "LoweredAtomicOr32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true}, + {name: "LoweredAtomicAnd32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, zeroUpperBits: 32}, + {name: "LoweredAtomicOr32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, zeroUpperBits: 32}, // LoweredWB invokes runtime.gcWriteBarrier. arg0=mem, auxint=# of buffer entries needed // It saves all GP registers if necessary, @@ -798,8 +800,8 @@ func init() { {name: "PRFM", argLength: 2, aux: "Int64", reg: prefreg, asm: "PRFM", hasSideEffects: true}, // Publication barrier - {name: "DMB", argLength: 1, aux: "Int64", asm: "DMB", hasSideEffects: true}, // Do data barrier. arg0=memory, aux=option. - {name: "ZERO", zeroWidth: true, fixedReg: true, earlyOk: true}, // reads-as-zero register + {name: "DMB", argLength: 1, aux: "Int64", asm: "DMB", hasSideEffects: true}, // Do data barrier. arg0=memory, aux=option. + {name: "ZERO", zeroWidth: true, fixedReg: true, earlyOk: true, zeroUpperBits: 56}, // reads-as-zero register // Broadcast constant to each lane of a SIMD register. aux=constant. // TODO: add the other arrangements after assembler supports them, to be used in simdgen-generated opt rules. diff --git a/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules b/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules index 3372fb1bd0e730..963a58d83d3647 100644 --- a/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules +++ b/src/cmd/compile/internal/ssa/_gen/ARM64latelower.rules @@ -29,9 +29,9 @@ (MOVBUreg x:((Equal|NotEqual|LessThan|LessThanU|LessThanF|LessEqual|LessEqualU|LessEqualF|GreaterThan|GreaterThanU|GreaterThanF|GreaterEqual|GreaterEqualU|GreaterEqualF) _)) => x // omit unsigned extension -(MOVBUreg x) && ZeroUpper56Bits(x, 3) => x -(MOVHUreg x) && ZeroUpper48Bits(x, 3) => x -(MOVWUreg x) && ZeroUpper32Bits(x, 3) => x +(MOVBUreg x) && ZeroUpper56Bits(x) => x +(MOVHUreg x) && ZeroUpper48Bits(x) => x +(MOVWUreg x) && ZeroUpper32Bits(x) => x // don't extend after proper load (MOVBreg x:(MOVBload _ _)) => (MOVDreg x) diff --git a/src/cmd/compile/internal/ssa/_gen/main.go b/src/cmd/compile/internal/ssa/_gen/main.go index d87150a039bc07..46bb6a40f730bb 100644 --- a/src/cmd/compile/internal/ssa/_gen/main.go +++ b/src/cmd/compile/internal/ssa/_gen/main.go @@ -77,6 +77,7 @@ type opData struct { addrSinkArg1 bool // the address in arg1 does not propagate to the result symEffect string // effect this op has on symbol in aux scale uint8 // amd64/386 indexed load scale + zeroUpperBits uint8 // the op writes a 64-bit GPR whose upper N bits are always zero (0, 32, 48 or 56); for a tuple op, this holds for every integer result } type blockData struct { @@ -451,6 +452,14 @@ func genOp() { if v.scale != 0 { fmt.Fprintf(w, "scale: %d,\n", v.scale) } + if v.zeroUpperBits != 0 { + switch v.zeroUpperBits { + case 32, 48, 56: + default: + log.Fatalf("%s: zeroUpperBits must be 0, 32, 48 or 56, have %d", v.name, v.zeroUpperBits) + } + fmt.Fprintf(w, "zeroUpperBits: %d,\n", v.zeroUpperBits) + } fmt.Fprintln(w, "reg:regInfo{") // Compute input allocation order. We allocate from the diff --git a/src/cmd/compile/internal/ssa/addressingmodes.go b/src/cmd/compile/internal/ssa/addressingmodes.go index 4e3209e396b5af..a221c9f45a5612 100644 --- a/src/cmd/compile/internal/ssa/addressingmodes.go +++ b/src/cmd/compile/internal/ssa/addressingmodes.go @@ -316,6 +316,14 @@ var combine = map[[2]Op]Op{ [2]Op{OpAMD64ORQconstmodify, OpAMD64ADDQ}: OpAMD64ORQconstmodifyidx1, [2]Op{OpAMD64XORLconstmodify, OpAMD64ADDQ}: OpAMD64XORLconstmodifyidx1, [2]Op{OpAMD64XORQconstmodify, OpAMD64ADDQ}: OpAMD64XORQconstmodifyidx1, + [2]Op{OpAMD64ADDWconstmodify, OpAMD64ADDQ}: OpAMD64ADDWconstmodifyidx1, + [2]Op{OpAMD64ADDBconstmodify, OpAMD64ADDQ}: OpAMD64ADDBconstmodifyidx1, + [2]Op{OpAMD64ANDWconstmodify, OpAMD64ADDQ}: OpAMD64ANDWconstmodifyidx1, + [2]Op{OpAMD64ANDBconstmodify, OpAMD64ADDQ}: OpAMD64ANDBconstmodifyidx1, + [2]Op{OpAMD64ORWconstmodify, OpAMD64ADDQ}: OpAMD64ORWconstmodifyidx1, + [2]Op{OpAMD64ORBconstmodify, OpAMD64ADDQ}: OpAMD64ORBconstmodifyidx1, + [2]Op{OpAMD64XORWconstmodify, OpAMD64ADDQ}: OpAMD64XORWconstmodifyidx1, + [2]Op{OpAMD64XORBconstmodify, OpAMD64ADDQ}: OpAMD64XORBconstmodifyidx1, [2]Op{OpAMD64ADDLconstmodify, OpAMD64LEAQ1}: OpAMD64ADDLconstmodifyidx1, [2]Op{OpAMD64ADDLconstmodify, OpAMD64LEAQ4}: OpAMD64ADDLconstmodifyidx4, @@ -337,6 +345,18 @@ var combine = map[[2]Op]Op{ [2]Op{OpAMD64XORLconstmodify, OpAMD64LEAQ8}: OpAMD64XORLconstmodifyidx8, [2]Op{OpAMD64XORQconstmodify, OpAMD64LEAQ1}: OpAMD64XORQconstmodifyidx1, [2]Op{OpAMD64XORQconstmodify, OpAMD64LEAQ8}: OpAMD64XORQconstmodifyidx8, + [2]Op{OpAMD64ADDWconstmodify, OpAMD64LEAQ1}: OpAMD64ADDWconstmodifyidx1, + [2]Op{OpAMD64ADDWconstmodify, OpAMD64LEAQ2}: OpAMD64ADDWconstmodifyidx2, + [2]Op{OpAMD64ADDBconstmodify, OpAMD64LEAQ1}: OpAMD64ADDBconstmodifyidx1, + [2]Op{OpAMD64ANDWconstmodify, OpAMD64LEAQ1}: OpAMD64ANDWconstmodifyidx1, + [2]Op{OpAMD64ANDWconstmodify, OpAMD64LEAQ2}: OpAMD64ANDWconstmodifyidx2, + [2]Op{OpAMD64ANDBconstmodify, OpAMD64LEAQ1}: OpAMD64ANDBconstmodifyidx1, + [2]Op{OpAMD64ORWconstmodify, OpAMD64LEAQ1}: OpAMD64ORWconstmodifyidx1, + [2]Op{OpAMD64ORWconstmodify, OpAMD64LEAQ2}: OpAMD64ORWconstmodifyidx2, + [2]Op{OpAMD64ORBconstmodify, OpAMD64LEAQ1}: OpAMD64ORBconstmodifyidx1, + [2]Op{OpAMD64XORWconstmodify, OpAMD64LEAQ1}: OpAMD64XORWconstmodifyidx1, + [2]Op{OpAMD64XORWconstmodify, OpAMD64LEAQ2}: OpAMD64XORWconstmodifyidx2, + [2]Op{OpAMD64XORBconstmodify, OpAMD64LEAQ1}: OpAMD64XORBconstmodifyidx1, [2]Op{OpAMD64ADDSSload, OpAMD64LEAQ1}: OpAMD64ADDSSloadidx1, [2]Op{OpAMD64ADDSSload, OpAMD64LEAQ4}: OpAMD64ADDSSloadidx4, diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index d2657d7acdd9c0..480da486090804 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -30,7 +30,7 @@ import ( // - the order of f.Blocks is the order to emit the Blocks // - the order of b.Values is the order to emit the Values in each Block // - f has a non-nil regAlloc field -func Compile(f *Func) { +func Compile(f *Func, htmlWriter *HTMLWriter) { // TODO: debugging - set flags to control verbosity of compiler, // which phases to dump IR before/after, etc. if f.Log() { @@ -51,8 +51,8 @@ func Compile(f *Func) { stack := make([]byte, 16384) n := runtime.Stack(stack, false) stack = stack[:n] - if f.HTMLWriter != nil { - f.HTMLWriter.flushPhases() + if htmlWriter != nil { + htmlWriter.flushPhases() } f.Fatalf("panic during %s while compiling %s:\n\n%v\n\n%s\n", phaseName, f.Name, err, stack) } @@ -62,7 +62,7 @@ func Compile(f *Func) { if f.Log() { printFunc(f) } - f.HTMLWriter.WritePhase("start", "start") + htmlWriter.WritePhase("start", "start") if BuildDump[f.Name] { f.dumpFile("build") } @@ -101,7 +101,7 @@ func Compile(f *Func) { tEnd := time.Now() // Need something less crude than "Log the whole intermediate result". - if f.Log() || f.HTMLWriter != nil { + if f.Log() || htmlWriter != nil { time := tEnd.Sub(tStart).Nanoseconds() var stats string if logMemStats { @@ -118,7 +118,7 @@ func Compile(f *Func) { f.Logf(" pass %s end %s\n", p.name, stats) printFunc(f) } - f.HTMLWriter.WritePhase(phaseName, fmt.Sprintf("%s %s", phaseName, stats)) + htmlWriter.WritePhase(phaseName, fmt.Sprintf("%s %s", phaseName, stats)) } if p.time || p.mem { // Surround timing information w/ enough context to allow comparisons. @@ -143,9 +143,9 @@ func Compile(f *Func) { } } - if f.HTMLWriter != nil { + if htmlWriter != nil { // Ensure we write any pending phases to the html - f.HTMLWriter.flushPhases() + htmlWriter.flushPhases() } if f.ruleMatches != nil { diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 10304e79009403..f963986cb035e5 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -538,20 +538,6 @@ func (c *Config) buildRecipes(arch string) { func(m, x, y *Value) *Value { return m.Block.NewValue2(m.Pos, OpARM64SUB, m.Type, x, y) }) - // regular shifts - for i := 1; i < 64; i++ { - c := 10 - if i == 1 { - // Prefer x<<1 over x+x. - // Note that we eventually reverse this decision in ARM64latelower.rules, - // but this makes shift combining rules in ARM64.rules simpler. - c-- - } - r(1<%s", f.pass.name, stats)) - f.HTMLWriter.flushPhases() + if f.FatalCleanup != nil { + f.FatalCleanup() } f.fe.Fatalf(f.Entry.Pos, msg, args...) } diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index accb558cdbbfff..7af6386a7e743c 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -804,6 +804,14 @@ func (w *HTMLWriter) WritePhase(phase, title string) { w.prevHash = hash } +// FatalCleanup should be called to do cleanup if the complation is exiting early due to +// a fatal error. +func (w *HTMLWriter) FatalCleanup() { + const stats = "crashed" + w.WritePhase(w.Func.pass.name, fmt.Sprintf("%s %s", w.Func.pass.name, stats)) + w.flushPhases() +} + // flushPhases collects any pending phases and titles, writes them to the html, and resets the pending slices. func (w *HTMLWriter) flushPhases() { phaseLen := len(w.pendingPhases) diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 79c76dd71662e9..5ff3d3202c3bf0 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -51,6 +51,7 @@ type opInfo struct { addrSinkArg1 bool // the address in arg1 does not propagate to the result symEffect SymEffect // effect this op has on symbol in aux scale uint8 // amd64/386 indexed load scale + zeroUpperBits uint8 // the op writes a 64-bit GPR whose upper N bits are always zero (0, 32, 48 or 56); for a tuple op, this holds for every integer result } type inputInfo struct { diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index c0516e67ca3588..17c2a661501503 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -309,6 +309,8 @@ const ( OpAMD64ADDLconst OpAMD64ADDQconstmodify OpAMD64ADDLconstmodify + OpAMD64ADDWconstmodify + OpAMD64ADDBconstmodify OpAMD64SUBQ OpAMD64SUBL OpAMD64SUBQconst @@ -350,18 +352,24 @@ const ( OpAMD64ANDLconst OpAMD64ANDQconstmodify OpAMD64ANDLconstmodify + OpAMD64ANDWconstmodify + OpAMD64ANDBconstmodify OpAMD64ORQ OpAMD64ORL OpAMD64ORQconst OpAMD64ORLconst OpAMD64ORQconstmodify OpAMD64ORLconstmodify + OpAMD64ORWconstmodify + OpAMD64ORBconstmodify OpAMD64XORQ OpAMD64XORL OpAMD64XORQconst OpAMD64XORLconst OpAMD64XORQconstmodify OpAMD64XORLconstmodify + OpAMD64XORWconstmodify + OpAMD64XORBconstmodify OpAMD64CMPQ OpAMD64CMPL OpAMD64CMPW @@ -531,15 +539,27 @@ const ( OpAMD64ADDLconstmodifyidx1 OpAMD64ADDLconstmodifyidx4 OpAMD64ADDLconstmodifyidx8 + OpAMD64ADDWconstmodifyidx1 + OpAMD64ADDWconstmodifyidx2 + OpAMD64ADDBconstmodifyidx1 OpAMD64ANDLconstmodifyidx1 OpAMD64ANDLconstmodifyidx4 OpAMD64ANDLconstmodifyidx8 + OpAMD64ANDWconstmodifyidx1 + OpAMD64ANDWconstmodifyidx2 + OpAMD64ANDBconstmodifyidx1 OpAMD64ORLconstmodifyidx1 OpAMD64ORLconstmodifyidx4 OpAMD64ORLconstmodifyidx8 + OpAMD64ORWconstmodifyidx1 + OpAMD64ORWconstmodifyidx2 + OpAMD64ORBconstmodifyidx1 OpAMD64XORLconstmodifyidx1 OpAMD64XORLconstmodifyidx4 OpAMD64XORLconstmodifyidx8 + OpAMD64XORWconstmodifyidx1 + OpAMD64XORWconstmodifyidx2 + OpAMD64XORBconstmodifyidx1 OpAMD64NEGQ OpAMD64NEGL OpAMD64NOTQ @@ -12845,12 +12865,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDL", - argLen: 2, - commutative: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AADDL, + name: "ADDL", + argLen: 2, + commutative: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -12878,12 +12899,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLconst", - auxType: auxInt32, - argLen: 1, - clobberFlags: true, - earlyOk: true, - asm: x86.AADDL, + name: "ADDLconst", + auxType: auxInt32, + argLen: 1, + clobberFlags: true, + earlyOk: true, + asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -12923,6 +12945,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ADDWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ADDBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "SUBQ", argLen: 2, @@ -12941,12 +12993,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASUBL, + name: "SUBL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASUBL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -12975,13 +13028,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASUBL, + name: "SUBLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASUBL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13010,13 +13064,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AIMULL, + name: "MULL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AIMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13044,12 +13099,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULLconst", - auxType: auxInt32, - argLen: 1, - clobberFlags: true, - earlyOk: true, - asm: x86.AIMUL3L, + name: "MULLconst", + auxType: auxInt32, + argLen: 1, + clobberFlags: true, + earlyOk: true, + asm: x86.AIMUL3L, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13060,11 +13116,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULLU", - argLen: 2, - commutative: true, - clobberFlags: true, - asm: x86.AMULL, + name: "MULLU", + argLen: 2, + commutative: true, + clobberFlags: true, + asm: x86.AMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13113,11 +13170,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "HMULL", - argLen: 2, - clobberFlags: true, - earlyOk: true, - asm: x86.AIMULL, + name: "HMULL", + argLen: 2, + clobberFlags: true, + earlyOk: true, + asm: x86.AIMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13147,11 +13205,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "HMULLU", - argLen: 2, - clobberFlags: true, - earlyOk: true, - asm: x86.AMULL, + name: "HMULLU", + argLen: 2, + clobberFlags: true, + earlyOk: true, + asm: x86.AMULL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13198,11 +13257,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DIVL", - auxType: auxBool, - argLen: 2, - clobberFlags: true, - asm: x86.AIDIVL, + name: "DIVL", + auxType: auxBool, + argLen: 2, + clobberFlags: true, + asm: x86.AIDIVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13248,10 +13308,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DIVLU", - argLen: 2, - clobberFlags: true, - asm: x86.ADIVL, + name: "DIVLU", + argLen: 2, + clobberFlags: true, + asm: x86.ADIVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 1, v2: 0}}, // AX @@ -13280,10 +13341,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NEGLflags", - argLen: 1, - resultInArg0: true, - asm: x86.ANEGL, + name: "NEGLflags", + argLen: 1, + resultInArg0: true, + asm: x86.ANEGL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13311,11 +13373,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLconstflags", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - asm: x86.AADDL, + name: "ADDLconstflags", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13526,13 +13589,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AANDL, + name: "ANDL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13561,13 +13625,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AANDL, + name: "ANDLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13607,6 +13672,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ANDWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ANDBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "ORQ", argLen: 2, @@ -13626,13 +13721,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AORL, + name: "ORL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13661,13 +13757,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AORL, + name: "ORLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13707,6 +13804,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ORWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ORBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "XORQ", argLen: 2, @@ -13726,13 +13853,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORL", - argLen: 2, - commutative: true, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AXORL, + name: "XORL", + argLen: 2, + commutative: true, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AXORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13761,13 +13889,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLconst", - auxType: auxInt32, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AXORL, + name: "XORLconst", + auxType: auxInt32, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AXORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -13807,6 +13936,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "XORWconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORW, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "XORBconstmodify", + auxType: auxSymValAndOff, + argLen: 2, + clobberFlags: true, + faultOnNilArg0: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORB, + reg: regInfo{ + inputs: []inputInfo{ + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "CMPQ", argLen: 2, @@ -14289,12 +14448,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BTCL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ABTCL, + name: "BTCL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ABTCL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14323,12 +14483,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BTRL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ABTRL, + name: "BTRL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ABTRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14357,12 +14518,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BTSL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ABTSL, + name: "BTSL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ABTSL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14620,12 +14782,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHLL, + name: "SHLL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -14654,13 +14817,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHLL, + name: "SHLLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14688,12 +14852,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHRL, + name: "SHRL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -14756,13 +14921,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASHRL, + name: "SHRLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASHRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14824,12 +14990,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASARL, + name: "SARL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASARL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -14892,13 +15059,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ASARL, + name: "SARLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ASARL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -14960,12 +15128,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AROLL, + name: "ROLL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AROLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -15028,12 +15197,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RORL", - argLen: 2, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ARORL, + name: "RORL", + argLen: 2, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ARORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 2, v2: 0}}, // CX @@ -15096,13 +15266,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLLconst", - auxType: auxInt8, - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.AROLL, + name: "ROLLconst", + auxType: auxInt8, + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.AROLL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15156,6 +15327,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15216,6 +15388,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.ASUBL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15236,6 +15409,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15296,6 +15470,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15336,6 +15511,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg1: true, symEffect: SymRead, asm: x86.AXORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15347,15 +15523,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AADDL, - scale: 1, + name: "ADDLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AADDL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15368,15 +15545,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AADDL, - scale: 4, + name: "ADDLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AADDL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15389,15 +15567,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AADDL, - scale: 8, + name: "ADDLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AADDL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15452,15 +15631,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.ASUBL, - scale: 1, + name: "SUBLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.ASUBL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15473,15 +15653,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.ASUBL, - scale: 4, + name: "SUBLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.ASUBL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15494,15 +15675,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.ASUBL, - scale: 8, + name: "SUBLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.ASUBL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15557,15 +15739,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AANDL, - scale: 1, + name: "ANDLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AANDL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15578,15 +15761,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AANDL, - scale: 4, + name: "ANDLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AANDL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15599,15 +15783,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AANDL, - scale: 8, + name: "ANDLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AANDL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15662,15 +15847,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AORL, - scale: 1, + name: "ORLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AORL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15683,15 +15869,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AORL, - scale: 4, + name: "ORLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AORL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15704,15 +15891,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AORL, - scale: 8, + name: "ORLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AORL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15767,15 +15955,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLloadidx1", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AXORL, - scale: 1, + name: "XORLloadidx1", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AXORL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15788,15 +15977,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLloadidx4", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AXORL, - scale: 4, + name: "XORLloadidx4", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AXORL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -15809,15 +15999,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLloadidx8", - auxType: auxSymOff, - argLen: 4, - resultInArg0: true, - clobberFlags: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AXORL, - scale: 8, + name: "XORLloadidx8", + auxType: auxSymOff, + argLen: 4, + resultInArg0: true, + clobberFlags: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AXORL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -16632,6 +16823,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ADDWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ADDWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ADDBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AADDB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "ANDLconstmodifyidx1", auxType: auxSymValAndOff, @@ -16680,6 +16919,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ANDWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ANDWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ANDBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AANDB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "ORLconstmodifyidx1", auxType: auxSymValAndOff, @@ -16728,6 +17015,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "ORWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ORWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "ORBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AORB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "XORLconstmodifyidx1", auxType: auxSymValAndOff, @@ -16776,6 +17111,54 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "XORWconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORW, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "XORWconstmodifyidx2", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORW, + scale: 2, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, + { + name: "XORBconstmodifyidx1", + auxType: auxSymValAndOff, + argLen: 3, + clobberFlags: true, + addrSinkArg0: true, + symEffect: SymRead | SymWrite, + asm: x86.AXORB, + scale: 1, + reg: regInfo{ + inputs: []inputInfo{ + {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 + {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB + }, + }, + }, { name: "NEGQ", argLen: 1, @@ -16793,12 +17176,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NEGL", - argLen: 1, - resultInArg0: true, - clobberFlags: true, - earlyOk: true, - asm: x86.ANEGL, + name: "NEGL", + argLen: 1, + resultInArg0: true, + clobberFlags: true, + earlyOk: true, + asm: x86.ANEGL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -16824,11 +17208,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NOTL", - argLen: 1, - resultInArg0: true, - earlyOk: true, - asm: x86.ANOTL, + name: "NOTL", + argLen: 1, + resultInArg0: true, + earlyOk: true, + asm: x86.ANOTL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17059,11 +17444,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLEQ", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLEQ, + name: "CMOVLEQ", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLEQ, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17075,11 +17461,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLNE", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLNE, + name: "CMOVLNE", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLNE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17091,11 +17478,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLLT", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLLT, + name: "CMOVLLT", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLLT, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17107,11 +17495,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGT", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLGT, + name: "CMOVLGT", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLGT, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17123,11 +17512,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLLE", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLLE, + name: "CMOVLLE", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLLE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17139,11 +17529,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGE", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLGE, + name: "CMOVLGE", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLGE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17155,11 +17546,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLLS", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLLS, + name: "CMOVLLS", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLLS, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17171,11 +17563,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLHI", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLHI, + name: "CMOVLHI", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLHI, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17187,11 +17580,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLCC", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLCC, + name: "CMOVLCC", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLCC, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17203,11 +17597,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLCS", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLCS, + name: "CMOVLCS", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLCS, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17444,12 +17839,13 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLEQF", - argLen: 3, - resultInArg0: true, - needIntTemp: true, - earlyOk: true, - asm: x86.ACMOVLNE, + name: "CMOVLEQF", + argLen: 3, + resultInArg0: true, + needIntTemp: true, + earlyOk: true, + asm: x86.ACMOVLNE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17461,11 +17857,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLNEF", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLNE, + name: "CMOVLNEF", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLNE, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17477,11 +17874,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGTF", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLHI, + name: "CMOVLGTF", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLHI, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17493,11 +17891,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMOVLGEF", - argLen: 3, - resultInArg0: true, - earlyOk: true, - asm: x86.ACMOVLCC, + name: "CMOVLGEF", + argLen: 3, + resultInArg0: true, + earlyOk: true, + asm: x86.ACMOVLCC, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17589,11 +17988,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BSWAPL", - argLen: 1, - resultInArg0: true, - earlyOk: true, - asm: x86.ABSWAPL, + name: "BSWAPL", + argLen: 1, + resultInArg0: true, + earlyOk: true, + asm: x86.ABSWAPL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17604,10 +18004,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "POPCNTQ", - argLen: 1, - clobberFlags: true, - asm: x86.APOPCNTQ, + name: "POPCNTQ", + argLen: 1, + clobberFlags: true, + asm: x86.APOPCNTQ, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17618,10 +18019,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "POPCNTL", - argLen: 1, - clobberFlags: true, - asm: x86.APOPCNTL, + name: "POPCNTL", + argLen: 1, + clobberFlags: true, + asm: x86.APOPCNTL, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -17857,10 +18259,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SBBLcarrymask", - argLen: 1, - earlyOk: true, - asm: x86.ASBBL, + name: "SBBLcarrymask", + argLen: 1, + earlyOk: true, + asm: x86.ASBBL, + zeroUpperBits: 32, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18383,10 +18786,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBQZX", - argLen: 1, - earlyOk: true, - asm: x86.AMOVBLZX, + name: "MOVBQZX", + argLen: 1, + earlyOk: true, + asm: x86.AMOVBLZX, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18411,10 +18815,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWQZX", - argLen: 1, - earlyOk: true, - asm: x86.AMOVWLZX, + name: "MOVWQZX", + argLen: 1, + earlyOk: true, + asm: x86.AMOVWLZX, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18439,10 +18844,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLQZX", - argLen: 1, - earlyOk: true, - asm: x86.AMOVL, + name: "MOVLQZX", + argLen: 1, + earlyOk: true, + asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18459,6 +18865,7 @@ var opcodeTable = [...]opInfo{ rematerializeable: true, earlyOk: true, asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18479,10 +18886,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTTSD2SL", - argLen: 1, - earlyOk: true, - asm: x86.ACVTTSD2SL, + name: "CVTTSD2SL", + argLen: 1, + earlyOk: true, + asm: x86.ACVTTSD2SL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -18507,10 +18915,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CVTTSS2SL", - argLen: 1, - earlyOk: true, - asm: x86.ACVTTSS2SL, + name: "CVTTSS2SL", + argLen: 1, + earlyOk: true, + asm: x86.ACVTTSS2SL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -18658,9 +19067,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLf2i", - argLen: 1, - earlyOk: true, + name: "MOVLf2i", + argLen: 1, + earlyOk: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -18729,6 +19139,7 @@ var opcodeTable = [...]opInfo{ earlyOk: true, symEffect: SymAddr, asm: x86.ALEAL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -18775,14 +19186,15 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL1", - auxType: auxSymOff, - argLen: 2, - commutative: true, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 1, + name: "LEAL1", + auxType: auxSymOff, + argLen: 2, + commutative: true, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18831,13 +19243,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL2", - auxType: auxSymOff, - argLen: 2, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 2, + name: "LEAL2", + auxType: auxSymOff, + argLen: 2, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 2, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18885,13 +19298,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL4", - auxType: auxSymOff, - argLen: 2, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 4, + name: "LEAL4", + auxType: auxSymOff, + argLen: 2, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18939,13 +19353,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAL8", - auxType: auxSymOff, - argLen: 2, - earlyOk: true, - symEffect: SymAddr, - asm: x86.ALEAL, - scale: 8, + name: "LEAL8", + auxType: auxSymOff, + argLen: 2, + earlyOk: true, + symEffect: SymAddr, + asm: x86.ALEAL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -18982,6 +19397,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVBLZX, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -19016,6 +19432,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVWLZX, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -19050,6 +19467,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -19186,15 +19604,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVBLZX, - scale: 1, + name: "MOVBloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVBLZX, + scale: 1, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19206,15 +19625,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVWLZX, - scale: 1, + name: "MOVWloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVWLZX, + scale: 1, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19226,13 +19646,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWloadidx2", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVWLZX, - scale: 2, + name: "MOVWloadidx2", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVWLZX, + scale: 2, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19244,15 +19665,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVL, - scale: 1, + name: "MOVLloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19264,13 +19686,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLloadidx4", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVL, - scale: 4, + name: "MOVLloadidx4", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19282,13 +19705,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLloadidx8", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVL, - scale: 8, + name: "MOVLloadidx8", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19885,6 +20309,7 @@ var opcodeTable = [...]opInfo{ argLen: 0, rematerializeable: true, symEffect: SymNone, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -19980,6 +20405,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, symEffect: SymRead, asm: x86.AMOVL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -20033,6 +20459,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, symEffect: SymRdWr, asm: x86.AXCHGL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20072,6 +20499,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, symEffect: SymRdWr, asm: x86.AXADDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20287,6 +20715,7 @@ var opcodeTable = [...]opInfo{ unsafePoint: true, symEffect: SymRdWr, asm: x86.AANDL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49134, v2: 0}}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20333,6 +20762,7 @@ var opcodeTable = [...]opInfo{ unsafePoint: true, symEffect: SymRdWr, asm: x86.AORL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49134, v2: 0}}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20382,10 +20812,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDNL", - argLen: 2, - clobberFlags: true, - asm: x86.AANDNL, + name: "ANDNL", + argLen: 2, + clobberFlags: true, + asm: x86.AANDNL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20411,10 +20842,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BLSIL", - argLen: 1, - clobberFlags: true, - asm: x86.ABLSIL, + name: "BLSIL", + argLen: 1, + clobberFlags: true, + asm: x86.ABLSIL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20439,10 +20871,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BLSMSKL", - argLen: 1, - clobberFlags: true, - asm: x86.ABLSMSKL, + name: "BLSMSKL", + argLen: 1, + clobberFlags: true, + asm: x86.ABLSMSKL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20467,9 +20900,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "BLSRL", - argLen: 1, - asm: x86.ABLSRL, + name: "BLSRL", + argLen: 1, + asm: x86.ABLSRL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20559,6 +20993,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.AMOVBEL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 72057594037993471, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 g R15 SB @@ -20616,15 +21051,16 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBELloadidx1", - auxType: auxSymOff, - argLen: 3, - commutative: true, - addrSinkArg0: true, - addrSinkArg1: true, - symEffect: SymRead, - asm: x86.AMOVBEL, - scale: 1, + name: "MOVBELloadidx1", + auxType: auxSymOff, + argLen: 3, + commutative: true, + addrSinkArg0: true, + addrSinkArg1: true, + symEffect: SymRead, + asm: x86.AMOVBEL, + scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20636,13 +21072,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBELloadidx4", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVBEL, - scale: 4, + name: "MOVBELloadidx4", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVBEL, + scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20654,13 +21091,14 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBELloadidx8", - auxType: auxSymOff, - argLen: 3, - addrSinkArg0: true, - symEffect: SymRead, - asm: x86.AMOVBEL, - scale: 8, + name: "MOVBELloadidx8", + auxType: auxSymOff, + argLen: 3, + addrSinkArg0: true, + symEffect: SymRead, + asm: x86.AMOVBEL, + scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49151, v2: 0}}, // AX CX DX BX SP BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20842,9 +21280,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARXL", - argLen: 2, - asm: x86.ASARXL, + name: "SARXL", + argLen: 2, + asm: x86.ASARXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20870,9 +21309,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLXL", - argLen: 2, - asm: x86.ASHLXL, + name: "SHLXL", + argLen: 2, + asm: x86.ASHLXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20898,9 +21338,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRXL", - argLen: 2, - asm: x86.ASHRXL, + name: "SHRXL", + argLen: 2, + asm: x86.ASHRXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20919,6 +21360,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.ASARXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20955,6 +21397,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.ASHLXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -20991,6 +21434,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: x86.ASHRXL, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21028,6 +21472,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASARXL, scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21048,6 +21493,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASARXL, scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21068,6 +21514,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASARXL, scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21128,6 +21575,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHLXL, scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21148,6 +21596,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHLXL, scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21168,6 +21617,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHLXL, scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21228,6 +21678,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHRXL, scale: 1, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21248,6 +21699,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHRXL, scale: 4, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21268,6 +21720,7 @@ var opcodeTable = [...]opInfo{ symEffect: SymRead, asm: x86.ASHRXL, scale: 8, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {2, regMask{v1: 49135, v2: 0}}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R15 @@ -21407,9 +21860,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "PMOVMSKB", - argLen: 1, - asm: x86.APMOVMSKB, + name: "PMOVMSKB", + argLen: 1, + asm: x86.APMOVMSKB, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22078,9 +22532,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VPMOVMSKB128", - argLen: 1, - asm: x86.AVPMOVMSKB, + name: "VPMOVMSKB128", + argLen: 1, + asm: x86.AVPMOVMSKB, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22091,9 +22546,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VPMOVMSKB256", - argLen: 1, - asm: x86.AVPMOVMSKB, + name: "VPMOVMSKB256", + argLen: 1, + asm: x86.AVPMOVMSKB, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22104,9 +22560,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPS128", - argLen: 1, - asm: x86.AVMOVMSKPS, + name: "VMOVMSKPS128", + argLen: 1, + asm: x86.AVMOVMSKPS, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22117,9 +22574,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPS256", - argLen: 1, - asm: x86.AVMOVMSKPS, + name: "VMOVMSKPS256", + argLen: 1, + asm: x86.AVMOVMSKPS, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22130,9 +22588,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPD128", - argLen: 1, - asm: x86.AVMOVMSKPD, + name: "VMOVMSKPD128", + argLen: 1, + asm: x86.AVMOVMSKPD, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22143,9 +22602,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "VMOVMSKPD256", - argLen: 1, - asm: x86.AVMOVMSKPD, + name: "VMOVMSKPD256", + argLen: 1, + asm: x86.AVMOVMSKPD, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 2147418112, v2: 0}}, // X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 @@ -22528,9 +22988,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "KMOVDi", - argLen: 1, - asm: x86.AKMOVD, + name: "KMOVDi", + argLen: 1, + asm: x86.AKMOVD, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 71494644084506624, v2: 0}}, // K1 K2 K3 K4 K5 K6 K7 @@ -22541,9 +23002,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "KMOVWi", - argLen: 1, - asm: x86.AKMOVW, + name: "KMOVWi", + argLen: 1, + asm: x86.AKMOVW, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 71494644084506624, v2: 0}}, // K1 K2 K3 K4 K5 K6 K7 @@ -22554,9 +23016,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "KMOVBi", - argLen: 1, - asm: x86.AKMOVB, + name: "KMOVBi", + argLen: 1, + asm: x86.AKMOVB, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 71494644084506624, v2: 0}}, // K1 K2 K3 K4 K5 K6 K7 @@ -74979,10 +75442,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADCzerocarry", - argLen: 1, - earlyOk: true, - asm: arm64.AADC, + name: "ADCzerocarry", + argLen: 1, + earlyOk: true, + asm: arm64.AADC, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -75128,11 +75592,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULW", - argLen: 2, - commutative: true, - earlyOk: true, - asm: arm64.AMULW, + name: "MULW", + argLen: 2, + commutative: true, + earlyOk: true, + asm: arm64.AMULW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75160,11 +75625,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MNEGW", - argLen: 2, - commutative: true, - earlyOk: true, - asm: arm64.AMNEGW, + name: "MNEGW", + argLen: 2, + commutative: true, + earlyOk: true, + asm: arm64.AMNEGW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75270,10 +75736,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DIVW", - argLen: 2, - earlyOk: true, - asm: arm64.ASDIVW, + name: "DIVW", + argLen: 2, + earlyOk: true, + asm: arm64.ASDIVW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75285,10 +75752,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "UDIVW", - argLen: 2, - earlyOk: true, - asm: arm64.AUDIVW, + name: "UDIVW", + argLen: 2, + earlyOk: true, + asm: arm64.AUDIVW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75330,10 +75798,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MODW", - argLen: 2, - earlyOk: true, - asm: arm64.AREMW, + name: "MODW", + argLen: 2, + earlyOk: true, + asm: arm64.AREMW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75345,10 +75814,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "UMODW", - argLen: 2, - earlyOk: true, - asm: arm64.AUREMW, + name: "UMODW", + argLen: 2, + earlyOk: true, + asm: arm64.AUREMW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75865,10 +76335,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "REVW", - argLen: 1, - earlyOk: true, - asm: arm64.AREVW, + name: "REVW", + argLen: 1, + earlyOk: true, + asm: arm64.AREVW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75893,10 +76364,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "REV16W", - argLen: 1, - earlyOk: true, - asm: arm64.AREV16W, + name: "REV16W", + argLen: 1, + earlyOk: true, + asm: arm64.AREV16W, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75921,10 +76393,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RBITW", - argLen: 1, - earlyOk: true, - asm: arm64.ARBITW, + name: "RBITW", + argLen: 1, + earlyOk: true, + asm: arm64.ARBITW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75935,10 +76408,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CLZ", - argLen: 1, - earlyOk: true, - asm: arm64.ACLZ, + name: "CLZ", + argLen: 1, + earlyOk: true, + asm: arm64.ACLZ, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -75949,10 +76423,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CLZW", - argLen: 1, - earlyOk: true, - asm: arm64.ACLZW, + name: "CLZW", + argLen: 1, + earlyOk: true, + asm: arm64.ACLZW, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76165,10 +76640,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MADDW", - argLen: 3, - earlyOk: true, - asm: arm64.AMADDW, + name: "MADDW", + argLen: 3, + earlyOk: true, + asm: arm64.AMADDW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76197,10 +76673,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MSUBW", - argLen: 3, - earlyOk: true, - asm: arm64.AMSUBW, + name: "MSUBW", + argLen: 3, + earlyOk: true, + asm: arm64.AMSUBW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76318,10 +76795,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RORW", - argLen: 2, - earlyOk: true, - asm: arm64.ARORW, + name: "RORW", + argLen: 2, + earlyOk: true, + asm: arm64.ARORW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76348,11 +76826,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "RORWconst", - auxType: auxInt64, - argLen: 1, - earlyOk: true, - asm: arm64.ARORW, + name: "RORWconst", + auxType: auxInt64, + argLen: 1, + earlyOk: true, + asm: arm64.ARORW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -76379,11 +76858,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "EXTRWconst", - auxType: auxInt64, - argLen: 2, - earlyOk: true, - asm: arm64.AEXTRW, + name: "EXTRWconst", + auxType: auxInt64, + argLen: 2, + earlyOk: true, + asm: arm64.AEXTRW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77452,6 +77932,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.AMOVBU, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77486,6 +77967,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77520,6 +78002,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77623,6 +78106,7 @@ var opcodeTable = [...]opInfo{ addrSinkArg0: true, symEffect: SymRead, asm: arm64.ALDPW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -77738,11 +78222,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWUloadidx", - argLen: 3, - addrSinkArg0: true, - addrSinkArg1: true, - asm: arm64.AMOVWU, + name: "MOVWUloadidx", + argLen: 3, + addrSinkArg0: true, + addrSinkArg1: true, + asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77770,11 +78255,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVHUloadidx", - argLen: 3, - addrSinkArg0: true, - addrSinkArg1: true, - asm: arm64.AMOVHU, + name: "MOVHUloadidx", + argLen: 3, + addrSinkArg0: true, + addrSinkArg1: true, + asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77802,11 +78288,12 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBUloadidx", - argLen: 3, - addrSinkArg0: true, - addrSinkArg1: true, - asm: arm64.AMOVBU, + name: "MOVBUloadidx", + argLen: 3, + addrSinkArg0: true, + addrSinkArg1: true, + asm: arm64.AMOVBU, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77865,10 +78352,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVHUloadidx2", - argLen: 3, - addrSinkArg0: true, - asm: arm64.AMOVHU, + name: "MOVHUloadidx2", + argLen: 3, + addrSinkArg0: true, + asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -77895,10 +78383,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWUloadidx4", - argLen: 3, - addrSinkArg0: true, - asm: arm64.AMOVWU, + name: "MOVWUloadidx4", + argLen: 3, + addrSinkArg0: true, + asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78331,10 +78820,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FMOVSfpgp", - argLen: 1, - earlyOk: true, - asm: arm64.AFMOVS, + name: "FMOVSfpgp", + argLen: 1, + earlyOk: true, + asm: arm64.AFMOVS, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78359,10 +78849,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBUreg", - argLen: 1, - earlyOk: true, - asm: arm64.AMOVBU, + name: "MOVBUreg", + argLen: 1, + earlyOk: true, + asm: arm64.AMOVBU, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78387,10 +78878,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVHUreg", - argLen: 1, - earlyOk: true, - asm: arm64.AMOVHU, + name: "MOVHUreg", + argLen: 1, + earlyOk: true, + asm: arm64.AMOVHU, + zeroUpperBits: 48, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78415,10 +78907,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWUreg", - argLen: 1, - earlyOk: true, - asm: arm64.AMOVWU, + name: "MOVWUreg", + argLen: 1, + earlyOk: true, + asm: arm64.AMOVWU, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 402653183, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 @@ -78569,10 +79062,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZSSW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZSSW, + name: "FCVTZSSW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZSSW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78583,10 +79077,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZSDW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZSDW, + name: "FCVTZSDW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZSDW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78597,10 +79092,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZUSW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZUSW, + name: "FCVTZUSW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZUSW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -78611,10 +79107,11 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "FCVTZUDW", - argLen: 1, - earlyOk: true, - asm: arm64.AFCVTZUDW, + name: "FCVTZUDW", + argLen: 1, + earlyOk: true, + asm: arm64.AFCVTZUDW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372034707292160, v2: 0}}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -79124,9 +79621,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "Equal", - argLen: 1, - earlyOk: true, + name: "Equal", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79134,9 +79632,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotEqual", - argLen: 1, - earlyOk: true, + name: "NotEqual", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79144,9 +79643,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThan", - argLen: 1, - earlyOk: true, + name: "LessThan", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79154,9 +79654,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessEqual", - argLen: 1, - earlyOk: true, + name: "LessEqual", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79164,9 +79665,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterThan", - argLen: 1, - earlyOk: true, + name: "GreaterThan", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79174,9 +79676,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqual", - argLen: 1, - earlyOk: true, + name: "GreaterEqual", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79184,9 +79687,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThanU", - argLen: 1, - earlyOk: true, + name: "LessThanU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79194,9 +79698,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessEqualU", - argLen: 1, - earlyOk: true, + name: "LessEqualU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79204,9 +79709,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterThanU", - argLen: 1, - earlyOk: true, + name: "GreaterThanU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79214,9 +79720,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqualU", - argLen: 1, - earlyOk: true, + name: "GreaterEqualU", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79224,9 +79731,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThanF", - argLen: 1, - earlyOk: true, + name: "LessThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79234,9 +79742,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessEqualF", - argLen: 1, - earlyOk: true, + name: "LessEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79244,9 +79753,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterThanF", - argLen: 1, - earlyOk: true, + name: "GreaterThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79254,9 +79764,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqualF", - argLen: 1, - earlyOk: true, + name: "GreaterEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79264,9 +79775,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotLessThanF", - argLen: 1, - earlyOk: true, + name: "NotLessThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79274,9 +79786,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotLessEqualF", - argLen: 1, - earlyOk: true, + name: "NotLessEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79284,9 +79797,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotGreaterThanF", - argLen: 1, - earlyOk: true, + name: "NotGreaterThanF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79294,9 +79808,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "NotGreaterEqualF", - argLen: 1, - earlyOk: true, + name: "NotGreaterEqualF", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79304,9 +79819,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LessThanNoov", - argLen: 1, - earlyOk: true, + name: "LessThanNoov", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79314,9 +79830,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "GreaterEqualNoov", - argLen: 1, - earlyOk: true, + name: "GreaterEqualNoov", + argLen: 1, + earlyOk: true, + zeroUpperBits: 56, reg: regInfo{ outputs: []outputInfo{ {0, regMask{v1: 335544319, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30 @@ -79443,6 +79960,7 @@ var opcodeTable = [...]opInfo{ argLen: 2, faultOnNilArg0: true, asm: arm64.ALDARB, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -79457,6 +79975,7 @@ var opcodeTable = [...]opInfo{ argLen: 2, faultOnNilArg0: true, asm: arm64.ALDARW, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {0, regMask{v1: 9223372038331170815, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB @@ -79529,6 +80048,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79546,6 +80066,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79578,6 +80099,7 @@ var opcodeTable = [...]opInfo{ resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79595,6 +80117,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79679,6 +80202,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79698,6 +80222,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79717,6 +80242,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79736,6 +80262,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79756,6 +80283,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AAND, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79775,6 +80303,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AORR, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79832,6 +80361,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AAND, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79851,6 +80381,7 @@ var opcodeTable = [...]opInfo{ hasSideEffects: true, unsafePoint: true, asm: arm64.AORR, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79868,6 +80399,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79884,6 +80416,7 @@ var opcodeTable = [...]opInfo{ resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, + zeroUpperBits: 56, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79934,6 +80467,7 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, hasSideEffects: true, unsafePoint: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -79950,6 +80484,7 @@ var opcodeTable = [...]opInfo{ resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true, + zeroUpperBits: 32, reg: regInfo{ inputs: []inputInfo{ {1, regMask{v1: 939524095, v2: 0}}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 ZERO @@ -80034,12 +80569,13 @@ var opcodeTable = [...]opInfo{ reg: regInfo{}, }, { - name: "ZERO", - argLen: 0, - zeroWidth: true, - fixedReg: true, - earlyOk: true, - reg: regInfo{}, + name: "ZERO", + argLen: 0, + zeroWidth: true, + fixedReg: true, + earlyOk: true, + zeroUpperBits: 56, + reg: regInfo{}, }, { name: "VMOVI16B", diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 2597106f09aa5f..4245145cefd0c0 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -1384,210 +1384,63 @@ func overlap(offset1, size1, offset2, size2 int64) bool { return false } -// check if value zeroes out upper 32-bit of 64-bit register. +// ZeroUpper32Bits checks if value zeroes out upper 32-bit of 64-bit register. // depth limits recursion depth. In AMD64.rules 3 is used as limit, // because it catches same amount of cases as 4. -func ZeroUpper32Bits(x *Value, depth int) bool { - if x.Type.IsSigned() && x.Type.Size() < 8 { - // If the value is signed, it might get re-sign-extended - // during spill and restore. See issue 68227. - return false - } - switch x.Op { - // Every amd64 op below writes a 32-bit GPR result, which the - // hardware zero-extends into the full 64-bit register, so at the - // point of the write the upper 32 bits are zero. Ops whose result - // is memory, a flags value, or a narrower register do not qualify. - // - // 32-bit constants, zero-extensions and loads. The MOVW/MOVB - // loads assemble to zero-extending MOVWLZX/MOVBLZX. - case OpAMD64MOVLconst, OpAMD64MOVLQZX, - OpAMD64MOVLload, OpAMD64MOVLloadidx1, OpAMD64MOVLloadidx4, OpAMD64MOVLloadidx8, - OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2, - OpAMD64MOVBload, OpAMD64MOVBloadidx1, - // Byte-swapping 32-bit loads (MOVBE), zero-extending like MOVL. - OpAMD64MOVBELload, OpAMD64MOVBELloadidx1, OpAMD64MOVBELloadidx4, OpAMD64MOVBELloadidx8, - // 32-bit arithmetic and logic, register and folded-load forms. - OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst, - OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst, - OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL, - OpAMD64ADDLload, OpAMD64SUBLload, OpAMD64ANDLload, - OpAMD64ORLload, OpAMD64XORLload, - OpAMD64ADDLloadidx1, OpAMD64ADDLloadidx4, OpAMD64ADDLloadidx8, - OpAMD64SUBLloadidx1, OpAMD64SUBLloadidx4, OpAMD64SUBLloadidx8, - OpAMD64ANDLloadidx1, OpAMD64ANDLloadidx4, OpAMD64ANDLloadidx8, - OpAMD64ORLloadidx1, OpAMD64ORLloadidx4, OpAMD64ORLloadidx8, - OpAMD64XORLloadidx1, OpAMD64XORLloadidx4, OpAMD64XORLloadidx8, - // 32-bit shifts and rotates. RORLconst is absent because - // const-amount right rotates are canonicalized to ROLLconst. - OpAMD64SHRL, OpAMD64SHRLconst, OpAMD64SARL, OpAMD64SARLconst, - OpAMD64SHLL, OpAMD64SHLLconst, - OpAMD64ROLL, OpAMD64ROLLconst, OpAMD64RORL, - // BMI2 shifts, which AMD64latelower.rules promotes SHRL/SARL/SHLL - // into at GOAMD64>=3 in the same pass that applies this fold, - // plus their folded-load forms. - OpAMD64SHRXL, OpAMD64SARXL, OpAMD64SHLXL, - OpAMD64SHRXLload, OpAMD64SARXLload, OpAMD64SHLXLload, - OpAMD64SHRXLloadidx1, OpAMD64SHRXLloadidx4, OpAMD64SHRXLloadidx8, - OpAMD64SARXLloadidx1, OpAMD64SARXLloadidx4, OpAMD64SARXLloadidx8, - OpAMD64SHLXLloadidx1, OpAMD64SHLXLloadidx4, OpAMD64SHLXLloadidx8, - // 32-bit address computations and products. - OpAMD64LEAL, OpAMD64LEAL1, OpAMD64LEAL2, OpAMD64LEAL4, OpAMD64LEAL8, - OpAMD64MULL, OpAMD64MULLconst, - // In 64-bit mode a 32-bit CMOV zero-extends its destination - // even when the condition is false. - OpAMD64CMOVLCC, OpAMD64CMOVLCS, OpAMD64CMOVLEQ, OpAMD64CMOVLGE, - OpAMD64CMOVLGT, OpAMD64CMOVLHI, OpAMD64CMOVLLE, OpAMD64CMOVLLS, - OpAMD64CMOVLLT, OpAMD64CMOVLNE, - OpAMD64CMOVLEQF, OpAMD64CMOVLGEF, OpAMD64CMOVLGTF, OpAMD64CMOVLNEF, - // Byte swap, bit counts and BMI1 bit manipulation. - OpAMD64BSWAPL, OpAMD64POPCNTL, - OpAMD64ANDNL, OpAMD64BLSIL, OpAMD64BLSMSKL, - // Register-destination bit set/reset/complement. - OpAMD64BTSL, OpAMD64BTRL, OpAMD64BTCL, - // SBBL x, x: 32-bit result, 0 or -1 depending on the carry flag. - OpAMD64SBBLcarrymask, - // float -> int32 conversions. - OpAMD64CVTTSD2SL, OpAMD64CVTTSS2SL, - // 32-bit move out of an X register (MOVD xmm, r32). - OpAMD64MOVLf2i: - return true - case OpAMD64MOVQconst: - return uint64(uint32(x.AuxInt)) == uint64(x.AuxInt) - // arm64 likewise zero-extends every write to a W register into - // the full X register. - // - // 32-bit bit-twiddling, multiplies, divides and rotates. - case OpARM64REV16W, OpARM64REVW, OpARM64RBITW, OpARM64CLZW, OpARM64EXTRWconst, - OpARM64MULW, OpARM64MNEGW, OpARM64MADDW, OpARM64MSUBW, - OpARM64DIVW, OpARM64UDIVW, OpARM64MODW, OpARM64UMODW, - OpARM64RORW, OpARM64RORWconst, - // The zero-extensions themselves and the zero-extending loads. - // The MOVWload forms sign-extend and are deliberately not here. - OpARM64MOVWUreg, OpARM64MOVWUload, OpARM64MOVWUloadidx, OpARM64MOVWUloadidx4, - OpARM64MOVHUreg, OpARM64MOVHUload, OpARM64MOVHUloadidx, OpARM64MOVHUloadidx2, - OpARM64MOVBUreg, OpARM64MOVBUload, OpARM64MOVBUloadidx, - // float -> 32-bit int conversions. - OpARM64FCVTZSSW, OpARM64FCVTZSDW, OpARM64FCVTZUSW, OpARM64FCVTZUDW: - return true - case OpArg: // note: but not ArgIntReg - // amd64 always loads args from the stack unsigned. - // most other architectures load them sign/zero extended based on the type. - return x.Type.Size() == 4 && x.Block.Func.Config.arch == "amd64" - case OpSelect0, OpSelect1: - // A Select names one register result of a tuple-producing op, so - // the question is what that op's write does; recursing into the - // argument the way the Phi case below does would instead ask - // about the tuple itself, which no case above can answer. - s := x.Args[0].Op - if x.Op == OpSelect0 { - switch s { - case OpAMD64DIVL, OpAMD64DIVLU, // quotient, in a 32-bit GPR - OpAMD64MULLU, // low half of the 32x32 product - OpAMD64NEGLflags, // 32-bit negation - OpAMD64ADDLconstflags, // 32-bit add of a constant - OpAMD64BLSRL, // BMI1 reset-lowest-set-bit - OpAMD64MOVLatomicload, // atomic 32-bit load - OpAMD64XCHGL, // the old memory value, in a 32-bit GPR - OpAMD64XADDLlock, // the pre-add memory value, in a 32-bit GPR - OpARM64LDARW, // 32-bit load-acquire - OpARM64LDPW: // first word of a zero-extending pair load - return true - } - } else { - switch s { - case OpAMD64DIVL, OpAMD64DIVLU, // remainder, in a 32-bit GPR - OpARM64LDPW: // second word of a zero-extending pair load - return true - } - } - return false - case OpPhi: - // Phis can use each-other as an arguments, instead of tracking visited values, - // just limit recursion depth. - if depth <= 0 { - return false - } - for i := range x.Args { - if !ZeroUpper32Bits(x.Args[i], depth-1) { - return false - } - } - return true - - } - return false -} +func ZeroUpper32Bits(x *Value) bool { return zeroUpperBits(x, 32, 3) } // ZeroUpper48Bits is similar to ZeroUpper32Bits, but for upper 48 bits. -func ZeroUpper48Bits(x *Value, depth int) bool { - if x.Type.IsSigned() && x.Type.Size() <= 2 { +func ZeroUpper48Bits(x *Value) bool { return zeroUpperBits(x, 48, 3) } + +// ZeroUpper56Bits is similar to ZeroUpper32Bits, but for upper 56 bits. +func ZeroUpper56Bits(x *Value) bool { return zeroUpperBits(x, 56, 3) } + +// zeroUpperBits reports whether the 64-bit register holding x provably has +// its upper `bits` bits zero, i.e. the value is below 2^(64-bits). +// +// Which ops guarantee this is declared per op in the _gen op definitions +// (the zeroUpperBits attribute); only the value-dependent cases live here. +func zeroUpperBits(x *Value, bits int64, depth int) bool { + if x.Type.IsSigned() && 8*x.Type.Size() <= 64-bits { // A spill/restore sign-extends from the type's width (issue 68227). - // An int8/int16 may have its sign bit set, so a restore can write - // ones into the upper 48 bits. Wider signed types are safe: their - // value is below 2^16, so their sign bit is zero and a restore - // zero-extends. + // A signed type no wider than the claimed value width may have its + // sign bit set, so a restore can write ones into the upper bits. + // Wider signed types are safe: their value is below the type's + // sign bit, so a restore zero-extends. return false } - switch x.Op { - case OpAMD64MOVWQZX, OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVWloadidx2, - OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1: + if int64(opcodeTable[x.Op].zeroUpperBits) >= bits { return true - case OpAMD64MOVQconst, OpAMD64MOVLconst: - return uint64(uint16(x.AuxInt)) == uint64(x.AuxInt) - case OpARM64MOVHUreg, OpARM64MOVHUload, OpARM64MOVHUloadidx, OpARM64MOVHUloadidx2, - OpARM64MOVBUreg, OpARM64MOVBUload, OpARM64MOVBUloadidx: - return true - case OpArg: // note: but not ArgIntReg - return x.Type.Size() == 2 && x.Block.Func.Config.arch == "amd64" - case OpPhi, OpSelect0, OpSelect1: - // Phis can use each-other as an arguments, instead of tracking visited values, - // just limit recursion depth. - if depth <= 0 { - return false - } - for i := range x.Args { - if !ZeroUpper48Bits(x.Args[i], depth-1) { - return false - } - } - return true - - } - return false -} - -// ZeroUpper56Bits is similar to ZeroUpper32Bits, but for upper 56 bits. -func ZeroUpper56Bits(x *Value, depth int) bool { - if x.Type.IsSigned() && x.Type.Size() == 1 { - // As in ZeroUpper48Bits: an int8 may have its sign bit set, so a - // spill/restore can write ones into the upper 56 bits. Wider - // signed types are safe: their value is below 2^8, so their sign - // bit is zero and a restore zero-extends. - return false } switch x.Op { - case OpAMD64MOVBQZX, OpAMD64MOVBload, OpAMD64MOVBloadidx1: - return true case OpAMD64MOVQconst, OpAMD64MOVLconst: - return uint64(uint8(x.AuxInt)) == uint64(x.AuxInt) - case OpARM64MOVBUreg, OpARM64MOVBUload, OpARM64MOVBUloadidx: - return true + // A constant qualifies whenever its value fits the claimed width. + // (MOVLconst always zeroes the upper 32 bits, so for bits==32 it + // is already handled by its zeroUpperBits attribute.) + return uint64(x.AuxInt)>>(64-bits) == 0 case OpArg: // note: but not ArgIntReg - return x.Type.Size() == 1 && x.Block.Func.Config.arch == "amd64" - case OpPhi, OpSelect0, OpSelect1: + // amd64 always loads args from the stack unsigned. + // most other architectures load them sign/zero extended based on the type. + return 8*x.Type.Size() == 64-bits && x.Block.Func.Config.arch == "amd64" + case OpSelect0, OpSelect1: + // A Select names one register result of a tuple-producing op, so + // the question is what that op's write does. The op's attribute + // covers every integer result; a Select of a non-covered result + // (flags, memory) never appears as an operand of the rules that + // ask about upper bits. + return int64(opcodeTable[x.Args[0].Op].zeroUpperBits) >= bits + case OpPhi: // Phis can use each-other as an arguments, instead of tracking visited values, // just limit recursion depth. if depth <= 0 { return false } for i := range x.Args { - if !ZeroUpper56Bits(x.Args[i], depth-1) { + if !zeroUpperBits(x.Args[i], bits, depth-1) { return false } } return true - } return false } diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 8f501c19d28506..da19508fc959f7 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -57,6 +57,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ADCQ(v) case OpAMD64ADCQconst: return rewriteValueAMD64_OpAMD64ADCQconst(v) + case OpAMD64ADDBconstmodify: + return rewriteValueAMD64_OpAMD64ADDBconstmodify(v) case OpAMD64ADDL: return rewriteValueAMD64_OpAMD64ADDL(v) case OpAMD64ADDLconst: @@ -87,6 +89,10 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ADDSS(v) case OpAMD64ADDSSload: return rewriteValueAMD64_OpAMD64ADDSSload(v) + case OpAMD64ADDWconstmodify: + return rewriteValueAMD64_OpAMD64ADDWconstmodify(v) + case OpAMD64ANDBconstmodify: + return rewriteValueAMD64_OpAMD64ANDBconstmodify(v) case OpAMD64ANDL: return rewriteValueAMD64_OpAMD64ANDL(v) case OpAMD64ANDLconst: @@ -111,6 +117,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ANDQload(v) case OpAMD64ANDQmodify: return rewriteValueAMD64_OpAMD64ANDQmodify(v) + case OpAMD64ANDWconstmodify: + return rewriteValueAMD64_OpAMD64ANDWconstmodify(v) case OpAMD64BSFQ: return rewriteValueAMD64_OpAMD64BSFQ(v) case OpAMD64BSWAPL: @@ -379,6 +387,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64NOTL(v) case OpAMD64NOTQ: return rewriteValueAMD64_OpAMD64NOTQ(v) + case OpAMD64ORBconstmodify: + return rewriteValueAMD64_OpAMD64ORBconstmodify(v) case OpAMD64ORL: return rewriteValueAMD64_OpAMD64ORL(v) case OpAMD64ORLconst: @@ -399,6 +409,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64ORQload(v) case OpAMD64ORQmodify: return rewriteValueAMD64_OpAMD64ORQmodify(v) + case OpAMD64ORWconstmodify: + return rewriteValueAMD64_OpAMD64ORWconstmodify(v) case OpAMD64ROLB: return rewriteValueAMD64_OpAMD64ROLB(v) case OpAMD64ROLBconst: @@ -3051,6 +3063,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64XCHGL(v) case OpAMD64XCHGQ: return rewriteValueAMD64_OpAMD64XCHGQ(v) + case OpAMD64XORBconstmodify: + return rewriteValueAMD64_OpAMD64XORBconstmodify(v) case OpAMD64XORL: return rewriteValueAMD64_OpAMD64XORL(v) case OpAMD64XORLconst: @@ -3071,6 +3085,8 @@ func rewriteValueAMD64(v *Value) bool { return rewriteValueAMD64_OpAMD64XORQload(v) case OpAMD64XORQmodify: return rewriteValueAMD64_OpAMD64XORQmodify(v) + case OpAMD64XORWconstmodify: + return rewriteValueAMD64_OpAMD64XORWconstmodify(v) case OpAbsInt16x16: v.Op = OpAMD64VPABSW256 return true @@ -7594,6 +7610,54 @@ func rewriteValueAMD64_OpAMD64ADCQconst(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ADDBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ADDBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ADDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ADDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ADDBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ADDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ADDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ADDL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -9006,6 +9070,102 @@ func rewriteValueAMD64_OpAMD64ADDSSload(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ADDWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ADDWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ADDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ADDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ADDWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ADDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ADDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} +func rewriteValueAMD64_OpAMD64ANDBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ANDBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ANDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ANDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ANDBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ANDBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ANDL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -9828,6 +9988,54 @@ func rewriteValueAMD64_OpAMD64ANDQmodify(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ANDWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ANDWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ANDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ANDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ANDWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ANDWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ANDWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64BSFQ(v *Value) bool { v_0 := v.Args[0] b := v.Block @@ -26026,6 +26234,114 @@ func rewriteValueAMD64_OpAMD64MOVBstore(v *Value) bool { v.AddArg3(base, val, mem) return true } + // match: (MOVBstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ADDBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ADDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ADDBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVBstore [off] {sym} ptr a:(ANDLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ANDBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ANDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ANDBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVBstore [off] {sym} ptr a:(ORLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ORBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ORBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVBstore [off] {sym} ptr a:(XORLconst [c] l:(MOVBload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (XORBconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64XORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVBload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64XORBconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } // match: (MOVBstore [off] {sym} ptr (KMOVBi mask) mem) // result: (KMOVBstore [off] {sym} ptr mask mem) for { @@ -29009,6 +29325,114 @@ func rewriteValueAMD64_OpAMD64MOVWstore(v *Value) bool { v.AddArg3(base, val, mem) return true } + // match: (MOVWstore [off] {sym} ptr a:(ADDLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ADDWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ADDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ADDWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVWstore [off] {sym} ptr a:(ANDLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ANDWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ANDLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ANDWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVWstore [off] {sym} ptr a:(ORLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (ORWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64ORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64ORWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } + // match: (MOVWstore [off] {sym} ptr a:(XORLconst [c] l:(MOVWload [off] {sym} ptr2 mem)) mem) + // cond: isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a) + // result: (XORWconstmodify {sym} [makeValAndOff(int32(c),off)] ptr mem) + for { + off := auxIntToInt32(v.AuxInt) + sym := auxToSym(v.Aux) + ptr := v_0 + a := v_1 + if a.Op != OpAMD64XORLconst { + break + } + c := auxIntToInt32(a.AuxInt) + l := a.Args[0] + if l.Op != OpAMD64MOVWload || auxIntToInt32(l.AuxInt) != off || auxToSym(l.Aux) != sym { + break + } + mem := l.Args[1] + ptr2 := l.Args[0] + if mem != v_2 || !(isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && c == int32(int8(c)) && clobber(l, a)) { + break + } + v.reset(OpAMD64XORWconstmodify) + v.AuxInt = valAndOffToAuxInt(makeValAndOff(int32(c), off)) + v.Aux = symToAux(sym) + v.AddArg2(ptr, mem) + return true + } // match: (MOVWstore [i] {s} p x:(ROLWconst [8] w) mem) // cond: x.Uses == 1 && buildcfg.GOAMD64 >= 3 // result: (MOVBEWstore [i] {s} p w mem) @@ -29634,6 +30058,54 @@ func rewriteValueAMD64_OpAMD64NOTQ(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ORBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ORBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ORL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -30286,6 +30758,54 @@ func rewriteValueAMD64_OpAMD64ORQmodify(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64ORWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (ORWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (ORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64ORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (ORWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (ORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64ORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64ROLB(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -93107,6 +93627,54 @@ func rewriteValueAMD64_OpAMD64XCHGQ(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORBconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (XORBconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (XORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64XORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (XORBconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (XORBconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORBconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAMD64XORL(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] @@ -93847,6 +94415,54 @@ func rewriteValueAMD64_OpAMD64XORQmodify(v *Value) bool { } return false } +func rewriteValueAMD64_OpAMD64XORWconstmodify(v *Value) bool { + v_1 := v.Args[1] + v_0 := v.Args[0] + // match: (XORWconstmodify [valoff1] {sym} (ADDQconst [off2] base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) + // result: (XORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {sym} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym := auxToSym(v.Aux) + if v_0.Op != OpAMD64ADDQconst { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2)) { + break + } + v.reset(OpAMD64XORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(sym) + v.AddArg2(base, mem) + return true + } + // match: (XORWconstmodify [valoff1] {sym1} (LEAQ [off2] {sym2} base) mem) + // cond: ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2) + // result: (XORWconstmodify [ValAndOff(valoff1).addOffset32(off2)] {mergeSym(sym1,sym2)} base mem) + for { + valoff1 := auxIntToValAndOff(v.AuxInt) + sym1 := auxToSym(v.Aux) + if v_0.Op != OpAMD64LEAQ { + break + } + off2 := auxIntToInt32(v_0.AuxInt) + sym2 := auxToSym(v_0.Aux) + base := v_0.Args[0] + mem := v_1 + if !(ValAndOff(valoff1).canAdd32(off2) && canMergeSym(sym1, sym2)) { + break + } + v.reset(OpAMD64XORWconstmodify) + v.AuxInt = valAndOffToAuxInt(ValAndOff(valoff1).addOffset32(off2)) + v.Aux = symToAux(mergeSym(sym1, sym2)) + v.AddArg2(base, mem) + return true + } + return false +} func rewriteValueAMD64_OpAddr(v *Value) bool { v_0 := v.Args[0] // match: (Addr {sym} base) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go b/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go index 531fbe1dd0117f..7ad27924f81236 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64latelower.go @@ -30,11 +30,11 @@ func rewriteValueAMD64latelower(v *Value) bool { func rewriteValueAMD64latelower_OpAMD64MOVBQZX(v *Value) bool { v_0 := v.Args[0] // match: (MOVBQZX x) - // cond: ZeroUpper56Bits(x,3) + // cond: ZeroUpper56Bits(x) // result: x for { x := v_0 - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } v.copyOf(x) @@ -45,11 +45,11 @@ func rewriteValueAMD64latelower_OpAMD64MOVBQZX(v *Value) bool { func rewriteValueAMD64latelower_OpAMD64MOVLQZX(v *Value) bool { v_0 := v.Args[0] // match: (MOVLQZX x) - // cond: ZeroUpper32Bits(x,3) + // cond: ZeroUpper32Bits(x) // result: x for { x := v_0 - if !(ZeroUpper32Bits(x, 3)) { + if !(ZeroUpper32Bits(x)) { break } v.copyOf(x) @@ -60,11 +60,11 @@ func rewriteValueAMD64latelower_OpAMD64MOVLQZX(v *Value) bool { func rewriteValueAMD64latelower_OpAMD64MOVWQZX(v *Value) bool { v_0 := v.Args[0] // match: (MOVWQZX x) - // cond: ZeroUpper48Bits(x,3) + // cond: ZeroUpper48Bits(x) // result: x for { x := v_0 - if !(ZeroUpper48Bits(x, 3)) { + if !(ZeroUpper48Bits(x)) { break } v.copyOf(x) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index a9fea2a0597b26..622ca5c30ecb52 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -25158,7 +25158,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (GE (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -25166,7 +25166,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -25174,7 +25174,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (GE (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -25182,7 +25182,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -26290,7 +26290,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (LT (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -26298,7 +26298,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) @@ -26306,7 +26306,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (LT (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -26314,7 +26314,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) @@ -27484,7 +27484,7 @@ func rewriteBlockARM64(b *Block) bool { } case block.BlockARM64UGE: // match: (UGE (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -27492,7 +27492,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -27500,7 +27500,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (UGE (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBNZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -27508,7 +27508,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBNZ, x) @@ -27674,7 +27674,7 @@ func rewriteBlockARM64(b *Block) bool { } case block.BlockARM64ULT: // match: (ULT (CMPWconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPWconst { v_0 := b.Controls[0] @@ -27682,7 +27682,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) @@ -27690,7 +27690,7 @@ func rewriteBlockARM64(b *Block) bool { return true } // match: (ULT (CMPconst [128] x) yes no) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: (TBZ [7] x yes no) for b.Controls[0].Op == OpARM64CMPconst { v_0 := b.Controls[0] @@ -27698,7 +27698,7 @@ func rewriteBlockARM64(b *Block) bool { break } x := v_0.Args[0] - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } b.resetWithControl(block.BlockARM64TBZ, x) diff --git a/src/cmd/compile/internal/ssa/rewriteARM64latelower.go b/src/cmd/compile/internal/ssa/rewriteARM64latelower.go index 671a7120a2a67c..9c2688785599b9 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64latelower.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64latelower.go @@ -341,11 +341,11 @@ func rewriteValueARM64latelower_OpARM64MOVBUreg(v *Value) bool { return true } // match: (MOVBUreg x) - // cond: ZeroUpper56Bits(x, 3) + // cond: ZeroUpper56Bits(x) // result: x for { x := v_0 - if !(ZeroUpper56Bits(x, 3)) { + if !(ZeroUpper56Bits(x)) { break } v.copyOf(x) @@ -469,11 +469,11 @@ func rewriteValueARM64latelower_OpARM64MOVDreg(v *Value) bool { func rewriteValueARM64latelower_OpARM64MOVHUreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVHUreg x) - // cond: ZeroUpper48Bits(x, 3) + // cond: ZeroUpper48Bits(x) // result: x for { x := v_0 - if !(ZeroUpper48Bits(x, 3)) { + if !(ZeroUpper48Bits(x)) { break } v.copyOf(x) @@ -675,11 +675,11 @@ func rewriteValueARM64latelower_OpARM64MOVHreg(v *Value) bool { func rewriteValueARM64latelower_OpARM64MOVWUreg(v *Value) bool { v_0 := v.Args[0] // match: (MOVWUreg x) - // cond: ZeroUpper32Bits(x, 3) + // cond: ZeroUpper32Bits(x) // result: x for { x := v_0 - if !(ZeroUpper32Bits(x, 3)) { + if !(ZeroUpper32Bits(x)) { break } v.copyOf(x) diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 06c2f6720ff7ff..08c6cd8a638185 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -43,7 +43,7 @@ func makeConstShiftFunc(c *Conf, amount int64, op Op, typ *types.Type) fun { Valu("shift", op, typ, 0, nil, "load", "c"), Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "shift", "mem"), Exit("store"))) - Compile(fun.f) + runPasses(fun.f) return fun } @@ -102,6 +102,19 @@ func makeShiftExtensionFunc(c *Conf, amount int64, lshift, rshift Op, typ *types Valu("rshift", rshift, typ, 0, nil, "lshift", "c"), Valu("store", OpStore, types.TypeMem, 0, c.config.Types.UInt64, "resptr", "rshift", "mem"), Exit("store"))) - Compile(fun.f) + runPasses(fun.f) return fun } + +// runPasses is a simplified version of Compile that runs the passes +// for the tests in this file. +func runPasses(f *Func) { + for i := range passes { + p := &passes[i] + if !f.Config.optimize && !p.required || p.disabled { + continue + } + f.pass = p + p.fn(f) + } +} diff --git a/src/cmd/compile/internal/ssagen/pgen.go b/src/cmd/compile/internal/ssagen/pgen.go index 0a2010363f8d04..58401927dd1c0f 100644 --- a/src/cmd/compile/internal/ssagen/pgen.go +++ b/src/cmd/compile/internal/ssagen/pgen.go @@ -301,7 +301,7 @@ const maxStackSize = 1 << 30 // and flushes that plist to machine code. // worker indicates which of the backend workers is doing the processing. func Compile(fn *ir.Func, worker int, profile *pgoir.Profile) { - f := buildssa(fn, worker, inline.IsPgoHotFunc(fn, profile) || inline.HasPgoHotInline(fn)) + f, htmlWriter := buildssa(fn, worker, inline.IsPgoHotFunc(fn, profile) || inline.HasPgoHotInline(fn)) // Note: check arg size to fix issue 25507. if f.Frontend().(*ssafn).stksize >= maxStackSize || f.OwnAux.ArgWidth() >= maxStackSize { largeStackFramesMu.Lock() @@ -311,7 +311,7 @@ func Compile(fn *ir.Func, worker int, profile *pgoir.Profile) { } pp := objw.NewProgs(fn, worker) defer pp.Free() - genssa(f, pp) + genssa(htmlWriter, f, pp) // Check frame size again. // The check above included only the space needed for local variables. // After genssa, the space needed includes local variables and the callee arg region. diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index f08c15f5317e0d..b6a9ed53d381d9 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -295,7 +295,7 @@ func (s *state) emitOpenDeferInfo() { // buildssa builds an SSA function for fn. // worker indicates which of the backend workers is doing the processing. -func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { +func buildssa(fn *ir.Func, worker int, isPgoHot bool) (*ssa.Func, *ssa.HTMLWriter) { name := ir.FuncName(fn) abiSelf := abiForFunc(fn, ssaConfig.ABI0, ssaConfig.ABI1) @@ -378,6 +378,7 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { s.f.Entry = s.f.NewBlock(block.BlockPlain) s.f.Entry.Pos = fn.Pos() s.f.IsPgoHot = isPgoHot + var htmlWriter *ssa.HTMLWriter if printssa { ssaDF := ssaDumpFile @@ -386,10 +387,11 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { ssaD := filepath.Dir(ssaDF) os.MkdirAll(ssaD, 0755) } - s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG) + htmlWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG) // TODO: generate and print a mapping from nodes to values and blocks - dumpSourcesColumn(s.f.HTMLWriter, fn) - s.f.HTMLWriter.WriteAST("AST", astBuf) + dumpSourcesColumn(htmlWriter, fn) + htmlWriter.WriteAST("AST", astBuf) + s.f.FatalCleanup = htmlWriter.FatalCleanup } // Allocate starting values @@ -589,12 +591,12 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { } } - s.f.HTMLWriter.WritePhase("before insert phis", "before insert phis") + htmlWriter.WritePhase("before insert phis", "before insert phis") s.insertPhis() // Main call to ssa package to compile function - ssa.Compile(s.f) + ssa.Compile(s.f, htmlWriter) fe.AllocFrame(s.f) @@ -620,7 +622,7 @@ func buildssa(fn *ir.Func, worker int, isPgoHot bool) *ssa.Func { } } - return s.f + return s.f, htmlWriter } func (s *state) storeParameterRegsToStack(abi *abi.ABIConfig, paramAssignment *abi.ABIParamAssignment, n *ir.Name, addr *ssa.Value, pointersOnly bool) { @@ -6981,7 +6983,7 @@ func emitWrappedFuncInfo(e *ssafn, pp *objw.Progs) { } // genssa appends entries to pp for each instruction in f. -func genssa(f *ssa.Func, pp *objw.Progs) { +func genssa(htmlWriter *ssa.HTMLWriter, f *ssa.Func, pp *objw.Progs) { var s State s.ABI = f.OwnAux.Fn.ABI() @@ -7433,7 +7435,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) { f.Logf(" %-6s\t%.5d (%s)\t%s\n", s, p.Pc, p.InnermostLineNumber(), p.InstructionString()) } } - if f.HTMLWriter != nil { // spew to ssa.html + if htmlWriter != nil { // spew to ssa.html var buf strings.Builder buf.WriteString("") buf.WriteString("
") @@ -7482,7 +7484,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) { } buf.WriteString("
") buf.WriteString("
") - f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String()) + htmlWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String()) } if ssa.GenssaDump[f.Name] { fi := f.DumpFileForPhase("genssa") @@ -7533,8 +7535,8 @@ func genssa(f *ssa.Func, pp *objw.Progs) { } } - f.HTMLWriter.Close() - f.HTMLWriter = nil + htmlWriter.Close() + htmlWriter = nil } func defframe(s *State, e *ssafn, f *ssa.Func) { diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 6c1e51e1a3e0a8..70616305f0defa 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -2443,6 +2443,9 @@ func (p *Package) setBuildInfo(ctx context.Context, f *modfetch.Fetcher, autoVCS if buildmode == "default" { if p.Name == "main" { buildmode = "exe" + if platform.DefaultPIE(cfg.Goos, cfg.Goarch, cfg.BuildRace) { + buildmode = "pie" + } } else { buildmode = "archive" } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index db3b7bfc87efb3..41d1673dec9372 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -1669,7 +1669,10 @@ func (b *Builder) linkActionID(a *Action) cache.ActionID { // Toolchain-independent configuration. fmt.Fprintf(h, "link\n") - fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", cfg.BuildBuildmode, cfg.Goos, cfg.Goarch) + // Hash the resolved buildmode (ldBuildmode), not cfg.BuildBuildmode, + // so that -buildmode=default produces the same build ID as the + // buildmode it resolves to. See go.dev/issue/63559. + fmt.Fprintf(h, "buildmode %s goos %s goarch %s\n", ldBuildmode, cfg.Goos, cfg.Goarch) fmt.Fprintf(h, "import %q\n", p.ImportPath) fmt.Fprintf(h, "omitdebug %v standard %v local %v prefix %q\n", p.Internal.OmitDebug, p.Standard, p.Internal.Local, p.Internal.LocalPrefix) fmt.Fprintf(h, "defaultgodebug %q\n", p.DefaultGODEBUG) diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go index be3f1a25336bef..1398f123c92672 100644 --- a/src/cmd/go/internal/work/security.go +++ b/src/cmd/go/internal/work/security.go @@ -260,7 +260,7 @@ var validPkgConfigFlags = []*lazyregexp.Regexp{ re(`--cflags-only-I`), re(`--cflags`), re(`--define-prefix`), - re(`--define-variable=[A-Za-z_][A-Za-z0-9_]*=[^@\-]*`), + re(`--define-variable=[A-Za-z_][A-Za-z0-9_]*=[^@\-].*`), re(`--digraph`), re(`--dont-define-prefix`), re(`--dont-relocate-paths`), diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go index 68f0ea3770fe56..0b8219b5dc74f5 100644 --- a/src/cmd/go/internal/work/security_test.go +++ b/src/cmd/go/internal/work/security_test.go @@ -308,6 +308,33 @@ func TestCheckLinkerFlags(t *testing.T) { } } +func TestCheckPkgConfigFlags(t *testing.T) { + good := [][]string{ + {"--define-variable=A=b-c"}, + {"--define-variable=A=b@c"}, + {"--define-variable=prefix=/opt/my-pkg/lib"}, + } + for _, f := range good { + if err := checkPkgConfigFlags("test", "test", f); err != nil { + t.Errorf("unexpected error for %q: %v", f, err) + } + } + + bad := [][]string{ + {"--define-variable=A=-b"}, + {"--define-variable=A=@b"}, + {"--define-variable=A="}, + {"--define-variable=1A=b"}, + {"--define-variable=A"}, + {"--log-file=/tmp/log"}, + } + for _, f := range bad { + if err := checkPkgConfigFlags("test", "test", f); err == nil { + t.Errorf("missing error for %q", f) + } + } +} + func TestCheckFlagAllowDisallow(t *testing.T) { if err := checkCompilerFlags("TEST", "test", []string{"-disallow"}); err == nil { t.Fatalf("missing error for -disallow") diff --git a/src/cmd/go/scriptconds_test.go b/src/cmd/go/scriptconds_test.go index 25053dd1da562b..277352ddaf921f 100644 --- a/src/cmd/go/scriptconds_test.go +++ b/src/cmd/go/scriptconds_test.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "internal/buildcfg" + "internal/platform" "os" "os/exec" "path/filepath" @@ -45,6 +46,7 @@ func scriptConditions(t *testing.T) map[string]script.Cond { add("git-sha256", script.OnceCondition("the local 'git' version is recent enough to support sha256 object/commit hashes", gitSupportsSHA256)) add("trimpath", script.OnceCondition("test binary was built with -trimpath", isTrimpath)) add("default-cgo", lazyBool("when CGO_ENABLED=1|0 was set in make.bash", defaultCgo)) + add("default-pie", script.Condition("-buildmode=default resolves to -buildmode=pie", defaultPIE)) return conds } @@ -149,3 +151,14 @@ func gitSupportsSHA256() (bool, error) { func defaultCgo() bool { return buildcfg.DefaultCGO_ENABLED == "1" || buildcfg.DefaultCGO_ENABLED == "0" } + +// defaultPIE reports whether -buildmode=default resolves to -buildmode=pie for +// the script's GOOS/GOARCH. It assumes -race is not in effect, which is the only +// case where the resolved default buildmode depends on the race flag (PIE is not +// the default with -race on windows). Scripts that build with -race must not rely +// on this condition. +func defaultPIE(s *script.State) (bool, error) { + GOOS, _ := s.LookupEnv("GOOS") + GOARCH, _ := s.LookupEnv("GOARCH") + return platform.DefaultPIE(GOOS, GOARCH, false), nil +} diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index 71052159b6e4f5..cd0484243fdeed 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -391,6 +391,8 @@ The available conditions are: cmd/go GOOS/GOARCH != GOHOSTOS/GOHOSTARCH [default-cgo] when CGO_ENABLED=1|0 was set in make.bash +[default-pie] + -buildmode=default resolves to -buildmode=pie [exec:*] names an executable in the test binary's PATH [fuzz] diff --git a/src/cmd/go/testdata/script/build_buildmode_default_reproducible.txt b/src/cmd/go/testdata/script/build_buildmode_default_reproducible.txt new file mode 100644 index 00000000000000..a841e5c45b47e4 --- /dev/null +++ b/src/cmd/go/testdata/script/build_buildmode_default_reproducible.txt @@ -0,0 +1,37 @@ +# Issue 63559: building with -buildmode=default should produce +# a binary identical to one built with the buildmode that default +# resolves to, and the build info stamped into the binary should +# record the resolved buildmode. + +[short] skip 'links binaries' +# gccgo does not set -fPIE for the default->pie case (unlike explicit +# -buildmode=pie), so the two binaries would not be identical there. +[compiler:gccgo] skip + +# Build with -buildmode=default and, separately, with the buildmode that +# default resolves to. Use distinct build caches so that the second build +# cannot be served from the first build's link cache: the binaries must be +# byte-identical because they are truly reproducible, not because one was +# copied from the other. +env GOCACHE=$WORK/cache-default +go build -buildmode=default -o default$GOEXE . + +env GOCACHE=$WORK/cache-explicit +[!default-pie] go build -buildmode=exe -o explicit$GOEXE . +[default-pie] go build -buildmode=pie -o explicit$GOEXE . + +cmp -q default$GOEXE explicit$GOEXE + +# The build info must record the resolved buildmode, not the literal "default". +go version -m default$GOEXE +[!default-pie] stdout -buildmode=exe +[default-pie] stdout -buildmode=pie + +-- go.mod -- +module m + +go 1.26 +-- main.go -- +package main + +func main() {} diff --git a/src/cmd/go/testdata/script/cgo_pkgconfig_define_variable.txt b/src/cmd/go/testdata/script/cgo_pkgconfig_define_variable.txt new file mode 100644 index 00000000000000..89a400b0bf9fa7 --- /dev/null +++ b/src/cmd/go/testdata/script/cgo_pkgconfig_define_variable.txt @@ -0,0 +1,33 @@ +[!cgo] skip +[short] skip + +go build -o $WORK/pkg-config$GOEXE ./pkgconfig +env PKG_CONFIG=$WORK/pkg-config$GOEXE +go build ./p + +-- go.mod -- +module example + +go 1.27 +-- pkgconfig/main.go -- +package main + +import ( + "fmt" + "os" +) + +func main() { + for _, arg := range os.Args { + if arg == "--define-variable=A=b-c" { + return + } + } + fmt.Fprintln(os.Stderr, "missing --define-variable argument") + os.Exit(1) +} +-- p/p.go -- +package p + +// #cgo pkg-config: --define-variable=A=b-c example +import "C" diff --git a/src/cmd/go/testdata/script/version.txt b/src/cmd/go/testdata/script/version.txt index 722859f25867e7..5958dca930de83 100644 --- a/src/cmd/go/testdata/script/version.txt +++ b/src/cmd/go/testdata/script/version.txt @@ -47,14 +47,16 @@ go build -o fortune.exe rsc.io/fortune go version fortune.exe stdout '^fortune.exe: .+' go version -m fortune.exe -stdout -buildmode=exe +[!default-pie] stdout -buildmode=exe +[default-pie] stdout -buildmode=pie stdout '^\tpath\trsc.io/fortune' stdout '^\tmod\trsc.io/fortune\tv1.0.0' # Check the build info of a binary built from $GOROOT/src/cmd go build -o test2json.exe cmd/test2json go version -m test2json.exe -stdout -buildmode=exe +[!default-pie] stdout -buildmode=exe +[default-pie] stdout -buildmode=pie stdout '^test2json.exe: .+' stdout '^\tpath\tcmd/test2json$' ! stdout 'mod[^e]' diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go index fcd9d8c8d57ecd..f7e58e8dfc2f5c 100644 --- a/src/compress/flate/deflate.go +++ b/src/compress/flate/deflate.go @@ -250,6 +250,7 @@ func (d *compressor) fillWindow(b []byte) { // Update window information. d.windowEnd += n s.index = n + d.blockStart = d.windowEnd } // findMatch finds the longest match starting at pos in the hash chain starting diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go index 47ef8f0da087d3..073c63a5eef550 100644 --- a/src/compress/flate/deflate_test.go +++ b/src/compress/flate/deflate_test.go @@ -494,6 +494,40 @@ func TestWriterDict(t *testing.T) { } } +// TestNonCompressedBlockDoesntLeakDict checks that the dictionary isn't sent when +// sending a non-compressed block. See https://go.dev/issue/80538 +func TestNonCompressedBlockDoesntLeakDict(t *testing.T) { + data := make([]byte, 763) + rand.New(rand.NewSource(42)).Read(data) + dict := []byte("0123456789abcdefghij") + for l := range BestCompression + 1 { + t.Run(fmt.Sprintf("level=%d", l), func(t *testing.T) { + var b bytes.Buffer + w, err := NewWriterDict(&b, l, dict) + if err != nil { + t.Fatalf("NewWriterDict: %v", err) + } + if _, err := w.Write(data); err != nil { + t.Fatalf("Write: %v", err) + } + if err := w.Close(); err != nil { + t.Fatalf("Close: %v", err) + } + got, err := io.ReadAll(NewReaderDict(&b, dict)) + if err != nil { + t.Fatalf("NewReaderDict: %v", err) + } + if !bytes.Equal(got, data) { + t.Errorf("round trip mismatch: got %d bytes, want %d (dictionary emitted: %v)", + len(got), len(data), bytes.HasPrefix(got, dict)) + } + if b.Len() != 0 { + t.Errorf("compressed stream not fully consumed: %d bytes left", b.Len()) + } + }) + } +} + // See https://golang.org/issue/2508 func TestRegression2508(t *testing.T) { if testing.Short() { diff --git a/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod b/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod index d7c20ce6f6d307..f5d0b8da2d315b 100644 --- a/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod +++ b/src/crypto/internal/cryptotest/wycheproof/_schema/go.mod @@ -3,7 +3,7 @@ module crypto/internal/cryptotest/wycheproof/_schema go 1.26.4 require ( - github.com/atombender/go-jsonschema v0.23.1 + github.com/atombender/go-jsonschema v0.24.1 github.com/c2sp/wycheproof v0.0.0-20260625212325-ee7b4f7e6119 ) @@ -15,5 +15,3 @@ require ( github.com/sanity-io/litter v1.5.8 // indirect github.com/sosodev/duration v1.4.0 // indirect ) - -replace github.com/atombender/go-jsonschema => github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31 diff --git a/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum b/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum index 5ad2f74b721e16..386610162f409b 100644 --- a/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum +++ b/src/crypto/internal/cryptotest/wycheproof/_schema/go.sum @@ -1,12 +1,12 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/atombender/go-jsonschema v0.24.1 h1:Vb2JHFA0AxtMl8F1ecrpMQ3uQ2Cxm0HgpX1ZyInY0Lc= +github.com/atombender/go-jsonschema v0.24.1/go.mod h1:yYMQVvK3WlxXJIpciA84rKg/xf2VCxIsxNt9I7Ugvmw= github.com/c2sp/wycheproof v0.0.0-20260625212325-ee7b4f7e6119 h1:jOCu6erj86P93+eFn8Qxp6XLwftn1nW0C9RUx7xZwZg= github.com/c2sp/wycheproof v0.0.0-20260625212325-ee7b4f7e6119/go.mod h1:/5JsOpi3fKmnnig5BQ2mz49TNtnrD308VfTVHcbr5x4= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31 h1:c2W1mlsq9K/W+GPQWycHmGxTq4/RkWgDHOY99K+rtaw= -github.com/filippo-claude/go-jsonschema v0.23.2-0.20260625215234-f867483bec31/go.mod h1:4SrgNrwGKijxhewvpPQ8HKEbin5Q2N4Tk+pFKW77HEk= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= diff --git a/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod b/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod index bfb3d5ce6bca92..e67e1c6e4d85a2 100644 --- a/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod +++ b/src/crypto/internal/cryptotest/x509limbo/_schema/go.mod @@ -2,7 +2,7 @@ module crypto/internal/cryptotest/x509limbo/_schema go 1.26 -require github.com/atombender/go-jsonschema v0.23.1 +require github.com/atombender/go-jsonschema v0.24.1 require ( dario.cat/mergo v1.0.2 // indirect diff --git a/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum b/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum index fef1f2b29fb0b3..5c491c89cd3ada 100644 --- a/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum +++ b/src/crypto/internal/cryptotest/x509limbo/_schema/go.sum @@ -1,7 +1,7 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= -github.com/atombender/go-jsonschema v0.23.1 h1:hpj94ehS+gpVvd1NJSTE0BMtWIpab06ObCz57rwo37c= -github.com/atombender/go-jsonschema v0.23.1/go.mod h1:4SrgNrwGKijxhewvpPQ8HKEbin5Q2N4Tk+pFKW77HEk= +github.com/atombender/go-jsonschema v0.24.1 h1:Vb2JHFA0AxtMl8F1ecrpMQ3uQ2Cxm0HgpX1ZyInY0Lc= +github.com/atombender/go-jsonschema v0.24.1/go.mod h1:yYMQVvK3WlxXJIpciA84rKg/xf2VCxIsxNt9I7Ugvmw= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/src/crypto/internal/cryptotest/x509limbo/schema.go b/src/crypto/internal/cryptotest/x509limbo/schema.go index 2b0a1c440b0b06..28958061138ba9 100644 --- a/src/crypto/internal/cryptotest/x509limbo/schema.go +++ b/src/crypto/internal/cryptotest/x509limbo/schema.go @@ -462,7 +462,7 @@ type Testcase struct { ValidationKind ValidationKind `json:"validation_kind"` // The time at which to perform the validation - ValidationTime interface{} `json:"validation_time,omitempty,omitzero"` + ValidationTime *time.Time `json:"validation_time,omitempty,omitzero"` } // For server (i.e. client-side) validation: the expected peer name, if any @@ -501,8 +501,6 @@ type TestcaseMaxChainDepth_0 *int type TestcasePeerCertificateKey_0 *string -type TestcaseValidationTime_0 *time.Time - // UnmarshalJSON implements json.Unmarshaler. func (j *Testcase) UnmarshalJSON(value []byte) error { var raw map[string]interface{} diff --git a/src/crypto/tls/fips140_test.go b/src/crypto/tls/fips140_test.go index c3f6ec917b5632..571fe896e1d408 100644 --- a/src/crypto/tls/fips140_test.go +++ b/src/crypto/tls/fips140_test.go @@ -570,6 +570,58 @@ func TestFIPSCertAlgs(t *testing.T) { } } +func TestFIPSCertificateWithoutVerification(t *testing.T) { + badCert := fipsCert(t, "L", fipsRSAKey(t, 1024), nil, fipsCertLeaf) + + serverCert := func(t *testing.T, version uint16) (clientErr, serverErr error) { + clientConfig := testConfigFIPS140.Clone() + clientConfig.InsecureSkipVerify = true + clientConfig.MinVersion = version + clientConfig.MaxVersion = version + serverConfig := testConfigFIPS140.Clone() + serverConfig.Certificates = []Certificate{{Certificate: [][]byte{badCert.der}, PrivateKey: badCert.key}} + serverConfig.MinVersion = version + serverConfig.MaxVersion = version + return fipsHandshake(t, clientConfig, serverConfig) + } + + clientCert := func(t *testing.T, version uint16) (clientErr, serverErr error) { + clientConfig := testConfigFIPS140.Clone() + clientConfig.InsecureSkipVerify = true + clientConfig.Certificates = []Certificate{{Certificate: [][]byte{badCert.der}, PrivateKey: badCert.key}} + clientConfig.MinVersion = version + clientConfig.MaxVersion = version + serverConfig := testConfigFIPS140.Clone() + serverConfig.ClientAuth = RequireAnyClientCert + serverConfig.MinVersion = version + serverConfig.MaxVersion = version + return fipsHandshake(t, clientConfig, serverConfig) + } + + for _, version := range []uint16{VersionTLS12, VersionTLS13} { + t.Run(VersionName(version), func(t *testing.T) { + runWithFIPSDisabled(t, func(t *testing.T) { + if clientErr, serverErr := serverCert(t, version); clientErr != nil { + t.Errorf("server cert: expected success; client error: %v; server error: %v", clientErr, serverErr) + } + if clientErr, serverErr := clientCert(t, version); serverErr != nil { + t.Errorf("client cert: expected success; client error: %v; server error: %v", clientErr, serverErr) + } + }) + + runWithFIPSEnabled(t, func(t *testing.T) { + const want = "not allowed in FIPS 140-3 mode" + if clientErr, _ := serverCert(t, version); clientErr == nil || !strings.Contains(clientErr.Error(), want) { + t.Errorf("server cert: got client error %v, want error containing %q", clientErr, want) + } + if _, serverErr := clientCert(t, version); serverErr == nil || !strings.Contains(serverErr.Error(), want) { + t.Errorf("client cert: got server error %v, want error containing %q", serverErr, want) + } + }) + }) + } +} + const ( fipsCertCA = iota fipsCertLeaf diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go index 74389458f5b214..8bdef57bb42463 100644 --- a/src/crypto/tls/handshake_client.go +++ b/src/crypto/tls/handshake_client.go @@ -1174,6 +1174,12 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error { } } + if fips140tls.Required() && !isCertificateAllowedFIPS(certs[0]) { + c.sendAlert(alertBadCertificate) + err := errors.New("server's certificate is not allowed in FIPS 140-3 mode") + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + switch certs[0].PublicKey.(type) { case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: case *mldsa.PublicKey: diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go index a05d6c896bf02f..3991f212c1f8a1 100644 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@ -1003,6 +1003,12 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error { c.scts = certificate.SignedCertificateTimestamps if len(certs) > 0 { + if fips140tls.Required() && !isCertificateAllowedFIPS(certs[0]) { + c.sendAlert(alertBadCertificate) + err := errors.New("client's certificate is not allowed in FIPS 140-3 mode") + return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err} + } + switch certs[0].PublicKey.(type) { case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey: case *mldsa.PublicKey: diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go index 4a1416e314d811..34bc6006c8a4b5 100644 --- a/src/crypto/x509/parser.go +++ b/src/crypto/x509/parser.go @@ -11,6 +11,7 @@ import ( "crypto/ecdsa" "crypto/ed25519" "crypto/mldsa" + "crypto/mlkem" "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" @@ -379,6 +380,19 @@ func parsePublicKey(keyData *publicKeyInfo) (any, error) { return nil, errors.New("x509: X25519 key encoded with illegal parameters") } return ecdh.X25519().NewPublicKey(data) + case oid.Equal(oidPublicKeyMLKEM768): + // RFC 9935, Section 3 + // > The parameters field of the AlgorithmIdentifier for the ML-KEM + // > public key MUST be absent. + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: ML-KEM-768 key encoded with illegal parameters") + } + return mlkem.NewEncapsulationKey768(data) + case oid.Equal(oidPublicKeyMLKEM1024): + if len(params.FullBytes) != 0 { + return nil, errors.New("x509: ML-KEM-1024 key encoded with illegal parameters") + } + return mlkem.NewEncapsulationKey1024(data) case oid.Equal(oidPublicKeyDSA): der := cryptobyte.String(data) y := new(big.Int) diff --git a/src/crypto/x509/pkcs8.go b/src/crypto/x509/pkcs8.go index 1c2f2172bb2cf7..808b33184c34bf 100644 --- a/src/crypto/x509/pkcs8.go +++ b/src/crypto/x509/pkcs8.go @@ -9,6 +9,7 @@ import ( "crypto/ecdsa" "crypto/ed25519" "crypto/mldsa" + "crypto/mlkem" "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" @@ -28,9 +29,10 @@ type pkcs8 struct { // ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form. // -// It returns a *[rsa.PrivateKey], an *[ecdsa.PrivateKey], an [ed25519.PrivateKey] (not -// a pointer), a *[mldsa.PrivateKey], or an *[ecdh.PrivateKey] (for X25519). -// More types might be supported in the future. +// It returns a *[rsa.PrivateKey], an *[ecdsa.PrivateKey], an [ed25519.PrivateKey] +// (not a pointer), a *[mldsa.PrivateKey], an *[ecdh.PrivateKey] (for X25519), a +// *[mlkem.DecapsulationKey768], or a *[mlkem.DecapsulationKey1024]. More types +// might be supported in the future. // // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". // @@ -120,6 +122,41 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) { } return ecdh.X25519().NewPrivateKey(curvePrivateKey) + case privKey.Algo.Algorithm.Equal(oidPublicKeyMLKEM768), + privKey.Algo.Algorithm.Equal(oidPublicKeyMLKEM1024): + // RFC 9935, Section 3 + // > The parameters field of the AlgorithmIdentifier for the ML-KEM + // > public key MUST be absent. + if l := len(privKey.Algo.Parameters.FullBytes); l != 0 { + return nil, errors.New("x509: invalid ML-KEM private key parameters") + } + // RFC 9935, Section 6 defines a CHOICE between a seed (IMPLICIT [0] + // OCTET STRING), an expandedKey (OCTET STRING), and a SEQUENCE + // containing both. Only the seed-only format is supported. + if l := len(privKey.PrivateKey); l == 0 { + return nil, fmt.Errorf("x509: invalid ML-KEM private key length: %d", l) + } + switch privKey.PrivateKey[0] { + case 0x80: // IMPLICIT [0] OCTET STRING (seed) + case 0x04: // OCTET STRING (expandedKey) + return nil, errors.New("x509: expanded ML-KEM private keys without seed are not supported") + case 0x30: // SEQUENCE (both) + return nil, errors.New(`x509: ML-KEM private keys with both seed and expanded key are not supported, use e.g. "openssl pkey -provparam ml-kem.output_formats=seed-only" to convert to a seed-only key`) + default: + return nil, fmt.Errorf("x509: invalid ML-KEM private key: invalid ASN.1 tag %02x", privKey.PrivateKey[0]) + } + if l := len(privKey.PrivateKey); l != 2+mlkem.SeedSize { + return nil, fmt.Errorf("x509: invalid ML-KEM private key length: %d", l) + } + if privKey.PrivateKey[1] != mlkem.SeedSize { + return nil, errors.New("x509: invalid ML-KEM private key ASN.1 encoding") + } + seed := privKey.PrivateKey[2:] + if privKey.Algo.Algorithm.Equal(oidPublicKeyMLKEM768) { + return mlkem.NewDecapsulationKey768(seed) + } + return mlkem.NewDecapsulationKey1024(seed) + default: return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) } @@ -129,7 +166,8 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) { // // The following key types are currently supported: *[rsa.PrivateKey], // *[ecdsa.PrivateKey], [ed25519.PrivateKey] (not a pointer), *[mldsa.PrivateKey], -// and *[ecdh.PrivateKey]. Unsupported key types result in an error. +// *[ecdh.PrivateKey], *[mlkem.DecapsulationKey768], and +// *[mlkem.DecapsulationKey1024]. Unsupported key types result in an error. // // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY". // @@ -188,6 +226,18 @@ func MarshalPKCS8PrivateKey(key any) ([]byte, error) { } privKey.PrivateKey = append([]byte{0x80, mldsa.PrivateKeySize}, k.Bytes()...) + case *mlkem.DecapsulationKey768: + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyMLKEM768, + } + privKey.PrivateKey = append([]byte{0x80, mlkem.SeedSize}, k.Bytes()...) + + case *mlkem.DecapsulationKey1024: + privKey.Algo = pkix.AlgorithmIdentifier{ + Algorithm: oidPublicKeyMLKEM1024, + } + privKey.PrivateKey = append([]byte{0x80, mlkem.SeedSize}, k.Bytes()...) + case *ecdh.PrivateKey: if k.Curve() == ecdh.X25519() { privKey.Algo = pkix.AlgorithmIdentifier{ diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go index 755007f543b332..fa219b53454631 100644 --- a/src/crypto/x509/x509.go +++ b/src/crypto/x509/x509.go @@ -29,6 +29,7 @@ import ( "crypto/elliptic" "crypto/fips140" "crypto/mldsa" + "crypto/mlkem" "crypto/rsa" "crypto/sha1" "crypto/sha256" @@ -67,8 +68,9 @@ type pkixPublicKey struct { // public key is a SubjectPublicKeyInfo structure (see RFC 5280, Section 4.1). // // It returns a *[rsa.PublicKey], *[dsa.PublicKey], *[ecdsa.PublicKey], -// [ed25519.PublicKey] (not a pointer), *[mldsa.PublicKey], or *[ecdh.PublicKey] -// (for X25519). More types might be supported in the future. +// [ed25519.PublicKey] (not a pointer), *[mldsa.PublicKey], *[ecdh.PublicKey] +// (for X25519), *[mlkem.EncapsulationKey768], or *[mlkem.EncapsulationKey1024]. +// More types might be supported in the future. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func ParsePKIXPublicKey(derBytes []byte) (pub any, err error) { @@ -141,6 +143,12 @@ func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.A } publicKeyAlgorithm.Parameters.FullBytes = paramBytes } + case *mlkem.EncapsulationKey768: + publicKeyBytes = pub.Bytes() + publicKeyAlgorithm.Algorithm = oidPublicKeyMLKEM768 + case *mlkem.EncapsulationKey1024: + publicKeyBytes = pub.Bytes() + publicKeyAlgorithm.Algorithm = oidPublicKeyMLKEM1024 default: return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub) } @@ -154,7 +162,8 @@ func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.A // // The following key types are currently supported: *[rsa.PublicKey], // *[ecdsa.PublicKey], [ed25519.PublicKey] (not a pointer), *[mldsa.PublicKey], -// and *[ecdh.PublicKey]. Unsupported key types result in an error. +// *[ecdh.PublicKey], *[mlkem.EncapsulationKey768], and +// *[mlkem.EncapsulationKey1024]. Unsupported key types result in an error. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func MarshalPKIXPublicKey(pub any) ([]byte, error) { @@ -530,6 +539,17 @@ var ( oidPublicKeyMLDSA44 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 17} oidPublicKeyMLDSA65 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 18} oidPublicKeyMLDSA87 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 19} + // RFC 9935, Section 3 + // + // id-alg-ml-kem-768 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + // country(16) us(840) organization(1) gov(101) csor(3) + // nistAlgorithm(4) kems(4) id-alg-ml-kem-768(2) } + // + // id-alg-ml-kem-1024 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) + // country(16) us(840) organization(1) gov(101) csor(3) + // nistAlgorithm(4) kems(4) id-alg-ml-kem-1024(3) } + oidPublicKeyMLKEM768 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 4, 2} + oidPublicKeyMLKEM1024 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 4, 3} ) // getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go index 53735bdd8e8825..acca2bfebc9dad 100644 --- a/src/crypto/x509/x509_test.go +++ b/src/crypto/x509/x509_test.go @@ -15,6 +15,7 @@ import ( "crypto/fips140" "crypto/internal/cryptotest" "crypto/mldsa" + "crypto/mlkem" "crypto/rand" "crypto/rsa" _ "crypto/sha256" @@ -4719,6 +4720,110 @@ func testMLDSA(t *testing.T, privateKeyPEM, publicKeyPEM, certPEM string) { } } +func TestMLKEM(t *testing.T) { + t.Run("ML-KEM-768", func(t *testing.T) { + testMLKEM[*mlkem.DecapsulationKey768](t, + rfc9935ExamplePrivateKeyMLKEM768, + rfc9935ExamplePublicKeyMLKEM768, + rfc9935ExampleCertificateMLKEM768) + }) + t.Run("ML-KEM-1024", func(t *testing.T) { + testMLKEM[*mlkem.DecapsulationKey1024](t, + rfc9935ExamplePrivateKeyMLKEM1024, + rfc9935ExamplePublicKeyMLKEM1024, + rfc9935ExampleCertificateMLKEM1024) + }) + + key, err := ParsePKCS8PrivateKey(pemDecode(t, rfc9935ExamplePrivateKeyMLKEM768Expanded)) + if key != nil || err == nil || !strings.Contains(err.Error(), "supported") { + t.Fatalf("ParsePKCS8PrivateKey should fail when parsing expanded ML-KEM-768 private key: got key %v, err %v", key, err) + } + key, err = ParsePKCS8PrivateKey(pemDecode(t, rfc9935ExamplePrivateKeyMLKEM768Both)) + if key != nil || err == nil || !strings.Contains(err.Error(), "supported") { + t.Fatalf("ParsePKCS8PrivateKey should fail when parsing ML-KEM-768 private key with both seed and expanded: got key %v, err %v", key, err) + } + + // CreateCertificate must reject ML-KEM subject public keys. + dk, err := mlkem.GenerateKey768() + if err != nil { + t.Fatalf("GenerateKey768: %v", err) + } + caPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("ecdsa.GenerateKey: %v", err) + } + tmpl := &Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{CommonName: "ML-KEM-768"}, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour), + } + if _, err := CreateCertificate(rand.Reader, tmpl, tmpl, dk.EncapsulationKey(), caPriv); err == nil { + t.Fatal("CreateCertificate with ML-KEM subject public key should fail") + } +} + +func testMLKEM[DK interface { + Bytes() []byte + EncapsulationKey() EK +}, EK interface { + Bytes() []byte +}](t *testing.T, privateKeyPEM, publicKeyPEM, certPEM string) { + privKey, err := ParsePKCS8PrivateKey(pemDecode(t, privateKeyPEM)) + if err != nil { + t.Fatalf("ParsePKCS8PrivateKey failed: %s", err) + } + dk, ok := privKey.(DK) + if !ok { + t.Fatalf("ParsePKCS8PrivateKey returned wrong type: got %T, want %T", privKey, *new(DK)) + } + // All the example private keys in RFC 9935, Appendix C.1 use this seed. + if hex.EncodeToString(dk.Bytes()) != "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f" { + t.Fatal("ParsePKCS8PrivateKey returned wrong private key value") + } + + got, err := MarshalPKCS8PrivateKey(privKey) + if err != nil { + t.Fatalf("MarshalPKCS8PrivateKey failed: %s", err) + } + if !bytes.Equal(got, pemDecode(t, privateKeyPEM)) { + t.Fatal("MarshalPKCS8PrivateKey did not return original DER bytes") + } + + pubKey, err := ParsePKIXPublicKey(pemDecode(t, publicKeyPEM)) + if err != nil { + t.Fatalf("ParsePKIXPublicKey failed: %s", err) + } + ek, ok := pubKey.(EK) + if !ok { + t.Fatalf("ParsePKIXPublicKey returned wrong type: got %T, want %T", pubKey, *new(EK)) + } + if !bytes.Equal(ek.Bytes(), dk.EncapsulationKey().Bytes()) { + t.Fatal("ParsePKIXPublicKey returned public key that does not match private key") + } + + got, err = MarshalPKIXPublicKey(pubKey) + if err != nil { + t.Fatalf("MarshalPKIXPublicKey failed: %s", err) + } + if !bytes.Equal(got, pemDecode(t, publicKeyPEM)) { + t.Fatal("MarshalPKIXPublicKey did not return original DER bytes") + } + + // We don't support ML-KEM certificates, ParseCertificate must leave + // PublicKey nil and report UnknownPublicKeyAlgorithm. + cert, err := ParseCertificate(pemDecode(t, certPEM)) + if err != nil { + t.Fatalf("ParseCertificate failed: %s", err) + } + if cert.PublicKey != nil { + t.Errorf("ParseCertificate returned non-nil PublicKey for ML-KEM certificate: %T", cert.PublicKey) + } + if cert.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { + t.Errorf("ParseCertificate returned PublicKeyAlgorithm %v, want UnknownPublicKeyAlgorithm", cert.PublicKeyAlgorithm) + } +} + func pemDecode(t *testing.T, pemStr string) []byte { b, _ := pem.Decode([]byte(pemStr)) if b == nil { @@ -5457,3 +5562,454 @@ func TestIPv4MappedIPsConstraintCreate(t *testing.T) { t.Fatalf("unexpected success creating certificate with IPv4-mapped IPv6 address constraint") } } + +// RFC 9935, Appendix C.1.2.1. +var rfc9935ExamplePrivateKeyMLKEM768 = testingKey(` +-----BEGIN TESTING KEY----- +MFQCAQAwCwYJYIZIAWUDBAQCBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ +GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8= +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.1.3.1. +var rfc9935ExamplePrivateKeyMLKEM1024 = testingKey(` +-----BEGIN TESTING KEY----- +MFQCAQAwCwYJYIZIAWUDBAQDBEKAQAABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZ +GhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj8= +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.1.2.2. +var rfc9935ExamplePrivateKeyMLKEM768Expanded = testingKey(` +-----BEGIN TESTING KEY----- +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 +JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+Pw== +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.1.2.3. +var rfc9935ExamplePrivateKeyMLKEM768Both = testingKey(` +-----BEGIN TESTING KEY----- +MIIJvgIBADALBglghkgBZQMEBAIEggmqMIIJpgRAAAECAwQFBgcICQoLDA0ODxAR +EhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+PwSC +CWAn0qd/M3VvYSCO8ROr6CWVhz1KvHMOW11nlSm/akzrY4NCcjGoYS9BVQUVrLpS +5I6ti5QoM7vmhl0T0Up50sXD4H8KBW2N56rfyroFjEk8gLN8q4xWJ1O7O6a27IKX ++IXqp1QNUwAVqEQG5VsTZrV34jbOWKJtih61pE1UIyPCFn2b9KR/mFaZygW65DuN +7GF/AjgKOJCv1LjH7H7eJlU6Al885bxdemITAwQjXLGtSDa1ZrW4Y72b20WihEpw +R7bI04PkSFJeBAtNyKK0jGw3yW1i1D8/2I4ogcQKIFyeJI9lK1kngad5+GiA8qFH +tnhj85HMGlqQjACV4HISKR4u+KNuuanAxgcyJbNHA6SvBJOCxHVz2mj96SRa1ETj +Gx+9tSHx9h83vAzvKSBn5nDSih/9kE9vEZCplpGKEwN6bKvzw3O/gpbNN6szundG +gJzD+K3hs2Ob1Xv8xpZQqq8d4Zj8TARjKZ5SxGF4DMQo/F0EpcUYUMumwqUnQ0Bn +V5PdoJvkTCnmOVxl+F0qCnxt9BHmkRsfLLbDUc0uh19Rtji+d2CX6T4vKy+D2gvu +9KqFup52OrZFAqDKUiLp6rWztwiO1SBg6Mgmm5Q6casK4cWxtofS4BnPgDa8+b9u +e6w6qjbkFmD6pFQPJkjNk6GJ7Fwt6nC6yqpP/JBvkIEOobZ78k8seM9rqIGq6mHA +ZSv/lbG65EJtF3O5zCyoLCHjjGNuOxxSMkSYawvoqD9d1c8tVHYvs8Xr9ZuOiFMC +sc5HAz7fdg9OApvkC21WaxnddYrNXHQSh4ExJE+QFyxT8mZjwh2QUwHUi6+RyRfM +d3np2IAswQ2Jo3BQmaKtOjqIlnQ8EURpgJO+JX2stm3HhSKLkSyNll0Uqig0LDrE +qT/vpTKyCUXdwQIBOcFNY4uQjE3d6aBkW5Wy5EFNQLt58EQTgw8VqHPCi7cFnCdB +ACAV8gQI8FjnFbC/mVtTgLfdMloFarl+ZZor4M32wzcxxoOmNLdx6MkqE5ruS7Dk +nHB3Mh1C/BmffB8pjKYl0iOlwmOgPMSBWbeBJmW3hjfk4YcgssKaa5n0J2aky8Tc +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 +Pj8= +-----END TESTING KEY----- +`) + +// RFC 9935, Appendix C.2. +var rfc9935ExamplePublicKeyMLKEM768 = ` +-----BEGIN PUBLIC KEY----- +MIIEsjALBglghkgBZQMEBAIDggShACmKoQ1CPI3aBp0CvFnmzfA6CWuLPaTKubgM +pKFJB2cszvHsT68jSgvFt+nUc/KzEzs7JqHRdctnp4BZGWmcAvdlMbmcX4kYBwS7 +TKRTXFuJcmecZgoHxeUUuHAJyGLrj1FXaV77P8QKne9rgcHMAqJJrk8JStDZvTSF +wcHGgIBSCnyMYyAyzuc4FU5cUXbAfaVgJHdqQw/nbqz2ZaP3uDIQIhW8gvEJOcg1 +VwQzao+sHYHkuwSFql18dNa1m75cXpcqDYusQRtVtdVVfNaAoaj3G064a8SMmgUJ +cxpUvZ1ykLJ5Y+Q3Lcmxmc/crAsBrNKKYjlREuTENkjWIsSMgjTQFEDozDdskn8j +pa/JrAR0xmInTkJFJchVLs47P+JlFt6QG8fVFb3olVjmJslcgLkzQvgBAATznmxs +lIccXjRMqzlmyDX5qWpZr9McQChrOLHBp4RwurlHUYk0RTzoZzapGfH1ptUQqG9U +VPw5gMtcdlvSvV97NrFBDWY1yM60fE3aDXaijqyTnHHDAkgEhmxxYmZYRCFjwsIh +F+UKzvzmN4qYVlIwKk7wws4Mxxa3eW4ray43d9+hrD2iWaMbWptTD4y2OKgaYqww +GEmrr5WnMBvaMAaJCb/bfmfbzLs4pVUaJbGjoPaFdIrVdT2IgPABbGJ0hhZjhMVX +H+I2WQA2TQODEeLYdds2ZoaTK17GAkMKNp6Hpu9cM4eGZXglvUwFes65I+sJNeaQ +XmO0ztf4CFenc91ksVDSZhLqmsEgUtsgF78YQ8y0sygbaQ3HKK36hcACgbjjwJKH +M1+Fa0/CiS9povV5Ia2gGRTECYhmLVd2lmKnhjUbm2ZJPat5WU2YbeIQDWW6D/Tq +WLgVONJKRDWiWPrCVASqf0H2WLE4UGXhWNy2ARVzJyD0BFmqrBXkBpU6kKxSmX0c +zQcAYO/GXbnmUzVEZ/rVbscTyG51QMQjrPJmn1L6b0rGiI2HHvPoR8ApqKr7uS4X +skqgebH0GbphdbRCr7EZCdSla3CgM1soc5IYqnyTSOLDwvPrPRWkHmQXwN2Uv+sh +QZsxGnuxOhgLvoMyGKmmsXRHzIXyJYWVh6cwdwSay8/UTQ8CVDjhXRU4Jw1Ybhv4 +MZKpRZz2PA6XL4UpdnmDHs8SFQmFHLg0D28Qew+hoO/Rs2qBibwIXE9ct4TlU/Qb +kY+AOXzhlW94W+43fKmqi+aZitowwmt8PYxrVSVMyWIDsgxCruCsTh67QI5JqeP4 +edCrB4XrcCVCXRMFoimcAV4SDRY7DhlJTOVyU9AkbRgnRcuBl6t0OLPBu3lyvsWj +BuujVnhVwBRpn+9lrlTHcKDYXBhADPZCrtxmB3e6SxOFAr1aeBL2IfhKSClrmN1D +IrbxWCi4qPDgCoukSlPDqLFDVxsHQKvVZ9rxzenHnCBLbV4lnRdmoxu7y05qBc9F +AhdrMBwcL0Ekd1AVe87IXoCbMKTWDXdHzdD1uZqoyCaYdRd5OqqAgKCxJKhVjfcr +vje3X07btr6CFtbGM/srIoDiURPYaV5DSBw+6zl+sZJQUim2eiAeqJPD4ssy2ovD +QvpN6gV4 +-----END PUBLIC KEY----- +` + +// RFC 9935, Appendix C.2. +var rfc9935ExamplePublicKeyMLKEM1024 = ` +-----BEGIN PUBLIC KEY----- +MIIGMjALBglghkgBZQMEBAMDggYhAEuUwpRQERGRgjs1FMmsHqPZglzLhjk6LfsE +ZU+iGS03v60cSXxlAu7lyoCnO/zguvWlSohYWkATl6PSMvQmp6+wgrwhpEMXCQ6q +x1ksLqiKZTxEkeoZOTEzX1LpiaPEzFbZxVNzLVfEcPtBq3WbZdLQREU4L82cTjRK +ESj6nhHgQ1jhku0BSyMjKn7isi4jcX9EER7jNXU5nDdkbamBPsmyEq/pTl3FwjMK +cpTMH0I0ptP7tPFoWriJLASssXzRwXDXsGEbanF2x5TMjGf1X8kjwq0gMQDzZZkY +gsMCQ9d4E4Q7XsfJZAMiY3BgkuzwDHUWvmTkWYykImwGm7XmfkF1zyKGyN1cSIps +WGHzG6oL0CaUcOi1Ud07zTjIbBL5zbF2x33ItsAqcB9HiQLIVT9pTA2CcntMSlws +EEEhKqEnSAi4IRGzd+x1IU6bGXj3YATUE52YYT9LjpjSCve1NAc6UJqVm3p1ZPm0 +DKIYv2GCkyCoUCAXlU0yjXrGx2nsKXAHVuewaFs0DV4RgFlQSkmppQoQGY6xCleE +Z460J9e0uruVUpM7BiiXlz4TGOrwoOrDdYSmVAGxcD4EKszYN1MUg/JBytzRwdN4 +EZ5pRCnbGZrIkeTFNDdXCFuzrng2ZzUMRFjZdnLoYegLHSZ5UQ6jpvI2DHekaULH +oGpVTSKAgMhLR67xTbF2IMsWwGqzChvkzacIK+n4fpwhHEaRY0mluo6qUgHHKUo8 +CIW1O2V0UhCIJexkbJCgRhIyTufQMa/lNDEyy+9ntu+xpewoCbdzU4znez2LBOsL +PCJWAR5McWwZqLoHUr9xSSEXZJ8GFcMpD8KaRv3kvVLbkobWAziCRCWcFaesK2QK +YMwDN2pYQaP7ikc1aPqbGiZyFfNMAWl7Dw5icXXXIQW3cHwpueYUvcM6b2yBipU3 +C0J4gte0dnlqnsbrmTJ0zZsjkagrpF4zk9Lprpchyp1sG5iLWCdxP5CmWF3pQzUo +wCsDzhC7X3IBOND7tMMMEma5GOUpJd/hezf5XSK8pU9HWRmshZCYwPDQisWHXvKb +Vv0UHm7xX3AKC2bzlZXFiBdzc8RmmyG8Bx5MOqXwtKMbYljzXaJKw80px/IJJBDF +B4NVsTj7U6a5rm4LnAgkPnuqRcRzduuMfxPUz1Gqc2+jFUDJJB83DaVEv5+cKNml +fi8qfKlaTktGbmQas7zHat8ROdVnpvErUvOmXn7AquJryqjFWDOwTlmZjryaGTD7 +ttIjPFPSwfi5UY48Lec6Gd7ms4Clsylxz2ThKf1sH6bnXUojRQHpZt06VAr1yPTz +SmtKJT7ihJJWbV5nxvVYVfywUG+wbBVnRNmgOjGib6lMrRTxV7fzA9B6acdzdo/L +TQecCQWXA6DDqU3kuZ6jovFlg9D5Fwo5UNsHtPC8MIApJ/n3lhtiWYkmNqlQKicF +MDY3eZ3TRNpFHBz3v2eEDOsweauMa4wZJ/ZAU8YSRQxFyeYDvBZmbllrNHHhA7bx +VEdCTRcCIEgRH/vTfhxnD2TxS4p7MrlMGkm0XdL8OM1SidkQrWNgLPXhMELGSsZ5 +e4n7VRrQjgWpLSAMzLfnEu8jyTEss1DwKatTfihzR/0wdawQkGp4PxxsB8y4j0Ei +jEvhxkD3kLXDpdXTynkklddLxGFWJljAesYAJ2uSSrW8m+HwSUy3b4L0YKdICXJm +M4HhaZlgYdeZhZ7FTU9cpcQRwB2xWXsWWXdmneE6koo0r7rCWP6oxHZCOclCHcMR +m/W0dpkgaXgyexxTRe90anmDhB8FbiU0EAqyTU6au9CxfGqVvUw8DkD2nhYSrO6y +i5kIbJURbnIEJziTOQv0a4mbNihrDr8ZR7uYhPcyyifagrGbXcDMf4iFcUkQiIsj +EMT5MZ1BCzTmQzuQA+IXa7mVJXRWEG6JUhY7i6WSUwzFqgrrQ605j+npe6pSPXpE +MWd8PTrwcZ5HXbhcqVr1CJvqvrBbL6q0iWumD4HIhHKle0aoKIJqDN+0RvgYkYLS +v16sTsHMXer1mcihPkgjVAbRf/3cg0S2xmmEqGiqkvoCInoIaVDrDIcB7VjcYod2 +uYOILhF1 +-----END PUBLIC KEY----- +` + +// RFC 9935, Appendix C.3. +var rfc9935ExampleCertificateMLKEM768 = ` +-----BEGIN CERTIFICATE----- +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 +AAAAAAAAAAAAAAAFDBUZHyU= +-----END CERTIFICATE----- +` + +// RFC 9935, Appendix C.3. +var rfc9935ExampleCertificateMLKEM1024 = ` +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- +` diff --git a/src/crypto/x509/x509limbo_test.go b/src/crypto/x509/x509limbo_test.go index dd67ab4acb148b..c1fcee42bf93bc 100644 --- a/src/crypto/x509/x509limbo_test.go +++ b/src/crypto/x509/x509limbo_test.go @@ -5,7 +5,6 @@ package x509 import ( - "crypto/fips140" "crypto/internal/cryptotest" "crypto/internal/cryptotest/x509limbo" "encoding/json" @@ -206,8 +205,8 @@ func TestX509Limbo(t *testing.T) { t.Skipf("name constraints for DirectoryNames are not supported") } - if slices.Contains(tc.Features, x509limbo.FeatureHasMldsa) && fips140.Version() == "v1.0.0" { - t.Skipf("ML-DSA is not available in FIPS 140-3 module v1.0.0") + if slices.Contains(tc.Features, x509limbo.FeatureHasMldsa) { + cryptotest.MustMinimumFIPS140ModuleVersion(t, "v1.26.0") } if len(tc.SignatureAlgorithms) != 0 { @@ -268,15 +267,7 @@ func TestX509Limbo(t *testing.T) { validationTime := time.Now() if tc.ValidationTime != nil { - vtStr, ok := tc.ValidationTime.(string) - if !ok { - t.Fatalf("validation time is not a string: %T %v", tc.ValidationTime, tc.ValidationTime) - } - parsed, err := time.Parse(time.RFC3339, vtStr) - if err != nil { - t.Fatalf("invalid validation time %q: %v", vtStr, err) - } - validationTime = parsed + validationTime = *tc.ValidationTime } var ekus []ExtKeyUsage diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go index 952cf0c6f859a3..d0eee1a5eae82a 100644 --- a/src/encoding/base64/base64.go +++ b/src/encoding/base64/base64.go @@ -441,12 +441,23 @@ type decoder struct { readErr error // error from r.Read enc *Encoding r io.Reader + end bool // saw a padded group: no more input may follow + total int64 // input consumed so far, excluding filtered newlines buf [1024]byte // leftover input nbuf int out []byte // leftover decoded output outbuf [1024 / 4 * 3]byte } +// rebaseError updates the offset of a CorruptInputError returned by decoding +// d.buf so that it refers to a position in the whole input stream. +func (d *decoder) rebaseError(err error) error { + if e, ok := err.(CorruptInputError); ok { + return CorruptInputError(int64(e) + d.total) + } + return err +} + func (d *decoder) Read(p []byte) (n int, err error) { // Use leftover decoded output from last read. if len(d.out) > 0 { @@ -474,11 +485,19 @@ func (d *decoder) Read(p []byte) (n int, err error) { d.nbuf += nn } + // A padded group must end the stream: decoding the same input as a whole + // reports any input after it as garbage. + if d.end && d.nbuf > 0 { + d.err = CorruptInputError(d.total) + return 0, d.err + } + if d.nbuf < 4 { if d.enc.padChar == NoPadding && d.nbuf > 0 { // Decode final fragment, without padding. var nw int nw, d.err = d.enc.Decode(d.outbuf[:], d.buf[:d.nbuf]) + d.err = d.rebaseError(d.err) d.nbuf = 0 d.out = d.outbuf[:nw] n = copy(p, d.out) @@ -508,6 +527,13 @@ func (d *decoder) Read(p []byte) (n int, err error) { } else { n, d.err = d.enc.Decode(p, d.buf[:nr]) } + if d.err != nil { + d.err = d.rebaseError(d.err) + } else if d.enc.padChar != NoPadding && d.buf[nr-1] == byte(d.enc.padChar) { + // The decoded chunk ended with a padded group. + d.end = true + } + d.total += int64(nr) d.nbuf -= nr copy(d.buf[:d.nbuf], d.buf[nr:]) return n, d.err diff --git a/src/encoding/base64/base64_test.go b/src/encoding/base64/base64_test.go index bc67413cc7ca85..88d4ccf9ccf30f 100644 --- a/src/encoding/base64/base64_test.go +++ b/src/encoding/base64/base64_test.go @@ -197,6 +197,36 @@ func TestDecoder(t *testing.T) { } } +func TestDecoderChunking(t *testing.T) { + // The decoder must behave identically to decoding the whole input at + // once, regardless of how the underlying reader chunks the input. + // See golang.org/issue/31626. + tests := []struct { + enc *Encoding + in string + }{ + {StdEncoding, "Rw==bw=="}, // padding inside the stream + {StdEncoding, "AAAA####"}, // error offset must not reset per chunk + {StdEncoding, "Rw==x"}, // trailing garbage after a padded group + {StdEncoding, "Rw===="}, // extra padding after a padded group + {StdEncoding, "AAAABBBBCCCC"}, // valid input + {StdEncoding, "AAAABB=="}, // valid input with padding + {RawStdEncoding, "AAAABB"}, // valid input, no padding + {RawStdEncoding, "AAAA#B"}, // invalid byte in final fragment + } + for _, tt := range tests { + want, wantErr := tt.enc.DecodeString(tt.in) + for i := 0; i <= len(tt.in); i++ { + r := io.MultiReader(strings.NewReader(tt.in[:i]), strings.NewReader(tt.in[i:])) + got, gotErr := io.ReadAll(NewDecoder(tt.enc, r)) + if !bytes.Equal(got, want) || gotErr != wantErr { + t.Errorf("Decode(%q) with split at %d = %q, %v; want %q, %v", + tt.in, i, got, gotErr, want, wantErr) + } + } + } +} + func TestDecoderBuffering(t *testing.T) { for bs := 1; bs <= 12; bs++ { decoder := NewDecoder(StdEncoding, strings.NewReader(bigtest.encoded)) diff --git a/src/go/build/constraint/expr.go b/src/go/build/constraint/expr.go index 943c8f3444b3f8..66d22439e897c3 100644 --- a/src/go/build/constraint/expr.go +++ b/src/go/build/constraint/expr.go @@ -66,6 +66,9 @@ func (x *NotExpr) Eval(ok func(tag string) bool) bool { } func (x *NotExpr) String() string { + if y := stripDoubleNot(x); y != x { + return y.String() + } s := x.X.String() switch x.X.(type) { case *AndExpr, *OrExpr: @@ -76,6 +79,21 @@ func (x *NotExpr) String() string { func not(x Expr) Expr { return &NotExpr{x} } +// stripDoubleNot removes pairs of leading negations from x. +func stripDoubleNot(x Expr) Expr { + for { + n, ok := x.(*NotExpr) + if !ok { + return x + } + nn, ok := n.X.(*NotExpr) + if !ok { + return x + } + x = nn.X + } +} + // An AndExpr represents the expression X && Y. type AndExpr struct { X, Y Expr @@ -95,6 +113,7 @@ func (x *AndExpr) String() string { } func andArg(x Expr) string { + x = stripDoubleNot(x) s := x.String() if _, ok := x.(*OrExpr); ok { s = "(" + s + ")" @@ -125,6 +144,7 @@ func (x *OrExpr) String() string { } func orArg(x Expr) string { + x = stripDoubleNot(x) s := x.String() if _, ok := x.(*AndExpr); ok { s = "(" + s + ")" diff --git a/src/go/build/constraint/expr_test.go b/src/go/build/constraint/expr_test.go index f0d08956aad82e..798f49007ac638 100644 --- a/src/go/build/constraint/expr_test.go +++ b/src/go/build/constraint/expr_test.go @@ -25,6 +25,10 @@ var exprStringTests = []struct { x: not(tag("abc")), out: "!abc", }, + { + x: not(not(tag("abc"))), + out: "abc", + }, { x: not(and(tag("abc"), tag("def"))), out: "!(abc && def)", @@ -33,10 +37,18 @@ var exprStringTests = []struct { x: and(tag("abc"), or(tag("def"), tag("ghi"))), out: "abc && (def || ghi)", }, + { + x: and(tag("abc"), not(not(or(tag("def"), tag("ghi"))))), + out: "abc && (def || ghi)", + }, { x: or(and(tag("abc"), tag("def")), tag("ghi")), out: "(abc && def) || ghi", }, + { + x: or(not(not(and(tag("abc"), tag("def")))), tag("ghi")), + out: "(abc && def) || ghi", + }, } func TestExprString(t *testing.T) { diff --git a/src/internal/stringslite/strings.go b/src/internal/stringslite/strings.go index c74eb961237758..5f5839f66cdd1a 100644 --- a/src/internal/stringslite/strings.go +++ b/src/internal/stringslite/strings.go @@ -65,7 +65,7 @@ func Index(s, substr string) int { return r + i } return -1 - } else if fails >= 4+i>>4 && i < t { + } else if n > bytealg.MaxLen && fails >= 4+i>>4 && i < t { // See comment in ../bytes/bytes.go. j := bytealg.IndexRabinKarp(s[i:], substr) if j < 0 { diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index c6006b614f319e..520bcb724abbb8 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -34,6 +34,7 @@ func FormatMediaType(t string, param map[string]string) string { b.WriteString(strings.ToLower(sub)) } + seenAttrs := make(map[string]struct{}, len(param)) for _, attribute := range slices.Sorted(maps.Keys(param)) { value := param[attribute] b.WriteByte(';') @@ -41,7 +42,12 @@ func FormatMediaType(t string, param map[string]string) string { if !isToken(attribute) { return "" } - b.WriteString(strings.ToLower(attribute)) + attribute = strings.ToLower(attribute) + if _, ok := seenAttrs[attribute]; ok { + return "" + } + seenAttrs[attribute] = struct{}{} + b.WriteString(attribute) needEnc := needsEncoding(value) if needEnc { diff --git a/src/mime/mediatype_test.go b/src/mime/mediatype_test.go index da8d64de7a3f0c..343beb863da892 100644 --- a/src/mime/mediatype_test.go +++ b/src/mime/mediatype_test.go @@ -531,6 +531,7 @@ var formatTests = []formatTest{ {"foo/BAR", map[string]string{"both": `With \backslash and "quote`}, `foo/bar; both="With \\backslash and \"quote"`}, {"foo/BAR", map[string]string{"": "empty attribute"}, ""}, {"foo/BAR", map[string]string{"bad attribute": "baz"}, ""}, + {"foo/BAR", map[string]string{"Name": "foo", "name": "bar"}, ""}, {"foo/BAR", map[string]string{"nonascii": "not an ascii character: ä"}, "foo/bar; nonascii*=utf-8''not%20an%20ascii%20character%3A%20%C3%A4"}, {"foo/BAR", map[string]string{"ctl": "newline: \n nil: \000"}, "foo/bar; ctl*=utf-8''newline%3A%20%0A%20nil%3A%20%00"}, {"foo/bar", map[string]string{"a": "av", "b": "bv", "c": "cv"}, "foo/bar; a=av; b=bv; c=cv"}, diff --git a/src/net/mail/message.go b/src/net/mail/message.go index 81acf018edd039..94553c193a6139 100644 --- a/src/net/mail/message.go +++ b/src/net/mail/message.go @@ -321,7 +321,7 @@ func (a *Address) String() string { // Text in an encoded-word in a display-name must not contain certain // characters like quotes or parentheses (see RFC 2047 section 5.3). // When this is the case encode the name using base64 encoding. - if strings.ContainsAny(a.Name, "\"#$%&'(),.:;<>@[]^`{|}~") { + if strings.ContainsAny(a.Name, "\\\"#$%&'(),.:;<>@[]^`{|}~") { return mime.BEncoding.Encode("utf-8", a.Name) + " " + s } return mime.QEncoding.Encode("utf-8", a.Name) + " " + s diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go index 2c1198a698cf4a..c606dd930411e5 100644 --- a/src/net/mail/message_test.go +++ b/src/net/mail/message_test.go @@ -1260,6 +1260,7 @@ func TestAddressFormattingAndParsing(t *testing.T) { {Name: "Böb ???", Address: "bob@example.com"}, {Name: "Böb (Jacöb)", Address: "bob@example.com"}, {Name: "à#$%&'(),.:;<>@[]^`{|}~'", Address: "bob@example.com"}, + {Name: `é\`, Address: "user@example.com"}, // https://golang.org/issue/11292 {Name: "\"\\\x1f,\"", Address: "0@0"}, // https://golang.org/issue/12782 diff --git a/src/net/rpc/debug.go b/src/net/rpc/debug.go index 81d4ea368563e4..b1ec2f785bb825 100644 --- a/src/net/rpc/debug.go +++ b/src/net/rpc/debug.go @@ -57,14 +57,6 @@ type debugService struct { type serviceArray []debugService -func (s serviceArray) Len() int { return len(s) } -func (s serviceArray) Less(i, j int) bool { return s[i].Name < s[j].Name } -func (s serviceArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - -func (m methodArray) Len() int { return len(m) } -func (m methodArray) Less(i, j int) bool { return m[i].Name < m[j].Name } -func (m methodArray) Swap(i, j int) { m[i], m[j] = m[j], m[i] } - type debugHTTP struct { *Server } diff --git a/src/runtime/callers_test.go b/src/runtime/callers_test.go index 9429442fc08d39..5a7369be2d5ce2 100644 --- a/src/runtime/callers_test.go +++ b/src/runtime/callers_test.go @@ -487,3 +487,27 @@ func TestFPUnwindAfterRecovery(t *testing.T) { }() panic(1) } + +//go:noinline +func deref() int { + var i *int + runtime.KeepAlive(&i) + return *i +} + +func TestFPUnwindStackGrowthAfterRecovery(t *testing.T) { + if !runtime.FramePointerEnabled { + t.Skip("frame pointers not supported for this architecture") + } + state := runtime.StackPoisonCopy() + defer state.Restore() + defer func() { + if recover() == nil { + t.Fatal("did not recover from panic") + } + growStack(nil) + var pcs [32]uintptr + runtime.FPCallers(pcs[:]) + }() + deref() +} diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go index 1239bfabbf2c04..ae5c5168502f0c 100644 --- a/src/runtime/export_test.go +++ b/src/runtime/export_test.go @@ -453,6 +453,16 @@ func ShrinkStackAndVerifyFramePointers() { FPCallers(make([]uintptr, 1024)) } +type StackPoisonCopyRestore int + +func (s StackPoisonCopyRestore) Restore() { stackPoisonCopy = int(s) } + +func StackPoisonCopy() StackPoisonCopyRestore { + before := stackPoisonCopy + stackPoisonCopy = 1 + return StackPoisonCopyRestore(before) +} + // BlockOnSystemStack switches to the system stack, prints "x\n" to // stderr, and blocks in a stack containing // "runtime.blockOnSystemStackInternal". diff --git a/src/runtime/stack.go b/src/runtime/stack.go index 6f89cc142c39f0..838090067a1769 100644 --- a/src/runtime/stack.go +++ b/src/runtime/stack.go @@ -699,15 +699,6 @@ func adjustpointers(scanp unsafe.Pointer, bv *bitvector, adjinfo *adjustinfo, f // Note: the argument/return area is adjusted by the callee. func adjustframe(frame *stkframe, adjinfo *adjustinfo) { - if frame.continpc == 0 { - // Frame is dead. - return - } - f := frame.fn - if stackDebug >= 2 { - print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n") - } - // Adjust saved frame pointer if there is one. if (goarch.ArchFamily == goarch.AMD64 || goarch.ArchFamily == goarch.ARM64) && frame.argp-frame.varp == 2*goarch.PtrSize { if stackDebug >= 3 { @@ -729,6 +720,44 @@ func adjustframe(frame *stkframe, adjinfo *adjustinfo) { // by the caller in its frame (one word below its SP). adjustpointer(adjinfo, unsafe.Pointer(frame.varp)) } + if goarch.ArchFamily == goarch.ARM64 && isInjectedCall(frame.fn.funcID) { + // If this is an injected call on arm64, then we need to adjust + // the frame pointer saved by the original function into which + // the call was injected. Normally this would be handled when + // adjusting the callee's frame or in adjustctxt. But when a + // call is injected, the frame is placed 16 bytes below the + // original stack pointer to make room to save the link + // register, and the frame pointer saved by the original + // function isn't inside any call frame. We can adjust that + // saved frame pointer here by looking just above frame.fp. + // + // ^ original call ^ + // | frame above... | + // +-------------------+ <- stack pointer at the time of injection + // : FP saved by : + // : original func : + // :···················: <- frame pointer register from original function + // : LR saved during : + // : injection : + // +-------------------+ <- frame.fp (injection decrements SP by 16 bytes) + // | FP saved | + // | during injection | + // +-------------------+ + // | injected call | + // V frame below... V + adjustpointer(adjinfo, unsafe.Pointer(frame.fp+goarch.PtrSize)) + } + + if frame.continpc == 0 { + // Frame is dead. The program might still see the frame pointer + // saved in the frame, adjusted above, but we don't need to + // adjust the rest of the frame. + return + } + f := frame.fn + if stackDebug >= 2 { + print(" adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n") + } locals, args, objs := frame.getStackMap(true) diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index e05075432df93a..58161dee06bddb 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -438,6 +438,10 @@ func (u *unwinder) resolveInternal(innermost, isSyscall bool) { } } +func isInjectedCall(id abi.FuncID) bool { + return id == abi.FuncID_sigpanic || id == abi.FuncID_asyncPreempt || id == abi.FuncID_debugCallV2 +} + func (u *unwinder) next() { frame := &u.frame f := frame.fn @@ -482,7 +486,7 @@ func (u *unwinder) next() { throw("traceback stuck") } - injectedCall := f.funcID == abi.FuncID_sigpanic || f.funcID == abi.FuncID_asyncPreempt || f.funcID == abi.FuncID_debugCallV2 + injectedCall := isInjectedCall(f.funcID) if injectedCall { u.flags |= unwindTrap } else { diff --git a/src/strings/strings.go b/src/strings/strings.go index d366d52e1e6610..8cb1f0e115b03f 100644 --- a/src/strings/strings.go +++ b/src/strings/strings.go @@ -1085,10 +1085,7 @@ func trimRightUnicode(s, cutset string) string { func trimSpaceUnicode(s string) string { for len(s) > 0 { - r, n := rune(s[0]), 1 - if r >= utf8.RuneSelf { - r, n = utf8.DecodeRuneInString(s) - } + r, n := utf8.DecodeRuneInString(s) if !stringslite.IsSpace(r) { break } diff --git a/test/codegen/bmi.go b/test/codegen/bmi.go index 3c00dd328bd5b9..e9ae079ce437ef 100644 --- a/test/codegen/bmi.go +++ b/test/codegen/bmi.go @@ -211,11 +211,15 @@ func shlrx32_load(x []uint32, i int, s uint32) uint32 { func XSubXandYAndn64(x, y uint64) uint64 { // amd64/v1:"ANDQ" "NOTQ" -"SUBQ" // amd64/v3:"ANDNQ" -"SUBQ" -"ANDQ" + // arm64:"BIC" -"SUB" -"AND" + // riscv64:"ANDN" -"SUB" -"AND " return x - (x & y) } func XSubXandYAndn32(x, y uint32) uint32 { // amd64/v1:"ANDL" "NOTL" -"SUBL" // amd64/v3:"ANDNL" -"SUBL" -"ANDL" + // arm64:"BIC" -"SUB" -"AND" + // riscv64:"ANDN" -"SUB" -"AND " return x - (x & y) } diff --git a/test/codegen/memops.go b/test/codegen/memops.go index 378521c5f76e72..c7f7d63c0ec16b 100644 --- a/test/codegen/memops.go +++ b/test/codegen/memops.go @@ -401,3 +401,107 @@ func bitOps(p *[12]uint64) { // amd64: `BTCQ \$63, 88\(AX\)` p[11] ^= 1 << 63 } + +func constModify8(p *[8]uint8) { + // amd64: `INCB \([A-Z]+[0-9]*\)` -`MOVB` + p[0]++ + // amd64: `DECB 1\([A-Z]+[0-9]*\)` -`MOVB` + p[1]-- + // amd64: `ADDB [$]77, 2\([A-Z]+[0-9]*\)` -`MOVB` + p[2] += 77 + // amd64: `ANDB [$]77, 3\([A-Z]+[0-9]*\)` -`MOVB` + p[3] &= 77 + // amd64: `ORB [$]12, 4\([A-Z]+[0-9]*\)` -`MOVB` + p[4] |= 12 + // amd64: `ANDB [$]-13, 5\([A-Z]+[0-9]*\)` -`MOVB` + p[5] &^= 12 + // amd64: `XORB [$]12, 6\([A-Z]+[0-9]*\)` -`MOVB` + p[6] ^= 12 +} + +func constModify16(p *[8]uint16) { + // amd64: `INCW \([A-Z]+[0-9]*\)` -`MOVW` + p[0]++ + // amd64: `DECW 2\([A-Z]+[0-9]*\)` -`MOVW` + p[1]-- + // amd64: `ADDW [$]77, 4\([A-Z]+[0-9]*\)` -`MOVW` + p[2] += 77 + // amd64: `ANDW [$]77, 6\([A-Z]+[0-9]*\)` -`MOVW` + p[3] &= 77 + // amd64: `ORW [$]12, 8\([A-Z]+[0-9]*\)` -`MOVW` + p[4] |= 12 + // amd64: `ANDW [$]-13, 10\([A-Z]+[0-9]*\)` -`MOVW` + p[5] &^= 12 + // amd64: `XORW [$]12, 12\([A-Z]+[0-9]*\)` -`MOVW` + p[6] ^= 12 +} + +// Constants that do not fit in an 8-bit immediate keep the +// load/modify/store form rather than growing a 16-bit immediate. +func constModify16Wide(p *uint16) { + // amd64: -`ORW [$]` + *p |= 0x1234 +} + +func constModifyGlobal() { + // amd64: `ORB [$]12, command-line-arguments\.x8\+1\(SB\)` -`MOVB` + x8[1] |= 12 + // amd64: `XORW [$]12, command-line-arguments\.x16\+2\(SB\)` -`MOVW` + x16[1] ^= 12 +} + +func idxStorePlusOpConst8(x []uint8, i int) { + // amd64: `INCB 1\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVB` + x[i+1]++ + // amd64: `DECB 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+2]-- + // amd64: `ADDB [$]77, 3\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+3] += 77 + // amd64: `ANDB [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+4] &= 77 + // amd64: `ORB [$]77, 5\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+5] |= 77 + // amd64: `XORB [$]77, 6\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` + x[i+6] ^= 77 +} + +func idxStorePlusOpConst16(x []uint16, i int) { + // amd64: `INCW 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` -`MOVW` + x[i+1]++ + // amd64: `DECW 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+2]-- + // amd64: `ADDW [$]77, 6\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+3] += 77 + // amd64: `ANDW [$]77, 8\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+4] &= 77 + // amd64: `ORW [$]77, 10\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+5] |= 77 + // amd64: `XORW [$]77, 12\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*2\)` + x[i+6] ^= 77 +} + +func idxStorePlusOpConst16Idx1(b []byte, i int) { + v := uint16(b[i]) | uint16(b[i+1])<<8 + v += 77 + // amd64: `ADDW [$]77, \([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i] = byte(v) + b[i+1] = byte(v >> 8) + + v = uint16(b[i+2]) | uint16(b[i+3])<<8 + v &^= 12 + // amd64: `ANDW [$]-13, 2\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i+2] = byte(v) + b[i+3] = byte(v >> 8) + + v = uint16(b[i+4]) | uint16(b[i+5])<<8 + v |= 77 + // amd64: `ORW [$]77, 4\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i+4] = byte(v) + b[i+5] = byte(v >> 8) + + v = uint16(b[i+6]) | uint16(b[i+7])<<8 + v ^= 77 + // amd64: `XORW [$]77, 6\([A-Z]+[0-9]*\)\([A-Z]+[0-9]*\*1\)` -`MOVW` + b[i+6] = byte(v) + b[i+7] = byte(v >> 8) +} diff --git a/test/codegen/multiply.go b/test/codegen/multiply.go index 8c76fd9bb188b1..54b61e4789e54c 100644 --- a/test/codegen/multiply.go +++ b/test/codegen/multiply.go @@ -180,7 +180,7 @@ func m28(x int64) int64 { func m29(x int64) int64 { // amd64: "IMUL3Q [$]29," // arm64: "MOVD [$]29," "MUL" - // loong64: "ALSLV [$]1," "SLLV [$]5," "SUBVU" + // loong64: "ALSLV [$]1," "ALSLV [$]2," "ALSLV [$]3," return x * 29 } func m30(x int64) int64 { @@ -307,7 +307,7 @@ func mn9(x int64) int64 { func mn10(x int64) int64 { // amd64: "IMUL3Q [$]-10," // arm64: "MOVD [$]-10," "MUL" - // loong64: "ADDVU" "ALSLV [$]3" "SUBVU" + // loong64: "ALSLV [$]2," "SUBVU" "ADDVU" return x * -10 } func mn11(x int64) int64 { @@ -319,13 +319,13 @@ func mn11(x int64) int64 { func mn12(x int64) int64 { // amd64: "IMUL3Q [$]-12," // arm64: "LSL [$]2," "SUB R[0-9]+<<2," - // loong64: "SUBVU" "SLLV [$]2," "ALSLV [$]4," + // loong64: "ALSLV [$]2," "ALSLV [$]4," "SUBVU" return x * -12 } func mn13(x int64) int64 { // amd64: "IMUL3Q [$]-13," // arm64: "MOVD [$]-13," "MUL" - // loong64: "ALSLV [$]4," "SLLV [$]2, " "SUBVU" + // loong64: "ALSLV [$]1," "SUBVU" "ALSLV [$]4," return x * -13 } func mn14(x int64) int64 { @@ -355,7 +355,7 @@ func mn17(x int64) int64 { func mn18(x int64) int64 { // amd64: "IMUL3Q [$]-18," // arm64: "MOVD [$]-18," "MUL" - // loong64: "ADDVU" "ALSLV [$]4," "SUBVU" + // loong64: "ALSLV [$]3," "SUBVU" "ADDVU" return x * -18 } func mn19(x int64) int64 { @@ -367,6 +367,6 @@ func mn19(x int64) int64 { func mn20(x int64) int64 { // amd64: "IMUL3Q [$]-20," // arm64: "MOVD [$]-20," "MUL" - // loong64: "SLLV [$]2," "ALSLV [$]4," "SUBVU" + // loong64: "ALSLV [$]2," "SUBVU" "SLLV [$]2," return x * -20 } diff --git a/test/codegen/noextend.go b/test/codegen/noextend.go index 68bf5472afb455..c014e38e39962f 100644 --- a/test/codegen/noextend.go +++ b/test/codegen/noextend.go @@ -857,3 +857,43 @@ func noZeroExtLDPW(p *[2]uint32) (uint64, uint64) { // arm64:"LDPW" -"MOVWU R[0-9]+, R[0-9]+" -"MOVD R[0-9]+, R[0-9]+" return uint64(p[0]), uint64(p[1]) } + +// Ops whose result is bounded below 2^8 regardless of input, declared +// via zeroUpperBits: 56 — even byte-sized zero-extensions fold away. + +func noZeroExt56CLZ(a uint64) uint8 { + // arm64:"CLZ " -"MOVBU R[0-9]+, R[0-9]+" -"MOVD R[0-9]+, R[0-9]+" + return uint8(bits.LeadingZeros64(a)) +} + +func noZeroExt56CLZW(a uint32) uint8 { + // arm64:"CLZW" -"MOVBU R[0-9]+, R[0-9]+" -"MOVD R[0-9]+, R[0-9]+" + return uint8(bits.LeadingZeros32(a)) +} + +func noZeroExt56POPCNTL(a uint32) uint8 { + // amd64/v2:"POPCNTL" -`MOVBLZX [A-Z][A-Z0-9]*, [A-Z][A-Z0-9]*` + return uint8(bits.OnesCount32(a)) +} + +// The flags-to-bool pseudo-ops produce 0/1 via a single CSET, so a +// bool-to-bool compare reads the CSET results directly. +func noZeroExtCSET(a, b, c, d uint64) bool { + // arm64:"CSET" -"MOVBU R[0-9]+, R[0-9]+" + return (a == b) == (c == d) +} + +// The 32-bit atomic exchange/and/or ops return their old value already +// zero-extended (LDAXRW on v8.0; SWPALW/LDCLRALW/LDORALW on v8.1). + +func noZeroExtAtomicAnd32(p *atomic.Uint32, m uint32) uint64 { + // arm64/v8.0:"LDAXRW" -"MOVWU R[0-9]+, R[0-9]+" + // arm64/v8.1:"LDCLRALW" -"MOVWU R[0-9]+, R[0-9]+" + return uint64(p.And(m)) +} + +func noZeroExtAtomicSwap32(p *atomic.Uint32, n uint32) uint64 { + // arm64/v8.0:"LDAXRW" -"MOVWU R[0-9]+, R[0-9]+" + // arm64/v8.1:"SWPALW" -"MOVWU R[0-9]+, R[0-9]+" + return uint64(p.Swap(n)) +}