2 -- The above warning supression flag is a temporary kludge.
3 -- While working on this module you are encouraged to remove it and fix
4 -- any warnings in the module. See
5 -- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
8 -----------------------------------------------------------------------------
10 -- (c) The University of Glasgow 2004-2006
12 -- CmmLint: checking the correctness of Cmm statements and expressions
14 -----------------------------------------------------------------------------
32 -- -----------------------------------------------------------------------------
33 -- Exported entry points:
35 cmmLint :: GenCmm d h (ListGraph CmmStmt) -> Maybe SDoc
36 cmmLint (Cmm tops) = runCmmLint $ mapM_ lintCmmTop tops
38 cmmLintTop :: GenCmmTop d h (ListGraph CmmStmt) -> Maybe SDoc
39 cmmLintTop top = runCmmLint $ lintCmmTop top
41 runCmmLint :: CmmLint a -> Maybe SDoc
44 Left err -> Just (ptext (sLit "Cmm lint error:") $$ nest 2 err)
47 lintCmmTop :: (GenCmmTop h i (ListGraph CmmStmt)) -> CmmLint ()
48 lintCmmTop (CmmProc _ lbl _ (ListGraph blocks))
49 = addLintInfo (text "in proc " <> pprCLabel lbl) $
50 let labels = foldl (\s b -> extendBlockSet s (blockId b)) emptyBlockSet blocks
51 in mapM_ (lintCmmBlock labels) blocks
53 lintCmmTop (CmmData {})
56 lintCmmBlock labels (BasicBlock id stmts)
57 = addLintInfo (text "in basic block " <> ppr (getUnique id)) $
58 mapM_ (lintCmmStmt labels) stmts
60 -- -----------------------------------------------------------------------------
63 -- Checks whether a CmmExpr is "type-correct", and check for obvious-looking
64 -- byte/word mismatches.
66 lintCmmExpr :: CmmExpr -> CmmLint MachRep
67 lintCmmExpr (CmmLoad expr rep) = do
69 when (machRepByteWidth rep >= wORD_SIZE) $
70 cmmCheckWordAddress expr
72 lintCmmExpr expr@(CmmMachOp op args) = do
73 mapM_ lintCmmExpr args
74 if map cmmExprRep args == machOpArgReps op
75 then cmmCheckMachOp op args
76 else cmmLintMachOpErr expr (map cmmExprRep args) (machOpArgReps op)
77 lintCmmExpr (CmmRegOff reg offset)
78 = lintCmmExpr (CmmMachOp (MO_Add rep)
79 [CmmReg reg, CmmLit (CmmInt (fromIntegral offset) rep)])
80 where rep = cmmRegRep reg
81 lintCmmExpr lit@(CmmLit (CmmInt _ rep))
83 = cmmLintErr (text "integer literal with floating MachRep: " <> ppr lit)
85 return (cmmExprRep expr)
87 -- Check for some common byte/word mismatches (eg. Sp + 1)
88 cmmCheckMachOp op args@[CmmReg reg, CmmLit (CmmInt i _)]
89 | isWordOffsetReg reg && isOffsetOp op && i `rem` fromIntegral wORD_SIZE /= 0
90 = cmmLintDubiousWordOffset (CmmMachOp op args)
91 cmmCheckMachOp op [lit@(CmmLit (CmmInt { })), reg@(CmmReg _)]
92 = cmmCheckMachOp op [reg, lit]
93 cmmCheckMachOp op@(MO_U_Conv from to) args
94 | isFloatingRep from || isFloatingRep to
95 = cmmLintErr (text "unsigned conversion from/to floating rep: "
96 <> ppr (CmmMachOp op args))
97 cmmCheckMachOp op _args
98 = return (resultRepOfMachOp op)
100 isWordOffsetReg (CmmGlobal Sp) = True
101 -- No warnings for unaligned arithmetic, which is used to tag dynamic constructor closures.
102 --isWordOffsetReg (CmmGlobal Hp) = True
103 isWordOffsetReg _ = False
105 isOffsetOp (MO_Add _) = True
106 isOffsetOp (MO_Sub _) = True
109 -- This expression should be an address from which a word can be loaded:
110 -- check for funny-looking sub-word offsets.
111 cmmCheckWordAddress e@(CmmMachOp op [arg, CmmLit (CmmInt i _)])
112 | isOffsetOp op && notNodeReg arg && i `rem` fromIntegral wORD_SIZE /= 0
113 = cmmLintDubiousWordOffset e
114 cmmCheckWordAddress e@(CmmMachOp op [CmmLit (CmmInt i _), arg])
115 | isOffsetOp op && notNodeReg arg && i `rem` fromIntegral wORD_SIZE /= 0
116 = cmmLintDubiousWordOffset e
117 cmmCheckWordAddress _
120 -- No warnings for unaligned arithmetic with the node register,
121 -- which is used to extract fields from tagged constructor closures.
122 notNodeReg (CmmReg reg) | reg == nodeReg = False
125 lintCmmStmt :: BlockSet -> CmmStmt -> CmmLint ()
126 lintCmmStmt labels = lint
127 where lint (CmmNop) = return ()
128 lint (CmmComment {}) = return ()
129 lint stmt@(CmmAssign reg expr) = do
130 erep <- lintCmmExpr expr
131 if (erep == cmmRegRep reg)
133 else cmmLintAssignErr stmt
134 lint (CmmStore l r) = do
138 lint (CmmCall target _res args _ _) =
139 lintTarget target >> mapM_ (lintCmmExpr . hintlessCmm) args
140 lint (CmmCondBranch e id) = checkTarget id >> lintCmmExpr e >> checkCond e
141 lint (CmmSwitch e branches) = do
142 mapM_ checkTarget $ catMaybes branches
143 erep <- lintCmmExpr e
146 else cmmLintErr (text "switch scrutinee is not a word: " <> ppr e)
147 lint (CmmJump e args) = lintCmmExpr e >> mapM_ (lintCmmExpr . hintlessCmm) args
148 lint (CmmReturn ress) = mapM_ (lintCmmExpr . hintlessCmm) ress
149 lint (CmmBranch id) = checkTarget id
150 checkTarget id = if elemBlockSet id labels then return ()
151 else cmmLintErr (text "Branch to nonexistent id" <+> ppr id)
153 lintTarget :: CmmCallTarget -> CmmLint ()
154 lintTarget (CmmCallee e _) = lintCmmExpr e >> return ()
155 lintTarget (CmmPrim {}) = return ()
158 checkCond (CmmMachOp mop _) | isComparisonMachOp mop = return ()
159 checkCond expr = cmmLintErr (hang (text "expression is not a conditional:") 2
162 -- -----------------------------------------------------------------------------
165 -- just a basic error monad:
167 newtype CmmLint a = CmmLint { unCL :: Either SDoc a }
169 instance Monad CmmLint where
170 CmmLint m >>= k = CmmLint $ case m of
172 Right a -> unCL (k a)
173 return a = CmmLint (Right a)
175 cmmLintErr :: SDoc -> CmmLint a
176 cmmLintErr msg = CmmLint (Left msg)
178 addLintInfo :: SDoc -> CmmLint a -> CmmLint a
179 addLintInfo info thing = CmmLint $
181 Left err -> Left (hang info 2 err)
184 cmmLintMachOpErr :: CmmExpr -> [MachRep] -> [MachRep] -> CmmLint a
185 cmmLintMachOpErr expr argsRep opExpectsRep
186 = cmmLintErr (text "in MachOp application: " $$
187 nest 2 (pprExpr expr) $$
188 (text "op is expecting: " <+> ppr opExpectsRep) $$
189 (text "arguments provide: " <+> ppr argsRep))
191 cmmLintAssignErr :: CmmStmt -> CmmLint a
192 cmmLintAssignErr stmt = cmmLintErr (text "in assignment: " $$
193 nest 2 (pprStmt stmt))
195 cmmLintDubiousWordOffset :: CmmExpr -> CmmLint a
196 cmmLintDubiousWordOffset expr
197 = cmmLintErr (text "offset is not a multiple of words: " $$
198 nest 2 (pprExpr expr))