[GHC] #15094: unknown symbol `___divmoddi4' error with clock on 32-bit windows

GHC ghc-devs at haskell.org
Tue May 1 20:58:27 UTC 2018


#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 at 4D.8347 (&timeD.60116);
   # .MEM_8 = VDEF <.MEM_7>
   # USE = nonlocal { D.60116 D.60117 } (escaped)
   # CLB = nonlocal { D.60116 D.60117 } (escaped)
   QueryPerformanceFrequency at 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


More information about the ghc-tickets mailing list