Where each arm goes when the switch is over
Everything in this chapter shows up in one function here, and the piece that takes the most reading is not the switch itself. It is what each case arm does when it finishes.
A case that ends in return leaves the function. A case that ends in break falls out of the switch and into whatever code follows it. In a listing those two look identical — both are a b to a forward address — and the only way to tell them apart is to notice that they go to different forward addresses.
Here is a function where every arm returns:
0 cmp r1, #99
2 ble 6 ~>
4 mov r1, #99
6 ~>cmp r0, #1
8 beq 30 ~>
10 cmp r0, #1
12 bgt 20 ~>
14 cmp r0, #0
16 beq 26 ~>
18 b 38 ~>
20 ~>cmp r0, #2
22 beq 34 ~>
24 b 38 ~>
26 ~>mov r0, r1
28 b 40 ~>
30 ~>add r0, r1, #1
32 b 40 ~>
34 ~>neg r0, r1
36 b 40 ~>
38 ~>mov r0, #0
40 ~>bx lr
A ceiling clamp at 0 through 4, the compare tree at 6 through 24, and four bodies: three of them branch to 40 — the bx lr — and the default at 38 falls straight into it. One destination for every arm means no code after the switch at all, and the clamp had to run before it because there is nowhere else for it to go.
Your target arranges the same three ingredients differently. The clamp sits on the far side of the switch this time, and the case bodies below the tree have two forward destinations rather than one: some land on the clamp's compare and one steps over it. Work out what that difference says about how each arm left the switch.
The guard is the other thing to weigh. A bail-out returning a value that is already in r0 costs a single branch, as it did in the guard lesson; a bail-out returning a constant has to build it and carry it to the exit. Count the instructions in the guard and you know which kind you are looking at before you read anything else.
Work outwards: guard first, then the tree's case labels, then each body, then where each body goes.
Your task
Write func_0816ac60 to reproduce the target assembly.