summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2022-06-15 10:56:52 -0400
committerZubin Duggal <zubin.duggal@gmail.com>2022-07-11 11:25:55 +0530
commit13deefd69948e86d6605defed263122fddef5099 (patch)
treee127190c3b045e386857b39c7901f6f9f6334bf0
parent66ee5a7220e3a0388e8c13f9fca05334a5d986e1 (diff)
downloadhaskell-13deefd69948e86d6605defed263122fddef5099.tar.gz
ncg/aarch64: Fix implementation of IntMulMayOflo
The code generated for IntMulMayOflo was previously wrong as it depended upon the overflow flag, which the AArch64 MUL instruction does not set. Fix this. Fixes #21624. (cherry picked from commit a1e1d8eecceaa2fa64668376d5ea44990d94a3ea)
-rw-r--r--compiler/GHC/CmmToAsm/AArch64/CodeGen.hs42
1 files changed, 41 insertions, 1 deletions
diff --git a/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs b/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
index 07216c90d3..06cacc664a 100644
--- a/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
+++ b/compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
@@ -893,7 +893,7 @@ getRegister' config plat expr
-- Signed multiply/divide
MO_Mul w -> intOp True w (\d x y -> unitOL $ MUL d x y)
- MO_S_MulMayOflo w -> intOp True w (\d x y -> toOL [ MUL d x y, CSET d VS ])
+ MO_S_MulMayOflo w -> do_mul_may_oflo w x y
MO_S_Quot w -> intOp True w (\d x y -> unitOL $ SDIV d x y)
-- No native rem instruction. So we'll compute the following
@@ -978,6 +978,46 @@ getRegister' config plat expr
,0b0111_1111, 0b1111_1110
,0b1111_1111]
+ -- N.B. MUL does not set the overflow flag.
+ do_mul_may_oflo :: Width -> CmmExpr -> CmmExpr -> NatM Register
+ do_mul_may_oflo w@W64 x y = do
+ (reg_x, _format_x, code_x) <- getSomeReg x
+ (reg_y, _format_y, code_y) <- getSomeReg y
+ lo <- getNewRegNat II64
+ hi <- getNewRegNat II64
+ return $ Any (intFormat w) (\dst ->
+ code_x `appOL`
+ code_y `snocOL`
+ MUL (OpReg w lo) (OpReg w reg_x) (OpReg w reg_y) `snocOL`
+ SMULH (OpReg w hi) (OpReg w reg_x) (OpReg w reg_y) `snocOL`
+ CMP (OpReg w hi) (OpRegShift w lo SASR 63) `snocOL`
+ CSET (OpReg w dst) NE)
+ do_mul_may_oflo w x y = do
+ (reg_x, _format_x, code_x) <- getSomeReg x
+ (reg_y, _format_y, code_y) <- getSomeReg y
+ let tmp_w = case w of
+ W32 -> W64
+ W16 -> W32
+ W8 -> W32
+ _ -> panic "do_mul_may_oflo: impossible"
+ -- This will hold the product
+ tmp <- getNewRegNat (intFormat tmp_w)
+ let ext_mode = case w of
+ W32 -> ESXTW
+ W16 -> ESXTH
+ W8 -> ESXTB
+ _ -> panic "do_mul_may_oflo: impossible"
+ mul = case w of
+ W32 -> SMULL
+ W16 -> MUL
+ W8 -> MUL
+ _ -> panic "do_mul_may_oflo: impossible"
+ return $ Any (intFormat w) (\dst ->
+ code_x `appOL`
+ code_y `snocOL`
+ mul (OpReg tmp_w tmp) (OpReg w reg_x) (OpReg w reg_y) `snocOL`
+ CMP (OpReg tmp_w tmp) (OpRegExt tmp_w tmp ext_mode 0) `snocOL`
+ CSET (OpReg w dst) NE)
-- | Instructions to sign-extend the value in the given register from width @w@
-- up to width @w'@.