29034, "jabraham17", "[Bug]: LICM incorrectly hoists part of conditionals", "2026-06-29T16:27:55Z"
The following code works fine, however it results in signed integer overflow
proc tester(maxBytes, maxChars) {
var buffSz = 10;
var n = 0;
var nChars = 0;
while nChars < maxChars {
var requestSz = 2*buffSz;
// make sure to at least request 16 bytes
if requestSz < n + 16 then requestSz = n + 16;
// but don't ever ask for more bytes than maxBytes + 5
if maxBytes < max(int) && requestSz > maxBytes + 5 then
requestSz = maxBytes + 5;
nChars += requestSz;
}
return n;
}
config const maxBytes:int, maxChars:int;
proc main() {
tester(maxBytes, maxChars);
}
requestSz > maxBytes + 5 can overflow, however its guarded by maxBytes < max(int), so in practice it shouldn't. There are two issues with that
- Technically, if
maxBytesis2**63 - 2, it will still overflow because the comparison will pass. This can be fixed by adjusting the code (and it should be) - When compiled by default, the Chapel compiler actually LICM's several subexpressions out of the loop, including
maxBytes + 5andmaxBytes < max(int). This means thatmaxBytes + 5is actually executed unconditionally.
This code snippet is from IO:readStringImpl, and the overflow can be triggered by compiling chpl test/io/serializers/maps.chpl -sformat=FormatKind.json and then running it. Compiling with --no-loop-invariant-code-motion results in the overflow going away. The best way to observe this failure is with CHPL_SANITIZE_EXE=undefined
CHPL_HOST_PLATFORM: linux64
CHPL_HOST_COMPILER: clang
CHPL_HOST_CC: /llvm-22.1.6-aowpbepnipvtffkn6ccoirruwirq46mv/bin/clang
CHPL_HOST_CXX: /llvm-22.1.6-aowpbepnipvtffkn6ccoirruwirq46mv/bin/clang++
CHPL_HOST_ARCH: x86_64
CHPL_TARGET_PLATFORM: linux64
CHPL_TARGET_COMPILER: clang *
CHPL_TARGET_CC: clang
CHPL_TARGET_CXX: clang++
CHPL_TARGET_LD: clang++
CHPL_TARGET_ARCH: x86_64
CHPL_TARGET_CPU: native
CHPL_LOCALE_MODEL: flat
CHPL_COMM: none
CHPL_TASKS: qthreads
CHPL_LAUNCHER: none
CHPL_TIMERS: generic
CHPL_UNWIND: bundled
CHPL_HOST_MEM: jemalloc
CHPL_HOST_JEMALLOC: bundled
CHPL_TARGET_MEM: cstdlib *
CHPL_ATOMICS: cstdlib
CHPL_GMP: bundled
CHPL_HWLOC: bundled
CHPL_HWLOC_PCI: disable
CHPL_RE2: bundled
CHPL_LLVM: system
CHPL_LLVM_SUPPORT: system
CHPL_LLVM_CONFIG: /llvm-22.1.6-aowpbepnipvtffkn6ccoirruwirq46mv/bin/llvm-config *
CHPL_LLVM_VERSION: 22
CHPL_AUX_FILESYS: none
CHPL_LIB_PIC: none
CHPL_SANITIZE: none
CHPL_SANITIZE_EXE: undefined *
The bad comparison can easily be fixed by adjusting readStringImpl (and should be), but the LICM bug will require a compiler fix (have not investigated further yet). LICM should not violate the semantics of &&. If you replace the + with a function call (even with a user defined overloaded +), the hoist will not occur, so its not possible to get side effects, but undefined behavior will still occur