#15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows ---------------------------------+------------------------------ Reporter: simonmic | Owner: (none) Type: bug | Status: new Priority: normal | Milestone: 8.6.1 Component: Compiler | Version: 8.4.2 Resolution: | Keywords: Operating System: Windows | Architecture: x86 Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | ---------------------------------+------------------------------ Comment (by Phyx-): It does. It's right there in {{{ void hs_clock_win32_gettime_monotonic(long long* t) { LARGE_INTEGER time; LARGE_INTEGER frequency; QueryPerformanceCounter(&time); QueryPerformanceFrequency(&frequency); // seconds t[0] = time.QuadPart / frequency.QuadPart; // nanos = t[1] = ticks_to_nanos(time.QuadPart % frequency.QuadPart, frequency.QuadPart); } }}} At the optimization level `clock` is requesting, namely `-O3` GCC will do multiplication widening optimizations. This optimize `time.QuadPart / frequency.QuadPart` and `time.QuadPart % frequency.QuadPart` into a single `divmod`. It even says so {{{ Pass statistics of "widening_mul": ---------------- divmod calls inserted: 1 hs_clock_win32_gettime_monotonic (long long intD.8 * tD.60113) { # PT = nonlocal null long long intD.8 * t_9(D) = tD.60113; union LARGE_INTEGERD.2224 frequencyD.60117; union LARGE_INTEGERD.2224 timeD.60116; long long intD.8 _1; long long intD.8 _2; long long intD.8 _3; long long intD.8 _4; long long intD.8 _5; doubleD.23 _11; doubleD.23 _15; doubleD.23 _16; doubleD.23 _17; long intD.3 _18; __complex__ long long intD.8 divmod_tmp_19; ;; basic block 2, loop depth 0, count 0, freq 10000, maybe hot ;; prev block 0, next block 1, flags: (NEW, REACHABLE, VISITED) ;; pred: ENTRY [100.0%] (FALLTHRU,EXECUTABLE) # .MEM_7 = VDEF <.MEM_6(D)> # USE = nonlocal { D.60116 D.60117 } (escaped) # CLB = nonlocal { D.60116 D.60117 } (escaped) QueryPerformanceCounter@4D.8347 (&timeD.60116); # .MEM_8 = VDEF <.MEM_7> # USE = nonlocal { D.60116 D.60117 } (escaped) # CLB = nonlocal { D.60116 D.60117 } (escaped) QueryPerformanceFrequency@4D.8349 (&frequencyD.60117); # VUSE <.MEM_8> _1 = timeD.60116.QuadPartD.2223; # VUSE <.MEM_8> _2 = frequencyD.60117.QuadPartD.2223; divmod_tmp_19 = DIVMOD (_1, _2); <---- divmod inserted here. - Phyx _3 = REALPART_EXPR <divmod_tmp_19>; # .MEM_10 = VDEF <.MEM_8> *t_9(D) = _3; # RANGE [-9223372036854775807, 9223372036854775807] _4 = IMAGPART_EXPR <divmod_tmp_19>; _11 = (doubleD.23) _4; _15 = _11 * 1.0e+9; _16 = (doubleD.23) _2; _17 = _15 / _16; _18 = (long intD.3) _17; # RANGE [-2147483648, 2147483647] _5 = (long long intD.8) _18; # .MEM_12 = VDEF <.MEM_10> MEM[(long long intD.8 *)t_9(D) + 8B] = _5; # .MEM_13 = VDEF <.MEM_12> timeD.60116 ={v} {CLOBBER}; # .MEM_14 = VDEF <.MEM_13> frequencyD.60117 ={v} {CLOBBER}; # VUSE <.MEM_14> return; ;; succ: EXIT [100.0%] (EXECUTABLE) } }}} This entire file, always uses 64 bit types. You have no hardware support for 64 bit `divmod`. The compiler is smart enough to know this and expands the built-in `DIVMOD` to a library call which is expected to do the operation. The implementation for the call is in `libgcc`. The explicit purpose for `libgcc` is to handle these calls the compiler emits to do the software emulation[1]. {{{ GCC provides a low-level runtime library, libgcc.a or libgcc_s.so.1 on some platforms. GCC generates calls to routines in this library automatically, whenever it needs to perform some operation that is too complicated to emit inline code for. Most of the routines in libgcc handle arithmetic operations that the target processor cannot perform directly. This includes integer multiply and divide on some machines, and all floating-point and fixed-point operations on other machines. libgcc also includes routines for exception handling, and a handful of miscellaneous operations. }}} So yes, using a complex operation that the architecture has no support for requires explicit software emulation, and thus requires compiling against `libgcc`. Or turning off the optimization. Possibly for that function alone using an attribute. Either way, this is not a GHC bug. [1] https://gcc.gnu.org/onlinedocs/gccint/Libgcc.html -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/15094#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler