2 % (c) The AQUA Project, Glasgow University, 1993-1996
4 \section[SimplEnv]{Environment stuff for the simplifier}
8 nullSimplEnv, combineSimplEnv,
9 pprSimplEnv, -- debugging only
11 extendTyEnv, extendTyEnvList, extendTyEnvEnv,
14 extendIdEnvWithAtom, extendIdEnvWithAtoms,
15 extendIdEnvWithClone, extendIdEnvWithClones,
20 lookupRhsInfo, lookupOutIdEnv, isEvaluated,
21 extendEnvGivenBinding, extendEnvGivenNewRhs,
22 extendEnvGivenRhsInfo, extendEnvGivenInlining,
26 getSwitchChecker, switchIsSet, getSimplIntSwitch,
27 switchOffInlining, setCaseScrutinee,
29 setEnclosingCC, getEnclosingCC,
38 InId, InBinder, InBinding, InType,
39 OutId, OutBinder, OutBinding, OutType,
41 InExpr, InAlts, InDefault, InArg,
42 OutExpr, OutAlts, OutDefault, OutArg
45 #include "HsVersions.h"
47 import BinderInfo ( orBinderInfo, andBinderInfo, noBinderInfo, isOneOcc,
49 BinderInfo {-instances, too-}
51 import CmdLineOpts ( switchIsOn, intSwitchSet, opt_UnfoldingCreationThreshold,
52 SimplifierSwitch(..), SwitchResult(..)
55 import CoreUnfold ( mkFormSummary, couldBeSmallEnoughToInline, whnfOrBottom,
56 Unfolding(..), UfExpr, RdrName,
57 SimpleUnfolding(..), FormSummary(..),
58 calcUnfoldingGuidance, UnfoldingGuidance(..)
60 import CoreUtils ( coreExprCc, unTagBinders )
61 import CostCentre ( CostCentre, subsumedCosts, noCostCentreAttached )
62 import FiniteMap -- lots of things
63 import Id ( idType, getIdUnfolding, getIdStrictness, idWantsToBeINLINEd,
64 applyTypeEnvToId, getInlinePragma,
65 nullIdEnv, growIdEnvList, rngIdEnv, lookupIdEnv,
66 addOneToIdEnv, modifyIdEnv, mkIdSet, modifyIdEnv_Directly,
67 IdEnv, IdSet, GenId, Id )
68 import Literal ( isNoRepLit, Literal{-instances-} )
69 import Maybes ( maybeToBool, expectJust )
70 import Name ( isLocallyDefined )
71 import OccurAnal ( occurAnalyseExpr )
72 import PprCore -- various instances
73 import PprType ( GenType, GenTyVar )
74 import Type ( instantiateTy, Type )
75 import TyVar ( emptyTyVarEnv, plusTyVarEnv, addToTyVarEnv, growTyVarEnvList,
76 TyVarEnv, GenTyVar{-instance Eq-} ,
79 import Unique ( Unique{-instance Outputable-}, Uniquable(..) )
80 import UniqFM ( addToUFM, addToUFM_C, ufmToList )
81 import Util ( Eager, appEager, returnEager, runEager,
82 zipEqual, thenCmp, cmpList )
86 %************************************************************************
88 \subsection[Simplify-types]{Type declarations}
90 %************************************************************************
93 type InId = Id -- Not yet cloned
94 type InBinder = (InId, BinderInfo)
95 type InType = Type -- Ditto
96 type InBinding = SimplifiableCoreBinding
97 type InExpr = SimplifiableCoreExpr
98 type InAlts = SimplifiableCoreCaseAlts
99 type InDefault = SimplifiableCoreCaseDefault
100 type InArg = SimplifiableCoreArg
102 type OutId = Id -- Cloned
104 type OutType = Type -- Cloned
105 type OutBinding = CoreBinding
106 type OutExpr = CoreExpr
107 type OutAlts = CoreCaseAlts
108 type OutDefault = CoreCaseDefault
109 type OutArg = CoreArg
111 type SwitchChecker = SimplifierSwitch -> SwitchResult
114 %************************************************************************
116 \subsubsection{The @SimplEnv@ type}
118 %************************************************************************
121 INVARIANT: we assume {\em no shadowing}. (ToDo: How can we ASSERT
122 this? WDP 94/06) This allows us to neglect keeping everything paired
123 with its static environment.
125 The environment contains bindings for all
127 {\em locally-defined}
130 For such things, any unfolding is found in the environment, not in the
131 Id. Unfoldings in the Id itself are used only for imported things
132 (otherwise we get trouble because we have to simplify the unfoldings
133 inside the Ids, etc.).
139 CostCentre -- The enclosing cost-centre (when profiling)
140 InTypeEnv -- Maps old type variables to new clones
141 InIdEnv -- Maps locally-bound Ids to new clones
142 OutIdEnv -- Info about the values of OutIds
143 ConAppMap -- Maps constructor applications back to OutIds
146 nullSimplEnv :: SwitchChecker -> SimplEnv
149 = SimplEnv sw_chkr subsumedCosts emptyTyVarEnv nullIdEnv nullIdEnv nullConApps
151 combineSimplEnv :: SimplEnv -> SimplEnv -> SimplEnv
152 combineSimplEnv env@(SimplEnv chkr _ _ _ out_id_env con_apps)
153 new_env@(SimplEnv _ encl_cc ty_env in_id_env _ _ )
154 = SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps
156 pprSimplEnv (SimplEnv _ _ ty_env in_id_env out_id_env con_apps) = panic "pprSimplEnv"
160 %************************************************************************
162 \subsubsection{Command-line switches}
164 %************************************************************************
167 getSwitchChecker :: SimplEnv -> SwitchChecker
168 getSwitchChecker (SimplEnv chkr _ _ _ _ _) = chkr
170 switchIsSet :: SimplEnv -> SimplifierSwitch -> Bool
171 switchIsSet (SimplEnv chkr _ _ _ _ _) switch
172 = switchIsOn chkr switch
174 getSimplIntSwitch :: SwitchChecker -> (Int-> SimplifierSwitch) -> Int
175 getSimplIntSwitch chkr switch
176 = expectJust "getSimplIntSwitch" (intSwitchSet chkr switch)
179 setCaseScrutinee :: SimplEnv -> SimplEnv
180 setCaseScrutinee (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
181 = SimplEnv chkr' encl_cc ty_env in_id_env out_id_env con_apps
183 chkr' SimplCaseScrutinee = SwBool True
184 chkr' other = chkr other
187 @switchOffInlining@ is used to prepare the environment for simplifying
188 the RHS of an Id that's marked with an INLINE pragma. It is going to
189 be inlined wherever they are used, and then all the inlining will take
190 effect. Meanwhile, there isn't much point in doing anything to the
191 as-yet-un-INLINEd rhs. Furthremore, it's very important to switch off
193 (a) not doing so will inline a worker straight back into its wrapper!
195 and (b) Consider the following example
200 in ...g...g...g...g...g...
202 Now, if that's the ONLY occurrence of f, it will be inlined inside g,
203 and thence copied multiple times when g is inlined.
205 Andy disagrees! Example:
206 all xs = foldr (&&) True xs
207 any p = all . map p {-# INLINE any #-}
209 Problem: any won't get deforested, and so if it's exported and
210 the importer doesn't use the inlining, (eg passes it as an arg)
211 then we won't get deforestation at all.
212 We havn't solved this problem yet!
214 We prepare the envt by simply discarding the out_id_env, which has
215 all the unfolding info. At one point we did it by modifying the chkr so
216 that it said "EssentialUnfoldingsOnly", but that prevented legitmate, and important,
217 simplifications happening in the body of the RHS.
220 switchOffInlining :: SimplEnv -> SimplEnv
221 switchOffInlining (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
222 = SimplEnv chkr encl_cc ty_env in_id_env nullIdEnv nullConApps
225 %************************************************************************
227 \subsubsection{The ``enclosing cost-centre''}
229 %************************************************************************
232 setEnclosingCC :: SimplEnv -> CostCentre -> SimplEnv
234 setEnclosingCC (SimplEnv chkr _ ty_env in_id_env out_id_env con_apps) encl_cc
235 = SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps
237 getEnclosingCC :: SimplEnv -> CostCentre
238 getEnclosingCC (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps) = encl_cc
241 %************************************************************************
243 \subsubsection{The @TypeEnv@ part}
245 %************************************************************************
248 type TypeEnv = TyVarEnv Type
249 type InTypeEnv = TypeEnv -- Maps InTyVars to OutTypes
251 extendTyEnv :: SimplEnv -> TyVar -> Type -> SimplEnv
252 extendTyEnv (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps) tyvar ty
253 = SimplEnv chkr encl_cc new_ty_env in_id_env out_id_env con_apps
255 new_ty_env = addToTyVarEnv ty_env tyvar ty
257 extendTyEnvList :: SimplEnv -> [(TyVar,Type)] -> SimplEnv
258 extendTyEnvList (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps) pairs
259 = SimplEnv chkr encl_cc new_ty_env in_id_env out_id_env con_apps
261 new_ty_env = growTyVarEnvList ty_env pairs
263 extendTyEnvEnv :: SimplEnv -> TypeEnv -> SimplEnv
264 extendTyEnvEnv (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps) new_ty_env
265 = SimplEnv chkr encl_cc new_ty_env in_id_env out_id_env con_apps
267 new_ty_env = ty_env `plusTyVarEnv` new_ty_env
269 simplTy (SimplEnv _ _ ty_env _ _ _) ty = returnEager (instantiateTy ty_env ty)
270 simplTyInId (SimplEnv _ _ ty_env _ _ _) id = returnEager (applyTypeEnvToId ty_env id)
273 %************************************************************************
275 \subsubsection{The ``Id env'' part}
277 %************************************************************************
280 type InIdEnv = IdEnv OutArg -- Maps InIds to their value
281 -- Usually this is just the cloned Id, but if
282 -- if the orig defn is a let-binding, and
283 -- the RHS of the let simplifies to an atom,
284 -- we just bind the variable to that atom, and
289 lookupId :: SimplEnv -> Id -> Eager ans OutArg
291 lookupId (SimplEnv _ _ _ in_id_env _ _) id
292 = case (lookupIdEnv in_id_env id) of
293 Just atom -> returnEager atom
294 Nothing -> returnEager (VarArg id)
301 -> OutArg{-Val args only, please-}
304 extendIdEnvWithAtom (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
305 (in_id,occ_info) atom
307 LitArg _ -> SimplEnv chkr encl_cc ty_env new_in_id_env out_id_env con_apps
308 VarArg out_id -> SimplEnv chkr encl_cc ty_env new_in_id_env
309 (modifyOccInfo out_id_env (uniqueOf out_id, occ_info)) con_apps
310 --SimplEnv chkr encl_cc ty_env new_in_id_env new_out_id_env con_apps
312 new_in_id_env = addOneToIdEnv in_id_env in_id atom
314 new_out_id_env = case atom of
315 LitArg _ -> out_id_env
316 VarArg out_id -> modifyOccInfo out_id_env (uniqueOf out_id, occ_info)
319 extendIdEnvWithAtoms :: SimplEnv -> [(InBinder, OutArg)] -> SimplEnv
320 extendIdEnvWithAtoms = foldr (\ (bndr,val) env -> extendIdEnvWithAtom env bndr val)
323 extendIdEnvWithClone :: SimplEnv -> InBinder -> OutId -> SimplEnv
325 extendIdEnvWithClone (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
327 = SimplEnv chkr encl_cc ty_env new_in_id_env out_id_env con_apps
329 new_in_id_env = addOneToIdEnv in_id_env in_id (VarArg out_id)
331 extendIdEnvWithClones :: SimplEnv -> [InBinder] -> [OutId] -> SimplEnv
332 extendIdEnvWithClones (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
334 = SimplEnv chkr encl_cc ty_env new_in_id_env out_id_env con_apps
336 new_in_id_env = growIdEnvList in_id_env bindings
337 bindings = zipEqual "extendIdEnvWithClones"
338 [id | (id,_) <- in_binders]
342 %************************************************************************
344 \subsubsection{The @OutIdEnv@}
346 %************************************************************************
349 The domain of @OutIdInfo@ is some, but not necessarily all, in-scope @OutId@s;
350 both locally-bound ones, and perhaps some imported ones too.
353 type OutIdEnv = IdEnv (OutId, BinderInfo, RhsInfo)
357 The "Id" part is just so that we can recover the domain of the mapping, which
358 IdEnvs don't allow directly.
360 The @BinderInfo@ tells about the occurrences of the @OutId@.
361 Anything that isn't in here should be assumed to occur many times.
362 We keep this info so we can modify it when something changes.
364 The @RhsInfo@ part tells about the value to which the @OutId@ is bound.
367 data RhsInfo = NoRhsInfo
368 | OtherLit [Literal] -- It ain't one of these
369 | OtherCon [Id] -- It ain't one of these
371 -- InUnfolding is used for let(rec) bindings that
372 -- are *definitely* going to be inlined.
373 -- We record the un-simplified RHS and drop the binding
374 | InUnfolding SimplEnv -- Un-simplified unfolding
375 SimplifiableCoreExpr -- (need to snag envts therefore)
377 | OutUnfolding CostCentre
378 SimpleUnfolding -- Already-simplified unfolding
380 lookupOutIdEnv :: SimplEnv -> OutId -> Maybe (OutId,BinderInfo,RhsInfo)
381 lookupOutIdEnv (SimplEnv _ _ _ _ out_id_env _) id = lookupIdEnv out_id_env id
383 lookupRhsInfo :: SimplEnv -> OutId -> RhsInfo
385 = case lookupOutIdEnv env id of
386 Just (_,_,info) -> info
389 modifyOutEnvItem :: (OutId, BinderInfo, RhsInfo)
390 -> (OutId, BinderInfo, RhsInfo)
391 -> (OutId, BinderInfo, RhsInfo)
392 modifyOutEnvItem (id, occ, info1) (_, _, info2)
393 = case (info1, info2) of
394 (OtherLit ls1, OtherLit ls2) -> (id,occ, OtherLit (ls1++ls2))
395 (OtherCon cs1, OtherCon cs2) -> (id,occ, OtherCon (cs1++cs2))
396 (_, NoRhsInfo) -> (id,occ, info1)
397 other -> (id,occ, info2)
402 isEvaluated :: RhsInfo -> Bool
403 isEvaluated (OtherLit _) = True
404 isEvaluated (OtherCon _) = True
405 isEvaluated (OutUnfolding _ (SimpleUnfolding ValueForm _ expr)) = True
406 isEvaluated other = False
412 mkSimplUnfoldingGuidance chkr out_id rhs
413 = calcUnfoldingGuidance (getInlinePragma out_id) opt_UnfoldingCreationThreshold rhs
415 extendEnvGivenRhsInfo :: SimplEnv -> OutId -> BinderInfo -> RhsInfo -> SimplEnv
416 extendEnvGivenRhsInfo env@(SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
417 out_id occ_info rhs_info
418 = SimplEnv chkr encl_cc ty_env in_id_env new_out_id_env con_apps
420 new_out_id_env = addToUFM_C modifyOutEnvItem out_id_env out_id
421 (out_id, occ_info, rhs_info)
426 modifyOccInfo out_id_env (uniq, new_occ)
427 = modifyIdEnv_Directly modify_fn out_id_env uniq
429 modify_fn (id,occ,rhs) = (id, orBinderInfo occ new_occ, rhs)
431 markDangerousOccs (SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps) atoms
432 = SimplEnv chkr encl_cc ty_env in_id_env new_out_id_env con_apps
434 new_out_id_env = foldl (modifyIdEnv modify_fn) out_id_env [v | VarArg v <- atoms]
435 modify_fn (id,occ,rhs) = (id, noBinderInfo, rhs)
440 extendEnvGivenInlining :: SimplEnv -> Id -> BinderInfo -> InExpr -> SimplEnv
441 extendEnvGivenInlining env@(SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
443 = SimplEnv chkr encl_cc ty_env in_id_env new_out_id_env con_apps
445 new_out_id_env = addToUFM out_id_env id (id, occ_info, InUnfolding env rhs)
448 %************************************************************************
450 \subsubsection{The @ConAppMap@ type}
452 %************************************************************************
454 The @ConAppMap@ maps applications of constructors (to value atoms)
455 back to an association list that says "if the constructor was applied
456 to one of these lists-of-Types, then this OutId is your man (in a
457 non-gender-specific sense)". I.e., this is a reversed mapping for
458 (part of) the main OutIdEnv
461 type ConAppMap = FiniteMap UnfoldConApp [([Type], OutId)]
464 = UCA OutId -- data constructor
465 [OutArg] -- *value* arguments; see use below
469 nullConApps = emptyFM
471 extendConApps con_apps id (Con con args)
472 = addToFM_C (\old new -> new++old) con_apps (UCA con val_args) [(ty_args,id)]
474 val_args = filter isValArg args -- Literals and Ids
475 ty_args = [ty | TyArg ty <- args] -- Just types
477 extendConApps con_apps id other_rhs = con_apps
481 lookForConstructor (SimplEnv _ _ _ _ _ con_apps) con args
482 = case lookupFM con_apps (UCA con val_args) of
485 Just assocs -> case [id | (tys, id) <- assocs,
486 and (zipWith (==) tys ty_args)]
491 val_args = filter isValArg args -- Literals and Ids
492 ty_args = [ty | TyArg ty <- args] -- Just types
496 NB: In @lookForConstructor@ we used (before Apr 94) to have a special case
497 for nullary constructors, but now we only do constructor re-use in
498 let-bindings the special case isn't necessary any more.
501 = -- Don't re-use nullary constructors; it's a waste. Consider
509 -- Here the False in the second case will get replace by "a", hardly
515 The main thing about @UnfoldConApp@ is that it has @Ord@ defined on
516 it, so we can use it for a @FiniteMap@ key.
519 instance Eq UnfoldConApp where
520 a == b = case (a `compare` b) of { EQ -> True; _ -> False }
521 a /= b = case (a `compare` b) of { EQ -> False; _ -> True }
523 instance Ord UnfoldConApp where
524 a <= b = case (a `compare` b) of { LT -> True; EQ -> True; GT -> False }
525 a < b = case (a `compare` b) of { LT -> True; EQ -> False; GT -> False }
526 a >= b = case (a `compare` b) of { LT -> False; EQ -> True; GT -> True }
527 a > b = case (a `compare` b) of { LT -> False; EQ -> False; GT -> True }
528 compare a b = cmp_app a b
530 cmp_app (UCA c1 as1) (UCA c2 as2)
531 = compare c1 c2 `thenCmp` cmpList cmp_arg as1 as2
533 -- ToDo: make an "instance Ord CoreArg"???
535 cmp_arg (VarArg x) (VarArg y) = x `compare` y
536 cmp_arg (LitArg x) (LitArg y) = x `compare` y
537 cmp_arg (TyArg x) (TyArg y) = panic "SimplEnv.cmp_app:TyArgs"
539 | tag x _LT_ tag y = LT
542 tag (VarArg _) = ILIT(1)
543 tag (LitArg _) = ILIT(2)
544 tag (TyArg _) = panic# "SimplEnv.cmp_app:TyArg"
548 @extendUnfoldEnvGivenRhs@ records in the UnfoldEnv info about the RHS
549 of a new binding. There is a horrid case we have to take care about,
550 due to Andr\'e Santos:
552 type Array_type b = Array Int b;
553 type Descr_type = (Int,Int);
555 tabulate :: (Int -> x) -> Descr_type -> Array_type x;
556 tabulate f (l,u) = listArray (l,u) [f i | i <- [l..u]];
560 f_aareorder::(Array_type Int) -> (Array_type t1) -> Array_type t1;
561 f_aareorder a_index a_ar=
563 f_aareorder' a_i= a_ar ! (a_index ! a_i)
564 } in tabulate f_aareorder' (bounds a_ar);
565 r_index=tabulate ((+) 1) (1,1);
566 arr = listArray (1,1) a_xs;
567 arg = f_aareorder r_index arr
570 Now, when the RHS of arg gets simplified, we inline f_aareorder to get
572 arg = let f_aareorder' a_i = arr ! (r_index ! a_i)
573 in tabulate f_aareorder' (bounds arr)
575 Note that r_index is not inlined, because it was bound to a_index which
576 occurs inside a lambda.
578 Alas, if elems is inlined, so that (elems arg) becomes (case arg of ...),
579 then arg is inlined. IF WE USE THE NEW VERSION OF arg, and re-occurrence
580 analyse it, we won't spot the inside-lambda property of r_index, so r_index
581 will get inlined inside the lambda. AARGH.
583 Solution: when we occurrence-analyse the new RHS we have to go back
584 and modify the info recorded in the UnfoldEnv for the free vars
585 of the RHS. In the example we'd go back and record that r_index is now used
589 extendEnvGivenNewRhs :: SimplEnv -> OutId -> OutExpr -> SimplEnv
590 extendEnvGivenNewRhs env out_id rhs
591 = extendEnvGivenBinding env noBinderInfo out_id rhs
593 extendEnvGivenBinding :: SimplEnv -> BinderInfo -> OutId -> OutExpr -> SimplEnv
594 extendEnvGivenBinding env@(SimplEnv chkr encl_cc ty_env in_id_env out_id_env con_apps)
596 = SimplEnv chkr encl_cc ty_env in_id_env new_out_id_env new_con_apps
598 new_out_id_env | okToInline (whnfOrBottom form)
599 (couldBeSmallEnoughToInline guidance)
601 = out_id_env_with_unfolding
604 -- Don't bother to extend the OutIdEnv unless there is some possibility
605 -- that the thing might be inlined. We check this by calling okToInline suitably.
607 new_con_apps = _scc_ "eegnr.conapps"
608 extendConApps con_apps out_id rhs
610 -- Modify the occ info for rhs's interesting free variables.
611 out_id_env_with_unfolding = _scc_ "eegnr.modify_occ"
612 foldl modifyOccInfo env1 full_fv_occ_info
613 -- NB: full_fv_occ_info *combines* the occurrence of the current binder
614 -- with the occurrences of its RHS's free variables. That's to take
616 -- let a = \x -> BIG in
618 -- in ...b...b...b...
619 -- Here "a" occurs exactly once. "b" simplifies to a small value.
620 -- So "b" will be inlined at each call site, and there's a good chance
621 -- that "a" will too. So we'd better modify "a"s occurrence info to
622 -- record the fact that it can now occur many times by virtue that "b" can.
624 full_fv_occ_info = _scc_ "eegnr.full_fv"
625 [ (uniq, fv_occ `andBinderInfo` occ_info)
626 | (uniq, fv_occ) <- ufmToList fv_occ_info
629 -- Add an unfolding and rhs_info for the new Id.
630 -- If the out_id is already in the OutIdEnv (which can happen if
631 -- the call to extendEnvGivenBinding is from extendEnvGivenNewRhs)
632 -- then just replace the unfolding, leaving occurrence info alone.
633 env1 = _scc_ "eegnr.modify_out"
634 addToUFM_C modifyOutEnvItem out_id_env out_id
635 (out_id, occ_info, rhs_info)
637 -- Occurrence-analyse the RHS
638 -- The "interesting" free variables we want occurrence info for are those
639 -- in the OutIdEnv that have only a single occurrence right now.
640 (fv_occ_info, template) = _scc_ "eegnr.occ-anal"
641 occurAnalyseExpr is_interesting rhs
643 is_interesting v = _scc_ "eegnr.mkidset"
644 case lookupIdEnv out_id_env v of
645 Just (_, occ, _) -> isOneOcc occ
648 -- Compute unfolding details
649 rhs_info = OutUnfolding unf_cc (SimpleUnfolding form guidance template)
650 form = _scc_ "eegnr.form_sum"
652 guidance = _scc_ "eegnr.guidance"
653 mkSimplUnfoldingGuidance chkr out_id rhs
655 -- Compute cost centre for thing
656 unf_cc | noCostCentreAttached expr_cc = encl_cc
657 | otherwise = expr_cc
659 expr_cc = coreExprCc rhs