]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: implement jump table on loong64
authorlimeidan <limeidan@loongson.cn>
Fri, 19 Sep 2025 03:18:13 +0000 (11:18 +0800)
committerabner chenc <chenguoqi@loongson.cn>
Sat, 27 Sep 2025 12:02:58 +0000 (05:02 -0700)
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>
src/cmd/compile/internal/loong64/ssa.go
src/cmd/compile/internal/ssa/_gen/LOONG64.rules
src/cmd/compile/internal/ssa/_gen/LOONG64Ops.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewriteLOONG64.go
src/cmd/internal/obj/loong64/asm.go
src/cmd/internal/sys/arch.go
test/codegen/switch.go

index 100ebf04567594a8b3dc6a153e91a148275931ac..bd0d96a6954957ec0cf403b3ff7bf9be7bb1cfe9 100644 (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())
        }
index 0d2384143c483772f4ff07aef16c76fab5d6198e..287eedee37401b273cc39e58ff730c6a8d2bbba9 100644 (file)
 (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 ...)
 
index a3db4def569e9f9ecd4cedf98be619e0433760cc..a85a566660eee62fabdffdca698ca69a82161368 100644 (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{
index b4aae50b895ff84d8cb44d0f9f8ea8c9b4b86f2e..92adf5341b25745a7cca71daa1425c147a4a2ebc 100644 (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",
index 3990b2833b20298f51116140649629c9720766dc..3fc57e9f497eca6965aff3dc4e14c094bf3d599f 100644 (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
index e20ceaae9592069d12d2089509707e1a987f5e71..ca6e2be4aa9eb672285fb989f32154384b14000c 100644 (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.
index 484538f28f0dd53f62d84cdacd7ca4da5116f096..3c92a6bbf2561981e9eeb6bba1c8357f00a174f2 100644 (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
 }
index 509343110a32db307298a5759703df827b9daa02..1a66a5ddf84f81dd4b5ac8a499e7f5351b8f98ac 100644 (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