{-# LANGUAGE CPP, MagicHash, UnboxedTuples, NoImplicitPrelude #-}
{-# OPTIONS_HADDOCK hide #-}
#include "MachDeps.h"
module GHC.Integer.Logarithms.Internals
( integerLog2#
, integerLog2IsPowerOf2#
, wordLog2#
, roundingMode#
) where
import GHC.Prim
import GHC.Types (isTrue#)
import GHC.Integer.Type
#if (WORD_SIZE_IN_BITS != 32) && (WORD_SIZE_IN_BITS != 64)
import GHC.Integer
default ()
wordLog2# :: Word# -> Int#
wordLog2# w = go 8# w
where
go acc u = case u `uncheckedShiftRL#` 8# of
0## -> case leadingZeros of
BA ba -> acc -# indexInt8Array# ba (word2Int# u)
v -> go (acc +# 8#) v
integerLog2# :: Integer -> Int#
integerLog2# (S# i) = wordLog2# (int2Word# i)
integerLog2# m = case step m (smallInteger 2#) 1# of
(# _, l #) -> l
where
step n pw lg =
if n `ltInteger` pw
then (# n, 0# #)
else case step n (shiftLInteger pw lg) (2# *# lg) of
(# q, e #) ->
if q `ltInteger` pw
then (# q, 2# *# e #)
else (# q `shiftRInteger` lg, 2# *# e +# 1# #)
integerLog2IsPowerOf2# :: Integer -> (# Int#, Int# #)
integerLog2IsPowerOf2# m =
case integerLog2# m of
lg -> if m `eqInteger` (smallInteger 1# `shiftLInteger` lg)
then (# lg, 0# #)
else (# lg, 1# #)
roundingMode# :: Integer -> Int# -> Int#
roundingMode# m h =
case smallInteger 1# `shiftLInteger` h of
c -> case m `andInteger`
((c `plusInteger` c) `minusInteger` smallInteger 1#) of
r ->
if c `ltInteger` r
then 2#
else if c `gtInteger` r
then 0#
else 1#
#else
default ()
#if WORD_SIZE_IN_BITS == 32
#define WSHIFT 5
#define MMASK 31
#else
#define WSHIFT 6
#define MMASK 63
#endif
integerLog2# :: Integer -> Int#
integerLog2# (S# i) = wordLog2# (int2Word# i)
integerLog2# (J# s ba) = check (s -# 1#)
where
check i = case indexWordArray# ba i of
0## -> check (i -# 1#)
w -> wordLog2# w +# (uncheckedIShiftL# i WSHIFT#)
integerLog2IsPowerOf2# :: Integer -> (# Int#, Int# #)
integerLog2IsPowerOf2# (S# i) =
case int2Word# i of
w -> (# wordLog2# w, word2Int# (w `and#` (w `minusWord#` 1##)) #)
integerLog2IsPowerOf2# (J# s ba) = check (s -# 1#)
where
check :: Int# -> (# Int#, Int# #)
check i = case indexWordArray# ba i of
0## -> check (i -# 1#)
w -> (# wordLog2# w +# (uncheckedIShiftL# i WSHIFT#)
, case w `and#` (w `minusWord#` 1##) of
0## -> test (i -# 1#)
_ -> 1# #)
test :: Int# -> Int#
test i = if isTrue# (i <# 0#)
then 0#
else case indexWordArray# ba i of
0## -> test (i -# 1#)
_ -> 1#
roundingMode# :: Integer -> Int# -> Int#
roundingMode# (S# i) t =
case int2Word# i `and#` ((uncheckedShiftL# 2## t) `minusWord#` 1##) of
k -> case uncheckedShiftL# 1## t of
c -> if isTrue# (c `gtWord#` k)
then 0#
else if isTrue# (c `ltWord#` k)
then 2#
else 1#
roundingMode# (J# _ ba) t =
case word2Int# (int2Word# t `and#` MMASK##) of
j ->
case uncheckedIShiftRA# t WSHIFT# of
k ->
case indexWordArray# ba k `and#`
((uncheckedShiftL# 2## j) `minusWord#` 1##) of
r ->
case uncheckedShiftL# 1## j of
c -> if isTrue# (c `gtWord#` r)
then 0#
else if isTrue# (c `ltWord#` r)
then 2#
else test (k -# 1#)
where
test i = if isTrue# (i <# 0#)
then 1#
else case indexWordArray# ba i of
0## -> test (i -# 1#)
_ -> 2#
{-# INLINE wordLog2# #-}
wordLog2# :: Word# -> Int#
wordLog2# w =
case leadingZeros of
BA lz ->
let zeros u = indexInt8Array# lz (word2Int# u) in
#if WORD_SIZE_IN_BITS == 64
case uncheckedShiftRL# w 56# of
a ->
if isTrue# (a `neWord#` 0##)
then 64# -# zeros a
else
case uncheckedShiftRL# w 48# of
b ->
if isTrue# (b `neWord#` 0##)
then 56# -# zeros b
else
case uncheckedShiftRL# w 40# of
c ->
if isTrue# (c `neWord#` 0##)
then 48# -# zeros c
else
case uncheckedShiftRL# w 32# of
d ->
if isTrue# (d `neWord#` 0##)
then 40# -# zeros d
else
#endif
case uncheckedShiftRL# w 24# of
e ->
if isTrue# (e `neWord#` 0##)
then 32# -# zeros e
else
case uncheckedShiftRL# w 16# of
f ->
if isTrue# (f `neWord#` 0##)
then 24# -# zeros f
else
case uncheckedShiftRL# w 8# of
g ->
if isTrue# (g `neWord#` 0##)
then 16# -# zeros g
else 8# -# zeros w
#endif
data BA = BA ByteArray#
leadingZeros :: BA
leadingZeros =
let mkArr s =
case newByteArray# 256# s of
(# s1, mba #) ->
case writeInt8Array# mba 0# 9# s1 of
s2 ->
let fillA lim val idx st =
if isTrue# (idx ==# 256#)
then st
else if isTrue# (idx <# lim)
then case writeInt8Array# mba idx val st of
nx -> fillA lim val (idx +# 1#) nx
else fillA (2# *# lim) (val -# 1#) idx st
in case fillA 2# 8# 1# s2 of
s3 -> case unsafeFreezeByteArray# mba s3 of
(# _, ba #) -> ba
in case mkArr realWorld# of
b -> BA b