AVI-crak 0 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба Помогите кто чем может, уже вторую неделю головой об стену, и каждый раз ничего хорошего не получается. От этой функции зависит общая скорость. Для того чтобы меньше путаться, я дал имена переменным согласно позиции в числе 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" у меня не получается. Встроенные функции дают невообразимо длинную лапшу, использовать нельзя. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1113 5 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 47 minutes ago, AVI-crak said: uint64_t c1c0 = (uint64_t) (val1 & 0xffffffff) * (val2 & 0xffffffff); а как компилятор должен догадаться что это умножение 32-битных операндов? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба Очень просто, для него все операции имеют входные и выходные операнды размером с регистр. Нужно дополнительно указывать варианты событий с иным результатом. В моём случае это дополнительное (uint64_t), без него будет выполнено обычное умножение u32=u32*u32. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1113 5 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба https://godbolt.org/z/nrc54G83o так лучше? строк в асм меньше но я не понимаю в командах Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба Вот о чём я говорил чуть выше "((uint32_t) (val2 >> 32))" - val2 в этом преобразовании уже имеет размер uint32_t, соответственно результат ноль, и сокращение одной операции умножения. Операций умножения должно быть 4, иначе фигня получится. Тут очень просто, все биты первого числа перемножаются на все биты второго, со смещением и последующим сложением. Столбиком (ненавижу это слово). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
1113 5 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба а так? https://godbolt.org/z/99ehMrEG6 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 1 час назад, AVI-crak сказал: Помогите кто чем может, уже вторую неделю головой об стену, и каждый раз ничего хорошего не получается. От этой функции зависит общая скорость. Вы бы хоть написали - какой результат ожидаете от функции? И что именно не устраивает в результате GCC? А то все телепаты на пляже... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба А так вообще пропало умножение 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? Полное описание в первом сообщении, с картинками.😁 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 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" у меня не получается. Зачем его заставлять??? Он по дефолту их использует - см. листинг выше. ЧЯДНТ?? 46 минут назад, AVI-crak сказал: Логика умножения long double Причём тут long double - вообще не понял. Каша у вас какая-то.... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 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 килобайт. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 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". Всё. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба On 8/6/2023 at 7:03 PM, jcxz said: Скопировал ваш код Это кейл? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 184 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба 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] Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AVI-crak 0 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба Ок, переключился на ARM GCC 9.2.1, вижу umlal, но не понимаю отчего так код разбух. У меня на асме получалось всего 18 команд, и я хотел-бы увидеть то-же от GCC. Использовать вставки на ассемблере в подобных вещах считаю недопустимым, а иным способом ситуацию исправить невозможно. Тогда просто буду ждать у моря погоды, когда оно само исправится. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 131 6 августа, 2023 Опубликовано 6 августа, 2023 · Жалоба Ладно, допустим, добрались до оптимизации по тактам. Так почему бы и не оставить асм-функцию? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться