Changed the behaviour of assignment for records

Previously, assignments of records were directly flattened into assignment of each of the fields.  Now, we instead generate a copy_<recordname> inline procedure for each record definition, and compile code that uses that (for C++, we could even make this an operator= implementation later on).  This allows us to re-use the proc later in the C/C++ backends if needed.
This commit is contained in:
Neil Brown 2008-02-29 16:36:47 +00:00
parent f5022228ba
commit 08d02bfb17

View File

@ -89,7 +89,7 @@ removeParAssign = doGeneric `extM` doProcess
-- | Turn assignment of arrays and records into multiple assignments. -- | Turn assignment of arrays and records into multiple assignments.
flattenAssign :: Data t => t -> PassM t flattenAssign :: Data t => t -> PassM t
flattenAssign = doGeneric `extM` doProcess flattenAssign = doGeneric `extM` doProcess `ext1M` doStructured
where where
doGeneric :: Data t => t -> PassM t doGeneric :: Data t => t -> PassM t
doGeneric = makeGeneric flattenAssign doGeneric = makeGeneric flattenAssign
@ -100,6 +100,13 @@ flattenAssign = doGeneric `extM` doProcess
assign m t v m' e assign m t v m' e
doProcess p = doGeneric p doProcess p = doGeneric p
doStructured :: Data a => A.Structured a -> PassM (A.Structured a)
doStructured (A.Spec m (A.Specification m' n t@(A.RecordType _ _ fs)) s)
= do procSpec <- recordCopyProc n m fs
s' <- doStructured s
return $ A.Spec m (A.Specification m' n t) (procSpec s')
doStructured s = doGeneric s
assign :: Meta -> A.Type -> A.Variable -> Meta -> A.Expression -> PassM A.Process assign :: Meta -> A.Type -> A.Variable -> Meta -> A.Expression -> PassM A.Process
assign m t@(A.Array _ _) v m' e = complexAssign m t v m' e assign m t@(A.Array _ _) v m' e = complexAssign m t v m' e
assign m t@(A.Record _) v m' e = complexAssign m t v m' e assign m t@(A.Record _) v m' e = complexAssign m t v m' e
@ -133,19 +140,30 @@ flattenAssign = doGeneric `extM` doProcess
(A.ExprVariable m' (A.ExprVariable m'
(A.SubscriptedVariable m' sub srcV)) (A.SubscriptedVariable m' sub srcV))
return $ A.Rep m rep $ A.Only m inner return $ A.Rep m rep $ A.Only m inner
A.Record _ -> A.Record n ->
-- Record assignments become a sequence of return $ A.Only m $ A.ProcCall m (n {A.nameName = "copy_" ++ A.nameName n})
-- assignments, one for each field. [A.ActualVariable A.Abbrev t destV, A.ActualVariable A.ValAbbrev t srcV]
do
fs <- recordFields m t
assigns <-
sequence [do let sub = A.SubscriptField m fName
assign m fType
(A.SubscriptedVariable m sub destV) m'
(A.ExprVariable m'
(A.SubscriptedVariable m' sub srcV))
| (fName, fType) <- fs]
return $ A.Several m $ map (A.Only m) assigns
return $ A.Seq m $ A.Spec m src $ A.Spec m dest body return $ A.Seq m $ A.Spec m src $ A.Spec m dest body
-- TODO could make this a separate pass if we wanted (to be run first)
recordCopyProc :: Data a => A.Name -> Meta -> [(A.Name, A.Type)] -> PassM (A.Structured a -> A.Structured a)
recordCopyProc n m fs
-- Record assignments become a sequence of
-- assignments, one for each field.
= do let t = A.Record n
(A.Specification _ nonceLHS _) <- makeNonceVariable "record_copy_arg" m t A.VariableName A.Abbrev
let destV = A.Variable m nonceLHS
(A.Specification _ nonceRHS _) <- makeNonceVariable "record_copy_arg" m t A.VariableName A.Abbrev
let srcV = A.Variable m nonceRHS
assigns <-
sequence [do let sub = A.SubscriptField m fName
assign m fType
(A.SubscriptedVariable m sub destV) m
(A.ExprVariable m
(A.SubscriptedVariable m sub srcV))
| (fName, fType) <- fs]
let code = A.Seq m $ A.Several m $ map (A.Only m) assigns
return (A.Spec m (A.Specification m (n {A.nameName = "copy_" ++ A.nameName n})
(A.Proc m A.InlineSpec [A.Formal A.Abbrev t nonceLHS, A.Formal A.ValAbbrev t nonceRHS] code)))