Я использую GCC 4.8.1 для компиляции кода C, и мне нужно определить, происходит ли недочет при вычитании на архитектуре x86/64. Оба не подключены. Я знаю, что в сборке очень просто, но мне интересно, могу ли я сделать это в коде C и у GCC его оптимизировать, потому что я не могу его найти. Это очень полезная функция (или низкий уровень, это термин?), Поэтому мне нужно, чтобы она была эффективной, но GCC кажется слишком глупым, чтобы распознать эту простую операцию? Я пробовал так много способов дать ему подсказки на языке C, но он всегда использует два регистра, а не только суб и условный прыжок. И, честно говоря, я раздражаюсь, увидев такой глупый код, написанный так много раз (функция называется лот).Вычесть и обнаружить нижний поток, наиболее эффективным способом? (x86/64 с GCC)
Мой лучший подход в C казалось следующее:
if((a-=b)+b < b) {
// underflow here
}
В основном, вычесть из А, и если результат обнуляется, обнаружить его и сделать некоторые условную обработку (которая не имеет отношения к своей стоимости, например, , это приводит к ошибке и т. д.).
GCC кажется слишком глупым, чтобы уменьшить приведенное выше значение только до суб и условного перехода, и поверьте, я пробовал так много способов сделать это в коде C и пытался использовать множество параметров командной строки (-O3 и -Os включены конечно). Что GCC делает что-то вроде этого (сборки Intel синтаксис):
mov rax, rcx ; 'a' is in rcx
sub rcx, rdx ; 'b' is in rdx
cmp rax, rdx ; useless comparison since sub already sets flags
jc underflow
Излишне говорить выше глупо, когда все, что нужно это:
sub rcx, rdx
jc underflow
Это так раздражает, потому что GCC, понимает что sub изменяет флаги таким образом, так как, если я привожу его в «int», он будет генерировать точный выше, за исключением того, что использует «js», который является прыжком со знаком, а не переносом, который не будет работать, если разность значений без знака высокая достаточно, чтобы установить высокий бит. Тем не менее он показывает, что он знает о вспомогательной инструкции, влияющей на эти флаги.
Теперь, может быть, я должен отказаться от попыток сделать GCC оптимальным для этого правильно и сделать это с помощью встроенной сборки, с которой у меня нет проблем. К сожалению, для этого требуется «asm goto», потому что мне нужен условный JUMP, и asm goto не очень эффективен с выходом, потому что он изменчив.
Я пробовал что-то, но я понятия не имею, безопасно ли это использовать или нет. По какой-то причине asm goto не может иметь выход. Я не хочу, чтобы он сбрасывал все регистры в память, что убьет весь момент, когда я делаю это, что является эффективностью. Но если я использую пустые операторы asm с выходами, установленными в переменную 'a' до и после нее, это будет работать и безопасно? Вот мой макрос:
#define subchk(a,b,g) { typeof(a) _a=a; \
asm("":"+rm"(_a)::"cc"); \
asm goto("sub %1,%0;jc %l2"::"r,m,r"(_a),"r,r,m"(b):"cc":g); \
asm("":"+rm"(_a)::"cc"); }
и использовать его как это:
subchk(a,b,underflow)
// normal code with no underflow
// ...
underflow:
// underflow occured here
Это немного некрасиво, но это работает просто отлично. В моем тестовом сценарии он компилирует только FINE без изменчивых накладных расходов (сброс регистров в память), не создавая ничего плохого, и кажется, что он работает нормально, однако это всего лишь ограниченный тест, я не могу проверить это везде, где я использую эту функцию/macro, поскольку я сказал, что он используется LOT, поэтому я хотел бы знать, хорошо ли кто-то осведомлен, есть ли что-то небезопасное в вышеупомянутой конструкции?
В частности, значение «a» НЕ НЕОБХОДИМО, если происходит недостаточное течение, поэтому, имея в виду, есть ли какие-либо побочные эффекты или небезопасные вещи, которые могут произойти с моим встроенным макросом asm? Если нет, я буду использовать его без проблем, пока они не оптимизируют компилятор, поэтому я могу заменить его обратно после того, как я предполагаю.
Пожалуйста, не превращайте это в дискуссию о преждевременных оптимизациях, а что нет, оставайтесь на теме вопроса, я полностью об этом знаю, так что спасибо.
Я думаю, что проблема заключается в том, что вы предполагаете, что компиляторы всегда оптимизируют «лучший» способ сделать что-то, недостаток - это ваше предположение, а не компилятор или оптимизатор. –
gcc, это с открытым исходным кодом ... Если вам это не нравится, измените его ... –
Узор if ((r = x - y)> x) лучше. На самом деле, это один из ответов ниже. –