diff --git a/backends/GenerateCPPCSP.hs b/backends/GenerateCPPCSP.hs index 3928518..b01a33b 100644 --- a/backends/GenerateCPPCSP.hs +++ b/backends/GenerateCPPCSP.hs @@ -423,26 +423,56 @@ cppgenInputItem ops c (A.InVariable m v) call genVariable ops v tell [";\n"] --- | If we are sending an array, we use the versionToSend function to coerce away any annoying const tags on the array data: -genJustOutputItem :: GenOps -> A.OutputItem -> CGen() -genJustOutputItem ops (A.OutCounted m ce ae) - = do call genExpression ops ae - tell[" .sliceFor("] - call genExpression ops ce - tell[") .versionToSend() "] -genJustOutputItem ops (A.OutExpression m e) - = do t <- typeOfExpression e - call genExpression ops e - case t of - (A.Array _ _) -> tell [" .versionToSend() "] - _ -> return () - cppgenOutputItem :: GenOps -> A.Variable -> A.OutputItem -> CGen () -cppgenOutputItem ops chan item - = do genCPPCSPChannelOutput ops chan - tell ["<<"] - genJustOutputItem ops item - tell [";"] +cppgenOutputItem ops chan item + = case item of + (A.OutCounted m (A.ExprVariable _ cv) (A.ExprVariable _ av)) -> + do chan' + tell ["< + do t <- typeOfVariable chan + tsv <- typeOfVariable sv + case (byteArrayChan t,tsv) of + (True,_) -> do chan' + tell ["< do tell ["tockSendArray("] + chan' + tell [","] + call genVariable ops sv + tell [");"] + (False,_) -> do chan' + tell ["<<"] + genNonPoint sv + tell [";"] + where + chan' = genCPPCSPChannelOutput ops chan + + byteArrayChan :: A.Type -> Bool + byteArrayChan (A.Chan _ _ (A.UserProtocol _)) = True + byteArrayChan (A.Chan _ _ A.Any) = True + byteArrayChan (A.Chan _ _ (A.Counted _ _)) = True + byteArrayChan _ = False + + genPoint :: A.Variable -> CGen() + genPoint v = do t <- typeOfVariable v + when (not $ isPoint t) $ tell ["&"] + call genVariable ops v + genNonPoint :: A.Variable -> CGen() + genNonPoint v = do t <- typeOfVariable v + when (isPoint t) $ tell ["*"] + call genVariable ops v + isPoint :: A.Type -> Bool + isPoint (A.Record _) = True + isPoint (A.Array _ _) = True + isPoint _ = False -- FIXME Should be a generic helper somewhere (along with the others from GenerateC) -- | Helper function to place a comma between items, but not before or after @@ -1028,6 +1058,12 @@ cppgenType ops (A.Chan dir attr t) cppTypeInsideChannel ops A.Any = tell ["tockSendableArrayOfBytes"] cppTypeInsideChannel ops (A.Counted _ _) = tell ["tockSendableArrayOfBytes"] cppTypeInsideChannel ops (A.UserProtocol _) = tell ["tockSendableArrayOfBytes"] + cppTypeInsideChannel ops (A.Array ds t) + = do tell ["tockSendableArray<"] + call genType ops t + tell [","] + tell $ intersperse "*" [case d of A.Dimension n -> show n | d <- ds] + tell [">/**/"] cppTypeInsideChannel ops t = call genType ops t cppgenType ops t = case call getScalarType ops t of diff --git a/backends/GenerateCTest.hs b/backends/GenerateCTest.hs index 0d55054..1800aa7 100644 --- a/backends/GenerateCTest.hs +++ b/backends/GenerateCTest.hs @@ -243,6 +243,13 @@ testGenType = TestList ,testBoth "GenType 900" "Channel" "csp::One2OneChannel" (tcall genType $ A.Chan A.DirUnknown (A.ChanAttributes False False) $ A.UserProtocol (simpleName "foo")) --Counted: ,testBoth "GenType 1000" "Channel" "csp::One2OneChannel" (tcall genType $ A.Chan A.DirUnknown (A.ChanAttributes False False) $ A.Counted A.Int A.Int) + + --Channels of arrays are special in C++: + ,testBoth "GenType 1100" "Channel" "csp::One2OneChannel>" + (tcall genType $ A.Chan A.DirUnknown (A.ChanAttributes False False) $ A.Array [A.Dimension 6] A.Int) + ,testBoth "GenType 1101" "Channel" "csp::One2OneChannel>" + (tcall genType $ A.Chan A.DirUnknown (A.ChanAttributes False False) $ A.Array [A.Dimension 6,A.Dimension 7,A.Dimension 8] A.Int) + ] @@ -692,39 +699,54 @@ testOutput = TestList ,testBothSame "testOutput 1" "^" ((tcall2 genOutput undefined [undefined]) . overOutputItem) ,testBothSame "testOutput 2" "^^^" ((tcall2 genOutput undefined [undefined,undefined,undefined]) . overOutputItem) - ,testBothS "testOutput 100" "ChanOutInt(@,bar_foo);^" "tockSendInt(@->writer(),bar_foo);^" ((tcall3 genOutputCase (A.Variable emptyMeta chan) bar []) . overOutput) state - ,testBothS "testOutput 101" "ChanOutInt(@,bar_foo);^" "tockSendInt(@,bar_foo);^" ((tcall3 genOutputCase (A.Variable emptyMeta chanOut) bar []) . overOutput) state + ,testBothS "testOutput 100" "ChanOutInt((&c),bar_foo);^" "tockSendInt((&c)->writer(),bar_foo);^" ((tcall3 genOutputCase (A.Variable emptyMeta chan) bar []) . overOutput) state + ,testBothS "testOutput 101" "ChanOutInt(cOut,bar_foo);^" "tockSendInt(cOut,bar_foo);^" ((tcall3 genOutputCase (A.Variable emptyMeta chanOut) bar []) . overOutput) state --Integers are a special case in the C backend: - ,testOutputItem 200 "ChanOutInt(@,$);" ("@->writer()<<$;", "@<<$;") (A.OutExpression emptyMeta $ intLiteral 0) A.Int - ,testOutputItem 201 "ChanOutInt(@,$);" ("@->writer()<<$;", "@<<$;") (A.OutExpression emptyMeta $ exprVariable "x") A.Int + ,testOutputItem 201 "ChanOutInt(#,x);" "#<writer()<<$;", "@<<$;") (A.OutExpression emptyMeta $ exprVariable "x") A.Int64 - --A record type on the channel of the right type (because records are pointed to, so they shouldn't need the address-of operator): - ,testOutputItem 202 "ChanOut(@,@,^);" ("@->writer()<<$;", "@<<$;") (A.OutExpression emptyMeta $ exprVariable "x") (A.Record foo) + ,testOutputItem 202 "ChanOut(#,&x,^);" "#<writer()<<$;", "@<<$;") (A.OutExpression emptyMeta $ exprVariable "x") (A.Array [A.Dimension 6] A.Int) - ,testOutputItem 204 "ChanOut(@,@,^);" ("@->writer()<<$;", "@<<$;") (A.OutExpression emptyMeta $ exprVariable "x") (A.Array [A.Dimension 6, A.Dimension 7, A.Dimension 8] A.Int) + ,testOutputItem 204 "ChanOut(#,x,^);" "tockSendArray(#,x);" (A.OutExpression emptyMeta $ exprVariable "x") (A.Array [A.Dimension 6] A.Int) + ,testOutputItem 205 "ChanOut(#,x,^);" "tockSendArray(#,x);" (A.OutExpression emptyMeta $ exprVariable "x") (A.Array [A.Dimension 6, A.Dimension 7, A.Dimension 8] A.Int) --A counted array: - ,testOutputItem 205 "ChanOutInt(@,$);ChanOut(@,@,$*^);" ("tockSendInt(@->writer(),$);@->writer()<<$;", "tockSendInt(@,$);@<<$;") + ,testOutputItem 206 "ChanOutInt(#,x);ChanOut(#,xs,x*^);" "#<writer(),$);@->writer()<<$;", "tockSendInt(@,$);@<<$;") (A.OutCounted emptyMeta (exprVariable "x") (exprVariable "xs")) (A.Counted A.Int (A.Array [A.Dimension 8] A.Int)) - --TODO add a pass that makes sure all outputs are either of type Int or are variables. Including count for counted items + --TODO add a pass that makes sure all outputs are variables. Including count for counted items - --TODO test sending things that are part of protocols (this will require different code in the C++ backend) + --Test sending things that are part of protocols (this will require different code in the C++ backend) + ,testOutputItemProt 301 "ChanOutInt(#,x);" "#< String -> (String,String) -> A.OutputItem -> A.Type -> Test - testOutputItem n eC (eCPP,eCPP_Out) oi t = TestList + testOutputItem :: Int -> String -> String -> A.OutputItem -> A.Type -> Test + testOutputItem n eC eCPP oi t = testOutputItem' n eC eCPP oi t t + -- Tests sending things over channels of protocol or ANY + testOutputItemProt :: Int -> String -> String -> A.OutputItem -> A.Type -> Test + testOutputItemProt n eC eCPP oi t = TestList [testOutputItem' n eC eCPP oi t (A.UserProtocol foo),testOutputItem' n eC eCPP oi t A.Any] + + testOutputItem' :: Int -> String -> String -> A.OutputItem -> A.Type -> A.Type -> Test + testOutputItem' n eC eCPP oi t ct = TestList [ - testBothS ("testOutput " ++ show n) eC eCPP ((tcall2 genOutputItem (A.Variable emptyMeta $ simpleName "c") oi) . over) (state A.DirUnknown) - ,testBothS ("testOutput [out] " ++ show n) eC eCPP_Out ((tcall2 genOutputItem (A.Variable emptyMeta $ simpleName "c") oi) . over) (state A.DirOutput) + testBothS ("testOutput " ++ show n) (hashIs "(&c)" eC) (hashIs "(&c)->writer()" eCPP) ((tcall2 genOutputItem (A.Variable emptyMeta $ simpleName "c") oi) . over) (state A.DirUnknown) + ,testBothS ("testOutput [out] " ++ show n) (hashIs "c" eC) (hashIs "c" eCPP) ((tcall2 genOutputItem (A.Variable emptyMeta $ simpleName "c") oi) . over) (state A.DirOutput) ] where - state dir = do defineName (simpleName "c") $ simpleDefDecl "c" (A.Chan dir (A.ChanAttributes False False) t) + hashIs x y = subRegex (mkRegex "#") y x + + state dir = do defineName (simpleName "c") $ simpleDefDecl "c" (A.Chan dir (A.ChanAttributes False False) ct) case t of A.Counted t t' -> do defineName (simpleName "x") $ simpleDefDecl "x" t defineName (simpleName "xs") $ simpleDefDecl "xs" (A.Array [A.Dimension 6] t') @@ -734,9 +756,9 @@ testOutput = TestList chanOut = simpleName "cOut" state = do defineName chan $ simpleDefDecl "c" (A.Chan A.DirUnknown (A.ChanAttributes False False) $ A.UserProtocol foo) defineName chanOut $ simpleDefDecl "cOut" (A.Chan A.DirOutput (A.ChanAttributes False False) $ A.UserProtocol foo) - overOutput ops = ops {genVariable = override1 at, genOutput = override2 caret} + overOutput ops = ops {genOutput = override2 caret} overOutputItem ops = ops {genOutputItem = override2 caret} - over ops = ops {genVariable = override1 at, genExpression = override1 dollar, genBytesIn = override2 caret} + over ops = ops {genBytesIn = override2 caret} ---Returns the list of tests: tests :: Test diff --git a/tock_support_cppcsp.h b/tock_support_cppcsp.h index ae33c84..0d7e48e 100644 --- a/tock_support_cppcsp.h +++ b/tock_support_cppcsp.h @@ -313,35 +313,6 @@ public: return tockArrayView((const T*)realArray,std::make_pair(dims,totalSubDim)); } - inline tockArrayView::type,DIMS> versionToSend() - { - return tockArrayView::type,DIMS>(const_cast::type*>(realArray),std::make_pair(dims,totalSubDim)); - } - - inline const tockArrayView::type,DIMS> versionToSend() const - { - return tockArrayView::type,DIMS>(const_cast::type*>(realArray),std::make_pair(dims,totalSubDim)); - } - - inline tockArrayView& operator=(const tockArrayView& tav) - { - //TODO investigate speeding up when T is primitive (maybe there's a boost class for that?) - - unsigned n = tav.size(); - for (unsigned i = 0;i < n;i++) - { - realArray[i] = tav.realArray[i]; - } - - dims = tav.dims; - totalSubDim = tav.totalSubDim; - return *this; - } - - inline tockArrayView& operator=(const tockAny&) - { - //TODO later on - } }; template @@ -405,3 +376,29 @@ void tockRecvInt(const csp::Chanin& c, unsigned int* p tockSendableArrayOfBytes d(sizeof(unsigned int),p); c >> d; } + +template +class tockSendableArray +{ +private: + tockSendableArrayOfBytes aob; +public: + template + inline explicit tockSendableArray(const tockArrayView& arr) + : aob(N*sizeof(T),arr.data()) + { + } +}; + +template +void tockSendArray(const csp::Chanout< tockSendableArray >& out,const tockArrayView& arr) +{ + out << tockSendableArray(arr); +} + +template +void tockRecvArray(const csp::Chanin< tockSendableArray >& in,const tockArrayView& arr) +{ + tockSendableArray tsa(arr); + in >> tsa; +}