diff options
author | Ben Gamari <ben@smart-cactus.org> | 2022-06-15 10:56:52 -0400 |
---|---|---|
committer | Zubin Duggal <zubin.duggal@gmail.com> | 2022-07-11 11:25:55 +0530 |
commit | 13deefd69948e86d6605defed263122fddef5099 (patch) | |
tree | e127190c3b045e386857b39c7901f6f9f6334bf0 | |
parent | 66ee5a7220e3a0388e8c13f9fca05334a5d986e1 (diff) | |
download | haskell-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.hs | 42 |
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'@. |