From af6999e60d498887fceaeca89f4aa88ff35c91df Mon Sep 17 00:00:00 2001 From: limeidan Date: Fri, 19 Sep 2025 11:18:13 +0800 Subject: [PATCH] cmd/compile: implement jump table on loong64 MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Junyang Shao Reviewed-by: Michael Knyszek Reviewed-by: abner chenc --- src/cmd/compile/internal/loong64/ssa.go | 23 ++++++++++++++ .../compile/internal/ssa/_gen/LOONG64.rules | 2 ++ .../compile/internal/ssa/_gen/LOONG64Ops.go | 6 ++++ src/cmd/compile/internal/ssa/opGen.go | 30 ++++++++++--------- .../compile/internal/ssa/rewriteLOONG64.go | 13 ++++++++ src/cmd/internal/obj/loong64/asm.go | 9 ++++++ src/cmd/internal/sys/arch.go | 1 + test/codegen/switch.go | 2 ++ 8 files changed, 72 insertions(+), 14 deletions(-) diff --git a/src/cmd/compile/internal/loong64/ssa.go b/src/cmd/compile/internal/loong64/ssa.go index 100ebf0456..bd0d96a695 100644 --- a/src/cmd/compile/internal/loong64/ssa.go +++ b/src/cmd/compile/internal/loong64/ssa.go @@ -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()) } diff --git a/src/cmd/compile/internal/ssa/_gen/LOONG64.rules b/src/cmd/compile/internal/ssa/_gen/LOONG64.rules index 0d2384143c..287eedee37 100644 --- a/src/cmd/compile/internal/ssa/_gen/LOONG64.rules +++ b/src/cmd/compile/internal/ssa/_gen/LOONG64.rules @@ -504,6 +504,8 @@ (MOVBUreg x:((SGT|SGTU) _ _)) => x (MOVBUreg x:(XOR (MOVVconst [1]) ((SGT|SGTU) _ _))) => x +(JumpTable idx) => (JUMPTABLE {makeJumpTableSym(b)} idx (MOVVaddr {makeJumpTableSym(b)} (SB))) + // Write barrier. (WB ...) => (LoweredWB ...) diff --git a/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go b/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go index a3db4def56..a85a566660 100644 --- a/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go +++ b/src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go @@ -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{ diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index b4aae50b89..92adf5341b 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -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", diff --git a/src/cmd/compile/internal/ssa/rewriteLOONG64.go b/src/cmd/compile/internal/ssa/rewriteLOONG64.go index 3990b2833b..3fc57e9f49 100644 --- a/src/cmd/compile/internal/ssa/rewriteLOONG64.go +++ b/src/cmd/compile/internal/ssa/rewriteLOONG64.go @@ -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 {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 diff --git a/src/cmd/internal/obj/loong64/asm.go b/src/cmd/internal/obj/loong64/asm.go index e20ceaae95..ca6e2be4aa 100644 --- a/src/cmd/internal/obj/loong64/asm.go +++ b/src/cmd/internal/obj/loong64/asm.go @@ -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. diff --git a/src/cmd/internal/sys/arch.go b/src/cmd/internal/sys/arch.go index 484538f28f..3c92a6bbf2 100644 --- a/src/cmd/internal/sys/arch.go +++ b/src/cmd/internal/sys/arch.go @@ -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 } diff --git a/test/codegen/switch.go b/test/codegen/switch.go index 509343110a..1a66a5ddf8 100644 --- a/test/codegen/switch.go +++ b/test/codegen/switch.go @@ -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 -- 2.52.0