Простой цикл while в сборке GCC

Я хочу написать следующий цикл, используя расширенный встроенный ASM GCC:

long* arr = new long[ARR_LEN]();
long* act_ptr = arr;
long* end_ptr = arr + ARR_LEN;

while (act_ptr < end_ptr)
{
*act_ptr = SOME_VALUE;
act_ptr += STEP_SIZE;
}

delete[] arr;

Массив типа long с длиной ARR_LEN выделяется и инициализируется нулями. Цикл проходит по массиву с шагом STEP_SIZE, Каждый затронутый элемент установлен в SOME_VALUE,

Ну, это была моя первая попытка в ГАЗ:

long* arr = new long[ARR_LEN]();

asm volatile
(
"loop:""movl %[sval], (%[aptr]);""leal (%[aptr], %[incr], 4), %[aptr];""cmpl %[eptr], %[aptr];""jl loop;": // no output
: [aptr] "r" (arr),
[eptr] "r" (arr + ARR_LEN),
[incr] "r" (STEP_SIZE),
[sval] "i" (SOME_VALUE)
: "cc", "memory");

delete[] arr;

Как уже упоминалось в комментариях, это правда, что этот ассемблерный код больше do {...} while цикл, но на самом деле он делает ту же работу.

Странная вещь в этом куске кода в том, что сначала он работал нормально для меня. Но когда я позже попытался заставить его работать в другом проекте, казалось, что он ничего не сделает. Я даже сделал 1: 1 копии за работой проект, скомпилированный снова и … все же результат является случайным.

Может быть, я принял неправильные ограничения для входных операндов, но на самом деле я уже опробовал почти все из них, и у меня нет никакой реальной идеи. Что меня особенно озадачивает, так это то, что он все еще работает в некоторых случаях.

Я не являюсь экспертом в ASM, хотя я узнал об этом, когда еще учился в университете. Обратите внимание, что я не ищу оптимизации — я просто пытаюсь понять, как работает встроенная сборка. Итак, вот мой вопрос: есть ли что-то принципиально неправильное в моей попытке или я совершил здесь более тонкую ошибку? Заранее спасибо.

(Работа с g ++ MinGW Win32 x86 v.4.8.1)

Обновить

Я уже опробовал каждое предложение, которое было внесено здесь до сих пор. В частности я пробовал

  • используя ограничение операнда «q» вместо «r», иногда это работает, иногда нет,
  • пишу ... : [aptr] "=r" (arr) : "0" (arr) ... вместо того же результата,
  • или даже ... : [aptr] "+r" (arr) : ..., все тот же.

Между тем я знаю чиновника документация почти наизусть, но я все еще не вижу свою ошибку.

3

Решение

Вы модифицируете входной операнд (aptr) что не разрешено. Либо ограничьте его совпадением с выходным операндом, либо измените его на операнд ввода / вывода.

2

Другие решения

Вот полный код, который имеет предполагаемое поведение.

  • Обратите внимание, что код написан для 64-битной машины. Поэтому, например, %%rbx используется вместо %%ebx в качестве базового адреса для массива. По той же причине leaq а также cmpq следует использовать вместо leal а также cmpl,
  • movq должен использоваться, так как массив имеет тип long,
  • Тип long это 8 байт, а не 4 байта на 64-битной машине.
  • jl в вопросе должно быть изменено на jg,
  • Метки регистров нельзя использовать, поскольку они будут заменены компилятором на 32-битную версию выбранного регистра (например, ebx).
  • скованность "r" не может быть использован. "r" означает, что любой регистр может быть использован, однако не любая комбинация регистров является приемлемой для leaq, Смотри сюда: режимы адресации x86

    #include <iostream>
    
    using namespace std;
    
    int main(){
    
    int ARR_LEN=20;
    int STEP_SIZE=2;
    long SOME_VALUE=100;
    
    long* arr = new long[ARR_LEN];
    
    int i;for (i=0; i<ARR_LEN; i++){
    arr[i] = 0;
    }
    
    __asm__ __volatile__
    (
    "loop:""movq %%rdx, (%%rbx);""leaq (%%rbx, %%rcx, 8), %%rbx;""cmpq %%rbx, %%rax;""jg loop;": // no output
    : "b" (arr),
    "a" (arr+ARR_LEN),
    "c" (STEP_SIZE),
    "d" (SOME_VALUE)
    : "cc", "memory");
    
    for (i=0; i<ARR_LEN; i++){
    cout << "element " << i << " is " << arr[i] << endl;
    }
    
    delete[] arr;
    
    return 0;
    
    }
    
2

Как насчет ответа, который работает как для x86, так и для x64 (хотя он предполагает, что long всегда 4 байта, а-ля Windows)? Основным изменением от OP является использование «+ r» и (temp).

#include <iostream>

using namespace std;

int main(){

int ARR_LEN=20;
size_t STEP_SIZE=2;
long SOME_VALUE=100;

long* arr = new long[ARR_LEN];

for (int i=0; i<ARR_LEN; i++){
arr[i] = 0;
}

long* temp = arr;

asm volatile (
"loop:\n\t""movl %[sval], (%[aptr])\n\t""lea (%[aptr], %[incr], %c[size]), %[aptr]\n\t""cmp %[eptr], %[aptr]\n\t""jl loop\n\t": [aptr] "+r" (temp)
: [eptr] "r" (arr + ARR_LEN),
[incr] "r" (STEP_SIZE),
[sval] "i" (SOME_VALUE),
[size] "i" (sizeof(long))
: "cc", "memory");

for (int i=0; i<ARR_LEN; i++){
cout << "element " << i << " is " << arr[i] << endl;
}

delete[] arr;

return 0;
}
0
По вопросам рекламы [email protected]