Repository navigation
drivers: fix overflow in ClockDevice.sleep_ms - #1088
Conversation
|
Did you try enabling compiler_rt? |
|
Yes. With .bundle_compiler_rt = true on the ATmega328P, compiler_rt itself fails to build with Zig 0.17.0 (address space 'flash' cannot cast into address space 'generic', ziglang/zig#37090, still open), which is why the AVR ports turn it off. |
Grazfather
left a comment
There was a problem hiding this comment.
- This adds avr-specific comments in a generic driver. I would just say that it avoid using mult instructions. Please test against multiple targets (e.g. wch, esp32c3, rp2040, and atmega328) + disassemble and provide evidence
- Do you see evidence of the
mswasting time storing to the stack and then copying to an arg. I wonder if using a bunch of@as(u64...might avoid this. Again, please test against those targets.
|
Thanks for the review. I went back to a plain multiply, I built a small probe with ReleaseSmall (Zig 0.17.0) for avr5, rp2040, esp32c3, ch32v003 and ch32v203 and looked at the disassembly. With optimizations LLVM turns the shifts back into
At first the shifts looked better on AVR, because they linked in the example firmware and the multiply didn't. The reason was something else: in the default build the drivers module is compiled in Debug even when the firmware is ReleaseSmall ( On AVR this is the same as main: with a constant like About This is compile and disassembly only, I didn't run it on hardware. Probe and results
const ClockDevice = @import("base/ClockDevice.zig");
export fn old_u32_mul(td: *const ClockDevice, time_ms: u32) void {
td.sleep_us(time_ms * 1000);
}
export fn u64_mul(td: *const ClockDevice, time_ms: u32) void {
td.sleep_us(@as(u64, time_ms) * 1000);
}
export fn shifts(td: *const ClockDevice, time_ms: u32) void {
const ms: u64 = time_ms;
td.sleep_us((ms << 10) - (ms << 4) - (ms << 3));
}cd drivers/src
zig build-obj probe_sleep.zig -OReleaseSmall -ffunction-sections -target avr-freestanding -mcpu=avr5 -femit-bin=avr.o
zig build-obj probe_sleep.zig -OReleaseSmall -ffunction-sections -target thumb-freestanding-eabi -mcpu=cortex_m0plus -femit-bin=rp2040.o
zig build-obj probe_sleep.zig -OReleaseSmall -ffunction-sections -target riscv32-freestanding-eabi -mcpu=generic_rv32+c+m+zicsr+zifencei -femit-bin=esp32c3.o
zig build-obj probe_sleep.zig -OReleaseSmall -ffunction-sections -target riscv32-freestanding-eabi -mcpu=generic_rv32+e+c+xwchc+zicsr+zifencei-i -femit-bin=ch32v003.o
zig build-obj probe_sleep.zig -OReleaseSmall -ffunction-sections -target riscv32-freestanding-eabi -mcpu=generic_rv32+m+a+c+xwchc+zicsr+zifencei -femit-bin=ch32v203.o
avr-objdump -dr avr.o
llvm-objdump -dr rp2040.o # same for the other threeInstruction counts exclude callees;
AVR example firmware (Nano, ReleaseSmall,
With |
|
This was merged before I pushed the change I described above, so I opened #1090 with it. |
ClockDevice.sleep_mscomputedtime_ms * 1000inu32, which overflows from 4,294,968 ms (about 71.6 minutes): a panic with runtime safety enabled, illegal behavior otherwise. This multiplies inu64instead.Adds a test for 0, 1, the last value that fit, the first that overflowed, and
maxInt(u32); it fails against main's implementation withinteger overflow.