Перейти к содержанию
    

Помогите кто чем может, уже вторую неделю головой об стену, и каждый раз ничего хорошего не получается. От этой функции зависит общая скорость.

Для того чтобы меньше путаться, я дал имена переменным согласно позиции в числе uint128.

uint64_t mult64toH128(uint64_t val1, uint64_t val2, int32_t* nr)
{
    uint64_t c1c0 = (uint64_t) (val1 & 0xffffffff) * (val2 & 0xffffffff);
    uint64_t a2a1 = (uint64_t) (val1 & 0xffffffff) * (val2 >> 32) + (c1c0 >> 32);
    uint64_t b2b1 = (uint64_t) (val1 >> 32) * (val2 & 0xffffffff) + (a2a1 & 0xffffffff);
    uint64_t c3c2 = (uint64_t) (val1 >> 32) * (val2 >> 32) + (a2a1 >> 32);
    c3c2 = (uint64_t) c3c2 + (b2b1 >> 32);
    if((c3c2 >> 63) == 0){
        c3c2 <<= 1;
        c3c2 |= (b2b1 >> 31) & 1;

    }else *nr += 1;
    return c3c2;
}

Эта функция выдаёт примерно такой код (на ARM): mult64toH128:  Топорное использование umull - умножение без накопления u64=u32*u32, и только потом добавляет u32. ARM и другие архитектуры имеют команды u64 +=u32*u32 (UMLAL для ARM). В этом случае например "(c1c0 >> 32)" нужно поместить в "a2a1", или в наглую использовать "(c1c0 >> 32)" по месту создания и очистить свободный регистр. Я считаю что команда записи нуля и умножение с накоплением дают в сумме меньший код. На чистой асме у меня получилось написать компактно (18 команд), тесты на скорость показали ускорение. Но заставить GCC использовать "UMLAL" у меня не получается.

Встроенные функции дают невообразимо длинную лапшу, использовать нельзя.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 minutes ago, AVI-crak said:

 uint64_t c1c0 = (uint64_t) (val1 & 0xffffffff) * (val2 & 0xffffffff);

а как компилятор должен догадаться что это умножение 32-битных операндов?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Очень просто, для него все операции имеют входные и выходные операнды размером с регистр. Нужно дополнительно указывать варианты событий с иным результатом. В моём случае это дополнительное (uint64_t), без него будет выполнено обычное умножение u32=u32*u32.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

https://godbolt.org/z/nrc54G83o

так лучше? строк в асм меньше но я не понимаю в командах

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот о чём я говорил чуть выше "((uint32_t) (val2 >> 32))" - val2 в этом преобразовании уже имеет размер uint32_t, соответственно результат ноль, и сокращение одной операции умножения. Операций умножения должно быть 4, иначе фигня получится. Тут очень просто, все биты первого числа перемножаются на все биты второго, со смещением и последующим сложением. Столбиком (ненавижу это слово). 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, AVI-crak сказал:

Помогите кто чем может, уже вторую неделю головой об стену, и каждый раз ничего хорошего не получается. От этой функции зависит общая скорость.

Вы бы хоть написали - какой результат ожидаете от функции? И что именно не устраивает в результате GCC?

А то все телепаты на пляже...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А так вообще пропало умножение u64=u32*u32. 

Моя функция "uint64_t mult64toH128(uint64_t val1, uint64_t val2, int32_t* nr)" используется для замены встроенной функции умножения чисел long double. Там по дефолту такая дикая ересь добавляется на 6 килобайт, и всё это тормозит как стадо егэшников на экзамене.

Логика умножения long double простая как тапок: u64=(u128)u64*u64>>64;. Если число получается больше или равным (1<<63) - тогда к сумме степеней (двоичное со знаком) первого и второго числа добавляется единица. В оригинале там степень использует число без знака с диким легаси в обработке, мне такого не надо.

On 8/6/2023 at 5:57 PM, jcxz said:

И что именно не устраивает в результате GCC?

Полное описание в первом сообщении, с картинками.😁

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

46 минут назад, AVI-crak сказал:

Полное описание в первом сообщении, с картинками.😁

Где именно? Процитируйте конкретное место. Для нетелепатов.

Что вас не устраивает - не понятно. Скармливаю ваш код GCC, компилю, получаю:

 8                  .eabi_attribute 26, 1                        
 9                  .eabi_attribute 30, 4                        
10                  .eabi_attribute 34, 1                        
11                  .eabi_attribute 18, 4                        
12                  .file "main.cpp"                             
13                  .text                                        
14                  .align  1                                    
15                  .global _Z12mult64toH128yyPl                 
16                  .arch armv7e-m                               
17                  .syntax unified                              
18                  .thumb                                       
19                  .thumb_func                                  
20                  .fpu fpv5-d16                                
22                _Z12mult64toH128yyPl:                          
23                  .fnstart                                     
24                .LFB0:                                         
25                  @ args = 4, pretend = 0, frame = 0           
26                  @ frame_needed = 0, uses_anonymous_args = 0  
27 0000 2DE9F04F    push  {r4, r5, r6, r7, r8, r9, r10, fp, lr}  
28 0004 4FF0000C    mov ip, #0                                   
29 0008 A0FB02AB    umull r10, fp, r0, r2                        
30 000c 8E46        mov lr, r1                                   
31 000e 9846        mov r8, r3                                   
32 0010 5E46        mov r6, fp                                   
33 0012 6746        mov r7, ip                                   
34 0014 6146        mov r1, ip                                   
35 0016 DDF82490    ldr r9, [sp, #36]                            
36 001a E0FB0367    umlal r6, r7, r0, r3                         
37 001e 3046        mov r0, r6                                   
38 0020 6346        mov r3, ip                                   
39 0022 E2FB0E01    umlal r0, r1, r2, lr                         
40 0026 3A46        mov r2, r7                                   
41 0028 EEFB0823    umlal r2, r3, lr, r8                         
42 002c 8C18        adds  r4, r1, r2                             
43 002e 4CEB0305    adc r5, ip, r3                               
44 0032 002C        cmp r4, #0                                   
45 0034 75F10003    sbcs  r3, r5, #0                             
46 0038 09DB        blt .L2                                      
47 003a 2219        adds  r2, r4, r4                             
48 003c 45EB0503    adc r3, r5, r5                               
49 0040 42EAD074    orr r4, r2, r0, lsr #31                      
50 0044 1D46        mov r5, r3                                   
51                .L1:                                           
52 0046 2046        mov r0, r4                                   
53 0048 2946        mov r1, r5                                   
54 004a BDE8F08F    pop {r4, r5, r6, r7, r8, r9, r10, fp, pc}    
55                .L2:                                           
56 004e D9F80030    ldr r3, [r9]                                 
57 0052 0133        adds  r3, r3, #1                             
58 0054 C9F80030    str r3, [r9]                                 
59 0058 F5E7        b .L1                                        
2 часа назад, AVI-crak сказал:

Но заставить GCC использовать "UMLAL" у меня не получается.

Зачем его заставлять??? Он по дефолту их использует - см. листинг выше. ЧЯДНТ?? :unknw:

46 минут назад, AVI-crak сказал:

Логика умножения long double

Причём тут long double - вообще не понял. :wacko2:  Каша у вас какая-то....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

On 8/6/2023 at 6:45 PM, jcxz said:

Скармливаю ваш код GCC

Как у вас это получилось? Потому как мой вариант компилируется так-же как в онлан сервисе.

20000E6E	push	{r4, r5, r6, lr}
20000E70	umull	r6, r5, r0, r2
20000E74	ldr	r4, [sp, #16]
20000E76	umull	r0, r6, r0, r3
20000E7A	adds	r5, r5, r0
20000E7C	umull	r2, r0, r2, r1
20000E80	umull	r3, r1, r3, r1
20000E84	adc.w	r6, r6, #0
20000E88	adds	r2, r2, r5
20000E8A	adc.w	r0, r0, #0
20000E8E	adds	r3, r3, r6
20000E90	adc.w	r1, r1, #0
20000E94	adds	r0, r0, r3
20000E96	adc.w	r1, r1, #0
20000E9A	cmp	r1, #0
20000E9C	blt.n	0x20000ea8 <mult64toH128+58>
20000E9E	adds	r0, r0, r0
20000EA0	adcs	r1, r1
20000EA2	orr.w	r0, r0, r2, lsr #31
20000EA6	pop	{r4, r5, r6, pc}
20000EA8	ldr	r3, [r4, #0]
20000EAA	adds	r3, #1
20000EAC	str	r3, [r4, #0]
20000EAE	b.n	0x20000ea6 <mult64toH128+56>

 

On 8/6/2023 at 6:45 PM, jcxz said:

Причём тут long double - вообще не понял.

Эта функция используется вместо встроенной лапши на 6 килобайт.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 минут назад, AVI-crak сказал:

Как у вас это получилось?

Скопировал ваш код, чуть-чуть подправил типы (так как не использую у себя всякие uintXX_t):

u64 mult64toH128(u64 val1, u64 val2, s32 *nr)
{
  u64 c1c0 = (u64)(u32)val1 * (u32)val2;
  u64 a2a1 = (u64)(u32)val1 * (u32)(val2 >> 32) + (u32)(c1c0 >> 32);
  u64 b2b1 = (u64)(u32)(val1 >> 32) * (u32)val2 + (u32)a2a1;
  u64 c3c2 = (u64)(u32)(val1 >> 32) * (u32)(val2 >> 32) + (u32)(a2a1 >> 32);
  c3c2 = (u64)c3c2 + (b2b1 >> 32);
  if ((c3c2 >> 63) == 0) {
    c3c2 <<= 1;
    c3c2 |= (b2b1 >> 31) & 1;
  } else *nr += 1;
  return c3c2;
}

скопировал ваши ключи компиляции. И нажал "compile".

Всё.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

7 минут назад, AVI-crak сказал:

Это кейл?

при чём тут кейл?

gcc-arm-none-eabi-9.2.1-2019.10-win32

Цитата

arm-none-eabi-c++.exe (GNU Tools for Arm Embedded Processors 9-2019-q4-major) 9.2.1 20191025 (release) [ARM/arm-9-branch revision 277599]

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ок, переключился на ARM GCC 9.2.1, вижу umlal, но не понимаю отчего так код разбух. У меня на асме получалось всего 18 команд, и я хотел-бы увидеть то-же от GCC. 

Использовать вставки на ассемблере в подобных вещах считаю недопустимым, а иным способом ситуацию исправить невозможно.

Тогда просто буду ждать у моря погоды, когда оно само исправится. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ладно, допустим, добрались до оптимизации по тактам. Так почему бы и не оставить асм-функцию?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...