Если TL; DR, то переходите к концу для линии удара.
Пробовал это на синей таблетке STM32, STM32F103C8T6
Определенно ожидайте, что результаты изменятся с разными чипами, даже если они имеют одинаковую частоту вращения cortex-m3, поскольку процессор - это одно, а то, что питает его, и то, как другое, и это зависит от поставщика. Также иногда производитель чипов может компилировать ядро по-разному, иногда он может иметь многоцикловые умножения, чтобы сэкономить на стоимости чипа, некоторые ядра, которые он может выбрать между выборкой 16 битов за раз или 32. Тесты часто легко проверять, поэтому берите их недоверчиво.
Я видел, что выполнение в sram было быстрее, чем во flash. ST, хотя, иногда нет, я не думаю, что на этих древних cortex-m3s у них есть свой (инструктивный) кеш с каким-то причудливым названием. Более новые делают, и вы не можете выключить его.
Другие производители микросхем не имеют этого и будут использовать ядра, которые поддерживают его, реализующие кэши вооружений, а не свои собственные (или не имеющие ни одного). Возможно, почему первые два эксперимента, приведенные ниже, выполняются в разное время (двузначное число впереди - шестнадцатеричное, счетчик таймера синцикла, cvr-адрес синусика передается в r0. Вы можете видеть, что я использовал nop, чтобы изменить выравнивание цикла. Документация arm не указала в обычном месте, что cortex-m3 извлекает полуслова или слова, но документация ST при разговоре о чем-то еще указывает выборки слов. Ваш цикл из четырех инструкций состоит из 2 слов, но выровненный не по границе слова означает, что он должен извлекать три слова в цикле. Если эти четыре слова выровнены, то нужно извлечь два слова в цикле, что позволит Питеру или кому-то еще посчитать инструкции для этого / вашего кода. Я уверен, что это фактор, но, возможно, есть и другие, вероятно нет.
Для этого чипа, работающего на флэш-памяти, гораздо быстрее. Вы можете увидеть эффект отключения предварительной выборки ST и добавления состояний ожидания.
000 Zero wait state, if 0 < SYSCLK≤ 24 MHz
001 One wait state, if 24 MHz < SYSCLK ≤ 48 MHz
010 Two wait states, if 48 MHz < SYSCLK ≤ 72 MHz
Так что, пока я работаю на внутренних часах с частотой 8 МГц, здесь есть два измерения, одно из которых - это количество часов, которое требуется, чтобы что-то сделать, если мы увеличим sysclk до 24 МГц, количество часов не должно измениться. Продолжительность настенных часов каждого цикла sysclk составляет треть времени, поэтому время настенных часов меньше. Производительность в реальном времени лучше. Следуя этим правилам, перейдите на один шаг выше 24 МГц, и теперь вы добавляете состояние ожидания, и ваш код снова замедляется. Поскольку количество системных часов для запуска кода теперь замедлилось. Теперь, если вы удвоите это до 48 МГц, это преодолело состояние ожидания? Вероятно, но для каждой программы / цикла существует точка между 24 МГц + полоса пропускания и 48 МГц, которые улавливаются прямо при производительности 24 МГц. И 48 МГц плюс чуть-чуть, теперь вы снова замедляетесь и где-то между 48 МГц плюс чуть-чуть 72 МГц, мы надеемся догнать и пропустить производительность 48 МГц.
Точно так же, как флэш-память не может работать, у других периферийных устройств есть правила, особенно с этими старыми чипами, такими как многие из основанных на Cortex-M3, есть другие проблемы производительности, с которыми вы падаете, некоторые периферийные устройства не могут работать так же быстро, как и любой другой sysclk. это значит, что у вас может быть какая-то другая скорость X, где вы находитесь на максимальной скорости для одной / некоторых ваших периферийных устройств или периферийных шин, и X + означает, что вам придется сократить время вдвое, так как это ваш самый маленький делитель теперь ваших периферийных устройств и / или их шины теперь в два раза медленнее, поэтому производительность вашего кода падает со скалы, возможно, хуже, чем половина. Этот ваш код не касается периферийных устройств. Он использует умножение, которое рискованно для производительности, но для cortex-m3 я не видел, чтобы была опция времени компиляции для одного цикла против другого, он просто сказал один цикл.
Питер рассмотрел очевидную оптимизацию, когда вы рассчитываете до некоторого числа, если позволяет набор инструкций, и ваш код, что он делает в этом случае, потому что a * b * c = c * b * a, так что вы хотитевести обратный отсчет и использовать флаги для сравнения с нулем или плюс минус, если это плавает на вашей лодке, а не с приращением, а затем необходимо выполнить сравнение перед условным.Когда вы пропустите до конца, вы увидите, что это было быстрее (меньше часов).
У M3 нет кэшей, у m4s и m7s.Таким образом, выполнение этого кода с его небольшим циклом потребует многократного выполнения цикла и цикла, чтобы увидеть влияние кэширования и выравнивания строк кэша и тому подобное.Но для m3 хорошо пройти один раз (если у чипа нет скрытого кэша, которым вы не можете управлять).
Меня действительно интересует только цикл, так как он имеет наибольший потенциал для циклических краж.Проверка / ограничение ввода, проверка ярлыков, поиск переполнения при умножении и т. Д., А это не то, о чем беспокоится этот ответ.
Я рекомендую вам поискать книги Майкла Абраша в Google.Например, Zen of Assembly, которую вы можете создать на github.Я прочитал его, когда он вышел, и я в значительной степени использовал то, чему научился там с тех пор, отлаживая чипы, инструменты, ломая вещи, улучшая производительность и т. Д. 8088/86 устарел, когда вышел, и если вы думаете, что это книга x86Вы полностью упускаете суть.Например, мое предположение о sram будет быстрее, не произошло здесь.Я также пробовал такие вещи, как добавление nops (дополнительных инструкций) внутри цикла, верите или нет, бывают моменты, когда это может повысить производительность цикла.Эти короткие конвейеры, небольшие процессоры предварительной выборки, хотя, как правило, это не так.
Иногда вы можете получить бесплатные инструкции в цикле, количество часов одинаково даже с большим количеством инструкций.Например, если это умножилось на несколько часов, в зависимости от количества часов и от того, к каким регистрам / ресурсам вы прикоснулись, вы можете получить несколько бесплатных инструкций в этом цикле.Похоже, что это умножение на один цикл, поэтому не могу надеяться на это здесь.
Затем есть материал, который вы читаете в учебниках Паттерсона и Хеннесси.Какие регистры вы выберете, могут повлиять на производительность.Порядок инструкций, если вы можете функционально перестроить инструкции и т. Д.
Заметки, сделанные в ходе простых экспериментов
15
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 2100 movs r1, #0
2000001c: 2203 movs r2, #3
2000001e: 2301 movs r3, #1
20000020: 6804 ldr r4, [r0, #0]
20000022 <fact_loop>:
20000022: 3101 adds r1, #1
20000024: 434b muls r3, r1
20000026: 4291 cmp r1, r2
20000028: d4fb bmi.n 20000022 <fact_loop>
2000002a: 6805 ldr r5, [r0, #0]
2000002c: 1b60 subs r0, r4, r5
2000002e: bc30 pop {r4, r5}
20000030: 4770 bx lr
12
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 2100 movs r1, #0
2000001c: 2203 movs r2, #3
2000001e: 2301 movs r3, #1
20000020: 46c0 nop ; (mov r8, r8)
20000022: 6804 ldr r4, [r0, #0]
20000024 <fact_loop>:
20000024: 3101 adds r1, #1
20000026: 434b muls r3, r1
20000028: 4291 cmp r1, r2
2000002a: d4fb bmi.n 20000024 <fact_loop>
2000002c: 6805 ldr r5, [r0, #0]
2000002e: 1b60 subs r0, r4, r5
20000030: bc30 pop {r4, r5}
20000032: 4770 bx lr
15
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 2100 movs r1, #0
2000001c: 2203 movs r2, #3
2000001e: 2301 movs r3, #1
20000020: 46c0 nop ; (mov r8, r8)
20000022: 46c0 nop ; (mov r8, r8)
20000024: 6804 ldr r4, [r0, #0]
20000026 <fact_loop>:
20000026: 3101 adds r1, #1
20000028: 434b muls r3, r1
2000002a: 4291 cmp r1, r2
2000002c: d4fb bmi.n 20000026 <fact_loop>
2000002e: 6805 ldr r5, [r0, #0]
20000030: 1b60 subs r0, r4, r5
20000032: bc30 pop {r4, r5}
20000034: 4770 bx lr
20000036: 46c0 nop ; (mov r8, r8)
12
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 2100 movs r1, #0
2000001c: 2203 movs r2, #3
2000001e: 2301 movs r3, #1
20000020: 46c0 nop ; (mov r8, r8)
20000022: 46c0 nop ; (mov r8, r8)
20000024: 46c0 nop ; (mov r8, r8)
20000026: 6804 ldr r4, [r0, #0]
20000028 <fact_loop>:
20000028: 3101 adds r1, #1
2000002a: 434b muls r3, r1
2000002c: 4291 cmp r1, r2
2000002e: d4fb bmi.n 20000028 <fact_loop>
20000030: 6805 ldr r5, [r0, #0]
20000032: 1b60 subs r0, r4, r5
20000034: bc30 pop {r4, r5}
20000036: 4770 bx lr
55
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 2100 movs r1, #0
2000001c: 220b movs r2, #11
2000001e: 2301 movs r3, #1
20000020: 6804 ldr r4, [r0, #0]
20000022 <fact_loop>:
20000022: 3101 adds r1, #1
20000024: 434b muls r3, r1
20000026: 4291 cmp r1, r2
20000028: d4fb bmi.n 20000022 <fact_loop>
2000002a: 6805 ldr r5, [r0, #0]
2000002c: 1b60 subs r0, r4, r5
2000002e: bc30 pop {r4, r5}
20000030: 4770 bx lr
20000032: bf00 nop
42
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 2100 movs r1, #0
2000001c: 220b movs r2, #11
2000001e: 2301 movs r3, #1
20000020: 46c0 nop ; (mov r8, r8)
20000022: 6804 ldr r4, [r0, #0]
20000024 <fact_loop>:
20000024: 3101 adds r1, #1
20000026: 434b muls r3, r1
20000028: 4291 cmp r1, r2
2000002a: d4fb bmi.n 20000024 <fact_loop>
2000002c: 6805 ldr r5, [r0, #0]
2000002e: 1b60 subs r0, r4, r5
20000030: bc30 pop {r4, r5}
20000032: 4770 bx lr
41
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 210b movs r1, #11
2000001c: 2301 movs r3, #1
2000001e: 6804 ldr r4, [r0, #0]
20000020 <fact_loop>:
20000020: 434b muls r3, r1
20000022: 3901 subs r1, #1
20000024: d1fc bne.n 20000020 <fact_loop>
20000026: 6805 ldr r5, [r0, #0]
20000028: 1b60 subs r0, r4, r5
2000002a: bc30 pop {r4, r5}
2000002c: 4770 bx lr
2000002e: bf00 nop
42
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 210b movs r1, #11
2000001c: 2301 movs r3, #1
2000001e: 46c0 nop ; (mov r8, r8)
20000020: 6804 ldr r4, [r0, #0]
20000022 <fact_loop>:
20000022: 434b muls r3, r1
20000024: 3901 subs r1, #1
20000026: d1fc bne.n 20000022 <fact_loop>
20000028: 6805 ldr r5, [r0, #0]
2000002a: 1b60 subs r0, r4, r5
2000002c: bc30 pop {r4, r5}
2000002e: 4770 bx lr
41
20000018 <fact>:
20000018: b430 push {r4, r5}
2000001a: 210b movs r1, #11
2000001c: 2301 movs r3, #1
2000001e: 46c0 nop ; (mov r8, r8)
20000020: 46c0 nop ; (mov r8, r8)
20000022: 6804 ldr r4, [r0, #0]
20000024 <fact_loop>:
20000024: 434b muls r3, r1
20000026: 3901 subs r1, #1
20000028: d1fc bne.n 20000024 <fact_loop>
2000002a: 6805 ldr r5, [r0, #0]
2000002c: 1b60 subs r0, r4, r5
2000002e: bc30 pop {r4, r5}
20000030: 4770 bx lr
20000032: bf00 nop
FLASH ACR 0x30
2d
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 434b muls r3, r1
800002a: 3901 subs r1, #1
800002c: d1fc bne.n 8000028 <fact_loop>
800002e: 6805 ldr r5, [r0, #0]
8000030: 1b60 subs r0, r4, r5
8000032: bc30 pop {r4, r5}
8000034: 4770 bx lr
2d
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 46c0 nop ; (mov r8, r8)
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 434b muls r3, r1
800002c: 3901 subs r1, #1
800002e: d1fc bne.n 800002a <fact_loop>
8000030: 6805 ldr r5, [r0, #0]
8000032: 1b60 subs r0, r4, r5
8000034: bc30 pop {r4, r5}
8000036: 4770 bx lr
FLASH_ACR 0x00
2d
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 46c0 nop ; (mov r8, r8)
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 434b muls r3, r1
800002c: 3901 subs r1, #1
800002e: d1fc bne.n 800002a <fact_loop>
8000030: 6805 ldr r5, [r0, #0]
8000032: 1b60 subs r0, r4, r5
8000034: bc30 pop {r4, r5}
8000036: 4770 bx lr
FLASH_ACR 0x02
5e
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 434b muls r3, r1
800002a: 3901 subs r1, #1
800002c: d1fc bne.n 8000028 <fact_loop>
800002e: 6805 ldr r5, [r0, #0]
8000030: 1b60 subs r0, r4, r5
8000032: bc30 pop {r4, r5}
8000034: 4770 bx lr
5f
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 46c0 nop ; (mov r8, r8)
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 434b muls r3, r1
800002c: 3901 subs r1, #1
800002e: d1fc bne.n 800002a <fact_loop>
8000030: 6805 ldr r5, [r0, #0]
8000032: 1b60 subs r0, r4, r5
8000034: bc30 pop {r4, r5}
8000036: 4770 bx lr
FLASH_ACR 0x32
41
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 434b muls r3, r1
800002a: 3901 subs r1, #1
800002c: d1fc bne.n 8000028 <fact_loop>
800002e: 6805 ldr r5, [r0, #0]
8000030: 1b60 subs r0, r4, r5
8000032: bc30 pop {r4, r5}
8000034: 4770 bx lr
41
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 46c0 nop ; (mov r8, r8)
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 434b muls r3, r1
800002c: 3901 subs r1, #1
800002e: d1fc bne.n 800002a <fact_loop>
8000030: 6805 ldr r5, [r0, #0]
8000032: 1b60 subs r0, r4, r5
8000034: bc30 pop {r4, r5}
8000036: 4770 bx lr
PUT32(FLASH_ACR,0x3A);
41
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 434b muls r3, r1
800002a: 3901 subs r1, #1
800002c: d1fc bne.n 8000028 <fact_loop>
800002e: 6805 ldr r5, [r0, #0]
8000030: 1b60 subs r0, r4, r5
8000032: bc30 pop {r4, r5}
8000034: 4770 bx lr
...
41
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 46c0 nop ; (mov r8, r8)
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 434b muls r3, r1
800002c: 3901 subs r1, #1
800002e: d1fc bne.n 800002a <fact_loop>
8000030: 6805 ldr r5, [r0, #0]
8000032: 1b60 subs r0, r4, r5
8000034: bc30 pop {r4, r5}
8000036: 4770 bx lr
flash acr 0x32
4c
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 46c0 nop ; (mov r8, r8)
800002a: 434b muls r3, r1
800002c: 3901 subs r1, #1
800002e: d1fb bne.n 8000028 <fact_loop>
8000030: 6805 ldr r5, [r0, #0]
8000032: 1b60 subs r0, r4, r5
8000034: bc30 pop {r4, r5}
8000036: 4770 bx lr
4c
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 46c0 nop ; (mov r8, r8)
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 46c0 nop ; (mov r8, r8)
800002c: 434b muls r3, r1
800002e: 3901 subs r1, #1
8000030: d1fb bne.n 800002a <fact_loop>
8000032: 6805 ldr r5, [r0, #0]
8000034: 1b60 subs r0, r4, r5
8000036: bc30 pop {r4, r5}
8000038: 4770 bx lr
flash acr 0x30
38
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 46c0 nop ; (mov r8, r8)
800002a: 434b muls r3, r1
800002c: 3901 subs r1, #1
800002e: d1fb bne.n 8000028 <fact_loop>
8000030: 6805 ldr r5, [r0, #0]
8000032: 1b60 subs r0, r4, r5
8000034: bc30 pop {r4, r5}
8000036: 4770 bx lr
3b
0800002c <fact_loop>:
800002c: d002 beq.n 8000034 <fact_done>
800002e: 434b muls r3, r1
8000030: 3901 subs r1, #1
8000032: e7fb b.n 800002c <fact_loop>
08000034 <fact_done>:
8000034: 6805 ldr r5, [r0, #0]
8000036: 1b60 subs r0, r4, r5
8000038: bc30 pop {r4, r5}
800003a: 4770 bx lr
38
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 2100 movs r1, #0
8000024: 220b movs r2, #11
8000026: 2301 movs r3, #1
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 3101 adds r1, #1
800002c: 434b muls r3, r1
800002e: 4291 cmp r1, r2
8000030: d4fb bmi.n 800002a <fact_loop>
8000032: 6805 ldr r5, [r0, #0]
8000034: 1b60 subs r0, r4, r5
8000036: bc30 pop {r4, r5}
8000038: 4770 bx lr
38
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 2100 movs r1, #0
8000024: 220b movs r2, #11
8000026: 2301 movs r3, #1
8000028: 46c0 nop ; (mov r8, r8)
800002a: 6804 ldr r4, [r0, #0]
0800002c <fact_loop>:
800002c: 3101 adds r1, #1
800002e: 434b muls r3, r1
8000030: 4291 cmp r1, r2
8000032: d4fb bmi.n 800002c <fact_loop>
8000034: 6805 ldr r5, [r0, #0]
8000036: 1b60 subs r0, r4, r5
8000038: bc30 pop {r4, r5}
800003a: 4770 bx lr
2d
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 434b muls r3, r1
800002a: 3901 subs r1, #1
800002c: d1fc bne.n 8000028 <fact_loop>
800002e: 6805 ldr r5, [r0, #0]
8000030: 1b60 subs r0, r4, r5
8000032: bc30 pop {r4, r5}
8000034: 4770 bx lr
Пропустите здесь:
Обратите внимание, чтоЯ изменил количество циклов, входное значение с 3 на 11.
При нулевых состояниях ожидания на флэш-памяти и включенной предварительной выборке ваш цикл:
38
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 2100 movs r1, #0
8000024: 220b movs r2, #11
8000026: 2301 movs r3, #1
8000028: 6804 ldr r4, [r0, #0]
0800002a <fact_loop>:
800002a: 3101 adds r1, #1
800002c: 434b muls r3, r1
800002e: 4291 cmp r1, r2
8000030: d4fb bmi.n 800002a <fact_loop>
8000032: 6805 ldr r5, [r0, #0]
8000034: 1b60 subs r0, r4, r5
8000036: bc30 pop {r4, r5}
8000038: 4770 bx lr
Это означает, что тактовая частота 0x38 междудве инструкции ldr.Выравнивание не повлияло на это в мгновение ока.
Если вы используете Питера или его вариант (bne имеет для меня больше смысла, чем плюс минус, YMMV) * 1042 *
2d
08000020 <fact>:
8000020: b430 push {r4, r5}
8000022: 210b movs r1, #11
8000024: 2301 movs r3, #1
8000026: 6804 ldr r4, [r0, #0]
08000028 <fact_loop>:
8000028: 434b muls r3, r1
800002a: 3901 subs r1, #1
800002c: d1fc bne.n 8000028 <fact_loop>
800002e: 6805 ldr r5, [r0, #0]
8000030: 1b60 subs r0, r4, r5
8000032: bc30 pop {r4, r5}
8000034: 4770 bx lr
Выравнивание также не влияет на этот цикл,Это меньше инструкций, а также быстрее.
Таким образом, из другого ответа и документации mul и sub по одному такту каждая ветвь, когда берется, составляет 2 такта в соответствии с этим ответом, поэтому 4 такта в цикле 1144 часа или 0x2C.Нет сомнений, что эти два номера имеют стоимость, возможно, отсюда и дополнительные два часа.Или это может быть то, как работает модуль предварительной выборки или другое.
Ваш цикл равен 5 часам или 55 или 0x37, тот же ответ для дополнительных двух измеряемых часов.
Так что я слишком усложнил некоторые из нихэксперименты, блок предварительной выборки из ST и работа в нулевом состоянии ожидания позволили нам увидеть производительность, показанную в документации ARM.При обратном отсчете вместо повышения сохранялась инструкция в цикле, которая меньше по размеру и быстрее, чего вы и просили.
Ваши 5 часов за цикл 3 факторных значения означают 14 часов (5 + 5 + 4), ваши 22 часа (проверьте, как вы их измерили, очень часто у линейки есть проблема с тестированием, а не с кодом), где 8 часов где-то ещеминус 3 за инструкции по установке, если вы их считали.Какой бы линейкой вы ни пользовались, если используете решение обратного отсчета, посмотрите, как это сравнивается в вашей системе.Сохраняет пару инструкций, одну внутри и одну вне цикла.
------- EDIT
Я немного удивлен, что gcc не оптимизировал это в цикл обратного отсчета.Я пробовал только одну версию, возможно, более старая версия 3.x или 4.x.Также, если вы собираете для cortex-m3, он использует инструкцию thumb2, а не команду thumb.
unsigned int fact ( unsigned int x )
{
unsigned int a;
unsigned int rb;
a=1;
for(rb=1;rb<=x;rb++)
{
a*=rb;
}
return(a);
}
unsigned int fact2 ( unsigned int x )
{
unsigned int a;
a=1;
while(x)
{
a*=x--;
}
return(a);
}
Да, я мог бы оптимизировать код C дальше ...
Disassembly of section .text:
00000000 <fact>:
0: b140 cbz r0, 14 <fact+0x14>
2: 2301 movs r3, #1
4: 461a mov r2, r3
6: fb03 f202 mul.w r2, r3, r2
a: 3301 adds r3, #1
c: 4298 cmp r0, r3
e: d2fa bcs.n 6 <fact+0x6>
10: 4610 mov r0, r2
12: 4770 bx lr
14: 2201 movs r2, #1
16: 4610 mov r0, r2
18: 4770 bx lr
1a: bf00 nop
0000001c <fact2>:
1c: 4603 mov r3, r0
1e: 2001 movs r0, #1
20: b123 cbz r3, 2c <fact2+0x10>
22: fb03 f000 mul.w r0, r3, r0
26: 3b01 subs r3, #1
28: d1fb bne.n 22 <fact2+0x6>
2a: 4770 bx lr
2c: 4770 bx lr
2e: bf00 nop
Iзабыл про cbz, я не использую thumb2 без необходимости, не такой универсально переносимый, как классические инструкции для большого пальца ...
более портативная версия:
Disassembly of section .text:
00000000 <fact>:
0: 2800 cmp r0, #0
2: d007 beq.n 14 <fact+0x14>
4: 2301 movs r3, #1
6: 2201 movs r2, #1
8: 435a muls r2, r3
a: 3301 adds r3, #1
c: 4298 cmp r0, r3
e: d2fb bcs.n 8 <fact+0x8>
10: 0010 movs r0, r2
12: 4770 bx lr
14: 2201 movs r2, #1
16: e7fb b.n 10 <fact+0x10>
00000018 <fact2>:
18: 0003 movs r3, r0
1a: 2001 movs r0, #1
1c: 2b00 cmp r3, #0
1e: d003 beq.n 28 <fact2+0x10>
20: 4358 muls r0, r3
22: 3b01 subs r3, #1
24: 2b00 cmp r3, #0
26: d1fb bne.n 20 <fact2+0x8>
28: 4770 bx lr
2a: 46c0 nop ; (mov r8, r8)
Хмммм:
20: 4358 muls r0, r3
22: 3b01 subs r3, #1
24: 2b00 cmp r3, #0
26: d1fb bne.n 20 <fact2+0x8>
вау.
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.