From 4c37c683bcd63b3c7ee1c8c2294602ae5ee60d12 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Fri, 1 Feb 2019 16:48:42 -0500 Subject: [PATCH 01/12] initial stab at adding construct for readByteArray --- CrossCodegen.hs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CrossCodegen.hs b/CrossCodegen.hs index 06c3911..a26942d 100644 --- a/CrossCodegen.hs +++ b/CrossCodegen.hs @@ -226,6 +226,17 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke (\i -> "(\\hsc_ptr -> peekByteOff hsc_ptr " ++ show i ++ ")") >> return False "poke" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> pokeByteOff hsc_ptr " ++ show i ++ ")") >> return False + "read" -> case break (== ',') value of + (typ,',':field) -> do + byteOffset <- computeConst z ("offsetof(" ++ value ++ ")") + -- This is the FIELD_SIZEOF macro as defined in the linux kernel. + fieldSize <- computeConst z ("sizeof(((" ++ typ ++ "*)0)->" ++ field ++ ")") + when (not (isPowerOfTwo fieldSize)) (testFail pos ("#error " ++ value)) + let (elemOffset,remainder) = divMod byteOffset fieldSize + when (remainder /= 0) (testFail pos ("#error " ++ value)) + output ("(\\hsc_ptr -> readByteArray hsc_ptr " ++ show elemOffset ++ ")") + return False + _ -> testFail pos ("#error " ++ value) "ptr" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> hsc_ptr `plusPtr` " ++ show i ++ ")") >> return False "type" -> computeType z >>= output >> return False @@ -406,6 +417,12 @@ binarySearch z nonNegative l u = do u'-l' < u-l) -- @|u' - l'| < |u - l|@ (binarySearch z nonNegative l' u') +isPowerOfTwo :: Integer -> Bool +isPowerOfTwo 0 = False +isPowerOfTwo 1 = True +isPowerOfTwo n = case divMod n 2 of + (m,r) -> if r == 0 then isPowerOfTwo m else False + -- Establishes bounds on the unknown integer. By searching increasingly -- large powers of 2, it'll bracket an integer x by lower & upper -- such that lower <= x <= upper. From 17bf52c81d70cba5aebf5d58785e769caa96f622 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Sun, 3 Feb 2019 09:54:36 -0500 Subject: [PATCH 02/12] Make indexByteArray, readByteArray, and writeByteArray all work correctly when doing cross compilation. Factor out common code. --- CrossCodegen.hs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/CrossCodegen.hs b/CrossCodegen.hs index a26942d..e58b4ca 100644 --- a/CrossCodegen.hs +++ b/CrossCodegen.hs @@ -226,17 +226,9 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke (\i -> "(\\hsc_ptr -> peekByteOff hsc_ptr " ++ show i ++ ")") >> return False "poke" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> pokeByteOff hsc_ptr " ++ show i ++ ")") >> return False - "read" -> case break (== ',') value of - (typ,',':field) -> do - byteOffset <- computeConst z ("offsetof(" ++ value ++ ")") - -- This is the FIELD_SIZEOF macro as defined in the linux kernel. - fieldSize <- computeConst z ("sizeof(((" ++ typ ++ "*)0)->" ++ field ++ ")") - when (not (isPowerOfTwo fieldSize)) (testFail pos ("#error " ++ value)) - let (elemOffset,remainder) = divMod byteOffset fieldSize - when (remainder /= 0) (testFail pos ("#error " ++ value)) - output ("(\\hsc_ptr -> readByteArray hsc_ptr " ++ show elemOffset ++ ")") - return False - _ -> testFail pos ("#error " ++ value) + "read" -> outputByteArrayOperation "readByteArray" + "write" -> outputByteArrayOperation "writeByteArray" + "index" -> outputByteArrayOperation "indexByteArray" "ptr" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> hsc_ptr `plusPtr` " ++ show i ++ ")") >> return False "type" -> computeType z >>= output >> return False @@ -247,7 +239,23 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke "define" -> return True "undef" -> return True _ -> testFail pos ("directive " ++ key ++ " cannot be handled in cross-compilation mode") - where outputConst value' formatter = computeConst z value' >>= (output . formatter) + where + outputConst value' formatter = computeConst z value' >>= (output . formatter) + -- GHC's ByteArray# type only supports read/write/index in an aligned + -- fashion. The index is always given in elements, not bytes. So, we + -- must divide the field's offset in bytes by its size to get index in + -- terms of elements. + outputByteArrayOperation operation = case break (== ',') value of + (typ,',':field) -> do + byteOffset <- computeConst z ("offsetof(" ++ value ++ ")") + -- This is the FIELD_SIZEOF macro as defined in the linux kernel. + fieldSize <- computeConst z ("sizeof(((" ++ typ ++ "*)0)->" ++ field ++ ")") + when (not (isPowerOfTwo fieldSize)) (testFail pos ("#error " ++ value)) + let (elemOffset,remainder) = divMod byteOffset fieldSize + when (remainder /= 0) (testFail pos ("#error " ++ value)) + output ("(\\hsc_ptr -> " ++ operation ++ " hsc_ptr " ++ show elemOffset ++ ")") + return False + _ -> testFail pos ("#error " ++ value) outputSpecial _ _ = error "outputSpecial's argument isn't a Special" outputText :: (Bool, Bool) -> (String -> TestMonad ()) -> SourcePos -> String From 601283ee3f935744d8f8bdfd70924f8c8978a73d Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Sun, 3 Feb 2019 10:12:54 -0500 Subject: [PATCH 03/12] support readByteArray# and writeByteArray# with readHash and writeHash --- CrossCodegen.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CrossCodegen.hs b/CrossCodegen.hs index e58b4ca..3584ce5 100644 --- a/CrossCodegen.hs +++ b/CrossCodegen.hs @@ -229,6 +229,8 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke "read" -> outputByteArrayOperation "readByteArray" "write" -> outputByteArrayOperation "writeByteArray" "index" -> outputByteArrayOperation "indexByteArray" + "readHash" -> outputByteArrayOperation "readByteArray#" + "writeHash" -> outputByteArrayOperation "writeByteArray#" "ptr" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> hsc_ptr `plusPtr` " ++ show i ++ ")") >> return False "type" -> computeType z >>= output >> return False @@ -253,7 +255,7 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke when (not (isPowerOfTwo fieldSize)) (testFail pos ("#error " ++ value)) let (elemOffset,remainder) = divMod byteOffset fieldSize when (remainder /= 0) (testFail pos ("#error " ++ value)) - output ("(\\hsc_ptr -> " ++ operation ++ " hsc_ptr " ++ show elemOffset ++ ")") + output ("(\\hsc_arr -> " ++ operation ++ " hsc_arr " ++ show elemOffset ++ ")") return False _ -> testFail pos ("#error " ++ value) outputSpecial _ _ = error "outputSpecial's argument isn't a Special" From 73afb33f45ffc3b673cecc9a67954be14d4b0a8c Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Sun, 3 Feb 2019 18:20:03 -0500 Subject: [PATCH 04/12] add bytearray operation macros to default hsc template --- template-hsc.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/template-hsc.h b/template-hsc.h index dec0e43..70006c4 100644 --- a/template-hsc.h +++ b/template-hsc.h @@ -23,6 +23,10 @@ void *hsc_stdout(void); #define offsetof(t, f) ((size_t) &((t *)0)->f) #endif +#ifndef FIELD_SIZEOF +#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) +#endif + #if __NHC__ #define hsc_line(line, file) \ hsc_printf ("# %d \"%s\"\n", line, file); @@ -129,3 +133,38 @@ void *hsc_stdout(void); } \ } \ } + +#define hsc_read(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ + hsc_printf ("(\\hsc_arr -> readByteArray hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } + +#define hsc_write(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ + hsc_printf ("(\\hsc_arr -> writeByteArray hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } + +#define hsc_index(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ + hsc_printf ("(\\hsc_arr -> indexByteArray hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } + +#define hsc_readHash(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ + hsc_printf ("(\\hsc_arr -> readByteArray# hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } + +#define hsc_writeHash(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ + hsc_printf ("(\\hsc_arr -> writeByteArray# hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } From 9a892382c75515837aee61eee8731592fc499f25 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Sun, 3 Feb 2019 19:20:37 -0500 Subject: [PATCH 05/12] add bytearray construct as safe for cross compilation --- DirectCodegen.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DirectCodegen.hs b/DirectCodegen.hs index 9bfdd42..25b5a43 100644 --- a/DirectCodegen.hs +++ b/DirectCodegen.hs @@ -58,7 +58,8 @@ outputDirect config outName outDir outBase name toks = do forM_ specials (\ (SourcePos file line _,key,_) -> when (not $ key `elem` ["const","offset","size","alignment","peek","poke","ptr", "type","enum","error","warning","include","define","undef", - "if","ifdef","ifndef", "elif","else","endif"]) $ + "if","ifdef","ifndef", "elif","else","endif", + "read","write","index","readHash","writeHash"]) $ die (file ++ ":" ++ show line ++ " directive \"" ++ key ++ "\" is not safe for cross-compilation")) writeBinaryFile cProgName $ From 3ea6ab019f781d916376ce7204ecef3bbae72f3a Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Sun, 3 Feb 2019 21:05:22 -0500 Subject: [PATCH 06/12] redo bytearray operations to allow them to accept an index --- CrossCodegen.hs | 10 +++++++--- DirectCodegen.hs | 2 +- template-hsc.h | 27 +++++++++++++++++---------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/CrossCodegen.hs b/CrossCodegen.hs index 3584ce5..f8aa70a 100644 --- a/CrossCodegen.hs +++ b/CrossCodegen.hs @@ -231,6 +231,7 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke "index" -> outputByteArrayOperation "indexByteArray" "readHash" -> outputByteArrayOperation "readByteArray#" "writeHash" -> outputByteArrayOperation "writeByteArray#" + "indexHash" -> outputByteArrayOperation "indexByteArray#" "ptr" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> hsc_ptr `plusPtr` " ++ show i ++ ")") >> return False "type" -> computeType z >>= output >> return False @@ -250,12 +251,15 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke outputByteArrayOperation operation = case break (== ',') value of (typ,',':field) -> do byteOffset <- computeConst z ("offsetof(" ++ value ++ ")") + typSize <- computeConst z ("sizeof(" ++ typ ++ ")") -- This is the FIELD_SIZEOF macro as defined in the linux kernel. fieldSize <- computeConst z ("sizeof(((" ++ typ ++ "*)0)->" ++ field ++ ")") when (not (isPowerOfTwo fieldSize)) (testFail pos ("#error " ++ value)) - let (elemOffset,remainder) = divMod byteOffset fieldSize - when (remainder /= 0) (testFail pos ("#error " ++ value)) - output ("(\\hsc_arr -> " ++ operation ++ " hsc_arr " ++ show elemOffset ++ ")") + let (elemOffset,r1) = divMod byteOffset fieldSize + when (r1 /= 0) (testFail pos ("#error " ++ value)) + let (typFieldRatio,r2) = divMod typSize fieldSize + when (r2 /= 0) (testFail pos ("#error " ++ value)) + output ("(\\hsc_arr hsc_ix -> " ++ operation ++ " hsc_arr (" ++ show elemOffset ++ " + (hsc_ix * " ++ show typFieldRatio ++ ")))") return False _ -> testFail pos ("#error " ++ value) outputSpecial _ _ = error "outputSpecial's argument isn't a Special" diff --git a/DirectCodegen.hs b/DirectCodegen.hs index 25b5a43..66f07fc 100644 --- a/DirectCodegen.hs +++ b/DirectCodegen.hs @@ -59,7 +59,7 @@ outputDirect config outName outDir outBase name toks = do when (not $ key `elem` ["const","offset","size","alignment","peek","poke","ptr", "type","enum","error","warning","include","define","undef", "if","ifdef","ifndef", "elif","else","endif", - "read","write","index","readHash","writeHash"]) $ + "read","write","index","readHash","writeHash","indexHash"]) $ die (file ++ ":" ++ show line ++ " directive \"" ++ key ++ "\" is not safe for cross-compilation")) writeBinaryFile cProgName $ diff --git a/template-hsc.h b/template-hsc.h index 70006c4..f43d5fc 100644 --- a/template-hsc.h +++ b/template-hsc.h @@ -135,36 +135,43 @@ void *hsc_stdout(void); } #define hsc_read(t, f) \ - if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ - hsc_printf ("(\\hsc_arr -> readByteArray hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_write(t, f) \ - if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ - hsc_printf ("(\\hsc_arr -> writeByteArray hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_index(t, f) \ - if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ - hsc_printf ("(\\hsc_arr -> indexByteArray hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_readHash(t, f) \ - if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ - hsc_printf ("(\\hsc_arr -> readByteArray# hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeHash(t, f) \ - if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0) { \ - hsc_printf ("(\\hsc_arr -> writeByteArray# hsc_arr %ld)", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f)))); \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } + +#define hsc_indexHash(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } From dec46f811fd93216025ebb8fc9f11033a3404071 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Mon, 4 Feb 2019 08:51:25 -0500 Subject: [PATCH 07/12] rename bytearray constructs and add constructs for readOffAddr# and friends --- CrossCodegen.hs | 15 +++++++++------ DirectCodegen.hs | 12 ++++++++---- template-hsc.h | 33 +++++++++++++++++++++++++++------ 3 files changed, 44 insertions(+), 16 deletions(-) diff --git a/CrossCodegen.hs b/CrossCodegen.hs index f8aa70a..16b8772 100644 --- a/CrossCodegen.hs +++ b/CrossCodegen.hs @@ -226,12 +226,15 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke (\i -> "(\\hsc_ptr -> peekByteOff hsc_ptr " ++ show i ++ ")") >> return False "poke" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> pokeByteOff hsc_ptr " ++ show i ++ ")") >> return False - "read" -> outputByteArrayOperation "readByteArray" - "write" -> outputByteArrayOperation "writeByteArray" - "index" -> outputByteArrayOperation "indexByteArray" - "readHash" -> outputByteArrayOperation "readByteArray#" - "writeHash" -> outputByteArrayOperation "writeByteArray#" - "indexHash" -> outputByteArrayOperation "indexByteArray#" + "readByteArray" -> outputByteArrayOperation "readByteArray" + "writeByteArray" -> outputByteArrayOperation "writeByteArray" + "indexByteArray" -> outputByteArrayOperation "indexByteArray" + "readByteArrayHash" -> outputByteArrayOperation "readByteArray#" + "writeByteArrayHash" -> outputByteArrayOperation "writeByteArray#" + "indexByteArrayHash" -> outputByteArrayOperation "indexByteArray#" + "readOffAddrHash" -> outputByteArrayOperation "readOffAddr#" + "writeOffAddrHash" -> outputByteArrayOperation "writeOffAddr#" + "indexOffAddrHash" -> outputByteArrayOperation "indexOffAddr#" "ptr" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> hsc_ptr `plusPtr` " ++ show i ++ ")") >> return False "type" -> computeType z >>= output >> return False diff --git a/DirectCodegen.hs b/DirectCodegen.hs index 66f07fc..85a2cb2 100644 --- a/DirectCodegen.hs +++ b/DirectCodegen.hs @@ -56,10 +56,14 @@ outputDirect config outName outDir outBase name toks = do when (cCrossSafe config) $ forM_ specials (\ (SourcePos file line _,key,_) -> - when (not $ key `elem` ["const","offset","size","alignment","peek","poke","ptr", - "type","enum","error","warning","include","define","undef", - "if","ifdef","ifndef", "elif","else","endif", - "read","write","index","readHash","writeHash","indexHash"]) $ + when (not $ key `elem` + ["const","offset","size","alignment","peek","poke","ptr" + ,"type","enum","error","warning","include","define","undef" + ,"if","ifdef","ifndef", "elif","else","endif" + ,"readByteArray","writeByteArray","indexByteArray" + ,"readByteArrayHash","writeByteArrayHash","indexByteArrayHash" + ,"readOffAddrHash","writeOffAddrHash","indexOffAddrHash" + ]) $ die (file ++ ":" ++ show line ++ " directive \"" ++ key ++ "\" is not safe for cross-compilation")) writeBinaryFile cProgName $ diff --git a/template-hsc.h b/template-hsc.h index f43d5fc..669d58f 100644 --- a/template-hsc.h +++ b/template-hsc.h @@ -134,44 +134,65 @@ void *hsc_stdout(void); } \ } -#define hsc_read(t, f) \ +#define hsc_readByteArray(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } -#define hsc_write(t, f) \ +#define hsc_writeByteArray(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } -#define hsc_index(t, f) \ +#define hsc_indexByteArray(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } -#define hsc_readHash(t, f) \ +#define hsc_readByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } -#define hsc_writeHash(t, f) \ +#define hsc_writeByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } -#define hsc_indexHash(t, f) \ +#define hsc_indexByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } + +#define hsc_readOffAddrHash(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> readOffAddr# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } + +#define hsc_writeOffAddrHash(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeOffAddr# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } + +#define hsc_indexOffAddrHash(t, f) \ + if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexOffAddr# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + } else { \ + hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ + } From 0d105b1c6699d8c7f21cb9ab856e98b896177967 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Mon, 4 Feb 2019 09:09:30 -0500 Subject: [PATCH 08/12] add some missing parentheses to template --- template-hsc.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/template-hsc.h b/template-hsc.h index 669d58f..5b004ad 100644 --- a/template-hsc.h +++ b/template-hsc.h @@ -136,63 +136,63 @@ void *hsc_stdout(void); #define hsc_readByteArray(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeByteArray(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_indexByteArray(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_readByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_indexByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_readOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> readOffAddr# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> readOffAddr# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> writeOffAddr# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeOffAddr# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_indexOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> indexOffAddr# hsc_arr (%ld + (hsc_ix * %ld))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexOffAddr# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } From a09fa7b75f9fbef2a147857fc2c7517f5c3d3496 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Mon, 4 Feb 2019 09:29:18 -0500 Subject: [PATCH 09/12] use unboxed Int arithmetic when dealing with the primitives ending in hash --- CrossCodegen.hs | 24 +++++++++++++----------- template-hsc.h | 12 ++++++------ 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/CrossCodegen.hs b/CrossCodegen.hs index 16b8772..f4b5ead 100644 --- a/CrossCodegen.hs +++ b/CrossCodegen.hs @@ -226,15 +226,15 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke (\i -> "(\\hsc_ptr -> peekByteOff hsc_ptr " ++ show i ++ ")") >> return False "poke" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> pokeByteOff hsc_ptr " ++ show i ++ ")") >> return False - "readByteArray" -> outputByteArrayOperation "readByteArray" - "writeByteArray" -> outputByteArrayOperation "writeByteArray" - "indexByteArray" -> outputByteArrayOperation "indexByteArray" - "readByteArrayHash" -> outputByteArrayOperation "readByteArray#" - "writeByteArrayHash" -> outputByteArrayOperation "writeByteArray#" - "indexByteArrayHash" -> outputByteArrayOperation "indexByteArray#" - "readOffAddrHash" -> outputByteArrayOperation "readOffAddr#" - "writeOffAddrHash" -> outputByteArrayOperation "writeOffAddr#" - "indexOffAddrHash" -> outputByteArrayOperation "indexOffAddr#" + "readByteArray" -> outputByteArrayOperation True "readByteArray" + "writeByteArray" -> outputByteArrayOperation True "writeByteArray" + "indexByteArray" -> outputByteArrayOperation True "indexByteArray" + "readByteArrayHash" -> outputByteArrayOperation False "readByteArray#" + "writeByteArrayHash" -> outputByteArrayOperation False "writeByteArray#" + "indexByteArrayHash" -> outputByteArrayOperation False "indexByteArray#" + "readOffAddrHash" -> outputByteArrayOperation False "readOffAddr#" + "writeOffAddrHash" -> outputByteArrayOperation False "writeOffAddr#" + "indexOffAddrHash" -> outputByteArrayOperation False "indexOffAddr#" "ptr" -> outputConst ("offsetof(" ++ value ++ ")") (\i -> "(\\hsc_ptr -> hsc_ptr `plusPtr` " ++ show i ++ ")") >> return False "type" -> computeType z >>= output >> return False @@ -251,7 +251,7 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke -- fashion. The index is always given in elements, not bytes. So, we -- must divide the field's offset in bytes by its size to get index in -- terms of elements. - outputByteArrayOperation operation = case break (== ',') value of + outputByteArrayOperation boxed operation = case break (== ',') value of (typ,',':field) -> do byteOffset <- computeConst z ("offsetof(" ++ value ++ ")") typSize <- computeConst z ("sizeof(" ++ typ ++ ")") @@ -262,7 +262,9 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke when (r1 /= 0) (testFail pos ("#error " ++ value)) let (typFieldRatio,r2) = divMod typSize fieldSize when (r2 /= 0) (testFail pos ("#error " ++ value)) - output ("(\\hsc_arr hsc_ix -> " ++ operation ++ " hsc_arr (" ++ show elemOffset ++ " + (hsc_ix * " ++ show typFieldRatio ++ ")))") + if boxed + then output ("(\\hsc_arr hsc_ix -> " ++ operation ++ " hsc_arr (" ++ show elemOffset ++ " + (hsc_ix * " ++ show typFieldRatio ++ ")))") + else output ("(\\hsc_arr hsc_ix -> " ++ operation ++ " hsc_arr (" ++ show elemOffset ++ " +# (hsc_ix *# " ++ show typFieldRatio ++ ")))") return False _ -> testFail pos ("#error " ++ value) outputSpecial _ _ = error "outputSpecial's argument isn't a Special" diff --git a/template-hsc.h b/template-hsc.h index 5b004ad..1d4a5c5 100644 --- a/template-hsc.h +++ b/template-hsc.h @@ -157,42 +157,42 @@ void *hsc_stdout(void); #define hsc_readByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_indexByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_readOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> readOffAddr# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> readOffAddr# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> writeOffAddr# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeOffAddr# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_indexOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> indexOffAddr# hsc_arr (%ld + (hsc_ix * %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexOffAddr# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } From 5d00b0e1d0b2464b1e29cb921250ea4ff08a7b57 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Mon, 4 Feb 2019 09:45:36 -0500 Subject: [PATCH 10/12] use unboxed int literals where appropriate --- CrossCodegen.hs | 2 +- template-hsc.h | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CrossCodegen.hs b/CrossCodegen.hs index f4b5ead..429a77f 100644 --- a/CrossCodegen.hs +++ b/CrossCodegen.hs @@ -264,7 +264,7 @@ outputSpecial output (z@ZCursor {zCursor=Special pos@(SourcePos file line _) ke when (r2 /= 0) (testFail pos ("#error " ++ value)) if boxed then output ("(\\hsc_arr hsc_ix -> " ++ operation ++ " hsc_arr (" ++ show elemOffset ++ " + (hsc_ix * " ++ show typFieldRatio ++ ")))") - else output ("(\\hsc_arr hsc_ix -> " ++ operation ++ " hsc_arr (" ++ show elemOffset ++ " +# (hsc_ix *# " ++ show typFieldRatio ++ ")))") + else output ("(\\hsc_arr hsc_ix -> " ++ operation ++ " hsc_arr (" ++ show elemOffset ++ "# +# (hsc_ix *# " ++ show typFieldRatio ++ "#)))") return False _ -> testFail pos ("#error " ++ value) outputSpecial _ _ = error "outputSpecial's argument isn't a Special" diff --git a/template-hsc.h b/template-hsc.h index 1d4a5c5..dc83d7f 100644 --- a/template-hsc.h +++ b/template-hsc.h @@ -157,42 +157,42 @@ void *hsc_stdout(void); #define hsc_readByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> readByteArray# hsc_arr (%ld# +# (hsc_ix *# %ld#)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeByteArray# hsc_arr (%ld# +# (hsc_ix *# %ld#)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_indexByteArrayHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexByteArray# hsc_arr (%ld# +# (hsc_ix *# %ld#)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_readOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> readOffAddr# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> readOffAddr# hsc_arr (%ld# +# (hsc_ix *# %ld#)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_writeOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> writeOffAddr# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> writeOffAddr# hsc_arr (%ld# +# (hsc_ix *# %ld#)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } #define hsc_indexOffAddrHash(t, f) \ if ((offsetof(t,f)) % (FIELD_SIZEOF(t,f)) == 0 && (sizeof(t) % (FIELD_SIZEOF(t,f))) == 0) { \ - hsc_printf ("(\\hsc_arr hsc_ix -> indexOffAddr# hsc_arr (%ld +# (hsc_ix *# %ld)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ + hsc_printf ("(\\hsc_arr hsc_ix -> indexOffAddr# hsc_arr (%ld# +# (hsc_ix *# %ld#)))", ((offsetof(t,f)) / (FIELD_SIZEOF(t,f))), (sizeof(t) / (FIELD_SIZEOF(t,f)))); \ } else { \ hsc_printf ("BAD_BYTEARRAY_ALIGNMENT"); \ } From 3e82758e0604f0d7acc5c3fcddbea9a0a8facaa0 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Tue, 11 Jun 2019 11:14:59 -0400 Subject: [PATCH 11/12] update README and changelog --- README.rst | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++ changelog.md | 3 ++ 2 files changed, 138 insertions(+) diff --git a/README.rst b/README.rst index 68a6368..7c5c54f 100644 --- a/README.rst +++ b/README.rst @@ -195,6 +195,25 @@ Meanings of specific keywords: Computes the alignment, in bytes, of ``struct_type``. It will have type ``Int``. +``#readByteArray ⟨struct_type⟩, ⟨field⟩`` + Outputs a function that indexes into an array of a C struct. It will + have the type ``Prim a => MutableByteArray (PrimState m) -> Int -> m a``. + The context must ensure that ``a`` is a type that can be marshalled + to the C field type. This only supports access to aligned fields and + will fail at compile time if the field is not aligned. The source + expression ``#{readByteArray struct foo, bar} arr 42`` becomes an + expression that has the same behavior as the C expression + ``((struct foo*) arr)[42].bar``. + +``#readByteArrayHash ⟨struct_type⟩, ⟨field⟩`` + Variant of ``#readByteArray`` with unlifted argument and result types. + It will have the type + ``Prim a => MutableByteArray# s -> Int# -> State# s -> (# State# s, a #)``. + The macros ``#readByteArrayHash``, ``#writeByteArayHash``, + ``#indexByteArrayHash``, ``#readOffAddrHash``, ``#writeOffAddrHash``, + and ``#indexOffAddrHash`` are intended to be used to implement instances + of ``Prim`` (see `instances`_). + ``#enum ⟨type⟩, ⟨constructor⟩, ⟨value⟩, ⟨value⟩, ...`` A shortcut for multiple definitions which use ``#const``. Each ``value`` is a name of a C integer constant, e.g. enumeration value. @@ -247,3 +266,119 @@ The following are unsupported: - ``#{let}`` - ``#{def}`` - Custom constructs + +.. _instances + +Implementing Instances +~~~~~~~~~~~~~~~~~~~~~~ + +As an example, the ``Storable`` and ``Prim`` instances for a haskell +data type corresponding to the POSIX ``struct pollfd`` are implemented +below. `IEEE Std 1003.1-2017`_ describes ``struct pollfd`` as: + +.. _`IEEE Std 1003.1-2017`: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/poll.h.html + ++-------+---------+----------------------------------------+ +| int | fd | The following descriptor being polled. | ++-------+---------+----------------------------------------+ +| short | events | The input event flags (see below). | ++-------+---------+----------------------------------------+ +| short | revents | The output event flags (see below). | ++-------+---------+----------------------------------------+ + +The `Linux poll man page`_ provides a concrete implementation, +describing ``struct pollfd`` as: + +.. _`Linux poll man page`: http://man7.org/linux/man-pages/man2/poll.2.html + +:: + struct pollfd { + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ + }; + +This type is most directly expressed in Haskell as: + +:: + data PollFd = PollFd + { descriptor :: !Fd + , request :: !CShort + , response :: !CShort + } + +We now use ``hsc2hs`` to help write a portable ``Storable`` instance. +The GHC ``NamedFieldPuns`` extension is used for succinctness although +it is not necessary:: + + instance Storable PollFd where + sizeOf _ = #size struct pollfd + alignment _ = #alignment struct pollfd + peek ptr = do + descriptor <- #{peek struct pollfd, fd} ptr + request <- #{peek struct pollfd, events} ptr + response <- #{peek struct pollfd, revents} ptr + return (PollFd{descriptor,request,response}) + poke ptr PollFd{descriptor,request,response} = do + #{poke struct pollfd, fd} ptr descriptor + #{poke struct pollfd, events} ptr request + #{poke struct pollfd, revents} ptr response + +More verbosely, ``hsc2hs`` can also be used to help write portable ``Prim`` +instances that are intended to marshall C data types. (Unlike ``Storable``, +whose sole purpose is to help marshall C data types, ``Prim`` is not used +exclusively for this purpose, but it is occassionally useful in this domain.) +This example uses the GHC extensions ``MagicHash`` and ``UnboxedTuples``, +which are required. It also uses the GHC extension ``NamedFieldPuns``, +which is optional as it was in the ``Storable`` example. Notice that all +the source Haskell hash characters escaped by doubling them:: + + import GHC.Exts + import Data.Primitive.Types (Prim(..),defaultSetByteArray##,defaultSetOffAddr##) + + unInt :: Int -> Int## + unInt (I## i) = i + + instance Prim PollFd where + sizeOf## _ = unInt #{size struct pollfd} + alignment## _ = unInt #{alignment struct pollfd} + indexByteArray## arr i = PollFd + { descriptor = #{indexByteArrayHash struct pollfd, fd} arr i + , request = #{indexByteArrayHash struct pollfd, events} arr i + , response = #{indexByteArrayHash struct pollfd, revents} arr i + } + writeByteArray## arr i PollFd{descriptor,request,response} s0 = + case #{writeByteArrayHash struct pollfd, fd} arr i descriptor s0 of + s1 -> case #{writeByteArrayHash struct pollfd, events} arr i request s1 of + s2 -> #{writeByteArrayHash struct pollfd, revents} arr i response s2 + readByteArray## arr i s0 = case #{readByteArrayHash struct pollfd, fd} arr i s0 of + (## s1, descriptor ##) -> case #{readByteArrayHash struct pollfd, events} arr i s1 of + (## s2, request ##) -> case #{readByteArrayHash struct pollfd, revents} arr i s2 of + (## s3, response ##) -> (## s3, PollFd{descriptor,request,response} ##) + setByteArray## = defaultSetByteArray## + indexOffAddr## arr i = PollFd + { descriptor = #{indexOffAddrHash struct pollfd, fd} arr i + , request = #{indexOffAddrHash struct pollfd, events} arr i + , response = #{indexOffAddrHash struct pollfd, revents} arr i + } + writeOffAddr## arr i PollFd{descriptor,request,response} s0 = + case #{writeOffAddrHash struct pollfd, fd} arr i descriptor s0 of + s1 -> case #{writeOffAddrHash struct pollfd, events} arr i request s1 of + s2 -> #{writeOffAddrHash struct pollfd, revents} arr i response s2 + readOffAddr## arr i s0 = case #{readOffAddrHash struct pollfd, fd} arr i s0 of + (## s1, descriptor ##) -> case #{readOffAddrHash struct pollfd, events} arr i s1 of + (## s2, request ##) -> case #{readOffAddrHash struct pollfd, revents} arr i s2 of + (## s3, response ##) -> (## s3, PollFd{descriptor,request,response} ##) + setOffAddr## = defaultSetOffAddr## + +Keep in mind that, unlike the code-generation for the ``Storable`` instance, +this code-generation will cause a compile-time failure if the operating system +has an esoteric implementation of ``struct pollfd`` with unaligned fields. +Note that the ``Prim`` instances is necessarily more verbose that the +``Storable`` instance. Two factors contribute to this: + +* ``Prim`` deals with both managed and unmanaged memory +* The typeclass methods of ``Prim`` use unlifted types + +Despite the verbosity, this is a portable solution for Haskell code that needs +to pass runtime-managed, unpinned memory to a C library using the unsafe FFI. diff --git a/changelog.md b/changelog.md index 33e8877..5a029c3 100644 --- a/changelog.md +++ b/changelog.md @@ -9,6 +9,9 @@ - Add support for haskell files that use a leading single quote for promoted data constructors. + - Add macros for accessing runtime-managed bytearrays. This uses the naming + scheme from `primitive` and is intended to be used with that library. + ## 0.68.4 - Add support to read command line arguments supplied via response files From 4d487822d5eb5faa30114baf98ea29809d3f0680 Mon Sep 17 00:00:00 2001 From: Andrew Martin Date: Tue, 11 Jun 2019 11:22:27 -0400 Subject: [PATCH 12/12] Fix restructured text mistakes in readme --- README.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.rst b/README.rst index 7c5c54f..2d77e90 100644 --- a/README.rst +++ b/README.rst @@ -212,7 +212,7 @@ Meanings of specific keywords: The macros ``#readByteArrayHash``, ``#writeByteArayHash``, ``#indexByteArrayHash``, ``#readOffAddrHash``, ``#writeOffAddrHash``, and ``#indexOffAddrHash`` are intended to be used to implement instances - of ``Prim`` (see `instances`_). + of ``Prim`` (see `implementing-instances`_). ``#enum ⟨type⟩, ⟨constructor⟩, ⟨value⟩, ⟨value⟩, ...`` A shortcut for multiple definitions which use ``#const``. Each @@ -267,7 +267,7 @@ The following are unsupported: - ``#{def}`` - Custom constructs -.. _instances +.. _implementing-instances: Implementing Instances ~~~~~~~~~~~~~~~~~~~~~~ @@ -281,9 +281,9 @@ below. `IEEE Std 1003.1-2017`_ describes ``struct pollfd`` as: +-------+---------+----------------------------------------+ | int | fd | The following descriptor being polled. | +-------+---------+----------------------------------------+ -| short | events | The input event flags (see below). | +| short | events | The input event flags. | +-------+---------+----------------------------------------+ -| short | revents | The output event flags (see below). | +| short | revents | The output event flags. | +-------+---------+----------------------------------------+ The `Linux poll man page`_ provides a concrete implementation, @@ -292,6 +292,7 @@ describing ``struct pollfd`` as: .. _`Linux poll man page`: http://man7.org/linux/man-pages/man2/poll.2.html :: + struct pollfd { int fd; /* file descriptor */ short events; /* requested events */ @@ -301,6 +302,7 @@ describing ``struct pollfd`` as: This type is most directly expressed in Haskell as: :: + data PollFd = PollFd { descriptor :: !Fd , request :: !CShort