Theory TSO_Code_Gen

(*<*)
theory TSO_Code_Gen
imports
  TSO
begin

(*>*)
subsection ‹ Code generator setup for TSO \label{sec:tso-code_generation} ›

text‹

The following is only sound if the generated code runs on a machine with a TSO memory model such as:
  x86
  x86 code running on macOS under Rosetta 2 (ask Google)

Notes:
  Haskell: GHC exposes unfenced operations for references and some kinds of arrays
   GHC has a zoo of arrays; for now we use the general but inefficient boxed array type
  SML: Poly/ML appears to have committed to release/acquire (see email with subject ``Git master update: ARM64, PIE and new bootstrap process'')
   on x86 this is TSO
  Scala: beyond the scope of this work

TODO:
  support a ‹CAS›-like operation
   Haskell: 🌐‹https://stackoverflow.com/questions/10102881/haskell-how-does-atomicmodifyioref-work›


subsubsection ‹Haskell›

text‹

Adaption layer

›

code_printing code_module "TSOHeap"  (Haskell)
‹
module TSOHeap (
    TSO
  , IORef, newIORef, readIORef, writeIORef
  , Array, newArray, newListArray, newFunArray, lengthArray, readArray, writeArray
  , parallel
  ) where

import Control.Concurrent (forkIO)
import qualified Control.Concurrent.MVar as MVar
import qualified Data.Array.IO as Array -- FIXME boxed, contemplate the menagerie of other arrays; perhaps type families might help here
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.List (genericLength)

type TSO a = IO a
type Array a = Array.IOArray Integer a
type Ref a = Data.IORef.IORef a

writeIORef :: IORef a -> a -> IO ()
writeIORef = writeIORef -- FIXME strict variant?

newArray :: Integer -> a -> IO (Array a)
newArray k = Array.newArray (0, k - 1)

newListArray :: [a] -> IO (Array a)
newListArray xs = Array.newListArray (0, genericLength xs - 1) xs

newFunArray :: Integer -> (Integer -> a) -> IO (Array a)
newFunArray k f = Array.newListArray (0, k - 1) (map f [0..k-1])

lengthArray :: Array a -> IO Integer
lengthArray a = Array.getBounds a >>= return . (\(_, l) -> l + 1)

readArray :: Array a -> Integer -> IO a
readArray = Array.readArray

writeArray :: Array a -> Integer -> a -> IO ()
writeArray = Array.writeArray

-- note we don't want "forkFinally" as we don't model exceptions
parallel :: IO () -> IO () -> IO ()
parallel p q = do
  mvar <- MVar.newEmptyMVar
  forkIO (p >> MVar.putMVar mvar ()) -- FIXME putMVar is lazy
  b <- q
  a <- MVar.takeMVar mvar
  return ()
›

code_reserved Haskell TSOHeap

text ‹Monad›

code_printing type_constructor tso  (Haskell) "TSOHeap.TSO _"
code_monad tso.bind Haskell
code_printing constant tso.return  (Haskell) "return"
code_printing constant tso.raise  (Haskell) "error"
code_printing constant tso.parallel  (Haskell) "TSOHeap.parallel"

text ‹Intermediate operation avoids invariance problem in Scala› (similar to value restriction)›

setup Sign.mandatory_path "tso.Ref"

definition ref' where
  [code del]: "ref' = tso.Ref.ref"

lemma [code]:
  "tso.Ref.ref x = tso.Ref.ref' x"
  by (simp add: tso.Ref.ref'_def)

setup Sign.parent_path

text ‹Haskell›

code_printing type_constructor ref  (Haskell) "TSOHeap.Ref _"
code_printing constant Ref  (Haskell) "error/ \"bare Ref\""
code_printing constant tso.Ref.ref'  (Haskell) "TSOHeap.newIORef"
code_printing constant tso.Ref.lookup  (Haskell) "TSOHeap.readIORef"
code_printing constant tso.Ref.update  (Haskell) "TSOHeap.writeIORef"
code_printing constant "HOL.equal :: 'a ref  'a ref  bool"  (Haskell) infix 4 "=="
code_printing class_instance ref :: HOL.equal  (Haskell) -

(*<*)

end
(*>*)