ARM-高效C编程|第三篇 ARM C 高效编程 - 除法以及求余

除法以及求余运算

/** * 结论: *1. 大部分arm都有除法指令,但需要指定相应的编译标志,不然就会直接调用 c 库函数 *2. 指定相应的体系架构,可以生成更优的代码 * compile with arm-linux-gnueabihf-gcc v8.3 * flags: -O3 -mcpu=cortex-a7 -mtune=cortex-a7 -mfloat-abi=hard -mfpu=neon * 000103d8 : * 103d8:e713f110sdivr3, r0, r1; 除法指令 * 103dc:e0600391mlsr0, r1, r3, r0 ; 乘减指令 * 103e0:e0830000addr0, r3, r0 * 103e4:e12fff1ebxlr * flags: -O3 * 00010410 : * 10410:e92d4010push{r4, lr} * 10414:eb000089bl10640 <__aeabi_idivmod> ; 调用 c 库提供的除法函数,同时返回商和余数 * 10418:e0800001addr0, r0, r1 * 1041c:e8bd8010pop{r4, pc} */int combined_div_mod(int a, int b) { return (a / b) + (a % b); }

/** * 结论: *1. 尽量将求余操作转为加法操作 * compile with arm-linux-gnueabihf-gcc v8.3 * flags: -O3 -mcpu=cortex-a7 -mtune=cortex-a7 -mfloat-abi=hard -mfpu=neon * 000103d8 : * 103d8:e2800001addr0, r0, #1 * 103dc:e3083889movwr3, #34953; 0x8889 * 103e0:e3483888movtr3, #34952; 0x8888 * 103e4:e3a0203cmovr2, #60 ; 0x3c * 103e8:e0831093umullr1, r3, r3, r0 ; 无符号长乘法 * 103ec:e1a032a3lsrr3, r3, #5 * 103f0:e0600392mlsr0, r2, r3, r0 ; 乘减指令 * 103f4:e12fff1ebxlr * 000103f8 : * 103f8:e2800001addr0, r0, #1 * 103fc:e350003ccmpr0, #60 ; 0x3c * 10400:23a00000movcsr0, #0 * 10404:e12fff1ebxlr */uint32_t counter1(uint32_t count) { return (++count % 60); }uint32_t counter2(uint32_t count) { if (++count >= 60) count = 0; return (count); }

/** * 结论: *1. 无符号数比有符号数除法更快 *2. 除数如果为 2 的幂。将转为超快的移位操作 *3. 除数如果为常数,也可以转为移位操作,不过要多一些指令,尤其是多了一条乘法指令 *4. 其余情况就只能调用除法指令 * compile with arm-linux-gnueabihf-gcc v8.3 * flags: -O3 -mcpu=cortex-a7 -mtune=cortex-a7 -mfloat-abi=hard -mfpu=neon * 00010410 : * 10410:e1a00220lsrr0, r0, #4 * 10414:e12fff1ebxlr * 00010424 : * 10424:e280300faddr3, r0, #15 * 10428:e3500000cmpr0, #0 * 1042c:b1a00003movltr0, r3 * 10430:e1a00240asrr0, r0, #4 * 10434:e12fff1ebxlr * 000103e0 : * 103e0:e730f110udivr0, r0, r1 ; 除法指令 * 103e4:e12fff1ebxlr * 000103e8 : * 103e8:e30f30f1movwr3, #61681; 0xf0f1 * 103ec:e34f30f0movtr3, #61680; 0xf0f0 * 103f0:e0803093umullr3, r0, r3, r0; 长乘法指令 * 103f4:e1a00220lsrr0, r0, #4 * 103f8:e12fff1ebxlr */uint32_t div16u(uint32_t a) { return a / 16; }int div16s(int a) { return a / 16; }uint32_t div_xx_u(uint32_t a, uint32_t b) { return a / b; }uint32_t div17u(uint32_t a) { return a / 17; }

    推荐阅读