aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/ppc64/ssa.go
diff options
context:
space:
mode:
authorDavid Chase <drchase@google.com>2016-08-10 11:44:57 -0700
committerDavid Chase <drchase@google.com>2016-08-15 14:47:49 +0000
commitd08010f94e06e5d5b6d01c248ba2a976b75d95a2 (patch)
treedf74490d9fecdccb5f75f7786ffa19f892cdb5ed /src/cmd/compile/internal/ppc64/ssa.go
parentd99cee79b98dfb6c1cd8e64c96845ee29aa28b4c (diff)
downloadgo-d08010f94e06e5d5b6d01c248ba2a976b75d95a2.tar.gz
go-d08010f94e06e5d5b6d01c248ba2a976b75d95a2.zip
[dev.ssa] cmd/compile: PPC64, FP to/from int conversions.dev.ssa
Passes ssa_test. Requires a few new instructions and some scratchpad memory to move data between G and F registers. Also fixed comparisons to be correct in case of NaN. Added missing instructions for run.bash. Removed some FP registers that are apparently "reserved" (but that are also apparently also unused except for a gratuitous multiplication by two when y = x+x would work just as well). Currently failing stack splits. Updates #16010. Change-Id: I73b161bfff54445d72bd7b813b1479f89fc72602 Reviewed-on: https://go-review.googlesource.com/26813 Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/cmd/compile/internal/ppc64/ssa.go')
-rw-r--r--src/cmd/compile/internal/ppc64/ssa.go175
1 files changed, 128 insertions, 47 deletions
diff --git a/src/cmd/compile/internal/ppc64/ssa.go b/src/cmd/compile/internal/ppc64/ssa.go
index 1aca551091..b6d06f88e1 100644
--- a/src/cmd/compile/internal/ppc64/ssa.go
+++ b/src/cmd/compile/internal/ppc64/ssa.go
@@ -73,11 +73,11 @@ var ssaRegToReg = []int16{
ppc64.REG_F24,
ppc64.REG_F25,
ppc64.REG_F26,
- ppc64.REG_F27,
- ppc64.REG_F28,
- ppc64.REG_F29,
- ppc64.REG_F30,
- ppc64.REG_F31,
+ // ppc64.REG_F27, // reserved for "floating conversion constant"
+ // ppc64.REG_F28, // 0.0
+ // ppc64.REG_F29, // 0.5
+ // ppc64.REG_F30, // 1.0
+ // ppc64.REG_F31, // 2.0
// ppc64.REG_CR0,
// ppc64.REG_CR1,
@@ -88,21 +88,12 @@ var ssaRegToReg = []int16{
// ppc64.REG_CR6,
// ppc64.REG_CR7,
- ppc64.REG_CR,
+ // ppc64.REG_CR,
// ppc64.REG_XER,
// ppc64.REG_LR,
// ppc64.REG_CTR,
}
-// Associated condition bit
-var condBits = map[ssa.Op]uint8{
- ssa.OpPPC64Equal: ppc64.C_COND_EQ,
- ssa.OpPPC64NotEqual: ppc64.C_COND_EQ,
- ssa.OpPPC64LessThan: ppc64.C_COND_LT,
- ssa.OpPPC64GreaterEqual: ppc64.C_COND_LT,
- ssa.OpPPC64GreaterThan: ppc64.C_COND_GT,
- ssa.OpPPC64LessEqual: ppc64.C_COND_GT,
-}
var condOps = map[ssa.Op]obj.As{
ssa.OpPPC64Equal: ppc64.ABEQ,
ssa.OpPPC64NotEqual: ppc64.ABNE,
@@ -110,16 +101,11 @@ var condOps = map[ssa.Op]obj.As{
ssa.OpPPC64GreaterEqual: ppc64.ABGE,
ssa.OpPPC64GreaterThan: ppc64.ABGT,
ssa.OpPPC64LessEqual: ppc64.ABLE,
-}
-// Is the condition bit set? 1=yes 0=no
-var condBitSet = map[ssa.Op]uint8{
- ssa.OpPPC64Equal: 1,
- ssa.OpPPC64NotEqual: 0,
- ssa.OpPPC64LessThan: 1,
- ssa.OpPPC64GreaterEqual: 0,
- ssa.OpPPC64GreaterThan: 1,
- ssa.OpPPC64LessEqual: 0,
+ ssa.OpPPC64FLessThan: ppc64.ABLT, // 1 branch for FCMP
+ ssa.OpPPC64FGreaterThan: ppc64.ABGT, // 1 branch for FCMP
+ ssa.OpPPC64FLessEqual: ppc64.ABLT, // 2 branches for FCMP <=, second is BEQ
+ ssa.OpPPC64FGreaterEqual: ppc64.ABGT, // 2 branches for FCMP >=, second is BEQ
}
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
@@ -205,6 +191,17 @@ func storeByType(t ssa.Type) obj.As {
panic("bad store type")
}
+// scratchFpMem initializes an Addr (field of a Prog)
+// to reference the scratchpad memory for movement between
+// F and G registers for FP conversions.
+func scratchFpMem(s *gc.SSAGenState, a *obj.Addr) {
+ a.Type = obj.TYPE_MEM
+ a.Name = obj.NAME_AUTO
+ a.Node = s.ScratchFpMem
+ a.Sym = gc.Linksym(s.ScratchFpMem.Sym)
+ a.Reg = ppc64.REGSP
+}
+
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
switch v.Op {
@@ -212,22 +209,55 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
// memory arg needs no code
case ssa.OpArg:
// input args need no code
- case ssa.OpSP, ssa.OpSB:
+ case ssa.OpSP, ssa.OpSB, ssa.OpGetG:
// nothing to do
case ssa.OpCopy, ssa.OpPPC64MOVDconvert:
- // TODO: copy of floats
- if v.Type.IsMemory() {
+ t := v.Type
+ if t.IsMemory() {
return
}
x := gc.SSARegNum(v.Args[0])
y := gc.SSARegNum(v)
if x != y {
- p := gc.Prog(ppc64.AMOVD)
+ rt := obj.TYPE_REG
+ op := ppc64.AMOVD
+
+ if t.IsFloat() {
+ op = ppc64.AFMOVD
+ }
+ p := gc.Prog(op)
+ p.From.Type = rt
+ p.From.Reg = x
+ p.To.Type = rt
+ p.To.Reg = y
+ }
+
+ case ssa.OpPPC64Xf2i64:
+ {
+ x := gc.SSARegNum(v.Args[0])
+ y := gc.SSARegNum(v)
+ p := gc.Prog(ppc64.AFMOVD)
p.From.Type = obj.TYPE_REG
p.From.Reg = x
+ scratchFpMem(s, &p.To)
+ p = gc.Prog(ppc64.AMOVD)
+ p.To.Type = obj.TYPE_REG
p.To.Reg = y
+ scratchFpMem(s, &p.From)
+ }
+ case ssa.OpPPC64Xi2f64:
+ {
+ x := gc.SSARegNum(v.Args[0])
+ y := gc.SSARegNum(v)
+ p := gc.Prog(ppc64.AMOVD)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = x
+ scratchFpMem(s, &p.To)
+ p = gc.Prog(ppc64.AFMOVD)
p.To.Type = obj.TYPE_REG
+ p.To.Reg = y
+ scratchFpMem(s, &p.From)
}
case ssa.OpPPC64LoweredGetClosurePtr:
@@ -235,8 +265,9 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.CheckLoweredGetClosurePtr(v)
case ssa.OpLoadReg:
- p := gc.Prog(loadByType(v.Type))
+ loadOp := loadByType(v.Type)
n, off := gc.AutoVar(v.Args[0])
+ p := gc.Prog(loadOp)
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
@@ -251,10 +282,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Reg = gc.SSARegNum(v)
case ssa.OpStoreReg:
- p := gc.Prog(storeByType(v.Type))
+ storeOp := storeByType(v.Type)
+ n, off := gc.AutoVar(v)
+ p := gc.Prog(storeOp)
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[0])
- n, off := gc.AutoVar(v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
@@ -376,7 +408,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = ppc64.REGTMP // Ignored; this is for the carry effect.
- case ssa.OpPPC64NEG, ssa.OpPPC64FNEG:
+ case ssa.OpPPC64NEG, ssa.OpPPC64FNEG, ssa.OpPPC64FSQRT, ssa.OpPPC64FSQRTS, ssa.OpPPC64FCTIDZ, ssa.OpPPC64FCTIWZ, ssa.OpPPC64FCFID, ssa.OpPPC64FRSP:
r := gc.SSARegNum(v)
p := gc.Prog(v.Op.Asm())
p.To.Type = obj.TYPE_REG
@@ -510,8 +542,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpPPC64Equal,
ssa.OpPPC64NotEqual,
ssa.OpPPC64LessThan,
+ ssa.OpPPC64FLessThan,
ssa.OpPPC64LessEqual,
ssa.OpPPC64GreaterThan,
+ ssa.OpPPC64FGreaterThan,
ssa.OpPPC64GreaterEqual:
// On Power7 or later, can use isel instruction:
// for a < b, a > b, a = b:
@@ -549,6 +583,30 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p = gc.Prog(obj.ANOP)
gc.Patch(pb, p)
+ case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion
+ ssa.OpPPC64FGreaterEqual:
+
+ p := gc.Prog(ppc64.AMOVW)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = 1
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = gc.SSARegNum(v)
+
+ pb0 := gc.Prog(condOps[v.Op])
+ pb0.To.Type = obj.TYPE_BRANCH
+ pb1 := gc.Prog(ppc64.ABEQ)
+ pb1.To.Type = obj.TYPE_BRANCH
+
+ p = gc.Prog(ppc64.AMOVW)
+ p.From.Type = obj.TYPE_CONST
+ p.From.Offset = 0
+ p.To.Type = obj.TYPE_REG
+ p.To.Reg = gc.SSARegNum(v)
+
+ p = gc.Prog(obj.ANOP)
+ gc.Patch(pb0, p)
+ gc.Patch(pb1, p)
+
case ssa.OpPPC64LoweredZero:
// Similar to how this is done on ARM,
// except that PPC MOVDU x,off(y) is *(y+off) = x; y=y+off
@@ -843,20 +901,22 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
}
var blockJump = [...]struct {
- asm, invasm obj.As
+ asm, invasm obj.As
+ asmeq, invasmeq bool
}{
- ssa.BlockPPC64EQ: {ppc64.ABEQ, ppc64.ABNE},
- ssa.BlockPPC64NE: {ppc64.ABNE, ppc64.ABEQ},
-
- ssa.BlockPPC64LT: {ppc64.ABLT, ppc64.ABGE},
- ssa.BlockPPC64GE: {ppc64.ABGE, ppc64.ABLT},
- ssa.BlockPPC64LE: {ppc64.ABLE, ppc64.ABGT},
- ssa.BlockPPC64GT: {ppc64.ABGT, ppc64.ABLE},
-
- ssa.BlockPPC64ULT: {ppc64.ABLT, ppc64.ABGE},
- ssa.BlockPPC64UGE: {ppc64.ABGE, ppc64.ABLT},
- ssa.BlockPPC64ULE: {ppc64.ABLE, ppc64.ABGT},
- ssa.BlockPPC64UGT: {ppc64.ABGT, ppc64.ABLE},
+ ssa.BlockPPC64EQ: {ppc64.ABEQ, ppc64.ABNE, false, false},
+ ssa.BlockPPC64NE: {ppc64.ABNE, ppc64.ABEQ, false, false},
+
+ ssa.BlockPPC64LT: {ppc64.ABLT, ppc64.ABGE, false, false},
+ ssa.BlockPPC64GE: {ppc64.ABGE, ppc64.ABLT, false, false},
+ ssa.BlockPPC64LE: {ppc64.ABLE, ppc64.ABGT, false, false},
+ ssa.BlockPPC64GT: {ppc64.ABGT, ppc64.ABLE, false, false},
+
+ // TODO: need to work FP comparisons into block jumps
+ ssa.BlockPPC64FLT: {ppc64.ABLT, ppc64.ABGT, false, true},
+ ssa.BlockPPC64FGE: {ppc64.ABGT, ppc64.ABLT, true, false},
+ ssa.BlockPPC64FLE: {ppc64.ABLT, ppc64.ABGT, true, false},
+ ssa.BlockPPC64FGT: {ppc64.ABGT, ppc64.ABLT, false, true},
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
@@ -893,12 +953,17 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
gc.Prog(obj.AUNDEF) // tell plive.go that we never reach here
case ssa.BlockRet:
gc.Prog(obj.ARET)
+ case ssa.BlockRetJmp:
+ p := gc.Prog(obj.AJMP)
+ p.To.Type = obj.TYPE_MEM
+ p.To.Name = obj.NAME_EXTERN
+ p.To.Sym = gc.Linksym(b.Aux.(*gc.Sym))
case ssa.BlockPPC64EQ, ssa.BlockPPC64NE,
ssa.BlockPPC64LT, ssa.BlockPPC64GE,
ssa.BlockPPC64LE, ssa.BlockPPC64GT,
- ssa.BlockPPC64ULT, ssa.BlockPPC64UGT,
- ssa.BlockPPC64ULE, ssa.BlockPPC64UGE:
+ ssa.BlockPPC64FLT, ssa.BlockPPC64FGE,
+ ssa.BlockPPC64FLE, ssa.BlockPPC64FGT:
jmp := blockJump[b.Kind]
likely := b.Likely
var p *obj.Prog
@@ -908,14 +973,30 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
likely *= -1
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[1].Block()})
+ if jmp.invasmeq {
+ // TODO: The second branch is probably predict-not-taken since it is for FP equality
+ q := gc.Prog(ppc64.ABEQ)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})
+ }
case b.Succs[1].Block():
p = gc.Prog(jmp.asm)
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ if jmp.asmeq {
+ q := gc.Prog(ppc64.ABEQ)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
+ }
default:
p = gc.Prog(jmp.asm)
p.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{P: p, B: b.Succs[0].Block()})
+ if jmp.asmeq {
+ q := gc.Prog(ppc64.ABEQ)
+ q.To.Type = obj.TYPE_BRANCH
+ s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[0].Block()})
+ }
q := gc.Prog(obj.AJMP)
q.To.Type = obj.TYPE_BRANCH
s.Branches = append(s.Branches, gc.Branch{P: q, B: b.Succs[1].Block()})