Ложное срабатывание: вызывающему объекту возвращено неопределенное или мусорное значение.

Следующий код заполняет результат с помощью встроенной сборки:

uint64_t Foo::f() {
    uint64_t result;

    asm volatile
    ("vldmia        %1, {q0-q1}     \n" // q0-1 = *this

     ⋮

     "vstmia        %0, {d0}        \n" // result = d0

     :: "r"(&result), "r"(this)
     : "q0", "q1");

    return result;
}

Переменная result безоговорочно установлена ​​в ассемблерном коде, но анализатор Xcode, похоже, игнорирует это (анализ потока переходит прямо от объявления к оператору возврата) и жалуется:

…/BitBoard.cpp:26:9: Undefined or garbage value returned to caller

Есть ли способ успокоить анализатор, не тратя циклы на инициализацию result?

EDIT: я попробовал указать ограничение вывода:

: "=r"(&result) : "r"(this), "r"(&result)

Но компилятор хрипит с "Invalid lvalue in asm output". Удаление & компилирует, но возвращает случайные результаты. Изменение vstmia %0, {d0} на vmov %0, d0 также завершается ошибкой с сообщением «Недопустимый операнд для инструкции».

Я подозреваю, что мне нужно пометить result как вывод, как было предложено, и заполнить его по-другому в коде сборки, но я не могу найти никакой информации о том, как это сделать.


person Marcelo Cantos    schedule 15.06.2013    source источник


Ответы (2)


Я подозреваю, что это связано с отсутствием ограничения вывода.

Попробуй это,

uint64_t Foo::f() {
    uint64_t result;

    asm /* volatile */
    ("vldmia        %1, {q0-q1}     \n" // q0-1 = *this

     ⋮

     "vstmia        %0, {d0}        \n" // result = d0

     : "=w"(result): "r"(this) : "q0", "q1");

    return result;
}

Вы должны использовать ограничение output, "=w"(result), чтобы сообщить компилятору, что ассемблер устанавливает значение. Вам, вероятно, не понадобится volatile, если вы это сделаете. По крайней мере, это хорошая проблема для устранения.

person Community    schedule 15.06.2013
comment
Это дает мне Invalid lvalue в выводе asm. Удаление & компилируется и запускается, но возвращает неверные (кажущиеся случайными) результаты. Изменение vstmia %0, {d0} на vmov %0, d0 также не скомпилируется с недопустимым операндом для инструкции. - person Marcelo Cantos; 15.06.2013
comment
Попробуйте "=Um"(&result) тогда; принцип в том, что вы не сказали компилятору, как он был установлен. См. встроенные секреты asm ARM для некоторых ограничений. Это внутренние для gcc, но я подозреваю, что те же ограничения работают для xcode/llvm. См.: constraints.md для полного списка. - person artless noise; 16.06.2013
comment
Это тоже не компилируется (та же ошибка, что и "=r"(&result)), и если я удалю &, я не смогу скомпилировать ни vstmia, ни vmov. Аналогично для Un, Us и Uq. - person Marcelo Cantos; 16.06.2013
comment
Я нашел это! "=w"(result). Я поставлю тебе галочку, так как ты поставил меня на правильный путь. - person Marcelo Cantos; 16.06.2013
comment
=w хорош тем, что это стандартное/задокументированное ограничение. Я меняю ответ на вики-режим, не стесняйтесь обновлять его. - person artless noise; 16.06.2013

Я нашел обходной путь, хотя я все еще надеюсь на более элегантное решение:

    union {
        uint64_t result;
        struct { uint32_t a, b; };
    };

    asm
    ("vldmia        %2, {q0-q1}     \n" // q0-1 = *this

     ⋮

     "vmov        %0, s0        \n"
     "vmov        %1, s1        \n"

     : "=r"(a), "=r"(b) : "r"(this)
     : "q0", "q1");

    return result;
person Marcelo Cantos    schedule 15.06.2013