@@ -118,7 +118,84 @@ class PEval a where
118118
119119markUsed x = tell $ Set. singleton x -- collect the use of the local
120120markUsed' (VarEnv _) = return ()
121- markUsed' (VarLocal x) = markUsed x
121+ markUsed' (VarLocal x) = markUsed x
122+
123+ -- | Check if an expression can fail at runtime or has side effects
124+ -- This is used to prevent unsound dead code elimination
125+ canFailOrHasEffects :: IRExpr -> Bool
126+ canFailOrHasEffects expr = case expr of
127+ -- Binary operations that can fail due to type errors
128+ Bin op _ _ -> case op of
129+ -- Arithmetic operations can fail if operands are not numbers
130+ Basics. Plus -> True
131+ Basics. Minus -> True
132+ Basics. Mult -> True
133+ Basics. Div -> True -- Also division by zero
134+ Basics. IntDiv -> True
135+ Basics. Mod -> True
136+ -- Bitwise operations require numbers
137+ Basics. BinAnd -> True
138+ Basics. BinOr -> True
139+ Basics. BinXor -> True
140+ Basics. BinShiftLeft -> True
141+ Basics. BinShiftRight -> True
142+ Basics. BinZeroShiftRight -> True
143+ -- String concatenation can fail if operands are not strings
144+ Basics. Concat -> True
145+ -- Comparisons that require numbers
146+ Basics. Le -> True
147+ Basics. Lt -> True
148+ Basics. Ge -> True
149+ Basics. Gt -> True
150+ -- These are generally safe
151+ Basics. Eq -> False
152+ Basics. Neq -> False
153+ Basics. And -> False
154+ Basics. Or -> False
155+ Basics. HasField -> False
156+ -- Level operations might be safe but conservative
157+ Basics. FlowsTo -> True
158+ Basics. LatticeJoin -> True
159+ Basics. LatticeMeet -> True
160+ Basics. RaisedTo -> True
161+
162+ -- Unary operations
163+ Un op _ -> case op of
164+ -- List/tuple operations can fail
165+ Basics. Head -> True
166+ Basics. Tail -> True
167+ Basics. Fst -> True
168+ Basics. Snd -> True
169+ -- Arithmetic
170+ Basics. UnMinus -> True
171+ -- Length operations are safe if the value is the right type
172+ Basics. ListLength -> True
173+ Basics. TupleLength -> True
174+ Basics. RecordSize -> True
175+ -- Type tests are safe
176+ Basics. IsTuple -> False
177+ Basics. IsList -> False
178+ Basics. IsRecord -> False
179+ -- Level operations
180+ Basics. LevelOf -> False
181+
182+ -- Field/index projections can fail
183+ ProjField _ _ -> True
184+ ProjIdx _ _ -> True
185+
186+ -- List operations
187+ ListCons _ _ -> True -- Second argument must be a list
188+
189+ -- Function calls can have side effects
190+ Base _ -> True
191+ Lib _ _ -> True
192+
193+ -- These are generally safe
194+ Tuple _ -> False
195+ Record _ -> False
196+ WithRecord _ _ -> False -- Assuming the base is a record
197+ List _ -> False
198+ Const _ -> False
122199
123200-- | Get evaluation of a variable.
124201varPEval :: VarAccess -> Opt PValue
@@ -239,7 +316,9 @@ irExprPeval e =
239316 Nothing -> def_
240317 _ -> def_
241318 -- TODO Implement optimization for ProjIdx
242- ProjIdx x idx -> def_
319+ ProjIdx x idx -> do
320+ markUsed' x -- Mark the tuple variable as used
321+ def_
243322 -- ProjIdx x idx -> do
244323 -- v <- varPEval x
245324 -- case v of
@@ -432,7 +511,8 @@ instance PEval IRBBTree where
432511
433512 (BB insts_ tr_, used) <- listen $ bbPeval bb
434513
435- let isNotDeadAssign (Assign x _) = Set. member x used
514+ let isNotDeadAssign (Assign x e) =
515+ Set. member x used || canFailOrHasEffects e
436516 isNotDeadAssign _ = True
437517
438518 instsFiltered = filter isNotDeadAssign insts_
0 commit comments