Skip to content

Constant folding for division operations (`quotRem` and `divMod`)

Motivation

I recently noticed that with GHC-9.2 and GHC-9.4 x `quot` 60 `quot` 60 doesn't get constant folded to x `quot` 3600.

I realised this as I wanted to write a module like the following and expected the function toHours to be optimised to just a single division, but we get two.

{-# OPTIONS_GHC -O2 -ddump-simpl -ddump-to-file -ddump-stg-final #-}
module Time where

{-# INLINE toHoursMinutesSeconds #-}
toHoursMinutesSeconds :: Int -> (Int, Int, Int)
toHoursMinutesSeconds t = (h, m', s)
  where
    (h, m') = m `quotRem` 60
    (m, s) = toMinutesSeconds t

toMinutesSeconds :: Int -> (Int, Int)
toMinutesSeconds t = t `quotRem` 60

toHours t = h
  where
    (h, _, _) = toHoursMinutesSeconds t

Proposal

Add constant folding rules for quotRem and divMod for repeated division where the remainder is not used, ie, x `quot` y `quot` z = x `quot` (y * z) and that multiplication is done at compile time.

Edited by Teo Camarasu
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information