[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 2 commits: Fix AArch64 clobbering bug for MUL2
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 <noreply@anthropic.com> - - - - - 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.
participants (1)
-
Marge Bot (@marge-bot)