[project @ 1999-06-24 13:04:13 by simonmar]
[ghc-hetmet.git] / ghc / compiler / nativeGen / AbsCStixGen.lhs
index 3997048..e4c1968 100644 (file)
@@ -1,62 +1,66 @@
 %
-% (c) The AQUA Project, Glasgow University, 1993-1995
+% (c) The AQUA Project, Glasgow University, 1993-1998
 %
 
 \begin{code}
-#include "HsVersions.h"
+module AbsCStixGen ( genCodeAbstractC ) where
 
-module AbsCStixGen (
-       genCodeAbstractC,
+#include "HsVersions.h"
 
-       -- and, of course, that's not enough...
-       AbstractC, Target, StixTree, UniqSupply, UniqSM(..)
-    ) where
+import Ratio   ( Rational )
 
 import AbsCSyn
-import PrelInfo                ( PrimOp(..), primOpNeedsWrapper, isCompareOp
-                         IF_ATTACK_PRAGMAS(COMMA tagOf_PrimOp)
-                         IF_ATTACK_PRAGMAS(COMMA pprPrimOp)
+import Stix
+import MachMisc
+
+import AbsCUtils       ( getAmodeRep, mixedTypeLocn,
+                         nonemptyAbsC, mkAbsCStmts, mkAbsCStmtList
                        )
-import CgCompInfo      ( mIN_UPD_SIZE )
-import ClosureInfo     ( infoTableLabelFromCI, entryLabelFromCI, fastLabelFromCI,
-                         closureUpdReqd
+import SMRep           ( fixedItblSize, 
+                         rET_SMALL, rET_BIG, 
+                         rET_VEC_SMALL, rET_VEC_BIG 
                        )
-import MachDesc
-import Maybes          ( Maybe(..), maybeToBool )
-import Outputable
-import PrimRep         ( isFloatingRep )
-import SMRep           ( SMRep(..), SMSpecRepKind(..), SMUpdateKind(..) )
-import Stix
-import StixInfo                ( genCodeInfoTable )
-import UniqSupply
-import Util
+import Constants       ( mIN_UPD_SIZE )
+import CLabel           ( CLabel, mkReturnInfoLabel, mkReturnPtLabel )
+import ClosureInfo     ( infoTableLabelFromCI, entryLabelFromCI,
+                         fastLabelFromCI, closureUpdReqd,
+                         staticClosureNeedsLink
+                       )
+import Const           ( Literal(..) )
+import Maybes          ( maybeToBool )
+import PrimOp          ( primOpNeedsWrapper, PrimOp(..) )
+import PrimRep         ( isFloatingRep, PrimRep(..) )
+import StixInfo                ( genCodeInfoTable, genBitmapInfoTable )
+import StixMacro       ( macroCode, checkCode )
+import StixPrim                ( primCode, amodeToStix, amodeToStix' )
+import UniqSupply      ( returnUs, thenUs, mapUs, getUniqueUs, UniqSM )
+import Util            ( naturalMergeSortLe )
+import Panic           ( panic )
+import BitSet          ( intBS )
+
+#ifdef REALLY_HASKELL_1_3
+ord = fromEnum :: Char -> Int
+#endif
 \end{code}
 
-For each independent chunk of AbstractC code, we generate a list of @StixTree@s,
-where each tree corresponds to a single Stix instruction.  We leave the chunks
-separated so that register allocation can be performed locally within the chunk.
+For each independent chunk of AbstractC code, we generate a list of
+@StixTree@s, where each tree corresponds to a single Stix instruction.
+We leave the chunks separated so that register allocation can be
+performed locally within the chunk.
 
 \begin{code}
--- hacking with Uncle Will:
-#define target_STRICT target@(Target _ _ _ _ _ _ _ _)
-
-genCodeAbstractC
-    :: Target
-    -> AbstractC
-    -> UniqSM [[StixTree]]
+genCodeAbstractC :: AbstractC -> UniqSM [[StixTree]]
 
-genCodeAbstractC target_STRICT absC =
-    mapUs gentopcode (mkAbsCStmtList absC) `thenUs` \ trees ->
+genCodeAbstractC absC
+  = mapUs gentopcode (mkAbsCStmtList absC) `thenUs` \ trees ->
     returnUs ([StComment SLIT("Native Code")] : trees)
  where
- -- "target" munging things... ---
- a2stix  = amodeToStix  target
- a2stix' = amodeToStix' target
- volsaves    = volatileSaves target
- volrestores = volatileRestores target
- p2stix      = primToStix target
- macro_code  = macroCode target
- hp_rel             = hpRel target
+ a2stix      = amodeToStix
+ a2stix'     = amodeToStix'
+ volsaves    = volatileSaves
+ volrestores = volatileRestores
+ p2stix      = primCode
+ macro_code  = macroCode
  -- real code follows... ---------
 \end{code}
 
@@ -66,45 +70,54 @@ Here we handle top-level things, like @CCodeBlock@s and
 \begin{code}
  {-
  genCodeTopAbsC
-    :: Target
-    -> AbstractC
+    :: AbstractC
     -> UniqSM [StixTree]
  -}
 
- gentopcode (CCodeBlock label absC) =
-    gencode absC                               `thenUs` \ code ->
+ gentopcode (CCodeBlock label absC)
+  = gencode absC                               `thenUs` \ code ->
     returnUs (StSegment TextSegment : StFunBegin label : code [StFunEnd label])
 
- gentopcode stmt@(CStaticClosure label _ _ _) =
-    genCodeStaticClosure stmt                  `thenUs` \ code ->
+ gentopcode stmt@(CStaticClosure label _ _ _)
+  = genCodeStaticClosure stmt                  `thenUs` \ code ->
     returnUs (StSegment DataSegment : StLabel label : code [])
 
- gentopcode stmt@(CRetUnVector _ _) = returnUs []
-
- gentopcode stmt@(CFlatRetVector label _) =
-    genCodeVecTbl stmt                         `thenUs` \ code ->
+ gentopcode stmt@(CRetVector label _ _ _)
+  = genCodeVecTbl stmt                         `thenUs` \ code ->
     returnUs (StSegment TextSegment : code [StLabel label])
 
- gentopcode stmt@(CClosureInfoAndCode cl_info slow Nothing _ _ _)
+ gentopcode stmt@(CRetDirect uniq absC srt liveness)
+  = gencode absC                                      `thenUs` \ code ->
+    genBitmapInfoTable liveness srt closure_type False `thenUs` \ itbl ->
+    returnUs (StSegment TextSegment : 
+              itbl (StLabel lbl_info : StLabel lbl_ret : code []))
+  where 
+       lbl_info = mkReturnInfoLabel uniq
+       lbl_ret  = mkReturnPtLabel uniq
+       closure_type = case liveness of
+                        LvSmall _ -> rET_SMALL
+                        LvLarge _ -> rET_BIG
+
+ gentopcode stmt@(CClosureInfoAndCode cl_info slow Nothing _)
 
   | slow_is_empty
-  = genCodeInfoTable hp_rel a2stix stmt                `thenUs` \ itbl ->
+  = genCodeInfoTable stmt              `thenUs` \ itbl ->
     returnUs (StSegment TextSegment : itbl [])
 
   | otherwise
-  = genCodeInfoTable hp_rel a2stix stmt                `thenUs` \ itbl ->
-    gencode slow                               `thenUs` \ slow_code ->
+  = genCodeInfoTable stmt              `thenUs` \ itbl ->
+    gencode slow                       `thenUs` \ slow_code ->
     returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
              slow_code [StFunEnd slow_lbl]))
   where
     slow_is_empty = not (maybeToBool (nonemptyAbsC slow))
     slow_lbl = entryLabelFromCI cl_info
 
- gentopcode stmt@(CClosureInfoAndCode cl_info slow (Just fast) _ _ _) =
+ gentopcode stmt@(CClosureInfoAndCode cl_info slow (Just fast) _) =
  -- ToDo: what if this is empty? ------------------------^^^^
-    genCodeInfoTable hp_rel a2stix stmt                `thenUs` \ itbl ->
-    gencode slow                               `thenUs` \ slow_code ->
-    gencode fast                               `thenUs` \ fast_code ->
+    genCodeInfoTable stmt              `thenUs` \ itbl ->
+    gencode slow                       `thenUs` \ slow_code ->
+    gencode fast                       `thenUs` \ fast_code ->
     returnUs (StSegment TextSegment : itbl (StFunBegin slow_lbl :
              slow_code (StFunEnd slow_lbl : StFunBegin fast_lbl :
              fast_code [StFunEnd fast_lbl])))
@@ -112,56 +125,73 @@ Here we handle top-level things, like @CCodeBlock@s and
     slow_lbl = entryLabelFromCI cl_info
     fast_lbl = fastLabelFromCI cl_info
 
- gentopcode absC =
-    gencode absC                               `thenUs` \ code ->
+ gentopcode stmt@(CSRT lbl closures)
+  = returnUs [ StSegment TextSegment 
+            , StLabel lbl 
+            , StData DataPtrRep (map StCLbl closures)
+            ]
+
+ gentopcode stmt@(CBitmap lbl mask)
+  = returnUs [ StSegment TextSegment 
+            , StLabel lbl 
+            , StData WordRep (StInt (toInteger (length mask)) : 
+                               map  (StInt . toInteger . intBS) mask)
+            ]
+
+ gentopcode absC
+  = gencode absC                               `thenUs` \ code ->
     returnUs (StSegment TextSegment : code [])
 
 \end{code}
 
-Vector tables are trivial!
-
 \begin{code}
  {-
  genCodeVecTbl
-    :: Target
-    -> AbstractC
+    :: AbstractC
     -> UniqSM StixTreeList
  -}
- genCodeVecTbl (CFlatRetVector label amodes) =
-    returnUs (\xs -> vectbl : xs)
+ genCodeVecTbl (CRetVector label amodes srt liveness)
+  = genBitmapInfoTable liveness srt closure_type True `thenUs` \itbl ->
+    returnUs (\xs -> vectbl : itbl xs)
   where
     vectbl = StData PtrRep (reverse (map a2stix amodes))
+    closure_type = case liveness of
+                   LvSmall _ -> rET_VEC_SMALL
+                   LvLarge _ -> rET_VEC_BIG
 
 \end{code}
 
-Static closures are not so hard either.
-
 \begin{code}
  {-
  genCodeStaticClosure
-    :: Target
-    -> AbstractC
+    :: AbstractC
     -> UniqSM StixTreeList
  -}
- genCodeStaticClosure (CStaticClosure _ cl_info cost_centre amodes) =
-    returnUs (\xs -> table : xs)
+ genCodeStaticClosure (CStaticClosure _ cl_info cost_centre amodes)
+  = returnUs (\xs -> table ++ xs)
   where
-    table = StData PtrRep (StCLbl info_lbl : body)
-    info_lbl = infoTableLabelFromCI cl_info
+    table = StData PtrRep [StCLbl (infoTableLabelFromCI cl_info)] : 
+           map (\amode -> StData (getAmodeRep amode) [a2stix amode]) amodes ++
+           [StData PtrRep (padding_wds ++ static_link)]
 
-    body = if closureUpdReqd cl_info then
-               take (max mIN_UPD_SIZE (length amodes')) (amodes' ++ zeros)
-          else
-               amodes'
+    -- always at least one padding word: this is the static link field
+    -- for the garbage collector.
+    padding_wds = if closureUpdReqd cl_info then
+                       take (max 0 (mIN_UPD_SIZE - length amodes)) zeros
+                 else
+                       []
 
-    zeros = StInt 0 : zeros
+    static_link | staticClosureNeedsLink cl_info = [StInt 0]
+               | otherwise                      = []
 
-    amodes' = map amodeZeroVoid amodes
+    zeros = StInt 0 : zeros
 
+    {- needed??? --SDM
        -- Watch out for VoidKinds...cf. PprAbsC
     amodeZeroVoid item
       | getAmodeRep item == VoidRep = StInt 0
       | otherwise = a2stix item
+    -}
 
 \end{code}
 
@@ -170,8 +200,7 @@ Now the individual AbstractC statements.
 \begin{code}
  {-
  gencode
-    :: Target
-    -> AbstractC
+    :: AbstractC
     -> UniqSM StixTreeList
  -}
 \end{code}
@@ -197,8 +226,8 @@ resulting StixTreeLists are joined together.
 
 \begin{code}
 
- gencode (AbsCStmts c1 c2) =
-    gencode c1                         `thenUs` \ b1 ->
+ gencode (AbsCStmts c1 c2)
+  = gencode c1                         `thenUs` \ b1 ->
     gencode c2                         `thenUs` \ b2 ->
     returnUs (b1 . b2)
 
@@ -212,12 +241,22 @@ addresses, etc.)
 
 \begin{code}
 
- gencode (CInitHdr cl_info reg_rel _ _) =
-    let
-       lhs = a2stix (CVal reg_rel PtrRep)
+ gencode (CInitHdr cl_info reg_rel _)
+  = let
+       lhs = a2stix reg_rel
        lbl = infoTableLabelFromCI cl_info
     in
-       returnUs (\xs -> StAssign PtrRep lhs (StCLbl lbl) : xs)
+       returnUs (\xs -> StAssign PtrRep (StInd PtrRep lhs) (StCLbl lbl) : xs)
+
+\end{code}
+
+Heap/Stack Checks.
+
+\begin{code}
+
+ gencode (CCheck macro args assts)
+  = gencode assts `thenUs` \assts_stix ->
+    checkCode macro args assts_stix
 
 \end{code}
 
@@ -232,8 +271,8 @@ of the source?  Be careful about floats/doubles.
 
  gencode (CAssign lhs rhs)
   | getAmodeRep lhs == VoidRep = returnUs id
-  | otherwise =
-    let pk = getAmodeRep lhs
+  | otherwise
+  = let pk = getAmodeRep lhs
        pk' = if mixedTypeLocn lhs && not (isFloatingRep pk) then IntRep else pk
        lhs' = a2stix lhs
        rhs' = a2stix' rhs
@@ -246,28 +285,33 @@ Unconditional jumps, including the special ``enter closure'' operation.
 Note that the new entry convention requires that we load the InfoPtr (R2)
 with the address of the info table before jumping to the entry code for Node.
 
+For a vectored return, we must subtract the size of the info table to
+get at the return vector.  This depends on the size of the info table,
+which varies depending on whether we're profiling etc.
+
 \begin{code}
 
- gencode (CJump dest) =
-    returnUs (\xs -> StJump (a2stix dest) : xs)
+ gencode (CJump dest)
+  = returnUs (\xs -> StJump (a2stix dest) : xs)
 
- gencode (CFallThrough (CLbl lbl _)) =
-    returnUs (\xs -> StFallThrough lbl : xs)
+ gencode (CFallThrough (CLbl lbl _))
+  = returnUs (\xs -> StFallThrough lbl : xs)
 
- gencode (CReturn dest DirectReturn) =
-    returnUs (\xs -> StJump (a2stix dest) : xs)
+ gencode (CReturn dest DirectReturn)
+  = returnUs (\xs -> StJump (a2stix dest) : xs)
 
- gencode (CReturn table (StaticVectoredReturn n)) =
-    returnUs (\xs -> StJump dest : xs)
+ gencode (CReturn table (StaticVectoredReturn n))
+  = returnUs (\xs -> StJump dest : xs)
   where
     dest = StInd PtrRep (StIndex PtrRep (a2stix table)
-                                         (StInt (toInteger (-n-1))))
+                                 (StInt (toInteger (-n-fixedItblSize-1))))
 
- gencode (CReturn table (DynamicVectoredReturn am)) =
-    returnUs (\xs -> StJump dest : xs)
+ gencode (CReturn table (DynamicVectoredReturn am))
+  = returnUs (\xs -> StJump dest : xs)
   where
     dest = StInd PtrRep (StIndex PtrRep (a2stix table) dyn_off)
-    dyn_off = StPrim IntSubOp [StPrim IntNegOp [a2stix am], StInt 1]
+    dyn_off = StPrim IntSubOp [StPrim IntNegOp [a2stix am], 
+                              StInt (toInteger (fixedItblSize+1))]
 
 \end{code}
 
@@ -275,10 +319,10 @@ Now the PrimOps, some of which may need caller-saves register wrappers.
 
 \begin{code}
 
- gencode (COpStmt results op args liveness_mask vols)
+ gencode (COpStmt results op args vols)
   -- ToDo (ADR?): use that liveness mask
-  | primOpNeedsWrapper op =
-    let
+  | primOpNeedsWrapper op
+  = let
        saves = volsaves vols
        restores = volrestores vols
     in
@@ -329,7 +373,7 @@ Now the if statement.  Almost *all* flow of control are of this form.
       other | simple_discrim -> mkSimpleSwitches discrim alts deflt
 
        -- Otherwise, we need to do a bit of work.
-      other ->  getUnique                        `thenUs` \ u ->
+      other ->  getUniqueUs                      `thenUs` \ u ->
                gencode (AbsCStmts
                (CAssign (CTemp u pk) discrim)
                (CSwitch (CTemp u pk) alts deflt))
@@ -356,22 +400,23 @@ Finally, all of the disgusting AbstractC macros.
 
  gencode (CMacroStmt macro args) = macro_code macro args
 
- gencode (CCallProfCtrMacro macro _) =
-    returnUs (\xs -> StComment macro : xs)
+ gencode (CCallProfCtrMacro macro _)
+  = returnUs (\xs -> StComment macro : xs)
 
- gencode (CCallProfCCMacro macro _) =
-    returnUs (\xs -> StComment macro : xs)
+ gencode (CCallProfCCMacro macro _)
+  = returnUs (\xs -> StComment macro : xs)
 
 \end{code}
 
-Here, we generate a jump table if there are more than four (integer) alternatives and
-the jump table occupancy is greater than 50%.  Otherwise, we generate a binary
-comparison tree.  (Perhaps this could be tuned.)
+Here, we generate a jump table if there are more than four (integer)
+alternatives and the jump table occupancy is greater than 50%.
+Otherwise, we generate a binary comparison tree.  (Perhaps this could
+be tuned.)
 
 \begin{code}
 
  intTag :: Literal -> Integer
- intTag (MachChar c) = toInteger (ord c)
+ intTag (MachChar c)  = fromInt (ord c)
  intTag (MachInt i _) = i
  intTag _ = panic "intTag"
 
@@ -383,12 +428,11 @@ comparison tree.  (Perhaps this could be tuned.)
 
  {-
  mkSimpleSwitches
-    :: Target
-    -> CAddrMode -> [(Literal,AbstractC)] -> AbstractC
+    :: CAddrMode -> [(Literal,AbstractC)] -> AbstractC
     -> UniqSM StixTreeList
  -}
- mkSimpleSwitches am alts absC =
-    getUniqLabelNCG                                    `thenUs` \ udlbl ->
+ mkSimpleSwitches am alts absC
+  = getUniqLabelNCG                                    `thenUs` \ udlbl ->
     getUniqLabelNCG                                    `thenUs` \ ujlbl ->
     let am' = a2stix am
        joinedAlts = map (\ (tag,code) -> (tag, mkJoin code ujlbl)) alts
@@ -401,14 +445,6 @@ comparison tree.  (Perhaps this could be tuned.)
        -- lowest and highest possible values the discriminant could take
        lowest = if floating then targetMinDouble else targetMinInt
        highest = if floating then targetMaxDouble else targetMaxInt
-
-       -- These should come from somewhere else, depending on the target arch
-       -- (Note that the floating point values aren't terribly important.)
-       -- ToDo: Fix!(JSM)
-       targetMinDouble = MachDouble (-1.7976931348623157e+308)
-       targetMaxDouble = MachDouble (1.7976931348623157e+308)
-       targetMinInt = mkMachInt (-2147483647)
-       targetMaxInt = mkMachInt 2147483647
     in
        (
        if not floating && choices > 4 && highTag - lowTag < toInteger (2 * choices) then
@@ -431,20 +467,20 @@ comparison tree.  (Perhaps this could be tuned.)
 
 \end{code}
 
-We use jump tables when doing an integer switch on a relatively dense list of
-alternatives.  We expect to be given a list of alternatives, sorted by tag,
-and a range of values for which we are to generate a table.  Of course, the tags of
-the alternatives should lie within the indicated range.  The alternatives need
-not cover the range; a default target is provided for the missing alternatives.
+We use jump tables when doing an integer switch on a relatively dense
+list of alternatives.  We expect to be given a list of alternatives,
+sorted by tag, and a range of values for which we are to generate a
+table.  Of course, the tags of the alternatives should lie within the
+indicated range.  The alternatives need not cover the range; a default
+target is provided for the missing alternatives.
 
-If a join is necessary after the switch, the alternatives should already finish
-with a jump to the join point.
+If a join is necessary after the switch, the alternatives should
+already finish with a jump to the join point.
 
 \begin{code}
  {-
  mkJumpTable
-    :: Target
-    -> StixTree                -- discriminant
+    :: StixTree                -- discriminant
     -> [(Literal, AbstractC)]  -- alternatives
     -> Integer                         -- low tag
     -> Integer                         -- high tag
@@ -452,15 +488,15 @@ with a jump to the join point.
     -> UniqSM StixTreeList
  -}
 
- mkJumpTable am alts lowTag highTag dflt =
-    getUniqLabelNCG                                    `thenUs` \ utlbl ->
+ mkJumpTable am alts lowTag highTag dflt
+  = getUniqLabelNCG                                    `thenUs` \ utlbl ->
     mapUs genLabel alts                                `thenUs` \ branches ->
-    let        cjmpLo = StCondJump dflt (StPrim IntLtOp [am, StInt lowTag])
-       cjmpHi = StCondJump dflt (StPrim IntGtOp [am, StInt highTag])
+    let        cjmpLo = StCondJump dflt (StPrim IntLtOp [am, StInt (toInteger lowTag)])
+       cjmpHi = StCondJump dflt (StPrim IntGtOp [am, StInt (toInteger highTag)])
 
        offset = StPrim IntSubOp [am, StInt lowTag]
-       jump = StJump (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
 
+       jump = StJump (StInd PtrRep (StIndex PtrRep (StCLbl utlbl) offset))
        tlbl = StLabel utlbl
        table = StData PtrRep (mkTable branches [lowTag..highTag] [])
     in
@@ -500,8 +536,7 @@ alternatives should already finish with a jump to the join point.
 \begin{code}
  {-
  mkBinaryTree
-    :: Target
-    -> StixTree                -- discriminant
+    :: StixTree                -- discriminant
     -> Bool                    -- floating point?
     -> [(Literal, AbstractC)]  -- alternatives
     -> Int                     -- number of choices
@@ -513,8 +548,8 @@ alternatives should already finish with a jump to the join point.
 
  mkBinaryTree am floating [(tag,alt)] _ lowTag highTag udlbl
   | rangeOfOne = gencode alt
-  | otherwise =
-    let        tag' = a2stix (CLit tag)
+  | otherwise
+  = let        tag' = a2stix (CLit tag)
        cmpOp = if floating then DoubleNeOp else IntNeOp
        test = StPrim cmpOp [am, tag']
        cjmp = StCondJump udlbl test
@@ -526,8 +561,8 @@ alternatives should already finish with a jump to the join point.
        rangeOfOne = not floating && intTag lowTag + 1 >= intTag highTag
        -- When there is only one possible tag left in range, we skip the comparison
 
- mkBinaryTree am floating alts choices lowTag highTag udlbl =
-    getUniqLabelNCG                                    `thenUs` \ uhlbl ->
+ mkBinaryTree am floating alts choices lowTag highTag udlbl
+  = getUniqLabelNCG                                    `thenUs` \ uhlbl ->
     let tag' = a2stix (CLit splitTag)
        cmpOp = if floating then DoubleGeOp else IntGeOp
        test = StPrim cmpOp [am, tag']
@@ -550,16 +585,15 @@ alternatives should already finish with a jump to the join point.
 \begin{code}
  {-
  mkIfThenElse
-    :: Target
-    -> CAddrMode           -- discriminant
+    :: CAddrMode           -- discriminant
     -> Literal             -- tag
     -> AbstractC           -- if-part
     -> AbstractC           -- else-part
     -> UniqSM StixTreeList
  -}
 
- mkIfThenElse discrim tag alt deflt =
-    getUniqLabelNCG                                    `thenUs` \ ujlbl ->
+ mkIfThenElse discrim tag alt deflt
+  = getUniqLabelNCG                                    `thenUs` \ ujlbl ->
     getUniqLabelNCG                                    `thenUs` \ utlbl ->
     let discrim' = a2stix discrim
        tag' = a2stix (CLit tag)
@@ -604,8 +638,8 @@ mightFallThrough absC = ft absC True
   ft _ if_empty = if_empty
 
 {- Old algorithm, which called nonemptyAbsC for every subexpression! =========
-fallThroughAbsC (AbsCStmts c1 c2) =
-    case nonemptyAbsC c2 of
+fallThroughAbsC (AbsCStmts c1 c2)
+  = case nonemptyAbsC c2 of
        Nothing -> fallThroughAbsC c1
        Just x -> fallThroughAbsC x
 fallThroughAbsC (CJump _)       = False