[GHC] #9340: Implement new `clz` inline primop
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: Type: feature request | Status: new Priority: normal | Milestone: 7.10.1 Component: Compiler | Version: 7.8.2 (CodeGen) | Differential Revisions: Keywords: primop clz | Architecture: Operating System: Unknown/Multiple | Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------- From a draft for #9281, I had to use a C FFI and using a gcc/clang `__builtin` to get access to the [http://en.wikipedia.org/wiki/Find_first_set CLZ instruction]: {{{#!hs -- | Compute base-2 log of 'Word#' -- -- This is internally implemented as count-leading-zeros machine instruction. foreign import ccall unsafe "integer_gmp_word_log2" wordLog2# :: Word# -> Int# }}} {{{#!c HsWord integer_gmp_word_log2(HsWord x) { #if (SIZEOF_HSWORD) == (SIZEOF_INT) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clz(x) : -1; #elif (SIZEOF_HSWORD) == (SIZEOF_LONG) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clzl(x) : -1; #elif (SIZEOF_HSWORD) == (SIZEOF_LONG_LONG) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clzll(x) : -1; #else # error unsupported SIZEOF_HSWORD #endif } }}} Since a `clz`-like operation should be available on most cpus GHC should expose that as a primop ({{{clz# :: Word# -> Int#}}}). -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: Type: feature | Status: new request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz (CodeGen) | Operating System: Unknown/Multiple Resolution: | Type of failure: None/Unknown Differential Revisions: | Test Case: Architecture: | Blocking: Unknown/Multiple | Difficulty: Unknown | Blocked By: | Related Tickets: | -------------------------------------+------------------------------------- Old description:
From a draft for #9281, I had to use a C FFI and using a gcc/clang `__builtin` to get access to the [http://en.wikipedia.org/wiki/Find_first_set CLZ instruction]:
{{{#!hs -- | Compute base-2 log of 'Word#' -- -- This is internally implemented as count-leading-zeros machine instruction. foreign import ccall unsafe "integer_gmp_word_log2" wordLog2# :: Word# -> Int# }}}
{{{#!c HsWord integer_gmp_word_log2(HsWord x) { #if (SIZEOF_HSWORD) == (SIZEOF_INT) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clz(x) : -1; #elif (SIZEOF_HSWORD) == (SIZEOF_LONG) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clzl(x) : -1; #elif (SIZEOF_HSWORD) == (SIZEOF_LONG_LONG) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clzll(x) : -1; #else # error unsupported SIZEOF_HSWORD #endif } }}}
Since a `clz`-like operation should be available on most cpus GHC should expose that as a primop ({{{clz# :: Word# -> Int#}}}).
New description: From a draft for #9281, I had to use a C FFI and using a gcc/clang `__builtin` to get access to the [http://en.wikipedia.org/wiki/Find_first_set CLZ instruction]: {{{#!hs -- | Compute base-2 log of 'Word#' -- -- This is internally implemented as count-leading-zeros machine instruction. foreign import ccall unsafe "integer_gmp_word_log2" wordLog2# :: Word# -> Int# }}} {{{#!c HsWord integer_gmp_word_log2(HsWord x) { #if (SIZEOF_HSWORD) == (SIZEOF_INT) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clz(x) : -1; #elif (SIZEOF_HSWORD) == (SIZEOF_LONG) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clzl(x) : -1; #elif (SIZEOF_HSWORD) == (SIZEOF_LONG_LONG) return x ? (WORD_SIZE_IN_BITS-1) - __builtin_clzll(x) : -1; #else # error unsupported SIZEOF_HSWORD #endif } }}} Since a `clz`-like operation should be available on most cpus GHC should expose that as a primop ({{{clz# :: Word# -> Int#}}}). -- Comment (by hvr): (remove hidden Unicode characters in code blocks) -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:1> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: new request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz (CodeGen) | Architecture: Unknown/Multiple Resolution: | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: | -------------------------------------+------------------------------------- Changes (by hvr): * owner: => hvr Comment: I'm now actively working on this one. And I've already got semi-working code that I'll submit to Phab soon (some pre-requisite code is already submitted as Phab:D141) -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:2> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: patch request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz (CodeGen) | Architecture: Unknown/Multiple Resolution: | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Changes (by hvr): * status: new => patch * differential: => Phab:D144 -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:3> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: patch request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz (CodeGen) | Architecture: Unknown/Multiple Resolution: | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Comment (by Herbert Valerio Riedel <hvr@…>): In [changeset:"9f285fa40f6fb0c8495dbec771d798ac6dfaabee/ghc"]: {{{ #!CommitTicketReference repository="ghc" revision="9f285fa40f6fb0c8495dbec771d798ac6dfaabee" Add CMOVcc insns to x86 NCG This is a pre-requisite for implementing count-{leading,trailing}-zero prim-ops (re #9340) and may be useful to NCG to help turn some code into branch-less code sequences. Test Plan: Compiles and validates in combination with clz/ctz primop impl Reviewers: ezyang, rwbarton, simonmar, austin Subscribers: simonmar, relrod, ezyang, carter Differential Revision: https://phabricator.haskell.org/D141 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:5> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: patch request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz (CodeGen) | Architecture: Unknown/Multiple Resolution: | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Comment (by Herbert Valerio Riedel <hvr@…>): In [changeset:"3669b60cb0b24e22563bfe624aab4aba369cbfca/ghc"]: {{{ #!CommitTicketReference repository="ghc" revision="3669b60cb0b24e22563bfe624aab4aba369cbfca" Add bit scan {forward,reverse} insns to x86 NCG This is a pre-requisite for implementing count-{leading,trailing}-zero prim-ops (re #9340) Reviewers: ezyang, rwbarton, simonmar, austin Subscribers: simonmar, relrod, ezyang, carter Differential Revision: https://phabricator.haskell.org/D141 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:4> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: patch request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz (CodeGen) | Architecture: Unknown/Multiple Resolution: | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Comment (by Herbert Valerio Riedel <hvr@…>): In [changeset:"e0c1767d0ea8d12e0a4badf43682a08784e379c6/ghc"]: {{{ #!CommitTicketReference repository="ghc" revision="e0c1767d0ea8d12e0a4badf43682a08784e379c6" Implement new CLZ and CTZ primops (re #9340) This implements the new primops clz#, clz32#, clz64#, ctz#, ctz32#, ctz64# which provide efficient implementations of the popular count-leading-zero and count-trailing-zero respectively (see testcase for a pure Haskell reference implementation). On x86, NCG as well as LLVM generates code based on the BSF/BSR instructions (which need extra logic to make the 0-case well-defined). Test Plan: validate and succesful tests on i686 and amd64 Reviewers: rwbarton, simonmar, ezyang, austin Subscribers: simonmar, relrod, ezyang, carter Differential Revision: https://phabricator.haskell.org/D144 GHC Trac Issues: #9340 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:6> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: closed request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz ctz (CodeGen) | Architecture: Unknown/Multiple Resolution: fixed | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Changes (by hvr): * keywords: primop clz => primop clz ctz * status: patch => closed * resolution: => fixed Comment: I consider this ticket resolved. The next step will be to expose those primops via `Data.Bits` (see Phab:D158 for a draft-patch which still needs to go through the library proposal process) -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:7> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: closed request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz ctz (CodeGen) | Architecture: Unknown/Multiple Resolution: fixed | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Comment (by Herbert Valerio Riedel <hvr@…>): In [changeset:"6375934bfe64ca15eb215327629f9f07a185377a/ghc"]: {{{ #!CommitTicketReference repository="ghc" revision="6375934bfe64ca15eb215327629f9f07a185377a" Workaround GCC `__ctzdi2` intrinsic linker errors On Linux/i386 the 64bit `__builtin_ctzll()` instrinsic doesn't get inlined by GCC but rather a short `__ctzdi2` runtime function is inserted when needed into compiled object files. This causes failures for the four test-cases TEST="T8639_api T8628 dynCompileExpr T5313" with error messages of the kind dynCompileExpr: .../libraries/ghc-prim/dist- install/build/libHSghcpr_BE58KUgBe9ELCsPXiJ1Q2r.a: unknown symbol `__ctzdi2' dynCompileExpr: dynCompileExpr: unable to load package `ghc-prim' This workaround forces GCC on 32bit x86 to to express `hs_ctz64` in terms of the 32bit `__builtin_ctz()` (this is no loss, as there's no 64bit BSF instruction on i686 anyway) and thus avoid the problematic out-of-line runtime function. Note: `__builtin_ctzll()` is used since e0c1767d0ea8d12e0a4badf43682a08784e379c6 (re #9340) }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:8> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: closed request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz ctz (CodeGen) | Architecture: Unknown/Multiple Resolution: fixed | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: #9532 Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Changes (by hvr): * related: => #9532 Comment: See #9532 for the related `Data.Bits` CLZ/CTZ interface ticket -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:9> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: closed request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz ctz (CodeGen) | Architecture: Unknown/Multiple Resolution: fixed | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: #9532 Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Comment (by Herbert Valerio Riedel <hvr@…>): In [changeset:"a8a969ae7a05e408b29961d0a2ea621a16d73d3e/ghc"]: {{{ #!CommitTicketReference repository="ghc" revision="a8a969ae7a05e408b29961d0a2ea621a16d73d3e" Add `FiniteBits(count{Leading,Trailing}Zeros)` This exposes the newly added CLZ/CTZ primops from e0c1767d0ea8d12e0a4badf43682a08784e379c6 (re #9340) via two new methods `countLeadingZeros` and `countTrailingZeros` in the `Data.Bits.FiniteBits` class. The original proposal can be found at http://www.haskell.org/pipermail/libraries/2014-August/023567.html Test Plan: successful validate Reviewers: ekmett, tibbe GHC Trac Issues: #9532 Differential Revision: https://phabricator.haskell.org/D158 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:10> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
#9340: Implement new `clz` inline primop -------------------------------------+------------------------------------- Reporter: hvr | Owner: hvr Type: feature | Status: closed request | Milestone: 7.10.1 Priority: normal | Version: 7.8.2 Component: Compiler | Keywords: primop clz ctz (CodeGen) | Architecture: Unknown/Multiple Resolution: fixed | Difficulty: Unknown Operating System: | Blocked By: Unknown/Multiple | Related Tickets: #9532 Type of failure: | None/Unknown | Test Case: | Blocking: | Differential Revisions: Phab:D144 | -------------------------------------+------------------------------------- Comment (by Herbert Valerio Riedel <hvr@…>): In [changeset:"612f3d120c65a461a4ad7f212d67bdae005f4975/ghc"]: {{{ #!CommitTicketReference repository="ghc" revision="612f3d120c65a461a4ad7f212d67bdae005f4975" Implement optimized NCG `MO_Ctz W64` op for i386 (#9340) Summary: This is an optimization to the CTZ primops introduced for #9340 Previously we called out to `hs_ctz64`, but we can actually generate better hand-tuned code while avoiding the FFI ccall. With this patch, the code {-# LANGUAGE MagicHash #-} module TestClz0 where import GHC.Prim ctz64 :: Word64# -> Word# ctz64 x = ctz64# x results in the following assembler generated by NCG on i386: TestClz.ctz64_info: movl (%ebp),%eax movl 4(%ebp),%ecx movl %ecx,%edx orl %eax,%edx movl $64,%edx je _nAO bsf %ecx,%ecx addl $32,%ecx bsf %eax,%eax cmovne %eax,%ecx movl %ecx,%edx _nAO: movl %edx,%esi addl $8,%ebp jmp *(%ebp) For comparision, here's what LLVM 3.4 currently generates: 000000fc <TestClzz_ctzz64_info>: fc: 0f bc 45 04 bsf 0x4(%ebp),%eax 100: b9 20 00 00 00 mov $0x20,%ecx 105: 0f 45 c8 cmovne %eax,%ecx 108: 83 c1 20 add $0x20,%ecx 10b: 8b 45 00 mov 0x0(%ebp),%eax 10e: 8b 55 08 mov 0x8(%ebp),%edx 111: 0f bc f0 bsf %eax,%esi 114: 85 c0 test %eax,%eax 116: 0f 44 f1 cmove %ecx,%esi 119: 83 c5 08 add $0x8,%ebp 11c: ff e2 jmp *%edx Reviewed By: austin Auditors: simonmar Differential Revision: https://phabricator.haskell.org/D163 }}} -- Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/9340#comment:11> GHC <http://www.haskell.org/ghc/> The Glasgow Haskell Compiler
participants (1)
-
GHC