@@ -4398,6 +4398,42 @@ improveIf f t cnd thn@(IAps chr@(ICon _ (ICPrim _ PrimChr)) ts1 [chr_thn])
4398
4398
let chrArgType = iGetType chr_thn
4399
4399
(e', _) <- improveIf f chrArgType cnd chr_thn chr_els
4400
4400
return (IAps chr ts1 [e'], True )
4401
+
4402
+ -- Push if improvement inside constructors when one arm is undefined
4403
+ -- and the type has only one constructor
4404
+ --
4405
+ -- Further down, a general improveIf rule optimizes 'if c e _' to just 'e'.
4406
+ -- But that can cause poor code generation for if-else chains returning
4407
+ -- the constructors of a union type, so an earlier improveIf rule catches
4408
+ -- that situation (before the general rule can apply).
4409
+ -- However, if there is only one constructor, we do want an optimization to apply,
4410
+ -- so we put that here, prior to the blocking rule.
4411
+ --
4412
+ improveIf f t cnd thn@ (IAps (ICon i1 c1@ (ICCon {})) ts1 es1)
4413
+ els@ (ICon i2 (ICUndet { iuKind = u }))
4414
+ | numCon (conTagInfo c1) == 1
4415
+ = do
4416
+ when doTraceIf $ traceM (" improveIf ICCon/ICUndet triggered" ++ ppReadable (cnd,thn,els))
4417
+ let realConType = itInst (iConType c1) ts1
4418
+ (argTypes, _) = itGetArrows realConType
4419
+ when (length argTypes /= length es1) $ internalError (" improveIf Con/Undet:" ++ ppReadable (argTypes, es1))
4420
+ let mkUndet t = icUndetAt (getIdPosition i2) t u
4421
+ (es', bs) <- mapAndUnzipM (\ (t, e1) -> improveIf f t cnd e1 (mkUndet t)) (zip argTypes es1)
4422
+ -- unambiguous improvement because the ICCon has propagated out
4423
+ return ((IAps (ICon i1 c1) ts1 es'), True )
4424
+ improveIf f t cnd thn@ (ICon i1 (ICUndet { iuKind = u }))
4425
+ els@ (IAps (ICon i2 c2@ (ICCon {})) ts2 es2)
4426
+ | numCon (conTagInfo c2) == 1
4427
+ = do
4428
+ when doTraceIf $ traceM (" improveIf ICCon/ICUndet triggered" ++ ppReadable (cnd,thn,els))
4429
+ let realConType = itInst (iConType c2) ts2
4430
+ (argTypes, _) = itGetArrows realConType
4431
+ when (length argTypes /= length es2) $ internalError (" improveIf Con/Undet:" ++ ppReadable (argTypes, es2))
4432
+ let mkUndet t = icUndetAt (getIdPosition i1) t u
4433
+ (es', bs) <- mapAndUnzipM (\ (t, e2) -> improveIf f t cnd (mkUndet t) e2) (zip argTypes es2)
4434
+ -- unambiguous improvement because the ICCon has propagated out
4435
+ return ((IAps (ICon i2 c2) ts2 es'), True )
4436
+
4401
4437
-- Do not "optimize" constructors against undefined values because this can remove
4402
4438
-- the conditions required to optimize chains of ifs like these:
4403
4439
-- if (x == 0) 0 else if (x == 1) 1 else ... back to just x
0 commit comments