Я должен исправить существующий тест набора инструкций, который не проверяет все используемые инструкции. Итак, мне нужно просмотреть ассемблерный файл одного уровня кода и выяснить, какой код C вызывает выполнение инструкции, чтобы я мог использовать ее в своем патче.
Ваша цель безумна, а первая половина вашего вопроса имеет обратное значение/лишь слабое отношение к вашей реальной проблеме.
Может быть способ убедить ваш компилятор использовать каждую конкретную инструкцию, которую вы хотите, но это будет зависеть от версии вашего компилятора, параметров и всего окружающего кода, включая потенциально константы в файлах заголовков.
Если вы хотите протестировать все инструкции в ISA, надеяться, что вы сможете убедить компилятор C сгенерировать их каким-то образом, — это совершенно неправильный подход. Вы хотите, чтобы ваш тест продолжал проверять одно и то же в будущем, поэтому вы должны . Если вам нужен конкретный asm, пишите на asm.
Это тот же вопрос, заданный пару недель назад для ARM: оптимизация-будет-ди">Как заставить IAR использовать нужные инструкции Cortex-M0+ (оптимизация для этой функции будет отключена) за исключением того, что вы говорите, что собираетесь строить с включенной оптимизацией (что может упрощают получение более широкого диапазона генерируемых инструкций: некоторые из них можно использовать только в качестве глазок-оптимизаторов по сравнению с простым обычным генерированием кода).
Кроме того, начиная с asm и превращая его в эквивалентный C, нет гарантии, что компилятор выберет эту инструкцию при компиляции, поэтому заголовок вопроса лишь слабо связан с вашей реальной проблемой.
Если вы все еще хотите заставить компилятор генерировать конкретный ассемблер, чтобы создать хрупкий исходный код, который может делать только то, что вы хотите, с очень специфическими компилятором / версией / параметрами, первым шагом будет подумайте: «когда эта инструкция станет частью оптимизированного способа выполнения чего-либо?».
Обычно этот ход мыслей более полезен для оптимизации путем настройки исходного кода для более эффективной компиляции. Сначала вы думаете об эффективной реализации функции, которую вы пишете, на ассемблере. Затем вы пишете свой исходный код на C или C++ таким же образом, т. е. используя те же временные файлы, которые, как вы надеетесь, будет использовать компилятор. Например, см. >Каков эффективный способ подсчета установленных битов в позиции или ниже? где я смог заставить gcc использовать более эффективную последовательность инструкций, как это делал clang в моей первой попытке.
Иногда это может сработать; для ваших целей это просто, когда в наборе инструкций есть только один действительно хороший способ что-то сделать. например ld.bu
выглядит как байтовая загрузка с нулевым расширением (u
для беззнакового) в полный регистр. unsigned foo(unsigned char*p) {return *p;}
должен компилироваться в это, и вы можете использовать атрибут noinline
, чтобы предотвратить его оптимизацию.
Но insert
, если это вставка нулевого бита в битовое поле, с тем же успехом могло бы быть and
с ~1
(0xFE), предполагая, что TriCore имеет и-немедленное. Если insert
имеет не непосредственную форму, это, вероятно, самый эффективный вариант для single-bit bitfield = rand()
(или любого значения, которое все еще не является константой времени компиляции после оптимизации с распространением констант).
Для упакованных арифметических инструкций TriCores (SIMD) вам понадобится компилятор для автоматической векторизации или использования встроенного.
В ISA вполне могут быть некоторые инструкции, которые ваш компилятор никогда не выдаст. Хотя я думаю, что вы только пытаетесь проверить инструкции, которые компилятор выдает в других частях вашего кода? Вы говорите «все используемые инструкции», а не «все инструкции», чтобы хотя бы гарантировать, что задача возможна.
Не встроенная функция с аргументом — отличный способ принудительно сгенерировать код для переменных времени выполнения. Те, кто использует asm, сгенерированный компилятором, часто пишут небольшие функции, которые принимают аргументы и возвращают значение (или сохраняют в глобальную или volatile
), чтобы заставить компиляцию генерировать код для чего-то, не отбрасывая результат и не превращая распространение констант. всю функцию в return 42;
, т. е. mov
-непосредственное / ret
. См. Как удалить шум из вывода сборки GCC/clang? подробнее об этом, а также выступление Мэтта Годболта на CppCon2017: «Что мой компилятор сделал для меня в последнее время? Unbolting the Compiler's Lid» для отличного введения новичка в чтение ассемблерного кода, сгенерированного компилятором, и того, что современные оптимизирующие компиляторы делают для небольших функций.
Присвоение volatile
, а затем чтение этой переменной было бы еще одним способом победить распространение констант даже для теста, который должен выполняться без внешних входных данных, если это проще, чем использование неинлайновых функций. (Компиляторы перезагружают из volatile
каждый раз, когда он читается в исходном коде C, т.е. они должны предполагать, что он может быть изменен асинхронно.)
int main(void) {
volatile int vtmp = 123;
int my_parameter = vtmp;
... then use my_parameter, not vtmp, so CSE and other optimizations can still work
}
[...] Он оптимизирован
Показанный вами вывод компилятора определенно не выглядит оптимизированным. Это похоже на загрузку/установку бита/сохранение, затем загрузку/очистку бита/сохранение, которое должно быть оптимизировано до простой загрузки/очистки бита/сохранения. Если только эти ассемблерные блоки не были на самом деле непрерывными, и вы показываете код из двух разных блоков, склеенных вместе.
Кроме того, InsertStruct.SomeMember = 0x0u;
— неполное описание: очевидно, оно зависит от определения структуры; Я предполагаю, что вы использовали однобитовое битовое поле int SomeMember :1;
? Согласно справочному руководству TriCore ISA, которое я нашел, insert
копирует диапазон битов из одного регистра в другой в указанной позиции вставки и поступает в форме регистра и непосредственного источника.
Замена целого байта может быть просто хранилищем вместо чтения/изменения/записи. Таким образом, ключевым моментом здесь является определение структуры, а не только оператор, скомпилированный в инструкцию.
person
Peter Cordes
schedule
18.12.2017
x / 15
путем умножения или удаляя значения суммирования всего цикла путем прямого вычисления результата и т. д. Если вы попытаетесь восстановить исходный код C из такой сборки, вы получите совершенно другой источник (с точки зрения алгоритма). - person Ped7g   schedule 18.12.2017