-
Notifications
You must be signed in to change notification settings - Fork 18k
cmd/compile: compile dense, pure-integer "switch" into jump table #5496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
So, I looked around a bit and I don't think this is easily done or possible within gc/swt.c alone. I don't know yet if it's possible to emit an OGOTO with a dynamic jump destination. Don't think so. Anyway, I see if I can cook up proof-of-concept code with a new opcode. Not sure if that's the right way to do it, but this allows me to better isolate my code and flush out errors. In case someone is not sure what I want to achieve, I want to compile this switch containing only integer cases or case lists: switch h { case '0', '1', ..., '9': d = h - '0' case 'a', 'b', ..., 'f': d = h - 'a' + 10 case 'A', 'B', ..., 'F': d = h - 'A' + 10 } ...into roughly this (pseudo) code: MOV reg, h CMP reg, 48 JLT default // h < 48 --> jump to default CMP reg, 102 JGT default // h > 102 --> jump to default SUB reg, 48 SHL reg, 1 // for 2-byte relative JMP instruction. // shift by 2 (3-byte JMP + NOP) for tables >255 INC reg // reg := (reg - 48) * 2 + 1 JMP reg // relative jump by <reg> bytes forward h0: JMP digits // '0'..'9' h1: JMP digits h2: JMP digits .. h9: JMP digits h10: JMP default // gap between '9'+1 and 'A'-1 .. h16: JMP default h17: JMP uppercase // 'A'..'F' .. h22: JMP uppercase h23: JMP default // gap between 'F'+1 and 'a'-1 .. h48: JMP default h49: JMP lowercase // 'a'..'f' .. h54: JMP lowercase digits: //code for: d = h - '0' JMP exit_switch uppercase: //code for: d = h - 'A' + 10 JMP exit_switch lowercase: //code for: d = h - 'a' + 10 JMP exit_switch default: // should be inlined if empty exit_switch: (This is pseudo-code. It might not even be correct, but it should give you an idea.) Why? What are the use-cases? Various encoders/decoders, lexers/scanners, parsers, state machines can potentially be sped up by this. |
Unfortunately, The plan9 linker doesn't support emitting a data reference to an instruction. This will have to be implemented in order to implement jump tables. https://groups.google.com/d/topic/golang-nuts/6M0BLgrKBRk/discussion has some more information on this topic. |
I have posted numbers in #19791 (comment) about implementing a |
Currently, for constants if the number of cases is less than 4, we use linear search when switching between cases in the resulting AST. Otherwise, the compiler converts switches with long runs of constants into an AST that uses binary search and this speeds case switching but also range recognition and coalescing was added by @josharian in June 2016 in CL https://go-review.googlesource.com/26770 Extrapolating from the status quo:
I believe that the range coalescing is something that the original reporter wanted and unless am mistaken, the current implementation solves the current problem. /cc @josharian @randall77 @rsc , is there perhaps something we could do more here? Also please feel free to correct and educate me :) |
Jump tables are distinct from range coalescing. There's a good discussion of jump tables, generalized jump tables, and other switch optimizations in https://www.nextmovesoftware.com/technology/SwitchOptimization.pdf. See also #15780. I think we should leave this open; jump table support is of continuing interest, I believe. |
Awesome, thank you @josharian! I'll digest the content of the referenced text and hopefully look at |
@odeke-em cool. The first step is to get support for jump tables into the object file format and assembler. Making the compiler generate them is a second step. Note that the paper I referenced (which is a great read) sheds some doubt about whether jump tables are a good idea. There will definitely be some experimentation required. |
The code for decoding struct fields is now a switch with contiguous constants. Although the Go compiler doesn't yet generate jump tables, it hopefully will someday (golang/go#5496), and these switches will get faster. Also, fix registration of benchmark types.
Change https://golang.org/cl/357330 mentions this issue: |
Change https://go.dev/cl/395714 mentions this issue: |
Reorganize the way we rewrite expression switches on strings, so that jump tables are naturally used for the outer switch on the string length. The changes to the prove pass in this CL are required so as to not repeat the test for string length in each case. name old time/op new time/op delta SwitchStringPredictable 2.28ns ± 9% 2.08ns ± 5% -9.04% (p=0.000 n=10+10) SwitchStringUnpredictable 10.5ns ± 1% 9.5ns ± 1% -9.08% (p=0.000 n=9+10) Update #5496 Update #34381 Change-Id: Ie6846b1dd27f3e472f7c30dfcc598c68d440b997 Reviewed-on: https://go-review.googlesource.com/c/go/+/395714 Run-TryBot: Keith Randall <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Cherry Mui <[email protected]> Reviewed-by: Keith Randall <[email protected]>
The text was updated successfully, but these errors were encountered: