Commit 88c8b7c7 authored by Keith Randall's avatar Keith Randall

Merge remote-tracking branch 'origin/dev.ssa' into merge

Merging from dev.ssa back into master.

Contains complete SSA backends for arm, arm64, 386, amd64p32.
Work in progress for PPC64.

Change-Id: Ifd7075e3ec6f88f776e29f8c7fd55830328897fd
parents 31ad583a d08010f9
...@@ -17,6 +17,7 @@ import ( ...@@ -17,6 +17,7 @@ import (
func setArch(goarch string) (*arch.Arch, *obj.Link) { func setArch(goarch string) (*arch.Arch, *obj.Link) {
os.Setenv("GOOS", "linux") // obj can handle this OS for all architectures. os.Setenv("GOOS", "linux") // obj can handle this OS for all architectures.
os.Setenv("GOARCH", goarch)
architecture := arch.Set(goarch) architecture := arch.Set(goarch)
if architecture == nil { if architecture == nil {
panic("asm: unrecognized architecture " + goarch) panic("asm: unrecognized architecture " + goarch)
......
...@@ -239,89 +239,87 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -239,89 +239,87 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
} }
opregreg(v.Op.Asm(), r, gc.SSARegNum(v.Args[1])) opregreg(v.Op.Asm(), r, gc.SSARegNum(v.Args[1]))
case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW, case ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU:
ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU, // Arg[0] (the dividend) is in AX.
ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW, // Arg[1] (the divisor) can be in any other register.
ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU: // Result[0] (the quotient) is in AX.
// Result[1] (the remainder) is in DX.
r := gc.SSARegNum(v.Args[1])
// Arg[0] is already in AX as it's the only register we allow // Zero extend dividend.
// and AX is the only output c := gc.Prog(x86.AXORL)
x := gc.SSARegNum(v.Args[1]) c.From.Type = obj.TYPE_REG
c.From.Reg = x86.REG_DX
// CPU faults upon signed overflow, which occurs when most c.To.Type = obj.TYPE_REG
// negative int is divided by -1. c.To.Reg = x86.REG_DX
var j *obj.Prog
if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
var c *obj.Prog
switch v.Op {
case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
c = gc.Prog(x86.ACMPQ)
j = gc.Prog(x86.AJEQ)
// go ahead and sign extend to save doing it later
gc.Prog(x86.ACQO)
case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
c = gc.Prog(x86.ACMPL)
j = gc.Prog(x86.AJEQ)
gc.Prog(x86.ACDQ)
case ssa.OpAMD64DIVW, ssa.OpAMD64MODW: // Issue divide.
c = gc.Prog(x86.ACMPW) p := gc.Prog(v.Op.Asm())
j = gc.Prog(x86.AJEQ) p.From.Type = obj.TYPE_REG
gc.Prog(x86.ACWD) p.From.Reg = r
}
c.From.Type = obj.TYPE_REG
c.From.Reg = x
c.To.Type = obj.TYPE_CONST
c.To.Offset = -1
j.To.Type = obj.TYPE_BRANCH case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW:
// Arg[0] (the dividend) is in AX.
// Arg[1] (the divisor) can be in any other register.
// Result[0] (the quotient) is in AX.
// Result[1] (the remainder) is in DX.
r := gc.SSARegNum(v.Args[1])
// CPU faults upon signed overflow, which occurs when the most
// negative int is divided by -1. Handle divide by -1 as a special case.
var c *obj.Prog
switch v.Op {
case ssa.OpAMD64DIVQ:
c = gc.Prog(x86.ACMPQ)
case ssa.OpAMD64DIVL:
c = gc.Prog(x86.ACMPL)
case ssa.OpAMD64DIVW:
c = gc.Prog(x86.ACMPW)
} }
c.From.Type = obj.TYPE_REG
c.From.Reg = r
c.To.Type = obj.TYPE_CONST
c.To.Offset = -1
j1 := gc.Prog(x86.AJEQ)
j1.To.Type = obj.TYPE_BRANCH
// for unsigned ints, we sign extend by setting DX = 0 // Sign extend dividend.
// signed ints were sign extended above switch v.Op {
if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU || case ssa.OpAMD64DIVQ:
v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU || gc.Prog(x86.ACQO)
v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU { case ssa.OpAMD64DIVL:
c := gc.Prog(x86.AXORQ) gc.Prog(x86.ACDQ)
c.From.Type = obj.TYPE_REG case ssa.OpAMD64DIVW:
c.From.Reg = x86.REG_DX gc.Prog(x86.ACWD)
c.To.Type = obj.TYPE_REG
c.To.Reg = x86.REG_DX
} }
// Issue divide.
p := gc.Prog(v.Op.Asm()) p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x p.From.Reg = r
// signed division, rest of the check for -1 case // Skip over -1 fixup code.
if j != nil { j2 := gc.Prog(obj.AJMP)
j2 := gc.Prog(obj.AJMP) j2.To.Type = obj.TYPE_BRANCH
j2.To.Type = obj.TYPE_BRANCH
var n *obj.Prog // Issue -1 fixup code.
if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL || // n / -1 = -n
v.Op == ssa.OpAMD64DIVW { n1 := gc.Prog(x86.ANEGQ)
// n * -1 = -n n1.To.Type = obj.TYPE_REG
n = gc.Prog(x86.ANEGQ) n1.To.Reg = x86.REG_AX
n.To.Type = obj.TYPE_REG
n.To.Reg = x86.REG_AX
} else {
// n % -1 == 0
n = gc.Prog(x86.AXORQ)
n.From.Type = obj.TYPE_REG
n.From.Reg = x86.REG_DX
n.To.Type = obj.TYPE_REG
n.To.Reg = x86.REG_DX
}
j.To.Val = n // n % -1 == 0
j2.To.Val = s.Pc() n2 := gc.Prog(x86.AXORL)
} n2.From.Type = obj.TYPE_REG
n2.From.Reg = x86.REG_DX
n2.To.Type = obj.TYPE_REG
n2.To.Reg = x86.REG_DX
// TODO(khr): issue only the -1 fixup code we need.
// For instance, if only the quotient is used, no point in zeroing the remainder.
j1.To.Val = n1
j2.To.Val = s.Pc()
case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB, case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU: ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
...@@ -500,8 +498,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -500,8 +498,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
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 = gc.SSARegNum(v) p.To.Reg = gc.SSARegNum(v)
case ssa.OpAMD64LEAQ: case ssa.OpAMD64LEAQ, ssa.OpAMD64LEAL:
p := gc.Prog(x86.ALEAQ) p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
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)
...@@ -705,7 +703,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -705,7 +703,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg)) p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
p.To.Offset = v.AuxInt p.To.Offset = v.AuxInt
case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy? case ssa.OpCopy, ssa.OpAMD64MOVQconvert, ssa.OpAMD64MOVLconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
if v.Type.IsMemory() { if v.Type.IsMemory() {
return return
} }
...@@ -754,27 +752,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -754,27 +752,14 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Name = obj.NAME_AUTO p.To.Name = obj.NAME_AUTO
} }
case ssa.OpPhi: case ssa.OpPhi:
// just check to make sure regalloc and stackalloc did it right gc.CheckLoweredPhi(v)
if v.Type.IsMemory() {
return
}
f := v.Block.Func
loc := f.RegAlloc[v.ID]
for _, a := range v.Args {
if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
v.Fatalf("phi arg at different location than phi: %v @ %v, but arg %v @ %v\n%s\n", v, loc, a, aloc, v.Block.Func)
}
}
case ssa.OpInitMem: case ssa.OpInitMem:
// memory arg needs no code // memory arg needs no code
case ssa.OpArg: case ssa.OpArg:
// input args need no code // input args need no code
case ssa.OpAMD64LoweredGetClosurePtr: case ssa.OpAMD64LoweredGetClosurePtr:
// Output is hardwired to DX only, // Closure pointer is DX.
// and DX contains the closure pointer on gc.CheckLoweredGetClosurePtr(v)
// closure entry, and this "instruction"
// is scheduled to the very beginning
// of the entry block.
case ssa.OpAMD64LoweredGetG: case ssa.OpAMD64LoweredGetG:
r := gc.SSARegNum(v) r := gc.SSARegNum(v)
// See the comments in cmd/internal/obj/x86/obj6.go // See the comments in cmd/internal/obj/x86/obj6.go
...@@ -871,6 +856,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -871,6 +856,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Reg = gc.SSARegNum(v) p.To.Reg = gc.SSARegNum(v)
case ssa.OpSP, ssa.OpSB: case ssa.OpSP, ssa.OpSB:
// nothing to do // nothing to do
case ssa.OpSelect0, ssa.OpSelect1:
// nothing to do
case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE, case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
ssa.OpAMD64SETL, ssa.OpAMD64SETLE, ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
ssa.OpAMD64SETG, ssa.OpAMD64SETGE, ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
......
...@@ -79,6 +79,8 @@ var progtable = [arm.ALAST & obj.AMask]obj.ProgInfo{ ...@@ -79,6 +79,8 @@ var progtable = [arm.ALAST & obj.AMask]obj.ProgInfo{
arm.AMULF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | RightRdwr}, arm.AMULF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
arm.ASUBD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr}, arm.ASUBD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
arm.ASUBF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | RightRdwr}, arm.ASUBF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
arm.ANEGD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
arm.ANEGF & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | RightRdwr},
arm.ASQRTD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr}, arm.ASQRTD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | RightRdwr},
// Conversions. // Conversions.
......
This diff is collapsed.
...@@ -6,6 +6,7 @@ package arm64 ...@@ -6,6 +6,7 @@ package arm64
import ( import (
"cmd/compile/internal/gc" "cmd/compile/internal/gc"
"cmd/compile/internal/ssa"
"cmd/internal/obj/arm64" "cmd/internal/obj/arm64"
) )
...@@ -61,6 +62,11 @@ func Main() { ...@@ -61,6 +62,11 @@ func Main() {
gc.Thearch.Doregbits = doregbits gc.Thearch.Doregbits = doregbits
gc.Thearch.Regnames = regnames gc.Thearch.Regnames = regnames
gc.Thearch.SSARegToReg = ssaRegToReg
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
gc.Thearch.SSAGenValue = ssaGenValue
gc.Thearch.SSAGenBlock = ssaGenBlock
gc.Main() gc.Main()
gc.Exit(0) gc.Exit(0)
} }
...@@ -44,24 +44,37 @@ var progtable = [arm64.ALAST & obj.AMask]obj.ProgInfo{ ...@@ -44,24 +44,37 @@ var progtable = [arm64.ALAST & obj.AMask]obj.ProgInfo{
// Integer // Integer
arm64.AADD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AADD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ASUB & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.ASUB & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ANEG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.ANEG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, // why RegRead? revisit once the old backend gone
arm64.AAND & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AAND & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AORR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AORR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AEOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AEOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ABIC & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AMVN & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite},
arm64.AMUL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AMUL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AMULW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ASMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.ASMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AUMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AUMULL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ASMULH & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.ASMULH & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AUMULH & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AUMULH & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ASDIV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.ASDIV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AUDIV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AUDIV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ASDIVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AUDIVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AREM & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AUREM & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AREMW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AUREMW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ALSL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.ALSL & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ALSR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.ALSR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AASR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AASR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ACMP & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead}, arm64.ACMP & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead},
arm64.ACMPW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead},
arm64.AADC & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.UseCarry}, arm64.AADC & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.UseCarry},
arm64.AROR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AROR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.ARORW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
arm64.AADDS & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.SetCarry}, arm64.AADDS & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite | gc.SetCarry},
arm64.ACSET & obj.AMask: {Flags: gc.SizeQ | gc.RightWrite},
arm64.ACSEL & obj.AMask: {Flags: gc.SizeQ | gc.RegRead | gc.RightWrite},
// Floating point. // Floating point.
arm64.AFADDD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite}, arm64.AFADDD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
......
This diff is collapsed.
...@@ -95,14 +95,15 @@ const runtimeimport = "" + ...@@ -95,14 +95,15 @@ const runtimeimport = "" +
"4div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64" + "4div\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64div\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x0fint64" +
"mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat6" + "mod\x00\x03\n\x00\n\x00\x01\n\x00\t\x11uint64mod\x00\x03\x14\x00\x14\x00\x01\x14\x00\t\x1bfloat6" +
"4toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t" + "4toint64\x00\x01\x1a\x00\x01\n\x00\t\x1dfloat64touint64\x00\x01\x1a\x00\x01\x14\x00\t" +
"\x1bint64tofloat64\x00\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00" + "\x1dfloat64touint32\x00\x01\x1a\x00\x01\x12\x00\t\x1bint64tofloat64\x00" +
"\x01\x14\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00\x00\x1e\vden·" + "\x01\n\x00\x01\x1a\x00\t\x1duint64tofloat64\x00\x01\x14\x00\x01\x1a\x00\t\x1duint32to" +
"3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16d\x00\t\x17race" + "float64\x00\x01\x12\x00\x01\x1a\x00\t\x19complex128div\x00\x04\x1e\vnum·2\x00" +
"funcexit\x00\x00\x00\t\x0fraceread\x00\x01\x16d\x00\t\x11racewrite\x00\x01\x16" + "\x00\x1e\vden·3\x00\x00\x02\x1e\vquo·1\x00\x00\t\x19racefuncenter\x00\x01\x16" +
"d\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00d\x16\rsize·2\x00" + "d\x00\t\x17racefuncexit\x00\x00\x00\t\x0fraceread\x00\x01\x16d\x00\t\x11race" +
"d\x00\t\x1bracewriterange\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x0fmsanrea" + "write\x00\x01\x16d\x00\t\x19racereadrange\x00\x04\x16\raddr·1\x00d\x16\r" +
"d\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\t\x11msanwrite\x00\x04\x16\x94\x03\x00d\x16\x96\x03\x00d\x00\v\xf4" + "size·2\x00d\x00\t\x1bracewriterange\x00\x04\x16\x98\x03\x00d\x16\x9a\x03\x00d\x00\t" +
"\x01\x02\v\x00\x01\x00\n$$\n" "\x0fmsanread\x00\x04\x16\x98\x03\x00d\x16\x9a\x03\x00d\x00\t\x11msanwrite\x00\x04\x16\x98\x03\x00d" +
"\x16\x9a\x03\x00d\x00\v\xf8\x01\x02\v\x00\x01\x00\n$$\n"
const unsafeimport = "" + const unsafeimport = "" +
"cn\x00\x03v1\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" + "cn\x00\x03v1\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" +
......
...@@ -150,8 +150,10 @@ func int64mod(int64, int64) int64 ...@@ -150,8 +150,10 @@ func int64mod(int64, int64) int64
func uint64mod(uint64, uint64) uint64 func uint64mod(uint64, uint64) uint64
func float64toint64(float64) int64 func float64toint64(float64) int64
func float64touint64(float64) uint64 func float64touint64(float64) uint64
func float64touint32(float64) uint32
func int64tofloat64(int64) float64 func int64tofloat64(int64) float64
func uint64tofloat64(uint64) float64 func uint64tofloat64(uint64) float64
func uint32tofloat64(uint32) float64
func complex128div(num complex128, den complex128) (quo complex128) func complex128div(num complex128, den complex128) (quo complex128)
......
This diff is collapsed.
...@@ -110,6 +110,67 @@ func testSmallIndexType() { ...@@ -110,6 +110,67 @@ func testSmallIndexType() {
} }
} }
//go:noinline
func testInt64Index_ssa(s string, i int64) byte {
return s[i]
}
//go:noinline
func testInt64Slice_ssa(s string, i, j int64) string {
return s[i:j]
}
func testInt64Index() {
tests := []struct {
i int64
j int64
b byte
s string
}{
{0, 5, 'B', "Below"},
{5, 10, 'E', "Exact"},
{10, 15, 'A', "Above"},
}
str := "BelowExactAbove"
for i, t := range tests {
if got := testInt64Index_ssa(str, t.i); got != t.b {
println("#", i, "got ", got, ", wanted", t.b)
failed = true
}
if got := testInt64Slice_ssa(str, t.i, t.j); got != t.s {
println("#", i, "got ", got, ", wanted", t.s)
failed = true
}
}
}
func testInt64IndexPanic() {
defer func() {
if r := recover(); r != nil {
println("paniced as expected")
}
}()
str := "foobar"
println("got ", testInt64Index_ssa(str, 1<<32+1))
println("expected to panic, but didn't")
failed = true
}
func testInt64SlicePanic() {
defer func() {
if r := recover(); r != nil {
println("paniced as expected")
}
}()
str := "foobar"
println("got ", testInt64Slice_ssa(str, 1<<32, 1<<32+1))
println("expected to panic, but didn't")
failed = true
}
//go:noinline //go:noinline
func testStringElem_ssa(s string, i int) byte { func testStringElem_ssa(s string, i int) byte {
return s[i] return s[i]
...@@ -153,6 +214,9 @@ func main() { ...@@ -153,6 +214,9 @@ func main() {
testSmallIndexType() testSmallIndexType()
testStringElem() testStringElem()
testStringElemConst() testStringElemConst()
testInt64Index()
testInt64IndexPanic()
testInt64SlicePanic()
if failed { if failed {
panic("failed") panic("failed")
......
...@@ -1207,6 +1207,7 @@ func (t *Type) ChanDir() ChanDir { ...@@ -1207,6 +1207,7 @@ func (t *Type) ChanDir() ChanDir {
func (t *Type) IsMemory() bool { return false } func (t *Type) IsMemory() bool { return false }
func (t *Type) IsFlags() bool { return false } func (t *Type) IsFlags() bool { return false }
func (t *Type) IsVoid() bool { return false } func (t *Type) IsVoid() bool { return false }
func (t *Type) IsTuple() bool { return false }
// IsUntyped reports whether t is an untyped type. // IsUntyped reports whether t is an untyped type.
func (t *Type) IsUntyped() bool { func (t *Type) IsUntyped() bool {
......
...@@ -1094,12 +1094,45 @@ opswitch: ...@@ -1094,12 +1094,45 @@ opswitch:
if n.Type.IsFloat() { if n.Type.IsFloat() {
if n.Left.Type.Etype == TINT64 { if n.Left.Type.Etype == TINT64 {
n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64])) n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
break break
} }
if n.Left.Type.Etype == TUINT64 { if n.Left.Type.Etype == TUINT64 {
n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64])) n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
break
}
}
}
if Thearch.LinkArch.Family == sys.I386 {
if n.Left.Type.IsFloat() {
if n.Type.Etype == TINT64 {
n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
break
}
if n.Type.Etype == TUINT64 {
n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
break
}
if n.Type.Etype == TUINT32 || n.Type.Etype == TUINTPTR {
n = mkcall("float64touint32", n.Type, init, conv(n.Left, Types[TFLOAT64]))
break
}
}
if n.Type.IsFloat() {
if n.Left.Type.Etype == TINT64 {
n = conv(mkcall("int64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TINT64])), n.Type)
break
}
if n.Left.Type.Etype == TUINT64 {
n = conv(mkcall("uint64tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT64])), n.Type)
break
}
if n.Left.Type.Etype == TUINT32 || n.Left.Type.Etype == TUINTPTR {
n = conv(mkcall("uint32tofloat64", Types[TFLOAT64], init, conv(n.Left, Types[TUINT32])), n.Type)
break break
} }
} }
...@@ -3303,6 +3336,7 @@ func samecheap(a *Node, b *Node) bool { ...@@ -3303,6 +3336,7 @@ func samecheap(a *Node, b *Node) bool {
// The result of walkrotate MUST be assigned back to n, e.g. // The result of walkrotate MUST be assigned back to n, e.g.
// n.Left = walkrotate(n.Left) // n.Left = walkrotate(n.Left)
func walkrotate(n *Node) *Node { func walkrotate(n *Node) *Node {
//TODO: enable LROT on ARM64 once the old backend is gone
if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) { if Thearch.LinkArch.InFamily(sys.MIPS64, sys.ARM64, sys.PPC64) {
return n return n
} }
...@@ -3496,16 +3530,6 @@ func walkdiv(n *Node, init *Nodes) *Node { ...@@ -3496,16 +3530,6 @@ func walkdiv(n *Node, init *Nodes) *Node {
goto ret goto ret
} }
// TODO(zhongwei) Test shows that TUINT8, TINT8, TUINT16 and TINT16's "quick division" method
// on current arm64 backend is slower than hardware div instruction on ARM64 due to unnecessary
// data movement between registers. It could be enabled when generated code is good enough.
if Thearch.LinkArch.Family == sys.ARM64 {
switch Simtype[nl.Type.Etype] {
case TUINT8, TINT8, TUINT16, TINT16:
return n
}
}
switch Simtype[nl.Type.Etype] { switch Simtype[nl.Type.Etype] {
default: default:
return n return n
......
...@@ -66,6 +66,11 @@ func Main() { ...@@ -66,6 +66,11 @@ func Main() {
gc.Thearch.Doregbits = doregbits gc.Thearch.Doregbits = doregbits
gc.Thearch.Regnames = regnames gc.Thearch.Regnames = regnames
gc.Thearch.SSARegToReg = ssaRegToReg
gc.Thearch.SSAMarkMoves = ssaMarkMoves
gc.Thearch.SSAGenValue = ssaGenValue
gc.Thearch.SSAGenBlock = ssaGenBlock
initvariants() initvariants()
initproginfo() initproginfo()
......
...@@ -42,22 +42,34 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{ ...@@ -42,22 +42,34 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
// Integer // Integer
ppc64.AADD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AADD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AADDC & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ASUB & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.ASUB & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AADDME & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ANEG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.ANEG & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AAND & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AAND & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AANDN & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AORN & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AXOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AXOR & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AEQV & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AMULLD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AMULLD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AMULLW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AMULLW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AMULHD & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AMULHD & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AMULHDU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AMULHDU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ADIVD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.ADIVD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ADIVDU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.ADIVDU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ADIVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ADIVWU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ASLD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.ASLD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ASRD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.ASRD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ASRAD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.ASRAD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ASLW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ASRW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ASRAW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.ACMP & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead}, ppc64.ACMP & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
ppc64.ACMPU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead}, ppc64.ACMPU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightRead},
ppc64.ACMPW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
ppc64.ACMPWU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightRead},
ppc64.ATD & obj.AMask: {Flags: gc.SizeQ | gc.RightRead}, ppc64.ATD & obj.AMask: {Flags: gc.SizeQ | gc.RightRead},
// Floating point. // Floating point.
...@@ -70,11 +82,13 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{ ...@@ -70,11 +82,13 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
ppc64.AFDIV & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFDIV & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFDIVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFDIVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCTIDZ & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFCTIDZ & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCTIWZ & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCFID & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFCFID & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCFIDU & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite}, ppc64.AFCFIDU & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RegRead | gc.RightWrite},
ppc64.AFCMPU & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead}, ppc64.AFCMPU & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightRead},
ppc64.AFRSP & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv}, ppc64.AFRSP & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Conv},
ppc64.AFSQRT & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite}, ppc64.AFSQRT & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
ppc64.AFNEG & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite},
// Moves // Moves
ppc64.AMOVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv}, ppc64.AMOVB & obj.AMask: {Flags: gc.SizeB | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
...@@ -91,6 +105,8 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{ ...@@ -91,6 +105,8 @@ var progtable = [ppc64.ALAST & obj.AMask]obj.ProgInfo{
ppc64.AMOVD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move}, ppc64.AMOVD & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move},
ppc64.AMOVDU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc}, ppc64.AMOVDU & obj.AMask: {Flags: gc.SizeQ | gc.LeftRead | gc.RightWrite | gc.Move | gc.PostInc},
ppc64.AFMOVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv}, ppc64.AFMOVS & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
ppc64.AFMOVSX & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
ppc64.AFMOVSZ & obj.AMask: {Flags: gc.SizeF | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
ppc64.AFMOVD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move}, ppc64.AFMOVD & obj.AMask: {Flags: gc.SizeD | gc.LeftRead | gc.RightWrite | gc.Move},
// Jumps // Jumps
......
This diff is collapsed.
...@@ -20,11 +20,18 @@ type Config struct { ...@@ -20,11 +20,18 @@ type Config struct {
lowerBlock func(*Block) bool // lowering function lowerBlock func(*Block) bool // lowering function
lowerValue func(*Value, *Config) bool // lowering function lowerValue func(*Value, *Config) bool // lowering function
registers []Register // machine registers registers []Register // machine registers
gpRegMask regMask // general purpose integer register mask
fpRegMask regMask // floating point register mask
FPReg int8 // register number of frame pointer, -1 if not used
hasGReg bool // has hardware g register
fe Frontend // callbacks into compiler frontend fe Frontend // callbacks into compiler frontend
HTML *HTMLWriter // html writer, for debugging HTML *HTMLWriter // html writer, for debugging
ctxt *obj.Link // Generic arch information ctxt *obj.Link // Generic arch information
optimize bool // Do optimization optimize bool // Do optimization
noDuffDevice bool // Don't use Duff's device noDuffDevice bool // Don't use Duff's device
nacl bool // GOOS=nacl
use387 bool // GO386=387
NeedsFpScratch bool // No direct move between GP and FP register sets
sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
curFunc *Func curFunc *Func
...@@ -106,6 +113,7 @@ type Frontend interface { ...@@ -106,6 +113,7 @@ type Frontend interface {
SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot) SplitSlice(LocalSlot) (LocalSlot, LocalSlot, LocalSlot)
SplitComplex(LocalSlot) (LocalSlot, LocalSlot) SplitComplex(LocalSlot) (LocalSlot, LocalSlot)
SplitStruct(LocalSlot, int) LocalSlot SplitStruct(LocalSlot, int) LocalSlot
SplitInt64(LocalSlot) (LocalSlot, LocalSlot) // returns (hi, lo)
// Line returns a string describing the given line number. // Line returns a string describing the given line number.
Line(int32) string Line(int32) string
...@@ -128,29 +136,87 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config ...@@ -128,29 +136,87 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.lowerBlock = rewriteBlockAMD64 c.lowerBlock = rewriteBlockAMD64
c.lowerValue = rewriteValueAMD64 c.lowerValue = rewriteValueAMD64
c.registers = registersAMD64[:] c.registers = registersAMD64[:]
case "386": c.gpRegMask = gpRegMaskAMD64
c.fpRegMask = fpRegMaskAMD64
c.FPReg = framepointerRegAMD64
c.hasGReg = false
case "amd64p32":
c.IntSize = 4 c.IntSize = 4
c.PtrSize = 4 c.PtrSize = 4
c.lowerBlock = rewriteBlockAMD64 c.lowerBlock = rewriteBlockAMD64
c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support c.lowerValue = rewriteValueAMD64
c.registers = registersAMD64[:]
c.gpRegMask = gpRegMaskAMD64
c.fpRegMask = fpRegMaskAMD64
c.FPReg = framepointerRegAMD64
c.hasGReg = false
c.noDuffDevice = true
case "386":
c.IntSize = 4
c.PtrSize = 4
c.lowerBlock = rewriteBlock386
c.lowerValue = rewriteValue386
c.registers = registers386[:]
c.gpRegMask = gpRegMask386
c.fpRegMask = fpRegMask386
c.FPReg = framepointerReg386
c.hasGReg = false
case "arm": case "arm":
c.IntSize = 4 c.IntSize = 4
c.PtrSize = 4 c.PtrSize = 4
c.lowerBlock = rewriteBlockARM c.lowerBlock = rewriteBlockARM
c.lowerValue = rewriteValueARM c.lowerValue = rewriteValueARM
c.registers = registersARM[:] c.registers = registersARM[:]
c.gpRegMask = gpRegMaskARM
c.fpRegMask = fpRegMaskARM
c.FPReg = framepointerRegARM
c.hasGReg = true
case "arm64":
c.IntSize = 8
c.PtrSize = 8
c.lowerBlock = rewriteBlockARM64
c.lowerValue = rewriteValueARM64
c.registers = registersARM64[:]
c.gpRegMask = gpRegMaskARM64
c.fpRegMask = fpRegMaskARM64
c.FPReg = framepointerRegARM64
c.hasGReg = true
case "ppc64le":
c.IntSize = 8
c.PtrSize = 8
c.lowerBlock = rewriteBlockPPC64
c.lowerValue = rewriteValuePPC64
c.registers = registersPPC64[:]
c.gpRegMask = gpRegMaskPPC64
c.fpRegMask = fpRegMaskPPC64
c.FPReg = framepointerRegPPC64
c.noDuffDevice = true // TODO: Resolve PPC64 DuffDevice (has zero, but not copy)
c.NeedsFpScratch = true
c.hasGReg = true
default: default:
fe.Unimplementedf(0, "arch %s not implemented", arch) fe.Unimplementedf(0, "arch %s not implemented", arch)
} }
c.ctxt = ctxt c.ctxt = ctxt
c.optimize = optimize c.optimize = optimize
c.nacl = obj.Getgoos() == "nacl"
// Don't use Duff's device on Plan 9, because floating // Don't use Duff's device on Plan 9 AMD64, because floating
// point operations are not allowed in note handler. // point operations are not allowed in note handler.
if obj.Getgoos() == "plan9" { if obj.Getgoos() == "plan9" && arch == "amd64" {
c.noDuffDevice = true c.noDuffDevice = true
} }
if c.nacl {
c.noDuffDevice = true // Don't use Duff's device on NaCl
// ARM assembler rewrites DIV/MOD to runtime calls, which
// clobber R12 on nacl
opcodeTable[OpARMDIV].reg.clobbers |= 1 << 12 // R12
opcodeTable[OpARMDIVU].reg.clobbers |= 1 << 12 // R12
opcodeTable[OpARMMOD].reg.clobbers |= 1 << 12 // R12
opcodeTable[OpARMMODU].reg.clobbers |= 1 << 12 // R12
}
// Assign IDs to preallocated values/blocks. // Assign IDs to preallocated values/blocks.
for i := range c.values { for i := range c.values {
c.values[i].ID = ID(i) c.values[i].ID = ID(i)
...@@ -180,6 +246,11 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config ...@@ -180,6 +246,11 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
return c return c
} }
func (c *Config) Set387(b bool) {
c.NeedsFpScratch = b
c.use387 = b
}
func (c *Config) Frontend() Frontend { return c.fe } func (c *Config) Frontend() Frontend { return c.fe }
func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff } func (c *Config) SparsePhiCutoff() uint64 { return c.sparsePhiCutoff }
......
...@@ -163,6 +163,29 @@ func cse(f *Func) { ...@@ -163,6 +163,29 @@ func cse(f *Func) {
} }
} }
// if we rewrite a tuple generator to a new one in a different block,
// copy its selectors to the new generator's block, so tuple generator
// and selectors stay together.
for _, b := range f.Blocks {
for _, v := range b.Values {
if rewrite[v.ID] != nil {
continue
}
if v.Op != OpSelect0 && v.Op != OpSelect1 {
continue
}
if !v.Args[0].Type.IsTuple() {
f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
}
t := rewrite[v.Args[0].ID]
if t != nil && t.Block != b {
// v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
c := v.copyInto(t.Block)
rewrite[v.ID] = c
}
}
}
rewrites := int64(0) rewrites := int64(0)
// Apply substitutions // Apply substitutions
......
...@@ -89,7 +89,7 @@ func dse(f *Func) { ...@@ -89,7 +89,7 @@ func dse(f *Func) {
} else { } else {
// zero addr mem // zero addr mem
sz := v.Args[0].Type.ElemType().Size() sz := v.Args[0].Type.ElemType().Size()
if v.AuxInt != sz { if SizeAndAlign(v.AuxInt).Size() != sz {
f.Fatalf("mismatched zero/store sizes: %d and %d [%s]", f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
v.AuxInt, sz, v.LongString()) v.AuxInt, sz, v.LongString())
} }
......
...@@ -25,6 +25,22 @@ func decomposeBuiltIn(f *Func) { ...@@ -25,6 +25,22 @@ func decomposeBuiltIn(f *Func) {
for _, name := range f.Names { for _, name := range f.Names {
t := name.Type t := name.Type
switch { switch {
case t.IsInteger() && t.Size() == 8 && f.Config.IntSize == 4:
var elemType Type
if t.IsSigned() {
elemType = f.Config.fe.TypeInt32()
} else {
elemType = f.Config.fe.TypeUInt32()
}
hiName, loName := f.Config.fe.SplitInt64(name)
newNames = append(newNames, hiName, loName)
for _, v := range f.NamedValues[name] {
hi := v.Block.NewValue1(v.Line, OpInt64Hi, elemType, v)
lo := v.Block.NewValue1(v.Line, OpInt64Lo, f.Config.fe.TypeUInt32(), v)
f.NamedValues[hiName] = append(f.NamedValues[hiName], hi)
f.NamedValues[loName] = append(f.NamedValues[loName], lo)
}
delete(f.NamedValues, name)
case t.IsComplex(): case t.IsComplex():
var elemType Type var elemType Type
if t.Size() == 16 { if t.Size() == 16 {
...@@ -78,6 +94,8 @@ func decomposeBuiltIn(f *Func) { ...@@ -78,6 +94,8 @@ func decomposeBuiltIn(f *Func) {
f.NamedValues[dataName] = append(f.NamedValues[dataName], data) f.NamedValues[dataName] = append(f.NamedValues[dataName], data)
} }
delete(f.NamedValues, name) delete(f.NamedValues, name)
case t.IsFloat():
// floats are never decomposed, even ones bigger than IntSize
case t.Size() > f.Config.IntSize: case t.Size() > f.Config.IntSize:
f.Unimplementedf("undecomposed named type %s %s", name, t) f.Unimplementedf("undecomposed named type %s %s", name, t)
default: default:
...@@ -88,8 +106,13 @@ func decomposeBuiltIn(f *Func) { ...@@ -88,8 +106,13 @@ func decomposeBuiltIn(f *Func) {
} }
func decomposeBuiltInPhi(v *Value) { func decomposeBuiltInPhi(v *Value) {
// TODO: decompose 64-bit ops on 32-bit archs?
switch { switch {
case v.Type.IsInteger() && v.Type.Size() == 8 && v.Block.Func.Config.IntSize == 4:
if v.Block.Func.Config.arch == "amd64p32" {
// Even though ints are 32 bits, we have 64-bit ops.
break
}
decomposeInt64Phi(v)
case v.Type.IsComplex(): case v.Type.IsComplex():
decomposeComplexPhi(v) decomposeComplexPhi(v)
case v.Type.IsString(): case v.Type.IsString():
...@@ -98,6 +121,8 @@ func decomposeBuiltInPhi(v *Value) { ...@@ -98,6 +121,8 @@ func decomposeBuiltInPhi(v *Value) {
decomposeSlicePhi(v) decomposeSlicePhi(v)
case v.Type.IsInterface(): case v.Type.IsInterface():
decomposeInterfacePhi(v) decomposeInterfacePhi(v)
case v.Type.IsFloat():
// floats are never decomposed, even ones bigger than IntSize
case v.Type.Size() > v.Block.Func.Config.IntSize: case v.Type.Size() > v.Block.Func.Config.IntSize:
v.Unimplementedf("undecomposed type %s", v.Type) v.Unimplementedf("undecomposed type %s", v.Type)
} }
...@@ -138,6 +163,26 @@ func decomposeSlicePhi(v *Value) { ...@@ -138,6 +163,26 @@ func decomposeSlicePhi(v *Value) {
v.AddArg(cap) v.AddArg(cap)
} }
func decomposeInt64Phi(v *Value) {
fe := v.Block.Func.Config.fe
var partType Type
if v.Type.IsSigned() {
partType = fe.TypeInt32()
} else {
partType = fe.TypeUInt32()
}
hi := v.Block.NewValue0(v.Line, OpPhi, partType)
lo := v.Block.NewValue0(v.Line, OpPhi, fe.TypeUInt32())
for _, a := range v.Args {
hi.AddArg(a.Block.NewValue1(v.Line, OpInt64Hi, partType, a))
lo.AddArg(a.Block.NewValue1(v.Line, OpInt64Lo, fe.TypeUInt32(), a))
}
v.reset(OpInt64Make)
v.AddArg(hi)
v.AddArg(lo)
}
func decomposeComplexPhi(v *Value) { func decomposeComplexPhi(v *Value) {
fe := v.Block.Func.Config.fe fe := v.Block.Func.Config.fe
var partType Type var partType Type
......
...@@ -49,6 +49,12 @@ func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) { ...@@ -49,6 +49,12 @@ func (d DummyFrontend) SplitComplex(s LocalSlot) (LocalSlot, LocalSlot) {
} }
return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), s.Off + 4} return LocalSlot{s.N, d.TypeFloat32(), s.Off}, LocalSlot{s.N, d.TypeFloat32(), s.Off + 4}
} }
func (d DummyFrontend) SplitInt64(s LocalSlot) (LocalSlot, LocalSlot) {
if s.Type.IsSigned() {
return LocalSlot{s.N, d.TypeInt32(), s.Off + 4}, LocalSlot{s.N, d.TypeUInt32(), s.Off}
}
return LocalSlot{s.N, d.TypeUInt32(), s.Off + 4}, LocalSlot{s.N, d.TypeUInt32(), s.Off}
}
func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot { func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)} return LocalSlot{s.N, s.Type.FieldType(i), s.Off + s.Type.FieldOff(i)}
} }
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
package ssa package ssa
const flagRegMask = regMask(1) << 33 // TODO: arch-specific
// flagalloc allocates the flag register among all the flag-generating // flagalloc allocates the flag register among all the flag-generating
// instructions. Flag values are recomputed if they need to be // instructions. Flag values are recomputed if they need to be
// spilled/restored. // spilled/restored.
...@@ -33,7 +31,7 @@ func flagalloc(f *Func) { ...@@ -33,7 +31,7 @@ func flagalloc(f *Func) {
if v == flag { if v == flag {
flag = nil flag = nil
} }
if opcodeTable[v.Op].reg.clobbers&flagRegMask != 0 { if opcodeTable[v.Op].clobberFlags {
flag = nil flag = nil
} }
for _, a := range v.Args { for _, a := range v.Args {
...@@ -97,7 +95,7 @@ func flagalloc(f *Func) { ...@@ -97,7 +95,7 @@ func flagalloc(f *Func) {
continue continue
} }
// Recalculate a // Recalculate a
c := a.copyInto(b) c := copyFlags(a, b)
// Update v. // Update v.
v.SetArg(i, c) v.SetArg(i, c)
// Remember the most-recently computed flag value. // Remember the most-recently computed flag value.
...@@ -105,7 +103,7 @@ func flagalloc(f *Func) { ...@@ -105,7 +103,7 @@ func flagalloc(f *Func) {
} }
// Issue v. // Issue v.
b.Values = append(b.Values, v) b.Values = append(b.Values, v)
if opcodeTable[v.Op].reg.clobbers&flagRegMask != 0 { if opcodeTable[v.Op].clobberFlags {
flag = nil flag = nil
} }
if v.Type.IsFlags() { if v.Type.IsFlags() {
...@@ -121,7 +119,7 @@ func flagalloc(f *Func) { ...@@ -121,7 +119,7 @@ func flagalloc(f *Func) {
if v := end[b.ID]; v != nil && v != flag { if v := end[b.ID]; v != nil && v != flag {
// Need to reissue flag generator for use by // Need to reissue flag generator for use by
// subsequent blocks. // subsequent blocks.
_ = v.copyInto(b) copyFlags(v, b)
// Note: this flag generator is not properly linked up // Note: this flag generator is not properly linked up
// with the flag users. This breaks the SSA representation. // with the flag users. This breaks the SSA representation.
// We could fix up the users with another pass, but for now // We could fix up the users with another pass, but for now
...@@ -135,3 +133,19 @@ func flagalloc(f *Func) { ...@@ -135,3 +133,19 @@ func flagalloc(f *Func) {
b.FlagsLiveAtEnd = end[b.ID] != nil b.FlagsLiveAtEnd = end[b.ID] != nil
} }
} }
// copyFlags copies v (flag generator) into b, returns the copy.
// If v's arg is also flags, copy recursively.
func copyFlags(v *Value, b *Block) *Value {
flagsArgs := make(map[int]*Value)
for i, a := range v.Args {
if a.Type.IsFlags() || a.Type.IsTuple() {
flagsArgs[i] = copyFlags(a, b)
}
}
c := v.copyInto(b)
for i, a := range flagsArgs {
c.SetArg(i, a)
}
return c
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build ignore
package main
var dec64Ops = []opData{}
var dec64Blocks = []blockData{}
func init() {
archs = append(archs, arch{
name: "dec64",
ops: dec64Ops,
blocks: dec64Blocks,
generic: true,
})
}
...@@ -67,6 +67,12 @@ ...@@ -67,6 +67,12 @@
(Const32F [f2i(float64(i2f32(c) * i2f32(d)))]) (Const32F [f2i(float64(i2f32(c) * i2f32(d)))])
(Mul64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) * i2f(d))]) (Mul64F (Const64F [c]) (Const64F [d])) -> (Const64F [f2i(i2f(c) * i2f(d))])
// Convert x * -1 to -x. The front-end catches some but not all of these.
(Mul8 (Const8 [-1]) x) -> (Neg8 x)
(Mul16 (Const16 [-1]) x) -> (Neg16 x)
(Mul32 (Const32 [-1]) x) -> (Neg32 x)
(Mul64 (Const64 [-1]) x) -> (Neg64 x)
(Mod8 (Const8 [c]) (Const8 [d])) && d != 0 -> (Const8 [int64(int8(c % d))]) (Mod8 (Const8 [c]) (Const8 [d])) && d != 0 -> (Const8 [int64(int8(c % d))])
(Mod16 (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(int16(c % d))]) (Mod16 (Const16 [c]) (Const16 [d])) && d != 0 -> (Const16 [int64(int16(c % d))])
(Mod32 (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(int32(c % d))]) (Mod32 (Const32 [c]) (Const32 [d])) && d != 0 -> (Const32 [int64(int32(c % d))])
...@@ -625,8 +631,10 @@ ...@@ -625,8 +631,10 @@
(Store [t.FieldType(0).Size()] dst f0 mem)))) (Store [t.FieldType(0).Size()] dst f0 mem))))
// un-SSAable values use mem->mem copies // un-SSAable values use mem->mem copies
(Store [size] dst (Load <t> src mem) mem) && !config.fe.CanSSA(t) -> (Move [size] dst src mem) (Store [size] dst (Load <t> src mem) mem) && !config.fe.CanSSA(t) ->
(Store [size] dst (Load <t> src mem) (VarDef {x} mem)) && !config.fe.CanSSA(t) -> (Move [size] dst src (VarDef {x} mem)) (Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src mem)
(Store [size] dst (Load <t> src mem) (VarDef {x} mem)) && !config.fe.CanSSA(t) ->
(Move [MakeSizeAndAlign(size, t.Alignment()).Int64()] dst src (VarDef {x} mem))
// string ops // string ops
// Decomposing StringMake and lowering of StringPtr and StringLen // Decomposing StringMake and lowering of StringPtr and StringLen
...@@ -832,3 +840,23 @@ ...@@ -832,3 +840,23 @@
-> (Sub64 x (Mul64 <t> (Div64 <t> x (Const64 <t> [c])) (Const64 <t> [c]))) -> (Sub64 x (Mul64 <t> (Div64 <t> x (Const64 <t> [c])) (Const64 <t> [c])))
(Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && umagic64ok(c) (Mod64u <t> x (Const64 [c])) && x.Op != OpConst64 && umagic64ok(c)
-> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c]))) -> (Sub64 x (Mul64 <t> (Div64u <t> x (Const64 <t> [c])) (Const64 <t> [c])))
// floating point optimizations
(Add32F x (Const32F [0])) -> x
(Add32F (Const32F [0]) x) -> x
(Add64F x (Const64F [0])) -> x
(Add64F (Const64F [0]) x) -> x
(Sub32F x (Const32F [0])) -> x
(Sub64F x (Const64F [0])) -> x
(Mul32F x (Const32F [f2i(1)])) -> x
(Mul32F (Const32F [f2i(1)]) x) -> x
(Mul64F x (Const64F [f2i(1)])) -> x
(Mul64F (Const64F [f2i(1)]) x) -> x
(Mul32F x (Const32F [f2i(-1)])) -> (Neg32F x)
(Mul32F (Const32F [f2i(-1)]) x) -> (Neg32F x)
(Mul64F x (Const64F [f2i(-1)])) -> (Neg64F x)
(Mul64F (Const64F [f2i(-1)]) x) -> (Neg64F x)
(Div32F x (Const32F [f2i(1)])) -> x
(Div64F x (Const64F [f2i(1)])) -> x
(Div32F x (Const32F [f2i(-1)])) -> (Neg32F x)
(Div64F x (Const64F [f2i(-1)])) -> (Neg32F x)
...@@ -21,13 +21,16 @@ import ( ...@@ -21,13 +21,16 @@ import (
) )
type arch struct { type arch struct {
name string name string
pkg string // obj package to import for this arch. pkg string // obj package to import for this arch.
genfile string // source file containing opcode code generation. genfile string // source file containing opcode code generation.
ops []opData ops []opData
blocks []blockData blocks []blockData
regnames []string regnames []string
generic bool gpregmask regMask
fpregmask regMask
framepointerreg int8
generic bool
} }
type opData struct { type opData struct {
...@@ -38,8 +41,9 @@ type opData struct { ...@@ -38,8 +41,9 @@ type opData struct {
aux string aux string
rematerializeable bool rematerializeable bool
argLength int32 // number of arguments, if -1, then this operation has a variable number of arguments argLength int32 // number of arguments, if -1, then this operation has a variable number of arguments
commutative bool // this operation is commutative (e.g. addition) commutative bool // this operation is commutative on its first 2 arguments (e.g. addition)
resultInArg0 bool // v and v.Args[0] must be allocated to the same register resultInArg0 bool // last output of v and v.Args[0] must be allocated to the same register
clobberFlags bool // this op clobbers flags register
} }
type blockData struct { type blockData struct {
...@@ -73,6 +77,7 @@ var archs []arch ...@@ -73,6 +77,7 @@ var archs []arch
func main() { func main() {
flag.Parse() flag.Parse()
sort.Sort(ArchsByName(archs))
genOp() genOp()
genLower() genLower()
} }
...@@ -155,13 +160,16 @@ func genOp() { ...@@ -155,13 +160,16 @@ func genOp() {
} }
if v.resultInArg0 { if v.resultInArg0 {
fmt.Fprintln(w, "resultInArg0: true,") fmt.Fprintln(w, "resultInArg0: true,")
if v.reg.inputs[0] != v.reg.outputs[0] { if v.reg.inputs[0] != v.reg.outputs[len(v.reg.outputs)-1] {
log.Fatalf("input[0] and output registers must be equal for %s", v.name) log.Fatalf("input[0] and last output register must be equal for %s", v.name)
} }
if v.commutative && v.reg.inputs[1] != v.reg.outputs[0] { if v.commutative && v.reg.inputs[1] != v.reg.outputs[len(v.reg.outputs)-1] {
log.Fatalf("input[1] and output registers must be equal for %s", v.name) log.Fatalf("input[1] and last output register must be equal for %s", v.name)
} }
} }
if v.clobberFlags {
fmt.Fprintln(w, "clobberFlags: true,")
}
if a.name == "generic" { if a.name == "generic" {
fmt.Fprintln(w, "generic:true,") fmt.Fprintln(w, "generic:true,")
fmt.Fprintln(w, "},") // close op fmt.Fprintln(w, "},") // close op
...@@ -191,14 +199,22 @@ func genOp() { ...@@ -191,14 +199,22 @@ func genOp() {
} }
fmt.Fprintln(w, "},") fmt.Fprintln(w, "},")
} }
if v.reg.clobbers > 0 { if v.reg.clobbers > 0 {
fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers)) fmt.Fprintf(w, "clobbers: %d,%s\n", v.reg.clobbers, a.regMaskComment(v.reg.clobbers))
} }
// reg outputs // reg outputs
if len(v.reg.outputs) > 0 { s = s[:0]
fmt.Fprintln(w, "outputs: []regMask{") for i, r := range v.reg.outputs {
for _, r := range v.reg.outputs { s = append(s, intPair{countRegs(r), i})
fmt.Fprintf(w, "%d,%s\n", r, a.regMaskComment(r)) }
if len(s) > 0 {
sort.Sort(byKey(s))
fmt.Fprintln(w, "outputs: []outputInfo{")
for _, p := range s {
r := v.reg.outputs[p.val]
fmt.Fprintf(w, "{%d,%d},%s\n", p.val, r, a.regMaskComment(r))
} }
fmt.Fprintln(w, "},") fmt.Fprintln(w, "},")
} }
...@@ -223,6 +239,9 @@ func genOp() { ...@@ -223,6 +239,9 @@ func genOp() {
fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r) fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r)
} }
fmt.Fprintln(w, "}") fmt.Fprintln(w, "}")
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 framepointerReg%s = int8(%d)\n", a.name, a.framepointerreg)
} }
// gofmt result // gofmt result
...@@ -298,3 +317,9 @@ type byKey []intPair ...@@ -298,3 +317,9 @@ type byKey []intPair
func (a byKey) Len() int { return len(a) } func (a byKey) Len() int { return len(a) }
func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byKey) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key } func (a byKey) Less(i, j int) bool { return a[i].key < a[j].key }
type ArchsByName []arch
func (x ArchsByName) Len() int { return len(x) }
func (x ArchsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
func (x ArchsByName) Less(i, j int) bool { return x[i].name < x[j].name }
This diff is collapsed.
...@@ -359,7 +359,7 @@ func (v *Value) LongHTML() string { ...@@ -359,7 +359,7 @@ func (v *Value) LongHTML() string {
} }
r := v.Block.Func.RegAlloc r := v.Block.Func.RegAlloc
if int(v.ID) < len(r) && r[v.ID] != nil { if int(v.ID) < len(r) && r[v.ID] != nil {
s += " : " + r[v.ID].Name() s += " : " + html.EscapeString(r[v.ID].Name())
} }
s += "</span>" s += "</span>"
return s return s
......
...@@ -36,3 +36,16 @@ func (s LocalSlot) Name() string { ...@@ -36,3 +36,16 @@ func (s LocalSlot) Name() string {
} }
return fmt.Sprintf("%s+%d[%s]", s.N, s.Off, s.Type) return fmt.Sprintf("%s+%d[%s]", s.N, s.Off, s.Type)
} }
type LocPair [2]Location
func (t LocPair) Name() string {
n0, n1 := "nil", "nil"
if t[0] != nil {
n0 = t[0].Name()
}
if t[1] != nil {
n1 = t[1].Name()
}
return fmt.Sprintf("<%s,%s>", n0, n1)
}
...@@ -21,10 +21,15 @@ func checkLower(f *Func) { ...@@ -21,10 +21,15 @@ func checkLower(f *Func) {
continue // lowered continue // lowered
} }
switch v.Op { switch v.Op {
case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive: case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1:
continue // ok not to lower continue // ok not to lower
case OpGetG:
if f.Config.hasGReg {
// has hardware g register, regalloc takes care of it
continue // ok not to lower
}
} }
s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString() s := "not lowered: " + v.String() + ", " + v.Op.String() + " " + v.Type.SimpleString()
for _, a := range v.Args { for _, a := range v.Args {
s += " " + a.Type.SimpleString() s += " " + a.Type.SimpleString()
} }
......
...@@ -26,7 +26,8 @@ type opInfo struct { ...@@ -26,7 +26,8 @@ type opInfo struct {
generic bool // this is a generic (arch-independent) opcode generic bool // this is a generic (arch-independent) opcode
rematerializeable bool // this op is rematerializeable rematerializeable bool // this op is rematerializeable
commutative bool // this operation is commutative (e.g. addition) commutative bool // this operation is commutative (e.g. addition)
resultInArg0 bool // v and v.Args[0] must be allocated to the same register resultInArg0 bool // last output of v and v.Args[0] must be allocated to the same register
clobberFlags bool // this op clobbers flags register
} }
type inputInfo struct { type inputInfo struct {
...@@ -34,10 +35,15 @@ type inputInfo struct { ...@@ -34,10 +35,15 @@ type inputInfo struct {
regs regMask // allowed input registers regs regMask // allowed input registers
} }
type outputInfo struct {
idx int // index in output tuple
regs regMask // allowed output registers
}
type regInfo struct { type regInfo struct {
inputs []inputInfo // ordered in register allocation order inputs []inputInfo // ordered in register allocation order
clobbers regMask clobbers regMask
outputs []regMask // NOTE: values can only have 1 output for now. outputs []outputInfo // ordered in register allocation order
} }
type auxType int8 type auxType int8
...@@ -124,3 +130,31 @@ func (x ValAndOff) add(off int64) int64 { ...@@ -124,3 +130,31 @@ func (x ValAndOff) add(off int64) int64 {
} }
return makeValAndOff(x.Val(), x.Off()+off) return makeValAndOff(x.Val(), x.Off()+off)
} }
// SizeAndAlign holds both the size and the alignment of a type,
// used in Zero and Move ops.
// The high 8 bits hold the alignment.
// The low 56 bits hold the size.
type SizeAndAlign int64
func (x SizeAndAlign) Size() int64 {
return int64(x) & (1<<56 - 1)
}
func (x SizeAndAlign) Align() int64 {
return int64(uint64(x) >> 56)
}
func (x SizeAndAlign) Int64() int64 {
return int64(x)
}
func (x SizeAndAlign) String() string {
return fmt.Sprintf("size=%d,align=%d", x.Size(), x.Align())
}
func MakeSizeAndAlign(size, align int64) SizeAndAlign {
if size&^(1<<56-1) != 0 {
panic("size too big in SizeAndAlign")
}
if align >= 1<<8 {
panic("alignment too big in SizeAndAlign")
}
return SizeAndAlign(size | align<<56)
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// +build !amd64 // +build !amd64,!arm,!amd64p32,!386,!arm64
// errorcheck -0 -l -live -wb=0 // errorcheck -0 -l -live -wb=0
// Copyright 2014 The Go Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment