text:
{-# LANGUAGE BangPatterns #-} module OccurAnal ( occurAnalysePgm, occurAnalyseExpr, occurAnalyseExpr_NoBinderSwap ) where #include "HsVersions.h" import CoreSyn import CoreFVs import CoreUtils ( exprIsTrivial, isDefaultAlt, isExpandableApp ) import Id import Name( localiseName ) import BasicTypes import Module( Module ) import Coercion import VarSet import VarEnv import Var import Demand ( argOneShots, argsOneShots ) import Maybes ( orElse ) import Digraph ( SCC(..), stronglyConnCompFromEdgedVerticesR ) import Unique import UniqFM import Util import Outputable import FastString import Data.List\end{code} %************************************************************************ %* * \subsection[OccurAnal-main]{Counting occurrences: main function} %* * %************************************************************************ Here's the externally-callable interface: \begin{code}
occurAnalysePgm :: Module -- Used only in debug output -> (Activation -> Bool) -> [CoreRule] -> [CoreVect] -> VarSet -> CoreProgram -> CoreProgram occurAnalysePgm this_mod active_rule imp_rules vects vectVars binds | isEmptyVarEnv final_usage = binds' | otherwise -- See Note [Glomming] = WARN( True, hang (text "Glomming in" <+> ppr this_mod <> colon) 2 (ppr final_usage ) ) [Rec (flattenBinds binds')] where (final_usage, binds') = go (initOccEnv active_rule) binds initial_uds = addIdOccs emptyDetails (rulesFreeVars imp_rules `unionVarSet` vectsFreeVars vects `unionVarSet` vectVars) -- The RULES and VECTORISE declarations keep things alive! (For VECTORISE declarations, -- we only get them *until* the vectoriser runs. Afterwards, these dependencies are -- reflected in 'vectors' — see Note [Vectorisation declarations and occurrences].) -- Note [Preventing loops due to imported functions rules] imp_rules_edges = foldr (plusVarEnv_C unionVarSet) emptyVarEnv [ mapVarEnv (const maps_to) (exprFreeIds arg `delVarSetList` ru_bndrs imp_rule) | imp_rule <- imp_rules , let maps_to = exprFreeIds (ru_rhs imp_rule) `delVarSetList` ru_bndrs imp_rule , arg <- ru_args imp_rule ] go :: OccEnv -> [CoreBind] -> (UsageDetails, [CoreBind]) go _ [] = (initial_uds, []) go env (bind:binds) = (final_usage, bind' ++ binds') where (bs_usage, binds') = go env binds (final_usage, bind') = occAnalBind env env imp_rules_edges bind bs_usage occurAnalyseExpr :: CoreExpr -> CoreExpr -- Do occurrence analysis, and discard occurrence info returned occurAnalyseExpr = occurAnalyseExpr' True -- do binder swap occurAnalyseExpr_NoBinderSwap :: CoreExpr -> CoreExpr occurAnalyseExpr_NoBinderSwap = occurAnalyseExpr' False -- do not do binder swap occurAnalyseExpr' :: Bool -> CoreExpr -> CoreExpr occurAnalyseExpr' enable_binder_swap expr = snd (occAnal env expr) where env = (initOccEnv all_active_rules) {occ_binder_swap = enable_binder_swap} -- To be conservative, we say that all inlines and rules are active all_active_rules = \_ -> True\end{code} %************************************************************************ %* * \subsection[OccurAnal-main]{Counting occurrences: main function} %* * %************************************************************************ Bindings ~~~~~~~~ \begin{code}
occAnalBind :: OccEnv -- The incoming OccEnv -> OccEnv -- Same, but trimmed by (binderOf bind) -> IdEnv IdSet -- Mapping from FVs of imported RULE LHSs to RHS FVs -> CoreBind -> UsageDetails -- Usage details of scope -> (UsageDetails, -- Of the whole let(rec) [CoreBind]) occAnalBind env _ imp_rules_edges (NonRec binder rhs) body_usage | isTyVar binder -- A type let; we don't gather usage info = (body_usage, [NonRec binder rhs]) | not (binder `usedIn` body_usage) -- It's not mentioned = (body_usage, []) | otherwise -- It's mentioned in the body = (body_usage' +++ rhs_usage4, [NonRec tagged_binder rhs']) where (body_usage', tagged_binder) = tagBinder body_usage binder (rhs_usage1, rhs') = occAnalNonRecRhs env tagged_binder rhs rhs_usage2 = addIdOccs rhs_usage1 (idUnfoldingVars binder) rhs_usage3 = addIdOccs rhs_usage2 (idRuleVars binder) -- See Note [Rules are extra RHSs] and Note [Rule dependency info] rhs_usage4 = maybe rhs_usage3 (addIdOccs rhs_usage3) $ lookupVarEnv imp_rules_edges binder -- See Note [Preventing loops due to imported functions rules] occAnalBind _ env imp_rules_edges (Rec pairs) body_usage = foldr occAnalRec (body_usage, []) sccs -- For a recursive group, we -- * occ-analyse all the RHSs -- * compute strongly-connected components -- * feed those components to occAnalRec where bndr_set = mkVarSet (map fst pairs) sccs :: [SCC (Node Details)] sccs = {-# SCC "occAnalBind.scc" #-} stronglyConnCompFromEdgedVerticesR nodes nodes :: [Node Details] nodes = {-# SCC "occAnalBind.assoc" #-} map (makeNode env imp_rules_edges bndr_set) pairs\end{code} Note [Dead code] ~~~~~~~~~~~~~~~~ Dropping dead code for a cyclic Strongly Connected Component is done in a very simple way: the entire SCC is dropped if none of its binders are mentioned in the body; otherwise the whole thing is kept. The key observation is that dead code elimination happens after dependency analysis: so 'occAnalBind' processes SCCs instead of the original term's binding groups. Thus 'occAnalBind' does indeed drop 'f' in an example like letrec f = ...g... g = ...(...g...)... in ...g... when 'g' no longer uses 'f' at all (eg 'f' does not occur in a RULE in 'g'). 'occAnalBind' first consumes 'CyclicSCC g' and then it consumes 'AcyclicSCC f', where 'body_usage' won't contain 'f'. ------------------------------------------------------------ Note [Forming Rec groups] ~~~~~~~~~~~~~~~~~~~~~~~~~ We put bindings {f = ef; g = eg } in a Rec group if "f uses g" and "g uses f", no matter how indirectly. We do a SCC analysis with an edge f -> g if "f uses g". More precisely, "f uses g" iff g should be in scope wherever f is. That is, g is free in: a) the rhs 'ef' b) or the RHS of a rule for f (Note [Rules are extra RHSs]) c) or the LHS or a rule for f (Note [Rule dependency info]) These conditions apply regardless of the activation of the RULE (eg it might be inactive in this phase but become active later). Once a Rec is broken up it can never be put back together, so we must be conservative. The principle is that, regardless of rule firings, every variable is always in scope. * Note [Rules are extra RHSs] ~~~~~~~~~~~~~~~~~~~~~~~~~~~ A RULE for 'f' is like an extra RHS for 'f'. That way the "parent" keeps the specialised "children" alive. If the parent dies (because it isn't referenced any more), then the children will die too (unless they are already referenced directly). To that end, we build a Rec group for each cyclic strongly connected component, *treating f's rules as extra RHSs for 'f'*. More concretely, the SCC analysis runs on a graph with an edge from f -> g iff g is mentioned in (a) f's rhs (b) f's RULES These are rec_edges. Under (b) we include variables free in *either* LHS *or* RHS of the rule. The former might seems silly, but see Note [Rule dependency info]. So in Example [eftInt], eftInt and eftIntFB will be put in the same Rec, even though their 'main' RHSs are both non-recursive. * Note [Rule dependency info] ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The VarSet in a SpecInfo is used for dependency analysis in the occurrence analyser. We must track free vars in *both* lhs and rhs. Hence use of idRuleVars, rather than idRuleRhsVars in occAnalBind. Why both? Consider x = y RULE f x = v+4 Then if we substitute y for x, we'd better do so in the rule's LHS too, so we'd better ensure the RULE appears to mention 'x' as well as 'v' * Note [Rules are visible in their own rec group] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We want the rules for 'f' to be visible in f's right-hand side. And we'd like them to be visible in other functions in f's Rec group. E.g. in Note [Specialisation rules] we want f' rule to be visible in both f's RHS, and fs's RHS. This means that we must simplify the RULEs first, before looking at any of the definitions. This is done by Simplify.simplRecBind, when it calls addLetIdInfo. ------------------------------------------------------------ Note [Choosing loop breakers] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loop breaking is surprisingly subtle. First read the section 4 of "Secrets of the GHC inliner". This describes our basic plan. We avoid infinite inlinings by choosing loop breakers, and ensuring that a loop breaker cuts each loop. Fundamentally, we do SCC analysis on a graph. For each recursive group we choose a loop breaker, delete all edges to that node, re-analyse the SCC, and iterate. But what is the graph? NOT the same graph as was used for Note [Forming Rec groups]! In particular, a RULE is like an equation for 'f' that is *always* inlined if it is applicable. We do *not* disable rules for loop-breakers. It's up to whoever makes the rules to make sure that the rules themselves always terminate. See Note [Rules for recursive functions] in Simplify.lhs Hence, if f's RHS (or its INLINE template if it has one) mentions g, and g has a RULE that mentions h, and h has a RULE that mentions f then we *must* choose f to be a loop breaker. Example: see Note [Specialisation rules]. In general, take the free variables of f's RHS, and augment it with all the variables reachable by RULES from those starting points. That is the whole reason for computing rule_fv_env in occAnalBind. (Of course we only consider free vars that are also binders in this Rec group.) See also Note [Finding rule RHS free vars] Note that when we compute this rule_fv_env, we only consider variables free in the *RHS* of the rule, in contrast to the way we build the Rec group in the first place (Note [Rule dependency info]) Note that if 'g' has RHS that mentions 'w', we should add w to g's loop-breaker edges. More concretely there is an edge from f -> g iff (a) g is mentioned in f's RHS `xor` f's INLINE rhs (see Note [Inline rules]) (b) or h is mentioned in f's RHS, and g appears in the RHS of an active RULE of h or a transitive sequence of active rules starting with h Why "active rules"? See Note [Finding rule RHS free vars] Note that in Example [eftInt], *neither* eftInt *nor* eftIntFB is chosen as a loop breaker, because their RHSs don't mention each other. And indeed both can be inlined safely. Note again that the edges of the graph we use for computing loop breakers are not the same as the edges we use for computing the Rec blocks. That's why we compute - rec_edges for the Rec block analysis - loop_breaker_edges for the loop breaker analysis * Note [Finding rule RHS free vars] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider this real example from Data Parallel Haskell tagZero :: Array Int -> Array Tag {-# INLINE [1] tagZeroes #-} tagZero xs = pmap (\x -> fromBool (x==0)) xs {-# RULES "tagZero" [~1] forall xs n. pmap fromBool
type Node details = (details, Unique, [Unique]) -- The Ints are gotten from the Unique, -- which is gotten from the Id. data Details = ND { nd_bndr :: Id -- Binder , nd_rhs :: CoreExpr -- RHS, already occ-analysed , nd_uds :: UsageDetails -- Usage from RHS, and RULES, and InlineRule unfolding -- ignoring phase (ie assuming all are active) -- See Note [Forming Rec groups] , nd_inl :: IdSet -- Free variables of -- the InlineRule (if present and active) -- or the RHS (ir no InlineRule) -- but excluding any RULES -- This is the IdSet that may be used if the Id is inlined , nd_weak :: IdSet -- Binders of this Rec that are mentioned in nd_uds -- but are *not* in nd_inl. These are the ones whose -- dependencies might not be respected by loop_breaker_edges -- See Note [Weak loop breakers] , nd_active_rule_fvs :: IdSet -- Free variables of the RHS of active RULES } instance Outputable Details where ppr nd = ptext (sLit "ND") <> braces (sep [ ptext (sLit "bndr =") <+> ppr (nd_bndr nd) , ptext (sLit "uds =") <+> ppr (nd_uds nd) , ptext (sLit "inl =") <+> ppr (nd_inl nd) , ptext (sLit "weak =") <+> ppr (nd_weak nd) , ptext (sLit "rule =") <+> ppr (nd_active_rule_fvs nd) ]) makeNode :: OccEnv -> IdEnv IdSet -> VarSet -> (Var, CoreExpr) -> Node Details makeNode env imp_rules_edges bndr_set (bndr, rhs) = (details, varUnique bndr, keysUFM node_fvs) where details = ND { nd_bndr = bndr , nd_rhs = rhs' , nd_uds = rhs_usage3 , nd_weak = node_fvs `minusVarSet` inl_fvs , nd_inl = inl_fvs , nd_active_rule_fvs = active_rule_fvs } -- Constructing the edges for the main Rec computation -- See Note [Forming Rec groups] (rhs_usage1, rhs') = occAnalRecRhs env rhs rhs_usage2 = addIdOccs rhs_usage1 all_rule_fvs -- Note [Rules are extra RHSs] -- Note [Rule dependency info] rhs_usage3 = case mb_unf_fvs of Just unf_fvs -> addIdOccs rhs_usage2 unf_fvs Nothing -> rhs_usage2 node_fvs = udFreeVars bndr_set rhs_usage3 -- Finding the free variables of the rules is_active = occ_rule_act env :: Activation -> Bool rules = filterOut isBuiltinRule (idCoreRules bndr) rules_w_fvs :: [(Activation, VarSet)] -- Find the RHS fvs rules_w_fvs = maybe id (\ids -> ((AlwaysActive, ids):)) (lookupVarEnv imp_rules_edges bndr) -- See Note [Preventing loops due to imported functions rules] [ (ru_act rule, fvs) | rule <- rules , let fvs = exprFreeVars (ru_rhs rule) `delVarSetList` ru_bndrs rule , not (isEmptyVarSet fvs) ] all_rule_fvs = foldr (unionVarSet . snd) rule_lhs_fvs rules_w_fvs rule_lhs_fvs = foldr (unionVarSet . (\ru -> exprsFreeVars (ru_args ru) `delVarSetList` ru_bndrs ru)) emptyVarSet rules active_rule_fvs = unionVarSets [fvs | (a,fvs) <- rules_w_fvs, is_active a] -- Finding the free variables of the INLINE pragma (if any) unf = realIdUnfolding bndr -- Ignore any current loop-breaker flag mb_unf_fvs = stableUnfoldingVars unf -- Find the "nd_inl" free vars; for the loop-breaker phase inl_fvs = case mb_unf_fvs of Nothing -> udFreeVars bndr_set rhs_usage1 -- No INLINE, use RHS Just unf_fvs -> unf_fvs -- We could check for an *active* INLINE (returning -- emptyVarSet for an inactive one), but is_active -- isn't the right thing (it tells about -- RULE activation), so we'd need more plumbing ----------------------------- occAnalRec :: SCC (Node Details) -> (UsageDetails, [CoreBind]) -> (UsageDetails, [CoreBind]) -- The NonRec case is just like a Let (NonRec ...) above occAnalRec (AcyclicSCC (ND { nd_bndr = bndr, nd_rhs = rhs, nd_uds = rhs_uds}, _, _)) (body_uds, binds) | not (bndr `usedIn` body_uds) = (body_uds, binds) -- See Note [Dead code] | otherwise -- It's mentioned in the body = (body_uds' +++ rhs_uds, NonRec tagged_bndr rhs : binds) where (body_uds', tagged_bndr) = tagBinder body_uds bndr -- The Rec case is the interesting one -- See Note [Loop breaking] occAnalRec (CyclicSCC nodes) (body_uds, binds) | not (any (`usedIn` body_uds) bndrs) -- NB: look at body_uds, not total_uds = (body_uds, binds) -- See Note [Dead code] | otherwise -- At this point we always build a single Rec = -- pprTrace "occAnalRec" (vcat -- [ text "tagged nodes" <+> ppr tagged_nodes -- , text "lb edges" <+> ppr loop_breaker_edges]) (final_uds, Rec pairs : binds) where bndrs = [b | (ND { nd_bndr = b }, _, _) <- nodes] bndr_set = mkVarSet bndrs ---------------------------- -- Tag the binders with their occurrence info tagged_nodes = map tag_node nodes total_uds = foldl add_uds body_uds nodes final_uds = total_uds `minusVarEnv` bndr_set add_uds usage_so_far (nd, _, _) = usage_so_far +++ nd_uds nd tag_node :: Node Details -> Node Details tag_node (details@ND { nd_bndr = bndr }, k, ks) = (details { nd_bndr = setBinderOcc total_uds bndr }, k, ks) --------------------------- -- Now reconstruct the cycle pairs :: [(Id,CoreExpr)] pairs | isEmptyVarSet weak_fvs = reOrderNodes 0 bndr_set weak_fvs tagged_nodes [] | otherwise = loopBreakNodes 0 bndr_set weak_fvs loop_breaker_edges [] -- If weak_fvs is empty, the loop_breaker_edges will include all -- the edges in tagged_nodes, so there isn't any point in doing -- a fresh SCC computation that will yield a single CyclicSCC result. weak_fvs :: VarSet weak_fvs = foldr (unionVarSet . nd_weak . fstOf3) emptyVarSet nodes -- See Note [Choosing loop breakers] for loop_breaker_edges loop_breaker_edges = map mk_node tagged_nodes mk_node (details@(ND { nd_inl = inl_fvs }), k, _) = (details, k, keysUFM (extendFvs_ rule_fv_env inl_fvs)) ------------------------------------ rule_fv_env :: IdEnv IdSet -- Maps a variable f to the variables from this group -- mentioned in RHS of active rules for f -- Domain is *subset* of bound vars (others have no rule fvs) rule_fv_env = transClosureFV (mkVarEnv init_rule_fvs) init_rule_fvs -- See Note [Finding rule RHS free vars] = [ (b, trimmed_rule_fvs) | (ND { nd_bndr = b, nd_active_rule_fvs = rule_fvs },_,_) <- nodes , let trimmed_rule_fvs = rule_fvs `intersectVarSet` bndr_set , not (isEmptyVarSet trimmed_rule_fvs)]\end{code} @loopBreakSCC@ is applied to the list of (binder,rhs) pairs for a cyclic strongly connected component (there's guaranteed to be a cycle). It returns the same pairs, but a) in a better order, b) with some of the Ids having a IAmALoopBreaker pragma The "loop-breaker" Ids are sufficient to break all cycles in the SCC. This means that the simplifier can guarantee not to loop provided it never records an inlining for these no-inline guys. Furthermore, the order of the binds is such that if we neglect dependencies on the no-inline Ids then the binds are topologically sorted. This means that the simplifier will generally do a good job if it works from top bottom, recording inlinings for any Ids which aren't marked as "no-inline" as it goes. \begin{code}
type Binding = (Id,CoreExpr) mk_loop_breaker :: Node Details -> Binding mk_loop_breaker (ND { nd_bndr = bndr, nd_rhs = rhs}, _, _) = (setIdOccInfo bndr strongLoopBreaker, rhs) mk_non_loop_breaker :: VarSet -> Node Details -> Binding -- See Note [Weak loop breakers] mk_non_loop_breaker used_in_rules (ND { nd_bndr = bndr, nd_rhs = rhs}, _, _) | bndr `elemVarSet` used_in_rules = (setIdOccInfo bndr weakLoopBreaker, rhs) | otherwise = (bndr, rhs) udFreeVars :: VarSet -> UsageDetails -> VarSet -- Find the subset of bndrs that are mentioned in uds udFreeVars bndrs uds = intersectUFM_C (\b _ -> b) bndrs uds loopBreakNodes :: Int -> VarSet -- All binders -> VarSet -- Binders whose dependencies may be "missing" -- See Note [Weak loop breakers] -> [Node Details] -> [Binding] -- Append these to the end -> [Binding] -- Return the bindings sorted into a plausible order, and marked with loop breakers. loopBreakNodes depth bndr_set weak_fvs nodes binds = go (stronglyConnCompFromEdgedVerticesR nodes) binds where go [] binds = binds go (scc:sccs) binds = loop_break_scc scc (go sccs binds) loop_break_scc scc binds = case scc of AcyclicSCC node -> mk_non_loop_breaker weak_fvs node : binds CyclicSCC [node] -> mk_loop_breaker node : binds CyclicSCC nodes -> reOrderNodes depth bndr_set weak_fvs nodes binds reOrderNodes :: Int -> VarSet -> VarSet -> [Node Details] -> [Binding] -> [Binding] -- Choose a loop breaker, mark it no-inline, -- do SCC analysis on the rest, and recursively sort them out reOrderNodes _ _ _ [] _ = panic "reOrderNodes" reOrderNodes depth bndr_set weak_fvs (node : nodes) binds = -- pprTrace "reOrderNodes" (text "unchosen" <+> ppr unchosen $$ -- text "chosen" <+> ppr chosen_nodes) $ loopBreakNodes new_depth bndr_set weak_fvs unchosen $ (map mk_loop_breaker chosen_nodes ++ binds) where (chosen_nodes, unchosen) = choose_loop_breaker (score node) [node] [] nodes approximate_loop_breaker = depth >= 2 new_depth | approximate_loop_breaker = 0 | otherwise = depth+1 -- After two iterations (d=0, d=1) give up -- and approximate, returning to d=0 choose_loop_breaker :: Int -- Best score so far -> [Node Details] -- Nodes with this score -> [Node Details] -- Nodes with higher scores -> [Node Details] -- Unprocessed nodes -> ([Node Details], [Node Details]) -- This loop looks for the bind with the lowest score -- to pick as the loop breaker. The rest accumulate in choose_loop_breaker _ loop_nodes acc [] = (loop_nodes, acc) -- Done -- If approximate_loop_breaker is True, we pick *all* -- nodes with lowest score, else just one -- See Note [Complexity of loop breaking] choose_loop_breaker loop_sc loop_nodes acc (node : nodes) | sc < loop_sc -- Lower score so pick this new one = choose_loop_breaker sc [node] (loop_nodes ++ acc) nodes | approximate_loop_breaker && sc == loop_sc = choose_loop_breaker loop_sc (node : loop_nodes) acc nodes | otherwise -- Higher score so don't pick it = choose_loop_breaker loop_sc loop_nodes (node : acc) nodes where sc = score node score :: Node Details -> Int -- Higher score => less likely to be picked as loop breaker score (ND { nd_bndr = bndr, nd_rhs = rhs }, _, _) | not (isId bndr) = 100 -- A type or cercion variable is never a loop breaker | isDFunId bndr = 9 -- Never choose a DFun as a loop breaker -- Note [DFuns should not be loop breakers] | Just _ <- isStableCoreUnfolding_maybe (idUnfolding bndr) = 3 -- Note [INLINE pragmas] -- Data structures are more important than INLINE pragmas -- so that dictionary/method recursion unravels -- Note that this case hits all InlineRule things, so we -- never look at 'rhs' for InlineRule stuff. That's right, because -- 'rhs' is irrelevant for inlining things with an InlineRule | is_con_app rhs = 5 -- Data types help with cases: Note [Constructor applications] | exprIsTrivial rhs = 10 -- Practically certain to be inlined -- Used to have also: && not (isExportedId bndr) -- But I found this sometimes cost an extra iteration when we have -- rec { d = (a,b); a = ...df...; b = ...df...; df = d } -- where df is the exported dictionary. Then df makes a really -- bad choice for loop breaker -- If an Id is marked "never inline" then it makes a great loop breaker -- The only reason for not checking that here is that it is rare -- and I've never seen a situation where it makes a difference, -- so it probably isn't worth the time to test on every binder -- | isNeverActive (idInlinePragma bndr) = -10 | isOneOcc (idOccInfo bndr) = 2 -- Likely to be inlined | canUnfold (realIdUnfolding bndr) = 1 -- The Id has some kind of unfolding -- Ignore loop-breaker-ness here because that is what we are setting! | otherwise = 0 -- Checking for a constructor application -- Cheap and cheerful; the simplifer moves casts out of the way -- The lambda case is important to spot x = /\a. C (f a) -- which comes up when C is a dictionary constructor and -- f is a default method. -- Example: the instance for Show (ST s a) in GHC.ST -- -- However we *also* treat (\x. C p q) as a con-app-like thing, -- Note [Closure conversion] is_con_app (Var v) = isConLikeId v is_con_app (App f _) = is_con_app f is_con_app (Lam _ e) = is_con_app e is_con_app (Tick _ e) = is_con_app e is_con_app _ = False\end{code} Note [Complexity of loop breaking] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The loop-breaking algorithm knocks out one binder at a time, and performs a new SCC analysis on the remaining binders. That can behave very badly in tightly-coupled groups of bindings; in the worst case it can be (N**2)*log N, because it does a full SCC on N, then N-1, then N-2 and so on. To avoid this, we switch plans after 2 (or whatever) attempts: Plan A: pick one binder with the lowest score, make it a loop breaker, and try again Plan B: pick *all* binders with the lowest score, make them all loop breakers, and try again Since there are only a small finite number of scores, this will terminate in a constant number of iterations, rather than O(N) iterations. You might thing that it's very unlikely, but RULES make it much more likely. Here's a real example from Trac #1969: Rec { $dm = \d.\x. op d {-# RULES forall d. $dm Int d = $s$dm1 forall d. $dm Bool d = $s$dm2 #-} dInt = MkD .... opInt ... dInt = MkD .... opBool ... opInt = $dm dInt opBool = $dm dBool $s$dm1 = \x. op dInt $s$dm2 = \x. op dBool } The RULES stuff means that we can't choose $dm as a loop breaker (Note [Choosing loop breakers]), so we must choose at least (say) opInt *and* opBool, and so on. The number of loop breakders is linear in the number of instance declarations. Note [INLINE pragmas] ~~~~~~~~~~~~~~~~~~~~~ Avoid choosing a function with an INLINE pramga as the loop breaker! If such a function is mutually-recursive with a non-INLINE thing, then the latter should be the loop-breaker. ----> Historical note, dating from when strictness wrappers were generated from the strictness signatures: Usually this is just a question of optimisation. But a particularly bad case is wrappers generated by the demand analyser: if you make then into a loop breaker you may get an infinite inlining loop. For example: rec { $wfoo x = ....foo x.... {-loop brk-} foo x = ...$wfoo x... } The interface file sees the unfolding for $wfoo, and sees that foo is strict (and hence it gets an auto-generated wrapper). Result: an infinite inlining in the importing scope. So be a bit careful if you change this. A good example is Tree.repTree in nofib/spectral/minimax. If the repTree wrapper is chosen as the loop breaker then compiling Game.hs goes into an infinite loop. This happened when we gave is_con_app a lower score than inline candidates: Tree.repTree = __inline_me (/\a. \w w1 w2 -> case Tree.$wrepTree @ a w w1 w2 of { (# ww1, ww2 #) -> Branch @ a ww1 ww2 }) Tree.$wrepTree = /\a w w1 w2 -> (# w2_smP, map a (Tree a) (Tree.repTree a w1 w) (w w2) #) Here we do *not* want to choose 'repTree' as the loop breaker. -----> End of historical note Note [DFuns should not be loop breakers] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's particularly bad to make a DFun into a loop breaker. See Note [How instance declarations are translated] in TcInstDcls We give DFuns a higher score than ordinary CONLIKE things because if there's a choice we want the DFun to be the non-looop breker. Eg rec { sc = /\ a \$dC. $fBWrap (T a) ($fCT @ a $dC) $fCT :: forall a_afE. (Roman.C a_afE) => Roman.C (Roman.T a_afE) {-# DFUN #-} $fCT = /\a \$dC. MkD (T a) ((sc @ a $dC) |> blah) ($ctoF @ a $dC) } Here 'sc' (the superclass) looks CONLIKE, but we'll never get to it if we can't unravel the DFun first. Note [Constructor applications] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It's really really important to inline dictionaries. Real example (the Enum Ordering instance from GHC.Base): rec f = \ x -> case d of (p,q,r) -> p x g = \ x -> case d of (p,q,r) -> q x d = (v, f, g) Here, f and g occur just once; but we can't inline them into d. On the other hand we *could* simplify those case expressions if we didn't stupidly choose d as the loop breaker. But we won't because constructor args are marked "Many". Inlining dictionaries is really essential to unravelling the loops in static numeric dictionaries, see GHC.Float. Note [Closure conversion] ~~~~~~~~~~~~~~~~~~~~~~~~~ We treat (\x. C p q) as a high-score candidate in the letrec scoring algorithm. The immediate motivation came from the result of a closure-conversion transformation which generated code like this: data Clo a b = forall c. Clo (c -> a -> b) c ($:) :: Clo a b -> a -> b Clo f env $: x = f env x rec { plus = Clo plus1 () ; plus1 _ n = Clo plus2 n ; plus2 Zero n = n ; plus2 (Succ m) n = Succ (plus $: m $: n) } If we inline 'plus' and 'plus1', everything unravels nicely. But if we choose 'plus1' as the loop breaker (which is entirely possible otherwise), the loop does not unravel nicely. @occAnalRhs@ deals with the question of bindings where the Id is marked by an INLINE pragma. For these we record that anything which occurs in its RHS occurs many times. This pessimistically assumes that ths inlined binder also occurs many times in its scope, but if it doesn't we'll catch it next time round. At worst this costs an extra simplifier pass. ToDo: try using the occurrence info for the inline'd binder. [March 97] We do the same for atomic RHSs. Reason: see notes with loopBreakSCC. [June 98, SLPJ] I've undone this change; I don't understand it. See notes with loopBreakSCC. \begin{code}
occAnalRecRhs :: OccEnv -> CoreExpr -- Rhs -> (UsageDetails, CoreExpr) -- Returned usage details covers only the RHS, -- and *not* the RULE or INLINE template for the Id occAnalRecRhs env rhs = occAnal (rhsCtxt env) rhs occAnalNonRecRhs :: OccEnv -> Id -> CoreExpr -- Binder and rhs -- Binder is already tagged with occurrence info -> (UsageDetails, CoreExpr) -- Returned usage details covers only the RHS, -- and *not* the RULE or INLINE template for the Id occAnalNonRecRhs env bndr rhs = occAnal rhs_env rhs where -- See Note [Use one-shot info] env1 = env { occ_one_shots = argOneShots OneShotLam dmd } -- See Note [Cascading inlines] rhs_env | certainly_inline = env1 | otherwise = rhsCtxt env1 certainly_inline -- See Note [Cascading inlines] = case idOccInfo bndr of OneOcc in_lam one_br _ -> not in_lam && one_br && active && not_stable _ -> False dmd = idDemandInfo bndr active = isAlwaysActive (idInlineActivation bndr) not_stable = not (isStableUnfolding (idUnfolding bndr)) addIdOccs :: UsageDetails -> VarSet -> UsageDetails addIdOccs usage id_set = foldVarSet add usage id_set where add v u | isId v = addOneOcc u v NoOccInfo | otherwise = u -- Give a non-committal binder info (i.e NoOccInfo) because -- a) Many copies of the specialised thing can appear -- b) We don't want to substitute a BIG expression inside a RULE -- even if that's the only occurrence of the thing -- (Same goes for INLINE.)\end{code} Note [Cascading inlines] ~~~~~~~~~~~~~~~~~~~~~~~~ By default we use an rhsCtxt for the RHS of a binding. This tells the occ anal n that it's looking at an RHS, which has an effect in occAnalApp. In particular, for constructor applications, it makes the arguments appear to have NoOccInfo, so that we don't inline into them. Thus x = f y k = Just x we do not want to inline x. But there's a problem. Consider x1 = a0 : [] x2 = a1 : x1 x3 = a2 : x2 g = f x3 First time round, it looks as if x1 and x2 occur as an arg of a let-bound constructor ==> give them a many-occurrence. But then x3 is inlined (unconditionally as it happens) and next time round, x2 will be, and the next time round x1 will be Result: multiple simplifier iterations. Sigh. So, when analysing the RHS of x3 we notice that x3 will itself definitely inline the next time round, and so we analyse x3's rhs in an ordinary context, not rhsCtxt. Hence the "certainly_inline" stuff. Annoyingly, we have to approximate SimplUtils.preInlineUnconditionally. If we say "yes" when preInlineUnconditionally says "no" the simplifier iterates indefinitely: x = f y k = Just x inline ==> k = Just (f y) float ==> x1 = f y k = Just x1 This is worse than the slow cascade, so we only want to say "certainly_inline" if it really is certain. Look at the note with preInlineUnconditionally for the various clauses. Expressions ~~~~~~~~~~~ \begin{code}
occAnal :: OccEnv -> CoreExpr -> (UsageDetails, -- Gives info only about the "interesting" Ids CoreExpr) occAnal _ expr@(Type _) = (emptyDetails, expr) occAnal _ expr@(Lit _) = (emptyDetails, expr) occAnal env expr@(Var v) = (mkOneOcc env v False, expr) -- At one stage, I gathered the idRuleVars for v here too, -- which in a way is the right thing to do. -- But that went wrong right after specialisation, when -- the *occurrences* of the overloaded function didn't have any -- rules in them, so the *specialised* versions looked as if they -- weren't used at all. occAnal _ (Coercion co) = (addIdOccs emptyDetails (coVarsOfCo co), Coercion co) -- See Note [Gather occurrences of coercion veriables]\end{code} Note [Gather occurrences of coercion veriables] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We need to gather info about what coercion variables appear, so that we can sort them into the right place when doing dependency analysis. \begin{code}
occAnal env (Tick tickish body) | Breakpoint _ ids <- tickish = (mapVarEnv markInsideSCC usage +++ mkVarEnv (zip ids (repeat NoOccInfo)), Tick tickish body') -- never substitute for any of the Ids in a Breakpoint | tickishScoped tickish = (mapVarEnv markInsideSCC usage, Tick tickish body') | otherwise = (usage, Tick tickish body') where !(usage,body') = occAnal env body occAnal env (Cast expr co) = case occAnal env expr of { (usage, expr') -> let usage1 = markManyIf (isRhsEnv env) usage usage2 = addIdOccs usage1 (coVarsOfCo co) -- See Note [Gather occurrences of coercion veriables] in (usage2, Cast expr' co) -- If we see let x = y `cast` co -- then mark y as 'Many' so that we don't -- immediately inline y again. }\end{code} \begin{code}
occAnal env app@(App _ _) = occAnalApp env (collectArgs app) -- Ignore type variables altogether -- (a) occurrences inside type lambdas only not marked as InsideLam -- (b) type variables not in environment occAnal env (Lam x body) | isTyVar x = case occAnal env body of { (body_usage, body') -> (body_usage, Lam x body') } -- For value lambdas we do a special hack. Consider -- (\x. \y. ...x...) -- If we did nothing, x is used inside the \y, so would be marked -- as dangerous to dup. But in the common case where the abstraction -- is applied to two arguments this is over-pessimistic. -- So instead, we just mark each binder with its occurrence -- info in the *body* of the multiple lambda. -- Then, the simplifier is careful when partially applying lambdas. occAnal env expr@(Lam _ _) = case occAnal env_body body of { (body_usage, body') -> let (final_usage, tagged_binders) = tagLamBinders body_usage binders' -- Use binders' to put one-shot info on the lambdas really_final_usage | all isOneShotBndr binders' = final_usage | otherwise = mapVarEnv markInsideLam final_usage in (really_final_usage, mkLams tagged_binders body') } where (binders, body) = collectBinders expr (env_body, binders') = oneShotGroup env binders occAnal env (Case scrut bndr ty alts) = case occ_anal_scrut scrut alts of { (scrut_usage, scrut') -> case mapAndUnzip occ_anal_alt alts of { (alts_usage_s, alts') -> let alts_usage = foldr combineAltsUsageDetails emptyDetails alts_usage_s (alts_usage1, tagged_bndr) = tag_case_bndr alts_usage bndr total_usage = scrut_usage +++ alts_usage1 in total_usage `seq` (total_usage, Case scrut' tagged_bndr ty alts') }} where -- Note [Case binder usage] -- ~~~~~~~~~~~~~~~~~~~~~~~~ -- The case binder gets a usage of either "many" or "dead", never "one". -- Reason: we like to inline single occurrences, to eliminate a binding, -- but inlining a case binder *doesn't* eliminate a binding. -- We *don't* want to transform -- case x of w { (p,q) -> f w } -- into -- case x of w { (p,q) -> f (p,q) } tag_case_bndr usage bndr = case lookupVarEnv usage bndr of Nothing -> (usage, setIdOccInfo bndr IAmDead) Just _ -> (usage `delVarEnv` bndr, setIdOccInfo bndr NoOccInfo) alt_env = mkAltEnv env scrut bndr occ_anal_alt = occAnalAlt alt_env bndr occ_anal_scrut (Var v) (alt1 : other_alts) | not (null other_alts) || not (isDefaultAlt alt1) = (mkOneOcc env v True, Var v) -- The 'True' says that the variable occurs -- in an interesting context; the case has -- at least one non-default alternative occ_anal_scrut scrut _alts = occAnal (vanillaCtxt env) scrut -- No need for rhsCtxt occAnal env (Let bind body) = case occAnal env body of { (body_usage, body') -> case occAnalBind env env emptyVarEnv bind body_usage of { (final_usage, new_binds) -> (final_usage, mkLets new_binds body') }} occAnalArgs :: OccEnv -> [CoreExpr] -> [OneShots] -> (UsageDetails, [CoreExpr]) occAnalArgs _ [] _ = (emptyDetails, []) occAnalArgs env (arg:args) one_shots | isTypeArg arg = case occAnalArgs env args one_shots of { (uds, args') -> (uds, arg:args') } | otherwise = case argCtxt env one_shots of { (arg_env, one_shots') -> case occAnal arg_env arg of { (uds1, arg') -> case occAnalArgs env args one_shots' of { (uds2, args') -> (uds1 +++ uds2, arg':args') }}}\end{code} Applications are dealt with specially because we want the "build hack" to work. Note [Arguments of let-bound constructors] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider f x = let y = expensive x in let z = (True,y) in (case z of {(p,q)->q}, case z of {(p,q)->q}) We feel free to duplicate the WHNF (True,y), but that means that y may be duplicated thereby. If we aren't careful we duplicate the (expensive x) call! Constructors are rather like lambdas in this way. \begin{code}
occAnalApp :: OccEnv -> (Expr CoreBndr, [Arg CoreBndr]) -> (UsageDetails, Expr CoreBndr) occAnalApp env (Var fun, args) = case args_stuff of { (args_uds, args') -> let final_args_uds = markManyIf (isRhsEnv env && is_exp) args_uds -- We mark the free vars of the argument of a constructor or PAP -- as "many", if it is the RHS of a let(rec). -- This means that nothing gets inlined into a constructor argument -- position, which is what we want. Typically those constructor -- arguments are just variables, or trivial expressions. -- -- This is the *whole point* of the isRhsEnv predicate -- See Note [Arguments of let-bound constructors] in (fun_uds +++ final_args_uds, mkApps (Var fun) args') } where n_val_args = valArgCount args fun_uds = mkOneOcc env fun (n_val_args > 0) is_exp = isExpandableApp fun n_val_args -- See Note [CONLIKE pragma] in BasicTypes -- The definition of is_exp should match that in -- Simplify.prepareRhs one_shots = argsOneShots (idStrictness fun) n_val_args -- See Note [Use one-shot info] args_stuff = occAnalArgs env args one_shots -- (foldr k z xs) may call k many times, but it never -- shares a partial application of k; hence [False,True] -- This means we can optimise -- foldr (\x -> let v = ...x... in \y -> ...v...) z xs -- by floating in the v occAnalApp env (fun, args) = case occAnal (addAppCtxt env args) fun of { (fun_uds, fun') -> -- The addAppCtxt is a bit cunning. One iteration of the simplifier -- often leaves behind beta redexs like -- (\x y -> e) a1 a2 -- Here we would like to mark x,y as one-shot, and treat the whole -- thing much like a let. We do this by pushing some True items -- onto the context stack. case occAnalArgs env args [] of { (args_uds, args') -> (fun_uds +++ args_uds, mkApps fun' args') }} markManyIf :: Bool -- If this is true -> UsageDetails -- Then do markMany on this -> UsageDetails markManyIf True uds = mapVarEnv markMany uds markManyIf False uds = uds\end{code} Note [Use one-shot information] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The occurrrence analyser propagates one-shot-lambda information in two situation * Applications: eg build (\cn -> blah) Propagate one-shot info from the strictness signature of 'build' to the \cn * Let-bindings: eg let f = \c. let ... in \n -> blah in (build f, build f) Propagate one-shot info from the demanand-info on 'f' to the lambdas in its RHS (which may not be syntactically at the top) Some of this is done by the demand analyser, but this way it happens much earlier, taking advantage of the strictness signature of imported functions. Note [Binders in case alternatives] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Consider case x of y { (a,b) -> f y } We treat 'a', 'b' as dead, because they don't physically occur in the case alternative. (Indeed, a variable is dead iff it doesn't occur in its scope in the output of OccAnal.) It really helps to know when binders are unused. See esp the call to isDeadBinder in Simplify.mkDupableAlt In this example, though, the Simplifier will bring 'a' and 'b' back to life, beause it binds 'y' to (a,b) (imagine got inlined and scrutinised y). \begin{code}
occAnalAlt :: (OccEnv, Maybe (Id, CoreExpr)) -> CoreBndr -> CoreAlt -> (UsageDetails, Alt IdWithOccInfo) occAnalAlt (env, scrut_bind) case_bndr (con, bndrs, rhs) = case occAnal env rhs of { (rhs_usage1, rhs1) -> let (rhs_usage2, rhs2) = wrapProxy (occ_binder_swap env) scrut_bind case_bndr rhs_usage1 rhs1 (alt_usg, tagged_bndrs) = tagLamBinders rhs_usage2 bndrs bndrs' = tagged_bndrs -- See Note [Binders in case alternatives] in (alt_usg, (con, bndrs', rhs2)) } wrapProxy :: Bool -> Maybe (Id, CoreExpr) -> Id -> UsageDetails -> CoreExpr -> (UsageDetails, CoreExpr) wrapProxy enable_binder_swap (Just (scrut_var, rhs)) case_bndr body_usg body | enable_binder_swap, scrut_var `usedIn` body_usg = ( body_usg' +++ unitVarEnv case_bndr NoOccInfo , Let (NonRec tagged_scrut_var rhs) body ) where (body_usg', tagged_scrut_var) = tagBinder body_usg scrut_var wrapProxy _ _ _ body_usg body = (body_usg, body)\end{code} %************************************************************************ %* * OccEnv %* * %************************************************************************ \begin{code}
data OccEnv = OccEnv { occ_encl :: !OccEncl -- Enclosing context information , occ_one_shots :: !OneShots -- Tells about linearity , occ_gbl_scrut :: GlobalScruts , occ_rule_act :: Activation -> Bool -- Which rules are active -- See Note [Finding rule RHS free vars] , occ_binder_swap :: !Bool -- enable the binder_swap -- See CorePrep Note [Dead code in CorePrep] } type GlobalScruts = IdSet -- See Note [Binder swap on GlobalId scrutinees] ----------------------------- -- OccEncl is used to control whether to inline into constructor arguments -- For example: -- x = (p,q) -- Don't inline p or q -- y = /\a -> (p a, q a) -- Still don't inline p or q -- z = f (p,q) -- Do inline p,q; it may make a rule fire -- So OccEncl tells enought about the context to know what to do when -- we encounter a contructor application or PAP. data OccEncl = OccRhs -- RHS of let(rec), albeit perhaps inside a type lambda -- Don't inline into constructor args here | OccVanilla -- Argument of function, body of lambda, scruintee of case etc. -- Do inline into constructor args here instance Outputable OccEncl where ppr OccRhs = ptext (sLit "occRhs") ppr OccVanilla = ptext (sLit "occVanilla") type OneShots = [OneShotInfo] -- [] No info -- -- one_shot_info:ctxt Analysing a function-valued expression that -- will be applied as described by one_shot_info initOccEnv :: (Activation -> Bool) -> OccEnv initOccEnv active_rule = OccEnv { occ_encl = OccVanilla , occ_one_shots = [] , occ_gbl_scrut = emptyVarSet -- PE emptyVarEnv emptyVarSet , occ_rule_act = active_rule , occ_binder_swap = True } vanillaCtxt :: OccEnv -> OccEnv vanillaCtxt env = env { occ_encl = OccVanilla, occ_one_shots = [] } rhsCtxt :: OccEnv -> OccEnv rhsCtxt env = env { occ_encl = OccRhs, occ_one_shots = [] } argCtxt :: OccEnv -> [OneShots] -> (OccEnv, [OneShots]) argCtxt env [] = (env { occ_encl = OccVanilla, occ_one_shots = [] }, []) argCtxt env (one_shots:one_shots_s) = (env { occ_encl = OccVanilla, occ_one_shots = one_shots }, one_shots_s) isRhsEnv :: OccEnv -> Bool isRhsEnv (OccEnv { occ_encl = OccRhs }) = True isRhsEnv (OccEnv { occ_encl = OccVanilla }) = False oneShotGroup :: OccEnv -> [CoreBndr] -> ( OccEnv , [CoreBndr] ) -- The result binders have one-shot-ness set that they might not have had originally. -- This happens in (build (\cn -> e)). Here the occurrence analyser -- linearity context knows that c,n are one-shot, and it records that fact in -- the binder. This is useful to guide subsequent float-in/float-out tranformations oneShotGroup env@(OccEnv { occ_one_shots = ctxt }) bndrs = go ctxt bndrs [] where go ctxt [] rev_bndrs = ( env { occ_one_shots = ctxt, occ_encl = OccVanilla } , reverse rev_bndrs ) go [] bndrs rev_bndrs = ( env { occ_one_shots = [], occ_encl = OccVanilla } , reverse rev_bndrs ++ bndrs ) go ctxt (bndr:bndrs) rev_bndrs | isId bndr = case ctxt of [] -> go [] bndrs (bndr : rev_bndrs) (one_shot : ctxt) -> go ctxt bndrs (bndr': rev_bndrs) where bndr' = updOneShotInfo bndr one_shot | otherwise = go ctxt bndrs (bndr:rev_bndrs) addAppCtxt :: OccEnv -> [Arg CoreBndr] -> OccEnv addAppCtxt env@(OccEnv { occ_one_shots = ctxt }) args = env { occ_one_shots = replicate (valArgCount args) OneShotLam ++ ctxt }\end{code} \begin{code}
transClosureFV :: UniqFM VarSet -> UniqFM VarSet -- If (f,g), (g,h) are in the input, then (f,h) is in the output -- as well as (f,g), (g,h) transClosureFV env | no_change = env | otherwise = transClosureFV (listToUFM new_fv_list) where (no_change, new_fv_list) = mapAccumL bump True (ufmToList env) bump no_change (b,fvs) | no_change_here = (no_change, (b,fvs)) | otherwise = (False, (b,new_fvs)) where (new_fvs, no_change_here) = extendFvs env fvs ------------- extendFvs_ :: UniqFM VarSet -> VarSet -> VarSet extendFvs_ env s = fst (extendFvs env s) -- Discard the Bool flag extendFvs :: UniqFM VarSet -> VarSet -> (VarSet, Bool) -- (extendFVs env s) returns -- (s `union` env(s), env(s) `subset` s) extendFvs env s | isNullUFM env = (s, True) | otherwise = (s `unionVarSet` extras, extras `subVarSet` s) where extras :: VarSet -- env(s) extras = foldUFM unionVarSet emptyVarSet $ intersectUFM_C (\x _ -> x) env s\end{code} %************************************************************************ %* * Binder swap %* * %************************************************************************ Note [Binder swap] ~~~~~~~~~~~~~~~~~~ We do these two transformations right here: (1) case x of b { pi -> ri } ==> case x of b { pi -> let x=b in ri } (2) case (x |> co) of b { pi -> ri } ==> case (x |> co) of b { pi -> let x = b |> sym co in ri } Why (2)? See Note [Case of cast] In both cases, in a particular alternative (pi -> ri), we only add the binding if (a) x occurs free in (pi -> ri) (ie it occurs in ri, but is not bound in pi) (b) the pi does not bind b (or the free vars of co) We need (a) and (b) for the inserted binding to be correct. For the alternatives where we inject the binding, we can transfer all x's OccInfo to b. And that is the point. Notice that * The deliberate shadowing of 'x'. * That (a) rapidly becomes false, so no bindings are injected. The reason for doing these transformations here is because it allows us to adjust the OccInfo for 'x' and 'b' as we go. * Suppose the only occurrences of 'x' are the scrutinee and in the ri; then this transformation makes it occur just once, and hence get inlined right away. * If we do this in the Simplifier, we don't know whether 'x' is used in ri, so we are forced to pessimistically zap b's OccInfo even though it is typically dead (ie neither it nor x appear in the ri). There's nothing actually wrong with zapping it, except that it's kind of nice to know which variables are dead. My nose tells me to keep this information as robustly as possible. The Maybe (Id,CoreExpr) passed to occAnalAlt is the extra let-binding {x=b}; it's Nothing if the binder-swap doesn't happen. There is a danger though. Consider let v = x +# y in case (f v) of w -> ...v...v... And suppose that (f v) expands to just v. Then we'd like to use 'w' instead of 'v' in the alternative. But it may be too late; we may have substituted the (cheap) x+#y for v in the same simplifier pass that reduced (f v) to v. I think this is just too bad. CSE will recover some of it. Note [Case of cast] ~~~~~~~~~~~~~~~~~~~ Consider case (x `cast` co) of b { I# -> ... (case (x `cast` co) of {...}) ... We'd like to eliminate the inner case. That is the motivation for equation (2) in Note [Binder swap]. When we get to the inner case, we inline x, cancel the casts, and away we go. Note [Binder swap on GlobalId scrutinees] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When the scrutinee is a GlobalId we must take care in two ways i) In order to *know* whether 'x' occurs free in the RHS, we need its occurrence info. BUT, we don't gather occurrence info for GlobalIds. That's the reason for the (small) occ_gbl_scrut env in OccEnv is for: it says "gather occurrence info for these". ii) We must call localiseId on 'x' first, in case it's a GlobalId, or has an External Name. See, for example, SimplEnv Note [Global Ids in the substitution]. Note [Zap case binders in proxy bindings] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From the original case x of cb(dead) { p -> ...x... } we will get case x of cb(live) { p -> let x = cb in ...x... } Core Lint never expects to find an *occurrence* of an Id marked as Dead, so we must zap the OccInfo on cb before making the binding x = cb. See Trac #5028. Historical note [no-case-of-case] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We *used* to suppress the binder-swap in case expressions when -fno-case-of-case is on. Old remarks: "This happens in the first simplifier pass, and enhances full laziness. Here's the bad case: f = \ y -> ...(case x of I# v -> ...(case x of ...) ... ) If we eliminate the inner case, we trap it inside the I# v -> arm, which might prevent some full laziness happening. I've seen this in action in spectral/cichelli/Prog.hs: [(m,n) | m <- [1..max], n <- [1..max]] Hence the check for NoCaseOfCase." However, now the full-laziness pass itself reverses the binder-swap, so this check is no longer necessary. Historical note [Suppressing the case binder-swap] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This old note describes a problem that is also fixed by doing the binder-swap in OccAnal: There is another situation when it might make sense to suppress the case-expression binde-swap. If we have case x of w1 { DEFAULT -> case x of w2 { A -> e1; B -> e2 } ...other cases .... } We'll perform the binder-swap for the outer case, giving case x of w1 { DEFAULT -> case w1 of w2 { A -> e1; B -> e2 } ...other cases .... } But there is no point in doing it for the inner case, because w1 can't be inlined anyway. Furthermore, doing the case-swapping involves zapping w2's occurrence info (see paragraphs that follow), and that forces us to bind w2 when doing case merging. So we get case x of w1 { A -> let w2 = w1 in e1 B -> let w2 = w1 in e2 ...other cases .... } This is plain silly in the common case where w2 is dead. Even so, I can't see a good way to implement this idea. I tried not doing the binder-swap if the scrutinee was already evaluated but that failed big-time: data T = MkT !Int case v of w { MkT x -> case x of x1 { I# y1 -> case x of x2 { I# y2 -> ... Notice that because MkT is strict, x is marked "evaluated". But to eliminate the last case, we must either make sure that x (as well as x1) has unfolding MkT y1. THe straightforward thing to do is to do the binder-swap. So this whole note is a no-op. It's fixed by doing the binder-swap in OccAnal because we can do the binder-swap unconditionally and still get occurrence analysis information right. \begin{code}
mkAltEnv :: OccEnv -> CoreExpr -> Id -> (OccEnv, Maybe (Id, CoreExpr)) -- Does two things: a) makes the occ_one_shots = OccVanilla -- b) extends the GlobalScruts if possible -- c) returns a proxy mapping, binding the scrutinee -- to the case binder, if possible mkAltEnv env@(OccEnv { occ_gbl_scrut = pe }) scrut case_bndr = case scrut of Var v -> add_scrut v case_bndr' Cast (Var v) co -> add_scrut v (Cast case_bndr' (mkSymCo co)) -- See Note [Case of cast] _ -> (env { occ_encl = OccVanilla }, Nothing) where add_scrut v rhs = ( env { occ_encl = OccVanilla, occ_gbl_scrut = pe `extendVarSet` v } , Just (localise v, rhs) ) case_bndr' = Var (zapIdOccInfo case_bndr) -- See Note [Zap case binders in proxy bindings] localise scrut_var = mkLocalId (localiseName (idName scrut_var)) (idType scrut_var) -- Localise the scrut_var before shadowing it; we're making a -- new binding for it, and it might have an External Name, or -- even be a GlobalId; Note [Binder swap on GlobalId scrutinees] -- Also we don't want any INLINE or NOINLINE pragmas!\end{code} %************************************************************************ %* * \subsection[OccurAnal-types]{OccEnv} %* * %************************************************************************ \begin{code}
type UsageDetails = IdEnv OccInfo -- A finite map from ids to their usage -- INVARIANT: never IAmDead -- (Deadness is signalled by not being in the map at all) (+++), combineAltsUsageDetails :: UsageDetails -> UsageDetails -> UsageDetails (+++) usage1 usage2 = plusVarEnv_C addOccInfo usage1 usage2 combineAltsUsageDetails usage1 usage2 = plusVarEnv_C orOccInfo usage1 usage2 addOneOcc :: UsageDetails -> Id -> OccInfo -> UsageDetails addOneOcc usage id info = plusVarEnv_C addOccInfo usage (unitVarEnv id info) -- ToDo: make this more efficient emptyDetails :: UsageDetails emptyDetails = (emptyVarEnv :: UsageDetails) usedIn :: Id -> UsageDetails -> Bool v `usedIn` details = isExportedId v || v `elemVarEnv` details type IdWithOccInfo = Id tagLamBinders :: UsageDetails -- Of scope -> [Id] -- Binders -> (UsageDetails, -- Details with binders removed [IdWithOccInfo]) -- Tagged binders -- Used for lambda and case binders -- It copes with the fact that lambda bindings can have InlineRule -- unfoldings, used for join points tagLamBinders usage binders = usage' `seq` (usage', bndrs') where (usage', bndrs') = mapAccumR tag_lam usage binders tag_lam usage bndr = (usage2, setBinderOcc usage bndr) where usage1 = usage `delVarEnv` bndr usage2 | isId bndr = addIdOccs usage1 (idUnfoldingVars bndr) | otherwise = usage1 tagBinder :: UsageDetails -- Of scope -> Id -- Binders -> (UsageDetails, -- Details with binders removed IdWithOccInfo) -- Tagged binders tagBinder usage binder = let usage' = usage `delVarEnv` binder binder' = setBinderOcc usage binder in usage' `seq` (usage', binder') setBinderOcc :: UsageDetails -> CoreBndr -> CoreBndr setBinderOcc usage bndr | isTyVar bndr = bndr | isExportedId bndr = case idOccInfo bndr of NoOccInfo -> bndr _ -> setIdOccInfo bndr NoOccInfo -- Don't use local usage info for visible-elsewhere things -- BUT *do* erase any IAmALoopBreaker annotation, because we're -- about to re-generate it and it shouldn't be "sticky" | otherwise = setIdOccInfo bndr occ_info where occ_info = lookupVarEnv usage bndr `orElse` IAmDead\end{code} %************************************************************************ %* * \subsection{Operations over OccInfo} %* * %************************************************************************ \begin{code}
mkOneOcc :: OccEnv -> Id -> InterestingCxt -> UsageDetails mkOneOcc env id int_cxt | isLocalId id = unitVarEnv id (OneOcc False True int_cxt) | id `elemVarEnv` occ_gbl_scrut env = unitVarEnv id NoOccInfo | otherwise = emptyDetails markMany, markInsideLam, markInsideSCC :: OccInfo -> OccInfo markMany _ = NoOccInfo markInsideSCC occ = markInsideLam occ -- inside an SCC, we can inline lambdas only. markInsideLam (OneOcc _ one_br int_cxt) = OneOcc True one_br int_cxt markInsideLam occ = occ addOccInfo, orOccInfo :: OccInfo -> OccInfo -> OccInfo addOccInfo a1 a2 = ASSERT( not (isDeadOcc a1 || isDeadOcc a2) ) NoOccInfo -- Both branches are at least One -- (Argument is never IAmDead) -- (orOccInfo orig new) is used -- when combining occurrence info from branches of a case orOccInfo (OneOcc in_lam1 _ int_cxt1) (OneOcc in_lam2 _ int_cxt2) = OneOcc (in_lam1 || in_lam2) False -- False, because it occurs in both branches (int_cxt1 && int_cxt2) orOccInfo a1 a2 = ASSERT( not (isDeadOcc a1 || isDeadOcc a2) ) NoOccInfo\end{code}


text:
Free next day collection from every store with Click+Collect
Pay Monthly Phones & SIMs
Tesco Mobile Pay monthly
Services & Support
Home Furniture
Brands & Characters
Shop F&F
Catalogue Number: 211-0939
Sorry, there are currently no sellers for this product.
We've carefully chosen all our Tesco Partners, to give you even more choice when you shop with us online.
The 20kg Hammertone dumbbell set is the ideal way to tone your upper body. Their heavy-duty steel handles ensure a tight, non-slip grip optimizing your workout for great results.
Durable cast iron plates mean this Golds Gym dumbbell set is built to last. What's more sure lock threaded collars keep the weights firmly in place meaning all your attention is focused on getting in shape.
You have no recently viewed items
Follow us
We value your opinion

subset: commoncrawl


text:
Whether you're looking to hit the back nine at dusk or dawn, you'll find your tee times here. Use our online booking service.
Use our Pro Shop to get outfitted with gear, inquire about club membership and get expert advice about your game.
We have three 9-hole Championship courses with three tee boxes each. No matter your skill level, you'll enjoy our links.
Carefree Shopping Network
Free Membership...Free Vacation...We Pay You...
FREE Membership
Free Vacation
We Pay You!!!!
Type your paragraph here.
Type your paragraph here.
Type your paragraph here.


text:
We want to ensure that making a return is as easy and hassle-free as possible! If for any reason you decide that your purchase just isn't for you, simply return the item within 30 days of receipt and we'll cover the return shipping when you choose our FREE Pre-Paid Return Shipping Label. Learn more about our return policy.
Shop now and get Free Value Shipping on most orders over $49 to contiguous 48 states, DC and to all U.S. Military APO/FPO/DPO addresses.
We're excited to offer an incredible catalog of Bushnell Gun Cleaning Kits! These first class Gun Cleaning Kits by Bushnell were designed to provide you with a great opportunity for success. Our Bushnell Gun Cleaning Kits page enables you to narrow down our incredibly massive selection. From the beginning, we've added hundreds of brands, thousands of product styles and hundreds of thousands of products so that you can find your needs met right here. From our incredible inventory of riflescopes, red dots and holsters for hunters, shooters and military professionals to our many educational microscopes, compact magnifiers and lab cleaning supplies for lab techs, we do everything we can to give you the widest selection on the net! Our commitment to your total satisfaction does not stop with selection and prices. To be sure we fully answer all your questions and carry out your order as satisfyingly as we can, we have a wonderful staff of qualified customer service representatives and product specialists at our headquarters to help. We also suggest you check out our educational blogs and how-to articles, as you'll select the best gear if you have the most info about what you want. OpticsPlanet is your first and best location when you're looking for the best Bushnell Gun Cleaning Kits, so favorite this page and return often because we work to constantly expand our selection!


text:
Accarp Family Photos
Find Accarp records
Find birth, death, marriage, military, and other Accarp records at Ancestry.com.
Search for Accarp recordsLatest Photos
We couldn't find any Accarp family photos, if you have any to share with the community, click here. Return to this page to find Accarp pictures as they are uploaded by the community. Here are the latest photos upload to AncientFaces:


text:
shes a beauty, wish i had one. Maybe that one can be next on the list
DON'T BUY DELL!!!!! BEWARE!!! The toes you step on today may be connected to the ass you kiss tomorrow. PM Tango about his upcoming SHARTFOO courses.
Now you've done it. Before long you'll be selling or trading off the rest off the rest of your collection for more 1911's.
Tackleberry that is a nice shot of yer Kimber with the lighting.
LOL - Welcome out of the cave and into the Light. Once you have one, there is no way to stop them from growing and populating your safe. You have got your hands on one hell of a good piece there. Taken care of, it will take care of you and yours for many years to come. Now, let's see some range targets.
Great Choice on the Kimber Custom!! And TackleBerry1 your Eclipse still looks Great after 8 years. You have been treating your girlfriend fine!! Jerry
Yep Just a mild case of holster wear around the leading edges of the slide, or as I call it, CHARACTER!


text:
off road lights
I bought a 2013 Tacoma double cab 4x4, I did not get the fog lights, but I would like to add some bright off road lights into the spot on bumper where the factory's are installed. what's my best option?
All times are GMT -7. The time now is 10:04 PM. |


text:
Kieran Davies
Budget red ink no surprise to the RBA
PUBLISHED: 14 May 2013 00:08:00 | UPDATED: 14 May 2013 04:43:24PUBLISHED: 14 May 2013 PRINT EDITION: 14 May 2013The budget would be low down the Reserve Bank's list of concerns, but gradual fiscal consolidation at all levels of government is one reason why interest rates should stay low for longer.
Already a subscriber? Please login here
Stay with the story for less than $1.90 a day


text:
The 2014 BET Awards was certainly Pharrell's night! Not only did he open the show with an amazing performance of 'Come Get It Bae', but he also won tons of awards!
You go, Pharrell! The rapper and upcoming coach on The Voice stunned at the 2014 BET Awards on June 29, 2014 with a killer performance of "Come Get It Bae" — Missy Elliott even joined him on stage!
Pharrell Williams BET Awards Performance — Opens Show With 'Come Get It Bae'
Pharrell Williams opened the show with his hot hit "Come Get It Bae," and we loved it.
Pharrell, in his signature hat (of course) was accompanied by tons of female dancers wearing "Bae" shirts, but the ladies weren't the only ones who danced with him.
Miley Cyrus guest vocals on the track, but it wasn't Miley that joined him on stage — Missy Elliott showed up to rap "Pass That Dutch!"
We loved seeing the female rapper surprise everyone, but we've got to give the night to Pharrell. Not only did he begin with one of the best performances of the entire show, but he stunned throughout the entire night with tons of awards!
Pharrell's Big Night At 2014 BET Awards
We know that Pharrell knows how to command an audience and sing, but he also knows how to win!
He won for Video of the Year for "Happy," in addition to Best Male R&B/Pop Artist. As if that wasn't enough, Pharrell also introduced the Lifetime Achievement Award to Lionel Richie. Talk about having a moment!
And to top it all off, he got a big smooch from his beautiful wife Helen Lasichanh to celebrate his huge victories at the BET Awards!
HollywoodLifers, was Pharrell's "Come Get It Bae" performance the best of the night? Let us know!
– Elizabeth Wagmeister
More BET Awards News:
- BET Awards Red Carpet: Zendaya, Karrueche Tran & More
- BET Awards 2014 Winners — Full List: August Alsina & More
- Nicki Minaj Performs Sexy 'Pills N Potions' At BET Awards 2014
View Comment
Posted at 4:43 AM on June 30, 2014
Hello. My dear friends ❤ Women Looking For Couples. Ćom ❤ Just for every bisexual friend. Feel for free to share your Bisexual Date ideas, bisexual advice, first bisexual experiences, bisexual videos, bisexual Fashion show, successful dating advice and safety tips and more.bgvfgbfhgfhgf


text:
- 34Promote
Tote Bag
Our quality crafted Tote Bags are hand sewn in America using durable, yet lightweight, poly poplin fabric. All seams and stress points are double stitched for durability. Available in 13" x 13", 16" x 16" and 18" x 18" variations, the tote bags are washable, feature original artwork on both sides and a sturdy 1" wide cotton webbing strap for comfortably carrying over your shoulder.
Please do Ironforge please!!! Something about Dwarves and brews and kegs and barrels of beer and pubs and beards and taverns and dancing to that awesome pub music just rocks, if you could capture all that in a poster like this I will give you my paychecks till kingdome come!!! (Not really though I'm poor)


text:
Sun's out, guns out
If you've ever wondered why repeated listenings to Johnny Nash's "I Can See Clearly Now" have driven you to suicidal thoughts (Just me? OK.), statistics may now know why.
According to a new study published in JAMA Psychiatry and data collected by the CDC, there is "a positive association between the number of suicides on a particular day and the hours of sunshine," meaning more people kill themselves on sunny days.
We're also more likely to do it in the spring, while December has the fewest suicides of all months. So, take that Holiday Seasonal Affective Disorder and shove it to Easter. Which, when you think about it, is the more depressing holiday season between Mardi Gras STIs, Lent, crucifixions and rabbits that lay eggs.
Researchers aren't sure why the sun drives us to offing ourselves, but one factor may be light itself. Increased light improves our drive to do things and decreases our serotonin transferrals, making us even more impulsive. So, if you're depressed, stay indoors!
… Oh, you're already walled up inside of your home with the windows taped shut? Good.


text:
Newest Photo Galleries
Travel PR from
Kathryn Brown Art
Kathryn Brown is an Award Winning Illustrator. All of her many books may be found on her website www.kathrynbrownart.com
Travel Deal for
Le Meridien
Complimentary Night in Bangkok at Plaza Athénée Bangkok, A Royal Méridien Hotel .
Click here for details
© 2012 Travelers411. All Rights Reserved. Travelers411 and Persistent Visions are Registered Trademarks. "Your Travel Community" TM. "Explore Your World" TM. Travelers411 and all subpages and sub domains are protected by US Copyright law. We also strive to respect the copyrights of others. Please do not post material to this site for which you do not have proper permission from the copyright holder. To request use or report abuse please contact us.


text:
Cheapest self catering accommodation in Bowness On Windermere. For best cheap breaks, stay in cheap self catering accommodation, accommodation self catering or self catering accommodation in Bowness On Windermere Langdale UK.
Find cheap Bowness accommodation selfcatering, cheap bed and breakfast hotels and cheap self catering accommodation. Bowness On Windermere cheap places to stay self catering for good food / drinks


text:
In 2008, Kamloops City council held the rezoning for a proposed Sandman Inn on Versatile Drive at third reading, pending design and some other work, including a traffic study.
Four years later, the study still isn't done.
Council is being asked Tuesday to extend the deadline so that the study, along with a City staff review of all highway interface areas in Kamloops, can be completed and examined.
City traffic and transportation engineer Chris Darwent said Monday the Versatile Drive area has seen a lot of growth, particularly as it leads to Aberdeen and Pineview Valley.
The two studies will help determine what improvements the Sandman needs to make, and how much the hotel's portion of costs are, he said.
"There is a lot of growth from a lot of areas up there. So it will likely to be a shared cost," he said. "They're still pursuing the rezoning."
City community development manager Randy Lambright said the land the hotel has sited was originally zoned as industrial. It's been delayed awaiting the traffic study, but in the meantime there's been increasing pressure in town for more industrial land.
"The bylaw was held at third reading. It can be held without a deadline. But when we look at one, two or three years . . . and there's nothing. And a neighbourhood starts to change, the original rezone analysis can change because circumstances around the property can change," he said.
In the area near the hotel, Pineview Valley is developing, the Dufferin neighbourhood is developing, Aberdeen is expanding - and all of that influences the corridor from a traffic perspective, he said.
"As far as I know, they're still pursuing it. When we indicated they hadn't closed off on their rezoning application, they hadn't met some of the conditions part of that application, we indicated we would go back to council to rescind," he said. "They said, no, we're still proceeding. But then we said we needed the traffic study."
And so council will face a recommendation Tuesday that calls for extending the deadline on the studies until September. Lambright said he expected they will be completed well before that.
© Copyright 2015 Kamloops Daily News


text:
Apart from the disease itself, the financial burden of cancer treatment is a major source of stress for patient and family. More than 90 per cent individuals end up paying the costs from their own pocket.
On World Cancer Day, February 4 when the focus globally is on unitedly fighting the disease, let us give a thought to the overall economic burden to a cancer patient who undergoes treatment in a public institution.
An average cancer patient bears an economic burden of Rs 36,812 for the entire cancer therapy at an institution like the All India Institute of Medical Sciences (AIIMS) that provides tertiary care for such patients.
Just to bring the overall burden into perspective, the average economic burden
to a cancer patient being treated at AIIMS amounted to Rs 14,031 (before start of radiotherapy) plus Rs 8,184 (for a seven week period of Radio Therapy course), adding up to Rs 22,215, where services are free or highly subsidised.
According to a paper published in the Economic and Political Weekly on 'The Economic Burden of Cancer' by Bidhu Kalyan Mohanti, Abhiroop Mukhopadhyay, Sanghamitra Das, Kuldeep Sharma, and Soumitra Das, a patient also incurs an average expenditure of Rs 14,597 before coming to the AIIMS.
Cancer is one such disease, where the financial burden of treatment is a major source of stress for patients and families.
The out-of-pocket costs incurred because of the illness can consume a substantial part of income and the family budget. However, patients and their families do not have a good estimate of the expenses involved.
The healthcare delivery in India is going through a process of transition, more so the tertiary specialty care of chronic diseases like diabetes, hypertension, heart attack, kidney or liver failure, mental disorder, ageing and cancer. More than 80 per cent of these patients are now seeking medical interventions from a private doctor or private/corporate hospital sector and more than 90 per cent individuals end up paying the costs from their own pocket. New medical technologies and newer drugs cause increasing expenditure borne by patients and their family carers.
Approximately one million newly diagnosed cancer patients are seen in India each year and out of these nearly 50-60 per cent present themselves at a disease stage suitable for curative cancer-directed therapy (CDT), which consist of surgery, chemotherapy and radiotherapy. Depending upon the cancer type and stage of disease, the initial therapy course is the most expensive period. Hence, a cancer patient and family members can face the double dilemma of confronting the cancer diagnosis and meeting the financial burden of CDT.
Radiation therapy (RT) is a key treatment. Two-thirds of all major cancers require RT with or without the other two types of treatment, and approximately 40 per cent of all cancer cures are directly attributable to the benefits of RT. Delivered over a continuous period covering several weeks, a RT course lasts between five and seven weeks. It is often observed that patients may not receive this RT course, because it is of long duration, the need to stay near a cancer centre/away from their own home and the unaffordable economic cost of therapy duration. This non-compliance can have serious implications in terms of a curative disease progressing to an incurable stage and the subsequent loss of life.
The AIIMS survey was done when the patient started the radiotherapy course and continued till the last week, spread over the RT period. It captured the major out-of-pocket expenditure incurred by the patient/household during the course of cancer therapy including medicines, tests, transportation cost to and from hospital, accommodation, and food.
The baseline survey was carried out on 432 patients between October 2006 and December 2007 when they first came to the RT-OPD registration at the cancer centre. Native place wise, 37 per cent of the sampled patients were from Uttar Pradesh, 26 per cent were from Delhi, 14 from Haryana, 10 per cent from Bihar, 5 per cent from Uttarakhand, 3 per cent from Rajasthan and the rest 5 per cent from other parts of India.
Almost half of the surveyed patients had already spent more than Rs 5,000 before coming to the AIIMS. For some, the expenditure may be very high, sometimes as much as Rs 3,72,500. Thus, the mean expenditure at Rs 14,597 is almost three times the median expenditure. These expenditures depend to a large extent on the length of time and the kind of facility patients go to.
The paper reports the expenses undertaken after reaching AIIMS and before the start of radiotherapy. The cost calculations are based on weekly data of 284 patients. The RT course in these 284 patients was for five weeks in 6.7 per cent, six weeks in 12.3 per cent, and seven weeks in 81 per cent of the surveyed patients. During the second phase of the study, for an initial subset of 141 patients, the authors collected data on all the prescribed weeks of radiotherapy.
It was concluded that the average cost across all treatment plans was Rs 1,062 per week. This would imply an average cost of Rs 5,310 for a radiotherapy course treatment lasting five weeks. If we add Rs 750 that has to be paid at the beginning as the RT course fee, the patients end up paying around Rs 6,060 for a five week RT course (in case of seven weeks, this cost is higher at Rs 8,184).
As much as 59 per cent of this cost is spent on transportation and food and lodging. These direct, indirect and total weekly costs are borne by patients during their RT course, depending upon treatment. There are significant differences between the expenditures of various treatment plans but patients are largely unaware about financial requirements for cancer diagnosis and its treatment, which can consist of direct medical, non-medical, and other indirect costs. Even the medical fraternity has little knowledge about the costs of cancer treatment borne by patients and their families.
India has a population of approximately 1,100 million with a requirement of 1,200 radiotherapy machines, whereas presently 400 RT machines are available for cancer treatment. The modern radiotherapy facilities are concentrated in private hospitals where the cost of the RT course appears to be prohibitively high and beyond the reach of common Indians, the paper points out.


text:
Bari Buddy DeFranco Bb Clarinet Mouthpiece
Product #468132 Bari 468132 KFGAB Bb Clarinet Mouthpieces https://www.esnapw.com/rses/ESnapServlet?MerchantNumberSent=63655- Write a Review
- Seen a Lower Price? Click Here.
FREE SHIPPING on Almost Everything
Designed to the specifications of one of the greats.
Buddy DeFranco & Bari Associates have combined their talent & know-how to bring this mouthpiece to its fullest potential. This is not just another mouthpiece with a prominent artist's name on it, but one that has been totally designed by Buddy DeFranco to meet all the requirements he demands. It should meet with your demands too. Power, control, and upper & lower partials are more vividly apparent than ever experienced. There are four available tip opening sizes available from the dropdown menu:
- Tip Opening: 1.27mm
- Facing: Med. short
- Ligature: Not included


text:
Mar 26th, 2005, 03:51 AM
The Miami Nasdaq 100 open website isnt living up to its the "5th" grand slam quality event. They dont even have the post match interviews and audios the Indian wells site had which was quite nice, I mean its much better to listen to an audio version of how the players feel they're playing, especially when you dont get to watch them play! Shame on the website masters of that site:fiery: :fiery: !


text:
Start learning with our library of video tutorials taught by experts. Get started
Discover how semantics (the process of adding markup, microdata, and metadata to a page) makes websites more search engine friendly, more meaningful, and more future-proof.
Shows how to create a web site strategy that will ensure the end product meets the client's needs and is as efficient and scalable as possible.
"As a teacher, I respect the way that your tutorials are hands-on and interactive. They are quick and to-the-point, and the teachers you have chosen are patient and concise." —Joshua M.
more from our members »


text:
on orders of $85 or more
An excerpt from www.HouseOfNames.com archives copyright © 2000 - 2015
Where did the Scottish Hatmaker family come from? What is the Scottish Hatmaker family crest and coat of arms? When did the Hatmaker family first arrive in the United States? Where did the various branches of the family go? What is the Hatmaker family history? Spelling variations of this family name include: Hatt, Hatmaker, Hatmaccar, Hatmalin, Hatte and many more. First found in Aberdeenshire (Gaelic: Siorrachd Obar Dheathain), a historic county, and present day Council Area of Aberdeen, located in the Grampian region of northeastern Scotland, where they held a family seat in their territories. The Pictish influence on Scottish history diminished after Kenneth Macalpine became King of all Scotland. But those east coast families still played an important role in government and were more accessible to Government than their western highland counterparts. Later they held a family seat at Brechin. This web page shows only a small excerpt of our Hatmaker research. Another 269 words(19 lines of text) covering the years 1481, 1521, 1642, 1684, 1670 and 1745 are included under the topic Early Hatmaker History in all our PDF Extended History products. More information is included under the topic Early Hatmaker Notables in all our PDF Extended History products. Some of the first settlers of this family name were: Hatmaker Settlers in United States in the 19th Century
The Hatmaker Family Crest was acquired from the Houseofnames.com archives. The Hatmaker Family Crest was drawn according to heraldic standards based on published blazons. We generally include the oldest published family crest once associated with each surname. This page was last modified on 18 June 2013 at 15:00. ©2000-2015 Swyrich Corporation. See Terms of Use for details. houseofnames.com is an internet property owned by Swyrich Corporation. Sign Up
on orders of $85 or more
Company Information Terms of Use Privacy Statement Security Policy TreeCanada Program |


text:
• Screen printed plastic signs use solvent based long lasting ink. Plastic signs won't bend and are perfect for outdoor use.
• These signs have nice round corners for an appealing look and have the same popular legends as our reflective signs.
• Questions? Give out live support team a call today!


text:
8 of 10 |
The eldest daughter of 2008 vice-presidential candidate, Sarah Palin, became a mother at the early age of 17. Bristol Palin now works with the National Campaign to Prevent Teen and Unplanned Pregnancy and the Candie's Foundation as an advocate for abstinence, and she speaks out against teen pregnancy. Her role as a spokesperson has been controversial as many question whether Bristol has been glamorizing or discouraging teen pregnancy.
10 Best Creative Apps for Kids Looking for apps that foster creativity? Check out these top-rated art and music apps for kids.
Kindergarten Readiness App Wins Gold
Our Kindergarten Readiness app won the Gold Award of Excellence in the educational category at the 2014 Communicator Awards. This valuable checklist comes with games and activities to help your child practice the essential skills she needs for kindergarten. Download the Kindergarten Readiness app today!
A New Intergalactic Reading Adventure!
Get your reluctant reader hooked on an irresistible new story, Galactic Hot Dogs! Join the Book 1 reading marathon, and get behind-the-scenes tidbits on the official Galactic Hot Dogs blog. Also, print this cool Galactic Hot Dogs reading log to keep your bookworm excited about reading!
Find Today's Newest & Best Children's Books!
Looking for newly released books for your child? Try our new Book Finder tool to search for new books by age, type, and theme, and create reading lists for kids!
Sign up for our free email newsletters and receive the latest advice and information on all things parenting.
Enter your email address to sign up or manage your account.
Make your own leprechauns and shamrocks!
Learn about the growing outbreak and vaccine safety.
Need ideas for what to do this weekend? We have it covered.
© 2000-2015 Pearson Education, Inc. All Rights Reserved.


text:
Back to a first-glance feeling on New York time
Back when you fit in my poems like a perfect rhyme
from Taylor Swift – Holy Ground Lyrics on Genius
A New York minute is an instant, since life whizzes in the Big Apple.
It's love at first sight. He was perfect for her, and loves when he forms words that make her heart melt.
NY is close to Taylor's heart, as her fans sold out the famous Madison Square Garden in 60 seconds… which was the fastest sellout in history!
To help improve the quality of the lyrics, visit Taylor Swift – Holy Ground Lyrics and leave a suggestion at the bottom of the page


text:
I missed out on the last ECY offering, anybody have any they are willing to part with? I know this is an odd question, but I would love to get my hands on some Bug Farm or any others for that matter, I would be willing to pay, trade or do whatever. I have some Pacman I could trade.
You might be able to find somebody with some washed yeast or cake from a prior batch they would trade or give you. I keep meaning to try to score one of the offerings but by the time I see there's a new offering it's already sold out. =/
The most recent sale was set up a bit differently. Joe notified everyone on the mailing list 24 hrs in advance of when they would be for sale on his website so people had a better chance to get in there and order. It was still all sold out in a matter of minutes. I have 3 beers sitting on cakes right now, they are all waiting to be bottled in the next few weeks. I might be able to spare a bit of washed yeast.
Coff, really interested in a bit of a wash if you could spare some down the road. Let me know please. What mailing list are you referring to?
Princeton Homebrew is the exclusive seller of ECY because the guy who puts ECY blends together (Al B) doesn't make that big of batches. I believe I heard or read he puts them together in his garage.
Apache, yeah I head similar, but I have also heard they rock and want to give them a shot. Every time I go to order one; sold out..
ECY recently got a new prop tank so hopefully soon he will have cultures available more frequently.
Going through life is hard. Going through life stupid is harder.
Coff, that would be awesome, would gladly trade some brews! I have a really nice RIS aged on port soaked oak cubes, cocoa and ancho chilis and a Saison using the Dupont strain. I could toss in a bottle of Burboun County Stout to sweeten up the deal..


text:
Quick Links |
Information for: For the Media: |
Primary Links: |
General Information:
Online Services & Logins: |
The College of Humanities and Social Sciences (CHSS) at UHD equips students with the marketable skills necessary to excel in the job market or continue on to graduate and professional studies. We offer students a Major Opportunity with 13 undergraduate programs and three master's degrees.
Bachelor of Arts:
Bachelor of Science:
Graduate Offerings
CHSS also serves every UHD student, regardless of major, by supporting core curriculum components, creating opportunities for interactive education, and encouraging community engagement through co-curricular initiatives.
Trip to Costa Rica - Summer 2015
O'Kane Theatre Spring 2015
The Diary of Anne Frank
Center for Critical Race Studies
Scholar in Residence for 2015
Jimmy Santiago Baca
The College of Humanities and Social Sciences
Main Building
Room 1015-South
One Main Street
Houston, TX 77002
Phone: 713-221-8009
Fax: 713-223-7465
E-mail: email@example.com
D. Fulton, Ph.D., Dean
D. Ryden, Ph.D., Associate Dean
C. Guillory, M.A., Assistant Dean
CHSS Advising
Related Links
Page maintained by CHSS Web
Last updated or reviewed on 12/12/14


text: Screenshot YouTube [ Footage Captures NYC Blizzard from 1902 [VIDEO] By Double Down February 5, 2014 If there all the snow and ice that New Jersey has been bombarded with has you down, just think it could be worse. Read More|Comment Category: Host Posts, Jim Gearhart Show, Videos Tags: blizzard footage, vintage footage Send to a friend! Share on Facebook Share on Twitter Pin it! Reddit This! Share on Tumblr!


text:
How's it going?
New guy from SW Florida. 2008 PreRunner Dbl Cab. I just picked her up about a month or so ago as a to me from me graduation present, and its been a blast ever since. I upgraded from an 03 corolla and wouldn't go back if you offered me money (or gas money).
The site looks awesome, btw.


text:
Blue Man Group
The Blue Man Group is like the heartbeat of Berlin: intense, innovative, and creative as well as being a little crazy! A unique show now famous all over the...
More DetailsPersonnel marketing and development, HR policy, change strategy, career management and outplacement. Kurfuerstendamm 54/55, 10707 Berlin.
Director-level consultation, conception and creation, campaign and marketing activities, PR and media relations. Rotherstrasse 21, 10245 Berlin.
Business expansion and acquisition analysis, business plan development, business valuations, financial advice, tax matters including international. Am Studio 22, 12489 Berlin-Adlershof.
Atheneum is a global expert platform and advisory firm that connects investment houses, consulting companies, corporations, research institutes and organizations with >100,000 leading industry specialists in order to access key market intelligence.
Offering management consulting services to small and medium-sized companies, practical support, restructure strategic direction, importing into Germany, build and expand local enterprises. Friedrichstr. 171 Einstein Palais, 10117 Berlin-Mitte.
Executive Search Firm sourcing professionals in IT, telecoms, new media, engineering, manufacturing, consumer, retail, logistics, media, entertainment, pharmaceuticals and biomedical technology, professional services. Hohenzollerndamm 187, 10713 Berlin.
Information for companies interested in investing in Berlin including business promotion, resettlement, foreign trade support and capital city marketing.
Training, consulting and project management developing local economy, project teams as well as European networking: In some cases the success-factor is simply software training, in other situations facilitation of your workshop may be the right strategy.
Advice for foreign companies interested in relocating or expanding their business in Berlin.
Career coaching in English and German for foreign job seekers wanting to position themselves on the German job market. Core elements include self assessment, application documents, networking strategies and intercultural issues.
Offering services for global minds, international companies, expats and diplomats. Consulting services include: International Sales & Marketing, Intercultural Competence, Expat Relocation Services, and Virtual Teams.
Specializing in online food orders for Berlin's local restaurants.
Business start-up including strategy search, feasibility assessment, business plan, support in procedures for start ups, management training. CityQuartier DomAquaree, Karl-Liebknecht-Strasse 5, 10178 Berlin.
Auditing, tax, legal and management consultancy, accounting and personnel management services. Chausseestrasse 128/129, 10115 Berlin.
International business strategies, strategic IT management, technology and innovation management. Kurfuerstendamm 30, 10719 Berlin.
Independent consultants specialising in company management, controlling, company foundation and development. Kronprinzendamm 1, 10711 Berlin-Grunewald.
Tourism related services for low and middle income countries offering consulting on strategies, systems, product development and policy; consulting of public, private and PPP institutions and teaching and training.
International business consultants. Experts in corporate finance, marketing and corporate development. At Boelckestrasse 122, 12101 Berlin-Tempelhof.
Culture specific and general training, business specific training, diversity management, team development, virtual communication, coaching and consulting, tolerance enhancement and cultural diversity programs. Berchtesgadener Strasse 18/19, 10825 Berlin.
Service for Expats, assignees & their families, to bridge the gap between finalized relocation & living in Germany, assist with personal administration, manage ongoing private contracts, expenses & much more. See website for more information.
International non-profit organisation helping people to develop communication and business presentation skills and leadership capabilities. Regular meetings in English. At Carmerstr. 10 10623 Berlin-Charlottenburg.
A full-service e-payment provider, connecting consumers with merchants an electronic voucher network. Products include: Branded Products, Promotion Cards, E-voucher and Print Cards, Mobile Solutions, Multi-currency Processing.
Consultancy for a broad range of industries focussing on outplacement, coaching and employee appraisal analysis. Hegelplatz 1, 10117 Berlin-Mitte.
Offering executive recruitment, recruiting experts for small and medium companies in Berlin, as well as Germany and Europe. IT, engineering, sales & marketing, new media, finance, legal, office, human resources, gastro & hotel.
Online food ordering system/script for websites that has a responsive design, iPhone App and Android App, SMS, Reviews, Paypal, Discount Codes, Mercado Pago, Pop-up Add-on.
Offering executive coaching, development, next generation human resources, women in business leadership, leadership team development, coaching skills for leadership. Friedrichstr. 200, 10117 Berlin-Mitte.
Global consulting company providing industry-specialised knowledge and assistance. Accounting, auditing, taxation, management, corporate finance and business reconstruction. At Lise-Meitner-Strasse 1, 10589 Berlin-Charlottenburg.
Analysis and market research, strategy and PR management, press and marketing office services, creation and design, event management. Albrechtstr. 22, 10117 Berlin.
Service provider for small enterprises, SMEs and corporate logistics covering sea/air cargo transportation, disposal logistics and other consultancy services. Osdorfer Ring 5-11, 14979 Berlin-Grossbeeren.
Global market research and corporate intelligence firm providing qualitative, quantitative and strategic research services. Located at Friedrichstr. 90, 10117 Berlin-Mitte.
Specializing in price promotions in the consumer goods industry, using econometric methods to calculate the price reduction for consumers to switch brands and retailers. Price Promotions are delivered via mobile apps and digital printing.
Management consultancy with focus on asset performance, change management and business processes for multi-utilities and industrial clients. Leipziger Platz 2, 10117 Berlin.
Competence centre for women executives and leaders in business and politics. Provision of mentoring and career-building programmes.
offers a range of author and publishing services, creative writing workshops, manuscript assessment, mentoring, proof-reading, copy editing, translation, services for screen writers and playwrights.
Global business consultants and advisors. At Uhlandstr. 179/180, 10623 Berlin.
Business consultants. Active sales and marketing support for products and services. Development of conceptual design and (e-)marketing strategies for individual requirements. Neue Jakobstr.5, D-10179 Berlin.
Specializing in Mobile App Marketing. Offering planning, tracking, optimizing strategies for mobile media advertising over mobile ad networks, RTB exchanges, and media partners. Creates the optimal media mix for the app marketing lifecycle.
Tax Advisors, offering audit services, legal advice for businesses with real estate transactions, due diligence, reorganization, contract laws, successor models and asset transfer. Located at Cicerostr. 2, 10709 Berlin-Wilmersdorf.
womeninbiz.de is a network founded by women and for women. Its mission is to act as a catalyst for more women to set up, run and grow their own businesses through mentoring, networking, business seminars and peer groups.
Startup company developing smart phone applications to impact people's lives in a positive and meaningful way.
Add your organisation to the 2,954 businesses and services already listed in AngloINFO Berlin's Business Directory.
Yoga for Beginners class is for everyone – older and younger, men and women, athletes and... Read more...
Postable's innovative service makes it incredibly easy for US expats to send holiday... Read more...
Individual and Couples Therapy and Counselling with a multi-cultural focus for the ex-pat... Read more...
Tax consultancy, accounting, auditing, legal consultancy, business planning, management... Read more...


text:
Wood Designs Book Display Rack
Wood Designs Book Display Rack
Weights & Dimensions
Product Type: Book display | Frame Color: Natural |
Primary Material: Wood | Folding: No |
Double Sided: No | Toddler Size: No |
Compartments Included: No | Doors Included: No |
Casters Included: No | Country of Manufacture: United States |
About the Manufacturer
30 years ago, Wood Designs started with one goal: to be the best early childhood manufacturer in the country. 30 years later, they continue to strive in improvement. Wood Designs has been a leader in the use of the latest technological advances, making existing products not only better, but safer. Here, you'll find a wide selection of children's classroom furniture, classroom storage, play kitchen sets and other products that are sure to bring the best into any child's life.Wood Designs Book Display Rack
Still have questions about this product? We're here to help
Customer Reviews
5 star | 1 | |
4 star | 2 | |
3 star | 0 | |
2 star | 0 | |
1 star | 0 |
Small book shelf Elizabeth from Jacksonville, FL– Verified Buyer Exactly what I wanted, true to the picture, very pleased. |
Almost perfect Corinne the lawyer from McLean, VA– Verified Buyer I was looking for a desktop book rack to store my most frequently-used reference books. This was the perfect size, and does the trick. The only two features I would have wished for are availability in a dark wood, and a sliding bookend. |
Valued Customer from New York |
Book Display Rack is also sometimes listed under the following manufacturer numbers: 13900


text:
From Sunlen Miller:
President Obama is hosting Russian President Dmitry Medvedev for a day-long visit at the White House today. After the two presidents huddled this morning in a private Oval Office meeting and then an expanded meeting in the Cabinet Room, it was lunch time.
The American president took his counterpart for an American meal: a hamburger at Ray's Hell Burger in Arlington, Virginia.
Both leaders ordered cheeseburgers – Mr. Obama's with onions, lettuce, tomato and 'bread and butter' pickles along with an iced tea. Medvedev's burger: onions, jalapenos and mushrooms, with a Coca-Cola. The two leaders shared fries and ate together at a table with a roll of paper towels for napkins. The president explained to Medvedev that Ray's burgers are "messy" to eat.
This is Mr. Obama's second visit to Ray's – he ate there last year with Vice President Biden.
-Sunlen Miller


text:
Last Night in London
- Posted by Rand Fishkin to Events
- My presentation on Analytics was great fun (download the PPT here). I fought a bit with Brian Clifton from Google Analytics - do they really have action tracking? Last time I looked (a few months back), their segmentation tools were virtually non-existent. He's a bit of a combatitive guy (damn smart, too), but it made the session incredibly engaging. I think the SES crowd loves a good conflict.
- Rebecca and Scott made it back from Paris - they'll give that good run-down, but suffice to say, they're in one piece and haven't yet been lured to the dark side by the blackhats who paid for their trip (300 quid to take the train!)
- I couldn't make the LondonSEO party, but I really wanted to, as I missed folks like Ammon Johns & Lisa Ditlefsen (who I promised I'd see). If I wasn't so ungodly sick, I surely would have come.
- Yahoo!'s results seem to be amazingly good lately. Several folks have remarked on it, and I think it might be worth doing a side-by-side comparison.
- Matt Cutts got mobbed in the speaker room a few times - they normally have security there, but it would appear the Brits are too powerful for that. I think Matt was struggling to cope with the deluge - it looked worse than San Jose or New York. British Cuttlets are going down in my books as the most relentless; I'm impressed. It must be all that advice you see at forums suggesting that a webmaster "goes and tracks down MC at a conference." Hopefully his Dublin trip will be a bit calmer.
- As I'm sitting at the conference hall exit, sniffling into my toilet paper and feeling entirely awful, Sosh Howell, whom I've never met before asks if I'm sick. When I reply in the affirmative, he gives me some British Theraflu type medicine which really helped me catch some zzzs this afternoon. Thanks, Sosh, you're a lifesaver.
- Thomas Bindl stopped by as I was scarfing down a burger in the hotel bar (around 10pm) with some more goodies, and an invite to SES Munich. If Mystery Guest can make it, I'm in, if not, I just can't leave her alone so much - I really feel like this week was hard for both of us.
- Met one of Matt's web spam team guys, Brian White, today - as friendly as they come. He really reminded me of Detlev Johnson for some reason. We talked a bit about international domain issues and duplicate content - a question which, at this time, still doesn't have a good answer.


text:
ShelterLogic 90402 Firewood Rack Fire Pit Accessory
By ShelterLogic
Height: 46.6in
Length: 96.2in
Width: 15.5in
Weight: 34.8lbs
8' Firewood Rack with Cover Firewood is safely stored and ready to use in a year round firewood storage solution. Great for backyard wood storage. Features: Holds 2/5 Cord / 1.4 cubic meters Complete wood storage rack and cover in one Easy assembly, all steel frame rack with black powder coat finish Keeps wood off of the ground eliminating bugs, mold growth, and rotting Open air design delivers excellent ventilation, perfect for seasoning firewood Waterproof cover adjusts to fit split wood up to 24" / 61 cm in length Adjustable cover slides up and down to fit height of wood stack Includes: (1) Round 1 1/2" / 3.8 cm tube frame (1) Black Polyester Cover Instruction manual Rack Frame 96.2" x 46.6" x 15.5"