copilot-c99 3.9 → 3.10
raw patch · 5 files changed
+115/−16 lines, 5 filesdep −containersdep −language-c99-utildep ~copilot-coredep ~mtlPVP ok
version bump matches the API change (PVP)
Dependencies removed: containers, language-c99-util
Dependency ranges changed: copilot-core, mtl
API changes (from Hackage documentation)
Files
- CHANGELOG +8/−0
- copilot-c99.cabal +6/−8
- src/Copilot/Compile/C99/CodeGen.hs +83/−7
- src/Copilot/Compile/C99/Compile.hs +9/−1
- src/Copilot/Compile/C99/Util.hs +9/−0
CHANGELOG view
@@ -1,3 +1,11 @@+2022-07-07+ * Version bump (3.10). (#356)+ * Remove unnecessary dependencies from Cabal package. (#323)+ * Remove duplicated compiler option. (#328)+ * Pass structs by reference, not value, in handlers. (#305)+ * Relax version bounds of dependencies. (#335)+ * Update repo info in cabal file. (#333)+ 2022-05-06 * Version bump (3.9). (#320) * Compliance with style guide (partial). (#316)
copilot-c99.cabal view
@@ -1,6 +1,6 @@ cabal-version : >= 1.10 name : copilot-c99-version : 3.9+version : 3.10 synopsis : A compiler for Copilot targeting C99. description : This package is a back-end from Copilot to C.@@ -31,8 +31,8 @@ source-repository head type: git- location: git://github.com/Copilot-Language/copilot.git- subdir: lib/copilot-c99+ location: https://github.com/Copilot-Language/copilot.git+ subdir: copilot-c99 library default-language : Haskell2010@@ -42,17 +42,15 @@ -- https://github.com/Copilot-Language/copilot/issues/237 -- It should be removed in a future version, when this library hides -- internal modules.- ghc-options : -Wall -fwarn-tabs -Wno-deprecations+ ghc-options : -Wall -Wno-deprecations build-depends : base >= 4.9 && < 5- , containers >= 0.4 && < 0.7 , directory >= 1.3 && < 1.4 , filepath >= 1.4 && < 1.5- , mtl >= 2.2 && < 2.3+ , mtl >= 2.2 && < 2.4 , pretty >= 1.1 && < 1.2 - , copilot-core >= 3.9 && < 3.10+ , copilot-core >= 3.10 && < 3.11 , language-c99 >= 0.1.1 && < 0.2- , language-c99-util >= 0.1.1 && < 0.2 , language-c99-simple >= 0.1.1 && < 0.2 exposed-modules : Copilot.Compile.C99
src/Copilot/Compile/C99/CodeGen.hs view
@@ -79,12 +79,16 @@ void = C.TypeSpec C.Void stmts = map mkexcopy exts- ++ map mktriggercheck triggers+ ++ triggerStmts ++ tmpassigns ++ bufferupdates ++ indexupdates- (declns, tmpassigns, bufferupdates, indexupdates) =+ declns = streamDeclns+ ++ concat triggerDeclns+ (streamDeclns, tmpassigns, bufferupdates, indexupdates) = unzip4 $ map mkupdateglobals streams+ (triggerDeclns, triggerStmts) =+ unzip $ map mktriggercheck triggers -- Write code to update global stream buffers and index. mkupdateglobals :: Stream -> (C.Decln, C.Stmt, C.Stmt, C.Stmt)@@ -129,13 +133,85 @@ _ -> C.Ident cpyname C..= C.Ident name - -- Make if-statement to check the guard, call the trigger if necessary.- mktriggercheck :: Trigger -> C.Stmt- mktriggercheck (Trigger name guard args) = C.If guard' firetrigger+ -- Make if-statement to check the guard, call the handler if necessary.+ -- This returns two things:+ --+ -- * A list of Declns for temporary variables, one for each argument that+ -- the handler function accepts. For example, if a handler function takes+ -- three arguments, the list of Declns might look something like this:+ --+ -- @+ -- int8_t handler_arg_temp0;+ -- int16_t handler_arg_temp1;+ -- struct s handler_arg_temp2;+ -- @+ --+ -- * A Stmt representing the if-statement. Continuing the example above,+ -- the if-statement would look something like this:+ --+ -- @+ -- if (handler_guard()) {+ -- handler_arg_temp0 = handler_arg0();+ -- handler_arg_temp1 = handler_arg1();+ -- handler_arg_temp2 = handler_arg2();+ -- handler(handler_arg_temp0, handler_arg_temp1, &handler_arg_temp2);+ -- }+ -- @+ --+ -- We create temporary variables because:+ --+ -- 1. We want to pass structs by reference intead of by value. To this end,+ -- we use C's & operator to obtain a reference to a temporary variable+ -- of a struct type and pass that to the handler function.+ --+ -- 2. Assigning a struct to a temporary variable defensively ensures that+ -- any modifications that the handler called makes to the struct argument+ -- will not affect the internals of the monitoring code.+ mktriggercheck :: Trigger -> ([C.Decln], C.Stmt)+ mktriggercheck (Trigger name guard args) =+ (aTmpDeclns, ifStmt) where- guard' = C.Funcall (C.Ident $ guardname name) []- firetrigger = [C.Expr $ C.Funcall (C.Ident name) args']+ aTmpDeclns = zipWith (\tmpVar arg ->+ C.VarDecln Nothing (tempType arg) tmpVar Nothing)+ aTempNames+ args where+ tempType (UExpr { uExprType = ty }) =+ case ty of+ -- If a temporary variable is being used to store an array,+ -- declare the type of the temporary variable as a pointer, not+ -- an array. The problem with declaring it as an array is that+ -- the `arg` function will return a pointer, not an array, and+ -- C doesn't make it easy to cast directly from an array to a+ -- pointer.+ Array ty' -> C.Ptr $ transtype ty'+ _ -> transtype ty++ aTempNames = take (length args) (argTempNames name)++ ifStmt = C.If guard' firetrigger++ guard' = C.Funcall (C.Ident $ guardname name) []++ -- The body of the if-statement. This consists of statements that assign+ -- the values of the temporary variables, following by a final statement+ -- that passes the temporary variables to the handler function.+ firetrigger = map C.Expr argAssigns +++ [C.Expr $ C.Funcall (C.Ident name)+ (zipWith passArg aTempNames args)]+ where+ passArg aTempName (UExpr { uExprType = ty }) =+ case ty of+ -- Special case for Struct to pass reference to temporary+ -- struct variable to handler. (See the comments for+ -- mktriggercheck for details.)+ Struct _ -> C.UnaryOp C.Ref $ C.Ident aTempName+ _ -> C.Ident aTempName++ argAssigns = zipWith (\aTempName arg ->+ C.AssignOp C.Assign (C.Ident aTempName) arg)+ aTempNames+ args' args' = take (length args) (map argcall (argnames name)) argcall name = C.Funcall (C.Ident name) []
src/Copilot/Compile/C99/Compile.hs view
@@ -157,7 +157,15 @@ where cty = C.TypeSpec C.Void params = map mkparam $ zip (argnames name) args- mkparam (name, UExpr ty _) = C.Param (transtype ty) name+ mkparam (name, UExpr ty _) = C.Param (mkParamTy ty) name++ -- Special case for Struct, to pass struct arguments by reference.+ -- Arrays are also passed by reference, but using C's array type+ -- does that automatically.+ mkParamTy ty =+ case ty of+ Struct _ -> C.Ptr (transtype ty)+ _ -> transtype ty -- Declaration for the step function. stepdecln :: C.Decln
src/Copilot/Compile/C99/Util.hs view
@@ -55,9 +55,18 @@ argname :: String -> Int -> String argname name n = name ++ "_arg" ++ show n +-- | Turn a handler function name into a name for a temporary variable for a+-- handler argument.+argTempName :: String -> Int -> String+argTempName name n = name ++ "_arg_temp" ++ show n+ -- | Enumerate all argument names based on trigger name. argnames :: String -> [String] argnames base = [aname | n <- [0..], let aname = argname base n]++-- | Enumerate all temporary variable names based on handler function name.+argTempNames :: String -> [String]+argTempNames base = map (argTempName base) [0..] -- | Define a C expression that calls a function with arguments. funcall :: C.Ident -> [C.Expr] -> C.Expr