diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs
index 8cd57d1bf6663181d3ad1c1bb9f7a233895fc092..5fabfe2f738cf2852306ae7a0ef1bf7a2abc69cb 100644
--- a/compiler/main/DynFlags.hs
+++ b/compiler/main/DynFlags.hs
@@ -310,8 +310,8 @@ data GeneralFlag
    | Opt_LLF_UseStr        -- ^ use strictness in the late-float
    | Opt_LLF_IgnoreLNEClo        -- ^ predict LNEs in the late-float
    | Opt_LLF_FloatLNE0        -- ^ float zero-arity LNEs
+   | Opt_LLF_OneShot
    | Opt_LLF_Retry
-   | Opt_LLF_SinglySAT
 
    -- Interface files
    | Opt_IgnoreInterfacePragmas
@@ -2566,9 +2566,8 @@ fFlags = [
   ( "late-float-use-strictness",        Opt_LLF_UseStr, nop),
   ( "late-float-ignore-LNE-clo",        Opt_LLF_IgnoreLNEClo, nop),
   ( "late-float-LNE0",                  Opt_LLF_FloatLNE0, nop),
-  ( "late-float-retry",                 Opt_LLF_Retry, nop),
-  ( "late-float-singly-SAT-fallback",   Opt_LLF_SinglySAT, nop)
-
+  ( "late-float-oneshot",               Opt_LLF_OneShot, nop),
+  ( "late-float-retry",                 Opt_LLF_Retry, nop)
   ]
 
 -- | These @-f\<blah\>@ flags can all be reversed with @-fno-\<blah\>@
diff --git a/compiler/simplCore/CoreMonad.lhs b/compiler/simplCore/CoreMonad.lhs
index 15f952a97902ef6ec33385cf9449e4fe603dfb3d..2fd534b7a9f3ce4c7edcf68ceb003654a40affd6 100644
--- a/compiler/simplCore/CoreMonad.lhs
+++ b/compiler/simplCore/CoreMonad.lhs
@@ -387,10 +387,8 @@ data FinalPassSwitches = FinalPassSwitches
   , fps_strictness        :: !Bool
   , fps_ignoreLNEClo      :: !Bool
   , fps_floatLNE0         :: !Bool
+  , fps_oneShot           :: !Bool
   , fps_retry             :: !Bool
-  , fps_singlySAT         :: !Bool
-  -- ^ if a singly recursive let is entered by its body no more than
-  -- once, perform SAT and then float
   }
 
 instance Outputable FloatOutSwitches where
diff --git a/compiler/simplCore/SetLevels.lhs b/compiler/simplCore/SetLevels.lhs
index 21ed653bd9e35b136bf9d2990e5379ba56ddf24b..d2db375380a235a0f101851b1575ab4b73ad6f40 100644
--- a/compiler/simplCore/SetLevels.lhs
+++ b/compiler/simplCore/SetLevels.lhs
@@ -71,7 +71,7 @@ import CoreSyn
 import CoreUnfold       ( mkInlinableUnfolding )
 import CoreMonad	( FloatOutSwitches(..), FinalPassSwitches(..) )
 import CoreUtils	( exprType, exprOkForSpeculation, exprIsHNF )
-import CoreArity	( exprArity, exprBotStrictness_maybe )
+import CoreArity	( exprBotStrictness_maybe )
 import CoreFVs		-- all of it
 import Coercion         ( isCoVar )
 import CoreSubst	( Subst, emptySubst, extendInScope, substBndr, substRecBndrs,
@@ -736,7 +736,7 @@ lvlBind ctxt_lvl env binding@(AnnNonRec (TB bndr _) rhs)
   | otherwise =
     case decideBindFloat ctxt_lvl env (isJust mb_bot) binding of
       Nothing -> doNotFloat
-      Just (x,y,_) -> uncurry doFloat (x,y)
+      Just p -> uncurry doFloat p
   where
     mb_bot     = exprBotStrictness_maybe (deTag $ deAnnotate rhs)
     bndr_w_str = annotateBotStr bndr mb_bot
@@ -779,46 +779,14 @@ lvlBind ctxt_lvl env binding@(AnnRec pairsTB) =
     rhss' <- mapM (lvlExpr bind_lvl env') rhss
     return (Rec (tagged_bndrs `zip` rhss'), bind_lvl, env')
 
-  Just (dest_lvl, abs_vars, need_SAT) -- decided to float
+  Just (dest_lvl, abs_vars) -- decided to float
     | null abs_vars -> do
       (new_env, new_bndrs) <- cloneRecVars env bndrs dest_lvl
       new_rhss <- mapM (lvlExpr ctxt_lvl new_env) rhss
       return ( Rec ([TB b (FloatMe dest_lvl) | b <- new_bndrs] `zip` new_rhss)
              , ctxt_lvl, new_env)
 
-    | need_SAT, [(TB bndr _, rhs)] <- pairsTB -> do
-        -- Special case for self recursion where there are
-        -- several variables carried around: build a local loop:        
-        --      poly_f = \abs_vars. \lam_vars . letrec f = \lam_vars. rhs in f lam_vars
-        -- This just makes the closures a bit smaller.  If we don't do
-        -- this, allocation rises significantly on some programs
-        --
-        -- We could elaborate it for the case where there are several
-        -- mutually functions, but it's quite a bit more complicated
-        -- 
-        -- This all seems a bit ad hoc -- sigh
-      let
-          (rhs_lvl, abs_vars_w_lvls) = lvlLamBndrs dest_lvl abs_vars
-          rhs_env = extendLvlEnv env abs_vars_w_lvls
-      (rhs_env', new_bndr) <- cloneVar rhs_env bndr rhs_lvl
-      let
-          (lam_bndrsTB, rhs_body)   = collectAnnBndrs rhs
-          lam_bndrs                 = map unTag lam_bndrsTB
-          (body_lvl, new_lam_bndrs) = lvlLamBndrs rhs_lvl lam_bndrs
-          body_env                  = extendLvlEnv rhs_env' new_lam_bndrs
-      new_rhs_body <- lvlExpr body_lvl body_env rhs_body
-      (poly_env, [poly_bndr]) <- newPolyBndrs dest_lvl env abs_vars [bndr]
-      return (Rec [(TB poly_bndr (FloatMe dest_lvl) 
-                   , mkLams abs_vars_w_lvls $
-                     mkLams new_lam_bndrs $
-                     Let (Rec [( TB new_bndr (StayPut rhs_lvl)
-                               , mkLams new_lam_bndrs new_rhs_body)]) 
-                         (mkVarApps (Var new_bndr) lam_bndrs))]
-             , ctxt_lvl
-             , poly_env)
-
-    | otherwise -> ASSERT( not need_SAT )
-                   do  -- Non-null abs_vars, do not SAT
+    | otherwise -> do  -- Non-null abs_vars
       (new_env, new_bndrs) <- newPolyBndrs dest_lvl env abs_vars bndrs
       new_rhss <- mapM (lvlFloatRhs abs_vars dest_lvl new_env) rhss
       return ( Rec ([TB b (FloatMe dest_lvl) | b <- new_bndrs] `zip` new_rhss)
@@ -828,17 +796,17 @@ decideBindFloat ::
   Level -> LevelEnv ->
   Bool -> -- is it a bottoming non-rec RHS?
   CoreBindWithBoth ->
-  Maybe (Level,[Var],Bool) -- Nothing <=> do not float
-                           --
-                           -- Just (lvl, vs, b) <=> float to lvl using
-                           -- vs as the abs_vars, if b then SAT first
+  Maybe (Level,[Var]) -- Nothing <=> do not float
+                      --
+                      -- Just (lvl, vs) <=> float to lvl using vs as
+                      -- the abs_vars
 decideBindFloat ctxt_lvl init_env is_bot binding =
   maybe conventionalFloatOut lateLambdaLift (finalPass env)
   where
     env | isLNE     = lneLvlEnv init_env ids
         | otherwise = init_env
 
-    conventionalFloatOut | isProfitableFloat = Just (dest_lvl, abs_vars, False)
+    conventionalFloatOut | isProfitableFloat = Just (dest_lvl, abs_vars)
                          | otherwise         = Nothing
       where
         dest_lvl = destLevel env is_bot bindings_fvs
@@ -851,7 +819,7 @@ decideBindFloat ctxt_lvl init_env is_bot binding =
 
     lateLambdaLift fps
       | all_funs || (fps_floatLNE0 fps && isLNE), -- only late lift functions and zero-arity LNEs
-        Left b <- decider emptyVarEnv = Just (tOP_LEVEL, abs_vars, b)
+        Nothing <- decider emptyVarEnv = Just (tOP_LEVEL, abs_vars)
            -- TODO Just x <- decider emptyVarEnv -> do the retry stuff
       | otherwise = Nothing -- do not lift
       where
@@ -859,7 +827,7 @@ decideBindFloat ctxt_lvl init_env is_bot binding =
         abs_ids_set = expandFloatedIds env $ mapVarEnv fii_var bindings_fiis
         abs_ids  = varSetElems abs_ids_set
 
-        decider = decideLateLambdaFloat env isRec isLNE potential_SAT_float abs_ids_set badTime spaceInfo ids extra_sdoc fps
+        decider = decideLateLambdaFloat env isRec isLNE all_one_shot abs_ids_set badTime spaceInfo ids extra_sdoc fps
 
         badTime   = wouldIncreaseRuntime    env abs_ids bindings_fiis
         spaceInfo = wouldIncreaseAllocation env isLNE abs_ids_set rhs_silt_s scope_silt
@@ -867,44 +835,39 @@ decideBindFloat ctxt_lvl init_env is_bot binding =
         -- for -ddump-late-float with -dppr-debug
         extra_sdoc = text "scope_silt:" <+> ppr scope_silt
 
-        potential_SAT_float
-          | fps_singlySAT fps,
-            isOnce,
-            AnnRec [(TB b (_,_,CloB _ body_silt), rhs)] <- binding
-            = let spaceInfo = wouldIncreaseAllocation env isLNE abs_ids_set rhs_silt_s body_silt
-              in Just (b, rhs, spaceInfo)
-          | otherwise = Nothing
-
     rhs_silt_s :: [(CoreBndr, FISilt)]
     (isRec, ids,
-     isLNE, isOnce,
+     isLNE,
      scope_silt,
      all_funs,
      bindings_fvs, bindings_fiis,
-     rhs_silt_s
+     rhs_silt_s,
+     all_one_shot
      ) = case binding of
-      AnnNonRec (TB bndr (isLNE,isOnce,bsilt)) rhs ->
+      AnnNonRec (TB bndr (isLNE,bsilt)) rhs ->
         (False, [bndr]
-        ,isLNE, isOnce
+        ,isLNE
         ,case bsilt of
            BoringB -> emptySilt
-           CloB scope _ -> scope
+           CloB scope -> scope
         ,isFunctionAnn rhs
         ,fvsOf rhs `unionVarSet` idFreeVars bndr   ,   siltFIIs rhs_silt
         ,[(bndr, rhs_silt)]
+        ,is_OneShot rhs
         )
         where rhs_silt = siltOf rhs
-      AnnRec pairs@((TB _ (isLNE,isOnce,bsilt),_):_) ->
-                 -- the LNE and Once properties and the scope and body
-                 -- silts silt are the same for each
+      AnnRec pairs@((TB _ (isLNE,bsilt),_):_) ->
+                 -- the LNE property and the scope silt are the same
+                 -- for each
         (True, bndrs
-        ,isLNE, isOnce
+        ,isLNE
         ,case bsilt of
            BoringB -> emptySilt
-           CloB scope _ -> scope
+           CloB scope -> scope
         ,all isFunctionAnn rhss
         ,delBindersFVs bndrs rhss_fvs   ,   siltFIIs $ delBindersSilt bndrs rhss_silt
         ,rhs_silt_s
+        ,all is_OneShot rhss
         )
         where (tbs,rhss) = unzip pairs
               bndrs = map unTag tbs
@@ -913,30 +876,33 @@ decideBindFloat ctxt_lvl init_env is_bot binding =
               rhss_fvs  = computeRecRHSsFVs bndrs (map fvsOf rhss)
       _ -> panic "decideBindFloat"
 
+    is_OneShot e = case collectBinders $ deTag $ deAnnotate e of
+      (bs,_) -> all (\b -> isId b && isOneShotBndr b) bs
+
 decideLateLambdaFloat ::
   LevelEnv ->
   Bool ->
-  Bool -> Maybe (CoreBndr, CoreExprWithBoth, (IdSet -> [(Bool, WordOff, WordOff, WordOff)])) ->
+  Bool ->
+  Bool ->
   IdSet ->
   IdSet -> (IdSet -> [(Bool, WordOff, WordOff, WordOff)]) ->
   [Id] -> SDoc ->
   FinalPassSwitches ->
   VarSet -> -- pinnees to ignore
-  Either Bool VarSet -- Left x <=> float to tOP_LEVEL (SAT first if x)
-                     --
-                     -- Right x <=> do not float, not (null x) <=>
-                     -- forgetting fast calls to the ids in x are the
-                     -- only thing pinning this binding
-decideLateLambdaFloat env isRec isLNE potential_SAT_float abs_ids_set badTime spaceInfo' ids extra_sdoc fps pinnees
+  Maybe VarSet -- Nothing <=> float to tOP_LEVEL
+               --
+               -- Just x <=> do not float, not (null x) <=> forgetting
+               -- fast calls to the ids in x are the only thing
+               -- pinning this binding
+decideLateLambdaFloat env isRec isLNE all_one_shot abs_ids_set badTime spaceInfo' ids extra_sdoc fps pinnees
   = (if fps_trace fps then pprTrace ('\n' : msg) msg_sdoc else (\x -> x)) $
-    if floating then Left isBadSpace else Right $
-    if floating_space
-    then unionVarSet badTime spoiledLNEs
+    if floating then Nothing else Just $
+    if isBadSpace
+    then emptyVarSet -- do not float, ever
+    else unionVarSet badTime spoiledLNEs
          -- not floating, in order to not abstract over these
-    else emptyVarSet -- do not float, ever
   where
-    floating = not $ spoilsLNEs || isBadTime || (isBadSpace && isBadSpace2)
-    floating_space = not $ isBadSpace && isBadSpace2
+    floating = not $ spoilsLNEs || isBadTime || isBadSpace
 
     msg = (if floating then "late-float" else "late-no-float")
           ++ (if isRec then "(rec " ++ show (length ids) ++ ")" else "")
@@ -950,14 +916,10 @@ decideLateLambdaFloat env isRec isLNE potential_SAT_float abs_ids_set badTime sp
                | otherwise = not $ isEmptyVarSet spoiledLNEs
     spoiledLNEs = le_LNEs env `intersectVarSet` abs_ids_set
 
-    isBadSpace = flip any spaceInfo $ \(createsPAPs, cloSize, cg, cgil) ->
+    isBadSpace | fps_oneShot fps && all_one_shot = False
+               | otherwise    = flip any spaceInfo $ \(createsPAPs, cloSize, cg, cgil) ->
       papViolation createsPAPs || cgViolation (cg - cloSize) || cgilViolation cgil
 
-    isBadSpace2 = case potential_SAT_float of
-      Nothing -> True
-      Just (_,_,spaceInfo') -> flip any (spaceInfo' pinnees) $ \(createsPAPs, _, cg, cgil) ->
-        papViolation createsPAPs || cgViolation cg || cgilViolation cgil
-
     papViolation x | fps_createPAPs fps = False
                    | otherwise = x
 
@@ -983,14 +945,13 @@ decideLateLambdaFloat env isRec isLNE potential_SAT_float abs_ids_set badTime sp
     msg_sdoc = vcat (zipWith space ids spaceInfo) where
       abs_ids = varSetElems abs_ids_set
       space v (badPAP, closureSize, cg, cgil) = vcat
-       [ ppr v <+> if isLNE then parens (text "LNE") else empty <+> if isJust potential_SAT_float then parens (text "once") else empty
+       [ ppr v <+> if isLNE then parens (text "LNE") else empty
        , text "size:" <+> ppr closureSize
        , text "abs_ids:" <+> ppr (length abs_ids) <+> ppr abs_ids
        , text "pinnees:" <+> ppr (varSetElems pinnees)
        , text "createsPAPs:" <+> ppr badPAP
        , text "closureGrowth:" <+> ppr cg
        , text "CG in lam:"   <+> ppr cgil
-       , text "CG body OK:" <+> ppr (not isBadSpace2)
        , text "fast-calls:" <+> ppr (varSetElems badTime)
        , text "spoiledLNEs:" <+> ppr spoiledLNEs
        , if opt_PprStyle_Debug then extra_sdoc else empty
@@ -1004,22 +965,18 @@ wouldIncreaseRuntime ::
   [Id] ->      -- the abstracted value ids
   FIIs ->      -- FIIs for the bindings' RHS
   VarSet       -- the forgotten ids
-wouldIncreaseRuntime env abs_ids binding_group_fiis =
-  case prjFlags `fmap` finalPass env of
+wouldIncreaseRuntime env abs_ids binding_group_fiis = case prjFlags `fmap` finalPass env of
   -- is final pass...
   Just (noUnder, noExact, noOver) | noUnder || noExact || noOver ->
     mkVarSet $ flip mapMaybe abs_ids $ \abs_id ->
       case lookupVarEnv binding_group_fiis abs_id of
-        Just fii | not (unapplied||under||exact||over), -- is used
-                   arity > 0, -- NB (arity > 0) iff "is known function"
+        Just fii | idArity abs_id > 0, -- NB (arity > 0) iff "is known function"
+                   under||exact||over, -- is applied
                       (noUnder && under)
                    || (noExact && exact)
                    || (noOver  && over)
                  -> Just abs_id
-          where arity = idArity (fii_var fii)
-                  -- NB cannot use abs_id here! As a parameter, its
-                  -- arity is 0.
-                (unapplied,under,exact,over) = fii_useInfo fii
+          where (_unapplied,under,exact,over) = fii_useInfo fii
         _ -> Nothing
   _ -> emptyVarSet
   where prjFlags fps = ( not (fps_absUnsatVar   fps) -- -fno-late-abstract-undersat-var
@@ -1027,12 +984,16 @@ wouldIncreaseRuntime env abs_ids binding_group_fiis =
                        , not (fps_absOversatVar fps) -- -fno-late-abstract-oversat-var
                        )
 
--- if a free id was floated, then its abs_ids are now free ids
+-- if a free id was floated, then its abs_ids are now free ids (and so
+-- on)
 expandFloatedIds :: LevelEnv -> IdSet -> IdSet
-expandFloatedIds env = foldl snoc emptyVarSet . varSetElems where
+expandFloatedIds env = w . varSetElems where
+   w = foldl snoc emptyVarSet
+
    snoc acc id = case lookupVarEnv (le_env env) id of
      Nothing            -> extendVarSet acc id
-     Just (abs_vars, _) -> extendVarSetList acc $ filter isId abs_vars
+     Just (_,abs_vars, _) -> extendVarSetList acc $ filter isId abs_vars
+      -- TODO unionVarSet acc $ w $ filter isId abs_vars
 
 wouldIncreaseAllocation ::
   LevelEnv ->
@@ -1242,7 +1203,7 @@ data LevelEnv
                                         -- The Id -> CoreExpr in the Subst is ignored
                                         -- (since we want to substitute in LevelledExpr
                                         -- instead) but we do use the Co/TyVar substs
-       , le_env      :: IdEnv ([Var], LevelledExpr)	-- Domain is pre-cloned Ids
+       , le_env      :: IdEnv (Var,[Var], LevelledExpr)	-- Domain is pre-cloned Ids
        , le_dflags   :: DynFlags
        , le_LNEs     :: VarSet
     }
@@ -1332,7 +1293,7 @@ extendCaseBndrLvlEnv :: LevelEnv -> Expr LevelledBndr
 extendCaseBndrLvlEnv le@(LE { le_subst = subst, le_env = id_env }) 
                      (Var scrut_var) (TB case_bndr _)
   = le { le_subst   = extendSubstWithVar subst case_bndr scrut_var
-       , le_env     = extendVarEnv id_env case_bndr ([scrut_var], ASSERT(not (isCoVar scrut_var)) Var scrut_var) }
+       , le_env     = extendVarEnv id_env case_bndr (scrut_var,[], ASSERT(not (isCoVar scrut_var)) Var scrut_var) }
      
 extendCaseBndrLvlEnv env _scrut case_bndr
   = extendLvlEnv env [case_bndr]
@@ -1348,7 +1309,7 @@ extendPolyLvlEnv dest_lvl
   where
      add_lvl   env (_, v') = extendVarEnv env v' dest_lvl
      add_subst env (v, v') = extendIdSubst env v (mkVarApps (Var v') abs_vars)
-     add_id    env (v, v') = extendVarEnv env v ((v':abs_vars), mkVarApps (Var v') abs_vars)
+     add_id    env (v, v') = extendVarEnv env v (v',abs_vars, mkVarApps (Var v') abs_vars)
 
 extendCloneLvlEnv :: Level -> LevelEnv -> Subst -> [(Var, Var)] -> LevelEnv
 extendCloneLvlEnv lvl le@(LE { le_lvl_env = lvl_env, le_env = id_env }) 
@@ -1360,7 +1321,7 @@ extendCloneLvlEnv lvl le@(LE { le_lvl_env = lvl_env, le_env = id_env })
      add_lvl env (_, v_cloned) = extendVarEnv env v_cloned lvl
      add_id  env (v, v_cloned) = if isTyVar v
                                  then delVarEnv    env v
-                                 else extendVarEnv env v ([v_cloned], ASSERT(not (isCoVar v_cloned)) Var v_cloned)
+                                 else extendVarEnv env v (v_cloned,[], ASSERT(not (isCoVar v_cloned)) Var v_cloned)
 
 maxFvLevel :: (Var -> Bool) -> LevelEnv -> VarSet -> Level
 maxFvLevel max_me (LE { le_lvl_env = lvl_env, le_env = id_env }) var_set
@@ -1368,7 +1329,7 @@ maxFvLevel max_me (LE { le_lvl_env = lvl_env, le_env = id_env }) var_set
   where
     max_in in_var lvl 
        = foldr max_out lvl (case lookupVarEnv id_env in_var of
-				Just (abs_vars, _) -> abs_vars
+				Just (v,abs_vars, _) -> v:abs_vars
 				Nothing		   -> [in_var])
 
     max_out out_var lvl 
@@ -1379,7 +1340,7 @@ maxFvLevel max_me (LE { le_lvl_env = lvl_env, le_env = id_env }) var_set
 
 lookupVar :: LevelEnv -> Id -> LevelledExpr
 lookupVar le v = case lookupVarEnv (le_env le) v of
-		    Just (_, expr) -> expr
+		    Just (_, _, expr) -> expr
 		    _              -> Var v
 
 abstractVars :: Level -> LevelEnv -> VarSet -> [Var]
@@ -1412,7 +1373,7 @@ abstractVars dest_lvl (LE { le_lvl_env = lvl_env, le_env = id_env }) fvs
 		     setIdInfo v vanillaIdInfo
 	  | otherwise = v
 
-absVarsOf :: IdEnv ([Var], LevelledExpr) -> Var -> VarSet
+absVarsOf :: IdEnv (Var,[Var], LevelledExpr) -> Var -> VarSet
 	-- If f is free in the expression, and f maps to poly_f a b c in the
 	-- current substitution, then we must report a b c as candidate type
 	-- variables
@@ -1421,8 +1382,8 @@ absVarsOf :: IdEnv ([Var], LevelledExpr) -> Var -> VarSet
 	-- we must look in x's type. What's more, if a mentions kind variables,
 	-- we must also return those.
 absVarsOf id_env v 
-  | isId v, Just (abs_vars, _) <- lookupVarEnv id_env v
-  = foldr (unionVarSet . close) emptyVarSet abs_vars
+  | isId v, Just (v,abs_vars, _) <- lookupVarEnv id_env v
+  = foldr (unionVarSet . close) emptyVarSet (v:abs_vars)
   | otherwise
   = close v
   where
@@ -1629,10 +1590,10 @@ as a free variable. That's the behavior we currently intend.
 -- decideLateLambdaFloat.
 data BSilt
   = BoringB
-  | CloB FISilt FISilt -- scope, body; cf Note [singly SAT fallback]
+  | CloB FISilt
 
-type CoreBindWithBoth = AnnBind (TaggedBndr (Bool,Bool,BSilt)) (VarSet,FISilt)
-type CoreExprWithBoth = AnnExpr (TaggedBndr (Bool,Bool,BSilt)) (VarSet,FISilt)
+type CoreBindWithBoth = AnnBind (TaggedBndr (Bool,BSilt)) (VarSet,FISilt)
+type CoreExprWithBoth = AnnExpr (TaggedBndr (Bool,BSilt)) (VarSet,FISilt)
 
 siltOf :: CoreExprWithBoth -> FISilt
 siltOf = snd . fst
@@ -1883,9 +1844,6 @@ data FVUp = FVUp {
   fvu_fvs :: VarSet,  -- free vars of E
   fvu_escapes :: IdSet, -- variables that occur escapingly in E; see
                          -- Note [recognizing LNE]
-  fvu_once :: VarEnv Bool, -- variables whose binding group is entered
-                           -- from outside that binding group at most
-                           -- once
 
   fvu_floats :: FIFloats, -- the floats, F
 
@@ -1895,17 +1853,10 @@ data FVUp = FVUp {
     -- fvu_isTrivial up <=> cpe_ExprIsTrivial (perhapsWrapFloatsFVUp up)
   }
 
-bothOnce :: VarEnv Bool -> VarEnv Bool -> VarEnv Bool
-bothOnce = plusVarEnv_C (\_ _ -> False)
-
-altOnce :: VarEnv Bool -> VarEnv Bool -> VarEnv Bool
-altOnce = plusVarEnv_C (&&)
-
 litFVUp :: FVUp
 litFVUp = FVUp {
   fvu_fvs = emptyVarSet,
   fvu_escapes = emptyVarSet,
-  fvu_once = emptyVarEnv,
   fvu_floats = emptyFloats,
   fvu_silt = emptySilt,
   fvu_isTrivial = True
@@ -1914,11 +1865,10 @@ litFVUp = FVUp {
 typeFVUp :: VarSet -> FVUp
 typeFVUp tyvars = litFVUp {fvu_fvs = tyvars}
 
-varFVUp :: Var -> Bool -> Bool -> Bool -> UseInfo -> FVUp
-varFVUp v escapes nonTopLevel isOnce usage = FVUp {
+varFVUp :: Var -> Bool -> Bool -> UseInfo -> FVUp
+varFVUp v escapes nonTopLevel usage = FVUp {
   fvu_fvs     = if local                  then unitVarSet v      else emptyVarSet,
   fvu_escapes = if nonTopLevel && escapes then unitVarSet v      else emptyVarSet,
-  fvu_once    = if nonTopLevel && isOnce  then unitVarEnv v True else emptyVarEnv,
   fvu_floats  = emptyFloats,
   fvu_silt = if nonTopLevel then FISilt [] (unitFIIs v usage) NilSk else emptySilt,
   fvu_isTrivial = True
@@ -1932,15 +1882,14 @@ lambdaLikeFVUp :: [CoreBndr] -> FVUp -> FVUp
 lambdaLikeFVUp bs up = up {
   fvu_fvs = del (fvu_fvs up),
   fvu_escapes = del (fvu_escapes up),
-  fvu_once = fvu_once up `delVarEnvList` bs,
   fvu_floats = emptyFloats,
   fvu_silt = delBindersSilt bs $ fvu_floats up `wrapFloats` fvu_silt up
   }
   where del = delBindersFVs bs
 
 -- see Note [FVUp for closures and floats]
-floatFVUp :: FVEnv -> Maybe Id -> Bool -> Bool -> Bool -> CoreExpr -> FVUp -> FVUp
-floatFVUp env mb_id use_case isLNE isOnce rhs up =
+floatFVUp :: FVEnv -> Maybe Id -> Bool -> Bool -> CoreExpr -> FVUp -> FVUp
+floatFVUp env mb_id use_case isLNE rhs up =
   let rhs_floats@(FIFloats _ _ bndrs_floating_out _ _) = fvu_floats up
 
       FISilt m fids sk = fvu_silt up
@@ -1967,8 +1916,6 @@ floatFVUp env mb_id use_case isLNE isOnce rhs up =
     -- if it's a proper closure, all ids escape
     fvu_escapes = let proper = not $ use_case || isLNE
                   in if proper then fvu_fvs up else fvu_escapes up,
-    fvu_once = if isOnce then fvu_once up
-               else mapVarEnv (const False) (fvu_once up),
 
     -- we are *moving* the fvu_silt to a new float
     fvu_floats = rhs_floats `appendFloats` new_float,
@@ -2030,15 +1977,15 @@ extendEnv bndrs env =
 analyzeFVs :: FVEnv -> CoreExpr -> CoreExprWithBoth
 analyzeFVs env e = fst $ runIdentity $ analyzeFVsM env e
 
-boringBinder :: CoreBndr -> TaggedBndr (Bool,Bool,BSilt)
-boringBinder b = TB b (False, False, BoringB)
+boringBinder :: CoreBndr -> TaggedBndr (Bool,BSilt)
+boringBinder b = TB b (False, BoringB)
 
 ret :: FVUp -> a -> FVM (((VarSet,FISilt), a), FVUp)
 ret up x = return (((fvu_fvs up,fvu_silt up),x),up)
 
 analyzeFVsM :: FVEnv -> CoreExpr -> FVM (CoreExprWithBoth, FVUp)
 analyzeFVsM  env (Var v) = ret up $ AnnVar v where
-  up = varFVUp v escapes nonTopLevel isOnce usage
+  up = varFVUp v escapes nonTopLevel usage
 
   n_runtime_args = fve_runtimeArgs env
 
@@ -2046,17 +1993,15 @@ analyzeFVsM  env (Var v) = ret up $ AnnVar v where
 
   arity = idArity v
   usage = (0     == n_runtime_args -- unapplied
-          ,arity >  n_runtime_args -- too few args
-          ,arity == n_runtime_args -- exact args
-          ,arity >  n_runtime_args -- too many args
+          ,w $ arity >  n_runtime_args -- too few args
+          ,w $ arity == n_runtime_args -- exact args
+          ,w $ arity <  n_runtime_args -- too many args
           )
+    where w x = (0 /= n_runtime_args) && x
 
   -- a variable escapes if it is under- or over-saturated
   escapes = n_runtime_args /= arity
 
-  -- a variable is only entered once if it is at least saturated
-  isOnce = n_runtime_args >= arity
-
 analyzeFVsM _env (Lit lit) = ret litFVUp $ AnnLit lit
 
 analyzeFVsM  env (Lam b body) = do
@@ -2067,9 +2012,6 @@ analyzeFVsM  env (Lam b body) = do
   let up = lambdaLikeFVUp [b] body_up
 
       up' = up {
-        fvu_once = if oneshot then fvu_once up
-                   else mapVarEnv (const False) (fvu_once up),
-
         fvu_silt = case fvu_silt up of
           FISilt m fiis sk -> FISilt m fiis $ lamSk oneshot sk,
 
@@ -2111,7 +2053,7 @@ analyzeFVsM  env app@(App fun arg) = do
   let binding_up = -- does the argument itself float?
         if fvu_isTrivial rhs_up
         then rhs_up -- no, it does not
-        else floatFVUp env Nothing use_case False (0 == exprArity rhs) rhs rhs_up
+        else floatFVUp env Nothing use_case False rhs rhs_up
 
   -- lastly: merge the Ups
   let up = fun_up {
@@ -2119,7 +2061,6 @@ analyzeFVsM  env app@(App fun arg) = do
         -- the arg ids either occur in a closure, in a scrutinee, or
         -- as a function argument; all of which count as escaping
         fvu_escapes = fvu_escapes fun_up `unionVarSet` fvu_fvs arg_up,
-        fvu_once = fvu_once fun_up `bothOnce` fvu_once binding_up,
 
         fvu_floats  = fvu_floats fun_up `appendFloats` fvu_floats  binding_up,
         fvu_silt    = fvu_silt   fun_up `bothSilt`     fvu_silt    binding_up,
@@ -2145,7 +2086,6 @@ analyzeFVsM env (Case scrut bndr ty alts) = do
 
   let alts2 = snd $ unzip pairs
 
-  let alts_once = foldr altOnce emptyVarEnv  $ map fvu_once rhs_up_s
   let alts_silt = foldr altSilt emptySilt    $ map fvu_silt rhs_up_s
 
   let up = FVUp {
@@ -2156,7 +2096,6 @@ analyzeFVsM env (Case scrut bndr ty alts) = do
         fvu_escapes = unionVarSets (map fvu_escapes rhs_up_s)
                         `delVarSet` bndr
                         `unionVarSet` scrut_fvs,
-        fvu_once = fvu_once scrut_up `bothOnce` alts_once,
 
         fvu_floats = fvu_floats scrut_up, -- nothing floats out of an alt
         fvu_silt   = fvu_silt scrut_up `bothSilt` delBindersSilt [bndr] alts_silt,
@@ -2174,17 +2113,13 @@ analyzeFVsM env (Let (NonRec binder rhs) body) = do
 
   -- step 2: recognize LNE
   let isLNE = not $ binder `elemVarSet` fvu_escapes body_up
-      isOnce = not (isId binder) || 0 == idArity binder ||
-        case lookupVarEnv (fvu_once body_up) binder of
-          Nothing -> False
-          Just x -> x
 
   -- step 3: approximate floating the binding
   let is_strict   = fve_useDmd env && isStrictDmd (idDemandInfo binder)
       is_unlifted = isUnLiftedType $ varType binder
       use_case    = is_strict || is_unlifted
 
-  let binding_up = floatFVUp env (Just binder) use_case isLNE isOnce rhs $
+  let binding_up = floatFVUp env (Just binder) use_case isLNE rhs $
                    perhapsWrapFloatsFVUp NonRecursive use_case rhs rhs_up
 
   -- lastly: merge the Ups
@@ -2194,7 +2129,6 @@ analyzeFVsM env (Let (NonRec binder rhs) body) = do
                     `unionVarSet` bndrRuleAndUnfoldingVars binder,
         fvu_escapes = fvu_escapes body_up `delVarSet` binder
                         `unionVarSet` fvu_escapes binding_up,
-        fvu_once = delVarEnv (fvu_once body_up) binder `bothOnce` fvu_once binding_up,
 
         fvu_floats = fvu_floats binding_up `appendFloats` fvu_floats body_up,
         fvu_silt = delBindersSilt [binder] $ fvu_silt body_up,
@@ -2202,13 +2136,11 @@ analyzeFVsM env (Let (NonRec binder rhs) body) = do
         fvu_isTrivial = fvu_isTrivial body_up
         }
 
-  -- extra lastly: tag the binder with LNE, Once, and its use info in
-  -- both its whole scope and just the body (which are the same for
-  -- NonRec)
-  let bsilt = CloB body_silt body_silt where
-        body_silt = fvu_floats body_up `wrapFloats` fvu_silt body_up
+  -- extra lastly: tag the binder with LNE and its use info in both
+  -- its whole scope
+  let bsilt = CloB $ fvu_floats body_up `wrapFloats` fvu_silt body_up
 
-  ret up $ AnnLet (AnnNonRec (TB binder (isLNE,isOnce,bsilt)) rhs2) body2
+  ret up $ AnnLet (AnnNonRec (TB binder (isLNE,bsilt)) rhs2) body2
 
 analyzeFVsM env (Let (Rec binds) body) = do
   let binders = map fst binds
@@ -2223,14 +2155,10 @@ analyzeFVsM env (Let (Rec binds) body) = do
   -- step 2: recognize LNE
   let scope_esc = unionVarSets $ fvu_escapes body_up : map fvu_escapes rhs_up_s
   let isLNE = not $ any (`elemVarSet` scope_esc) binders
-      isOnce = flip all binders $ \binder ->
-        not (isId binder) || 0 == idArity binder || case lookupVarEnv (fvu_once body_up) binder of
-          Nothing -> False
-          Just x -> x
 
   -- step 3: approximate floating the bindings
   let binding_up_s = flip map (zip binds rhs_up_s) $ \((binder,rhs),rhs_up) ->
-        floatFVUp env (Just binder) False isLNE isOnce rhs $
+        floatFVUp env (Just binder) False isLNE rhs $
         rhs_up {fvu_silt = delBindersSilt [binder] (fvu_silt rhs_up)}
 
   -- lastly: merge Ups
@@ -2240,7 +2168,6 @@ analyzeFVsM env (Let (Rec binds) body) = do
                     computeRecRHSsFVs binders (map fvu_fvs binding_up_s),
         fvu_escapes = unionVarSets (fvu_escapes body_up : map fvu_escapes binding_up_s)
                       `delVarSetList` binders,
-        fvu_once = flip delVarEnvList binders $ foldr bothOnce (fvu_once body_up) $ map fvu_once binding_up_s,
 
         fvu_floats = foldr appendFloats (fvu_floats body_up) $ map fvu_floats binding_up_s,
         fvu_silt   = delBindersSilt binders $ fvu_silt body_up,
@@ -2248,14 +2175,14 @@ analyzeFVsM env (Let (Rec binds) body) = do
         fvu_isTrivial = fvu_isTrivial body_up
         }
 
-  -- extra lastly: tag the binders with LNE, Once, and use info in
-  -- both the whole scope (ie including all RHSs) and just the body
+  -- extra lastly: tag the binders with LNE and use info in both the
+  -- whole scope (ie including all RHSs)
   --
   -- all of this information is all-or-nothing: all recursive binders
-  -- have to have the LNE/Once property in order for it to be true in
-  -- each TB tag. And the bsilt is the same for each binder.
-  let binfo = (isLNE,isOnce,bsilt)
-      bsilt = CloB scope_silt body_silt where
+  -- have to have the LNE property in order for it to be true in each
+  -- TB tag. And the bsilt is the same for each binder.
+  let binfo = (isLNE,bsilt)
+      bsilt = CloB scope_silt where
         body_silt  = fvu_floats body_up `wrapFloats` fvu_silt body_up
         scope_silt = foldr bothSilt body_silt $ map fvu_silt rhs_up_s
                        -- NB rhs_up_s have already been wrapFloat'd
diff --git a/compiler/simplCore/SimplCore.lhs b/compiler/simplCore/SimplCore.lhs
index 1af59173f2b533f81d85e27a5060e42331fc1441..1ce0ceb73f0c18af75f11f297995a285356c2297 100644
--- a/compiler/simplCore/SimplCore.lhs
+++ b/compiler/simplCore/SimplCore.lhs
@@ -148,8 +148,8 @@ getCoreToDo dflags
               , fps_ignoreLNEClo   = gopt Opt_LLF_IgnoreLNEClo  dflags
               , fps_strictness     = gopt Opt_LLF_UseStr        dflags
               , fps_floatLNE0      = gopt Opt_LLF_FloatLNE0     dflags
+              , fps_oneShot        = gopt Opt_LLF_OneShot       dflags
               , fps_retry          = gopt Opt_LLF_Retry         dflags
-              , fps_singlySAT      = gopt Opt_LLF_SinglySAT     dflags
               }
     static_args   = gopt Opt_StaticArgumentTransformation dflags
     rules_on      = gopt Opt_EnableRewriteRules           dflags