Как повлиять на создание кода Delphi XEx для целей Android / ARM?

Обновление 2017-05-17. Я больше не работаю в компании, где возник этот вопрос, и у меня нет доступа к Delphi XEx. В то время как я был там, проблема была решена путем перехода на смешанный FPC + GCC (Pascal + C), с NEON intrinsics для некоторых подпрограмм, где это имело значение. (FPC + GCC настоятельно рекомендуется также потому, что он позволяет использовать стандартные инструменты, в частности Valgrind). Если кто-то может продемонстрировать, с достоверными примерами, как они на самом деле способны создавать оптимизированный код ARM из Delphi XEx, я рад принять ответ ,


Компиляторы Delphi компании Embarcadero используют LLVM-сервер для создания собственного кода ARM для устройств Android. У меня есть большое количество кода Паскаля, которые мне нужно скомпилировать в приложениях Android, и я хотел бы знать, как заставить Delphi генерировать более эффективный код. Прямо сейчас, я даже не говорю о таких расширенных функциях, как автоматическая оптимизация SIMD, а именно о создании разумного кода. Разумеется, должен быть способ передать параметры стороне LLVM или каким-то образом повлиять на результат? Как правило, любой компилятор будет иметь множество вариантов, влияющих на компиляцию и оптимизацию кода, но цели ARM в Delphi, по-видимому, просто «оптимизация вкл / выкл», и все.

Предполагается, что LLVM способен производить разумно жесткий и разумный код, но, похоже, Delphi использует свои возможности странным образом. Delphi хочет использовать стек очень сильно, и он обычно использует только регистры процессора r0-r3 в качестве временных переменных. Возможно, самый сумасшедший из всех, как представляется, загружает нормальные 32-битные целые числа в виде четырех 1-байтовых операций загрузки. Как заставить Delphi создавать улучшенный код ARM, и без байт-байтовых проблем, которые он делает для Android?

Сначала я думал, что байтовая байтовая загрузка предназначена для замены байтового байта от big-endian, но это не так, на самом деле это просто загрузка 32-битного числа с 4 однобайтовыми нагрузками. * Возможно, потребуется загрузить Полные 32 бита без выполнения неравномерной нагрузки на размер слова. (Нужно ли СЛЕДУЕТ избежать этого – это еще одна вещь, которая намекала бы на то, что это ошибка компилятора) *

Давайте посмотрим на эту простую функцию:

function ReadInteger(APInteger : PInteger) : Integer; begin Result := APInteger^; end; 

Даже при включенной оптимизации Delphi XE7 с пакетом обновления 1, а также XE6 выдает следующий код сборки ARM для этой функции:

 Disassembly of section .text._ZN16Uarmcodetestform11ReadIntegerEPi: 00000000 <_ZN16Uarmcodetestform11ReadIntegerEPi>: 0: b580 push {r7, lr} 2: 466f mov r7, sp 4: b083 sub sp, #12 6: 9002 str r0, [sp, #8] 8: 78c1 ldrb r1, [r0, #3] a: 7882 ldrb r2, [r0, #2] c: ea42 2101 orr.w r1, r2, r1, lsl #8 10: 7842 ldrb r2, [r0, #1] 12: 7803 ldrb r3, [r0, #0] 14: ea43 2202 orr.w r2, r3, r2, lsl #8 18: ea42 4101 orr.w r1, r2, r1, lsl #16 1c: 9101 str r1, [sp, #4] 1e: 9000 str r0, [sp, #0] 20: 4608 mov r0, r1 22: b003 add sp, #12 24: bd80 pop {r7, pc} 

Просто подсчитайте количество инструкций и доступ к памяти для Delphi для этого. И построим 32-битное целое число из 4 однобайтовых нагрузок … Если я немного изменил функцию и вместо указателя использовал параметр var, он немного менее запутан:

 Disassembly of section .text._ZN16Uarmcodetestform14ReadIntegerVarERi: 00000000 <_ZN16Uarmcodetestform14ReadIntegerVarERi>: 0: b580 push {r7, lr} 2: 466f mov r7, sp 4: b083 sub sp, #12 6: 9002 str r0, [sp, #8] 8: 6801 ldr r1, [r0, #0] a: 9101 str r1, [sp, #4] c: 9000 str r0, [sp, #0] e: 4608 mov r0, r1 10: b003 add sp, #12 12: bd80 pop {r7, pc} 

Здесь я не буду включать дизассемблирование, но для iOS Delphi создает идентичный код для версий параметров указателя и var, и они почти точно не совпадают с версией параметров Android var. Изменить: чтобы уточнить, побайтовая загрузка загружается только на Android. И только на Android версии параметров указателя и var отличаются друг от друга. На iOS обе версии генерируют точно такой же код.

Для сравнения, вот что такое FPC 2.7.1 (версия SVN с мая 2014 года) думает о функции с уровнем оптимизации -O2. Варианты параметров указателя и var точно такие же.

 Disassembly of section .text.n_p$armcodetest_$$_readinteger$pinteger$$longint: 00000000 <P$ARMCODETEST_$$_READINTEGER$PINTEGER$$LONGINT>: 0: 6800 ldr r0, [r0, #0] 2: 46f7 mov pc, lr 

Я также проверил эквивалентную функцию C с компилятором C, который поставляется с Android NDK.

 int ReadInteger(int *APInteger) { return *APInteger; } 

И это сводится к тому же, что и FPC:

 Disassembly of section .text._Z11ReadIntegerPi: 00000000 <_Z11ReadIntegerPi>: 0: 6800 ldr r0, [r0, #0] 2: 4770 bx lr 

Solutions Collecting From Web of "Как повлиять на создание кода Delphi XEx для целей Android / ARM?"

Мы расследуем этот вопрос. Короче говоря, это зависит от возможного неправильного выравнивания (до 32 границ) Integer, на который ссылается указатель. Нужно немного больше времени, чтобы получить ответы на все вопросы … и план по решению этого вопроса.

Марко Канту, модератор Delphi Developers

Также ссылка Почему библиотеки Delphi zlib и zip настолько медленны до 64 бит? Поскольку библиотеки Win64 отправляются без оптимизации.


В отчете QP: RSP-9922 Bad ARM-код, созданный компилятором, игнорируется директивой $ O? , Марко добавил следующее объяснение:

Здесь есть несколько проблем:

  • Как указано, настройки оптимизации применяются только к целым файлам устройства, а не к отдельным функциям. Проще говоря, включение и выключение оптимизации в том же файле не будет иметь никакого эффекта.
  • Кроме того, просто включение «Отладочной информации» отключает оптимизацию. Таким образом, при отладке явное включение оптимизаций не будет иметь никакого эффекта. Следовательно, представление ЦП в среде IDE не сможет отобразить разобранное представление оптимизированного кода.
  • В-третьих, загрузка не выровненных 64-битных данных небезопасна и приводит к ошибкам, а следовательно, к отдельным 4-байтным операциям, которые необходимы в данных сценариях.