Skip to content

Commit cddddbc

Browse files
committed
cmd/compile: use ISEL, cleanup use of zero & extensions
Abandoned earlier efforts to expose zero register, but left it in numbering to decrease squirrelyness of register allocator. ISELrelOp used in code generation of bool := x relOp y. Some patterns added to better elide zero case and some sign extension. Updates: #17109 Change-Id: Ida7839f0023ca8f0ffddc0545f0ac269e65b05d9 Reviewed-on: https://go-review.googlesource.com/29380 Run-TryBot: David Chase <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Cherry Zhang <[email protected]>
1 parent dcbbd31 commit cddddbc

File tree

12 files changed

+825
-542
lines changed

12 files changed

+825
-542
lines changed

src/cmd/compile/internal/gc/go.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,9 @@ const (
336336

337337
// Instruction updates whichever of from/to is type D_OREG. (ppc64)
338338
PostInc = 1 << 29
339+
340+
// Optional 3rd input operand, only ever read.
341+
From3Read = 1 << 30
339342
)
340343

341344
type Arch struct {

src/cmd/compile/internal/gc/plive.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,20 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
624624
}
625625
}
626626

627+
if info.Flags&From3Read != 0 {
628+
from := prog.From3
629+
if from.Node != nil && from.Sym != nil {
630+
n := from.Node.(*Node)
631+
if pos := liveIndex(n, vars); pos >= 0 {
632+
if n.Addrtaken {
633+
bvset(avarinit, pos)
634+
} else {
635+
bvset(uevar, pos)
636+
}
637+
}
638+
}
639+
}
640+
627641
if info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
628642
to := &prog.To
629643
if to.Node != nil && to.Sym != nil {

src/cmd/compile/internal/ppc64/prog.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ var progtable = [ppc64.ALAST & obj.AMask]gc.ProgInfo{
100100
ppc64.AMOVHZ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
101101
ppc64.AMOVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
102102

103+
ppc64.AISEL & obj.AMask: {Flags: gc.SizeQ | gc.RegRead | gc.From3Read | gc.RightWrite},
104+
103105
// there is no AMOVWU.
104106
ppc64.AMOVWZU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
105107
ppc64.AMOVWZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},

src/cmd/compile/internal/ppc64/ssa.go

Lines changed: 92 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,28 @@ var condOps = map[ssa.Op]obj.As{
2626
ssa.OpPPC64FGreaterEqual: ppc64.ABGT, // 2 branches for FCMP >=, second is BEQ
2727
}
2828

29+
// iselOp encodes mapping of comparison operations onto ISEL operands
30+
type iselOp struct {
31+
cond int64
32+
valueIfCond int // if cond is true, the value to return (0 or 1)
33+
}
34+
35+
// Input registers to ISEL used for comparison. Index 0 is zero, 1 is (will be) 1
36+
var iselRegs = [2]int16{ppc64.REG_R0, ppc64.REGTMP}
37+
38+
var iselOps = map[ssa.Op]iselOp{
39+
ssa.OpPPC64Equal: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 1},
40+
ssa.OpPPC64NotEqual: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 0},
41+
ssa.OpPPC64LessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
42+
ssa.OpPPC64GreaterEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 0},
43+
ssa.OpPPC64GreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
44+
ssa.OpPPC64LessEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 0},
45+
ssa.OpPPC64FLessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
46+
ssa.OpPPC64FGreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
47+
ssa.OpPPC64FLessEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
48+
ssa.OpPPC64FGreaterEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
49+
}
50+
2951
// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
3052
func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
3153
// flive := b.FlagsLiveAtEnd
@@ -34,7 +56,7 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
3456
// }
3557
// for i := len(b.Values) - 1; i >= 0; i-- {
3658
// v := b.Values[i]
37-
// if flive && (v.Op == ssa.OpPPC64MOVWconst || v.Op == ssa.OpPPC64MOVDconst) {
59+
// if flive && (v.Op == v.Op == ssa.OpPPC64MOVDconst) {
3860
// // The "mark" is any non-nil Aux value.
3961
// v.Aux = v
4062
// }
@@ -120,6 +142,17 @@ func scratchFpMem(s *gc.SSAGenState, a *obj.Addr) {
120142
a.Reg = ppc64.REGSP
121143
}
122144

145+
func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
146+
r := v.Reg()
147+
p := gc.Prog(ppc64.AISEL)
148+
p.To.Type = obj.TYPE_REG
149+
p.To.Reg = r
150+
p.Reg = r1
151+
p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r2}
152+
p.From.Type = obj.TYPE_CONST
153+
p.From.Offset = cr
154+
}
155+
123156
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
124157
s.SetLineno(v.Line)
125158
switch v.Op {
@@ -382,7 +415,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
382415
v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
383416
}
384417

385-
case ssa.OpPPC64MOVDconst, ssa.OpPPC64MOVWconst:
418+
case ssa.OpPPC64MOVDconst:
386419
p := gc.Prog(v.Op.Asm())
387420
p.From.Type = obj.TYPE_CONST
388421
p.From.Offset = v.AuxInt
@@ -418,7 +451,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
418451
p.To.Reg = v.Reg()
419452
p.To.Type = obj.TYPE_REG
420453

421-
case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVBload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload:
454+
case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload:
422455
p := gc.Prog(v.Op.Asm())
423456
p.From.Type = obj.TYPE_MEM
424457
p.From.Reg = v.Args[0].Reg()
@@ -465,65 +498,80 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
465498
ssa.OpPPC64GreaterThan,
466499
ssa.OpPPC64FGreaterThan,
467500
ssa.OpPPC64GreaterEqual:
501+
468502
// On Power7 or later, can use isel instruction:
469503
// for a < b, a > b, a = b:
470-
// rt := 1
471-
// isel rt,rt,r0,cond
504+
// rtmp := 1
505+
// isel rt,rtmp,r0,cond // rt is target in ppc asm
472506

473507
// for a >= b, a <= b, a != b:
474-
// rt := 1
475-
// isel rt,0,rt,!cond
476-
477-
// However, PPCbe support is for older machines than that,
478-
// and isel (which looks a lot like fsel) isn't recognized
479-
// yet by the Go assembler. So for now, use the old instruction
480-
// sequence, which we'll need anyway.
481-
// TODO: add support for isel on PPCle and use it.
508+
// rtmp := 1
509+
// isel rt,0,rtmp,!cond // rt is target in ppc asm
482510

483-
// generate boolean values
484-
// use conditional move
511+
if v.Block.Func.Config.OldArch {
512+
p := gc.Prog(ppc64.AMOVD)
513+
p.From.Type = obj.TYPE_CONST
514+
p.From.Offset = 1
515+
p.To.Type = obj.TYPE_REG
516+
p.To.Reg = v.Reg()
485517

486-
p := gc.Prog(ppc64.AMOVW)
487-
p.From.Type = obj.TYPE_CONST
488-
p.From.Offset = 1
489-
p.To.Type = obj.TYPE_REG
490-
p.To.Reg = v.Reg()
518+
pb := gc.Prog(condOps[v.Op])
519+
pb.To.Type = obj.TYPE_BRANCH
491520

492-
pb := gc.Prog(condOps[v.Op])
493-
pb.To.Type = obj.TYPE_BRANCH
521+
p = gc.Prog(ppc64.AMOVD)
522+
p.From.Type = obj.TYPE_CONST
523+
p.From.Offset = 0
524+
p.To.Type = obj.TYPE_REG
525+
p.To.Reg = v.Reg()
494526

495-
p = gc.Prog(ppc64.AMOVW)
527+
p = gc.Prog(obj.ANOP)
528+
gc.Patch(pb, p)
529+
break
530+
}
531+
// Modern PPC uses ISEL
532+
p := gc.Prog(ppc64.AMOVD)
496533
p.From.Type = obj.TYPE_CONST
497-
p.From.Offset = 0
534+
p.From.Offset = 1
498535
p.To.Type = obj.TYPE_REG
499-
p.To.Reg = v.Reg()
500-
501-
p = gc.Prog(obj.ANOP)
502-
gc.Patch(pb, p)
536+
p.To.Reg = iselRegs[1]
537+
iop := iselOps[v.Op]
538+
ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
503539

504540
case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion
505541
ssa.OpPPC64FGreaterEqual:
506542

507-
p := gc.Prog(ppc64.AMOVW)
508-
p.From.Type = obj.TYPE_CONST
509-
p.From.Offset = 1
510-
p.To.Type = obj.TYPE_REG
511-
p.To.Reg = v.Reg()
543+
if v.Block.Func.Config.OldArch {
544+
p := gc.Prog(ppc64.AMOVW)
545+
p.From.Type = obj.TYPE_CONST
546+
p.From.Offset = 1
547+
p.To.Type = obj.TYPE_REG
548+
p.To.Reg = v.Reg()
512549

513-
pb0 := gc.Prog(condOps[v.Op])
514-
pb0.To.Type = obj.TYPE_BRANCH
515-
pb1 := gc.Prog(ppc64.ABEQ)
516-
pb1.To.Type = obj.TYPE_BRANCH
550+
pb0 := gc.Prog(condOps[v.Op])
551+
pb0.To.Type = obj.TYPE_BRANCH
552+
pb1 := gc.Prog(ppc64.ABEQ)
553+
pb1.To.Type = obj.TYPE_BRANCH
517554

518-
p = gc.Prog(ppc64.AMOVW)
555+
p = gc.Prog(ppc64.AMOVW)
556+
p.From.Type = obj.TYPE_CONST
557+
p.From.Offset = 0
558+
p.To.Type = obj.TYPE_REG
559+
p.To.Reg = v.Reg()
560+
561+
p = gc.Prog(obj.ANOP)
562+
gc.Patch(pb0, p)
563+
gc.Patch(pb1, p)
564+
break
565+
}
566+
// Modern PPC uses ISEL
567+
p := gc.Prog(ppc64.AMOVD)
519568
p.From.Type = obj.TYPE_CONST
520-
p.From.Offset = 0
569+
p.From.Offset = 1
521570
p.To.Type = obj.TYPE_REG
522-
p.To.Reg = v.Reg()
523-
524-
p = gc.Prog(obj.ANOP)
525-
gc.Patch(pb0, p)
526-
gc.Patch(pb1, p)
571+
p.To.Reg = iselRegs[1]
572+
iop := iselOps[v.Op]
573+
ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
574+
ssaGenISEL(v, ppc64.C_COND_EQ, iselRegs[1], v.Reg())
527575

528576
case ssa.OpPPC64LoweredZero:
529577
// Similar to how this is done on ARM,

src/cmd/compile/internal/ssa/config.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ type Config struct {
3232
noDuffDevice bool // Don't use Duff's device
3333
nacl bool // GOOS=nacl
3434
use387 bool // GO386=387
35+
OldArch bool // True for older versions of architecture, e.g. true for PPC64BE, false for PPC64LE
3536
NeedsFpScratch bool // No direct move between GP and FP register sets
36-
DebugTest bool // as a debugging aid for binary search using GOSSAHASH, make buggy new code conditional on this
37+
DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
3738
sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
3839
curFunc *Func
3940

@@ -180,7 +181,10 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
180181
c.FPReg = framepointerRegARM64
181182
c.hasGReg = true
182183
c.noDuffDevice = obj.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
183-
case "ppc64le", "ppc64":
184+
case "ppc64":
185+
c.OldArch = true
186+
fallthrough
187+
case "ppc64le":
184188
c.IntSize = 8
185189
c.PtrSize = 8
186190
c.lowerBlock = rewriteBlockPPC64

0 commit comments

Comments
 (0)