Я бы сказал, что оно того не стоит. Я работаю над программным обеспечением, которое выполняет 3D-рендеринг в режиме реального времени (то есть, рендеринг без помощи графического процессора). Я широко использую встроенные функции компилятора SSE - много уродливого кода, заполненного __mm_add_ps()
и друзьями, - но мне не нужно было очень долго перекодировать функцию в сборке.
По моему опыту, хорошие современные оптимизирующие компиляторы чертовски эффективны при сложной микроуровневой оптимизации. Они будут выполнять сложные циклические преобразования, такие как переупорядочивание, развертывание, конвейерная обработка, блокировка, укладка плитки, заклинивание, деление и тому подобное. Они планируют инструкции по заполнению конвейера, векторизации простых циклов и развертыванию некоторых интересных хитростей. Современные компиляторы невероятно увлекательные звери.
Можете ли вы победить их? Ну, конечно, учитывая, что они выбирают оптимизацию для эвристики, они иногда ошибаются. Но я обнаружил, что гораздо лучше оптимизировать сам код, глядя на картину в целом. Выкладываю ли я свои структуры данных наиболее удобным для кеша способом? Я делаю что-то неортодоксальное, что вводит в заблуждение компилятор? Могу ли я что-нибудь переписать, чтобы дать компилятору лучшие подсказки? Мне лучше пересчитать что-то, а не хранить? Может ли помочь вставка предварительной выборки? У меня где-то есть ложный обмен кешем? Есть ли небольшая оптимизация кода, которую компилятор считает небезопасной, но все в порядке (например, преобразование деления в умножение на обратную)?
Мне нравится работать с компилятором, а не против него. Пусть он позаботится об оптимизации на микроуровне, чтобы вы могли сосредоточиться на оптимизациях на мезонном уровне. Важно иметь хорошее представление о том, как работает ваш компилятор, чтобы вы знали, где находятся границы между этими двумя уровнями.