Адрес этикетки (MSVC) - PullRequest
25 голосов
/ 21 июня 2011

Мы пишем байт-код для высокоуровневого скомпилированного языка, и после небольшого количества профилирования и оптимизации выяснилось, что наибольшими в настоящее время издержками производительности является оператор switch, который мы используем для перехода кслучаи кода.

Мы исследовали извлечение адреса каждой метки случая и сохранение его в потоке самого байт-кода, а не идентификатора инструкции, который мы обычно включаем.Если мы это сделаем, мы можем пропустить таблицу переходов и напрямую перейти к расположению кода текущей выполняемой инструкции.В GCC это работает фантастически, однако MSVC, похоже, не поддерживает такую ​​функцию.

Мы попытались использовать встроенную сборку, чтобы получить адрес меток (и перейти к ним), и это работаетоднако использование встроенной сборки приводит к тому, что оптимизатор MSVC избегает выполнения всей функции.

Есть ли способ разрешить оптимизатору по-прежнему выполнять код?К сожалению, мы не можем извлечь встроенную сборку в другую функцию, отличную от той, в которой были сделаны метки, поскольку нет способа ссылаться на метку для другой функции даже во встроенной сборке.Есть мысли или идеи?Ваш вклад очень важен, спасибо!

Ответы [ 3 ]

17 голосов
/ 15 июля 2011

Единственный способ сделать это в MSVC - использовать встроенную сборку (что в основном приводит к сбоям в x64):

int _tmain(int argc, _TCHAR* argv[])
{
case_1:
    void* p;
    __asm{ mov [p],offset case_1 }
    printf("0x%p\n",p);
    return 0;
}

Если вы планируете сделать что-то подобное, то лучшим способом будет написать весь интерпретатор в сборке, а затем связать его с основным двоичным файлом через компоновщик (это то, что сделал LuaJIT, и это основная причина того, что ВМ работает так быстро, когда не выполняется код JIT).

LuaJIT с открытым исходным кодом , так что вы можете воспользоваться некоторыми советами, если пойдете по этому пути. В качестве альтернативы вы можете захотеть взглянуть на источник четвертого (создатель которого разработал принцип , который вы пытаетесь использовать), если есть сборка MSVC, вы можете увидеть, как они ее выполнили, иначе вы застряли с GCC (который не является плохой вещью, он работает на всех основных платформах).

10 голосов
/ 03 апреля 2012

Посмотрите, что делает Erlang для сборки на Windows.Они используют MSVC для большей части сборки, а затем GCC для одного файла, чтобы использовать расширение меток как значений.Полученный объектный код затем взламывается, чтобы сделать его совместимым с компоновщиком MSVC.

http://www.erlang.org/doc/installation_guide/INSTALL-WIN32.html

4 голосов
/ 15 июля 2011

Кажется, вы можете просто переместить действительный код в функции вместо меток регистра.Затем байтовый код можно легко преобразовать в прямые вызовы.Т.е. байт-код 1 будет переведен в CALL BC1.Поскольку вы генерируете прямые вызовы, у вас нет накладных расходов на указатели функций.Конвейеры большинства ЦП могут следовать таким безусловным прямым ветвям.

В результате фактические реализации каждого байтового кода оптимизируются, и преобразование из байтового кода в код машинного производства является тривиальным преобразованием 1: 1.Вы получаете немного расширения кода, поскольку каждый CALL составляет 5 байтов (при условии x86-32), но это вряд ли будет серьезной проблемой.

...