|
|
  |
Использование inline assembler в ARM GCC |
|
|
|
Apr 18 2007, 11:51
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 4-08-05
Из: г. Саратов
Пользователь №: 7 351

|
Возникла проблема при использовании inline assembler в ARM GCC. Есть следующий работающий код: Код typedef signed long fr32; typedef signed long long fx64;
fr32 fr32_mul(fr32 arg1, fr32 arg2) { fr32 result; asm ( "smull ip, r3, %1, %2 \n" "mov ip, ip, lsr #%a3 \n" "orr %0, ip, r3, lsl #2 \n" : "=r" (result) : "r" (arg1), "r" (arg2), "I" (FR32_FRACTION_BITS) : "r3", "ip" ); return result; } В нём аргумены и результат ("=r" (result), "r" (arg1), "r" (arg2)) 32-битные, а как описать 64-битные данные непонятно? Код fx64 fx64_mul(fx64 arg1, fx64 arg2) { fx64 result; asm ( ... : "=r" (result) // <- Какие модификатор тут должны быть ? : "r" (arg1), "r" (arg2) // <- Какие модификатор тут должны быть ? ); return result; } Есть, конечно, вариант реализовать аргументы и результат через объединение: Код union { fx64 value; struct { signed long msw; unsigned long lsw; } words; }; Но может, есть способ проще? К слову сказать для msp430 gcc существуют модификаторы: Код • %A[tag] acts as %[tag] for a register or address constant operand, or wraps an integer value as #llo(). #llo is an assembler macro, which extracts the lower 16 bits of the value. • %B[tag] adds 1 to a register number, or 2 to an address constant, or substitutes #lhi() for an integer constant. • %C[tag] adds 2 to a register number, or 4 to an address constant, or substitutes #hlo() for an integer constant. • %D[tag] adds 3 to a register number, 6 to an address constant, or substitutes #hhi() for an integer constant.
#define LONGVAL 0x12345678l { long a, b; ... asm("mov %A2, %A0 \n\t" "mov %B2, %B0 \n\t" "mov %A2, %A1 \n\t" "mov %B2, %B1 \n\t" : "=r"((long)a), "=m"((long)b) : "i"((long)LONGVAL) ); ... } А вот для arm gcc, я что-то подобного не нашёл.
|
|
|
|
|
Apr 19 2007, 10:29
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 4-08-05
Из: г. Саратов
Пользователь №: 7 351

|
Цитата(amw @ Apr 18 2007, 18:14)  На сколько я знаю, для ARM такого нет. По крайней мере в GCC 3.x.x. Перечитал всю документацию и пришёл к выводу, что в 4.1.1 тоже такого нет. Так что придётся использовать union
|
|
|
|
|
Apr 19 2007, 17:35
|
Местный
  
Группа: Свой
Сообщений: 359
Регистрация: 9-12-05
Пользователь №: 12 034

|
Немного не по вопросу, но... Если оно не инлайн, то что мешает полностью асм-овую функцию написать? Можно опять же встроенную в С, только объявить её c __attribute__((naked)), стандарт на ARM по передаче параметров вроде компиляторами поддерживается. Ещё не понял про FR32_FRACTION_BITS и "lsl #2". У Вас FR32_FRACTION_BITS может быть только 30? Или не нашли как из 32-х вычесть FR32_FRACTION_BITS (видимо можно так "lsl #(32 - %a3)" )? Кстати код Код b3 = (fr32)((((int64_t) b1) * ((int64_t) b2)) >> FR32_FRACTION_BITS); Генерит без учёта загрузки значений в регистры и сохранение результата на -O1 .. -O3 Код smull r1, r0, r2, r3 mov r3, r0, lsr #0x1e orr r3, r3, r1, lsl #0x02 mov r4, r1, asr #0x1e // лишняя командочка r4 потом не используется А на -Os вообще то что надо. Код smull r3, r12, r1, r2 mov r12, r12, lsr #0x1e orr r1, r12, r3, lsl #0x02 При этом на -Os GCC ещё и заинлайнил fr32_mul() вот в таком коде Код a3 = fr32_mul(a1, a2); b3 = (fr32)((((int64_t) b1) * ((int64_t) b2)) >> FR32_FRACTION_BITS); GCC - 4.1.2 PS Ещёб ответ на исходный вопрос найти.  Упс! Про -Os наврал. Код mov r4, r1, asr #0x02 там присутствует, просто код настолько наоптимизирован (перепутан) что строки Код a3 = fr32_mul(a1, a2); b3 = (fr32)((((int64_t) b1) * ((int64_t) b2)) >> FR32_FRACTION_BITS); на практике выполняются практически в обратном порядке.
|
|
|
|
|
Apr 20 2007, 14:21
|
Частый гость
 
Группа: Свой
Сообщений: 81
Регистрация: 4-08-05
Из: г. Саратов
Пользователь №: 7 351

|
Цитата(Alex03 @ Apr 19 2007, 18:35)  Если оно не инлайн, то что мешает полностью асм-овую функцию написать? В программе функция fr32_mul реализованна как инлайн, просто в вопросе я это опустил. Цитата(Alex03 @ Apr 19 2007, 18:35)  Можно опять же встроенную в С, только объявить её c __attribute__((naked)), стандарт на ARM по передаче параметров вроде компиляторами поддерживается. Тип fx64 имеет следующее представление: si.f, где s - знаковый бит, i - целая часть (23 бита), f - дробная часть (40 бит). Сейчас функция fx64_mul реализована без найкед, следующим образом Код fx64 fx64_mul(fx64 arg1, fx64 arg2) { register fx64 result asm("r0"); // Это формальность, а то gcc страшно ругается asm ( "umull r5, ip, r0, r2 \n" "umull lr, r5, r1, r2 \n" "mov r4, r1, asr #31 \n" "mla r4, r2, r4, r5 \n" "adds r2, lr, ip \n" "adc ip, r4, #0 \n" "umull r4, lr, r0, r3 \n" "mov r5, r3, asr #31 \n" "mla r5, r0, r5, lr \n" "adds r4, r4, r2 \n" "adc r5, r5, ip \n" "mov r4, r4, lsr #8 \n" "orr r2, r4, r5, lsl #24 \n" "smull r4, ip, r1, r3 \n" "mov r3, r5, asr #8 \n" "mov ip, ip, lsl #24 \n" "orr r1, ip, r4, lsr #8 \n" "mov r0, r4, lsl #24 \n" "adds r0, r0, r2 \n" "adc r1, r1, r3 \n" : /* no outputs */ : /* no inputs */ : "r0", "r1", "r2", "r3", "r4", "r5", "ip", "lr" ); return result; // Это формальность, а то gcc страшно ругается } Но мне так не очень нравится, поэтому и задал вопрос... Цитата(Alex03 @ Apr 19 2007, 18:35)  Ещё не понял про FR32_FRACTION_BITS и "lsl #2". У Вас FR32_FRACTION_BITS может быть только 30? Или не нашли как из 32-х вычесть FR32_FRACTION_BITS (видимо можно так "lsl #(32 - %a3)" )? Тут я согласен - вышла ошибочка, спасибо. Хотя с другой стороны FR32_FRACTION_BITS у меня всегда 30. Но для универсальности надо исправить.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|