Использование флагов условий в качестве встроенных выходных данных GNU C
Я работаю над кодом, в котором было бы крайне желательно получить выходные данные флагов условий из встроенного asm-блока и использовать их в качестве условия для перехода в вызывающем коде C. Я не хочу хранить флаги (это было бы бесполезно и неэффективно; уже есть более эффективные способы достижения результата), но использую флаги напрямую. Есть ли способ добиться этого с помощью встроенных ограничений GNU C? Мне интересны подходы, которые будут работать для нескольких архитектур наборов команд, с намерением использовать его с флагами условий, создаваемыми атомами стиля LL/SC архитектуры. Конечно, другой очевидный случай использования (отдельно от того, что я делаю) - позволить внешнему коду C перейти на результат флага переноса из операции inline asm.
3 ответа
Начиная с GCC6 на x86, вы можете использовать "=@ccCOND"
как вывод (где COND
любой допустимый код условия x86).
Пример изначально отсюда, очищенный предложениями Дэвида:
int variable_test_bit(long n, volatile const unsigned long *addr)
{
int oldbit;
asm volatile("bt %[value],%[bit]"
: "=@ccc" (oldbit)
: [value] "m" (*addr), [bit] "Jr" (n));
return oldbit;
}
Прежде чем использовать это, вы должны проверить, если __GCC_ASM_FLAG_OUTPUTS__
определено.
У меня есть частичное решение, но мне оно не очень нравится, потому что оно требует помещения инструкции перехода в asm, и потому что это требует очень уродливой функции GCC, которую другие "GNU C-совместимые" компиляторы могут не поддерживать: asm goto
, Это, однако, позволяет удалить ветку за пределами asm. Идея заключается в следующем:
static inline int foo(...)
{
__asm__ goto ( " .... ; cond_jmp %l[ret0]" : : "r"(...) ...
: "clobbers" : ret0 );
return 1;
ret0:
return 0;
}
Когда указывается в вызывающем if (foo(...)) ... else ...
условный переход в блоке asm в конечном итоге указывает на else
ветвь, даже если на уровне абстрактной машины присутствуют возвращаемые значения.
К сожалению, GCC не поддерживает доступ к флагам условий вне операторов asm. Если вы не хотите устанавливать значение, вам придется переместить условную ветвь в оператор asm. Это означает либо использование уже обнаруженных меток asm goto, либо добавление цели перехода в оператор asm.
Возможно, вы также захотите проверить, обеспечивают ли функциональные возможности GCC старого стиля GCC __sync или более новые атомы на основе модели памяти те функции, которые вы хотите использовать из атомарных инструкций, которые вы используете.