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 drop]: "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
(*>*)