-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for anoma-encode builtin (#2766)
This PR adds support for the `anoma-encode` builtin: ``` builtin anoma-encode axiom anomaEncode : {A : Type} -> A -> Nat ``` In the backend this is compiled to a call to the Anoma / nockma stdlib `jam` function. This PR also contains: * An implementation of the `jam` function in Haskell. This is used in the Nockma evaluator. * Unit tests for `jam` * A benchmark for `jam` applied to the Anoma / nockma stdlib. Benchmark results: ``` $ juvixbench -p 'Jam' All Nockma Jam jam stdlib: OK 109 ms ± 6.2 ms ```
- Loading branch information
1 parent
6d660f5
commit 1ab94f5
Showing
35 changed files
with
388 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module Benchmark.Nockma where | ||
|
||
import Benchmark.Nockma.Encoding qualified as NockmaEncoding | ||
import Test.Tasty.Bench | ||
|
||
bm :: Benchmark | ||
bm = | ||
bgroup | ||
"Nockma" | ||
[ NockmaEncoding.bm | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
module Benchmark.Nockma.Encoding where | ||
|
||
import Juvix.Compiler.Nockma.Encoding | ||
import Juvix.Compiler.Nockma.Language | ||
import Juvix.Compiler.Nockma.Stdlib (stdlib) | ||
import Juvix.Prelude.Base | ||
import Test.Tasty.Bench | ||
|
||
bm :: Benchmark | ||
bm = | ||
bgroup | ||
"Jam" | ||
[bench "jam stdlib" $ nf runJam stdlib] | ||
|
||
runJam :: Term Natural -> Natural | ||
runJam = | ||
(^. atom) | ||
. fromRight (error "jam failed") | ||
. run | ||
. runError @NockNaturalNaturalError | ||
. jam |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,13 @@ | ||
module Main where | ||
|
||
import Benchmark.Effect qualified as Effect | ||
import Benchmark.Nockma qualified as Nockma | ||
import Juvix.Prelude | ||
import Test.Tasty.Bench | ||
|
||
main :: IO () | ||
main = | ||
defaultMain | ||
[ Effect.bm | ||
[ Effect.bm, | ||
Nockma.bm | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module Juvix.Compiler.Nockma.Encoding | ||
( module Juvix.Compiler.Nockma.Encoding.Jam, | ||
) | ||
where | ||
|
||
import Juvix.Compiler.Nockma.Encoding.Jam |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
module Juvix.Compiler.Nockma.Encoding.Base where | ||
|
||
import Data.Bit as Bit | ||
import Data.Bits | ||
import Data.Vector.Unboxed qualified as U | ||
import Juvix.Compiler.Nockma.Encoding.Effect.BitWriter | ||
import Juvix.Prelude.Base | ||
|
||
-- | Binary encode an integer to a vector of bits, ordered from least to most significant bits. | ||
-- NB: 0 is encoded as the empty bit vector is specified by the Hoon serialization spec | ||
writeIntegral :: forall a r. (Integral a, Member BitWriter r) => a -> Sem r () | ||
writeIntegral x | ||
| x < 0 = error "integerToVectorBits: negative integers are not supported in this implementation" | ||
| otherwise = unfoldBits (fromIntegral x) | ||
where | ||
unfoldBits :: Integer -> Sem r () | ||
unfoldBits n | ||
| n == 0 = return () | ||
| otherwise = writeBit (Bit (testBit n 0)) <> unfoldBits (n `shiftR` 1) | ||
|
||
integerToVectorBits :: (Integral a) => a -> Bit.Vector Bit | ||
integerToVectorBits = run . execBitWriter . writeIntegral | ||
|
||
-- | Computes the number of bits required to store the argument in binary | ||
-- NB: 0 is encoded to the empty bit vector (as specified by the Hoon serialization spec), so 0 has bit length 0. | ||
bitLength :: forall a. (Integral a) => a -> Int | ||
bitLength = \case | ||
0 -> 0 | ||
n -> go (fromIntegral n) 0 | ||
where | ||
go :: Integer -> Int -> Int | ||
go 0 acc = acc | ||
go x acc = go (x `shiftR` 1) (acc + 1) | ||
|
||
-- | Decode a vector of bits (ordered from least to most significant bits) to an integer | ||
vectorBitsToInteger :: Bit.Vector Bit -> Integer | ||
vectorBitsToInteger = U.ifoldl' go 0 | ||
where | ||
go :: Integer -> Int -> Bit -> Integer | ||
go acc idx (Bit b) | ||
| b = setBit acc idx | ||
| otherwise = acc | ||
|
||
-- | Transform a Natural to an Int, computes Nothing if the Natural does not fit in an Int | ||
safeNaturalToInt :: Natural -> Maybe Int | ||
safeNaturalToInt n | ||
| n > fromIntegral (maxBound :: Int) = Nothing | ||
| otherwise = Just (fromIntegral n) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
module Juvix.Compiler.Nockma.Encoding.Effect.BitWriter where | ||
|
||
import Data.Bit as Bit | ||
import Juvix.Prelude.Base | ||
import VectorBuilder.Builder as Builder | ||
import VectorBuilder.Vector | ||
|
||
data BitWriter :: Effect where | ||
WriteBit :: Bit -> BitWriter m () | ||
GetCurrentPosition :: BitWriter m Int | ||
|
||
makeSem ''BitWriter | ||
|
||
writeOne :: (Member BitWriter r) => Sem r () | ||
writeOne = writeBit (Bit True) | ||
|
||
writeZero :: (Member BitWriter r) => Sem r () | ||
writeZero = writeBit (Bit False) | ||
|
||
newtype WriterState = WriterState | ||
{ _writerStateBuilder :: Builder Bit | ||
} | ||
|
||
makeLenses ''WriterState | ||
|
||
initWriterState :: WriterState | ||
initWriterState = WriterState {_writerStateBuilder = mempty} | ||
|
||
runBitWriter :: forall a r. Sem (BitWriter ': r) a -> Sem r (Bit.Vector Bit, a) | ||
runBitWriter sem = do | ||
(s, res) <- runState initWriterState (re sem) | ||
return (build (s ^. writerStateBuilder), res) | ||
|
||
execBitWriter :: forall a r. Sem (BitWriter ': r) a -> Sem r (Bit.Vector Bit) | ||
execBitWriter sem = do | ||
s <- execState initWriterState (re sem) | ||
return (build (s ^. writerStateBuilder)) | ||
|
||
re :: Sem (BitWriter ': r) a -> Sem (State WriterState ': r) a | ||
re = interpretTop $ \case | ||
WriteBit b -> writeBit' b | ||
GetCurrentPosition -> getCurrentPosition' | ||
|
||
writeBit' :: (Member (State WriterState) r) => Bit -> Sem r () | ||
writeBit' b = modify appendBit | ||
where | ||
appendBit :: WriterState -> WriterState | ||
appendBit = over writerStateBuilder (<> Builder.singleton b) | ||
|
||
getCurrentPosition' :: (Member (State WriterState) r) => Sem r Int | ||
getCurrentPosition' = Builder.size <$> gets (^. writerStateBuilder) |
Oops, something went wrong.