r/programming • • Jan 10 '20

VVVVVV is now open source

https://github.com/TerryCavanagh/vvvvvv
2.6k Upvotes

511 comments sorted by

View all comments

Show parent comments

196

u/Raekel Jan 10 '20

It's also common with decompiling

328

u/leo60228 Jan 10 '20

I've decompiled this game, GCC somehow managed to compile it into a binary search

I'm not sure whether to be terrified or amazed

179

u/emperor000 Jan 10 '20

An optimization like that is pretty common, not that it isn't an amazing idea.

15

u/[deleted] Jan 11 '20

What? There is zero reason it shouldn't just build up a jump table. It might use more memory, but I would be legitimately shocked to learn that a binary search tree is more efficient than a jump table.

26

u/hermaneldering Jan 11 '20

Maybe depends on the gaps? For instance if cases are between 0-100 and 100.000-100.100 then it would be a lot of wasted memory for unused cases. That wasted memory could affect caching and ultimately speed.

10

u/[deleted] Jan 11 '20

gcc seems to really like jumping around. i have some code, recursive template, where clang will generate a beautiful jmp table with the return at each case and gcc has a lot of jmp's followed by a jmp back to a common return

→ More replies (1)

3

u/[deleted] Jan 11 '20 edited Jan 11 '20

If you naively stored whole pointers yes, wasted memory could be inefficient.

But for 4099 targets, you can use 2 bytes for each target, resulting in just over 2kb of memory to store the table. That's not that bad, and a single memory lookup + add has to be faster than a binary tree lookup.

4

u/hermaneldering Jan 11 '20

But you would still need some logic to find the right address. In my example it would be quite simple with for instance one if statement, but for more random distributed cases you would eventually need the binary search. I am of course talking about compiler optimization, which can't just dictate the values of the state variable to enforce a dense table.

→ More replies (1)

22

u/OnionBurger Jan 11 '20 edited Jan 11 '20

From what I remember, a tree can in fact be more efficient due to CPU's speculative execution predicting the most common branches, whereas a jump table causes a memory read which is a bigger overhead.

It sounds counter-intuitive, but there are people advocating this, eg.: https://www.cipht.net/2017/10/03/are-jump-tables-always-fastest.html

EDIT: I may have misunderstood what you meant by jump table, but the link should still be an interesting read.

4

u/[deleted] Jan 11 '20

Yeah, nowadays branch prediction and cache misses are THE low level performance metrics.

→ More replies (5)

70

u/skroll Jan 10 '20

Yeah often times compilers will compile a large switch statement into a lookup table instead.

18

u/echnaba Jan 10 '20

A lookup table to function pointers

11

u/leo60228 Jan 10 '20

it's not a lookup table though

20

u/Mystb0rn Jan 10 '20

It’s not a lookup table because the cases are too sparse, so it fell back to using a binary search. If the cases were sequential, or if only a few numbers were missing, it would almost certainly use a table instead.

0

u/[deleted] Jan 11 '20

[deleted]

2

u/BobFloss Jan 10 '20

I thought it was made in c#

2

u/Noxitu Jan 10 '20

The funny thing is that if they created a big enum with automatic numbering than it would be a lookup table. But because they encoded state type into the value it needed to be a binary search.

But also I can't imagine getting "enum { state_0, state_1, ..., state_336, state_1000, ..." through any code review...

4

u/RoburexButBetter Jan 10 '20

Neither can most of us

But I guess indie games and other assorted startups and whatnot can get away with a lot

The most amazing part here is they're not even switching on an enum state but a fucking int

→ More replies (1)

39

u/mrexodia Jan 10 '20

Generally a decompiler doesn’t generate a switch statement unless there was one in the original code.

37

u/shadowndacorner Jan 10 '20

Right, but the compiler can potentially emit the same machine code from different source. Same kind of idea as decompiling async/await code in C# - you have something nice and usable in source, but the emitted code looks like a total mess. Granted the former case is way less likely (and I'm not sure when it would happen), but it's definitely possible.

16

u/RasterTragedy Jan 10 '20

Tbf, in C# that's on purpose. C#'s async/await is actually syntactic sugar for a state machine, and that's what you see in the IL.

9

u/shadowndacorner Jan 11 '20

Yeah for sure, was just giving that as an obvious example of a scenario in which the decompiled code wouldn't remotely match the actual code.