1
0
mirror of https://github.com/golang/go synced 2024-11-25 19:37:58 -07:00

cmd/compile: get MIPS64 SSA working

- implement *, /, %, shifts, Zero, Move.
- fix mistakes in comparison.
- fix floating point rounding.
- handle RetJmp in assembler (which was not handled, as a consequence
  Duff's device was disabled in the old backend.)

all.bash now passes with SSA on.

Updates #16359.

Change-Id: Ia14eed0ed1176b5d800592080c8f53dded7fe73f
Reviewed-on: https://go-review.googlesource.com/27592
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Cherry Zhang 2016-08-22 12:25:23 -04:00
parent e90ae90b7a
commit e71e1fe87e
10 changed files with 3872 additions and 197 deletions

View File

@ -90,9 +90,19 @@ var ssaRegToReg = []int16{
// see ../../../../runtime/mheap.go:/minPhysPageSize // see ../../../../runtime/mheap.go:/minPhysPageSize
const minZeroPage = 4096 const minZeroPage = 4096
// isFPreg returns whether r is an FP register
func isFPreg(r int16) bool {
return mips.REG_F0 <= r && r <= mips.REG_F31
}
// isHILO returns whether r is HI or LO register
func isHILO(r int16) bool {
return r == mips.REG_HI || r == mips.REG_LO
}
// loadByType returns the load instruction of the given type. // loadByType returns the load instruction of the given type.
func loadByType(t ssa.Type, r int16) obj.As { func loadByType(t ssa.Type, r int16) obj.As {
if mips.REG_F0 <= r && r <= mips.REG_F31 { if isFPreg(r) {
if t.IsFloat() && t.Size() == 4 { // float32 if t.IsFloat() && t.Size() == 4 { // float32
return mips.AMOVF return mips.AMOVF
} else { // float64 or integer in FP register } else { // float64 or integer in FP register
@ -127,7 +137,7 @@ func loadByType(t ssa.Type, r int16) obj.As {
// storeByType returns the store instruction of the given type. // storeByType returns the store instruction of the given type.
func storeByType(t ssa.Type, r int16) obj.As { func storeByType(t ssa.Type, r int16) obj.As {
if mips.REG_F0 <= r && r <= mips.REG_F31 { if isFPreg(r) {
if t.IsFloat() && t.Size() == 4 { // float32 if t.IsFloat() && t.Size() == 4 { // float32
return mips.AMOVF return mips.AMOVF
} else { // float64 or integer in FP register } else { // float64 or integer in FP register
@ -167,21 +177,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return return
} }
as := mips.AMOVV as := mips.AMOVV
if v.Type.IsFloat() { if isFPreg(x) && isFPreg(y) {
switch v.Type.Size() { as = mips.AMOVD
case 4:
as = mips.AMOVF
case 8:
as = mips.AMOVD
default:
panic("bad float size")
}
} }
p := gc.Prog(as) p := gc.Prog(as)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x p.From.Reg = x
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = y p.To.Reg = y
if isHILO(x) && isHILO(y) || isHILO(x) && isFPreg(y) || isFPreg(x) && isHILO(y) {
// cannot move between special registers, use TMP as intermediate
p.To.Reg = mips.REGTMP
p = gc.Prog(mips.AMOVV)
p.From.Type = obj.TYPE_REG
p.From.Reg = mips.REGTMP
p.To.Type = obj.TYPE_REG
p.To.Reg = y
}
case ssa.OpMIPS64MOVVnop: case ssa.OpMIPS64MOVVnop:
if gc.SSARegNum(v) != gc.SSARegNum(v.Args[0]) { if gc.SSARegNum(v) != gc.SSARegNum(v.Args[0]) {
v.Fatalf("input[0] and output not in same register %s", v.LongString()) v.Fatalf("input[0] and output not in same register %s", v.LongString())
@ -207,6 +219,15 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
} }
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
if isHILO(r) {
// cannot directly load, load to TMP and move
p.To.Reg = mips.REGTMP
p = gc.Prog(mips.AMOVV)
p.From.Type = obj.TYPE_REG
p.From.Reg = mips.REGTMP
p.To.Type = obj.TYPE_REG
p.To.Reg = r
}
case ssa.OpPhi: case ssa.OpPhi:
gc.CheckLoweredPhi(v) gc.CheckLoweredPhi(v)
case ssa.OpStoreReg: case ssa.OpStoreReg:
@ -215,6 +236,15 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return return
} }
r := gc.SSARegNum(v.Args[0]) r := gc.SSARegNum(v.Args[0])
if isHILO(r) {
// cannot directly store, move to TMP and store
p := gc.Prog(mips.AMOVV)
p.From.Type = obj.TYPE_REG
p.From.Reg = r
p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REGTMP
r = mips.REGTMP
}
p := gc.Prog(storeByType(v.Type, r)) p := gc.Prog(storeByType(v.Type, r))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = r p.From.Reg = r
@ -287,11 +317,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Reg = gc.SSARegNum(v.Args[1]) p.From.Reg = gc.SSARegNum(v.Args[1])
p.Reg = gc.SSARegNum(v.Args[0]) p.Reg = gc.SSARegNum(v.Args[0])
case ssa.OpMIPS64MOVVconst: case ssa.OpMIPS64MOVVconst:
r := gc.SSARegNum(v)
p := gc.Prog(v.Op.Asm()) p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v) p.To.Reg = r
if isFPreg(r) || isHILO(r) {
// cannot move into FP or special registers, use TMP as intermediate
p.To.Reg = mips.REGTMP
p = gc.Prog(mips.AMOVV)
p.From.Type = obj.TYPE_REG
p.From.Reg = mips.REGTMP
p.To.Type = obj.TYPE_REG
p.To.Reg = r
}
case ssa.OpMIPS64MOVFconst, case ssa.OpMIPS64MOVFconst,
ssa.OpMIPS64MOVDconst: ssa.OpMIPS64MOVDconst:
p := gc.Prog(v.Op.Asm()) p := gc.Prog(v.Op.Asm())
@ -312,9 +352,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpMIPS64MOVVaddr: case ssa.OpMIPS64MOVVaddr:
p := gc.Prog(mips.AMOVV) p := gc.Prog(mips.AMOVV)
p.From.Type = obj.TYPE_ADDR p.From.Type = obj.TYPE_ADDR
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
var wantreg string var wantreg string
// MOVV $sym+off(base), R // MOVV $sym+off(base), R
// the assembler expands it as the following: // the assembler expands it as the following:
@ -339,6 +376,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
if reg := gc.SSAReg(v.Args[0]); reg.Name() != wantreg { if reg := gc.SSAReg(v.Args[0]); reg.Name() != wantreg {
v.Fatalf("bad reg %s for symbol type %T, want %s", reg.Name(), v.Aux, wantreg) v.Fatalf("bad reg %s for symbol type %T, want %s", reg.Name(), v.Aux, wantreg)
} }
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpMIPS64MOVBload, case ssa.OpMIPS64MOVBload,
ssa.OpMIPS64MOVBUload, ssa.OpMIPS64MOVBUload,
ssa.OpMIPS64MOVHload, ssa.OpMIPS64MOVHload,
@ -386,12 +425,12 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
fallthrough fallthrough
case ssa.OpMIPS64MOVWF, case ssa.OpMIPS64MOVWF,
ssa.OpMIPS64MOVWD, ssa.OpMIPS64MOVWD,
ssa.OpMIPS64MOVFW, ssa.OpMIPS64TRUNCFW,
ssa.OpMIPS64MOVDW, ssa.OpMIPS64TRUNCDW,
ssa.OpMIPS64MOVVF, ssa.OpMIPS64MOVVF,
ssa.OpMIPS64MOVVD, ssa.OpMIPS64MOVVD,
ssa.OpMIPS64MOVFV, ssa.OpMIPS64TRUNCFV,
ssa.OpMIPS64MOVDV, ssa.OpMIPS64TRUNCDV,
ssa.OpMIPS64MOVFD, ssa.OpMIPS64MOVFD,
ssa.OpMIPS64MOVDF, ssa.OpMIPS64MOVDF,
ssa.OpMIPS64NEGF, ssa.OpMIPS64NEGF,
@ -409,6 +448,119 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.Reg = mips.REGZERO p.Reg = mips.REGZERO
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v) p.To.Reg = gc.SSARegNum(v)
case ssa.OpMIPS64DUFFZERO:
// runtime.duffzero expects start address - 8 in R1
p := gc.Prog(mips.ASUBVU)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 8
p.Reg = gc.SSARegNum(v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REG_R1
p = gc.Prog(obj.ADUFFZERO)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
p.To.Offset = v.AuxInt
case ssa.OpMIPS64LoweredZero:
// SUBV $8, R1
// MOVV R0, 8(R1)
// ADDV $8, R1
// BNE Rarg1, R1, -2(PC)
// arg1 is the address of the last element to zero
var sz int64
var mov obj.As
switch {
case v.AuxInt%8 == 0:
sz = 8
mov = mips.AMOVV
case v.AuxInt%4 == 0:
sz = 4
mov = mips.AMOVW
case v.AuxInt%2 == 0:
sz = 2
mov = mips.AMOVH
default:
sz = 1
mov = mips.AMOVB
}
p := gc.Prog(mips.ASUBVU)
p.From.Type = obj.TYPE_CONST
p.From.Offset = sz
p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REG_R1
p2 := gc.Prog(mov)
p2.From.Type = obj.TYPE_REG
p2.From.Reg = mips.REGZERO
p2.To.Type = obj.TYPE_MEM
p2.To.Reg = mips.REG_R1
p2.To.Offset = sz
p3 := gc.Prog(mips.AADDVU)
p3.From.Type = obj.TYPE_CONST
p3.From.Offset = sz
p3.To.Type = obj.TYPE_REG
p3.To.Reg = mips.REG_R1
p4 := gc.Prog(mips.ABNE)
p4.From.Type = obj.TYPE_REG
p4.From.Reg = gc.SSARegNum(v.Args[1])
p4.Reg = mips.REG_R1
p4.To.Type = obj.TYPE_BRANCH
gc.Patch(p4, p2)
case ssa.OpMIPS64LoweredMove:
// SUBV $8, R1
// MOVV 8(R1), Rtmp
// MOVV Rtmp, (R2)
// ADDV $8, R1
// ADDV $8, R2
// BNE Rarg2, R1, -4(PC)
// arg2 is the address of the last element of src
var sz int64
var mov obj.As
switch {
case v.AuxInt%8 == 0:
sz = 8
mov = mips.AMOVV
case v.AuxInt%4 == 0:
sz = 4
mov = mips.AMOVW
case v.AuxInt%2 == 0:
sz = 2
mov = mips.AMOVH
default:
sz = 1
mov = mips.AMOVB
}
p := gc.Prog(mips.ASUBVU)
p.From.Type = obj.TYPE_CONST
p.From.Offset = sz
p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REG_R1
p2 := gc.Prog(mov)
p2.From.Type = obj.TYPE_MEM
p2.From.Reg = mips.REG_R1
p2.From.Offset = sz
p2.To.Type = obj.TYPE_REG
p2.To.Reg = mips.REGTMP
p3 := gc.Prog(mov)
p3.From.Type = obj.TYPE_REG
p3.From.Reg = mips.REGTMP
p3.To.Type = obj.TYPE_MEM
p3.To.Reg = mips.REG_R2
p4 := gc.Prog(mips.AADDVU)
p4.From.Type = obj.TYPE_CONST
p4.From.Offset = sz
p4.To.Type = obj.TYPE_REG
p4.To.Reg = mips.REG_R1
p5 := gc.Prog(mips.AADDVU)
p5.From.Type = obj.TYPE_CONST
p5.From.Offset = sz
p5.To.Type = obj.TYPE_REG
p5.To.Reg = mips.REG_R2
p6 := gc.Prog(mips.ABNE)
p6.From.Type = obj.TYPE_REG
p6.From.Reg = gc.SSARegNum(v.Args[2])
p6.Reg = mips.REG_R1
p6.To.Type = obj.TYPE_BRANCH
gc.Patch(p6, p2)
case ssa.OpMIPS64CALLstatic: case ssa.OpMIPS64CALLstatic:
if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym { if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym {
// Deferred calls will appear to be returning to // Deferred calls will appear to be returning to
@ -468,7 +620,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Reg = gc.SSARegNum(v.Args[0]) p.From.Reg = gc.SSARegNum(v.Args[0])
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = mips.REGZERO p.To.Reg = mips.REGTMP
if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers if gc.Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
gc.Warnl(v.Line, "generated nil check") gc.Warnl(v.Line, "generated nil check")
} }

View File

@ -22,6 +22,7 @@ type Config struct {
registers []Register // machine registers registers []Register // machine registers
gpRegMask regMask // general purpose integer register mask gpRegMask regMask // general purpose integer register mask
fpRegMask regMask // floating point register mask fpRegMask regMask // floating point register mask
specialRegMask regMask // special register mask
FPReg int8 // register number of frame pointer, -1 if not used FPReg int8 // register number of frame pointer, -1 if not used
hasGReg bool // has hardware g register hasGReg bool // has hardware g register
fe Frontend // callbacks into compiler frontend fe Frontend // callbacks into compiler frontend
@ -202,6 +203,7 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.registers = registersMIPS64[:] c.registers = registersMIPS64[:]
c.gpRegMask = gpRegMaskMIPS64 c.gpRegMask = gpRegMaskMIPS64
c.fpRegMask = fpRegMaskMIPS64 c.fpRegMask = fpRegMaskMIPS64
c.specialRegMask = specialRegMaskMIPS64
c.FPReg = framepointerRegMIPS64 c.FPReg = framepointerRegMIPS64
c.hasGReg = true c.hasGReg = true
default: default:

View File

@ -18,6 +18,44 @@
(Sub32F x y) -> (SUBF x y) (Sub32F x y) -> (SUBF x y)
(Sub64F x y) -> (SUBD x y) (Sub64F x y) -> (SUBD x y)
(Mul64 x y) -> (Select1 (MULVU x y))
(Mul32 x y) -> (Select1 (MULVU x y))
(Mul16 x y) -> (Select1 (MULVU x y))
(Mul8 x y) -> (Select1 (MULVU x y))
(Mul32F x y) -> (MULF x y)
(Mul64F x y) -> (MULD x y)
(Hmul64 x y) -> (Select0 (MULV x y))
(Hmul64u x y) -> (Select0 (MULVU x y))
(Hmul32 x y) -> (SRAVconst (Select1 <config.fe.TypeInt64()> (MULV (SignExt32to64 x) (SignExt32to64 y))) [32])
(Hmul32u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt64()> (MULVU (ZeroExt32to64 x) (ZeroExt32to64 y))) [32])
(Hmul16 x y) -> (SRAVconst (Select1 <config.fe.TypeInt32()> (MULV (SignExt16to64 x) (SignExt16to64 y))) [16])
(Hmul16u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt32()> (MULVU (ZeroExt16to64 x) (ZeroExt16to64 y))) [16])
(Hmul8 x y) -> (SRAVconst (Select1 <config.fe.TypeInt16()> (MULV (SignExt8to64 x) (SignExt8to64 y))) [8])
(Hmul8u x y) -> (SRLVconst (Select1 <config.fe.TypeUInt16()> (MULVU (ZeroExt8to64 x) (ZeroExt8to64 y))) [8])
(Div64 x y) -> (Select1 (DIVV x y))
(Div64u x y) -> (Select1 (DIVVU x y))
(Div32 x y) -> (Select1 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
(Div32u x y) -> (Select1 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Div16 x y) -> (Select1 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
(Div16u x y) -> (Select1 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
(Div8 x y) -> (Select1 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
(Div8u x y) -> (Select1 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
(Div32F x y) -> (DIVF x y)
(Div64F x y) -> (DIVD x y)
(Mod64 x y) -> (Select0 (DIVV x y))
(Mod64u x y) -> (Select0 (DIVVU x y))
(Mod32 x y) -> (Select0 (DIVV (SignExt32to64 x) (SignExt32to64 y)))
(Mod32u x y) -> (Select0 (DIVVU (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Mod16 x y) -> (Select0 (DIVV (SignExt16to64 x) (SignExt16to64 y)))
(Mod16u x y) -> (Select0 (DIVVU (ZeroExt16to64 x) (ZeroExt16to64 y)))
(Mod8 x y) -> (Select0 (DIVV (SignExt8to64 x) (SignExt8to64 y)))
(Mod8u x y) -> (Select0 (DIVVU (ZeroExt8to64 x) (ZeroExt8to64 y)))
(Avg64u <t> x y) -> (ADDV (ADDV <t> (SRLVconst <t> x [1]) (SRLVconst <t> y [1])) (AND <t> (AND <t> x y) (MOVVconst [1])))
(And64 x y) -> (AND x y) (And64 x y) -> (AND x y)
(And32 x y) -> (AND x y) (And32 x y) -> (AND x y)
(And16 x y) -> (AND x y) (And16 x y) -> (AND x y)
@ -33,6 +71,69 @@
(Xor16 x y) -> (XOR x y) (Xor16 x y) -> (XOR x y)
(Xor8 x y) -> (XOR x y) (Xor8 x y) -> (XOR x y)
// shifts
// hardware instruction uses only the low 6 bits of the shift
// we compare to 64 to ensure Go semantics for large shifts
(Lsh64x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
(Lsh64x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
(Lsh64x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
(Lsh64x8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
(Lsh32x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
(Lsh32x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
(Lsh32x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
(Lsh32x8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
(Lsh16x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
(Lsh16x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
(Lsh16x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
(Lsh16x8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
(Lsh8x64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SLLV <t> x y))
(Lsh8x32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SLLV <t> x (ZeroExt32to64 y)))
(Lsh8x16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SLLV <t> x (ZeroExt16to64 y)))
(Lsh8x8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SLLV <t> x (ZeroExt8to64 y)))
(Rsh64Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> x y))
(Rsh64Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> x (ZeroExt32to64 y)))
(Rsh64Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> x (ZeroExt16to64 y)))
(Rsh64Ux8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> x (ZeroExt8to64 y)))
(Rsh32Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt32to64 x) y))
(Rsh32Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Rsh32Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt16to64 y)))
(Rsh32Ux8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> (ZeroExt32to64 x) (ZeroExt8to64 y)))
(Rsh16Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt16to64 x) y))
(Rsh16Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt32to64 y)))
(Rsh16Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt16to64 y)))
(Rsh16Ux8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> (ZeroExt16to64 x) (ZeroExt8to64 y)))
(Rsh8Ux64 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) y)) (SRLV <t> (ZeroExt8to64 x) y))
(Rsh8Ux32 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt32to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt32to64 y)))
(Rsh8Ux16 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt16to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt16to64 y)))
(Rsh8Ux8 <t> x y) -> (AND (NEGV <t> (SGTU (Const64 <config.fe.TypeUInt64()> [64]) (ZeroExt8to64 y))) (SRLV <t> (ZeroExt8to64 x) (ZeroExt8to64 y)))
(Rsh64x64 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
(Rsh64x32 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
(Rsh64x16 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
(Rsh64x8 <t> x y) -> (SRAV x (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
(Rsh32x64 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
(Rsh32x32 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
(Rsh32x16 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
(Rsh32x8 <t> x y) -> (SRAV (SignExt32to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
(Rsh16x64 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
(Rsh16x32 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
(Rsh16x16 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
(Rsh16x8 <t> x y) -> (SRAV (SignExt16to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
(Rsh8x64 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU y (Const64 <config.fe.TypeUInt64()> [63]))) y))
(Rsh8x32 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt32to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt32to64 y)))
(Rsh8x16 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt16to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt16to64 y)))
(Rsh8x8 <t> x y) -> (SRAV (SignExt8to64 x) (OR <t> (NEGV <t> (SGTU (ZeroExt8to64 y) (Const64 <config.fe.TypeUInt64()> [63]))) (ZeroExt8to64 y)))
// unary ops // unary ops
(Neg64 x) -> (NEGV x) (Neg64 x) -> (NEGV x)
(Neg32 x) -> (NEGV x) (Neg32 x) -> (NEGV x)
@ -92,27 +193,27 @@
(Cvt32to64F x) -> (MOVWD x) (Cvt32to64F x) -> (MOVWD x)
(Cvt64to32F x) -> (MOVVF x) (Cvt64to32F x) -> (MOVVF x)
(Cvt64to64F x) -> (MOVVD x) (Cvt64to64F x) -> (MOVVD x)
(Cvt32Fto32 x) -> (MOVFW x) (Cvt32Fto32 x) -> (TRUNCFW x)
(Cvt64Fto32 x) -> (MOVDW x) (Cvt64Fto32 x) -> (TRUNCDW x)
(Cvt32Fto64 x) -> (MOVFV x) (Cvt32Fto64 x) -> (TRUNCFV x)
(Cvt64Fto64 x) -> (MOVDV x) (Cvt64Fto64 x) -> (TRUNCDV x)
(Cvt32Fto64F x) -> (MOVFD x) (Cvt32Fto64F x) -> (MOVFD x)
(Cvt64Fto32F x) -> (MOVDF x) (Cvt64Fto32F x) -> (MOVDF x)
// comparisons // comparisons
(Eq8 x y) -> (SGTU (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)) (MOVVconst [0])) (Eq8 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)))
(Eq16 x y) -> (SGTU (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)) (MOVVconst [0])) (Eq16 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt16to64 x) (ZeroExt16to64 y)))
(Eq32 x y) -> (SGTU (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) (MOVVconst [0])) (Eq32 x y) -> (SGTU (MOVVconst [1]) (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)))
(Eq64 x y) -> (SGTU (XOR x y) (MOVVconst [0])) (Eq64 x y) -> (SGTU (MOVVconst [1]) (XOR x y))
(EqPtr x y) -> (SGTU (XOR x y) (MOVVconst [0])) (EqPtr x y) -> (SGTU (MOVVconst [1]) (XOR x y))
(Eq32F x y) -> (FPFlagTrue (CMPEQF x y)) (Eq32F x y) -> (FPFlagTrue (CMPEQF x y))
(Eq64F x y) -> (FPFlagTrue (CMPEQD x y)) (Eq64F x y) -> (FPFlagTrue (CMPEQD x y))
(Neq8 x y) -> (SGTU (MOVVconst [0]) (XOR (ZeroExt8to64 x) (ZeroExt8to64 y))) (Neq8 x y) -> (SGTU (XOR (ZeroExt8to64 x) (ZeroExt8to64 y)) (MOVVconst [0]))
(Neq16 x y) -> (SGTU (MOVVconst [0]) (XOR (ZeroExt16to32 x) (ZeroExt16to64 y))) (Neq16 x y) -> (SGTU (XOR (ZeroExt16to32 x) (ZeroExt16to64 y)) (MOVVconst [0]))
(Neq32 x y) -> (SGTU (MOVVconst [0]) (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) ) (Neq32 x y) -> (SGTU (XOR (ZeroExt32to64 x) (ZeroExt32to64 y)) (MOVVconst [0]))
(Neq64 x y) -> (SGTU (MOVVconst [0]) (XOR x y)) (Neq64 x y) -> (SGTU (XOR x y) (MOVVconst [0]))
(NeqPtr x y) -> (SGTU (MOVVconst [0]) (XOR x y)) (NeqPtr x y) -> (SGTU (XOR x y) (MOVVconst [0]))
(Neq32F x y) -> (FPFlagFalse (CMPEQF x y)) (Neq32F x y) -> (FPFlagFalse (CMPEQF x y))
(Neq64F x y) -> (FPFlagFalse (CMPEQD x y)) (Neq64F x y) -> (FPFlagFalse (CMPEQD x y))
@ -123,8 +224,8 @@
(Less32F x y) -> (FPFlagTrue (CMPGTF y x)) // reverse operands to work around NaN (Less32F x y) -> (FPFlagTrue (CMPGTF y x)) // reverse operands to work around NaN
(Less64F x y) -> (FPFlagTrue (CMPGTD y x)) // reverse operands to work around NaN (Less64F x y) -> (FPFlagTrue (CMPGTD y x)) // reverse operands to work around NaN
(Less8U x y) -> (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)) (Less8U x y) -> (SGTU (ZeroExt8to64 y) (ZeroExt8to64 x))
(Less16U x y) -> (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)) (Less16U x y) -> (SGTU (ZeroExt16to64 y) (ZeroExt16to64 x))
(Less32U x y) -> (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x)) (Less32U x y) -> (SGTU (ZeroExt32to64 y) (ZeroExt32to64 x))
(Less64U x y) -> (SGTU y x) (Less64U x y) -> (SGTU y x)
@ -189,6 +290,128 @@
(Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVFstore ptr val mem) (Store [4] ptr val mem) && is32BitFloat(val.Type) -> (MOVFstore ptr val mem)
(Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVDstore ptr val mem) (Store [8] ptr val mem) && is64BitFloat(val.Type) -> (MOVDstore ptr val mem)
// zeroing
(Zero [s] _ mem) && SizeAndAlign(s).Size() == 0 -> mem
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore ptr (MOVVconst [0]) mem)
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
(MOVHstore ptr (MOVVconst [0]) mem)
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 2 ->
(MOVBstore [1] ptr (MOVVconst [0])
(MOVBstore [0] ptr (MOVVconst [0]) mem))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
(MOVWstore ptr (MOVVconst [0]) mem)
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
(MOVHstore [2] ptr (MOVVconst [0])
(MOVHstore [0] ptr (MOVVconst [0]) mem))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
(MOVBstore [3] ptr (MOVVconst [0])
(MOVBstore [2] ptr (MOVVconst [0])
(MOVBstore [1] ptr (MOVVconst [0])
(MOVBstore [0] ptr (MOVVconst [0]) mem))))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
(MOVVstore ptr (MOVVconst [0]) mem)
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
(MOVWstore [4] ptr (MOVVconst [0])
(MOVWstore [0] ptr (MOVVconst [0]) mem))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 4 ->
(MOVHstore [6] ptr (MOVVconst [0])
(MOVHstore [4] ptr (MOVVconst [0])
(MOVHstore [2] ptr (MOVVconst [0])
(MOVHstore [0] ptr (MOVVconst [0]) mem))))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 3 ->
(MOVBstore [2] ptr (MOVVconst [0])
(MOVBstore [1] ptr (MOVVconst [0])
(MOVBstore [0] ptr (MOVVconst [0]) mem)))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
(MOVHstore [4] ptr (MOVVconst [0])
(MOVHstore [2] ptr (MOVVconst [0])
(MOVHstore [0] ptr (MOVVconst [0]) mem)))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
(MOVWstore [8] ptr (MOVVconst [0])
(MOVWstore [4] ptr (MOVVconst [0])
(MOVWstore [0] ptr (MOVVconst [0]) mem)))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
(MOVVstore [8] ptr (MOVVconst [0])
(MOVVstore [0] ptr (MOVVconst [0]) mem))
(Zero [s] ptr mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
(MOVVstore [16] ptr (MOVVconst [0])
(MOVVstore [8] ptr (MOVVconst [0])
(MOVVstore [0] ptr (MOVVconst [0]) mem)))
// medium zeroing uses a duff device
// 8, and 128 are magic constants, see runtime/mkduff.go
(Zero [s] ptr mem)
&& SizeAndAlign(s).Size()%8 == 0 && SizeAndAlign(s).Size() > 24 && SizeAndAlign(s).Size() <= 8*128
&& SizeAndAlign(s).Align()%8 == 0 && !config.noDuffDevice ->
(DUFFZERO [8 * (128 - int64(SizeAndAlign(s).Size()/8))] ptr mem)
// large or unaligned zeroing uses a loop
(Zero [s] ptr mem)
&& (SizeAndAlign(s).Size() > 8*128 || config.noDuffDevice) || SizeAndAlign(s).Align()%8 != 0 ->
(LoweredZero [SizeAndAlign(s).Align()]
ptr
(ADDVconst <ptr.Type> ptr [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
mem)
// moves
(Move [s] _ _ mem) && SizeAndAlign(s).Size() == 0 -> mem
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 1 -> (MOVBstore dst (MOVBload src mem) mem)
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 && SizeAndAlign(s).Align()%2 == 0 ->
(MOVHstore dst (MOVHload src mem) mem)
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 2 ->
(MOVBstore [1] dst (MOVBload [1] src mem)
(MOVBstore dst (MOVBload src mem) mem))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%4 == 0 ->
(MOVWstore dst (MOVWload src mem) mem)
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 && SizeAndAlign(s).Align()%2 == 0 ->
(MOVHstore [2] dst (MOVHload [2] src mem)
(MOVHstore dst (MOVHload src mem) mem))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 4 ->
(MOVBstore [3] dst (MOVBload [3] src mem)
(MOVBstore [2] dst (MOVBload [2] src mem)
(MOVBstore [1] dst (MOVBload [1] src mem)
(MOVBstore dst (MOVBload src mem) mem))))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%8 == 0 ->
(MOVVstore dst (MOVVload src mem) mem)
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%4 == 0 ->
(MOVWstore [4] dst (MOVWload [4] src mem)
(MOVWstore dst (MOVWload src mem) mem))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 8 && SizeAndAlign(s).Align()%2 == 0 ->
(MOVHstore [6] dst (MOVHload [6] src mem)
(MOVHstore [4] dst (MOVHload [4] src mem)
(MOVHstore [2] dst (MOVHload [2] src mem)
(MOVHstore dst (MOVHload src mem) mem))))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 3 ->
(MOVBstore [2] dst (MOVBload [2] src mem)
(MOVBstore [1] dst (MOVBload [1] src mem)
(MOVBstore dst (MOVBload src mem) mem)))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 6 && SizeAndAlign(s).Align()%2 == 0 ->
(MOVHstore [4] dst (MOVHload [4] src mem)
(MOVHstore [2] dst (MOVHload [2] src mem)
(MOVHstore dst (MOVHload src mem) mem)))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 12 && SizeAndAlign(s).Align()%4 == 0 ->
(MOVWstore [8] dst (MOVWload [8] src mem)
(MOVWstore [4] dst (MOVWload [4] src mem)
(MOVWstore dst (MOVWload src mem) mem)))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 16 && SizeAndAlign(s).Align()%8 == 0 ->
(MOVVstore [8] dst (MOVVload [8] src mem)
(MOVVstore dst (MOVVload src mem) mem))
(Move [s] dst src mem) && SizeAndAlign(s).Size() == 24 && SizeAndAlign(s).Align()%8 == 0 ->
(MOVVstore [16] dst (MOVVload [16] src mem)
(MOVVstore [8] dst (MOVVload [8] src mem)
(MOVVstore dst (MOVVload src mem) mem)))
// large or unaligned move uses a loop
(Move [s] dst src mem)
&& SizeAndAlign(s).Size() > 24 || SizeAndAlign(s).Align()%8 != 0 ->
(LoweredMove [SizeAndAlign(s).Align()]
dst
src
(ADDVconst <src.Type> src [SizeAndAlign(s).Size()-moveSize(SizeAndAlign(s).Align(), config)])
mem)
// calls // calls
(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem) (StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
(ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem) (ClosureCall [argwid] entry closure mem) -> (CALLclosure [argwid] entry closure mem)

View File

@ -160,14 +160,14 @@ func init() {
) )
ops := []opData{ ops := []opData{
// binary ops // binary ops
{name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true}, // arg0 + arg1 {name: "ADDV", argLength: 2, reg: gp21, asm: "ADDVU", commutative: true}, // arg0 + arg1
{name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"}, // arg0 + auxInt {name: "ADDVconst", argLength: 1, reg: gp11sp, asm: "ADDVU", aux: "Int64"}, // arg0 + auxInt
{name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"}, // arg0 - arg1 {name: "SUBV", argLength: 2, reg: gp21, asm: "SUBVU"}, // arg0 - arg1
{name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"}, // arg0 - auxInt {name: "SUBVconst", argLength: 1, reg: gp11, asm: "SUBVU", aux: "Int64"}, // arg0 - auxInt
{name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true}, // arg0 * arg1, signed, results hi,lo {name: "MULV", argLength: 2, reg: gp2hilo, asm: "MULV", commutative: true, typ: "(Int64,Int64)"}, // arg0 * arg1, signed, results hi,lo
{name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true}, // arg0 * arg1, unsigned, results hi,lo {name: "MULVU", argLength: 2, reg: gp2hilo, asm: "MULVU", commutative: true, typ: "(UInt64,UInt64)"}, // arg0 * arg1, unsigned, results hi,lo
{name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 {name: "DIVV", argLength: 2, reg: gp2hilo, asm: "DIVV", typ: "(Int64,Int64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
{name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1 {name: "DIVVU", argLength: 2, reg: gp2hilo, asm: "DIVVU", typ: "(UInt64,UInt64)"}, // arg0 / arg1, signed, results hi=arg0%arg1,lo=arg0/arg1
{name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1 {name: "ADDF", argLength: 2, reg: fp21, asm: "ADDF", commutative: true}, // arg0 + arg1
{name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1 {name: "ADDD", argLength: 2, reg: fp21, asm: "ADDD", commutative: true}, // arg0 + arg1
@ -252,16 +252,16 @@ func init() {
{name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register {name: "MOVVnop", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // nop, return arg0 in same register
{name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32 {name: "MOVWF", argLength: 1, reg: fp11, asm: "MOVWF"}, // int32 -> float32
{name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64 {name: "MOVWD", argLength: 1, reg: fp11, asm: "MOVWD"}, // int32 -> float64
{name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32 {name: "MOVVF", argLength: 1, reg: fp11, asm: "MOVVF"}, // int64 -> float32
{name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64 {name: "MOVVD", argLength: 1, reg: fp11, asm: "MOVVD"}, // int64 -> float64
{name: "MOVFW", argLength: 1, reg: fp11, asm: "MOVFW"}, // float32 -> int32 {name: "TRUNCFW", argLength: 1, reg: fp11, asm: "TRUNCFW"}, // float32 -> int32
{name: "MOVDW", argLength: 1, reg: fp11, asm: "MOVDW"}, // float64 -> int32 {name: "TRUNCDW", argLength: 1, reg: fp11, asm: "TRUNCDW"}, // float64 -> int32
{name: "MOVFV", argLength: 1, reg: fp11, asm: "MOVFV"}, // float32 -> int64 {name: "TRUNCFV", argLength: 1, reg: fp11, asm: "TRUNCFV"}, // float32 -> int64
{name: "MOVDV", argLength: 1, reg: fp11, asm: "MOVDV"}, // float64 -> int64 {name: "TRUNCDV", argLength: 1, reg: fp11, asm: "TRUNCDV"}, // float64 -> int64
{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64 {name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64
{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32 {name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32
// function calls // function calls
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem {name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff", clobberFlags: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
@ -270,6 +270,67 @@ func init() {
{name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem {name: "CALLgo", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call newproc. arg0=mem, auxint=argsize, returns mem
{name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem {name: "CALLinter", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", clobberFlags: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
// duffzero
// arg0 = address of memory to zero
// arg1 = mem
// auxint = offset into duffzero code to start executing
// returns mem
// R1 aka mips.REGRT1 changed as side effect
{
name: "DUFFZERO",
aux: "Int64",
argLength: 2,
reg: regInfo{
inputs: []regMask{gp},
clobbers: buildReg("R1"),
},
},
// large or unaligned zeroing
// arg0 = address of memory to zero (in R1, changed as side effect)
// arg1 = address of the last element to zero
// arg2 = mem
// auxint = alignment
// returns mem
// SUBV $8, R1
// MOVV R0, 8(R1)
// ADDV $8, R1
// BNE Rarg1, R1, -2(PC)
{
name: "LoweredZero",
aux: "Int64",
argLength: 3,
reg: regInfo{
inputs: []regMask{buildReg("R1"), gp},
clobbers: buildReg("R1"),
},
clobberFlags: true,
},
// large or unaligned move
// arg0 = address of dst memory (in R2, changed as side effect)
// arg1 = address of src memory (in R1, changed as side effect)
// arg2 = address of the last element of src
// arg3 = mem
// auxint = alignment
// returns mem
// SUBV $8, R1
// MOVV 8(R1), Rtmp
// MOVV Rtmp, (R2)
// ADDV $8, R1
// ADDV $8, R2
// BNE Rarg2, R1, -4(PC)
{
name: "LoweredMove",
aux: "Int64",
argLength: 4,
reg: regInfo{
inputs: []regMask{buildReg("R2"), buildReg("R1"), gp},
clobbers: buildReg("R1 R2"),
},
clobberFlags: true,
},
// pseudo-ops // pseudo-ops
{name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}}, // panic if arg0 is nil. arg1=mem. {name: "LoweredNilCheck", argLength: 2, reg: regInfo{inputs: []regMask{gpg}}}, // panic if arg0 is nil. arg1=mem.
@ -309,6 +370,7 @@ func init() {
regnames: regNamesMIPS64, regnames: regNamesMIPS64,
gpregmask: gp, gpregmask: gp,
fpregmask: fp, fpregmask: fp,
specialregmask: hi | lo,
framepointerreg: -1, // not used framepointerreg: -1, // not used
}) })
} }

View File

@ -29,6 +29,7 @@ type arch struct {
regnames []string regnames []string
gpregmask regMask gpregmask regMask
fpregmask regMask fpregmask regMask
specialregmask regMask
framepointerreg int8 framepointerreg int8
generic bool generic bool
} }
@ -241,6 +242,7 @@ func genOp() {
fmt.Fprintln(w, "}") fmt.Fprintln(w, "}")
fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask) fmt.Fprintf(w, "var gpRegMask%s = regMask(%d)\n", a.name, a.gpregmask)
fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask) fmt.Fprintf(w, "var fpRegMask%s = regMask(%d)\n", a.name, a.fpregmask)
fmt.Fprintf(w, "var specialRegMask%s = regMask(%d)\n", a.name, a.specialregmask)
fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg) fmt.Fprintf(w, "var framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
} }

View File

@ -1051,10 +1051,10 @@ const (
OpMIPS64MOVWD OpMIPS64MOVWD
OpMIPS64MOVVF OpMIPS64MOVVF
OpMIPS64MOVVD OpMIPS64MOVVD
OpMIPS64MOVFW OpMIPS64TRUNCFW
OpMIPS64MOVDW OpMIPS64TRUNCDW
OpMIPS64MOVFV OpMIPS64TRUNCFV
OpMIPS64MOVDV OpMIPS64TRUNCDV
OpMIPS64MOVFD OpMIPS64MOVFD
OpMIPS64MOVDF OpMIPS64MOVDF
OpMIPS64CALLstatic OpMIPS64CALLstatic
@ -1062,6 +1062,9 @@ const (
OpMIPS64CALLdefer OpMIPS64CALLdefer
OpMIPS64CALLgo OpMIPS64CALLgo
OpMIPS64CALLinter OpMIPS64CALLinter
OpMIPS64DUFFZERO
OpMIPS64LoweredZero
OpMIPS64LoweredMove
OpMIPS64LoweredNilCheck OpMIPS64LoweredNilCheck
OpMIPS64FPFlagTrue OpMIPS64FPFlagTrue
OpMIPS64FPFlagFalse OpMIPS64FPFlagFalse
@ -12905,9 +12908,9 @@ var opcodeTable = [...]opInfo{
}, },
}, },
{ {
name: "MOVFW", name: "TRUNCFW",
argLen: 1, argLen: 1,
asm: mips.AMOVFW, asm: mips.ATRUNCFW,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31 {0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31
@ -12918,9 +12921,9 @@ var opcodeTable = [...]opInfo{
}, },
}, },
{ {
name: "MOVDW", name: "TRUNCDW",
argLen: 1, argLen: 1,
asm: mips.AMOVDW, asm: mips.ATRUNCDW,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31 {0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31
@ -12931,9 +12934,9 @@ var opcodeTable = [...]opInfo{
}, },
}, },
{ {
name: "MOVFV", name: "TRUNCFV",
argLen: 1, argLen: 1,
asm: mips.AMOVFV, asm: mips.ATRUNCFV,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31 {0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31
@ -12944,9 +12947,9 @@ var opcodeTable = [...]opInfo{
}, },
}, },
{ {
name: "MOVDV", name: "TRUNCDV",
argLen: 1, argLen: 1,
asm: mips.AMOVDV, asm: mips.ATRUNCDV,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31 {0, 385057768005959680}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31
@ -13034,6 +13037,44 @@ var opcodeTable = [...]opInfo{
clobbers: 2114440025016893438, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31 HI LO clobbers: 2114440025016893438, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F25 F27 F29 F31 HI LO
}, },
}, },
{
name: "DUFFZERO",
auxType: auxInt64,
argLen: 2,
reg: regInfo{
inputs: []inputInfo{
{0, 33554430}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25
},
clobbers: 2, // R1
},
},
{
name: "LoweredZero",
auxType: auxInt64,
argLen: 3,
clobberFlags: true,
reg: regInfo{
inputs: []inputInfo{
{0, 2}, // R1
{1, 33554430}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25
},
clobbers: 2, // R1
},
},
{
name: "LoweredMove",
auxType: auxInt64,
argLen: 4,
clobberFlags: true,
reg: regInfo{
inputs: []inputInfo{
{0, 4}, // R2
{1, 2}, // R1
{2, 33554430}, // R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R18 R19 R20 R21 R22 R24 R25
},
clobbers: 6, // R1 R2
},
},
{ {
name: "LoweredNilCheck", name: "LoweredNilCheck",
argLen: 2, argLen: 2,
@ -16141,6 +16182,7 @@ var registers386 = [...]Register{
} }
var gpRegMask386 = regMask(239) var gpRegMask386 = regMask(239)
var fpRegMask386 = regMask(65280) var fpRegMask386 = regMask(65280)
var specialRegMask386 = regMask(0)
var framepointerReg386 = int8(5) var framepointerReg386 = int8(5)
var registersAMD64 = [...]Register{ var registersAMD64 = [...]Register{
{0, "AX"}, {0, "AX"},
@ -16179,6 +16221,7 @@ var registersAMD64 = [...]Register{
} }
var gpRegMaskAMD64 = regMask(65519) var gpRegMaskAMD64 = regMask(65519)
var fpRegMaskAMD64 = regMask(4294901760) var fpRegMaskAMD64 = regMask(4294901760)
var specialRegMaskAMD64 = regMask(0)
var framepointerRegAMD64 = int8(5) var framepointerRegAMD64 = int8(5)
var registersARM = [...]Register{ var registersARM = [...]Register{
{0, "R0"}, {0, "R0"},
@ -16217,6 +16260,7 @@ var registersARM = [...]Register{
} }
var gpRegMaskARM = regMask(5119) var gpRegMaskARM = regMask(5119)
var fpRegMaskARM = regMask(4294901760) var fpRegMaskARM = regMask(4294901760)
var specialRegMaskARM = regMask(0)
var framepointerRegARM = int8(-1) var framepointerRegARM = int8(-1)
var registersARM64 = [...]Register{ var registersARM64 = [...]Register{
{0, "R0"}, {0, "R0"},
@ -16285,6 +16329,7 @@ var registersARM64 = [...]Register{
} }
var gpRegMaskARM64 = regMask(133955583) var gpRegMaskARM64 = regMask(133955583)
var fpRegMaskARM64 = regMask(288230375077969920) var fpRegMaskARM64 = regMask(288230375077969920)
var specialRegMaskARM64 = regMask(0)
var framepointerRegARM64 = int8(-1) var framepointerRegARM64 = int8(-1)
var registersMIPS64 = [...]Register{ var registersMIPS64 = [...]Register{
{0, "R0"}, {0, "R0"},
@ -16352,6 +16397,7 @@ var registersMIPS64 = [...]Register{
} }
var gpRegMaskMIPS64 = regMask(33554430) var gpRegMaskMIPS64 = regMask(33554430)
var fpRegMaskMIPS64 = regMask(385057768005959680) var fpRegMaskMIPS64 = regMask(385057768005959680)
var specialRegMaskMIPS64 = regMask(1729382256910270464)
var framepointerRegMIPS64 = int8(-1) var framepointerRegMIPS64 = int8(-1)
var registersPPC64 = [...]Register{ var registersPPC64 = [...]Register{
{0, "SP"}, {0, "SP"},
@ -16415,4 +16461,5 @@ var registersPPC64 = [...]Register{
} }
var gpRegMaskPPC64 = regMask(536866812) var gpRegMaskPPC64 = regMask(536866812)
var fpRegMaskPPC64 = regMask(288230371856744448) var fpRegMaskPPC64 = regMask(288230371856744448)
var specialRegMaskPPC64 = regMask(0)
var framepointerRegPPC64 = int8(0) var framepointerRegPPC64 = int8(0)

View File

@ -471,7 +471,7 @@ func (s *regAllocState) init(f *Func) {
} }
// Figure out which registers we're allowed to use. // Figure out which registers we're allowed to use.
s.allocatable = s.f.Config.gpRegMask | s.f.Config.fpRegMask s.allocatable = s.f.Config.gpRegMask | s.f.Config.fpRegMask | s.f.Config.specialRegMask
s.allocatable &^= 1 << s.SPReg s.allocatable &^= 1 << s.SPReg
s.allocatable &^= 1 << s.SBReg s.allocatable &^= 1 << s.SBReg
if s.f.Config.hasGReg { if s.f.Config.hasGReg {
@ -1302,7 +1302,7 @@ func (s *regAllocState) regalloc(f *Func) {
// We assume that a control input can be passed in any // We assume that a control input can be passed in any
// type-compatible register. If this turns out not to be true, // type-compatible register. If this turns out not to be true,
// we'll need to introduce a regspec for a block's control value. // we'll need to introduce a regspec for a block's control value.
s.allocValToReg(v, s.compatRegs(v.Type), false, b.Line) b.Control = s.allocValToReg(v, s.compatRegs(v.Type), false, b.Line)
// Remove this use from the uses list. // Remove this use from the uses list.
vi := &s.values[v.ID] vi := &s.values[v.ID]
u := vi.uses u := vi.uses

File diff suppressed because it is too large Load Diff

View File

@ -84,7 +84,7 @@ func schedule(f *Func) {
// Compute score. Larger numbers are scheduled closer to the end of the block. // Compute score. Larger numbers are scheduled closer to the end of the block.
for _, v := range b.Values { for _, v := range b.Values {
switch { switch {
case v.Op == OpAMD64LoweredGetClosurePtr || v.Op == OpPPC64LoweredGetClosurePtr || v.Op == OpARMLoweredGetClosurePtr || v.Op == OpARM64LoweredGetClosurePtr || v.Op == Op386LoweredGetClosurePtr: case v.Op == OpAMD64LoweredGetClosurePtr || v.Op == OpPPC64LoweredGetClosurePtr || v.Op == OpARMLoweredGetClosurePtr || v.Op == OpARM64LoweredGetClosurePtr || v.Op == Op386LoweredGetClosurePtr || v.Op == OpMIPS64LoweredGetClosurePtr:
// We also score GetLoweredClosurePtr as early as possible to ensure that the // We also score GetLoweredClosurePtr as early as possible to ensure that the
// context register is not stomped. GetLoweredClosurePtr should only appear // context register is not stomped. GetLoweredClosurePtr should only appear
// in the entry block where there are no phi functions, so there is no // in the entry block where there are no phi functions, so there is no

View File

@ -400,19 +400,23 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
break break
} }
if p.To.Sym != nil { // retjmp retSym := p.To.Sym
p.As = AJMP p.To.Name = obj.NAME_NONE // clear fields as we may modify p to other instruction
p.To.Type = obj.TYPE_BRANCH p.To.Sym = nil
break
}
if cursym.Text.Mark&LEAF != 0 { if cursym.Text.Mark&LEAF != 0 {
if autosize == 0 { if autosize == 0 {
p.As = AJMP p.As = AJMP
p.From = obj.Addr{} p.From = obj.Addr{}
p.To.Type = obj.TYPE_MEM if retSym != nil { // retjmp
p.To.Offset = 0 p.To.Type = obj.TYPE_BRANCH
p.To.Reg = REGLINK p.To.Name = obj.NAME_EXTERN
p.To.Sym = retSym
} else {
p.To.Type = obj.TYPE_MEM
p.To.Reg = REGLINK
p.To.Offset = 0
}
p.Mark |= BRANCH p.Mark |= BRANCH
break break
} }
@ -444,22 +448,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
p.From.Reg = REGSP p.From.Reg = REGSP
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = REG_R4 p.To.Reg = REG_R4
if retSym != nil { // retjmp from non-leaf, need to restore LINK register
if false { p.To.Reg = REGLINK
// Debug bad returns
q = ctxt.NewProg()
q.As = AMOVV
q.Lineno = p.Lineno
q.From.Type = obj.TYPE_MEM
q.From.Offset = 0
q.From.Reg = REG_R4
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
q.Link = p.Link
p.Link = q
p = q
} }
if autosize != 0 { if autosize != 0 {
@ -479,9 +469,15 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
q1 = ctxt.NewProg() q1 = ctxt.NewProg()
q1.As = AJMP q1.As = AJMP
q1.Lineno = p.Lineno q1.Lineno = p.Lineno
q1.To.Type = obj.TYPE_MEM if retSym != nil { // retjmp
q1.To.Offset = 0 q1.To.Type = obj.TYPE_BRANCH
q1.To.Reg = REG_R4 q1.To.Name = obj.NAME_EXTERN
q1.To.Sym = retSym
} else {
q1.To.Type = obj.TYPE_MEM
q1.To.Offset = 0
q1.To.Reg = REG_R4
}
q1.Mark |= BRANCH q1.Mark |= BRANCH
q1.Spadj = +autosize q1.Spadj = +autosize