Andreas Klebinger pushed to branch wip/andreask/9.10.4-batch1 at Glasgow Haskell Compiler / GHC

Commits:

9 changed files:

Changes:

  • changelog.d/T27046
    1
    +section: compiler
    
    2
    +issues: #27046
    
    3
    +mrs: !16031
    
    4
    +synopsis:
    
    5
    +  Avoid AArch64 register clobbering bug in MUL2
    
    6
    +description:
    
    7
    +  Fixes an issue in which, on AArch64, code generation for the MUL2 operation
    
    8
    +  could clobber one of the input operands when computing the lower bits, which
    
    9
    +  rendered invalid the subsequent computation of the high bits.

  • compiler/GHC/Cmm/Parser.y
    ... ... @@ -1164,6 +1164,8 @@ callishMachOps platform = listToUFM $
    1164 1164
         , allWidths "fetch_nand" (\w -> MO_AtomicRMW w AMO_Nand)
    
    1165 1165
         , allWidths "fetch_or" (\w -> MO_AtomicRMW w AMO_Or)
    
    1166 1166
         , allWidths "fetch_xor" (\w -> MO_AtomicRMW w AMO_Xor)
    
    1167
    +    , allWidths "mul2_" (\w -> MO_S_Mul2 w)
    
    1168
    +    , allWidths "mul2u_" (\w -> MO_U_Mul2 w)
    
    1167 1169
         ]
    
    1168 1170
       where
    
    1169 1171
         allWidths
    

  • compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
    ... ... @@ -1694,11 +1694,17 @@ genCCall target dest_regs arg_regs bid = do
    1694 1694
                   let lo = getRegisterReg platform (CmmLocal dst_lo)
    
    1695 1695
                       hi = getRegisterReg platform (CmmLocal dst_hi)
    
    1696 1696
                       nd = getRegisterReg platform (CmmLocal dst_needed)
    
    1697
    +              -- Generate a fresh virtual register for the low word computation.
    
    1698
    +              -- This avoids clobbering reg_a or reg_b in the first MUL instruction,
    
    1699
    +              -- which could for example happen if 'lo' and 'reg_a' are the same
    
    1700
    +              -- virtual register.
    
    1701
    +              tmp_lo <- getNewRegNat II64
    
    1697 1702
                   return (
    
    1698 1703
                       code_x `appOL`
    
    1699 1704
                       code_y `snocOL`
    
    1700
    -                  MUL   (OpReg W64 lo) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
    
    1705
    +                  MUL   (OpReg W64 tmp_lo) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
    
    1701 1706
                       SMULH (OpReg W64 hi) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
    
    1707
    +                  MOV   (OpReg W64 lo) (OpReg W64 tmp_lo) `snocOL`
    
    1702 1708
                       -- Are all high bits equal to the sign bit of the low word?
    
    1703 1709
                       -- nd = (hi == ASR(lo,width-1)) ? 1 : 0
    
    1704 1710
                       CMP   (OpReg W64 hi) (OpRegShift W64 lo SASR (widthInBits w - 1)) `snocOL`
    

  • libraries/process
    1
    -Subproject commit f7d51387ba7f7f6079f3a9d5ce011ad9359b7dbb
    1
    +Subproject commit 11fd247ad33208da7a914acf15d4a09d64a6a4c4

  • rts/sm/Evac.h
    ... ... @@ -6,7 +6,7 @@
    6 6
      *
    
    7 7
      * Documentation on the architecture of the Garbage Collector can be
    
    8 8
      * found in the online commentary:
    
    9
    - * 
    
    9
    + *
    
    10 10
      *   https://gitlab.haskell.org/ghc/ghc/wikis/commentary/rts/storage/gc
    
    11 11
      *
    
    12 12
      * ---------------------------------------------------------------------------*/
    
    ... ... @@ -25,7 +25,9 @@
    25 25
     //         registers EAX, EDX, and ECX instead of on the stack. Functions that
    
    26 26
     //         take a variable number of arguments will continue to be passed all of
    
    27 27
     //         their arguments on the stack.
    
    28
    -#if __GNUC__ >= 2 && (defined(x86_64_HOST_ARCH) || defined(i386_HOST_ARCH))
    
    28
    +// On x86-64 the attribute has no effect (the first argument is already
    
    29
    +// passed in a register) and GCC 16 warns that it is ignored.
    
    30
    +#if defined(i386_HOST_ARCH)
    
    29 31
     #define REGPARM1 __attribute__((regparm(1)))
    
    30 32
     #else
    
    31 33
     #define REGPARM1
    

  • testsuite/driver/testlib.py
    ... ... @@ -2723,7 +2723,19 @@ def normalise_errmsg(s: str) -> str:
    2723 2723
         # clang may warn about unused argument when used as assembler
    
    2724 2724
         s = re.sub('.*warning: argument unused during compilation:.*\n', '', s)
    
    2725 2725
         # Emscripten displays cache info and old emcc doesn't support EMCC_LOGGING=0
    
    2726
    -    s = re.sub('cache:INFO: .*\n', '', s)
    
    2726
    +    s = drop_lines_containing(s, 'cache:INFO:')
    
    2727
    +    # Old emcc warns when we export HEAP8 but new one requires it (see #26290)
    
    2728
    +    s = s.replace('warning: invalid item in EXPORTED_RUNTIME_METHODS: HEAP8\nwarning: invalid item in EXPORTED_RUNTIME_METHODS: HEAPU8\nemcc: warning: warnings in JS library compilation [-Wjs-compiler]\n','')
    
    2729
    +
    
    2730
    +    if opsys('darwin'):
    
    2731
    +        # on newer versions of MacOS X, the shipped ranlib warns about object files with no symbols,
    
    2732
    +        # however, these are completely benign stubs.
    
    2733
    +        # See https://gitlab.haskell.org/ghc/ghc/-/issues/27116
    
    2734
    +        s = modify_lines(s, lambda l: re.sub(r'.*ranlib:.*has no symbols', '', l))
    
    2735
    +        # we also want to remove linker warnings having to do with undefined dynamic_lookup in combination with
    
    2736
    +        # making a single weak symbol undefined as this is dependent on other linker flags
    
    2737
    +        # See also https://github.com/haskell/process/pull/377
    
    2738
    +        s = drop_lines_containing(s, 'ld: warning: -U option is redundant when using -undefined dynamic_lookup')
    
    2727 2739
     
    
    2728 2740
         return s
    
    2729 2741
     
    

  • testsuite/tests/codeGen/should_run/T27046.hs
    1
    +{-# LANGUAGE MagicHash #-}
    
    2
    +{-# LANGUAGE ForeignFunctionInterface, GHCForeignImportPrim, UnliftedFFITypes #-}
    
    3
    +
    
    4
    +module Main where
    
    5
    +
    
    6
    +import Control.Monad
    
    7
    +  ( unless )
    
    8
    +import Data.Bits
    
    9
    +  ( shiftL )
    
    10
    +import GHC.Exts
    
    11
    +  ( Int64# )
    
    12
    +import GHC.Int
    
    13
    +  ( Int64(..) )
    
    14
    +
    
    15
    +foreign import prim "test_mul2_clobber"
    
    16
    +  test_mul2_clobber :: Int64# -> Int64# -> Int64#
    
    17
    +
    
    18
    +main :: IO ()
    
    19
    +main = do
    
    20
    +  let
    
    21
    +    I64# x = 1 `shiftL` 32
    
    22
    +    hi = I64# $ test_mul2_clobber x x
    
    23
    +
    
    24
    +  unless ( hi == 1 ) $
    
    25
    +    error $ unlines
    
    26
    +      [ "Incorrect result for Mul2 operation."
    
    27
    +      , "Expected high word: 1"
    
    28
    +      , "  Actual high word: " ++ show hi
    
    29
    +      ]

  • testsuite/tests/codeGen/should_run/T27046_cmm.cmm
    1
    +#include "Cmm.h"
    
    2
    +
    
    3
    +// Test for #27046
    
    4
    +test_mul2_clobber (bits64 x, bits64 y)
    
    5
    +{
    
    6
    +    bits64 hi, nd;
    
    7
    +
    
    8
    +    // Deliberately alias the destination 'lo' with the source 'x'
    
    9
    +    // This forces the NCG to use the same virtual register for both.
    
    10
    +    (nd, hi, x) = prim %mul2_64(x, y);
    
    11
    +
    
    12
    +    return (hi);
    
    13
    +}

  • testsuite/tests/codeGen/should_run/all.T
    ... ... @@ -253,6 +253,13 @@ test('T24893', normal, compile_and_run, ['-O'])
    253 253
     test('T26061', normal, compile_and_run, [''])
    
    254 254
     test('T26537', normal, compile_and_run, ['-O2 -fregs-graph'])
    
    255 255
     test('T24016', normal, compile_and_run, ['-O1 -fPIC'])
    
    256
    +test('T27046',
    
    257
    +     [ req_cmm
    
    258
    +     , when(arch('i386'), skip) # i386 does not support MO_S_Mul2 W64
    
    259
    +     , when(arch('wasm32'), skip)
    
    260
    +     , js_skip
    
    261
    +     , when(unregisterised(), skip) # pprCallishMachOp_for_C: MO_S_Mul2 W64 not supported
    
    262
    +     ], compile_and_run, ['T27046_cmm.cmm'])
    
    256 263
     
    
    257 264
     # Check that GHC-generated finalizers run on Darwin. The Apple linker doesn't
    
    258 265
     # support --wrap, so we can't intercept hs_spt_remove directly.  Instead we