Я хочу написать следующий цикл, используя расширенный встроенный 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) : ...
, все равно.
Между тем я знаю официальную документацию практически наизусть, но я все еще не вижу свою ошибку.
act_ptr += STEP_SIZE;
может ли STEP_SZIE обработать арифметику указателя, выходящую за пределы? Даже если это без разыменования? - person dhein   schedule 26.08.2013do ... while (...)
). Это означает, что вы можете (и, вероятно, делаете) записывать за пределы выделенной памяти. - person Some programmer dude   schedule 26.08.2013jl
вместоjle
для зацикливания. - person Rene R.   schedule 26.08.2013;
не для комментариев? ты пробовал\n
? - person Alex   schedule 26.08.2013\n\t
. Также работает;
, если ассемблер допускает точку с запятой в качестве символа разрыва строки. - person Rene R.   schedule 26.08.2013-S
.S
сvim
, и он показал код после;
, как прокомментировано, но разница двухobjdump -S
с;
и\n
не показывает различий, так что вы правы. Я получаю ошибкуfree()
при выполнении кода (как будто aptr становится недействительным), может быть, нужно затереть используемые регистры? - person Alex   schedule 26.08.2013"r"
для операнда вместо указания конкретного регистра устраняет необходимость его присутствия в списке затирания. - person Rene R.   schedule 26.08.2013movl
работает, но когда я включаюleal
, он не работает. - person Alex   schedule 26.08.2013lea
на вариантadd
, но результат тот же. - person Rene R.   schedule 26.08.2013"q"
(регистрыa b c d
) вместо"r"
, по умолчанию использовалосьesi
. Обратите внимание, что собранная версия C отличается от вашей реализации, но если я снова попытаюсь встроить asm, будет выбраноesi
и произойдет сбой. - person Alex   schedule 26.08.2013esi
- это регистр, в котором хранится результатnew
и никогда не обновляется, и поэтомуdelete
затем терпит неудачу. Думаю, лучше явно указать регистры для использования и стереть их. - person Alex   schedule 26.08.2013