|
Switch as Binary Search, Part 0
For a standard switch with a contiguous region of cases, as in the below, compilers generate constant-time lookups by treating the cases as indexes into an array of pointers. For switches with multiple labels pointing to the same code, some compilers save space by generating doubly-indexed, tabular code. For switches with non-contiguous, sparsely-distributed cases like the below, the table-based approaches from above are unsuitable, and yet cases like this do appear in practice, so the compiler must have a strategy for dealing with them. switch(x)One obvious solution to this problem would be to generate a sequence of comparisons, one for each case, starting from the lowest case and ending with the highest. This would work, but the lookup would be O(N) in the number of case labels. An equally obvious solution, and one that was mentioned in the book "Reversing", is to generate a binary search construct in the generated code to perform lookups in O(log(N)) time. To briefly review binary searching, consider the (necessarily) sorted sequence [1;2;3;4;5;6;7;8;9], and consider finding the value 2. We begin by comparing against the middle element, 5. Since 2 is lesser, we discard all values 5 and above and consider those below it. Now we have a smaller range of values upon which we can perform the same procedure. [1;2;3;4] As before, we compare against the middle element, 3. Since it is lesser, we can discard anything above 3, leaving [1;2] as the remaining search space. [1;2] The middle element is 2, which is our search key, so we stop. This process took three steps (log(9)) to complete, compared with N=9 steps for searching the whole array. The compiler is responsible for generating code that implements these comparisons. The first comparison will be against the middle element in the collection; whether the case value is above or below determines whether to repeat the process for the integers above or below the middle one. At each comparison there is a corresponding equality test to see whether the search key is the same as the comparator. Below is an example of this construct in the wild. AUTO:00462141 cmp eax, 0E3hHex-Rays does a nice job of illustrating the time-consuming ugly confusingness of dealing with code like this: if ( v7 <= 0x837FDF02 )
Comments
| ||||||