реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> IAR ARM ассемблер, Преобразовать процедуру в макрос
Sergey_Aleksandr...
сообщение Aug 28 2017, 13:42
Сообщение #1


Частый гость
**

Группа: Свой
Сообщений: 168
Регистрация: 8-10-08
Из: РФ Смоленск
Пользователь №: 40 764



Здравствуйте. В проекте функция реализована как ассемблерная процедура. Состоит из одной инструкции и хотелось бы преобразовать её в макрос, чтобы не тратить такты на вход и выход.
Реализована в *.s файле в виде
Код
    SECTION .text:CODE:NOROOT(2)
    PUBLIC MULSHIFT32
    THUMB
MULSHIFT32
    smull    r2, r0, r1, r0
    BX lr

Далее используется в *.c файлах как обычная функция b2 = MULSHIFT32(*cptr++, a1 - a2) << (s1);

Не зная тонкостей синтаксиса ассемблера IAR попробовал "в лоб" реализовать таким образом
Код
MULSHIFT32 MACRO
    smull    r2, r0, r1, r0
    ENDM


Линкер ругается на неизвестное имя MULSHIFT32. Ключевые слова PUBLIC и EXTERN вызывают ошибку. Кто подскажет, как этот макрос правильно оформить, чтобы можно было использовать его вне *.s-файла?
Go to the top of the page
 
+Quote Post
VladislavS
сообщение Aug 28 2017, 14:01
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140



Не занимайтесь ерундой. Умножать с нужной разрядностью - дело компилятора.

Код
  int32_t x=1L,y=2L;
  int64_t z;
  z = (int64_t)x*y;


Дадут вам
Код
//  106   int32_t x=1L,y=2L;
        MOVS     R0,#+1
        STR      R0,[SP, #+4]
        MOVS     R0,#+2
        STR      R0,[SP, #+0]
//  107   int64_t z;
//  108   z = (int64_t)x*y;
        LDR      R0,[SP, #+4]
        LDR      R1,[SP, #+0]
        SMULL    R0,R1,R1,R0
        STRD     R0,R1,[SP, #+8]
Go to the top of the page
 
+Quote Post
Sergey_Aleksandr...
сообщение Aug 28 2017, 14:43
Сообщение #3


Частый гость
**

Группа: Свой
Сообщений: 168
Регистрация: 8-10-08
Из: РФ Смоленск
Пользователь №: 40 764



VladislavS, спасибо за идею. Это не совсем то, что нужно, но получилось слегка ускорить алгоритм.
Создал обычный макрос
Код
#define MULSHIFT32(arg1, arg2)    ((((long long)arg1)*((long long)arg2))>>32)

Всё-равно получается избыточно, если верить листингу.

Было до
Код
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x59ac0: 0xf8d4 0xa010  LDR.W     R10, [R4, #0x10]
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x59ac4: 0x1846         ADDS      R6, R0, R1
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x59ac6: 0x1a09         SUBS      R1, R1, R0
      0x59ac8: 0xf855 0x0b04  LDR.W     R0, [R5], #0x4
      0x59acc: 0xf7fd 0xf9ea  BL        MULSHIFT32             ; 0x56ea4
        MULSHIFT32:
              0x56ea4: 0xfb81 0x2000  SMULL     R2, R0, R1, R0
              0x56ea8: 0x4770         BX        LR
      0x59ad0: 0x4680         MOV       R8, R0
      0x59ad2: 0xea4f 0x0848  LSL.W     R8, R8, #1


Стало после
Код
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x58dee: 0xf851 0x6b04  LDR.W     R6, [R1], #0x4
      0x58df2: 0x17f7         ASRS      R7, R6, #31
      0x58df4: 0x17e5         ASRS      R5, R4, #31
      0x58df6: 0x17d3         ASRS      R3, R2, #31
      0x58df8: 0x1aa2         SUBS      R2, R4, R2
      0x58dfa: 0xeb65 0x0303  SBC.W     R3, R5, R3
      0x58dfe: 0x4634         MOV       R4, R6
      0x58e00: 0x463d         MOV       R5, R7
      0x58e02: 0xfba2 0x6704  UMULL     R6, R7, R2, R4
      0x58e06: 0xfb02 0x7705  MLA       R7, R2, R5, R7
      0x58e0a: 0xfb03 0x7704  MLA       R7, R3, R4, R7
      0x58e0e: 0x46b8         MOV       R8, R7
      0x58e10: 0xea4f 0x0848  LSL.W     R8, R8, #1


В моём случае объявить, как в Вашем примере 64-битную переменную и положить в неё результат 32х32 не получится.
Go to the top of the page
 
+Quote Post
scifi
сообщение Aug 28 2017, 15:18
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Из любопытства попробовал на GCC вот такое:
Код
#define MULSHIFT32(arg1, arg2)    ((((long long)arg1)*((long long)arg2))>>32)
int volatile a0, a7, b7, ar[2];
void f(void)
{
    int* cptr = ar;
    b7 = MULSHIFT32(*cptr++, a0) << 1;
}

Получилось вот что:
Код
0x0800146E 4D72      LDR      r5,[pc,#456]; @0x08001638
0x08001470 686B      LDR      r3,[r5,#0x04]
0x08001472 68E8      LDR      r0,[r5,#0x0C]
0x08001474 FB830100  SMULL    r0,r1,r3,r0
0x08001478 184A      ADDS     r2,r1,r1
0x0800147A 612A      STR      r2,[r5,#0x10]

А если написать вот так
Код
    b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;

То получается АдЪ:
Код
0x0800146E 4D77      LDR      r5,[pc,#476]; @0x0800164C
0x08001470 6868      LDR      r0,[r5,#0x04]
0x08001472 68AE      LDR      r6,[r5,#0x08]
0x08001474 68EC      LDR      r4,[r5,#0x0C]
0x08001476 17C1      ASRS     r1,r0,#31
0x08001478 1B80      SUBS     r0,r0,r6
0x0800147A EB6171E6  SBC      r1,r1,r6,ASR #31
0x0800147E FB04F201  MUL      r2,r4,r1
0x08001482 17E3      ASRS     r3,r4,#31
0x08001484 FB002303  MLA      r3,r0,r3,r2
0x08001488 FBA40100  UMULL    r0,r1,r4,r0
0x0800148C 185C      ADDS     r4,r3,r1
0x0800148E 1922      ADDS     r2,r4,r4
0x08001490 616A      STR      r2,[r5,#0x14]
Go to the top of the page
 
+Quote Post
jcxz
сообщение Aug 28 2017, 15:49
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Sergey_Aleksandrovi4 @ Aug 28 2017, 17:43) *
Код
#define MULSHIFT32(arg1, arg2)    ((((long long)arg1)*((long long)arg2))>>32)

Если Вам нужны только старшие 32 бита (как следует из этого макроса), то всё просто:
#define MULSHIFT32(x, y) __SMMUL(x, y)
Go to the top of the page
 
+Quote Post
VladislavS
сообщение Aug 28 2017, 16:00
Сообщение #6


Местный
***

Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140



Во-первых, очень некрасиво не показывать типы используемых переменных и желаемого результата.
Во-вторых, разберитесь с размерностью вычислений. Написанный вами макрос делает совсем не то что вы хотите.
В-третьих, ваш mulshift32, судя по всему, это банальное
Код
int32_t x=1L,y=2L;
int32_t z;
z = ((int64_t)x*y)>>32;

Поверьте, компилятор сделает всё лучше вас, особенно с оптимизацией. Только не мешайте ему.
Код
//  int32_t x=1L,y=2L;
        MOVS     R0,#+1
        MOVS     R1,#+2
//  int32_t z;
//  z = ((int64_t)x*y)>>32;
        SMULL    R0,R1,R1,R0

В-четвёртых, вместо x и y можете ставить что угодно, только с соблюдением типов.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Aug 28 2017, 16:04
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(VladislavS @ Aug 28 2017, 19:00) *
Поверьте, компилятор сделает всё лучше вас, особенно с оптимизацией. Только не мешайте ему.

Вангую, что автор не сам ваяет, а пытается запустить/портировать готовое, где уже есть много MULSHIFT32()...
Go to the top of the page
 
+Quote Post
VladislavS
сообщение Aug 28 2017, 16:14
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140



Дарю

Код
#define MULSHIFT32(arg1, arg2)    (((int64_t)(int32_t)(arg1)*(int32_t)(arg2))>>32)
Go to the top of the page
 
+Quote Post
scifi
сообщение Aug 29 2017, 09:41
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Кстати, если в моём эксперименте с GCC сделать так
Код
#define MULSHIFT32(a, b)  (((long long)(a) * (b)) >> 32)

то код генерится вменяемый.
Очевидно, в первоначальном варианте макроса не хватает скобок вокруг аргументов. На первый взгляд, в данном случае неважно, но, возможно, я что-то не заметил.
Go to the top of the page
 
+Quote Post
Sergey_Aleksandr...
сообщение Aug 29 2017, 09:53
Сообщение #10


Частый гость
**

Группа: Свой
Сообщений: 168
Регистрация: 8-10-08
Из: РФ Смоленск
Пользователь №: 40 764



jcxz, всё верно, чужие библиотеки. Портирую mp3-декодер Helix. В очередной раз)

Цитата(jcxz @ Aug 28 2017, 18:49) *
Если Вам нужны только старшие 32 бита (как следует из этого макроса), то всё просто:
#define MULSHIFT32(x, y) __SMMUL(x, y)

Спасибо. Даже забыл, что в IAR есть intrinsic-ассемблер, как всё просто оказывается.
Цитата(VladislavS @ Aug 28 2017, 19:14) *
Дарю
Код
#define MULSHIFT32(arg1, arg2)    (((int64_t)(int32_t)(arg1)*(int32_t)(arg2))>>32)

Спасибо за подарок.
Прогнал оба варианта на разных уровнях оптимизации. По оси ординат разница выполнения алгоритма в мс. Time( __SMMUL(x, y)) - Time((((int64_t)(int32_t)(arg1)*(int32_t)(arg2))>>32)). Без оптимизации паритет, на умеренной оптимизации использование интринсик-функции __SMMUL(x, y) оказывается более быстрым, в случае максимальной оптимизации по скорости выигрывает решение от VladislavS. Разница не существенная, в районе 1%.
Прикрепленное изображение


Дизассемблер для каждой из реализаций. Алгоритм раскладывается в одни и те же инструкции, но с использованием разных РОН.
Код
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x59830: 0x1979         ADDS      R1, R7, R5
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x59832: 0x1bed         SUBS      R5, R5, R7
      0x59834: 0xf852 0x7b04  LDR.W     R7, [R2], #0x4
      0x59838: 0xfb57 0xfc05  SMMUL     R12, R7, R5
      0x5983c: 0xea4f 0x0c4c  LSL.W     R12, R12, #1

Код
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x59906: 0x1978         ADDS      R0, R7, R5
        b0 = a0 + a7;       b7 = MULSHIFT32(*cptr++, a0 - a7) << 1;
      0x59908: 0xf853 0xcb04  LDR.W     R12, [R3], #0x4
      0x5990c: 0x1bed         SUBS      R5, R5, R7
      0x5990e: 0xfb5c 0xfc05  SMMUL     R12, R12, R5
      0x59912: 0xea4f 0x0c4c  LSL.W     R12, R12, #1

И хотя первоначальный вопрос про синтаксис макросов остался открытым, но задача решена другими средствами. Спасибо за помощь!
Go to the top of the page
 
+Quote Post
scifi
сообщение Aug 29 2017, 10:29
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(Sergey_Aleksandrovi4 @ Aug 29 2017, 12:53) *
И хотя первоначальный вопрос про синтаксис макросов остался открытым, но задача решена другими средствами. Спасибо за помощь!

Имеется в виду вот этот вопрос?
Цитата(Sergey_Aleksandrovi4 @ Aug 28 2017, 16:42) *
Кто подскажет, как этот макрос правильно оформить, чтобы можно было использовать его вне *.s-файла?

Тогда ответ такой: никак. Это макросы ассемблера, фактически текстовая подстановка в пределах ассемблерного файла. Ни разу не видел, чтобы такие вещи действовали в сишных файлах. И уж точно на уровне линкера ничего этого быть не может.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Aug 29 2017, 10:58
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Sergey_Aleksandrovi4 @ Aug 29 2017, 12:53) *
jcxz, всё верно, чужие библиотеки. Портирую mp3-декодер Helix. В очередной раз)

Ну вот я так и думал, что Helix wink.gif
И макрос этот я запостил как раз из своего работающего проекта на Helix rolleyes.gif
Что ваяете, если не секрет?
Go to the top of the page
 
+Quote Post
Sergey_Aleksandr...
сообщение Aug 29 2017, 13:04
Сообщение #13


Частый гость
**

Группа: Свой
Сообщений: 168
Регистрация: 8-10-08
Из: РФ Смоленск
Пользователь №: 40 764



Цитата(scifi @ Aug 29 2017, 13:29) *
Это макросы ассемблера, фактически текстовая подстановка в пределах ассемблерного файла.

Вот оно что. Спасибо. С ARM-ассемблером пару раз в жизни сталкивался, не знал про эти тонкости.
jcxz, в двух словах - интерактивная игрушка для детей, ничего серьёзного. Кодек этот давно ещё портировал на cortex M3 (не без помощи здешних форумчан). Теперь перевожу на cortex M4, ну и решил по-максимуму из него выжать и закрыть тему навсегда.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Aug 30 2017, 08:26
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(VladislavS @ Aug 28 2017, 19:14) *
Дарю
Код
#define MULSHIFT32(arg1, arg2)    (((int64_t)(int32_t)(arg1)*(int32_t)(arg2))>>32)

__SMMUL() может быть чуть-чуть лучше если нужно ещё и округление результата: __SMMULR().
Правда без возможности предварительного сдвига результата влево на 1 бит, это округление редко бывает полезным. sad.gif
Не знаю почему в системе команд не предусмотрена опция сдвига влево результата на 1 бит.
Go to the top of the page
 
+Quote Post
VladislavS
сообщение Aug 30 2017, 11:34
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 475
Регистрация: 14-04-05
Из: Москва
Пользователь №: 4 140



Если есть возможность не уходить от чистого С/C++, то лучше от него не уходить. Чтобы не возникало потом таких тем как эта. Вот что заставило автора того кода ассемблерную функцию применить? Компилятор не знал команду smmul или программист не смог ему объяснить что он хочет? Я ставлю на второе.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 5th July 2025 - 06:39
Рейтинг@Mail.ru


Страница сгенерированна за 0.01541 секунд с 7
ELECTRONIX ©2004-2016