Simon Jakobi pushed to branch wip/sjakobi/T24813 at Glasgow Haskell Compiler / GHC

Commits:

5 changed files:

Changes:

  • changelog.d/ncg-x86-subword-popcnt
    1
    +section: compiler
    
    2
    +synopsis: The x86 native code generator now emits shorter code for ``popCnt8#``
    
    3
    +  and ``popCnt16#`` with ``-msse4.2``
    
    4
    +description:
    
    5
    +  Sub-word popcounts now use the 32-bit ``popcnt`` instruction, which
    
    6
    +  zero-extends its result for free, and skip zero-extending an argument that
    
    7
    +  is already zero-extended, as in ``popCount`` on ``Word8`` or ``Word16``.
    
    8
    +  The popcount sequence shrinks from up to five instructions to one to three.
    
    9
    +mrs: !16640
    
    10
    +issues: #24813

  • compiler/GHC/CmmToAsm/X86/CodeGen.hs
    ... ... @@ -6739,20 +6739,23 @@ genPopCnt bid width dst src = do
    6739 6739
     
    
    6740 6740
         True -> do
    
    6741 6741
           code_src <- getAnyReg src
    
    6742
    -      src_r <- getNewRegNat format
    
    6742
    +      -- Sub-word popcounts use 32-bit POPCNT, whose write zero-extends the
    
    6743
    +      -- result to the full register.
    
    6744
    +      src_r <- getNewRegNat (max II32 format)
    
    6743 6745
           let dst_r = getRegisterReg platform  (CmmLocal dst)
    
    6746
    +          -- A sub-word argument is a full Word# whose upper bits may be
    
    6747
    +          -- dirty, so zero-extend it unless it visibly already is.
    
    6748
    +          zx_src
    
    6749
    +            | CmmMachOp (MO_UU_Conv from _) [_] <- src, from <= width
    
    6750
    +            = nilOL
    
    6751
    +            | otherwise
    
    6752
    +            = unitOL (MOVZxL format (OpReg src_r) (OpReg src_r))
    
    6744 6753
           return $ code_src src_r `appOL`
    
    6745
    -          (if width == W8 then
    
    6746
    -               -- The POPCNT instruction doesn't take a r/m8
    
    6747
    -               unitOL (MOVZxL II8 (OpReg src_r) (OpReg src_r)) `appOL`
    
    6748
    -               unitOL (POPCNT II16 (OpReg src_r) dst_r)
    
    6749
    -           else
    
    6750
    -               unitOL (POPCNT format (OpReg src_r) dst_r)) `appOL`
    
    6751 6754
               (if width == W8 || width == W16 then
    
    6752
    -               -- We used a 16-bit destination register above,
    
    6753
    -               -- so zero-extend
    
    6754
    -               unitOL (MOVZxL II16 (OpReg dst_r) (OpReg dst_r))
    
    6755
    -           else nilOL)
    
    6755
    +               zx_src `appOL`
    
    6756
    +               unitOL (POPCNT II32 (OpReg src_r) dst_r)
    
    6757
    +           else
    
    6758
    +               unitOL (POPCNT format (OpReg src_r) dst_r))
    
    6756 6759
     
    
    6757 6760
         False ->
    
    6758 6761
           -- generate C call to hs_popcntN in ghc-prim
    

  • testsuite/tests/codeGen/should_gen_asm/T24813.asm
    1
    +popcnt8:
    
    2
    +        movzbl
    
    3
    +        popcnt
    
    4
    +        movq
    
    5
    +        jmp
    
    6
    +popcnt16:
    
    7
    +        movzwl
    
    8
    +        popcnt
    
    9
    +        movq
    
    10
    +        jmp

  • testsuite/tests/codeGen/should_gen_asm/T24813.cmm
    1
    +#include "Cmm.h"
    
    2
    +
    
    3
    +// Popcount of a zero-extended sub-word value should be a single
    
    4
    +// zero-extending load followed by one POPCNT (#24813).
    
    5
    +
    
    6
    +popcnt8 (W_ p) {
    
    7
    +    W_ r;
    
    8
    +    (r) = prim %popcnt8(%zx64(bits8[p]));
    
    9
    +    return (r);
    
    10
    +}
    
    11
    +
    
    12
    +popcnt16 (W_ p) {
    
    13
    +    W_ r;
    
    14
    +    (r) = prim %popcnt16(%zx64(bits16[p]));
    
    15
    +    return (r);
    
    16
    +}

  • testsuite/tests/codeGen/should_gen_asm/all.T
    ... ... @@ -27,6 +27,7 @@ test('T25233', [unless(arch('x86_64'), skip),
    27 27
                     when(unregisterised(), skip)], compile_grep_asm, ['hs', True, '-O'])
    
    28 28
     test('T25233b', [unless(arch('x86_64'), skip),
    
    29 29
                      when(unregisterised(), skip)], compile_grep_asm, ['cmm', True, ''])
    
    30
    +test('T24813', is_amd64_codegen, compile_cmp_asm, ['cmm', '-msse4.2'])
    
    30 31
     is_aarch64_codegen = [
    
    31 32
         unless(arch('aarch64'), skip),
    
    32 33
         when(unregisterised(), skip),