cmd/compile: implement jump table on loong64

Following CL 357330, use jump tables on Loong64.

goos: linux
goarch: loong64
pkg: cmd/compile/internal/test
cpu: Loongson-3A6000-HV @ 2500.00MHz
                                 │     old     │                 new                 │
                                 │   sec/op    │   sec/op     vs base                │
Switch8Predictable                 2.352n ± 0%   2.101n ± 0%  -10.65% (p=0.000 n=10)
Switch8Unpredictable               11.99n ± 0%   10.25n ± 0%  -14.51% (p=0.000 n=10)
Switch32Predictable                3.153n ± 0%   1.887n ± 1%  -40.14% (p=0.000 n=10)
Switch32Unpredictable              12.47n ± 0%   10.22n ± 0%  -18.00% (p=0.000 n=10)
SwitchStringPredictable            3.162n ± 0%   3.352n ± 0%   +6.01% (p=0.000 n=10)
SwitchStringUnpredictable          14.70n ± 0%   13.31n ± 0%   -9.46% (p=0.000 n=10)
SwitchTypePredictable              3.702n ± 0%   2.201n ± 0%  -40.55% (p=0.000 n=10)
SwitchTypeUnpredictable            16.18n ± 0%   14.48n ± 0%  -10.51% (p=0.000 n=10)
SwitchInterfaceTypePredictable     7.654n ± 0%   9.680n ± 0%  +26.47% (p=0.000 n=10)
SwitchInterfaceTypeUnpredictable   22.04n ± 0%   22.44n ± 0%   +1.81% (p=0.000 n=10)
geomean                            7.441n        6.469n       -13.07%

Change-Id: Id6f30fa73349c60fac17670084daee56973a955f
Reviewed-on: https://go-review.googlesource.com/c/go/+/705396
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Junyang Shao <shaojunyang@google.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: abner chenc <chenguoqi@loongson.cn>
This commit is contained in:
limeidan 2025-09-19 11:18:13 +08:00 committed by abner chenc
parent 63cd912083
commit af6999e60d
8 changed files with 72 additions and 14 deletions

View file

@ -1266,6 +1266,29 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) {
p.From.Reg = b.Controls[0].Reg()
}
}
case ssa.BlockLOONG64JUMPTABLE:
// ALSLV $3, Rarg0, Rarg1, REGTMP
// MOVV (REGTMP), REGTMP
// JMP (REGTMP)
p := s.Prog(loong64.AALSLV)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 3 // idx*8
p.Reg = b.Controls[0].Reg()
p.AddRestSourceReg(b.Controls[1].Reg())
p.To.Type = obj.TYPE_REG
p.To.Reg = loong64.REGTMP
p1 := s.Prog(loong64.AMOVV)
p1.From.Type = obj.TYPE_MEM
p1.From.Reg = loong64.REGTMP
p1.From.Offset = 0
p1.To.Type = obj.TYPE_REG
p1.To.Reg = loong64.REGTMP
p2 := s.Prog(obj.AJMP)
p2.To.Type = obj.TYPE_MEM
p2.To.Reg = loong64.REGTMP
// Save jump tables for later resolution of the target blocks.
s.JumpTables = append(s.JumpTables, b)
default:
b.Fatalf("branch not implemented: %s", b.LongString())
}

View file

@ -504,6 +504,8 @@
(MOVBUreg x:((SGT|SGTU) _ _)) => x
(MOVBUreg x:(XOR (MOVVconst [1]) ((SGT|SGTU) _ _))) => x
(JumpTable idx) => (JUMPTABLE {makeJumpTableSym(b)} idx (MOVVaddr <typ.Uintptr> {makeJumpTableSym(b)} (SB)))
// Write barrier.
(WB ...) => (LoweredWB ...)

View file

@ -577,6 +577,12 @@ func init() {
{name: "BLT", controls: 2}, // controls[0] < controls[1]
{name: "BGEU", controls: 2}, // controls[0] >= controls[1], unsigned
{name: "BLTU", controls: 2}, // controls[0] < controls[1], unsigned
// JUMPTABLE implements jump tables.
// Aux is the symbol (an *obj.LSym) for the jump table.
// control[0] is the index into the jump table.
// control[1] is the address of the jump table (the address of the symbol stored in Aux).
{name: "JUMPTABLE", controls: 2, aux: "Sym"},
}
archs = append(archs, arch{

View file

@ -108,6 +108,7 @@ const (
BlockLOONG64BLT
BlockLOONG64BGEU
BlockLOONG64BLTU
BlockLOONG64JUMPTABLE
BlockMIPSEQ
BlockMIPSNE
@ -250,20 +251,21 @@ var blockString = [...]string{
BlockARM64GEnoov: "GEnoov",
BlockARM64JUMPTABLE: "JUMPTABLE",
BlockLOONG64EQZ: "EQZ",
BlockLOONG64NEZ: "NEZ",
BlockLOONG64LTZ: "LTZ",
BlockLOONG64LEZ: "LEZ",
BlockLOONG64GTZ: "GTZ",
BlockLOONG64GEZ: "GEZ",
BlockLOONG64FPT: "FPT",
BlockLOONG64FPF: "FPF",
BlockLOONG64BEQ: "BEQ",
BlockLOONG64BNE: "BNE",
BlockLOONG64BGE: "BGE",
BlockLOONG64BLT: "BLT",
BlockLOONG64BGEU: "BGEU",
BlockLOONG64BLTU: "BLTU",
BlockLOONG64EQZ: "EQZ",
BlockLOONG64NEZ: "NEZ",
BlockLOONG64LTZ: "LTZ",
BlockLOONG64LEZ: "LEZ",
BlockLOONG64GTZ: "GTZ",
BlockLOONG64GEZ: "GEZ",
BlockLOONG64FPT: "FPT",
BlockLOONG64FPF: "FPF",
BlockLOONG64BEQ: "BEQ",
BlockLOONG64BNE: "BNE",
BlockLOONG64BGE: "BGE",
BlockLOONG64BLT: "BLT",
BlockLOONG64BGEU: "BGEU",
BlockLOONG64BLTU: "BLTU",
BlockLOONG64JUMPTABLE: "JUMPTABLE",
BlockMIPSEQ: "EQ",
BlockMIPSNE: "NE",

View file

@ -12148,6 +12148,19 @@ func rewriteBlockLOONG64(b *Block) bool {
b.resetWithControl(BlockLOONG64NEZ, v0)
return true
}
case BlockJumpTable:
// match: (JumpTable idx)
// result: (JUMPTABLE {makeJumpTableSym(b)} idx (MOVVaddr <typ.Uintptr> {makeJumpTableSym(b)} (SB)))
for {
idx := b.Controls[0]
v0 := b.NewValue0(b.Pos, OpLOONG64MOVVaddr, typ.Uintptr)
v0.Aux = symToAux(makeJumpTableSym(b))
v1 := b.NewValue0(b.Pos, OpSB, typ.Uintptr)
v0.AddArg(v1)
b.resetWithControl2(BlockLOONG64JUMPTABLE, idx, v0)
b.Aux = symToAux(makeJumpTableSym(b))
return true
}
case BlockLOONG64LEZ:
// match: (LEZ (MOVVconst [c]) yes no)
// cond: c <= 0

View file

@ -707,6 +707,15 @@ func span0(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
// so instruction sequences that use REGTMP are unsafe to
// preempt asynchronously.
obj.MarkUnsafePoints(c.ctxt, c.cursym.Func().Text, c.newprog, c.isUnsafePoint, c.isRestartable)
// Now that we know byte offsets, we can generate jump table entries.
for _, jt := range cursym.Func().JumpTables {
for i, p := range jt.Targets {
// The ith jumptable entry points to the p.Pc'th
// byte in the function symbol s.
jt.Sym.WriteAddr(ctxt, int64(i)*8, 8, cursym, p.Pc)
}
}
}
// isUnsafePoint returns whether p is an unsafe point.

View file

@ -145,6 +145,7 @@ var ArchLoong64 = &Arch{
MinLC: 4,
Alignment: 8, // Unaligned accesses are not guaranteed to be fast
CanMergeLoads: true,
CanJumpTable: true,
HasLR: true,
FixedFrameSize: 8, // LR
}

View file

@ -25,6 +25,7 @@ func f(x string) int {
func square(x int) int {
// amd64:`JMP\s\(.*\)\(.*\)$`
// arm64:`MOVD\s\(R.*\)\(R.*<<3\)`,`JMP\s\(R.*\)$`
// loong64: `ALSLV`,`MOVV`,`JMP`
switch x {
case 1:
return 1
@ -51,6 +52,7 @@ func square(x int) int {
func length(x string) int {
// amd64:`JMP\s\(.*\)\(.*\)$`
// arm64:`MOVD\s\(R.*\)\(R.*<<3\)`,`JMP\s\(R.*\)$`
// loong64:`ALSLV`,`MOVV`,`JMP`
switch x {
case "a":
return 1