{-# LANGUAGE RecordWildCards, QuasiQuotes, NamedFieldPuns, ScopedTypeVariables, CPP #-} {-# OPTIONS_GHC -fwarn-incomplete-patterns #-} -- OverloadedStrings -- TODO: currently causes ambiguities with toDoc ---------------------------------------------------------------------------------------------------- -- This is the code generator for the original (CnC/C++ 0.1-0.5) "context"-based C++ API. -- Original Author: Ryan Newton ---------------------------------------------------------------------------------------------------- -- This should eventually be based on some intermediate representation of C code. For a -- first cut, however, it is easier to just generate syntax directly. (Especially with -- the assistance of the pretty printing libary.) module Intel.Cnc.Spec.Codegen.CppOld where import Intel.Cnc.Spec.Codegen.CodegenShared import Intel.Cnc.Spec.Codegen.Plugins import Intel.Cnc.Spec.Codegen.Plugins.Depends import Intel.Cnc.Spec.AST import Intel.Cnc.Spec.TagFun import Intel.Cnc.Spec.CncGraph --import Intel.Cnc.Spec.GatherGraph import Intel.Cnc.Spec.Util as U hiding (commacat) import qualified Intel.Cnc.EasyEmit as EE import Intel.Cnc.EasyEmit hiding (app, not, (&&), (==), (||)) import Control.Monad.State import StringTable.Atom import Text.PrettyPrint.HughesPJClass import Text.Printf -- QuasiQuoting is too expensive in final binary size: -- import Text.InterpolatedString.QQ import qualified Data.Map as M import Data.List import Data.Maybe import Data.Graph.Inductive hiding (empty) import qualified StringTable.AtomMap as AM import qualified StringTable.AtomSet as AS ---------------------------------------------------------------------------------------------------- -- An annoying feature of our current API [2010.08.03] is that we -- don't have explicit step_collection objects. We make sure to only -- allocate one copy of the user's temporary Step() object and then -- use its pointer as a key: step_obj e | e == special_environment_name = e step_obj str = "m_" ++ str --obj_ref a = t"*" <> (t$ step_obj$ fromAtom a) obj_ref a = (t$ step_obj$ fromAtom a) -- [2010.11.14] TEMPTOGGLE: Disabling the one-argument version of get: oldstyle_get_method = False commacat ls = hcat (intersperse (text ", ") $ ls) s = Syn . text doc2Ty = TSym . toAtom . render instance FromAtom Doc where fromAtom = text . fromAtom -- If a block of text is nonempty, then preface it with a comment: maybeCommentDoc ls txt = if txt == t"" then txt else vcat (map (\ cmnt -> if cmnt == t"" then cmnt else t"// "<> cmnt) ls) $$ txt maybeComment ls mnd = -- FIXME FIXME: -- FIXME!! THIS EXECUTES IT TWICE! let doc = execEasyEmit mnd in if doc == t"" then return () -- else putD$ maybeCommentDoc ls doc else do forM_ ls $ \ cmnt -> putD$ if cmnt == t"" then cmnt else t"// "<> cmnt mnd ---------------------------------------------------------------------------------------------------- -- Name for a private context: privcontext stp = textAtom stp <> t"_context" ---------------------------------------------------------------------------------------------------- --emitCpp :: StringBuilder m => CodeGenConfig -> CncSpec -> m () emitCpp :: CodeGenConfig -> CncSpec -> EasyEmit () emitCpp (config@CodeGenConfig{..}) (spec @ CncSpec{appname, steps, tags, items, reductions, graph, realmap}) = do -- HOWTO READ the below code: -- This code emits a series of strings/docs to build up a file. -- Some of the more complex looking bits are building up large lists of type [Doc]. -- -- [2010.11.15] NOTE: This will get more complex for a little while -- because I am IN THE MIDDLE OF switching to use EasyEmit functionality. -------------------------------------------------------------------------------- -- Prelude: set up some bindings for EasyEmit functions and other helpers: -------------------------------------------------------------------------------- let -- Don't include builtins (e.g. the environment): stepls = filter (\ x -> not$ x `elem` builtinSteps) $ AS.toList steps stepls_with_types = zip stepls tagtys -- Call each plugin's "constructor" so it can analyze the spec. initialized_plugins = map (\pg -> pg spec) plugins -- Then create a map of which plugins apply to which steps: plug_map = AM.fromList$ filter (not . null . snd) $ map (\stpC -> (stpC, catMaybes$ map (\pg -> pg stpC) initialized_plugins)) (toAtom special_environment_name : stepls) -- This predicate determines whether there is any requirement to wrap a particular step collection: shouldWrapStep stpname = wrapall || AM.member stpname plug_map --wrapall || any (\ cgh -> hooksPredicate cgh stpname ) plugins areAnyWrapped = wrapall || any shouldWrapStep stepls tractible_depends_steps = AS.fromList (filter (all_tagfuns_tractible graph) stepls) prescribers = map (getStepPrescriber spec) stepls tagtys = map (\ name -> case tags AM.! name of Nothing -> error$ "Tag collection '"++ show name ++"' missing type, needed for C++ codegen!" Just ty -> ty) prescribers privcontext_member stp = t"m_priv_" <> privcontext stp tls_key stp = privcontext stp <> t"_tls_key" -------------------------------------------------------------------------------- -- First we produce the header of the file: -------------------------------------------------------------------------------- -- TODO: Try quasiquoting for multiline-strings here again when they fix the binary bloating problem: putS$ "\n//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n" putS$ "// This code was GENERATED from a CnC specification, DO NOT MODIFY.\n" putS$ "//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n" putS$ "#ifndef "++appname++"_H_ALREADY_INCLUDED\n" putS$ "#define "++appname++"_H_ALREADY_INCLUDED\n\n" -- Ideally this would only be included IF tuple types are used... complicated right now. -- putS "#include \"boost/tuple/tuple.hpp\"\n\n" putS "// For now we use C++ TR1 to provide tuples:\n" putS "#include \n" putS "#define cnctup std::tr1\n\n" putS "// This tells cnc.h to define certain things. TODO: should do this ONLY if tuples are needed!\n" putS "#define CNC_ASSUME_TR1 \n\n" putS "#include \n" putS "#include \n" when areAnyWrapped$ putS "#include \n" -- [2010.08.16] This is an INSUFFICIENT forward declaration: ------------------------------------------------------------ -- Emit the step prototypes (two possibilities here): ------------------------------------------------------------ when (genstepdefs)$ putS "\n// Next this generated file contains prototypes for each step implementation:\n" when (not genstepdefs)$ do putS "// The user's step types should be defined SEPARATELY from this header, and must \n" putS "// be in scope before this header is included.\n" putS "// As a hint, the below are valid example definitions:\n" putS "/*\n" forM_ stepls_with_types $ \ (stp,ty) -> do emitStep appname (fromAtom stp) ty putS "\n\n" when (not genstepdefs)$ putS "*/\n" when (not old_05_api) $ do maybeComment [t"", t"", t"Forward declarations for private contexts."] $ forM_ stepls $ \stp -> when (shouldWrapStep stp) $ putD$ t"class " <> privcontext stp <> semi <> t"\n" putS$ "\n" ------------------------------------------------------------ -- Prototype for user step wrappers ------------------------------------------------------------ let usercontext = appname++"_context" -- The top-level context exposed to the user maincontext = if areAnyWrapped -- The top-level context (internal) then t$ appname++"_context_INTERNAL" else t usercontext let stepwrapper stp = textAtom stp <> t"_step_wrapper" when (not old_05_api)$ do putS "// Forward declaration of the context class (representing the CnC graph)\n" putD$ t"class " <> maincontext <> t";" when areAnyWrapped$ putD$ t"class " <> t usercontext <> t";" maybeComment [t"", t"Type definitions for wrappers around steps."] (forM_ stepls_with_types $ \ (stp,ty) -> when (shouldWrapStep stp) $ do putD$ struct (stepwrapper stp) $ textAtom stp <+> t"m_step" <> semi $$ --stepwrapper stp <> parens empty <> semi t"int execute(" <+> constRefType ty <+> t "tag," <+> maincontext <> t" & c) const;" putS$ "\n") ------------------------------------------------------------ -- Emit the main context class ------------------------------------------------------------ putS$ "\n\n// Here is the definition for the main application context:\n" -- putD$ cppclass (maincontext <> t " : public CnC::context" <> angles (pad maincontext)) $ cppClass (Syn maincontext) (Syn$ t "public CnC::context" <> angles (pad maincontext)) $ do -- Discarded this API proposal already: -- t "\n private:" : -- t "// Members to store instances of the users Step type:" : -- ((flip map) stepls $ \ stp -> -- textAtom stp <> t"* " <> (t$ step_obj$ fromAtom stp) <> semi) ++ putS "\n public:" when (not old_05_api) $ do comm "Step collection members:" forM_ stepls $ \ stp -> var (doc2Ty$ t "CnC::step_collection" <> angles (if shouldWrapStep stp then stepwrapper stp else textAtom stp)) (strToSyn$ step_obj$ fromAtom stp) comm "" comm "Tag collection members:" forM_ (AM.toList tags) $ \ (tg,mty) -> case mty of Nothing -> error$ "CppOld.hs Codegen: tag collection without type: "++ (fromAtom tg) Just ty -> var (doc2Ty$ t"CnC::tag_collection" <> angles (cppType ty)) (atomToSyn tg) comm "" comm "Item collection members:" forM_ (AM.toList items) $ \ (itC,mty) -> case mty of Nothing -> error$ "CppOld Codegen: item collection without type: "++ (fromAtom itC) Just (ty1,ty2) -> let extra = case ty1 of -- In the case where the tag type is dense in all dimensions, turn on CNC_VECTOR: TDense _ -> commspc<> t"CnC::cnc_tag_hash_compare" <> angles (cppType ty1) <>commspc<> t"CnC::CNC_VECTOR" _ -> empty in var (doc2Ty$ t "CnC::item_collection" <> angles (cppType ty1 <>commspc<> cppType ty2 <> extra)) (atomToSyn itC) comm "" comm "Reduction collection members:" forM_ (AM.toList reductions) $ \ (rdC, mty) -> case mty of (_, _, Nothing) -> error$ "CppOld.hs Codegen: reduction collection without type: "++ (fromAtom rdC) (op, exp, Just (ty1,ty2)) -> var (doc2Ty$ t "CnC::reduction_collection" <> angles (cppType ty1 <> t", " <> cppType ty2)) (atomToSyn rdC) maybeComment [t"", t" Keys for thread local storage:"] $ forM_ stepls $ \stp -> when (shouldWrapStep stp) (putD$ t"int "<> tls_key stp <> semi) maybeComment [t"",t"Next, global state used/generated by plugins:"] $ forM_ (AM.toList plug_map) $ \ (stpC,hooks) -> sequence_ $ map (fst . addGlobalState) hooks comm "" comm "The context class constructor (prototype): " constructorPrototype (Syn maincontext) [] return () {- ++ ++ -} -- [2010.08.19] Don't need the destructor for now: -- [space, t "// The context class destructor: "] ++ -- [hangbraces -- (t"~" <> maincontext <> parens empty ) -- indent -- -- Body of the constructor -- empty -- -- Destroy temporary step objects/collections: -- -- (vcat$ (flip map) stepls $ \ stp -> -- -- t"delete " <> (t$ step_obj$ fromAtom stp) <> semi) -- ] ------------------------------------------------------------ -- Top level bindings (such as tuners): ------------------------------------------------------------ maybeComment [t"", t"Plugin-generated top-level bindings:"]$ forM_ (AM.toList plug_map) $ \ (stp, methodtables) -> do sequence_ $ map (\fn -> fn (Syn$t usercontext, Syn maincontext) ()) $ map addTopLevel methodtables -------------------------------------------------------------------------------- -- Emit private contexts for each step. This means building wrappers. -------------------------------------------------------------------------------- -- INVARIANT! Due to error checking above, we can omit some error checking here: when (not old_05_api) $ do maybeComment [t"", t"", t"Next we define 'private contexts'.", t"These allow steps to exist in their own little universes with special properties:"] $ forM_ stepls_with_types $ \ (stp,stpty) -> when (shouldWrapStep stp) $ do generate_wrapper_context config spec stp stpty plug_map maincontext usercontext when areAnyWrapped $ do comm "Also, we generate a wrapper for the main context that is exposed to the user:" comm "================================================================================" generate_wrapper_context config spec (toAtom special_environment_name) TInt plug_map maincontext usercontext ------------------------------------------------------------ -- Execute wrapper methods ------------------------------------------------------------ maybeComment [t"", t"", t"Execute method wrappers for each step that uses a private context:"] $ forM_ stepls_with_types $ \ (stp,ty) -> when (shouldWrapStep stp) $ do putD$ hangbraces (t"int "<> stepwrapper stp <> t"::execute(" <+> constRefType ty <+> t "tag," <+> maincontext <> t" & c) const") indent $ t"// To access the (thread local) state we fetch a pointer to the private context object:"$$ assignCast (mkPtr$ privcontext stp) (t"ptr") (U.app "CnC::Internal::CnC_TlsGetValue" [deref (t"c") (tls_key stp)]) $$ hangbraces (t"if " <> parens (t"!ptr")) indent (assign "ptr" (t"new " <> U.app (privcontext stp) ["c"]) $$ U.app "CnC::Internal::CnC_TlsSetValue" [deref (t"c") (tls_key stp), t"ptr" ] <> semi) $$ t"ptr->tag = &tag;\n" $$ -- t"printf(\"PTR %p\\n\", ptr);" $$ (execEasyEmit$ forM_ (AM.findWithDefault [] stp plug_map) $ \hks -> beforeStepExecute hks (Syn$ t"ptr", Syn$t"c") (Syn$ t"tag", Syn$ t"ptr", Syn$t"c")) $$ t"int result = " <+> U.app "m_step.execute" ["tag", "*ptr"] <> semi $$ (execEasyEmit$ forM_ (AM.findWithDefault [] stp plug_map) $ \hks -> afterStepExecute hks (Syn$ t"ptr", Syn$t"c") (Syn$ t"tag", Syn$ t"ptr", Syn$t"c")) $$ t"return result;" -- privcontext stp <> t"* ptr = ("<> privcontext stp -- <> t"*) CnC::Internal::CnC_TlsGetValue" <> parens (t"c." <> tls_key stp) <> semi ------------------------------------------------------------ -- Main Context constructor ------------------------------------------------------------ putS "\n\n" putS "// Finally, define the constructor for the main context:\n" --when (areAnyWrapped && not old_05_api) $ do when (not old_05_api) $ do putS "// (Note that this occurs AFTER the private contexts are defined.)\n" cppConstructor (Syn$ maincontext <> t"::" <> maincontext) [] -- Name, Args -- Initializer list: ((if old_05_api then [] else -- t "// Initialize step collections" : ((flip map) stepls $ \ stp -> (Syn$ t$ step_obj$ fromAtom stp, s"this"))) ++ -- t "// Initialize tag collections" : ((flip map) (AM.toList tags) $ \ (tg,Just ty) -> (atomToSyn tg, s"this, false")) ++ -- t "// Initialize item collections" : ((flip map) (AM.toList items) $ \ (itC,Just (ty1,ty2)) -> (atomToSyn itC, s "this")) ++ -- t "// Initialize reduction collections: " ((flip map) (AM.toList reductions) $ \ (rdC, (op, exp, Just ty)) -> (atomToSyn rdC, Syn(pPrint exp <> t", & "<> textAtom op <> t", this"))) ) $ -- Body of the constructor putD (nest 6 $ vcat $ [-- Create objects for all step collections: -- This was an intermediate step in our API evolution: -- (vcat$ (flip map) stepls $ \ stp -> -- (t$ step_obj$ fromAtom stp) <> t" = new " <> textAtom stp <> parens empty <> semi -- ), t"CnC::step_collection< "<> textAtom (head stepls) <>t" > env(this);\n" ]++ [t"", -- Generate prescribe relations first [mandatory]: (vcat $ (flip map) (zip3 stepls prescribers tagtys) $ \ (stp,tg,ty) -> t"prescribe" <> parens (pad$ hcat $ punctuate commspc $ [ textAtom tg , if old_05_api then textAtom stp <> parens empty else obj_ref stp] ++ if gendepends && AS.member stp tractible_depends_steps then [thunkapp (tuner_name stp)] else [] -- [2010.08.19] Revamp: don't need tuner/private context here anymore: -- if old_05_api then [] else -- [t"CnC::default_tuner< " <> cppType ty <>commspc<> privcontext stp <> t" >" <> parens empty -- , t"*" <> privcontext_member stp -- --, privcontext stp <> parens (t"this") -- ] ) <> semi), -- Next, consume relations: if old_05_api then empty else (let egs = concat $ map (\ (a,b,_) -> case (lab graph a, lab graph b) of (Just (CGItems i), Just (CGSteps s)) -> [(i,s)] _ -> []) $ labEdges graph in vcat $ (flip map) egs $ \ (a,b) -> t"consume" <> parens (obj_ref b <> commspc <> (t$ fromAtom a)) <> semi), -- Finally, produce relations: if old_05_api then empty else (let egs = concat $ map (\ (a,b,_) -> case (lab graph a, lab graph b) of (Just (CGSteps s), Just (CGItems i)) -> [(s,i)] (Just (CGSteps s), Just (CGTags t)) -> [(s,t)] _ -> []) $ labEdges graph in vcat $ (flip map) egs $ \ (a,b) -> t"produce" <> parens (obj_ref a <> commspc <> (t$ fromAtom b)) <> semi), t"", (vcat$ (flip map) stepls $ \ stp -> if shouldWrapStep stp then assign (tls_key stp) (thunkapp "CnC::Internal::CnC_TlsAlloc") else empty) ] ++ -------------------------------------------------------------------------------- -- FIXME: -- This should be completely obsoleted when the API catches up (e.g. trace_all works properly) [hangbraces (t"if " <> parens (if gentracing then t"1" else t"0")) indent (vcat $ ((flip map) (zip3 stepls prescribers tagtys) $ \ (stp,tg,ty) -> U.app "CnC::debug::trace" [(text$ step_obj$ fromAtom stp), (dubquotes stp)] <> semi) ++ ((flip map) (AM.toList tags) $ \ (tg,_) -> U.app "CnC::debug::trace" [textAtom tg, dubquotes tg] <> semi) ++ ((flip map) (AM.toList items) $ \ (itC,_) -> U.app "CnC::debug::trace" [textAtom itC, dubquotes itC] <> semi) )] ++ -------------------------------------------------------------------------------- [nest 6$ execEasyEmit$ (maybeComment [t"",t"Finally global state added by plugins is initalized:"] $ forM_ (AM.toList plug_map) $ \ (stpC,hooks) -> sequence_ $ map (snd . addGlobalState) hooks )] ) ------------------------------------------------------------ -- Finish up ------------------------------------------------------------ -- This is the "footer" for the document. putS$ "\n\n#endif // "++appname++"_H_ALREADY_INCLUDED\n" return () -------------------------------------------------------------------------------- -- Produce the prototype for a single step. emitStep appname name ty = putD$ struct (t name) (t ("template < class ctxt > ") $$ t "int execute(" <+> constRefType ty <+> t "tag," <+> t "ctxt & c) const;" --t appname <> t "_context & c) const;" ) -- Make a type both const and a reference. -- TODO: add some error checking here to see if it is already const or reference... constRefType ty = t "const" <+> cppType ty <+> t "&" ------------------------------------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------------------------------------ -- NOTE: This routine is multiplexed so that it can generate a wrapper -- either for the top-level context (for use by the environment) or for individual step's contexts. -- To call for the environment, simply call with name (stp) = special_environment_name -- --generate_wrapper_context :: Atom -> Type -> EasyEmit () generate_wrapper_context (CodeGenConfig{gendebug}) (spec @ CncSpec{appname, steps, tags, items, reductions, graph, realmap}) stp stpty plug_map maincontext usercontext = let is_top_context = (stp == toAtom special_environment_name) classname = if is_top_context then toDoc usercontext else privcontext stp fprintf = function$ Syn$t "fprintf" stderr = constant "stderr" abort = function$ Syn$t "abort" in do cppClass (Syn classname) (Syn empty) (do putS "\n public:\n" comm "First, state for the private context. Note one private context object is instantiated for EACH thread." when (not is_top_context) $ do comm "Cache the tag for each step instance:" var (TConst$ TPtr stpty) (s "tag") -- Execute plugin hooks: maybeComment [t"",t"Next, collection/thread local state used/generated by plugins:"] $ sequence_$ map (fst . addLocalState) (AM.findWithDefault [] stp plug_map) ------------------------------------------------------------ -- Wrap tag collections: ------------------------------------------------------------ comm "" comm "Wrappers for tag collections:" -- FIXME FIXME TODO TODO: Factor this to merge it with Item collections. forM_ (AM.toList tags) $ \ (tgC, Just ty) -> --var (TRef TTemplate "CnC::tag_collection" ty) (atomToSyn tgC) -- Unwrapped option, just a reference: --putD$ text "CnC::tag_collection" <> angles (cppType ty) <> t" & " <> textAtom tgC <> semi let wrapper = textAtom tgC <> t"_wrapper" member = t"m_" <> textAtom tgC in cppClass (Syn wrapper) (s"") (do putS "public:" var (TPtr$ doc2Ty$ classname) (s"m_context") var (TRef$ doc2Ty$ maincontext) (s"parent_context") putD$ t"CnC::tag_collection" <> angles (cppType ty) <> t" & " <> member <> semi $$ t"" comm "The constructor here needs to grab a reference from the main context:" cppConstructor (Syn wrapper) [(TRef$ litType maincontext, s"p"), (TPtr$ litType classname, s"c")] -- Args. [(Syn$ member, Syn$ t"p." <> textAtom tgC), (s"parent_context", s"p"), (s"m_context", s"c")] -- Initialization. (do return () -- set (s"m_context") (s"c") -- Body. -- set (s"parent_context") (s"&p") ) inlineFunDef voidTy (strToSyn "put") [TConst$ TRef ty] $ \ tagArg -> do let doplugs project = forM_ (AM.findWithDefault [] stp plug_map) $ \ hooks -> project hooks (s"m_context", s"parent_context", tgC) tagArg doplugs beforeTagPut EE.app (function$ Syn$ t "m_"<> textAtom tgC <> t".put") [tagArg] doplugs afterTagPut return () -- FIXME FIXME TODO TODO: Factor this to merge it with Item/Reduction collections. ) comm "" comm "PUBLIC MEMBERS: Tag collections are all wrapped for now:" forM_ (AM.toList tags) $ \ (tgC, Just ty1) -> (putD$ textAtom tgC <> t"_wrapper" <+> textAtom tgC <> semi) ------------------------------------------------------------ comm "" comm "Wrappers for reduction collections:" ------------------------------------------------------------ forM_ (AM.toList reductions) $ \ (redC, (op, init, Just (ty1,ty2))) -> do wrap_item_or_reduction_collection "reduction" redC ty1 ty2 classname stp plug_map fprintf stderr abort maincontext realmap gendebug graph comm "" comm "PUBLIC MEMBERS: Reduction collections are all wrapped for now:" forM_ (AM.toList reductions) $ \ (redC, (op, init, Just (ty1,ty2))) -> (putD$ textAtom redC <> t"_wrapper" <+> textAtom redC <> semi) ------------------------------------------------------------ comm "" comm "Wrappers for item collections:" ------------------------------------------------------------ forM_ (AM.toList items) $ \ (itC,Just (ty1,ty2)) -> do wrap_item_or_reduction_collection "item" itC ty1 ty2 classname stp plug_map fprintf stderr abort maincontext realmap gendebug graph comm "" comm "PUBLIC MEMBERS: Item collections are all wrapped for now:" forM_ (AM.toList items) $ \ (itC, Just (ty1,ty2)) -> (putD$ textAtom itC <> t"_wrapper" <+> textAtom itC <> semi) ------------------------------------------------------------ when is_top_context $ do comm "This member variable holds the *real* context:" var (doc2Ty maincontext) (s"p") comm "" let env_hooks = AM.findWithDefault [] (toAtom special_environment_name) plug_map ctxt_field = s"p" inlineFunDef voidTy (s "wait") [] $ \ () -> do forM_ env_hooks $ \ hooks -> beforeEnvWait hooks (MainCtxtRef$ ctxt_field) EE.app (function$ ctxt_field `dot` s"wait") [] forM_ env_hooks $ \ hooks -> afterEnvWait hooks (MainCtxtRef$ ctxt_field) return () comm "" comm "Constructor for the private/custom context: " if False -- is_top_context then do return () else cppConstructor (Syn classname) -- Name. (if is_top_context -- Args. then [] else [(TRef$ litType maincontext, s"p")]) -- Lots of initializers: ((if is_top_context -- In this case we initialize our own copy of the context rather than taking it as argument: then [(s"p", s"")] else []) ++ -- Item collections: ((flip map) (AM.toList items) $ \ (itC, Just (ty1,ty2)) -> (atomToSyn itC, s"p, this") ) ++ ((flip map) (AM.toList reductions) $ \ (redC, _) -> (atomToSyn redC, s"p, this") ) ++ ((flip map) (AM.toList tags) $ \ (tgC, Just ty) -> --(atomToSyn tgC, s"p" `dot` atomToSyn tgC) (atomToSyn tgC, s"p, this") -- This is for the new, WRAPPED, tag collection. )) (maybeComment [t"",t"Next, collection/thread-local state is initalized:"] $ sequence_$ map (snd . addLocalState) (AM.findWithDefault [] stp plug_map) ) -- Have to wrap tag collections as well just to redirect references to the main context: ) putS$ "\n" putS$ "\n" ------------------------------------------------------------------------------------------------------------------------ -- HACK: TEMPORARY: This needs refactoring. -- It has been factored out here, but clearly the interface is hugely complex: checkTagFun stp target getnbrs fprintf stderr abort tagty args realmap graph = -- TODO INSERT CORRECTNESS CHECKING HERE: let stpnd = realmap M.! (CGSteps stp) itemnd = realmap M.! target gctxt = context graph itemnd lnhbrs = getnbrs gctxt-- lpre' gctxt ++ lsuc' gctxt ls = filter (\ (nd,lab) -> nd == stpnd) lnhbrs -- [(_,tf)] = filter (\ (nd,lab) -> nd == stpnd)$ lpre' gctxt --[(_,tf)] = trace (" LENGTH "++ show (length ls) ++" "++ show stpnd ++" "++ show itemnd++" "++ show lnhbrs) ls in execEasyEmit$ case ls of -- If we have no relationship to that collection its an error to access it: [] -> do let str = printf " [tagfun_check] CnC graph violation: should not access collection '%s' from '%s'" (graphNodeName target :: String) (show stp) EE.app fprintf [stderr, stringconst$ str] EE.app abort[] [(_,Nothing)] -> comm " [tagfun_check] No tag function to check..." --((_,Just (TF args exps)) : []) -> ((_,Just (TF tfargs exps)) : tl) -> -- TEMPTOGGLE ... permissive, ignoring additional tag functions! case (tfargs,exps) of ([arg], [exp]) -> do comm (" [tagfun_check] Checking tag function "++ show arg ++" -> "++ show exp) -- TODO: use normal variable decl here: putD$ tagty <+> (fromAtom arg) <+> t"=" <+> t"* m_context->tag" <> semi when (not$ null args)$ assert (head args EE.== Syn (pPrint exp)) -- FIXME -- afer factoring fix this head args _ -> error "internal error: tag function correctness not fully implemented yet. Finish me." _ -> error$ "internal error: tag function correctness codegen: \n w"++show ls wrap_item_or_reduction_collection which colName ty1 ty2 classname stp plug_map fprintf stderr abort maincontext realmap gendebug graph = ( let isReduction = case which of "reduction" -> True "item" -> False _ -> error "the helper function wrap_item_or_reduction_collection must take either 'reduction' or 'item'" tagty = cppType ty1 -- A reused bit of syntax for wrapper get/put methods: -- (This is one of those things that you don't want to duplicate, -- but it has too many arguments and is poorly abstracted.) wrapGP doret retty nm args isPut = -- First let's put together the function's arguments: let doplugs project = execEasyEmit$ -- FIXME: HACK: when (length args Prelude.>= 2) $ forM_ (AM.findWithDefault [] stp plug_map) $ \ hooks -> project hooks (Syn$ t$ snd$ head args, Syn$ t$ snd$ head$ tail args, colName) (Syn$ t$ snd$ head args, Syn$ t$ snd$ head$ tail args) in inlineFunDef retty (s nm) (map (doc2Ty . fst) args) $ \ (args::[Syntax]) -> do #if 1 putD$ (if gendebug -- Optionally include debugging assertions. then checkTagFun stp ((if isReduction then CGReductions else CGItems) colName) (if isPut then lpre' else lsuc') fprintf stderr abort tagty args realmap graph else empty) #endif -- Execute plugin hooks: putD$ (if isPut then doplugs (if isReduction then beforeReducerPut else beforeItemPut) else doplugs (if isReduction then beforeReducerGet else beforeItemGet)) -------------------------------------------------------------------------------- putD$ (if doret then t"return " else t"") <> t "m_"<> textAtom colName <> t"." <> t nm <> parens (commacat$ map deSyn args) <> semi -------------------------------------------------------------------------------- putD$ (if isPut then doplugs (if isReduction then afterReducerPut else afterItemPut) else doplugs (if isReduction then afterReducerGet else afterItemGet)) -- Basic get or put: basicGP nm isPut = wrapGP False voidTy nm [(mkConstRef tagty, "tag"), ((if isPut then mkConstRef else mkRef) (cppType ty2) , "ref")] isPut wrapper = textAtom colName <> t"_wrapper" member = t"m_" <> textAtom colName in do comm$ "The "++ which ++" collection wrapper: A 'NoOp' wrapper class that does nothing: " cppClass (Syn wrapper) (s"") (do putS "public:" putD$ mkPtr classname <> t" m_context;" putD$ mkPtr maincontext <> t" parent_context;\n" putD$ t("CnC::"++ which ++"_collection") <> angles (cppType ty1 <>commspc<> cppType ty2) <> t" & " <> member <> semi $$ t"" comm "The constructor here needs to grab a reference from the main context:" cppConstructor (Syn wrapper) -- Name. [(TRef$ litType maincontext, s"p"), (TPtr$ litType classname, s"c")] [(Syn$ member, Syn$ t"p." <> textAtom colName)] (do set (s"m_context") (s"c") set (s"parent_context") (s"&p")) -- Just three methods: two variants of get and one put. basicGP "get" False basicGP "put" True -- Hackish: adding the done and done_all methods: when isReduction $ do wrapGP False voidTy "done" [(mkConstRef (cppType ty1),"tag")] False wrapGP False voidTy "all_done" [] False return () if oldstyle_get_method then do wrapGP True ty2 "get" [(mkConstRef (cppType ty1),"tag")] False return () else return () ) putS "") ------------------------------------------------------------------------------------------------------------------------ -- CODING HINTS GENERATION ------------------------------------------------------------------------------------------------------------------------ -- UNFINISHED codingHints :: StringBuilder m => Bool -> CncSpec -> m () codingHints old_05_api (spec @ CncSpec{..}) = do putD $ (hangbraces (t"foo") 4 (t"baz") ) -------------------------------------------------------------------------------- -- EXAMPLE: OLD CODING HINTS: {- /**************************************************************************** /* The following code provides an example of what the user code that invokes /* this graph might look, using the inputs and outputs defined for the /* environment (ENV). /***************************************************************************/ #include "mandel.h" // Create an instance of the context class which defines the graph mandel_context c; // Debug trace can be enabled for a collection with the call: // CnC::debug::trace( c.position, "position" ); // For each item from the environment (ENV), put the item using the // proper tag c.data.put( data_Tag, ... ); c.max_depth.put( max_depth_Tag, ... ); // For each tag value from the environment (ENV), put the tag into // the proper tag collection c.position.put( position_Tag ); // Wait for all steps to finish c.wait(); // For each output to the environment (ENV), get the item using the // proper tag int pixel_ENV; pixel.get( pair(...), pixel_ENV ); /********************************************************************* /* The following code provides an example of what the user Step code /* might look like for this Step, using the inputs and outputs defined /* in the context. /********************************************************************/ int compute::execute(const pair & t, mandel_context & c ) const { // For each input item for this step retrieve the item using the proper tag value complex data_instance; c.data.get( pair(...), data_instance ); int max_depth_instance; c.max_depth.get( int(...), max_depth_instance ); // Step implementation logic goes here ... // For each output item for this step, put the new item using the proper tag value c.pixel.put( pair(...), ... ); return CnC::CNC_Success; } -}