GCC compiler divmod call generation for Cortex-M0 - Page 1
Forum section: electronics / general

author: cv007
author_rank: Frequent Contributor
timestamp: January 03, 2025, 02:29:32 am
content: Any explanation for the following generation of div calls for the following test?https://godbolt.org/z/zbWzhjG9Yline 14 - comment/uncomment to see changesIf the base_ var is global, the compiler generates a single call to uidivmod, and if the var is local (or static) it generates a call to uidivmod but also another to uidiv. For some reason it appears the optimization is opposite of what it should be, or normally is. What am I missing here?

author: brucehoult
author_rank: Super Contributor
timestamp: January 03, 2025, 03:31:19 am
content: Because it sees that 10 is a constant and distributes it to the two divisions before noticing that actually there is no division instruction on that CPU.If you change the CPU to M3 then there is a single division instruction generated for the divide by 10, and a multiply-subtract to get the remainder.Even if you change it to ...Code:u32 q = u / base_;u32 r = u - q * base_;return q + r;... it just puts the 2nd division back in again.

author: brucehoult
author_rank: Super Contributor
timestamp: January 03, 2025, 03:38:23 am
content: Even the latest version of GCC does the same.Every version of Clang from 9 to head generates some variation on:Code:test1(unsigned int):push {r4, r5, r7, lr}add r7, sp, #8mov r4, r0movs r5, #10mov r1, r5bl __aeabi_uidivmuls r5, r0, r5subs r1, r4, r5adds r0, r1, r0pop {r4, r5, r7, pc}

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 03, 2025, 07:13:10 am
content: If you declare base_ 'constexpr', you'll also get the double div thing. Fun.

author: mikerj
author_rank: Super Contributor
timestamp: January 03, 2025, 11:33:58 am
content: Turn off optimisations and you get the two calls for any combination of global/local/constexpr, so it seems like an optimiser failure.

author: brucehoult
author_rank: Super Contributor
timestamp: January 03, 2025, 12:09:32 pm
content: Quote from: mikerj on January 03, 2025, 11:33:58 amSeems like a cost estimation failure for the C-M0. It's fine on cores with hardware divide.If no one submits a bug report then it will never change.

author: bson
author_rank: Unknown
timestamp: January 04, 2025, 08:35:06 pm
content: A lot of these optimizations happen in the target machine description, and it can get pretty messy when different target variants have different instruction sets. I'm not at all surprised there are bugs...

author: brucehoult
author_rank: Super Contributor
timestamp: January 04, 2025, 08:42:28 pm
content: Quote from: bson on January 04, 2025, 08:35:06 pmIt's not a bug, it's just less than optimal code generation.It is weird though that a "divmod" call exists which presumably returns both results, but you can't just use both of them.

author: cv007
author_rank: Frequent Contributor
timestamp: January 04, 2025, 09:16:49 pm
content: With -O1 and -fexpensive-optimizations the optimization appears to enable at that point-https://godbolt.org/z/n8eT5Meb5but still only with the base as a global. Any value known to the compiler as compile time results in the double call.My code that uses divmod is in a C++ class where the base is not a constant, so I do end up with a single divmod call for the m0. During various testing and code creation I will sometimes see the double call and get confused as to why that is happening.The avr will always produce a single divmod (with optimizations on), and in that case it looks like the optimization comes via the machine descriptor file in gcc. Maybe since the M0 is kind of the loner in cortex-m series, gcc is treating the costs of the divmod vs div in the same way for all cortex-m even though the m0 has to make a library call. Reloading of constants vs loading of memory I suppose is also involved in this cost calculation.

author: westfw
author_rank: Super Contributor
timestamp: January 04, 2025, 10:11:48 pm
content: Quotegcc support for ARMv6m (Cortex M0, M0+) isn't great.Another example is that there is no "optimized" floating point code (there IS for ARMv7m), so any use of floats on CM0 brings in the rather bloated and slow C version from gcc.

author: coppice
author_rank: Super Contributor
timestamp: January 04, 2025, 10:17:38 pm
content: Quote from: westfw on January 04, 2025, 10:11:48 pmVery few people implementing GCC for a machine without an FPU have bothered to do much about that slow C code implementation of floating point. I think it was only intended as a "get you started" version of floating point, so I don't think they even tried to make it as good as you can get with C. I started to do work on it at one point, but got distracted.

author: SiliconWizard
author_rank: Super Contributor
timestamp: January 04, 2025, 10:21:29 pm
content: For those who want faster FP on the M0/M0+, you should definitely look at the RPi's implementation for the RP2040. I don't know what license it is, so whether you're allowed to use it on other targets. Something to look at.If I'm not mistaken, it's based on this implementation, which for sure you can freely (GPL 2) use:https://www.quinapalus.com/qfplib-m0-full.html