GCC Перейти таблицы инициализации кода генерирования MOVSXD и добавить? - PullRequest
0 голосов
/ 05 сентября 2018

Когда я компилирую оператор switch с оптимизацией в GCC, он устанавливает таблицу переходов следующим образом:

(fcn) sym.foo 148
  sym.foo (unsigned int arg1);
; arg unsigned int arg1 @ rdi
0x000006e0      83ff06         cmp edi, 6                              ; arg1
0x000006e3      0f87a7000000   ja case.default.0x790
0x000006e9      488d156c0100.  lea rdx, [0x0000085c]
0x000006f0      89ff           mov edi, edi
0x000006f2      4883ec08       sub rsp, 8
0x000006f6      486304ba       movsxd rax, dword [rdx + rdi*4]
0x000006fa      4801d0         add rax, rdx                            ; '('
;-- switch.0x000006fd:
0x000006fd      ffe0           jmp rax                                 ; switch table (7 cases) at 0x85c

Является ли MOVSXD и ADD лучшим способом сделать это,

movsxd rax, dword [rdx + rdi*4]
add rax, rdx

Разве это не то же самое, что использование LEA с displacement

lea rax, [rdx + rdi*4 + rdx]

Мне приходит в голову, что я, вероятно, не понимаю, что здесь происходит. RDX кажется началом старта таблицы переходов. RDI является входящим аргументом для оператора switch. Почему мы добавляем RDX дважды, хотя?

Это оператор switch, с которым я компилировал -O3,

int foo (int x) {
  switch(x) {
    //case 0: puts("\nzero"); break;
    case 1: puts("\none"); break;
    case 2: puts("\ntwo"); break;
    case 3: puts("\nthree"); break;
    case 4: puts("\nfour"); break;
    case 5: puts("\nfive"); break;
    case 6: puts("\nsix"); break;
  }
  return 0;
}

Ответы [ 2 ]

0 голосов
/ 05 сентября 2018

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

Если вы компилируете с -fno-pie -no-pie, gcc может выбрать использование таблицы целей перехода с jmp [table + rdi*8]

Такие цели, как x86-64 Linux, поддерживают исправления данных во время выполнения, поэтому возможна простая таблица переходов. Но некоторые цели вообще не поддерживают исправления, поэтому gcc -fPIC / -fpie полностью их избегает. Эта потенциальная оптимизация - gcc bug 84011 . Смотрите обсуждение там для более.


К сожалению, gcc использует таблицу переходов вместо того, чтобы понимать, что единственное различие между каждым случаем - это данные, а не код. Так что на самом деле просто нужен поиск по таблице указателей строк. (Что может быть сделано с относительными смещениями, если это необходимо.)

Это отдельная пропущенная оптимизация, о которой я сообщил как ошибка 85585 . (Это напоминает мне, у меня есть продолжение к этой половине написанного, которое я должен закончить и опубликовать.)

0 голосов
/ 05 сентября 2018

Является ли MOVSXD и ДОБАВИТЬ лучший способ сделать это,

Это можно сделать с помощью add с операндом памяти qword. Конечно, недостатком является то, что он делает стол в два раза больше.

Разве это не то же самое, что использование LEA со смещением

Нет, lea не обращается к памяти.

Почему мы добавляем гексоген дважды?

Первый раз, когда она используется в качестве основы таблицы для индексации в ней. Таблица содержит адреса относительно себя, поэтому добавление RDX к значению из таблицы создает абсолютный адрес.

Кстати, это можно легко улучшить:

mov edi, edi     ; truncate rdi to 32bit

Самовывоз не может быть исключен при перемещении в существующих архитектурах, поэтому было бы лучше перейти в какой-либо другой регистр.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...