Любопытна реализация конструкции switch/case в компиляторе RVCT для процессоров ARM. Довольно специфическая вещь, но, может быть, кому-нибудь пригодится - в качестве примера.
Данный трюк используется при компиляции кода в режиме THUMB. Этот режим используется для получения компактного кода для процессоров ARM.
Итак, условия:
- конструкция switch/case;
- ключ switch является целочисленным;
- значения в case-метках идут "почти" подряд (т.е., возможны пропуски);
- используется пять и более case-меток.
Пример:
int a;
...
switch (a)
{
case 10:
return 123;
case 11:
return 43;
case 12:
return 12;
case 13:
return 21;
case 15:
return 98;
}
return 1;
В этом случае RVCT генерирует вызов специальной процедуры __ARM_switch8 и сразу после точки вызова - таблицу переходов. Таблица переходов состоит из (n + 2) байтов плюс байт для выравнивания по границе слова (n - число case-меток).
Таблица переходов имеет следующий вид:
Смещение | Значение |
---|---|
0 | Число case-меток |
1 | Смещение до первой case-метки |
2 | Смещение до второй case-метки |
3 | Смещение до третьей case-метки |
... | ... |
n | Смещение до n-ой case-метки |
n + 1 | Смещение до default-метки (default-метка может быть неявной) |
[n + 2] | Дополнение до границы слова (если нужно) |
В функцию передается номер case-метки a. После этого выполняются следующие действия:
- По адресу [lp] считывается число case-меток n;
- Переданный номер case-метки a "обрезается" по отрезку [0..n];
- Выполняется переход по адресу, указанному в таблице по индексу a.
lp - адрес возврата из процедуры.
Для приведенного выше примера код выглядит следующим образом (значиние a содержится в регистре r0):
SUBS r0,r0,#0xa
BL __ARM_switch8
DCB 0x06,0x04
DCB 0x06,0x08
DCB 0x0a,0x0e
DCB 0x0c,0x0e
Красным цветом выделены переходы по неявной default-метке. В частности, такой переход выполняется в случае, если значение a равно 14.
Комментариев нет:
Отправить комментарий