Futhark Fixes a Ten-Year-Old INT_MIN Division Bug and Pays 2.3x on One GPU Benchmark
Software / news
Futhark Fixes a Ten-Year-Old INT_MIN Division Bug and Pays 2.3x on One GPU Benchmark
The generated C divided the lowest 32-bit integer by -1, which C leaves undefined. The guard adds a branch to every signed division.
Futhark fixed a ten-year-old bug on October 14: dividing the most negative 32-bit integer by -1 in code the compiler generates is undefined behaviour in C, and the fix costs a branch on every signed division.
The language's author described the change in a post on the Futhark site, and the work landed in pull request #2579, opened October 13 and merged the next day as commit 6cca9ee.
What the bug is
Futhark compiles to C, so it inherits C's rules. A signed 32-bit integer runs from -2,147,483,648 to 2,147,483,647. Divide the lowest value by -1 and the true answer, 2,147,483,648, does not fit.
The C standard calls that undefined, and on x86 the idiv instruction raises a CPU exception instead of returning anything. John Regehr's 2013 write-up shows the result with gcc 4.7.2: a floating point exception at -O0 and -O1, and no crash at -O2 because the compiler folded the constant away. He wrote that the case "is explicitly undefined in C11 and C++11."
So a Futhark program could crash on one build setting and run on another, depending on what the C compiler did with the division.
How rare it is
The post's title puts the affected share at 0.000000000000000000542% of cases. The body says one in every 2^64 possible input pairs for 32-bit integers is affected. By my arithmetic, 2^-64 as a percentage is about 5.4e-18, so the title and the body do not quite agree. Either way, random testing would never find it, which is how it lasted about ten years.
Real data is not random. A program that negates a minimum value through division, or divides by a constant -1 after a sign flip, can reach the pair on purpose.
The fix and its price
The runtime function squot32 went from a plain x / y to a version that checks for a divisor of -1 and negates using unsigned arithmetic:
return y == -1 ? (int32_t)(0 - (uint32_t)x) : x / y;
The author measured it on a synthetic benchmark, divisions.fut, with an input of 100000i32 [10000]i32 [10000]i32.
| Backend | Old compiler | New compiler |
|---|---|---|
| C, sequential | 3,390,148 μs | 3,389,215 μs |
| CUDA (NVIDIA GPU) | 5,548 μs | 12,592 μs |
- Old compiler5548 μs
- New compiler13K μs
Source: Futhark blog, 2026-10-14, accessed 2026-10-20
On CUDA the contrived benchmark runs about 2.3 times slower. The author traced it to the generated PTX: the old code kept four div.s32 instructions in one basic block, and the fixed code puts branches between them. On the Futhark benchmark suite, on GPU, the author could not measure any effect. A HIP run on an AMD GPU is described as "slightly less" affected, with no figures given.
What a reader should take from it
Programs that never divide the minimum value by -1 see no difference in results. Programs on GPU that do heavy signed division in tight loops are the ones to re-time after upgrading.
The pull request's own review thread shows the change touched more than the scalar path. An automated Copilot review flagged three high-severity issues around ceiling division in the ISPC, uniform and scalar paths, including that "SCeilDiv mishandles minBound divided by -1". A later review marked all three resolved but recommended a closer human look at the cross-backend arithmetic. The change also adds edge-case tests for i8, i16, i32 and i64 division.
More coverage of developer tooling: OpenCode and CLI-Anything.
The author says this is the last undefined behaviour they remember in Futhark's generated C. One implementation-defined case, shifting by more bits than the type holds, is still unfixed.
Sources
More in Software
- 01Cloudflare's tsrs Claims 8x Over TypeScript 7.0, With the Typical Case UnpublishedThe Rust port is Apache-2.0, experimental and installable today. Its speedup is an 'up to' figure, and diagnostics still print in a different order.
- 02OpenBSD 8.0 Drops Loongson, Rebases Graphics on Linux 6.18 and Ships OpenSSH 10.6The 61st release lifts amd64 kernel address space to 512G and carries an SSH compression change that can slow transfers.
- 03Jepsen Found Orkes Conductor Marking Workflows Complete That Never RanNine findings across versions 5.3.2 to 5.5.0-rc2. Orkes, which funded the test, says seven are closed; Jepsen lists two as still under investigation.
- 04Orca Gains 1,590 Stars in a Day and Answers Three of crystl's Six tmux Limits, With 4,303 Open PRsThe MIT-licensed worktree app for coding agents has 98,318 stars and 4,306 open issues; its README addresses three of the six tmux limits crystl lists.