root/compiler/cmm/CmmLint.hs

Revision 2304a36272531fd20f163b6f378e417dc351aa25, 8.1 KB (checked in by Ian Lynagh <igloo@…>, 3 months ago)

Fix the unregisterised build; fixes #5901

  • Property mode set to 100644
Line 
1-----------------------------------------------------------------------------
2--
3-- (c) The University of Glasgow 2004-2006
4--
5-- CmmLint: checking the correctness of Cmm statements and expressions
6--
7-----------------------------------------------------------------------------
8
9{-# OPTIONS -fno-warn-tabs #-}
10-- The above warning supression flag is a temporary kludge.
11-- While working on this module you are encouraged to remove it and
12-- detab the module (please do the detabbing in a separate patch). See
13--     http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#TabsvsSpaces
14-- for details
15
16module CmmLint (
17  cmmLint, cmmLintTop
18  ) where
19
20import BlockId
21import OldCmm
22import CLabel
23import Outputable
24import OldPprCmm()
25import Constants
26import FastString
27import Platform
28
29import Data.Maybe
30
31-- -----------------------------------------------------------------------------
32-- Exported entry points:
33
34cmmLint :: (PlatformOutputable d, PlatformOutputable h)
35        => Platform -> GenCmmGroup d h (ListGraph CmmStmt) -> Maybe SDoc
36cmmLint platform tops = runCmmLint platform (mapM_ (lintCmmDecl platform)) tops
37
38cmmLintTop :: (PlatformOutputable d, PlatformOutputable h)
39           => Platform -> GenCmmDecl d h (ListGraph CmmStmt) -> Maybe SDoc
40cmmLintTop platform top = runCmmLint platform (lintCmmDecl platform) top
41
42runCmmLint :: PlatformOutputable a
43           => Platform -> (a -> CmmLint b) -> a -> Maybe SDoc
44runCmmLint platform l p =
45   case unCL (l p) of
46   Left err -> Just (vcat [ptext $ sLit ("Cmm lint error:"),
47                           nest 2 err,
48                           ptext $ sLit ("Program was:"),
49                           nest 2 (pprPlatform platform p)])
50   Right _  -> Nothing
51
52lintCmmDecl :: Platform -> (GenCmmDecl h i (ListGraph CmmStmt)) -> CmmLint ()
53lintCmmDecl platform (CmmProc _ lbl (ListGraph blocks))
54  = addLintInfo (text "in proc " <> pprCLabel platform lbl) $
55        let labels = foldl (\s b -> setInsert (blockId b) s) setEmpty blocks
56        in  mapM_ (lintCmmBlock platform labels) blocks
57
58lintCmmDecl _ (CmmData {})
59  = return ()
60
61lintCmmBlock :: Platform -> BlockSet -> GenBasicBlock CmmStmt -> CmmLint ()
62lintCmmBlock platform labels (BasicBlock id stmts)
63  = addLintInfo (text "in basic block " <> ppr id) $
64        mapM_ (lintCmmStmt platform labels) stmts
65
66-- -----------------------------------------------------------------------------
67-- lintCmmExpr
68
69-- Checks whether a CmmExpr is "type-correct", and check for obvious-looking
70-- byte/word mismatches.
71
72lintCmmExpr :: Platform -> CmmExpr -> CmmLint CmmType
73lintCmmExpr platform (CmmLoad expr rep) = do
74  _ <- lintCmmExpr platform expr
75  -- Disabled, if we have the inlining phase before the lint phase,
76  -- we can have funny offsets due to pointer tagging. -- EZY
77  -- when (widthInBytes (typeWidth rep) >= wORD_SIZE) $
78  --   cmmCheckWordAddress expr
79  return rep
80lintCmmExpr platform expr@(CmmMachOp op args) = do
81  tys <- mapM (lintCmmExpr platform) args
82  if map (typeWidth . cmmExprType) args == machOpArgReps op
83        then cmmCheckMachOp op args tys
84        else cmmLintMachOpErr platform expr (map cmmExprType args) (machOpArgReps op)
85lintCmmExpr platform (CmmRegOff reg offset)
86  = lintCmmExpr platform (CmmMachOp (MO_Add rep)
87                [CmmReg reg, CmmLit (CmmInt (fromIntegral offset) rep)])
88  where rep = typeWidth (cmmRegType reg)
89lintCmmExpr _ expr =
90  return (cmmExprType expr)
91
92-- Check for some common byte/word mismatches (eg. Sp + 1)
93cmmCheckMachOp   :: MachOp -> [CmmExpr] -> [CmmType] -> CmmLint CmmType
94cmmCheckMachOp op [lit@(CmmLit (CmmInt { })), reg@(CmmReg _)] tys
95  = cmmCheckMachOp op [reg, lit] tys
96cmmCheckMachOp op _ tys
97  = return (machOpResultType op tys)
98
99isOffsetOp :: MachOp -> Bool
100isOffsetOp (MO_Add _) = True
101isOffsetOp (MO_Sub _) = True
102isOffsetOp _ = False
103
104-- This expression should be an address from which a word can be loaded:
105-- check for funny-looking sub-word offsets.
106_cmmCheckWordAddress :: Platform -> CmmExpr -> CmmLint ()
107_cmmCheckWordAddress platform e@(CmmMachOp op [arg, CmmLit (CmmInt i _)])
108  | isOffsetOp op && notNodeReg arg && i `rem` fromIntegral wORD_SIZE /= 0
109  = cmmLintDubiousWordOffset platform e
110_cmmCheckWordAddress platform e@(CmmMachOp op [CmmLit (CmmInt i _), arg])
111  | isOffsetOp op && notNodeReg arg && i `rem` fromIntegral wORD_SIZE /= 0
112  = cmmLintDubiousWordOffset platform e
113_cmmCheckWordAddress _ _
114  = return ()
115
116-- No warnings for unaligned arithmetic with the node register,
117-- which is used to extract fields from tagged constructor closures.
118notNodeReg :: CmmExpr -> Bool
119notNodeReg (CmmReg reg) | reg == nodeReg = False
120notNodeReg _                             = True
121
122lintCmmStmt :: Platform -> BlockSet -> CmmStmt -> CmmLint ()
123lintCmmStmt platform labels = lint
124    where lint (CmmNop) = return ()
125          lint (CmmComment {}) = return ()
126          lint stmt@(CmmAssign reg expr) = do
127            erep <- lintCmmExpr platform expr
128            let reg_ty = cmmRegType reg
129            if (erep `cmmEqType_ignoring_ptrhood` reg_ty)
130                then return ()
131                else cmmLintAssignErr platform stmt erep reg_ty
132          lint (CmmStore l r) = do
133            _ <- lintCmmExpr platform l
134            _ <- lintCmmExpr platform r
135            return ()
136          lint (CmmCall target _res args _) =
137              do lintTarget platform labels target
138                 mapM_ (lintCmmExpr platform . hintlessCmm) args
139          lint (CmmCondBranch e id) = checkTarget id >> lintCmmExpr platform e >> checkCond platform e
140          lint (CmmSwitch e branches) = do
141            mapM_ checkTarget $ catMaybes branches
142            erep <- lintCmmExpr platform e
143            if (erep `cmmEqType_ignoring_ptrhood` bWord)
144              then return ()
145              else cmmLintErr (text "switch scrutinee is not a word: " <> pprPlatform platform e <>
146                               text " :: " <> ppr erep)
147          lint (CmmJump e _) = lintCmmExpr platform e >> return ()
148          lint (CmmReturn) = return ()
149          lint (CmmBranch id) = checkTarget id
150          checkTarget id = if setMember id labels then return ()
151                           else cmmLintErr (text "Branch to nonexistent id" <+> ppr id)
152
153lintTarget :: Platform -> BlockSet -> CmmCallTarget -> CmmLint ()
154lintTarget platform _      (CmmCallee e _) = do _ <- lintCmmExpr platform e
155                                                return ()
156lintTarget _        _      (CmmPrim _ Nothing) = return ()
157lintTarget platform labels (CmmPrim _ (Just stmts))
158    = mapM_ (lintCmmStmt platform labels) stmts
159
160
161checkCond :: Platform -> CmmExpr -> CmmLint ()
162checkCond _ (CmmMachOp mop _) | isComparisonMachOp mop = return ()
163checkCond _ (CmmLit (CmmInt x t)) | x == 0 || x == 1, t == wordWidth = return () -- constant values
164checkCond platform expr
165    = cmmLintErr (hang (text "expression is not a conditional:") 2
166                       (pprPlatform platform expr))
167
168-- -----------------------------------------------------------------------------
169-- CmmLint monad
170
171-- just a basic error monad:
172
173newtype CmmLint a = CmmLint { unCL :: Either SDoc a }
174
175instance Monad CmmLint where
176  CmmLint m >>= k = CmmLint $ case m of 
177                                Left e -> Left e
178                                Right a -> unCL (k a)
179  return a = CmmLint (Right a)
180
181cmmLintErr :: SDoc -> CmmLint a
182cmmLintErr msg = CmmLint (Left msg)
183
184addLintInfo :: SDoc -> CmmLint a -> CmmLint a
185addLintInfo info thing = CmmLint $ 
186   case unCL thing of
187        Left err -> Left (hang info 2 err)
188        Right a  -> Right a
189
190cmmLintMachOpErr :: Platform -> CmmExpr -> [CmmType] -> [Width] -> CmmLint a
191cmmLintMachOpErr platform expr argsRep opExpectsRep
192     = cmmLintErr (text "in MachOp application: " $$ 
193                                        nest 2 (pprPlatform platform expr) $$
194                                        (text "op is expecting: " <+> ppr opExpectsRep) $$
195                                        (text "arguments provide: " <+> ppr argsRep))
196
197cmmLintAssignErr :: Platform -> CmmStmt -> CmmType -> CmmType -> CmmLint a
198cmmLintAssignErr platform stmt e_ty r_ty
199  = cmmLintErr (text "in assignment: " $$ 
200                nest 2 (vcat [pprPlatform platform stmt, 
201                              text "Reg ty:" <+> ppr r_ty,
202                              text "Rhs ty:" <+> ppr e_ty]))
203                         
204                                       
205
206cmmLintDubiousWordOffset :: Platform -> CmmExpr -> CmmLint a
207cmmLintDubiousWordOffset platform expr
208   = cmmLintErr (text "offset is not a multiple of words: " $$
209                        nest 2 (pprPlatform platform expr))
Note: See TracBrowser for help on using the browser.