Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
c2989784 by sheaf at 2026-06-04T13:07:45-04:00
Fix AArch64 clobbering bug for MUL2
On AArch64, the code generator could clobber one of the input operands
when computing the lower bits of a MUL2 operation. This rendered invalid
the subsequent computation of the high bits.
This commit fixes that by using a temporary register. The register
allocator can remove the redundant move in the common case when the
registers do not conflict.
Fixes #27046
- - - - -
e834d92a by Simon Jakobi at 2026-06-04T13:07:46-04:00
testsuite: Deduplicate --only test names
config.only is assumed to be a set, but supplying --only overwrote it
with the (list) argparse result, which can contain duplicates. When a
test ran, config.only.remove(name) dropped only the first occurrence,
so a duplicated name lingered and was later misreported as a
"test not found" framework failure. Store it as a set instead.
Fixes #27322
Co-Authored-By: Claude Opus 4.7
- - - - -
6 changed files:
- + changelog.d/T27046
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- testsuite/driver/runtests.py
- + testsuite/tests/codeGen/should_run/T27046.hs
- + testsuite/tests/codeGen/should_run/T27046_cmm.cmm
- testsuite/tests/codeGen/should_run/all.T
Changes:
=====================================
changelog.d/T27046
=====================================
@@ -0,0 +1,9 @@
+section: compiler
+issues: #27046
+mrs: !16031
+synopsis:
+ Avoid AArch64 register clobbering bug in MUL2
+description:
+ Fixes an issue in which, on AArch64, code generation for the MUL2 operation
+ could clobber one of the input operands when computing the lower bits, which
+ rendered invalid the subsequent computation of the high bits.
=====================================
compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
=====================================
@@ -2300,11 +2300,19 @@ genCCall target dest_regs arg_regs = do
let lo = getRegisterReg platform (CmmLocal dst_lo)
hi = getRegisterReg platform (CmmLocal dst_hi)
nd = getRegisterReg platform (CmmLocal dst_needed)
+
+ -- Generate a fresh virtual register for the low word computation.
+ -- This avoids clobbering reg_a or reg_b in the first MUL instruction,
+ -- which could for example happen if 'lo' and 'reg_a' are the same
+ -- virtual register.
+ tmp_lo <- getNewRegNat II64
+
return $
code_x `appOL`
code_y `snocOL`
- MUL II64 (OpReg W64 lo) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
+ MUL II64 (OpReg W64 tmp_lo) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
SMULH (OpReg W64 hi) (OpReg W64 reg_a) (OpReg W64 reg_b) `snocOL`
+ MOV (OpReg W64 lo) (OpReg W64 tmp_lo) `snocOL`
-- Are all high bits equal to the sign bit of the low word?
-- nd = (hi == ASR(lo,width-1)) ? 1 : 0
CMP (OpReg W64 hi) (OpRegShift W64 lo SASR (widthInBits w - 1)) `snocOL`
=====================================
testsuite/driver/runtests.py
=====================================
@@ -133,7 +133,7 @@ if args.unexpected_output_dir:
config.unexpected_output_dir = Path(args.unexpected_output_dir)
if args.only:
- config.only = args.only
+ config.only = set(args.only)
config.run_only_some_tests = True
if args.skip:
=====================================
testsuite/tests/codeGen/should_run/T27046.hs
=====================================
@@ -0,0 +1,29 @@
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE ForeignFunctionInterface, GHCForeignImportPrim, UnliftedFFITypes #-}
+
+module Main where
+
+import Control.Monad
+ ( unless )
+import Data.Bits
+ ( shiftL )
+import GHC.Exts
+ ( Int64# )
+import GHC.Int
+ ( Int64(..) )
+
+foreign import prim "test_mul2_clobber"
+ test_mul2_clobber :: Int64# -> Int64# -> Int64#
+
+main :: IO ()
+main = do
+ let
+ I64# x = 1 `shiftL` 32
+ hi = I64# $ test_mul2_clobber x x
+
+ unless ( hi == 1 ) $
+ error $ unlines
+ [ "Incorrect result for Mul2 operation."
+ , "Expected high word: 1"
+ , " Actual high word: " ++ show hi
+ ]
=====================================
testsuite/tests/codeGen/should_run/T27046_cmm.cmm
=====================================
@@ -0,0 +1,13 @@
+#include "Cmm.h"
+
+// Test for #27046
+test_mul2_clobber (bits64 x, bits64 y)
+{
+ bits64 hi, nd;
+
+ // Deliberately alias the destination 'lo' with the source 'x'
+ // This forces the NCG to use the same virtual register for both.
+ (nd, hi, x) = prim %mul2_64(x, y);
+
+ return (hi);
+}
=====================================
testsuite/tests/codeGen/should_run/all.T
=====================================
@@ -260,6 +260,7 @@ test('T25364', normal, compile_and_run, [''])
test('T26061', normal, compile_and_run, [''])
test('T26537', normal, compile_and_run, ['-O2 -fregs-graph'])
test('T24016', normal, compile_and_run, ['-O1 -fPIC'])
+test('T27046', [req_cmm], compile_and_run, ['T27046_cmm.cmm'])
# Check that GHC-generated finalizers run on Darwin. The Apple linker doesn't
# support --wrap, so we can't intercept hs_spt_remove directly. Instead we
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c19aa850a1a18161cfb25ecf4781fae...
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c19aa850a1a18161cfb25ecf4781fae...
You're receiving this email because of your account on gitlab.haskell.org.