1
0
mirror of https://github.com/golang/go synced 2024-11-18 13:54:59 -07:00

cmd/compile: implement multi-control branches for riscv64

Implement multi-control branches for riscv64, switching to using the BNEZ
pseudo-instruction when rewriting conditionals. This will allow for further
branch optimisations to later be performed via rewrites.

Change-Id: I7f2c69f3c77494b403f26058c6bc8432d8070ad0
Reviewed-on: https://go-review.googlesource.com/c/go/+/226399
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Joel Sing <joel@sing.id.au>
This commit is contained in:
Joel Sing 2020-03-31 02:00:50 +11:00
parent 1518123114
commit 40f2dab0e1
5 changed files with 86 additions and 20 deletions

View File

@ -577,6 +577,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
}
}
var blockBranch = [...]obj.As{
ssa.BlockRISCV64BEQ: riscv.ABEQ,
ssa.BlockRISCV64BEQZ: riscv.ABEQZ,
ssa.BlockRISCV64BGE: riscv.ABGE,
ssa.BlockRISCV64BGEU: riscv.ABGEU,
ssa.BlockRISCV64BGEZ: riscv.ABGEZ,
ssa.BlockRISCV64BGTZ: riscv.ABGTZ,
ssa.BlockRISCV64BLEZ: riscv.ABLEZ,
ssa.BlockRISCV64BLT: riscv.ABLT,
ssa.BlockRISCV64BLTU: riscv.ABLTU,
ssa.BlockRISCV64BLTZ: riscv.ABLTZ,
ssa.BlockRISCV64BNE: riscv.ABNE,
ssa.BlockRISCV64BNEZ: riscv.ABNEZ,
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
s.SetPos(b.Pos)
@ -610,27 +625,44 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = b.Aux.(*obj.LSym)
case ssa.BlockRISCV64BNE:
case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BNEZ,
ssa.BlockRISCV64BLT, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BGEZ,
ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
as := blockBranch[b.Kind]
invAs := riscv.InvertBranch(as)
var p *obj.Prog
switch next {
case b.Succs[0].Block():
p = s.Br(riscv.ABNE, b.Succs[1].Block())
p.As = riscv.InvertBranch(p.As)
p = s.Br(invAs, b.Succs[1].Block())
case b.Succs[1].Block():
p = s.Br(riscv.ABNE, b.Succs[0].Block())
p = s.Br(as, b.Succs[0].Block())
default:
if b.Likely != ssa.BranchUnlikely {
p = s.Br(riscv.ABNE, b.Succs[0].Block())
p = s.Br(as, b.Succs[0].Block())
s.Br(obj.AJMP, b.Succs[1].Block())
} else {
p = s.Br(riscv.ABNE, b.Succs[1].Block())
p.As = riscv.InvertBranch(p.As)
p = s.Br(invAs, b.Succs[1].Block())
s.Br(obj.AJMP, b.Succs[0].Block())
}
}
p.Reg = b.Controls[0].Reg()
p.From.Type = obj.TYPE_REG
p.From.Reg = riscv.REG_ZERO
switch b.Kind {
case ssa.BlockRISCV64BEQ, ssa.BlockRISCV64BNE, ssa.BlockRISCV64BLT, ssa.BlockRISCV64BGE, ssa.BlockRISCV64BLTU, ssa.BlockRISCV64BGEU:
if b.NumControls() != 2 {
b.Fatalf("Unexpected number of controls (%d != 2): %s", b.NumControls(), b.LongString())
}
p.From.Reg = b.Controls[0].Reg()
p.Reg = b.Controls[1].Reg()
case ssa.BlockRISCV64BEQZ, ssa.BlockRISCV64BNEZ, ssa.BlockRISCV64BGEZ, ssa.BlockRISCV64BLEZ, ssa.BlockRISCV64BLTZ, ssa.BlockRISCV64BGTZ:
if b.NumControls() != 1 {
b.Fatalf("Unexpected number of controls (%d != 1): %s", b.NumControls(), b.LongString())
}
p.From.Reg = b.Controls[0].Reg()
}
default:
b.Fatalf("Unhandled block: %s", b.LongString())

View File

@ -447,13 +447,13 @@
// Conditional branches
//
// cond is 1 if true. BNE compares against 0.
// cond is 1 if true.
//
// TODO(prattmic): RISCV branch instructions take two operands to compare,
// so we could generate more efficient code by computing the condition in the
// branch itself. This should be revisited now that the compiler has support
// for two control values (https://golang.org/cl/196557).
(If cond yes no) => (BNE cond yes no)
(If cond yes no) => (BNEZ cond yes no)
// Calls
(StaticCall ...) => (CALLstatic ...)
@ -483,7 +483,7 @@
// Optimizations
// Absorb SNEZ into branch.
(BNE (SNEZ x) yes no) => (BNE x yes no)
(BNEZ (SNEZ x) yes no) => (BNEZ x yes no)
// Store zero
(MOVBstore [off] {sym} ptr (MOVBconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)

View File

@ -382,7 +382,19 @@ func init() {
}
RISCV64blocks := []blockData{
{name: "BNE", controls: 1}, // Control != 0 (take a register)
{name: "BEQ", controls: 2},
{name: "BNE", controls: 2},
{name: "BLT", controls: 2},
{name: "BGE", controls: 2},
{name: "BLTU", controls: 2},
{name: "BGEU", controls: 2},
{name: "BEQZ", controls: 1},
{name: "BNEZ", controls: 1},
{name: "BLEZ", controls: 1},
{name: "BGEZ", controls: 1},
{name: "BLTZ", controls: 1},
{name: "BGTZ", controls: 1},
}
archs = append(archs, arch{

View File

@ -112,7 +112,18 @@ const (
BlockPPC64FGT
BlockPPC64FGE
BlockRISCV64BEQ
BlockRISCV64BNE
BlockRISCV64BLT
BlockRISCV64BGE
BlockRISCV64BLTU
BlockRISCV64BGEU
BlockRISCV64BEQZ
BlockRISCV64BNEZ
BlockRISCV64BLEZ
BlockRISCV64BGEZ
BlockRISCV64BLTZ
BlockRISCV64BGTZ
BlockS390XBRC
BlockS390XCRJ
@ -231,7 +242,18 @@ var blockString = [...]string{
BlockPPC64FGT: "FGT",
BlockPPC64FGE: "FGE",
BlockRISCV64BNE: "BNE",
BlockRISCV64BEQ: "BEQ",
BlockRISCV64BNE: "BNE",
BlockRISCV64BLT: "BLT",
BlockRISCV64BGE: "BGE",
BlockRISCV64BLTU: "BLTU",
BlockRISCV64BGEU: "BGEU",
BlockRISCV64BEQZ: "BEQZ",
BlockRISCV64BNEZ: "BNEZ",
BlockRISCV64BLEZ: "BLEZ",
BlockRISCV64BGEZ: "BGEZ",
BlockRISCV64BLTZ: "BLTZ",
BlockRISCV64BGTZ: "BGTZ",
BlockS390XBRC: "BRC",
BlockS390XCRJ: "CRJ",

View File

@ -5132,21 +5132,21 @@ func rewriteValueRISCV64_OpZeroExt8to64(v *Value) bool {
}
func rewriteBlockRISCV64(b *Block) bool {
switch b.Kind {
case BlockRISCV64BNE:
// match: (BNE (SNEZ x) yes no)
// result: (BNE x yes no)
case BlockRISCV64BNEZ:
// match: (BNEZ (SNEZ x) yes no)
// result: (BNEZ x yes no)
for b.Controls[0].Op == OpRISCV64SNEZ {
v_0 := b.Controls[0]
x := v_0.Args[0]
b.resetWithControl(BlockRISCV64BNE, x)
b.resetWithControl(BlockRISCV64BNEZ, x)
return true
}
case BlockIf:
// match: (If cond yes no)
// result: (BNE cond yes no)
// result: (BNEZ cond yes no)
for {
cond := b.Controls[0]
b.resetWithControl(BlockRISCV64BNE, cond)
b.resetWithControl(BlockRISCV64BNEZ, cond)
return true
}
}