[Git][ghc/ghc][master] 7 commits: Add regression test for #12002
by Marge Bot (@marge-bot) 26 Mar '26
by Marge Bot (@marge-bot) 26 Mar '26
26 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
57b7878d by Simon Jakobi at 2026-03-26T03:53:07-04:00
Add regression test for #12002
Closes #12002.
- - - - -
c8f9df2d by Simon Jakobi at 2026-03-26T03:53:07-04:00
Add regression test for #12046
Closes #12046.
Co-authored-by: Andreas Klebinger <klebinger.andreas(a)gmx.at>
- - - - -
615d72ac by Simon Jakobi at 2026-03-26T03:53:07-04:00
Add regression test for #13180
Closes #13180.
- - - - -
423eebcf by Simon Jakobi at 2026-03-26T03:53:07-04:00
Add regression test for #11141
Closes #11141.
- - - - -
286849a4 by Simon Jakobi at 2026-03-26T03:53:07-04:00
Add regression test for #11505
Closes #11505.
- - - - -
7db149d9 by Simon Jakobi at 2026-03-26T03:53:07-04:00
Add regression perf test for #13820
Closes #13820.
- - - - -
e73c4adb by Simon Jakobi at 2026-03-26T03:53:07-04:00
Add regression test for #10381
Closes #10381.
- - - - -
19 changed files:
- + testsuite/tests/parser/should_compile/T12002.hs
- + testsuite/tests/parser/should_compile/T12002.stderr
- testsuite/tests/parser/should_compile/all.T
- + testsuite/tests/perf/compiler/T13820.hs
- testsuite/tests/perf/compiler/all.T
- + testsuite/tests/rebindable/T10381.hs
- testsuite/tests/rebindable/all.T
- + testsuite/tests/typecheck/T13180/T13180.hs
- + testsuite/tests/typecheck/T13180/T13180.hs-boot
- + testsuite/tests/typecheck/T13180/T13180.stderr
- + testsuite/tests/typecheck/T13180/T13180A.hs
- + testsuite/tests/typecheck/T13180/all.T
- + testsuite/tests/typecheck/should_compile/T11141.hs
- + testsuite/tests/typecheck/should_compile/T11141.stderr
- + testsuite/tests/typecheck/should_compile/T11505Bar.hs
- + testsuite/tests/typecheck/should_compile/T11505Foo.hs
- + testsuite/tests/typecheck/should_compile/T11505Foo.hs-boot
- + testsuite/tests/typecheck/should_compile/T12046.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
=====================================
testsuite/tests/parser/should_compile/T12002.hs
=====================================
@@ -0,0 +1,5 @@
+-- Test that the misplaced LANGUAGE pragma results in a warning but doesn't
+-- cause the program to be rejected.
+module T12002 where
+
+{-# LANGUAGE OverloadedStrings #-}
=====================================
testsuite/tests/parser/should_compile/T12002.stderr
=====================================
@@ -0,0 +1,6 @@
+T12002.hs:5:1: warning: [GHC-28007] [-Wmisplaced-pragmas (in -Wdefault)]
+ Misplaced LANGUAGE pragma
+ Suggested fix:
+ Perhaps you meant to place it in the module header?
+ The module header is the section at the top of the file, before the ‘module’ keyword
+
=====================================
testsuite/tests/parser/should_compile/all.T
=====================================
@@ -116,6 +116,7 @@ test('DumpParsedAst', normal, compile, ['-dsuppress-uniques -ddump-parsed-a
test('DumpParsedAstComments', normal, compile, ['-dsuppress-uniques -ddump-parsed-ast -dkeep-comments'])
test('DumpRenamedAst', normal, compile, ['-dsuppress-uniques -ddump-rn-ast'])
test('DumpTypecheckedAst', normal, compile, ['-dsuppress-uniques -ddump-tc-ast'])
+test('T12002', normal, compile, [''])
test('T12045e', normal, compile, [''])
test('T13087', normal, compile, [''])
test('T13747', normal, compile, [''])
=====================================
testsuite/tests/perf/compiler/T13820.hs
=====================================
@@ -0,0 +1,11 @@
+-- Regression test for #13820. Instead of the original 27 `id`s, this
+-- test uses only 24, so a regression is less likely to result in an
+-- out-of-memory situation.
+f = id id id id
+ id id id id
+ id id id id
+ id id id id
+ id id id id
+ id id id id
+
+main = print 1
=====================================
testsuite/tests/perf/compiler/all.T
=====================================
@@ -680,6 +680,12 @@ test ('T13253-spj',
],
compile,
['-v0 -O'])
+test ('T13820',
+ [ collect_compiler_stats('peak_megabytes_allocated', 5),
+ collect_compiler_stats('bytes allocated', 2),
+ ],
+ compile,
+ ['-v0'])
test ('T14766',
[ collect_compiler_stats('bytes allocated',2),
pre_cmd('python3 genT14766.py > T14766.hs'),
=====================================
testsuite/tests/rebindable/T10381.hs
=====================================
@@ -0,0 +1,43 @@
+{-# LANGUAGE RebindableSyntax, RankNTypes #-}
+
+module T10381 where
+
+import Prelude ( String, undefined )
+
+newtype Cont r a = Cont { runCont :: (forall i. a i -> r) -> r }
+
+(>>=) :: Cont r a -> (forall i. a i -> Cont r b) -> Cont r b
+ma >>= fmb
+ = Cont (\k -> runCont ma (\a -> runCont (fmb a) k))
+
+fail :: String -> Cont r a
+fail = undefined
+
+return :: a i -> Cont r a
+return x = Cont (\k -> k x)
+
+foo :: Cont r []
+foo = do
+ bar <- foo
+ return bar
+
+{- Previously, GHC used to reject this program with:
+
+ Couldn't match type ‘i0’ with ‘i’
+ because type variable ‘i’ would escape its scope
+ This (rigid, skolem) type variable is bound by
+ a type expected by the context: [i] -> Cont r []
+ at Bug.hs:21:3-12
+ Expected type: Cont r [] -> ([i0] -> Cont r []) -> Cont r []
+ Actual type: Cont r []
+ -> (forall i. [i] -> Cont r []) -> Cont r []
+ In a stmt of a 'do' block: bar <- foo
+ In the expression:
+ do { bar <- foo;
+ return bar }
+ In an equation for ‘foo’:
+ foo
+ = do { bar <- foo;
+ return bar }
+-}
+
=====================================
testsuite/tests/rebindable/all.T
=====================================
@@ -35,6 +35,7 @@ test('T4851', normal, compile, [''])
test('T5908', normal, compile, [''])
test('T10112', normal, compile, [''])
+test('T10381', normal, compile, [''])
test('T11216', normal, compile, [''])
test('T11216A', normal, compile, [''])
test('T12080', normal, compile, [''])
=====================================
testsuite/tests/typecheck/T13180/T13180.hs
=====================================
@@ -0,0 +1,15 @@
+-- Should only report an error of kind:
+--
+-- Type constructor ‘T’ has conflicting definitions ...
+--
+-- Previously, GHC also used to emit an error regarding f:
+--
+-- Identifier ‘f’ has conflicting definitions ...
+module T13180 (T, f) where
+
+import qualified T13180A
+
+type T = Int
+
+f :: T -> T
+f x = T13180A.f x
=====================================
testsuite/tests/typecheck/T13180/T13180.hs-boot
=====================================
@@ -0,0 +1,4 @@
+module T13180 where
+
+data T
+f :: T -> T
=====================================
testsuite/tests/typecheck/T13180/T13180.stderr
=====================================
@@ -0,0 +1,12 @@
+[1 of 3] Compiling T13180[boot] ( T13180.hs-boot, T13180.o-boot )
+[2 of 3] Compiling T13180A ( T13180A.hs, T13180A.o )
+[3 of 3] Compiling T13180 ( T13180.hs, T13180.o )
+T13180.hs-boot:3:1: error: [GHC-15843]
+ • Type constructor ‘T’ has conflicting definitions in the module
+ and its hs-boot file.
+ Main module: type T :: *
+ type T = Int
+ Boot file: type T :: *
+ data T
+ • In the type synonym declaration for ‘T’
+
=====================================
testsuite/tests/typecheck/T13180/T13180A.hs
=====================================
@@ -0,0 +1,3 @@
+module T13180A (f) where
+
+import {-# SOURCE #-} T13180
=====================================
testsuite/tests/typecheck/T13180/all.T
=====================================
@@ -0,0 +1 @@
+test('T13180', normal, multimod_compile_fail, ['T13180', '-fforce-recomp'])
=====================================
testsuite/tests/typecheck/should_compile/T11141.hs
=====================================
@@ -0,0 +1,28 @@
+{-# LANGUAGE FunctionalDependencies #-}
+{-# LANGUAGE InstanceSigs #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+module T11141 where
+
+data F a = F a
+instance Show a => Show (F a) where
+ show :: forall a. Show a => F a -> String
+ show (F x) = show x
+
+{- Previously emitted error:
+
+ Could not deduce (Show a0)
+ from the context (Show a)
+ bound by the type signature for show :: Show a => F a -> String
+ at A.hs:8:13-45
+ The type variable ‘a0’ is ambiguous
+ When checking that:
+ forall a. Show a => forall a1. Show a1 => F a1 -> String
+ is more polymorphic than: forall a. Show a => F a -> String
+ When checking that instance signature for ‘show’
+ is more general than its signature in the class
+ Instance sig: forall a.
+ Show a =>
+ forall a1. Show a1 => F a1 -> String
+ Class sig: forall a. Show a => F a -> String
+ In the instance declaration for ‘Show (F a)’
+-}
=====================================
testsuite/tests/typecheck/should_compile/T11141.stderr
=====================================
@@ -0,0 +1,4 @@
+T11141.hs:8:20: warning: [GHC-63397] [-Wname-shadowing (in -Wall)]
+ This binding for ‘a’ shadows the existing binding
+ bound at T11141.hs:7:10
+
=====================================
testsuite/tests/typecheck/should_compile/T11505Bar.hs
=====================================
@@ -0,0 +1,3 @@
+module T11505Bar where
+
+import {-# SOURCE #-} T11505Foo
=====================================
testsuite/tests/typecheck/should_compile/T11505Foo.hs
=====================================
@@ -0,0 +1,12 @@
+module T11505Foo where
+
+import T11505Bar
+
+-- #11505: this used to fail with:
+--
+-- T11505Foo.hs:12:1:
+-- Type constructor `Foo' has conflicting definitions in the module
+-- and its hs-boot file
+-- Main module: data Foo = Foo {x :: {-# UNPACK #-} !Int}
+-- Boot file: data Foo = Foo {x :: !Int}
+data Foo = Foo { x :: {-# UNPACK #-} !Int }
=====================================
testsuite/tests/typecheck/should_compile/T11505Foo.hs-boot
=====================================
@@ -0,0 +1,3 @@
+module T11505Foo where
+
+data Foo = Foo { x :: {-# UNPACK #-} !Int }
=====================================
testsuite/tests/typecheck/should_compile/T12046.hs
=====================================
@@ -0,0 +1,16 @@
+-- Test that AllowAmbiguousTypes works with UndecidableSuperClasses.
+-- Both test1 and test2 should be accepted.
+{-# LANGUAGE UndecidableSuperClasses #-}
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE TypeFamilies #-}
+module T12046 where
+
+class A (T a) => A a where
+ type T a
+
+test1 :: forall a. A a => ()
+test1 = ()
+
+test2 :: A a => proxy a -> ()
+test2 _ = ()
+
=====================================
testsuite/tests/typecheck/should_compile/all.T
=====================================
@@ -496,6 +496,7 @@ test('T10770b', expect_broken(10770), compile, [''])
test('T10935', normal, compile, [''])
test('T10971a', normal, compile, [''])
test('T11062', [extra_files(['T11062.hs', 'T11062.hs-boot', 'T11062a.hs'])], multimod_compile, ['T11062', '-v0'])
+test('T11141', normal, compile, ['-Wname-shadowing'])
test('T11237', normal, compile, [''])
test('T10592', normal, compile, [''])
test('T11305', normal, compile, [''])
@@ -507,6 +508,7 @@ test('RebindNegate', normal, compile, [''])
test('T11319', normal, compile, [''])
test('T11397', normal, compile, [''])
test('T11458', normal, compile, [''])
+test('T11505', [extra_files(['T11505Foo.hs', 'T11505Foo.hs-boot', 'T11505Bar.hs'])], multimod_compile, ['T11505Foo', '-v0'])
test('T11506', normal, compile, [''])
test('T11524', normal, compile, [''])
test('T11552', normal, compile, [''])
@@ -525,6 +527,7 @@ test('T11982a', expect_broken(11982), compile, [''])
test('T11982b', expect_broken(11982), compile, [''])
test('T11982c', normal, compile, [''])
test('T12045a', normal, compile, [''])
+test('T12046', normal, compile, [''])
test('T12064', [], multimod_compile, ['T12064', '-v0'])
test('ExPat', normal, compile, [''])
test('ExPatFail', normal, compile_fail, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2823b03966e495581f4695f07649c5…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2823b03966e495581f4695f07649c5…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][master] AArch64: fix MOVK regUsageOfInstr to mark dst as both read and written
by Marge Bot (@marge-bot) 26 Mar '26
by Marge Bot (@marge-bot) 26 Mar '26
26 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
2823b039 by Ian Duncan at 2026-03-26T03:52:21-04:00
AArch64: fix MOVK regUsageOfInstr to mark dst as both read and written
MOVK (move with keep) modifies only a 16-bit slice of the destination
register, so the destination is both read and written. The register
allocator must know this to avoid clobbering live values. Update
regUsageOfInstr to list the destination in both src and dst sets.
No regression test: triggering the misallocation requires specific
register pressure around a MOVK sequence, which is difficult to
reliably provoke from Haskell source.
- - - - -
1 changed file:
- compiler/GHC/CmmToAsm/AArch64/Instr.hs
Changes:
=====================================
compiler/GHC/CmmToAsm/AArch64/Instr.hs
=====================================
@@ -119,7 +119,7 @@ regUsageOfInstr platform instr = case instr of
LSL dst src1 src2 -> usage (regOp src1 ++ regOp src2, regOp dst)
LSR dst src1 src2 -> usage (regOp src1 ++ regOp src2, regOp dst)
MOV dst src -> usage (regOp src, regOp dst)
- MOVK dst src -> usage (regOp src, regOp dst)
+ MOVK dst src -> usage (regOp src ++ regOp dst, regOp dst)
MOVZ dst src -> usage (regOp src, regOp dst)
MVN dst src -> usage (regOp src, regOp dst)
ORR _fmt dst src1 src2 -> usage (regOp src1 ++ regOp src2, regOp dst)
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2823b03966e495581f4695f07649c58…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/2823b03966e495581f4695f07649c58…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
26 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
45428f88 by sheaf at 2026-03-26T03:51:31-04:00
Avoid infinite loop in deep subsumption
This commit ensures we only unify after we recur in the deep subsumption
code in the FunTy vs non-FunTy case of GHC.Tc.Utils.Unify.tc_sub_type_deep,
to avoid falling into an infinite loop.
See the new Wrinkle [Avoiding a loop in tc_sub_type_deep] in
Note [FunTy vs non-FunTy case in tc_sub_type_deep] in GHC.Tc.Utils.Unify.
Fixes #26823
Co-authored-by: simonpj <simon.peytonjones(a)gmail.com>
- - - - -
5 changed files:
- compiler/GHC/Tc/Utils/Unify.hs
- testsuite/tests/typecheck/should_compile/T26225.hs
- + testsuite/tests/typecheck/should_fail/T26823.hs
- + testsuite/tests/typecheck/should_fail/T26823.stderr
- testsuite/tests/typecheck/should_fail/all.T
Changes:
=====================================
compiler/GHC/Tc/Utils/Unify.hs
=====================================
@@ -1948,6 +1948,41 @@ the LHS vs the new RHS. And vice-versa (if it's the RHS that is a FunTy).
See T11305 and T26225 for examples of when this is important.
+Wrinkle [Avoiding a loop in tc_sub_type_deep]
+
+ In #26823, we had:
+
+ alpha <= a -> alpha
+
+ If we simply unified the two types, the occurs-check would trigger.
+ In deep subsumption however, we need to be careful, as we might do the
+ following:
+
+ A1. Create fresh metavariables beta, gamma
+ A2. Unify alpha ~ beta -> gamma
+ A3. Decompose "beta -> gamma <= a -> (beta -> gamma)", obtaining
+ a <= beta and gamma <= beta -> gamma
+ A4. Recur with gamma <= beta -> gamma
+
+ If we do this, we enter an infinite loop and GHC hangs at compile time.
+ To avoid this, we must first recur, before unifying. So the above becomes:
+
+ B1 (like A1). Create fresh metavariables beta, gamma
+ B2 (like A3). Decompose "beta -> gamma <= a -> alpha", obtaining
+ a <= beta and gamma <= alpha
+ B3. Solve these two sub-problems by unification
+ a ~ beta, gamma ~ alpha
+ B4 (like A2). Then, and only then, unify alpha ~ beta->gamma
+
+ With this approach, GHC will be left with the following unifications:
+
+ - alpha ~ (beta -> gamma)
+ - a ~ beta
+ - gamma ~ alpha
+
+ GHC will fail to solve this unification problem due to an occurs check
+ failure, thus rejecting the program with a type error (as desired).
+
Note [Deep subsumption and required foralls]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A required forall, (forall a -> ty) behaves like a "rho-type", one with no
@@ -2117,8 +2152,9 @@ tc_sub_type_deep fun_pos@(tc_fun, pos) ds_depth unify inst_orig ctxt ty_actual t
; exp_arg <- newOpenFlexiTyVarTy -- NB: no FRR check needed; we might not need to eta-expand
; exp_res <- newOpenFlexiTyVarTy
; let exp_funTy = FunTy { ft_af = af1, ft_mult = exp_mult, ft_arg = exp_arg, ft_res = exp_res }
- ; unify_wrap <- just_unify exp_funTy ty_e
+ -- Recur before unifying; see Wrinkle [Avoiding a loop in tc_sub_type_deep]
; fun_wrap <- go_fun af1 act_mult act_arg act_res af1 exp_mult exp_arg exp_res
+ ; unify_wrap <- just_unify exp_funTy ty_e
; return $ unify_wrap <.> fun_wrap
-- unify_wrap :: exp_funTy ~~> ty_e
-- fun_wrap :: ty_a ~~> exp_funTy
@@ -2129,8 +2165,9 @@ tc_sub_type_deep fun_pos@(tc_fun, pos) ds_depth unify inst_orig ctxt ty_actual t
; act_arg <- newOpenFlexiTyVarTy -- NB: no FRR check needed; we might not need to eta-expand
; act_res <- newOpenFlexiTyVarTy
; let act_funTy = FunTy { ft_af = af2, ft_mult = act_mult, ft_arg = act_arg, ft_res = act_res }
- ; unify_wrap <- just_unify ty_a act_funTy
+ -- Recur before unifying; see Wrinkle [Avoiding a loop in tc_sub_type_deep]
; fun_wrap <- go_fun af2 act_mult act_arg act_res af2 exp_mult exp_arg exp_res
+ ; unify_wrap <- just_unify ty_a act_funTy
; return $ fun_wrap <.> unify_wrap
-- unify_wrap :: ty_a ~~> act_funTy
-- fun_wrap :: act_funTy ~~> ty_e
=====================================
testsuite/tests/typecheck/should_compile/T26225.hs
=====================================
@@ -26,7 +26,7 @@ ex0 =
in g f
-- ((∀ a. a->a) -> Int) -> Bool ⊑ α[tau]
--- Rejected by GHC up to and including 9.14.
+-- Rejected by GHC up to and including 9.12.
ex1' :: ()
ex1' =
let
@@ -38,7 +38,7 @@ ex1' =
-- Couldn't match expected type ‘α’ with actual type ‘((∀ a. a -> a) -> Int) -> Bool’
-- ((∀ a. a->a) -> Int) -> Bool ⊑ β[tau] Bool
--- Rejected by GHC up to and including 9.14.
+-- Rejected by GHC up to and including 9.12.
ex2' :: ()
ex2' =
let
@@ -50,7 +50,7 @@ ex2' =
-- Couldn't match expected type ‘β’ with actual type ‘(->) ((∀ a. a -> a) -> Int)’
-- ex3 :: β[tau] Bool ⊑ (∀ a. a->a) -> Bool
--- Rejected by GHC up to and including 9.14.
+-- Rejected by GHC up to and including 9.12.
ex3 :: ()
ex3 =
let
@@ -62,7 +62,7 @@ ex3 =
-- Couldn't match expected type ‘β’ with actual type ‘(->) (∀ a. a -> a)’
-- ex3' :: F Int Bool ⊑ (∀ a. a->a) -> Bool, where F Int = (->) (Int -> Int)
--- Rejected by GHC up to and including 9.14.
+-- Rejected by GHC up to and including 9.12.
ex3' :: ()
ex3' =
let
=====================================
testsuite/tests/typecheck/should_fail/T26823.hs
=====================================
@@ -0,0 +1,15 @@
+{-# LANGUAGE DeepSubsumption #-}
+
+module T26823 where
+
+allocArray :: Int -> IO ()
+allocArray n = do
+ let
+ !off = 18
+ !size = 8
+ !vecAli = size
+
+ !rem = off `rem` vecAli
+ !start = if rem == 0 then off else off + ( vecAli - rem )
+
+ return ()
=====================================
testsuite/tests/typecheck/should_fail/T26823.stderr
=====================================
@@ -0,0 +1,32 @@
+T26823.hs:12:14: error: [GHC-25897]
+ • Couldn't match expected type ‘a0 -> a0 -> t’ with actual type ‘t’
+ ‘t’ is a rigid type variable bound by
+ the inferred type of rem :: a0 -> a0 -> t
+ at T26823.hs:12:5-29
+ • In the expression: off `rem` vecAli
+ In an equation for ‘rem’: !rem = off `rem` vecAli
+ In a stmt of a 'do' block:
+ let !off = 18
+ !size = 8
+ !vecAli = size
+ !rem = off `rem` vecAli
+ !start = if rem == 0 then off else off + (vecAli - rem)
+ • Relevant bindings include
+ rem :: a0 -> a0 -> t (bound at T26823.hs:12:6)
+ off :: a0 (bound at T26823.hs:8:6)
+ vecAli :: a0 (bound at T26823.hs:10:6)
+ size :: a0 (bound at T26823.hs:9:6)
+
+T26823.hs:13:57: error: [GHC-27958]
+ • Couldn't match expected type ‘a0’
+ with actual type ‘a0 -> a0 -> t0’
+ • In the second argument of ‘(-)’, namely ‘rem’
+ In the second argument of ‘(+)’, namely ‘(vecAli - rem)’
+ In the expression: off + (vecAli - rem)
+ • Relevant bindings include
+ start :: a0 (bound at T26823.hs:13:6)
+ rem :: forall {t}. a0 -> a0 -> t (bound at T26823.hs:12:6)
+ off :: a0 (bound at T26823.hs:8:6)
+ vecAli :: a0 (bound at T26823.hs:10:6)
+ size :: a0 (bound at T26823.hs:9:6)
+
=====================================
testsuite/tests/typecheck/should_fail/all.T
=====================================
@@ -755,5 +755,6 @@ test('T23162a', normal, compile_fail, [''])
test('T23162b', normal, compile_fail, [''])
test('T23162c', normal, compile, [''])
test('T23162d', normal, compile, [''])
+test('T26823', normal, compile_fail, [''])
test('T26861', normal, compile_fail, [''])
test('T26862', normal, compile_fail, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/45428f88f62896650156dc822229974…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/45428f88f62896650156dc822229974…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][master] ghc-internal: Float Generics to near top of module graph
by Marge Bot (@marge-bot) 26 Mar '26
by Marge Bot (@marge-bot) 26 Mar '26
26 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
661da815 by Teo Camarasu at 2026-03-26T03:50:33-04:00
ghc-internal: Float Generics to near top of module graph
We remove GHC.Internal.Generics from the critical path of the
`ghc-internal` module graph. GHC.Internal.Generics used to be in the
middle of the module graph, but now it is nearer the top (built later).
This change thins out the module graph and allows us to get rid of the
ByteOrder hs-boot file.
We implement this by moving Generics instances from the module where the
datatype is defined to the GHC.Internal.Generics module. This trades off
increasing the compiled size of GHC.Internal.Generics with reducing the
dependency footprint of datatype modules.
Not all instances are moved to GHC.Internal.Generics. For instance,
`GHC.Internal.Control.Monad.Fix` keeps its instance as it is one of the
very last modules compiled in `ghc-internal` and so inverting the
relationship here would risk adding GHC.Internal.Generics back onto the
critical path.
We also don't change modules that are re-exported from the `template-haskell` or `ghc-heap`.
This is done to make it easy to eventually move `Generics` to `base`
once something like #26657 is implemented.
Resolves #26930
Metric Decrease:
T21839c
- - - - -
23 changed files:
- libraries/ghc-internal/src/GHC/Internal/ByteOrder.hs
- − libraries/ghc-internal/src/GHC/Internal/ByteOrder.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Data/Foldable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Const.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Identity.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Monoid.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Semigroup/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Traversable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Version.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Control.hs
- libraries/ghc-internal/src/GHC/Internal/Functor/ZipList.hs
- libraries/ghc-internal/src/GHC/Internal/Generics.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- libraries/ghc-internal/src/GHC/Internal/Read.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Bits.hs
- testsuite/tests/ghci/scripts/ListTuplePunsPpr.stdout
- testsuite/tests/ghci/scripts/T10963.stderr
- testsuite/tests/ghci/scripts/ghci064.stdout
- testsuite/tests/interface-stability/base-exports.stdout
- testsuite/tests/interface-stability/base-exports.stdout-javascript-unknown-ghcjs
- testsuite/tests/interface-stability/base-exports.stdout-mingw32
- testsuite/tests/interface-stability/base-exports.stdout-ws-32
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/661da815f2551f86a55b73361bef881…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/661da815f2551f86a55b73361bef881…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][master] rts: Align stack to 64-byte boundary in StgRun on x86
by Marge Bot (@marge-bot) 26 Mar '26
by Marge Bot (@marge-bot) 26 Mar '26
26 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
a5ec467e by ARATA Mizuki at 2026-03-26T03:49:49-04:00
rts: Align stack to 64-byte boundary in StgRun on x86
When LLVM spills AVX/AVX-512 vector registers to the stack, it requires
32-byte (__m256) or 64-byte (__m512) alignment. If the stack is not
sufficiently aligned, LLVM inserts a realignment prologue that reserves
%rbp as a frame pointer, conflicting with GHC's use of %rbp as an STG
callee-saved register and breaking the tail-call-based calling convention.
Previously, GHC worked around this by lying to LLVM about the stack
alignment and rewriting aligned vector loads/stores (VMOVDQA, VMOVAPS)
to unaligned ones (VMOVDQU, VMOVUPS) in the LLVM Mangler. This had two
problems:
- It did not extend to AVX-512, which requires 64-byte alignment. (#26595)
- When Haskell calls a C function that takes __m256/__m512 arguments on
the stack, the callee requires genuine alignment, which could cause a
segfault. (#26822)
This patch genuinely aligns the stack to 64 bytes in StgRun by saving
the original stack pointer before alignment and restoring it in
StgReturn. We now unconditionally advertise 64-byte stack alignment to
LLVM for all x86 targets, making rewriteAVX in the LLVM Mangler
unnecessary. STG_RUN_STACK_FRAME_SIZE is increased from 48 to 56 bytes
on non-Windows x86-64 to store the saved stack pointer.
Closes #26595 and #26822
Co-Authored-By: Claude Opus 4.5 <noreply(a)anthropic.com>
- - - - -
13 changed files:
- compiler/GHC/CmmToLlvm.hs
- compiler/GHC/CmmToLlvm/Config.hs
- compiler/GHC/CmmToLlvm/Mangler.hs
- compiler/GHC/Driver/Config/CmmToLlvm.hs
- rts/StgCRun.c
- rts/include/rts/Constants.h
- + testsuite/tests/simd/should_run/StackAlignment32.hs
- + testsuite/tests/simd/should_run/StackAlignment32.stdout
- + testsuite/tests/simd/should_run/StackAlignment32_main.c
- + testsuite/tests/simd/should_run/StackAlignment64.hs
- + testsuite/tests/simd/should_run/StackAlignment64.stdout
- + testsuite/tests/simd/should_run/StackAlignment64_main.c
- testsuite/tests/simd/should_run/all.T
Changes:
=====================================
compiler/GHC/CmmToLlvm.hs
=====================================
@@ -217,11 +217,15 @@ cmmMetaLlvmPrelude = do
Nothing -> [ MetaStr name ]
platform <- getPlatform
- cfg <- getConfig
let stack_alignment_metas =
case platformArch platform of
- ArchX86_64 | llvmCgAvxEnabled cfg -> [mkStackAlignmentMeta 32]
- _ -> []
+ -- LLVM inserts stack realignment prologue/epilogue when it wants to place __m256 or __m512 on the stack.
+ -- However, it reserves %rbp as the frame pointer, conflicting with our use of it.
+ -- Therefore, we tell LLVM that the stack is already aligned to avoid stack realignment.
+ -- See also Note [Stack Alignment on X86] and https://gitlab.haskell.org/ghc/ghc/-/issues/26595.
+ ArchX86 -> [mkStackAlignmentMeta 64]
+ ArchX86_64 -> [mkStackAlignmentMeta 64]
+ _ -> []
let codel_model_metas =
case platformArch platform of
-- FIXME: We should not rely on LLVM
=====================================
compiler/GHC/CmmToLlvm/Config.hs
=====================================
@@ -22,7 +22,6 @@ data LlvmCgConfig = LlvmCgConfig
, llvmCgContext :: !SDocContext -- ^ Context for LLVM code generation
, llvmCgFillUndefWithGarbage :: !Bool -- ^ Fill undefined literals with garbage values
, llvmCgSplitSection :: !Bool -- ^ Split sections
- , llvmCgAvxEnabled :: !Bool
, llvmCgBmiVersion :: Maybe BmiVersion -- ^ (x86) BMI instructions
, llvmCgLlvmVersion :: Maybe LlvmVersion -- ^ version of Llvm we're using
, llvmCgDoWarn :: !Bool -- ^ True ==> warn unsupported Llvm version
=====================================
compiler/GHC/CmmToLlvm/Mangler.hs
=====================================
@@ -38,7 +38,7 @@ llvmFixupAsm platform f1 f2 = {-# SCC "llvm_mangler" #-}
-- | These are the rewrites that the mangler will perform
rewrites :: [Rewrite]
-rewrites = [rewriteSymType, rewriteAVX, rewriteCall, rewriteJump]
+rewrites = [rewriteSymType, rewriteCall, rewriteJump]
type Rewrite = Platform -> B.ByteString -> Maybe B.ByteString
@@ -85,23 +85,6 @@ rewriteSymType _ l
funcType = prefix `B.cons` B.pack "function"
objType = prefix `B.cons` B.pack "object"
--- | This rewrites aligned AVX instructions to their unaligned counterparts on
--- x86-64. This is necessary because the stack is not adequately aligned for
--- aligned AVX spills, so LLVM would emit code that adjusts the stack pointer
--- and disable tail call optimization. Both would be catastrophic here so GHC
--- tells LLVM that the stack is 32-byte aligned (even though it isn't) and then
--- rewrites the instructions in the mangler.
-rewriteAVX :: Rewrite
-rewriteAVX platform s
- | not isX86_64 = Nothing
- | isVmovdqa s = Just $ replaceOnce (B.pack "vmovdqa") (B.pack "vmovdqu") s
- | isVmovap s = Just $ replaceOnce (B.pack "vmovap") (B.pack "vmovup") s
- | otherwise = Nothing
- where
- isX86_64 = platformArch platform == ArchX86_64
- isVmovdqa = B.isPrefixOf (B.pack "vmovdqa")
- isVmovap = B.isPrefixOf (B.pack "vmovap")
-
-- | This rewrites (tail) calls to avoid creating PLT entries for
-- functions on riscv64. The replacement will load the address from the
-- GOT, which is resolved to point to the real address of the function.
=====================================
compiler/GHC/Driver/Config/CmmToLlvm.hs
=====================================
@@ -23,7 +23,6 @@ initLlvmCgConfig logger config_cache dflags = do
, llvmCgContext = initSDocContext dflags PprCode
, llvmCgFillUndefWithGarbage = gopt Opt_LlvmFillUndefWithGarbage dflags
, llvmCgSplitSection = gopt Opt_SplitSections dflags
- , llvmCgAvxEnabled = isAvxEnabled dflags
, llvmCgBmiVersion = case platformArch (targetPlatform dflags) of
ArchX86_64 -> bmiVersion dflags
ArchX86 -> bmiVersion dflags
=====================================
rts/StgCRun.c
=====================================
@@ -108,19 +108,24 @@ StgFunPtr StgReturn(void)
/*
* Note [Stack Alignment on X86]
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * On X86 (both 32bit and 64bit) we keep the stack aligned on function calls at
- * a 16-byte boundary. This is done because on a number of architectures the
- * ABI requires this (e.g. the System V AMD64 ABI, Mac OS X 32-bit/64-bit ABIs,
- * and the Win64 ABI) as well as interfacing with * other libraries through the
- * FFI.
+ * On X86, we keep the stack aligned on function calls. We use 64-byte alignment
+ * because it is required for passing AVX-512 vector types (__m512 and friends)
+ * as arguments. See #26822 for a problem caused by insufficient stack alignment.
*
- * As part of this arrangement we must maintain the stack at a 16-byte boundary
- * - word_size-bytes (so 16n - 4 for i386 and 16n - 8 for x64) on entry to a
- * procedure since both GCC and LLVM expect this. This is because the stack
- * should have been 16-byte boundary aligned and then a call made which pushes
- * a return address onto the stack (so word_size more space used). In STG code
- * we only jump to other STG procedures, so we maintain the 16n - word_size
- * alignment for these jumps.
+ * Strictly speaking, we only need 16-byte alignment when we do not use AVX or
+ * AVX-512, but dispatching based on the available ISA extensions would
+ * complicate things. Always using 64-byte alignment is simpler.
+ *
+ * However, the C ABI only requires 16-byte alignment, which is just sufficient
+ * for SSE2 vectors. Therefore, we dynamically align the stack with
+ * `and{l,q} $-64`, and save the original stack pointer.
+ *
+ * On entry to a procedure, we must maintain the stack at a 64-byte boundary
+ * - word_size-bytes (so 64n - 4 for i386 and 64n - 8 for x64) since both GCC
+ * and LLVM expect this. This is because the stack should have been aligned to
+ * a 64-byte boundary, and then a call made which pushes a return address onto
+ * the stack (so word_size more space used). In STG code we only jump to other
+ * STG procedures, so we maintain the 64n - word_size alignment for these jumps.
*
* This gives us binary compatibility with LLVM and GCC as well as dealing
* with the FFI. Previously we just maintained a 16n byte alignment for
@@ -157,51 +162,84 @@ StgFunPtr StgReturn(void)
* Concretely this means we must always keep the stack valid.
* */
+/* Stack layout on x86-32:
+ +-----------------------------+ <------ esp
+ | 4-byte padding |
+ |-----------------------------| <------ esp + 4 (64-byte aligned)
+ | |
+ | RESERVED_C_STACK_BYTES ~16k |
+ | |
+ |-----------------------------| <------ 64-byte aligned
+ | ebx |
+ |-----------------------------|
+ | esi |
+ |-----------------------------|
+ | edi |
+ |-----------------------------|
+ | ebp |
+ |-----------------------------|
+ | saved esp |----+
+ |-----------------------------| |
+ | (padding for alignment) | |
+ |-----------------------------| <--+
+ | eip saved by call StgRun |
+ | in schedule() |
+ +-----------------------------+
+ | the function pointer |
+ +-----------------------------+
+ | BaseReg |
+ +-----------------------------+
+ ...
+ schedule() stack frame
+
+ Lower addresses on the top
+ */
+
+#if RESERVED_C_STACK_BYTES % 64 != 0
+#error "RESERVED_C_STACK_BYTES must be a multiple of 64. If you are changing it, please make sure %esp+4 is a multiple of 64"
+#endif
static void STG_USED
StgRunIsImplementedInAssembler(void)
{
__asm__ volatile (
STG_GLOBAL STG_RUN "\n"
-#if !defined(mingw32_HOST_OS)
STG_HIDDEN STG_RUN "\n"
-#endif
STG_RUN ":\n\t"
/*
* move %esp down to reserve an area for temporary storage
* during the execution of STG code.
*
- * The stack pointer has to be aligned to a multiple of 16
- * bytes from here - this is a requirement of the C ABI, so
- * that C code can assign SSE2 registers directly to/from
- * stack locations.
- *
- * See Note [Windows Stack allocations]
+ * We want the stack pointer to be aligned to a multiple of 64
+ * bytes from here - this is a requirement of the C ABI for
+ * AVX-512, so that C code can assign ZMM registers directly
+ * to/from stack locations.
*/
-#if defined(mingw32_HOST_OS)
- "movl %0, %%eax\n\t"
- "call ___chkstk_ms\n\t"
-#endif
- "subl %0, %%esp\n\t"
+ /* We no longer support i386 Windows, so no need to call __chkstk_ms */
+
+ /* Save the original esp in eax */
+ "movl %%esp, %%eax\n\t"
+ "subl $20, %%esp\n\t" /* area to save 5 registers */
+ "andl $-64, %%esp\n\t"
/*
* save callee-saves registers on behalf of the STG code.
*/
- "movl %%esp, %%eax\n\t"
- "addl %0-16, %%eax\n\t"
- "movl %%ebx,0(%%eax)\n\t"
- "movl %%esi,4(%%eax)\n\t"
- "movl %%edi,8(%%eax)\n\t"
- "movl %%ebp,12(%%eax)\n\t"
+ "movl %%ebx, 0(%%esp)\n\t"
+ "movl %%esi, 4(%%esp)\n\t"
+ "movl %%edi, 8(%%esp)\n\t"
+ "movl %%ebp, 12(%%esp)\n\t"
+ "movl %%eax, 16(%%esp)\n\t"
+ "subl %0, %%esp\n\t"
/*
* Set BaseReg
*/
- "movl 24(%%eax),%%ebx\n\t"
+ "movl 8(%%eax),%%ebx\n\t"
/*
* grab the function argument from the stack
*/
- "movl 20(%%eax),%%eax\n\t"
+ "movl 4(%%eax),%%eax\n\t"
/*
* jump to it
*/
@@ -216,17 +254,16 @@ StgRunIsImplementedInAssembler(void)
* restore callee-saves registers. (Don't stomp on %%eax!)
*/
"movl %%esp, %%edx\n\t"
- "addl %0-16, %%edx\n\t"
+ "addl %0, %%edx\n\t"
"movl 0(%%edx),%%ebx\n\t" /* restore the registers saved above */
"movl 4(%%edx),%%esi\n\t"
"movl 8(%%edx),%%edi\n\t"
"movl 12(%%edx),%%ebp\n\t"
-
- "addl %0, %%esp\n\t"
+ "movl 16(%%edx),%%esp\n\t"
"ret"
- : : "i" (RESERVED_C_STACK_BYTES + 16)
- // + 16 to make room for the 4 registers we have to save
+ : : "i" (RESERVED_C_STACK_BYTES + 4)
+ // + 4 to mimic `calll`
// See Note [Stack Alignment on X86]
);
}
@@ -302,10 +339,12 @@ is as follows:
C STACK "ADDRESS SPACE" |
v
+-----------------------------+ <------ rsp
+ | 8-byte padding |
+ |-----------------------------| <------ rsp + 8 (64-byte aligned)
| |
| RESERVED_C_STACK_BYTES ~16k |
| |
- |-----------------------------|
+ |-----------------------------| <------ 64-byte aligned
| rbx ||
|-----------------------------| \
| rbp | |
@@ -315,9 +354,13 @@ is as follows:
| r13 | | STG_RUN_STACK_FRAME_SIZE
|-----------------------------| /
| r14 | |
- |-----------------------------| /
- | r15 | |
- |-----------------------------|/
+ |-----------------------------| |
+ | r15 | /
+ |-----------------------------| |
+ | saved rsp |-+---
+ |-----------------------------|/ |
+ | (padding for alignment) | |
+ |-----------------------------| <---
| rip saved by call StgRun |
| in schedule() |
+-----------------------------+
@@ -367,6 +410,10 @@ stack unwinding.
*/
+#if RESERVED_C_STACK_BYTES % 64 != 0
+#error "RESERVED_C_STACK_BYTES must be a multiple of 64. If you are changing it, please make sure %rsp+8 is a multiple of 64"
+#endif
+
static void STG_USED
StgRunIsImplementedInAssembler(void)
{
@@ -385,9 +432,22 @@ StgRunIsImplementedInAssembler(void)
#if defined(mingw32_HOST_OS)
"movq %1, %%rax\n\t"
"addq %0, %%rax\n\t"
+ "addq $63, %%rax\n\t" /* extra space for 64-byte alignment */
"callq ___chkstk_ms\n\t"
#endif
+ /*
+ * Save the original rsp in r11 (caller-saved, so we don't need to
+ * preserve it across calls). We need this to restore rsp after
+ * the 64-byte alignment.
+ */
+ "movq %%rsp, %%r11\n\t"
+ /*
+ * Allocate space for saved registers, then align to 64-byte boundary.
+ * The alignment is required for AVX-512 instructions.
+ * See Note [Stack Alignment on X86].
+ */
"subq %1, %%rsp\n\t"
+ "andq $-64, %%rsp\n\t"
"movq %%rsp, %%rax\n\t"
"subq %0, %%rsp\n\t"
"movq %%rbx,0(%%rax)\n\t"
@@ -396,6 +456,7 @@ StgRunIsImplementedInAssembler(void)
"movq %%r13,24(%%rax)\n\t"
"movq %%r14,32(%%rax)\n\t"
"movq %%r15,40(%%rax)\n\t"
+ "movq %%r11,48(%%rax)\n\t" /* save original rsp */
#if defined(mingw32_HOST_OS)
/*
* Additional callee saved registers on Win64. This must match
@@ -403,25 +464,35 @@ StgRunIsImplementedInAssembler(void)
* both represent the Win64 calling convention.
*
* Note that we must save the entire 128-bit width of the XMM
- * registers, as noted in #21465. Moreover, note that, due to the
- * presence of the return address on the stack, %rsp+8 is
- * 16-byte aligned. Since MOVAPS requires memory operands to be aligned
- * to 16-bytes, we must add a word of padding here.
+ * registers, as noted in #21465. Since we align the stack to
+ * 64 bytes, MOVAPS alignment requirements are satisfied.
+ *
+ * The Win64 calling convention says the upper YMM/ZMM parts are
+ * volatile, so we do not need to save them. See Microsoft Learn
+ * for the description of the calling convention:
+ * https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msv…
+ *
+ * Layout (offsets from rax):
+ * 0-47: rbx, rbp, r12, r13, r14, r15
+ * 48: original rsp
+ * 56: rdi
+ * 64: rsi
+ * 72: padding for 16-byte alignment of XMM registers
+ * 80-239: xmm6-xmm15 (10 * 16 bytes)
*/
- "movq %%rdi, 48(%%rax)\n\t"
- "movq %%rsi, 56(%%rax)\n\t"
- /* 8 bytes of padding for alignment */
- "movaps %%xmm6, 72(%%rax)\n\t"
- "movaps %%xmm7, 88(%%rax)\n\t"
- "movaps %%xmm8, 104(%%rax)\n\t"
- "movaps %%xmm9, 120(%%rax)\n\t"
- "movaps %%xmm10,136(%%rax)\n\t"
- "movaps %%xmm11,152(%%rax)\n\t"
- "movaps %%xmm12,168(%%rax)\n\t"
- "movaps %%xmm13,184(%%rax)\n\t"
- "movaps %%xmm14,200(%%rax)\n\t"
- "movaps %%xmm15,216(%%rax)\n\t"
+ "movq %%rdi, 56(%%rax)\n\t"
+ "movq %%rsi, 64(%%rax)\n\t"
/* 8 bytes of padding for alignment */
+ "movaps %%xmm6, 80(%%rax)\n\t"
+ "movaps %%xmm7, 96(%%rax)\n\t"
+ "movaps %%xmm8, 112(%%rax)\n\t"
+ "movaps %%xmm9, 128(%%rax)\n\t"
+ "movaps %%xmm10,144(%%rax)\n\t"
+ "movaps %%xmm11,160(%%rax)\n\t"
+ "movaps %%xmm12,176(%%rax)\n\t"
+ "movaps %%xmm13,192(%%rax)\n\t"
+ "movaps %%xmm14,208(%%rax)\n\t"
+ "movaps %%xmm15,224(%%rax)\n\t"
#endif
#if defined(ENABLE_UNWINDING)
@@ -431,6 +502,11 @@ StgRunIsImplementedInAssembler(void)
*
* N.B. We don't support unwinding on Darwin due to
* various toolchain insanity.
+ *
+ * Note: Due to dynamic 64-byte alignment, the exact stack offset
+ * varies at runtime. The original rsp is saved at offset 48 in the
+ * register save area. We use a DWARF expression to compute the
+ * CFA from the saved rsp value.
*/
".cfi_def_cfa rsp, 0\n\t"
".cfi_offset rbx, %c2\n\t"
@@ -439,30 +515,69 @@ StgRunIsImplementedInAssembler(void)
".cfi_offset r13, %c5\n\t"
".cfi_offset r14, %c6\n\t"
".cfi_offset r15, %c7\n\t"
- ".cfi_offset rip, %c8\n\t"
- ".cfi_escape " // DW_CFA_val_expression is not expressible otherwise
- "0x16, " // DW_CFA_val_expression
- "0x07, " // register num 7 - rsp
- "0x04, " // block length
- "0x77, " // DW_OP_breg7 - signed LEB128 offset from rsp
-#define RSP_DELTA (RESERVED_C_STACK_BYTES + STG_RUN_STACK_FRAME_SIZE + 8)
- "%c9" // signed LEB128 encoded delta - byte 1
-#if (RSP_DELTA >> 7) > 0
- ", %c10" // signed LEB128 encoded delta - byte 2
+ /*
+ * The original rsp is saved at RESERVED_C_STACK_BYTES + 56 from
+ * current rsp. We use DW_CFA_expression to indicate that rsp's
+ * value can be found by loading from that stack location.
+ */
+#define RSP_DELTA (RESERVED_C_STACK_BYTES + 56)
+ ".cfi_escape "
+ "0x10, " // DW_CFA_expression
+ "0x07, " // register num 7 - rsp
+#if (RSP_DELTA >> 20) > 0
+ "0x05, " // block length = 5
+#elif (RSP_DELTA >> 13) > 0
+ "0x04, " // block length = 4
+#elif (RSP_DELTA >> 6) > 0
+ "0x03, " // block length = 3
+#else
+ "0x02, " // block length = 2
#endif
-
-#if (RSP_DELTA >> 14) > 0
- ", %c11" // signed LEB128 encoded delta - byte 3
+ "0x77, " // DW_OP_breg7 (rsp + offset)
+ "%c8" // signed LEB128 offset to saved rsp (RESERVED_C_STACK_BYTES + 56)
+#if (RSP_DELTA >> 6) > 0
+ ", %c9" // signed LEB128 encoded delta - byte 2
#endif
-
-#if (RSP_DELTA >> 21) > 0
- ", %c12" // signed LEB128 encoded delta - byte 4
+#if (RSP_DELTA >> 13) > 0
+ ", %c10" // signed LEB128 encoded delta - byte 3
#endif
-
-#if (RSP_DELTA >> 28) > 0
+#if (RSP_DELTA >> 20) > 0
+ ", %c11" // signed LEB128 encoded delta - byte 4
+#endif
+#if (RSP_DELTA >> 27) > 0
#error "RSP_DELTA too big"
#endif
"\n\t"
+ /*
+ * The return address (rip) is at the original rsp location.
+ * Since original rsp is saved at offset 48 in register save area,
+ * rip = *saved_rsp = **(rsp + 8 + RESERVED_C_STACK_BYTES + 48).
+ */
+ ".cfi_escape "
+ "0x10, " // DW_CFA_expression
+ "0x10, " // register num 16 - rip
+#if (RSP_DELTA >> 20) > 0
+ "0x06, " // block length = 6
+#elif (RSP_DELTA >> 13) > 0
+ "0x05, " // block length = 5
+#elif (RSP_DELTA >> 6) > 0
+ "0x04, " // block length = 4
+#else
+ "0x03, " // block length = 3
+#endif
+ "0x77, " // DW_OP_breg7 (rsp + offset)
+ "%c8" // signed LEB128 offset to saved rsp
+#if (RSP_DELTA >> 6) > 0
+ ", %c9" // signed LEB128 encoded delta - byte 2
+#endif
+#if (RSP_DELTA >> 13) > 0
+ ", %c10" // signed LEB128 encoded delta - byte 3
+#endif
+#if (RSP_DELTA >> 20) > 0
+ ", %c11" // signed LEB128 encoded delta - byte 4
+#endif
+ ", 0x06" // DW_OP_deref
+ "\n\t"
#endif /* defined(ENABLE_UNWINDING) */
/*
@@ -510,55 +625,50 @@ StgRunIsImplementedInAssembler(void)
"movq 32(%%rsp),%%r14\n\t"
"movq 40(%%rsp),%%r15\n\t"
#if defined(mingw32_HOST_OS)
- "movq 48(%%rsp),%%rdi\n\t"
- "movq 56(%%rsp),%%rsi\n\t"
+ "movq 56(%%rsp),%%rdi\n\t"
+ "movq 64(%%rsp),%%rsi\n\t"
/* 8 bytes of padding for alignment */
- "movaps 72(%%rsp),%%xmm6\n\t"
- "movaps 88(%%rsp),%%xmm7\n\t"
- "movaps 104(%%rsp),%%xmm8\n\t"
- "movaps 120(%%rsp),%%xmm9\n\t"
- "movaps 136(%%rsp),%%xmm10\n\t"
- "movaps 152(%%rsp),%%xmm11\n\t"
- "movaps 168(%%rsp),%%xmm12\n\t"
- "movaps 184(%%rsp),%%xmm13\n\t"
- "movaps 200(%%rsp),%%xmm14\n\t"
- "movaps 216(%%rsp),%%xmm15\n\t"
- /* 8 bytes of padding for alignment */
-#endif
- "addq %1, %%rsp\n\t"
+ "movaps 80(%%rsp),%%xmm6\n\t"
+ "movaps 96(%%rsp),%%xmm7\n\t"
+ "movaps 112(%%rsp),%%xmm8\n\t"
+ "movaps 128(%%rsp),%%xmm9\n\t"
+ "movaps 144(%%rsp),%%xmm10\n\t"
+ "movaps 160(%%rsp),%%xmm11\n\t"
+ "movaps 176(%%rsp),%%xmm12\n\t"
+ "movaps 192(%%rsp),%%xmm13\n\t"
+ "movaps 208(%%rsp),%%xmm14\n\t"
+ "movaps 224(%%rsp),%%xmm15\n\t"
+#endif
+ "movq 48(%%rsp),%%rsp\n\t" /* restore original rsp */
"retq"
:
- : "i"(RESERVED_C_STACK_BYTES),
+ : "i"(RESERVED_C_STACK_BYTES + 8),
"i"(STG_RUN_STACK_FRAME_SIZE /* stack frame size */),
- "i"(RESERVED_C_STACK_BYTES /* rbx relative to cfa (rsp) */),
- "i"(RESERVED_C_STACK_BYTES + 8 /* rbp relative to cfa (rsp) */),
- "i"(RESERVED_C_STACK_BYTES + 16 /* r12 relative to cfa (rsp) */),
- "i"(RESERVED_C_STACK_BYTES + 24 /* r13 relative to cfa (rsp) */),
- "i"(RESERVED_C_STACK_BYTES + 32 /* r14 relative to cfa (rsp) */),
- "i"(RESERVED_C_STACK_BYTES + 40 /* r15 relative to cfa (rsp) */),
- "i"(RESERVED_C_STACK_BYTES + STG_RUN_STACK_FRAME_SIZE
- /* rip relative to cfa */)
+ "i"(RESERVED_C_STACK_BYTES + 8 /* rbx relative to cfa (rsp) */),
+ "i"(RESERVED_C_STACK_BYTES + 16 /* rbp relative to cfa (rsp) */),
+ "i"(RESERVED_C_STACK_BYTES + 24 /* r12 relative to cfa (rsp) */),
+ "i"(RESERVED_C_STACK_BYTES + 32 /* r13 relative to cfa (rsp) */),
+ "i"(RESERVED_C_STACK_BYTES + 40 /* r14 relative to cfa (rsp) */),
+ "i"(RESERVED_C_STACK_BYTES + 48 /* r15 relative to cfa (rsp) */)
#if defined(ENABLE_UNWINDING)
- , "i"((RSP_DELTA & 127) | (128 * ((RSP_DELTA >> 7) > 0)))
+ /* LEB128-encoded offset to saved rsp (RESERVED_C_STACK_BYTES + 56) */
+ , "i"((RSP_DELTA & 127) | (128 * ((RSP_DELTA >> 6) > 0)))
/* signed LEB128-encoded delta from rsp - byte 1 */
-#if (RSP_DELTA >> 7) > 0
- , "i"(((RSP_DELTA >> 7) & 127) | (128 * ((RSP_DELTA >> 14) > 0)))
+#if (RSP_DELTA >> 6) > 0
+ , "i"(((RSP_DELTA >> 7) & 127) | (128 * ((RSP_DELTA >> 13) > 0)))
/* signed LEB128-encoded delta from rsp - byte 2 */
#endif
-
-#if (RSP_DELTA >> 14) > 0
- , "i"(((RSP_DELTA >> 14) & 127) | (128 * ((RSP_DELTA >> 21) > 0)))
+#if (RSP_DELTA >> 13) > 0
+ , "i"(((RSP_DELTA >> 14) & 127) | (128 * ((RSP_DELTA >> 20) > 0)))
/* signed LEB128-encoded delta from rsp - byte 3 */
#endif
-
-#if (RSP_DELTA >> 21) > 0
- , "i"(((RSP_DELTA >> 21) & 127) | (128 * ((RSP_DELTA >> 28) > 0)))
+#if (RSP_DELTA >> 20) > 0
+ , "i"(((RSP_DELTA >> 21) & 127) | (128 * ((RSP_DELTA >> 27) > 0)))
/* signed LEB128-encoded delta from rsp - byte 4 */
#endif
#undef RSP_DELTA
-
#endif /* defined(ENABLE_UNWINDING) */
);
=====================================
rts/include/rts/Constants.h
=====================================
@@ -117,16 +117,14 @@
How large is the stack frame saved by StgRun?
world. Used in StgCRun.c.
- The size has to be enough to save the registers (see StgCRun)
- plus padding if the result is not 16 byte aligned.
- See the Note [Stack Alignment on X86] in StgCRun.c for details.
+ The size has to be enough to save the registers (see StgCRun).
-------------------------------------------------------------------------- */
#if defined(x86_64_HOST_ARCH)
# if defined(mingw32_HOST_OS)
# define STG_RUN_STACK_FRAME_SIZE 240
# else
-# define STG_RUN_STACK_FRAME_SIZE 48
+# define STG_RUN_STACK_FRAME_SIZE 56
# endif
#endif
=====================================
testsuite/tests/simd/should_run/StackAlignment32.hs
=====================================
@@ -0,0 +1,15 @@
+{-# LANGUAGE MagicHash, UnboxedTuples, UnliftedFFITypes #-}
+module StackAlignment32 where
+import GHC.Exts
+
+foreign import ccall unsafe add10 :: DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4# -> DoubleX4#
+
+foo :: Double -> IO ()
+foo (D# x) = do
+ let a = broadcastDoubleX4# x
+ b = packDoubleX4# (# 1.0##, 2.0##, 3.0##, 4.0## #)
+ c = add10 a a a a a a a a a b
+ (# c0, c1, c2, c3 #) = unpackDoubleX4# c
+ print (D# c0, D# c1, D# c2, D# c3)
+
+foreign export ccall foo :: Double -> IO ()
=====================================
testsuite/tests/simd/should_run/StackAlignment32.stdout
=====================================
@@ -0,0 +1,3 @@
+(1.1,2.1,3.1,4.1)
+(2.1,3.1,4.1,5.1)
+(3.2,4.2,5.2,6.2)
=====================================
testsuite/tests/simd/should_run/StackAlignment32_main.c
=====================================
@@ -0,0 +1,42 @@
+#include "HsFFI.h"
+#include <immintrin.h>
+
+extern void foo(double x);
+
+__m256d add10(__m256d a0, __m256d a1, __m256d a2, __m256d a3, __m256d a4, __m256d a5, __m256d a6, __m256d a7, __m256d a8, __m256d a9)
+{
+ // Test whether the stack is 32-byte aligned.
+ // Under the System V ABI, the first eight parameters are passed in registers.
+ // Here, `a8` and `a9` are passed on the stack.
+ // We want the compiler to emit `vmovapd` so we can verify 32-byte stack alignment.
+ // We cannot use `_mm256_add_pd(a0, a9)` because the compiler may fuse the load and
+ // the addition and emit a `vaddpd m256` form, which permits an unaligned load of `a9`.
+ // Therefore, we ensure that both operands are read from the stack,
+ // so that at least one operand is loaded using `vmovapd`.
+ return _mm256_add_pd(a8, a9);
+}
+
+__attribute__((noinline))
+void baz(void)
+{
+ // Make the stack pointer shift by 16 bytes on x86-64
+ foo(2.2);
+}
+
+__attribute__((noinline))
+void bar(void)
+{
+ // Make the stack pointer shift by 16 bytes on x86-64
+ foo(1.1);
+ baz();
+}
+
+int main(int argc, char *argv[])
+{
+ hs_init(&argc, &argv);
+
+ foo(0.1);
+ bar();
+
+ hs_exit();
+}
=====================================
testsuite/tests/simd/should_run/StackAlignment64.hs
=====================================
@@ -0,0 +1,15 @@
+{-# LANGUAGE MagicHash, UnboxedTuples, UnliftedFFITypes #-}
+module StackAlignment64 where
+import GHC.Exts
+
+foreign import ccall unsafe add10 :: DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8# -> DoubleX8#
+
+foo :: Double -> IO ()
+foo (D# x) = do
+ let a = broadcastDoubleX8# x
+ b = packDoubleX8# (# 1.0##, 2.0##, 3.0##, 4.0##, 5.0##, 6.0##, 7.0##, 8.0## #)
+ c = add10 a a a a a a a a a b
+ (# c0, c1, c2, c3, c4, c5, c6, c7 #) = unpackDoubleX8# c
+ print (D# c0, D# c1, D# c2, D# c3, D# c4, D# c5, D# c6, D# c7)
+
+foreign export ccall foo :: Double -> IO ()
=====================================
testsuite/tests/simd/should_run/StackAlignment64.stdout
=====================================
@@ -0,0 +1,3 @@
+(1.1,2.1,3.1,4.1,5.1,6.1,7.1,8.1)
+(2.1,3.1,4.1,5.1,6.1,7.1,8.1,9.1)
+(3.2,4.2,5.2,6.2,7.2,8.2,9.2,10.2)
=====================================
testsuite/tests/simd/should_run/StackAlignment64_main.c
=====================================
@@ -0,0 +1,42 @@
+#include "HsFFI.h"
+#include <immintrin.h>
+
+extern void foo(double x);
+
+__m512d add10(__m512d a0, __m512d a1, __m512d a2, __m512d a3, __m512d a4, __m512d a5, __m512d a6, __m512d a7, __m512d a8, __m512d a9)
+{
+ // Test whether the stack is 64-byte aligned.
+ // Under the System V ABI, the first eight parameters are passed in registers.
+ // Here, `a8` and `a9` are passed on the stack.
+ // We want the compiler to emit `vmovapd` so we can verify 64-byte stack alignment.
+ // We cannot use `_mm512_add_pd(a0, a9)` because the compiler may fuse the load and
+ // the addition and emit a `vaddpd m512` form, which permits an unaligned load of `a9`.
+ // Therefore, we ensure that both operands are read from the stack,
+ // so that at least one operand is loaded using `vmovapd`.
+ return _mm512_add_pd(a8, a9);
+}
+
+__attribute__((noinline))
+void baz(void)
+{
+ // Make the stack pointer shift by 16 bytes on x86-64
+ foo(2.2);
+}
+
+__attribute__((noinline))
+void bar(void)
+{
+ // Make the stack pointer shift by 16 bytes on x86-64
+ foo(1.1);
+ baz();
+}
+
+int main(int argc, char *argv[])
+{
+ hs_init(&argc, &argv);
+
+ foo(0.1);
+ bar();
+
+ hs_exit();
+}
=====================================
testsuite/tests/simd/should_run/all.T
=====================================
@@ -156,7 +156,7 @@ test('T26411b', [], compile_and_run, ['-O'])
# Even if the CPU we run on doesn't support *executing* those tests we should try to
# compile them.
# Currently even for compilation we only support 256+ bit on x86
-only_V32_plus_compilation_support = unless(arch('x86_64'), skip)
+only_V32_plus_compilation_support = unless(arch('x86_64') or arch('i386'), skip)
test('T25062_V32'
, [ extra_hc_opts('-mavx2')
@@ -180,16 +180,15 @@ test('T25486', [], compile_and_run, [''])
test('T26410_ffi'
, [ only_ways(llvm_ways) # SIMD NCG TODO: support 512-bit wide vectors
- , unless(arch('x86_64') and have_cpu_feature('avx512f'), skip)
+ , unless(arch('x86_64') or arch('i386'), skip)
, extra_hc_opts('-mavx512f -optc -mavx512f -optlc -mcpu=penryn')
- , when(opsys('mingw32'), fragile(26595))
]
, compile_and_run if have_cpu_feature('avx512f') else compile
, ['T26410_ffi_c.c'])
test('T26410_prim'
, [ only_ways(llvm_ways) # SIMD NCG TODO: support 512-bit wide vectors
- , unless(arch('x86_64') and have_cpu_feature('avx512f'), skip)
+ , unless(arch('x86_64') or arch('i386'), skip)
, extra_hc_opts('-mavx512f -optlc -mcpu=penryn')
]
, compile_and_run if have_cpu_feature('avx512f') else compile
@@ -197,3 +196,21 @@ test('T26410_prim'
test('FloatConstant', [], compile_and_run, [''])
test('IntConstant', [], compile_and_run, [''])
+
+test('StackAlignment32'
+ , [ only_ways(llvm_ways) # SIMD NCG TODO: support 256-bit wide vectors
+ , unless(arch('x86_64') or arch('i386'), skip)
+ , extra_hc_opts("-mavx -optc -mavx -no-hs-main")
+ ]
+ , compile_and_run if have_cpu_feature('avx') else compile
+ , ['StackAlignment32_main.c']
+ )
+
+test('StackAlignment64'
+ , [ only_ways(llvm_ways) # SIMD NCG TODO: support 512-bit wide vectors
+ , unless(arch('x86_64') or arch('i386'), skip)
+ , extra_hc_opts("-mavx512f -optc -mavx512f -no-hs-main")
+ ]
+ , compile_and_run if have_cpu_feature('avx512f') else compile
+ , ['StackAlignment64_main.c']
+ )
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a5ec467ee3d4e77c026437a54598126…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a5ec467ee3d4e77c026437a54598126…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][master] 2 commits: Check that shift values are valid
by Marge Bot (@marge-bot) 26 Mar '26
by Marge Bot (@marge-bot) 26 Mar '26
26 Mar '26
Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC
Commits:
aa5dfe67 by Sylvain Henry at 2026-03-26T03:48:56-04:00
Check that shift values are valid
In GHC's codebase in non-DEBUG builds we silently substitute shiftL/R
with unsafeShiftL/R for performance reasons. However we were not
checking that the shift value was valid for unsafeShiftL/R, leading to
wrong computations, but only in non-DEBUG builds.
This patch adds the necessary checks and reports an error when a wrong
shift value is passed.
- - - - -
c8a7b588 by Sylvain Henry at 2026-03-26T03:48:56-04:00
Implement basic value range analysis (#25718)
Perform basic value range analysis to try to determine at compile time
the result of the application of some comparison primops (ltWord#, etc.).
This subsumes the built-in rewrite rules used previously to check if one
of the comparison argument was a bound (e.g. (x :: Word8) <= 255 is
always True). Our analysis is more powerful and handles type
conversions: e.g. word8ToWord x <= 255 is now detected as always True too.
We also use value range analysis to filter unreachable alternatives in
case-expressions. To support this, we had to allow case-expressions for
primitive types to not have a DEFAULT alternative (as was assumed before
and checked in Core lint).
- - - - -
24 changed files:
- compiler/GHC/Core.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- + compiler/GHC/Core/Opt/Range.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Prelude/Basic.hs
- compiler/GHC/StgToCmm/Expr.hs
- compiler/GHC/StgToCmm/Utils.hs
- compiler/ghc.cabal.in
- libraries/ghc-internal/src/GHC/Internal/Char.hs
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/simplCore/should_compile/T19166.hs
- + testsuite/tests/simplCore/should_compile/T19166.stderr
- + testsuite/tests/simplCore/should_compile/T25718.hs
- + testsuite/tests/simplCore/should_compile/T25718.stderr
- + testsuite/tests/simplCore/should_compile/T25718a.hs
- + testsuite/tests/simplCore/should_compile/T25718a.stderr
- + testsuite/tests/simplCore/should_compile/T25718b.hs
- + testsuite/tests/simplCore/should_compile/T25718b.stderr
- + testsuite/tests/simplCore/should_compile/T25718c.hs
- + testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-32
- + testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-64
- testsuite/tests/simplCore/should_compile/all.T
Changes:
=====================================
compiler/GHC/Core.hs
=====================================
@@ -4,6 +4,7 @@
-}
{-# LANGUAGE NoPolyKinds #-}
+{-# LANGUAGE LambdaCase #-}
-- | GHC.Core holds all the main data types for use by for the Glasgow Haskell Compiler midsection
module GHC.Core (
@@ -36,7 +37,7 @@ module GHC.Core (
mkBinds,
- isId, cmpAltCon, cmpAlt, ltAlt,
+ isId, cmpAltCon, cmpAlt, ltAlt, altsLevity, CaseLevity(..),
-- ** Simple 'Expr' access functions and predicates
bindersOf, bindersOfBinds, rhssOfBind, rhssOfBinds, rhssOfAlts,
@@ -60,7 +61,7 @@ module GHC.Core (
unSaturatedOk, needSaturated, boringCxtOk, boringCxtNotOk,
-- ** Predicates and deconstruction on 'Unfolding'
- expandUnfolding_maybe,
+ expandUnfolding_maybe, expandUnfolding_always,
maybeUnfoldingTemplate, otherCons,
isValueUnfolding, isEvaldUnfolding, isCheapUnfolding,
isExpandableUnfolding, isConLikeUnfolding, isCompulsoryUnfolding,
@@ -1787,6 +1788,11 @@ expandUnfolding_maybe (CoreUnfolding { uf_cache = cache, uf_tmpl = rhs })
= Just rhs
expandUnfolding_maybe _ = Nothing
+-- Expand an unfolding, ignoring if it is expandable or not
+expandUnfolding_always :: Unfolding -> Maybe CoreExpr
+expandUnfolding_always (CoreUnfolding { uf_tmpl = rhs }) = Just rhs
+expandUnfolding_always _ = Nothing
+
isCompulsoryUnfolding :: Unfolding -> Bool
isCompulsoryUnfolding (CoreUnfolding { uf_src = src }) = isCompulsorySource src
isCompulsoryUnfolding _ = False
@@ -2006,6 +2012,25 @@ cmpAltCon (LitAlt _) DEFAULT = GT
cmpAltCon con1 con2 = pprPanic "cmpAltCon" (ppr con1 $$ ppr con2)
+data CaseLevity
+ = CaseUnlifted
+ | CaseLifted
+ deriving (Eq)
+
+altCon :: Alt a -> AltCon
+altCon (Alt con _ _) = con
+
+-- | Try to determine the levity of a case-expression (unlifted, lifted) from
+-- its alternatives
+altsLevity :: [Alt a] -> Maybe CaseLevity
+altsLevity = alts_levity . fmap altCon
+ where
+ alts_levity = \case
+ [] -> Nothing
+ (DEFAULT:xs) -> alts_levity xs
+ (LitAlt {}:_) -> Just CaseUnlifted
+ (DataAlt {}:_) -> Just CaseLifted
+
{-
************************************************************************
* *
=====================================
compiler/GHC/Core/Lint.hs
=====================================
@@ -1631,16 +1631,21 @@ checkCaseAlts e scrut scrut_ty alts
; checkL (increasing_tag con_alts) (mkNonIncreasingAltsMsg e)
-- See GHC.Core Note [Case expression invariants] item (3)
- -- For types Int#, Word# with an infinite (well, large!) number of
- -- possible values, there should usually be a DEFAULT case
- -- But (see Note [Empty case alternatives] in GHC.Core) it's ok to
- -- have *no* case alternatives.
- -- In effect, this is a kind of partial test. I suppose it's possible
- -- that we might *know* that 'x' was 1 or 2, in which case
- -- case x of { 1 -> e1; 2 -> e2 }
- -- would be fine.
- ; checkL (isJust maybe_deflt || not is_infinite_ty || null alts)
- (nonExhaustiveAltsMsg e)
+ -- Historical note: we used to check that primitive types with a large
+ -- number of possible values (e.g. Int#, Word#...) either had:
+ -- * no alternatives (see Note [Empty case alternatives] in GHC.Core)
+ -- * a DEFAULT alternative
+ -- The rationale was that we can't reasonably enumerate all possible
+ -- alternatives hence the need for a DEFAULT alternative. Moreover
+ -- HsToCore introduces a DEFAULT alternative to raise a pattern-match
+ -- error so there must be at least one.
+ --
+ -- However, since we implemented range analysis (see Note [Value range
+ -- analysis] in GHC.Core.Range), we're filtering unreachable
+ -- alternatives, even the DEFAULT one, so this check is no longer valid.
+ -- E.g. DEFAULT alternative is now removed in:
+ -- case x .&. 1 of { DEFAULT -> ..; 0 -> ..; 1 -> ..}
+ -- even if we're matching an Int#.
-- Check that the scrutinee is not a floating-point type
-- if there are any literal alternatives
@@ -1666,7 +1671,7 @@ checkCaseAlts e scrut scrut_ty alts
_otherwise -> return ()
}
where
- (con_alts, maybe_deflt) = findDefault alts
+ (con_alts, _maybe_deflt) = findDefault alts
-- Check that successive alternatives have strictly increasing tags
increasing_tag (alt1 : rest@( alt2 : _)) = alt1 `ltAlt` alt2 && increasing_tag rest
@@ -1678,10 +1683,6 @@ checkCaseAlts e scrut scrut_ty alts
is_lit_alt (Alt (LitAlt _) _ _) = True
is_lit_alt _ = False
- is_infinite_ty = case tyConAppTyCon_maybe scrut_ty of
- Nothing -> False
- Just tycon -> isPrimTyCon tycon
-
lintAltExpr :: CoreExpr -> OutType -> LintM UsageEnv
lintAltExpr expr ann_ty
= do { (actual_ty, ue) <- lintCoreExpr expr
@@ -3773,10 +3774,6 @@ mkNonDefltMsg e
mkNonIncreasingAltsMsg e
= hang (text "Case expression with badly-ordered alternatives") 4 (ppr e)
-nonExhaustiveAltsMsg :: CoreExpr -> SDoc
-nonExhaustiveAltsMsg e
- = hang (text "Case expression with non-exhaustive alternatives") 4 (ppr e)
-
mkBadConMsg :: TyCon -> DataCon -> SDoc
mkBadConMsg tycon datacon
= vcat [
=====================================
compiler/GHC/Core/Opt/ConstantFold.hs
=====================================
@@ -44,7 +44,7 @@ import GHC.Core
import GHC.Core.Make
import GHC.Core.SimpleOpt ( exprIsConApp_maybe, exprIsLiteral_maybe )
import GHC.Core.DataCon ( DataCon,dataConTagZ, dataConTyCon, dataConWrapId, dataConWorkId )
-import GHC.Core.Utils ( cheapEqExpr, exprIsHNF
+import GHC.Core.Utils ( cheapEqExpr, exprIsHNF, isDefaultAlt
, stripTicksTop, stripTicksTopT, mkTicks )
import GHC.Core.Multiplicity
import GHC.Core.Rules.Config
@@ -54,6 +54,7 @@ import GHC.Core.TyCon
( TyCon, tyConDataCons_maybe, tyConDataCons, tyConSingleDataCon, tyConFamilySize
, isEnumerationTyCon, isValidDTT2TyCon, isNewTyCon )
import GHC.Core.Map.Expr ( eqCoreExpr )
+import GHC.Core.Opt.Range
import GHC.Builtin.PrimOps ( PrimOp(..), tagToEnumKey )
import GHC.Builtin.PrimOps.Ids (primOpId)
@@ -76,6 +77,7 @@ import Data.Functor (($>))
import qualified Data.ByteString as BS
import Data.Ratio
import Data.Word
+import Data.Char (ord)
import Data.Maybe (fromMaybe, fromJust)
{-
@@ -777,60 +779,60 @@ primOpRules nm = \case
-- Relational operators, ordering
- Int8GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Int8GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Int8LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Int8LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- Int16GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Int16GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Int16LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Int16LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- Int32GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Int32GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Int32LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Int32LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- Int64GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Int64GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Int64LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Int64LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- IntGtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- IntGeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- IntLeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- IntLtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- Word8GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Word8GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Word8LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Word8LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- Word16GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Word16GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Word16LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Word16LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- Word32GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Word32GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Word32LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Word32LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- Word64GtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- Word64GeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- Word64LeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- Word64LtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- WordGtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- WordGeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- WordLeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- WordLtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
-
- CharGtOp -> mkRelOpRule nm (>) [ boundsCmp Gt ]
- CharGeOp -> mkRelOpRule nm (>=) [ boundsCmp Ge ]
- CharLeOp -> mkRelOpRule nm (<=) [ boundsCmp Le ]
- CharLtOp -> mkRelOpRule nm (<) [ boundsCmp Lt ]
+ Int8GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeInt8) Gt ]
+ Int8GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeInt8) Ge ]
+ Int8LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeInt8) Le ]
+ Int8LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeInt8) Lt ]
+
+ Int16GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeInt16) Gt ]
+ Int16GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeInt16) Ge ]
+ Int16LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeInt16) Le ]
+ Int16LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeInt16) Lt ]
+
+ Int32GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeInt32) Gt ]
+ Int32GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeInt32) Ge ]
+ Int32LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeInt32) Le ]
+ Int32LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeInt32) Lt ]
+
+ Int64GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeInt64) Gt ]
+ Int64GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeInt64) Ge ]
+ Int64LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeInt64) Le ]
+ Int64LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeInt64) Lt ]
+
+ IntGtOp -> mkRelOpRule nm (>) [ boundsCmp rangeInt Gt ]
+ IntGeOp -> mkRelOpRule nm (>=) [ boundsCmp rangeInt Ge ]
+ IntLeOp -> mkRelOpRule nm (<=) [ boundsCmp rangeInt Le ]
+ IntLtOp -> mkRelOpRule nm (<) [ boundsCmp rangeInt Lt ]
+
+ Word8GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeWord8) Gt ]
+ Word8GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeWord8) Ge ]
+ Word8LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeWord8) Le ]
+ Word8LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeWord8) Lt ]
+
+ Word16GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeWord16) Gt ]
+ Word16GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeWord16) Ge ]
+ Word16LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeWord16) Le ]
+ Word16LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeWord16) Lt ]
+
+ Word32GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeWord32) Gt ]
+ Word32GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeWord32) Ge ]
+ Word32LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeWord32) Le ]
+ Word32LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeWord32) Lt ]
+
+ Word64GtOp -> mkRelOpRule nm (>) [ boundsCmp (const rangeWord64) Gt ]
+ Word64GeOp -> mkRelOpRule nm (>=) [ boundsCmp (const rangeWord64) Ge ]
+ Word64LeOp -> mkRelOpRule nm (<=) [ boundsCmp (const rangeWord64) Le ]
+ Word64LtOp -> mkRelOpRule nm (<) [ boundsCmp (const rangeWord64) Lt ]
+
+ WordGtOp -> mkRelOpRule nm (>) [ boundsCmp rangeWord Gt ]
+ WordGeOp -> mkRelOpRule nm (>=) [ boundsCmp rangeWord Ge ]
+ WordLeOp -> mkRelOpRule nm (<=) [ boundsCmp rangeWord Le ]
+ WordLtOp -> mkRelOpRule nm (<) [ boundsCmp rangeWord Lt ]
+
+ CharGtOp -> mkRelOpRule nm (>) [ boundsCmp rangeChar Gt ]
+ CharGeOp -> mkRelOpRule nm (>=) [ boundsCmp rangeChar Ge ]
+ CharLeOp -> mkRelOpRule nm (<=) [ boundsCmp rangeChar Le ]
+ CharLtOp -> mkRelOpRule nm (<) [ boundsCmp rangeChar Lt ]
FloatGtOp -> mkFloatingRelOpRule nm (>)
FloatGeOp -> mkFloatingRelOpRule nm (>=)
@@ -1401,27 +1403,27 @@ litEq is_eq = msum
| otherwise = trueValInt platform
--- | Check if there is comparison with minBound or maxBound, that is
--- always true or false. For instance, an Int cannot be smaller than its
--- minBound, so we can replace such comparison with False.
-boundsCmp :: Comparison -> RuleM CoreExpr
-boundsCmp op = do
+-- | Perform value range analysis to check if can determine the result
+-- of a comparison statically. For instance, a Word8 converted into a Word is
+-- always smaller than 256.
+boundsCmp :: (Platform -> Range) -> Comparison -> RuleM CoreExpr
+boundsCmp mk_range op = do
platform <- getPlatform
[a, b] <- getArgs
- liftMaybe $ mkRuleFn platform op a b
-
-data Comparison = Gt | Ge | Lt | Le
-
-mkRuleFn :: Platform -> Comparison -> CoreExpr -> CoreExpr -> Maybe CoreExpr
-mkRuleFn platform Gt (Lit lit) _ | isMinBound platform lit = Just $ falseValInt platform
-mkRuleFn platform Le (Lit lit) _ | isMinBound platform lit = Just $ trueValInt platform
-mkRuleFn platform Ge _ (Lit lit) | isMinBound platform lit = Just $ trueValInt platform
-mkRuleFn platform Lt _ (Lit lit) | isMinBound platform lit = Just $ falseValInt platform
-mkRuleFn platform Ge (Lit lit) _ | isMaxBound platform lit = Just $ trueValInt platform
-mkRuleFn platform Lt (Lit lit) _ | isMaxBound platform lit = Just $ falseValInt platform
-mkRuleFn platform Gt _ (Lit lit) | isMaxBound platform lit = Just $ falseValInt platform
-mkRuleFn platform Le _ (Lit lit) | isMaxBound platform lit = Just $ trueValInt platform
-mkRuleFn _ _ _ _ = Nothing
+ let ty_range = mk_range platform
+ liftMaybe $ value_range_cmp platform op ty_range a b
+
+-- | See Note [Value range analysis] in GHC.Core.Opt.Range
+value_range_cmp :: Platform -> Comparison -> Range -> CoreExpr -> CoreExpr -> Maybe CoreExpr
+value_range_cmp platform cmp ty_range x y =
+ let rx = ty_range `rangeIntersect` valueRange platform x
+ ry = ty_range `rangeIntersect` valueRange platform y
+ to_bool = \case
+ Nothing -> Nothing
+ Just True -> Just (trueValInt platform)
+ Just False -> Just (falseValInt platform)
+ res = rangeCmp cmp rx ry
+ in to_bool res
-- | Create an Int literal expression while ensuring the given Integer is in the
-- target Int range
@@ -3188,8 +3190,8 @@ is_binop op e = case e of
is_op :: PrimOp -> CoreExpr -> Maybe (Arg CoreBndr)
is_op op e = case e of
- App (OpVal op') x | op == op' -> Just x
- _ -> Nothing
+ App (PrimOpVar op') x | op == op' -> Just x
+ _ -> Nothing
is_add, is_sub, is_mul, is_and, is_or, is_div :: NumOps -> CoreExpr -> Maybe (CoreArg, CoreArg)
is_add num_ops e = is_binop (numAdd num_ops) e
@@ -3249,12 +3251,12 @@ is_expr_mul num_ops x e = if
-- | Match the application of a binary primop
pattern BinOpApp :: Arg CoreBndr -> PrimOp -> Arg CoreBndr -> CoreExpr
-pattern BinOpApp x op y = OpVal op `App` x `App` y
+pattern BinOpApp x op y = PrimOpVar op `App` x `App` y
-- | Match a primop
-pattern OpVal:: PrimOp -> Arg CoreBndr
-pattern OpVal op <- Var (isPrimOpId_maybe -> Just op) where
- OpVal op = Var (primOpId op)
+pattern PrimOpVar:: PrimOp -> Arg CoreBndr
+pattern PrimOpVar op <- Var (isPrimOpId_maybe -> Just op) where
+ PrimOpVar op = Var (primOpId op)
-- | Match a literal
pattern L :: Integer -> Arg CoreBndr
@@ -3478,11 +3480,12 @@ caseRules _ _ = Nothing
--
-- It's important that occurrence info are present, hence the use of In* types.
caseRules2
- :: InExpr -- ^ Scutinee
- -> InId -- ^ Case-binder
- -> [InAlt] -- ^ Alternatives in standard (increasing) order
+ :: Platform -- ^ Target platform
+ -> InExpr -- ^ Scrutinee
+ -> InId -- ^ Case-binder
+ -> [InAlt] -- ^ Alternatives in standard (increasing) order
-> Maybe (InExpr, InId, [InAlt])
-caseRules2 scrut bndr alts
+caseRules2 platform scrut bndr alts
-- case quotRem# x y of
-- (# q, _ #) -> body
@@ -3507,6 +3510,46 @@ caseRules2 scrut bndr alts
| dead_r -> Just $ (BinOpApp x quot y, q, [Alt DEFAULT [] body])
| otherwise -> Nothing
+ -- filter alternatives that are not in the scrutinee's inferred range
+ -- See (VRA1) in Note [Value range analysis] in GHC.Core.Opt.Range
+ | Just CaseUnlifted <- altsLevity alts
+ , range <- valueRange platform scrut
+ , range /= noRange
+ = let
+ -- filters alternatives that aren't in range
+ alt_in_range = \case
+ Alt DEFAULT _ _ -> True
+ Alt (LitAlt (LitNumber _ n)) _ _ -> n `inRange` range
+ Alt (LitAlt (LitChar c)) _ _ -> fromIntegral (ord c) `inRange` range
+ Alt (LitAlt LitNullAddr) _ _ -> 0 `inRange` range
+ Alt _ _ _ -> True -- defaults to True to be safe
+
+ rebuild_alts alt (b,n,alts')
+ -- `n` is the number of remaining alternatives, hence alternatives which
+ -- are in range. If there are as many alternatives in range as the range
+ -- size, it means we can remove the DEFAULT one (it is dead code).
+ --
+ -- Note that this works as written because we use `foldr` below and the
+ -- DEFAULT alternative is always at the head of the list of alternatives
+ -- when it is present (invariant).
+ | isDefaultAlt alt
+ , Just sz <- rangeSize range
+ , n == sz
+ = (True,n,alts')
+
+ -- filter alternatives that aren't in range
+ | not (alt_in_range alt)
+ = (True,n,alts')
+
+ | otherwise
+ = (b,n+1,alt:alts')
+
+ (alts_changed,_nalts,final_alts) = foldr rebuild_alts (False,0,[]) alts
+
+ in case alts_changed of
+ True -> Just (scrut,bndr,final_alts)
+ False -> Nothing
+
| otherwise
= Nothing
@@ -3678,3 +3721,5 @@ an alternative that is unreachable.
You may wonder how this can happen: check out #15436.
-}
+
+
=====================================
compiler/GHC/Core/Opt/Range.hs
=====================================
@@ -0,0 +1,451 @@
+{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE MultiWayIf #-}
+{-# LANGUAGE CPP #-}
+
+-- | Range analysis
+--
+-- See Note [Value range analysis]
+module GHC.Core.Opt.Range
+ ( Comparison(..)
+ , Range(..)
+ , noRange
+ , valueRange
+ , rangeIntersect
+ , rangeCastFrom
+ , inRange
+ , rangeSize
+ , rangeCmp
+ , rangeLe
+ , rangeGe
+ , rangeLt
+ , rangeGt
+ , rangeOf
+ , rangeWord
+ , rangeWord8
+ , rangeWord16
+ , rangeWord32
+ , rangeWord64
+ , rangeChar
+ , rangeInt
+ , rangeInt8
+ , rangeInt16
+ , rangeInt32
+ , rangeInt64
+ )
+where
+
+import GHC.Prelude
+import GHC.Platform
+import GHC.Core
+import GHC.Builtin.PrimOps ( PrimOp(..) )
+import GHC.Builtin.PrimOps.Ids (primOpId)
+import GHC.Types.Literal
+import GHC.Types.Id
+#if defined(DEBUG)
+import GHC.Utils.Outputable
+import GHC.Utils.Panic
+#endif
+
+import Data.Word
+import Data.Int
+import Data.Char (ord)
+import Data.Maybe
+
+{-
+Note [Value range analysis]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+To perform some constant-folding optimisations, it is sometimes enough to know
+the range (interval) of what an expression will evaluate to. For example,
+consider the following expression:
+
+ word8ToWord x < 256
+
+Even without knowing the value of 'x', we know that:
+
+ - x is in range [0,255] because it is of type Word8
+ - `word8ToWord x` is in range [0,255] despite being of type Word
+ - `word8ToWord x < 256` is always `True`
+
+When a comparison primop is applied to two expressions (e.g. `ltWord# e1 e2`),
+we infer the ranges of `e1` and `e2` and use them to try to statically compute
+the result of the comparison (see `rangeCmp` function in this module).
+
+Value range analysis consists in inferring the range of a CoreExpr.
+ valueRange :: Platform -> CoreExpr -> Range
+is the workhorse function doing this analysis in this module. It traverses a
+CoreExpr recursively to infer a range as precise as possible. It takes into
+account:
+
+ - literals: a literal 'n' implies a range [n,n]
+ - narrowing primops (e.g. Narrow8IntOp)
+ - conversion primops (e.g. WordToIntOp)
+ - addition and subtraction primops (e.g. Word32AddOp)
+ - logical AND primops
+ - variable unfoldings: for example, consider:
+ case word8ToWord# x of y { ... case ltWord# y 256## { ... }}
+ the value range analysis is triggered in a rewrite-rule for ltWord# on
+ both `y` and `256##`. `y` is a variable so the analysis looks into its
+ unfolding (here `word8ToWord# x`) to infer its range. It's obviously only
+ possible when the variable has an unfolding. This unfolding, however, isn't
+ required to be expandable as we're not expanding/inlining the unfolding,
+ just computing its value range.
+
+VRA1: Filtering unreachable alternatives based on range analysis
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Consider the following example:
+
+ case word8ToWord# x of
+ 123456# -> ...
+ ...
+
+By applying value range analysis to the scrutinee, GHC infers that the 123456#
+alternative is unreachable because it's out of the range [0,255] of the
+scrutinee, hence it will never match.
+
+This filtering is done in GHC.Core.Opt.ConstantFold.caseRules2. See also T25718b
+
+
+Limitation 1: no disjoint ranges
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The current implementation doesn't support disjoint ranges hence it can't
+precisely track some ranges. In these cases it falls back to a wider range.
+For example: range analysis for `word8ToInt8 x` where x is in [100,130] would
+need a disjoint range union to be represented as [100,127] U [-128,-126] because
+of the overflow (130 > 127). See `rangeCastFrom` function in this module for the
+implementation.
+
+Similarly, additions and subtractions may overflow/underflow. In these cases, we
+would also need disjoint ranges to represent the resulting range. For example,
+`x+1` where (x :: Word8) and x is in [100,255] would require a disjoint range
+union: [0,0] U [101,255].
+We use `rangeCastFrom` to handle these cases too: e.g. `x+1` (as described
+above) is first computed to be in range [101,256] (ignoring the Word8 type), but
+this range isn't in Word8's range [0,255], so conservatively we assume a range
+[0,255] for `x+1` expression
+
+Limitation 2: limited top-down range information in alternatives
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The value range analysis for a variable currently consists in applying the
+analysis to the variable's unfolding (when it is available). This approach
+doesn't return the most precise range possible in some cases. For example
+consider:
+
+ case x ># 0# of
+ 1# -> {- Here we should know that x's range is > 0 -}
+ 0# -> {- ... and here <= 0 -}
+
+In both alternatives `x`'s unfolding (if any) is the same, yet we should be able
+to infer a different range for `x` as a consequence of the pattern matching on
+the comparison operator application.
+
+Possible future work: we could imagine extending the unfolding information to
+include range information. Then a top-down pass could compute and store more
+precise range information in cases like this one. Implementing this should
+change the output of the T25718a test.
+
+-}
+
+data Comparison = Gt | Ge | Lt | Le deriving (Show)
+
+
+-- | A range (minBound,maxBound)
+--
+-- Bounds may not be known.
+data Range
+ = MkRange {-# UNPACK #-} !(Maybe Integer) -- ^ Lower bound: Nothing means unbounded below
+ {-# UNPACK #-} !(Maybe Integer) -- ^ Upper bound: Nothing means unbounded above
+ deriving (Eq,Show)
+
+pattern Range :: Maybe Integer -> Maybe Integer -> Range
+pattern Range x y <- MkRange x y
+ where
+ Range x y = mkRange x y
+
+{-# COMPLETE Range #-}
+
+mkRange :: Maybe Integer -> Maybe Integer -> Range
+mkRange = \cases
+#if defined(DEBUG)
+ -- check that the bounds of the range are well ordered.
+ (Just x) (Just y) | x > y -> pprPanic "Invalid range" (ppr (x,y))
+#endif
+ x y -> MkRange x y
+
+
+-- | Compute the intersection of two overlapping ranges.
+--
+-- If the two ranges don't overlap, result is undefined.
+rangeIntersect :: Range -> Range -> Range
+rangeIntersect (Range mi1 ma1) (Range mi2 ma2) = Range mi ma
+ where
+ merge op = \cases
+ Nothing Nothing -> Nothing
+ Nothing v -> v
+ v Nothing -> v
+ (Just a) (Just b) -> Just (op a b)
+ mi = merge max mi1 mi2
+ ma = merge min ma1 ma2
+
+-- | Used for casts that share representation over a sub-range (e.g. [0,127] for
+-- Word8# ([0,255]) and Int8# ([-128,127]))
+--
+-- If from_range isn't fully included into to_range, then we return to_range.
+-- That's because for now we don't have a way to track disjoined ranges.
+-- E.g. if we wanted to cast [-1,10] (Int8) into [0,255] (Word8), we would
+-- need to represent a range union: [0,10] U [255,255] (Word8)
+--
+-- We also use this function to ensure that the result of an arithmetic
+-- operation on ranges didn't overflow/underflow.
+rangeCastFrom :: Range -> Range -> Range
+rangeCastFrom to_range from_range = case from_range of
+ Range (Just mi) (Just ma)
+ | mi `inRange` to_range
+ , ma `inRange` to_range
+ -> from_range
+ _ -> to_range
+
+inRange :: Integer -> Range -> Bool
+inRange x = \case
+ Range Nothing Nothing -> True
+ Range (Just mi) Nothing -> x >= mi
+ Range (Just mi) (Just ma) -> x >= mi && x <= ma
+ Range Nothing (Just ma) -> x <= ma
+
+rangeSize :: Range -> Maybe Integer
+rangeSize = \case
+ Range (Just mi) (Just ma) -> Just (ma-mi+1)
+ _ -> Nothing
+
+-- | Addition of two ranges
+rangeAdd :: Range -> Range -> Range
+rangeAdd (Range mi1 ma1) (Range mi2 ma2) = Range (add mi1 mi2) (add ma1 ma2)
+ where
+ add = \cases
+ (Just v) (Just u) -> Just (v+u)
+ _ _ -> Nothing
+
+-- | Subtraction of two ranges
+rangeSub :: Range -> Range -> Range
+rangeSub (Range mi1 ma1) (Range mi2 ma2) = Range (sub mi1 ma2) (sub ma1 mi2)
+ where
+ sub = \cases
+ (Just v) (Just u) -> Just (v-u)
+ _ _ -> Nothing
+
+-- | Logical AND of two ranges at the given type
+{-# NOINLINE rangeAnd #-}
+rangeAnd :: forall a. (FiniteBits a, Bounded a, Integral a) => Range -> Range -> Range
+rangeAnd (Range mi1' ma1') (Range mi2' ma2') = final_range
+ where
+ -- convert the Integer range bounds into the given type with FiniteBits
+ -- because we need to work on the actual representation, not on the Integer
+ -- value. We also take the minBound/maxBound when a bound is missing.
+ mi1, mi2, ma1, ma2 :: a
+ mi1 = fromMaybe minBound (fromInteger <$> mi1')
+ mi2 = fromMaybe minBound (fromInteger <$> mi2')
+ ma1 = fromMaybe maxBound (fromInteger <$> ma1')
+ ma2 = fromMaybe maxBound (fromInteger <$> ma2')
+
+ -- we compute the minimal number of leading zeros for each range.
+ -- Then we take the maximum of both values: this is the number of leading
+ -- bits that will always be set to zero in the resulting range.
+ clz1 = min (countLeadingZeros mi1) (countLeadingZeros ma1)
+ clz2 = min (countLeadingZeros mi2) (countLeadingZeros ma2)
+ clzr = max clz1 clz2
+
+ -- we generate a mask for the bits that might be set to 1 in the resulting
+ -- range and apply it to every bound. It may reorder the bounds: e.g.
+ -- ([-1,1] :: Int8) .&. 0xF ==> [15,1] ==> [1,15]
+ -- so we have to be careful when we reconstruct the final range
+ mask :: a
+ mask = if
+ | clzr == finiteBitSize mi1 -> zeroBits
+ | clzr == 0 -> complement zeroBits
+ | otherwise -> (1 `unsafeShiftL` (finiteBitSize mi1 - clzr)) - 1
+ -- we can't use: complement zeroBits `shiftR` clzr
+ -- because shiftR performs sign-extension for signed types
+ mk_final_bound x = toInteger (x .&. mask)
+
+ fmi1 = mk_final_bound mi1
+ fmi2 = mk_final_bound mi2
+ fma1 = mk_final_bound ma1
+ fma2 = mk_final_bound ma2
+ fmi = fmi1 `min` fmi2 `min` fma1 `min` fma2
+ fma = fmi1 `max` fmi2 `max` fma1 `max` fma2
+ final_range = Range (Just fmi) (Just fma)
+
+
+noRange :: Range
+noRange = Range Nothing Nothing
+
+rangeOf :: forall a. (Bounded a, Integral a) => Range
+rangeOf = Range (Just (toInteger (minBound :: a))) (Just (toInteger (maxBound :: a)))
+
+rangeWord8, rangeWord16, rangeWord32, rangeWord64 :: Range
+rangeWord8 = rangeOf @Word8
+rangeWord16 = rangeOf @Word16
+rangeWord32 = rangeOf @Word32
+rangeWord64 = rangeOf @Word64
+
+rangeInt8, rangeInt16, rangeInt32, rangeInt64 :: Range
+rangeInt8 = rangeOf @Int8
+rangeInt16 = rangeOf @Int16
+rangeInt32 = rangeOf @Int32
+rangeInt64 = rangeOf @Int64
+
+rangeWord, rangeInt, rangeChar :: Platform -> Range
+rangeWord p = case platformWordSize p of
+ PW4 -> rangeWord32
+ PW8 -> rangeWord64
+rangeInt p = case platformWordSize p of
+ PW4 -> rangeInt32
+ PW8 -> rangeInt64
+
+rangeChar = rangeInt -- a Char# is represented internally as an Int#
+
+-- | Compare two ranges
+--
+-- See Note [Value range analysis]
+rangeCmp :: Comparison -> Range -> Range -> Maybe Bool
+rangeCmp cmp rx ry = case cmp of
+ Gt -> rx `rangeGt` ry
+ Ge -> rx `rangeGe` ry
+ Le -> rx `rangeLe` ry
+ Lt -> rx `rangeLt` ry
+
+rangeGt :: Range -> Range -> Maybe Bool
+rangeGt = \cases
+ (Range (Just mi) _) (Range _ (Just ma)) | mi > ma -> Just True
+ (Range _ (Just ma)) (Range (Just mi) _) | ma <= mi -> Just False
+ _ _ -> Nothing
+
+rangeLt :: Range -> Range -> Maybe Bool
+rangeLt = \cases
+ (Range _ (Just ma)) (Range (Just mi) _) | ma < mi -> Just True
+ (Range (Just mi) _) (Range _ (Just ma)) | mi >= ma -> Just False
+ _ _ -> Nothing
+
+rangeGe :: Range -> Range -> Maybe Bool
+rangeGe = \cases
+ (Range (Just mi) _) (Range _ (Just ma)) | mi >= ma -> Just True
+ (Range _ (Just ma)) (Range (Just mi) _) | ma < mi -> Just False
+ _ _ -> Nothing
+
+rangeLe :: Range -> Range -> Maybe Bool
+rangeLe = \cases
+ (Range _ (Just ma)) (Range (Just mi) _) | ma <= mi -> Just True
+ (Range (Just mi) _) (Range _ (Just ma)) | mi > ma -> Just False
+ _ _ -> Nothing
+
+
+-- | Return the Integer range of an expression
+valueRange :: Platform -> CoreExpr -> Range
+valueRange platform = value_range 10
+ where
+ -- we use some fuel value to avoid recursing infinitely
+ value_range :: Word -> CoreExpr -> Range
+ value_range fuel expr
+ | fuel == 0 = noRange
+ | otherwise = case expr of
+ Lit (LitNumber _ n) -> Range (Just n) (Just n)
+ Lit (LitChar c) -> let n = fromIntegral (ord c) in Range (Just n) (Just n)
+ Lit _ -> noRange
+ Var v
+ | Just ebody <- expandUnfolding_always (idUnfolding v)
+ -> value_range (fuel-1) ebody
+ | otherwise
+ -> noRange
+ PrimOpVar op `App` x ->
+ let sub_range = value_range (fuel-1) x
+ in case op of
+ Word8ToWordOp -> rangeWord8 `rangeIntersect` sub_range
+ Word16ToWordOp -> rangeWord16 `rangeIntersect` sub_range
+ Word32ToWordOp -> rangeWord32 `rangeIntersect` sub_range
+ Word64ToWordOp -> rangeWord platform `rangeIntersect` sub_range
+ WordToWord8Op -> rangeWord8 `rangeIntersect` sub_range
+ WordToWord16Op -> rangeWord16 `rangeIntersect` sub_range
+ WordToWord32Op -> rangeWord32 `rangeIntersect` sub_range
+ WordToWord64Op -> rangeWord platform `rangeIntersect` sub_range
+
+ Word8ToInt8Op -> rangeInt8 `rangeCastFrom` (rangeWord8 `rangeIntersect` sub_range)
+ Word16ToInt16Op -> rangeInt16 `rangeCastFrom` (rangeWord16 `rangeIntersect` sub_range)
+ Word32ToInt32Op -> rangeInt32 `rangeCastFrom` (rangeWord32 `rangeIntersect` sub_range)
+ Word64ToInt64Op -> rangeInt64 `rangeCastFrom` (rangeWord64 `rangeIntersect` sub_range)
+ WordToIntOp -> rangeInt platform `rangeCastFrom` (rangeWord platform `rangeIntersect` sub_range)
+
+ Int8ToWord8Op -> rangeWord8 `rangeCastFrom` (rangeInt8 `rangeIntersect` sub_range)
+ Int16ToWord16Op -> rangeWord16 `rangeCastFrom` (rangeInt16 `rangeIntersect` sub_range)
+ Int32ToWord32Op -> rangeWord32 `rangeCastFrom` (rangeInt32 `rangeIntersect` sub_range)
+ Int64ToWord64Op -> rangeWord64 `rangeCastFrom` (rangeInt64 `rangeIntersect` sub_range)
+ IntToWordOp -> rangeWord platform `rangeCastFrom` (rangeInt platform `rangeIntersect` sub_range)
+
+ Narrow8IntOp -> rangeInt8 `rangeIntersect` sub_range
+ Narrow16IntOp -> rangeInt16 `rangeIntersect` sub_range
+ Narrow32IntOp -> rangeInt32 `rangeIntersect` sub_range
+ Narrow8WordOp -> rangeWord8 `rangeIntersect` sub_range
+ Narrow16WordOp -> rangeWord16 `rangeIntersect` sub_range
+ Narrow32WordOp -> rangeWord32 `rangeIntersect` sub_range
+
+ OrdOp -> sub_range
+ ChrOp -> sub_range
+
+ _ -> noRange
+
+ PrimOpVar op `App` x `App` y ->
+ let range_x = value_range (fuel-1) x
+ range_y = value_range (fuel-1) y
+ in case op of
+ Word8AddOp -> rangeWord8 `rangeCastFrom` rangeAdd range_x range_y
+ Word16AddOp -> rangeWord16 `rangeCastFrom` rangeAdd range_x range_y
+ Word32AddOp -> rangeWord32 `rangeCastFrom` rangeAdd range_x range_y
+ Word64AddOp -> rangeWord64 `rangeCastFrom` rangeAdd range_x range_y
+ WordAddOp -> rangeWord platform `rangeCastFrom` rangeAdd range_x range_y
+ Int8AddOp -> rangeInt8 `rangeCastFrom` rangeAdd range_x range_y
+ Int16AddOp -> rangeInt16 `rangeCastFrom` rangeAdd range_x range_y
+ Int32AddOp -> rangeInt32 `rangeCastFrom` rangeAdd range_x range_y
+ Int64AddOp -> rangeInt64 `rangeCastFrom` rangeAdd range_x range_y
+ IntAddOp -> rangeInt platform `rangeCastFrom` rangeAdd range_x range_y
+
+ Word8SubOp -> rangeWord8 `rangeCastFrom` rangeSub range_x range_y
+ Word16SubOp -> rangeWord16 `rangeCastFrom` rangeSub range_x range_y
+ Word32SubOp -> rangeWord32 `rangeCastFrom` rangeSub range_x range_y
+ Word64SubOp -> rangeWord64 `rangeCastFrom` rangeSub range_x range_y
+ WordSubOp -> rangeWord platform `rangeCastFrom` rangeSub range_x range_y
+ Int8SubOp -> rangeInt8 `rangeCastFrom` rangeSub range_x range_y
+ Int16SubOp -> rangeInt16 `rangeCastFrom` rangeSub range_x range_y
+ Int32SubOp -> rangeInt32 `rangeCastFrom` rangeSub range_x range_y
+ Int64SubOp -> rangeInt64 `rangeCastFrom` rangeSub range_x range_y
+ IntSubOp -> rangeInt platform `rangeCastFrom` rangeSub range_x range_y
+
+ IntAndOp -> case platformWordSize platform of
+ PW4 -> rangeAnd @Int32 range_x range_y
+ PW8 -> rangeAnd @Int64 range_x range_y
+ WordAndOp -> case platformWordSize platform of
+ PW4 -> rangeAnd @Word32 range_x range_y
+ PW8 -> rangeAnd @Word64 range_x range_y
+ Word8AndOp -> rangeAnd @Word8 range_x range_y
+ Word16AndOp -> rangeAnd @Word16 range_x range_y
+ Word32AndOp -> rangeAnd @Word32 range_x range_y
+ Word64AndOp -> rangeAnd @Word64 range_x range_y
+
+ -- TODO: shifts, or, clz, ctz, negate...
+ _ -> noRange
+
+ App {} -> noRange
+ Lam {} -> noRange
+ Let {} -> noRange
+ Case {} -> noRange
+ Cast e _ -> value_range fuel e
+ Tick _ e -> value_range fuel e
+ Type {} -> noRange
+ Coercion {} -> noRange
+
+-- | Match a primop
+pattern PrimOpVar:: PrimOp -> Arg CoreBndr
+pattern PrimOpVar op <- Var (isPrimOpId_maybe -> Just op) where
+ PrimOpVar op = Var (primOpId op)
+
=====================================
compiler/GHC/Core/Opt/Simplify/Iteration.hs
=====================================
@@ -3232,18 +3232,19 @@ rebuildCase env scrut case_bndr alts@[Alt _ bndrs rhs] cont
Just (rule_rhs, cont') -> simplExprF (zapSubstEnv env) rule_rhs cont'
Nothing -> reallyRebuildCase env scrut case_bndr alts cont }
+ where
+ all_dead_bndrs = all isDeadBinder bndrs -- bndrs are [InId]
+ is_plain_seq = all_dead_bndrs && isDeadBinder case_bndr -- Evaluation *only* for effect
+
+rebuildCase env scrut case_bndr alts cont
--------------------------------------------------
-- 3. Primop-related case-rules
--------------------------------------------------
- |Just (scrut', case_bndr', alts') <- caseRules2 scrut case_bndr alts
+ | Just (scrut', case_bndr', alts') <- caseRules2 (sePlatform env) scrut case_bndr alts
= reallyRebuildCase env scrut' case_bndr' alts' cont
- where
- all_dead_bndrs = all isDeadBinder bndrs -- bndrs are [InId]
- is_plain_seq = all_dead_bndrs && isDeadBinder case_bndr -- Evaluation *only* for effect
-
-rebuildCase env scrut case_bndr alts cont
+ | otherwise
= reallyRebuildCase env scrut case_bndr alts cont
doCaseToLet :: OutExpr -- Scrutinee
=====================================
compiler/GHC/Prelude/Basic.hs
=====================================
@@ -68,9 +68,6 @@ import qualified GHC.Data.List.NonEmpty as NE
import GHC.Stack.Types (HasCallStack)
import GHC.Bits as Bits hiding (bit, shiftL, shiftR, setBit, clearBit)
-# if defined(DEBUG)
-import qualified GHC.Bits as Bits (shiftL, shiftR)
-# endif
{- Note [Default to unsafe shifts inside GHC]
@@ -99,11 +96,29 @@ See also #19618
-- We always want the Data.Bits method to show up for rules etc.
{-# INLINE shiftL #-}
{-# INLINE shiftR #-}
-shiftL, shiftR :: Bits.Bits a => a -> Int -> a
#if defined(DEBUG)
-shiftL = Bits.shiftL
-shiftR = Bits.shiftR
+-- In debug mode we explicitly check that the shift value is valid for
+-- unsafeShiftL/R. Otherwise we may have bugs only showing up in non-DEBUG
+-- builds.
+shiftL, shiftR :: (HasCallStack, Bits.Bits a) => a -> Int -> a
+shiftL x n
+ | n < 0
+ = error ("shiftL: negative shift value: " ++ show n)
+ | Just s <- bitSizeMaybe x
+ , n >= s
+ = error ("shiftL: shift value greater than bitSize: " ++ show n ++ " >= " ++ show s)
+ | otherwise
+ = Bits.unsafeShiftL x n
+shiftR x n
+ | n < 0
+ = error ("shiftR: negative shift value: " ++ show n)
+ | Just s <- bitSizeMaybe x
+ , n >= s
+ = error ("shiftR: shift value greater than bitSize: " ++ show n ++ " >= " ++ show s)
+ | otherwise
+ = Bits.unsafeShiftR x n
#else
+shiftL, shiftR :: Bits.Bits a => a -> Int -> a
shiftL = Bits.unsafeShiftL
shiftR = Bits.unsafeShiftR
#endif
=====================================
compiler/GHC/StgToCmm/Expr.hs
=====================================
@@ -729,15 +729,13 @@ cgAlts gc_plan bndr (PrimAlt _) alts
; tagged_cmms <- cgAltRhss gc_plan bndr alts
; let bndr_reg = CmmLocal (idToReg platform bndr)
- deflt = case tagged_cmms of
- (DEFAULT,deflt):_ -> deflt
- _ -> panic "cgAlts PrimAlt"
- -- PrimAlts always have a DEFAULT case
- -- and it always comes first
+ mdeflt = case tagged_cmms of
+ (DEFAULT,deflt):_ -> Just deflt
+ _ -> Nothing
tagged_cmms' = [(lit,code)
| (LitAlt lit, code) <- tagged_cmms]
- ; emitCmmLitSwitch (CmmReg bndr_reg) tagged_cmms' deflt
+ ; emitCmmLitSwitch (CmmReg bndr_reg) tagged_cmms' mdeflt
; return AssignedDirectly }
cgAlts gc_plan bndr (AlgAlt tycon) alts
=====================================
compiler/GHC/StgToCmm/Utils.hs
=====================================
@@ -478,41 +478,49 @@ divideBranches branches = (lo_branches, mid, hi_branches)
--------------
emitCmmLitSwitch :: CmmExpr -- Tag to switch on
-> [(Literal, CmmAGraphScoped)] -- Tagged branches
- -> CmmAGraphScoped -- Default branch (always)
+ -> Maybe CmmAGraphScoped -- Default branch
-> FCode () -- Emit the code
-emitCmmLitSwitch _scrut [] deflt = emit $ fst deflt
-emitCmmLitSwitch scrut branches@(branch:_) deflt = do
+emitCmmLitSwitch _scrut [] (Just deflt) = emit $ fst deflt
+emitCmmLitSwitch _scrut [] Nothing = panic "emitCmmLitSwitch: expected DEFAULT branch (no alts)"
+emitCmmLitSwitch scrut branches@(branch:_) mdeflt = do
scrut' <- assignTemp' scrut
join_lbl <- newBlockId
- deflt_lbl <- label_code join_lbl deflt
branches_lbls <- label_branches join_lbl branches
platform <- getPlatform
let cmm_ty = cmmExprType platform scrut
rep = typeWidth cmm_ty
- -- We find the necessary type information in the literals in the branches
- let (signed,range) = case branch of
- (LitNumber nt _, _) -> (signed,range)
- where
- signed = litNumIsSigned nt
- range = case litNumRange platform nt of
- (Just mi, Just ma) -> (mi,ma)
- -- unbounded literals (Natural and
- -- Integer) must have been
- -- lowered at this point
- partial_bounds -> pprPanic "Unexpected unbounded literal range"
- (ppr partial_bounds)
- -- assuming native word range
- _ -> (False, (0, platformMaxWord platform))
-
if isFloatType cmm_ty
- then emit =<< mk_float_switch rep scrut' deflt_lbl noBound branches_lbls
- else emit $ mk_discrete_switch
+ then do
+ deflt_lbl <- case mdeflt of
+ Nothing -> panic "emitCmmLitSwitch: expected DEFAULT branch (float switch)"
+ Just deflt -> label_code join_lbl deflt
+ emit =<< mk_float_switch rep scrut' deflt_lbl noBound branches_lbls
+ else do
+ -- We find the necessary type information in the literals in the branches
+ let (signed,range) = case branch of
+ (LitNumber nt _, _) -> (signed,range)
+ where
+ signed = litNumIsSigned nt
+ range = case litNumRange platform nt of
+ (Just mi, Just ma) -> (mi,ma)
+ -- unbounded literals (Natural and
+ -- Integer) must have been
+ -- lowered at this point
+ partial_bounds -> pprPanic "Unexpected unbounded literal range"
+ (ppr partial_bounds)
+ -- assuming native word range
+ _ -> (False, (0, platformMaxWord platform))
+
+ mdeflt_lbl <- case mdeflt of
+ Nothing -> pure Nothing
+ Just deflt -> Just <$> label_code join_lbl deflt
+ emit $ mk_discrete_switch
signed
scrut'
[(litValue lit,l) | (lit,l) <- branches_lbls]
- (Just deflt_lbl)
+ mdeflt_lbl
range
emitLabel join_lbl
=====================================
compiler/ghc.cabal.in
=====================================
@@ -384,6 +384,7 @@ Library
GHC.Core.Opt.OccurAnal
GHC.Core.Opt.Pipeline
GHC.Core.Opt.Pipeline.Types
+ GHC.Core.Opt.Range
GHC.Core.Opt.SetLevels
GHC.Core.Opt.Simplify
GHC.Core.Opt.Simplify.Env
=====================================
libraries/ghc-internal/src/GHC/Internal/Char.hs
=====================================
@@ -14,13 +14,19 @@ import GHC.Internal.Classes (eqChar, neChar)
import GHC.Internal.Base (otherwise, (++))
import GHC.Internal.Err (errorWithoutStackTrace)
import GHC.Internal.Show
-import GHC.Internal.Prim (chr#, int2Word#, leWord#)
+import GHC.Internal.Prim (chr#, int2Word#, leWord#, Int#, Char#)
import GHC.Internal.Types (Char(..), Int(..), isTrue#)
-- | The 'Prelude.toEnum' method restricted to the type 'Data.Char.Char'.
chr :: Int -> Char
-chr i@(I# i#)
- | isTrue# (int2Word# i# `leWord#` 0x10FFFF##) = C# (chr# i#)
- | otherwise
- = errorWithoutStackTrace ("Prelude.chr: bad argument: " ++ showSignedInt (I# 9#) i "")
+chr (I# i#) = C# (safe_chr# i#)
+{-# INLINABLE safe_chr# #-}
+safe_chr# :: Int# -> Char#
+safe_chr# i#
+ | isTrue# (int2Word# i# `leWord#` 0x10FFFF##) = chr# i#
+ | otherwise = chr_error i#
+
+{-# NOINLINE chr_error #-}
+chr_error :: Int# -> Char#
+chr_error i# = errorWithoutStackTrace ("Prelude.chr: bad argument: " ++ showSignedInt (I# 9#) (I# i#) "")
=====================================
testsuite/tests/count-deps/CountDepsAst.stdout
=====================================
@@ -30,6 +30,7 @@ GHC.Core.Opt.Arity
GHC.Core.Opt.CallerCC.Types
GHC.Core.Opt.ConstantFold
GHC.Core.Opt.OccurAnal
+GHC.Core.Opt.Range
GHC.Core.PatSyn
GHC.Core.Ppr
GHC.Core.Predicate
=====================================
testsuite/tests/count-deps/CountDepsParser.stdout
=====================================
@@ -30,6 +30,7 @@ GHC.Core.Opt.Arity
GHC.Core.Opt.CallerCC.Types
GHC.Core.Opt.ConstantFold
GHC.Core.Opt.OccurAnal
+GHC.Core.Opt.Range
GHC.Core.PatSyn
GHC.Core.Ppr
GHC.Core.Predicate
=====================================
testsuite/tests/simplCore/should_compile/T19166.hs
=====================================
@@ -0,0 +1,12 @@
+module T19166 where
+
+import Data.Bits
+
+foo :: Int -> Int
+foo x = case x .&. 0x3 of
+ 0 -> 0
+ 1 -> 1
+ 2 -> 2
+ 3 -> 3
+ 4 -> 4 -- unreachable branch but not removed
+ _ -> undefined -- required for the PM checker but unreachable too
=====================================
testsuite/tests/simplCore/should_compile/T19166.stderr
=====================================
@@ -0,0 +1,26 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 29, types: 10, coercions: 0, joins: 0/0}
+
+foo4 = I# 0#
+
+foo3 = I# 1#
+
+foo2 = I# 2#
+
+foo1 = I# 3#
+
+foo
+ = \ x ->
+ case x of { I# x# ->
+ case andI# x# 3# of {
+ 0# -> foo4;
+ 1# -> foo3;
+ 2# -> foo2;
+ 3# -> foo1
+ }
+ }
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/T25718.hs
=====================================
@@ -0,0 +1,16 @@
+module T25718 where
+
+import Data.Char
+import Data.Word
+
+word8ToChar :: Word8 -> Char
+word8ToChar = chr . fromIntegral
+
+isAsciiChar :: Char -> Bool
+isAsciiChar = (< 256) . ord
+
+foo :: Word8 -> Bool
+foo = isAsciiChar . word8ToChar
+
+bar :: Word8 -> Bool
+bar x = fromIntegral x <= 255
=====================================
testsuite/tests/simplCore/should_compile/T25718.stderr
=====================================
@@ -0,0 +1,18 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 28, types: 18, coercions: 0, joins: 0/0}
+
+isAsciiChar
+ = \ x -> case x of { C# c# -> tagToEnum# (<# (ord# c#) 256#) }
+
+bar = \ x -> case x of { W8# x# -> True }
+
+word8ToChar
+ = \ x ->
+ case x of { W8# x# -> C# (chr# (word2Int# (word8ToWord# x#))) }
+
+foo = bar
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/T25718a.hs
=====================================
@@ -0,0 +1,13 @@
+{-# LANGUAGE MagicHash #-}
+module T25718a where
+
+import GHC.Exts
+
+-- Test a limitation of range analysis: if we improve the analysis, it could
+-- become a constant function `\_ -> True`
+foo :: Int# -> Bool
+foo x = case isTrue# (x ># 0#) of
+ True -> {- Here we should know that x's range is > 0 -}
+ not (isTrue# (x <=# 0#)) -- we write it this way to avoid CSE for `x ># 0#` to kick in
+ False -> {- ... and here <= 0 -}
+ isTrue# (x <=# 0#)
=====================================
testsuite/tests/simplCore/should_compile/T25718a.stderr
=====================================
@@ -0,0 +1,18 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 20, types: 6, coercions: 0, joins: 0/0}
+
+foo
+ = \ x ->
+ case ># x 0# of {
+ __DEFAULT -> tagToEnum# (<=# x 0#);
+ 1# ->
+ case <=# x 0# of {
+ __DEFAULT -> True;
+ 1# -> False
+ }
+ }
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/T25718b.hs
=====================================
@@ -0,0 +1,21 @@
+{-# LANGUAGE MagicHash #-}
+module T25718a where
+
+import GHC.Exts
+
+-- Test that value range analysis is used to remove unreachable alternatives
+
+foo :: Word8# -> Bool
+foo x = case word8ToWord# x of
+ 123456## -> False
+ 456789## -> False
+ 42## -> False
+ _ -> True
+
+bar :: Word# -> Bool
+bar x = case x `and#` 0xF## of
+ 123456## -> False
+ 456789## -> False
+ 0xF0## -> False
+ 0x05## -> False
+ _ -> True
=====================================
testsuite/tests/simplCore/should_compile/T25718b.stderr
=====================================
@@ -0,0 +1,21 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 19, types: 8, coercions: 0, joins: 0/0}
+
+foo
+ = \ x ->
+ case word8ToWord# x of {
+ __DEFAULT -> True;
+ 42## -> False
+ }
+
+bar
+ = \ x ->
+ case and# x 15## of {
+ __DEFAULT -> True;
+ 5## -> False
+ }
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/T25718c.hs
=====================================
@@ -0,0 +1,261 @@
+{-# LANGUAGE CPP, MagicHash #-}
+module T25718c where
+
+#include "MachDeps.h"
+
+import GHC.Exts
+
+-- Test that value range analysis handles all conversion/narrow/arithmetic primops.
+-- Each section tests a different op from `valueRange` in GHC.Core.Opt.Range.
+--
+-- Already tested in T25718/T25718b: Word8ToWordOp, WordAndOp.
+-- Here we test the remaining ops:
+--
+-- (1) Narrow8IntOp (narrow8Int#): result in Int8 range [-128, 127]
+-- (2) Narrow16IntOp (narrow16Int#): result in Int16 range [-32768,32767]
+-- (3) Narrow8WordOp (narrow8Word#): result in Word8 range [0, 255]
+-- (4) Narrow16WordOp (narrow16Word#):result in Word16 range [0, 65535]
+-- (5) Word16ToWordOp (word16ToWord#):result in Word16 range [0, 65535]
+-- (6) WordToWord8Op (wordToWord8#): result in Word8 range [0, 255]
+-- (7) WordToWord16Op (wordToWord16#):result in Word16 range [0, 65535]
+-- (8) Word8ToInt8Op (word8ToInt8#): rangeCastFrom -> Int8 range [-128, 127]
+-- (9) Word16ToInt16Op(word16ToInt16#):rangeCastFrom -> Int16 range [-32768,32767]
+-- (10) Int8ToWord8Op (int8ToWord8#): rangeCastFrom -> Word8 range [0, 255]
+-- (11) Int16ToWord16Op(int16ToWord16#):rangeCastFrom -> Word16 range [0, 65535]
+-- (12) Word8AddOp (plusWord8#): rangeCastFrom fallback -> Word8 range [0, 255]
+-- (13) VRA1 for Word16 (unreachable alt removal)
+-- (14) VRA1 for narrow8Int# (unreachable alt removal)
+-- (15) Word8SubOp (subWord8#): result in Word8 range [0, 255]
+-- (16) Word16AddOp (plusWord16#):result in Word16 range [0, 65535]
+-- (17) Word16SubOp (subWord16#): result in Word16 range [0, 65535]
+-- (18) Int8AddOp (plusInt8#): result in Int8 range [-128, 127]
+-- (19) Int8SubOp (subInt8#): result in Int8 range [-128, 127]
+-- (20) Int16AddOp (plusInt16#): result in Int16 range [-32768,32767]
+-- (21) Int16SubOp (subInt16#): result in Int16 range [-32768,32767]
+-- (22) Narrow32IntOp (narrow32Int#): result in Int32 range [-2147483648,2147483647]
+-- (23) Word32ToInt32Op (word32ToInt32#): rangeCastFrom -> Int32 range [-2147483648,2147483647]
+-- (24) Int32ToWord32Op (int32ToWord32#): rangeCastFrom -> Word32 range [0,4294967295]
+-- (25) Int32AddOp (plusInt32#): result in Int32 range [-2147483648,2147483647]
+-- (26) Int32SubOp (subInt32#): result in Int32 range [-2147483648,2147483647]
+-- (27) Word8AndOp (andWord8#): rangeAnd -> [0, mask]
+-- (28) Word16AndOp (andWord16#): rangeAnd -> [0, mask]
+-- (29) Word32AndOp (andWord32#): rangeAnd -> [0, mask]
+-- (30) Word64AndOp (and64#): rangeAnd -> [0, mask]
+-- (31) IntAndOp (andI#): rangeAnd -> [0, mask]
+-- Sections (32)-(38) require 64-bit literals; guarded with CPP:
+-- (32) Narrow32WordOp (narrow32Word#): on 64-bit, result in Word32 range [0,4294967295]
+-- (33) Word32ToWordOp (word32ToWord#): on 64-bit, result in Word32 range [0,4294967295]
+-- (34) WordToWord32Op (wordToWord32#): on 64-bit, composed chain in [0,4294967295]
+-- (35) Word32AddOp (plusWord32#): on 64-bit, result in Word32 range [0,4294967295]
+-- (36) Word32SubOp (subWord32#): on 64-bit, result in Word32 range [0,4294967295]
+-- (37) VRA1 for narrow32Int# (unreachable alts > 2147483647)
+-- (38) VRA1 for word32ToWord# (unreachable alts > 4294967295)
+
+-- (1) Narrow8IntOp: narrow8Int# x is always in [-128, 127]
+narrow8_ge_lb :: Int# -> Bool
+narrow8_ge_lb x = isTrue# (narrow8Int# x >=# -128#) -- True
+
+narrow8_le_ub :: Int# -> Bool
+narrow8_le_ub x = isTrue# (narrow8Int# x <=# 127#) -- True
+
+narrow8_gt_ub_false :: Int# -> Bool
+narrow8_gt_ub_false x = isTrue# (narrow8Int# x >=# 128#) -- False
+
+-- (2) Narrow16IntOp: narrow16Int# x is always in [-32768, 32767]
+narrow16_ge_lb :: Int# -> Bool
+narrow16_ge_lb x = isTrue# (narrow16Int# x >=# -32768#) -- True
+
+narrow16_le_ub :: Int# -> Bool
+narrow16_le_ub x = isTrue# (narrow16Int# x <=# 32767#) -- True
+
+-- (3) Narrow8WordOp: narrow8Word# x is always in [0, 255]
+narrow8w_lt_ub :: Word# -> Bool
+narrow8w_lt_ub x = isTrue# (narrow8Word# x `ltWord#` 256##) -- True
+
+-- (4) Narrow16WordOp: narrow16Word# x is always in [0, 65535]
+narrow16w_lt_ub :: Word# -> Bool
+narrow16w_lt_ub x = isTrue# (narrow16Word# x `ltWord#` 65536##) -- True
+
+-- (5) Word16ToWordOp: word16ToWord# x is always in [0, 65535]
+word16_lt_ub :: Word16# -> Bool
+word16_lt_ub x = isTrue# (word16ToWord# x `ltWord#` 65536##) -- True
+
+word16_ge_ub_false :: Word16# -> Bool
+word16_ge_ub_false x = isTrue# (word16ToWord# x `geWord#` 65536##) -- False
+
+-- (6) WordToWord8Op: word8ToWord# (wordToWord8# x) is in [0, 255]
+word_to_word8_lt :: Word# -> Bool
+word_to_word8_lt x = isTrue# (word8ToWord# (wordToWord8# x) `ltWord#` 256##) -- True
+
+-- (7) WordToWord16Op: word16ToWord# (wordToWord16# x) is in [0, 65535]
+word_to_word16_lt :: Word# -> Bool
+word_to_word16_lt x = isTrue# (word16ToWord# (wordToWord16# x) `ltWord#` 65536##) -- True
+
+-- (8) Word8ToInt8Op: word8ToInt8# x has range Int8 [-128, 127] (via rangeCastFrom)
+word8_to_int8_ge :: Word8# -> Bool
+word8_to_int8_ge x = isTrue# (geInt8# (word8ToInt8# x) (intToInt8# -128#)) -- True
+
+-- (9) Word16ToInt16Op: word16ToInt16# x has range Int16 [-32768, 32767]
+word16_to_int16_ge :: Word16# -> Bool
+word16_to_int16_ge x = isTrue# (geInt16# (word16ToInt16# x) (intToInt16# -32768#)) -- True
+
+-- (10) Int8ToWord8Op: int8ToWord8# x has range Word8 [0, 255] (via rangeCastFrom)
+int8_to_word8_le :: Int8# -> Bool
+int8_to_word8_le x = isTrue# (leWord8# (int8ToWord8# x) (wordToWord8# 255##)) -- True
+
+-- (11) Int16ToWord16Op: int16ToWord16# x has range Word16 [0, 65535]
+int16_to_word16_le :: Int16# -> Bool
+int16_to_word16_le x = isTrue# (leWord16# (int16ToWord16# x) (wordToWord16# 65535##)) -- True
+
+-- (12) Word8AddOp: plusWord8# result stays in [0, 255] (rangeCastFrom fallback)
+word8_add_lt_256 :: Word8# -> Word8# -> Bool
+word8_add_lt_256 x y = isTrue# (word8ToWord# (plusWord8# x y) `ltWord#` 256##) -- True
+
+-- (13) VRA1: unreachable alts for Word16 range [0, 65535]
+word16_alts :: Word16# -> Bool
+word16_alts x = case word16ToWord# x of
+ 100000## -> False -- unreachable: 100000 > 65535
+ 65536## -> False -- unreachable: 65536 > 65535
+ 42## -> False -- reachable
+ _ -> True
+
+-- (14) VRA1: unreachable alts for narrow8Int# range [-128, 127]
+narrow8_alts :: Int# -> Bool
+narrow8_alts x = case narrow8Int# x of
+ 200# -> False -- unreachable: 200 > 127
+ 128# -> False -- unreachable: 128 > 127
+ 42# -> False -- reachable
+ _ -> True
+
+-- (15) Word8SubOp: subWord8# result stays in [0, 255]
+word8_sub_lt_256 :: Word8# -> Word8# -> Bool
+word8_sub_lt_256 x y = isTrue# (word8ToWord# (subWord8# x y) `ltWord#` 256##) -- True
+
+-- (16) Word16AddOp: plusWord16# result stays in [0, 65535]
+word16_add_lt_ub :: Word16# -> Word16# -> Bool
+word16_add_lt_ub x y = isTrue# (word16ToWord# (plusWord16# x y) `ltWord#` 65536##) -- True
+
+-- (17) Word16SubOp: subWord16# result stays in [0, 65535]
+word16_sub_lt_ub :: Word16# -> Word16# -> Bool
+word16_sub_lt_ub x y = isTrue# (word16ToWord# (subWord16# x y) `ltWord#` 65536##) -- True
+
+-- (18) Int8AddOp: plusInt8# result stays in [-128, 127]
+int8_add_ge_lb :: Int8# -> Int8# -> Bool
+int8_add_ge_lb x y = isTrue# (geInt8# (plusInt8# x y) (intToInt8# -128#)) -- True
+
+-- (19) Int8SubOp: subInt8# result stays in [-128, 127]
+int8_sub_le_ub :: Int8# -> Int8# -> Bool
+int8_sub_le_ub x y = isTrue# (leInt8# (subInt8# x y) (intToInt8# 127#)) -- True
+
+-- (20) Int16AddOp: plusInt16# result stays in [-32768, 32767]
+int16_add_ge_lb :: Int16# -> Int16# -> Bool
+int16_add_ge_lb x y = isTrue# (geInt16# (plusInt16# x y) (intToInt16# -32768#)) -- True
+
+-- (21) Int16SubOp: subInt16# result stays in [-32768, 32767]
+int16_sub_le_ub :: Int16# -> Int16# -> Bool
+int16_sub_le_ub x y = isTrue# (leInt16# (subInt16# x y) (intToInt16# 32767#)) -- True
+
+-- (22) Narrow32IntOp: narrow32Int# result stays in [-2147483648, 2147483647]
+-- (literals fit on 32-bit: -2147483648 = minInt32, 2147483647 = maxInt32)
+narrow32_ge_lb :: Int# -> Bool
+narrow32_ge_lb x = isTrue# (narrow32Int# x >=# -2147483648#) -- True
+
+narrow32_le_ub :: Int# -> Bool
+narrow32_le_ub x = isTrue# (narrow32Int# x <=# 2147483647#) -- True
+
+-- (23) Word32ToInt32Op: word32ToInt32# result has range Int32 [-2147483648, 2147483647]
+word32_to_int32_ge :: Word32# -> Bool
+word32_to_int32_ge x = isTrue# (geInt32# (word32ToInt32# x) (intToInt32# -2147483648#)) -- True
+
+-- (24) Int32ToWord32Op: int32ToWord32# result has range Word32 [0, 4294967295]
+-- (4294967295## = maxWord32 = maxWord on 32-bit, valid literal on any platform)
+int32_to_word32_le :: Int32# -> Bool
+int32_to_word32_le x = isTrue# (leWord32# (int32ToWord32# x) (wordToWord32# 4294967295##)) -- True
+
+-- (25) Int32AddOp: plusInt32# result stays in [-2147483648, 2147483647]
+int32_add_ge_lb :: Int32# -> Int32# -> Bool
+int32_add_ge_lb x y = isTrue# (geInt32# (plusInt32# x y) (intToInt32# -2147483648#)) -- True
+
+-- (26) Int32SubOp: subInt32# result stays in [-2147483648, 2147483647]
+int32_sub_le_ub :: Int32# -> Int32# -> Bool
+int32_sub_le_ub x y = isTrue# (leInt32# (subInt32# x y) (intToInt32# 2147483647#)) -- True
+
+-- (27) Word8AndOp: andWord8# with constant mask gives bounded range [0, mask]
+word8_and_lt :: Word8# -> Bool
+word8_and_lt x = isTrue# (word8ToWord# (andWord8# x (wordToWord8# 0xF##)) `ltWord#` 16##) -- True
+
+word8_and_alts :: Word8# -> Bool
+word8_and_alts x = case word8ToWord# (andWord8# x (wordToWord8# 0xF##)) of
+ 100## -> False -- unreachable: 100 > 15
+ 20## -> False -- unreachable: 20 > 15
+ 5## -> False -- reachable
+ _ -> True
+
+-- (28) Word16AndOp: andWord16# with constant mask gives bounded range [0, mask]
+word16_and_lt :: Word16# -> Bool
+word16_and_lt x = isTrue# (word16ToWord# (andWord16# x (wordToWord16# 0xFF##)) `ltWord#` 256##) -- True
+
+-- (29) Word32AndOp: andWord32# with constant mask gives bounded range [0, mask]
+-- (65536## = 2^16, valid on any platform as Word# literal)
+word32_and_lt :: Word32# -> Bool
+word32_and_lt x = isTrue# (word32ToWord# (andWord32# x (wordToWord32# 0xFFFF##)) `ltWord#` 65536##) -- True
+
+-- (30) Word64AndOp (and64#): with constant mask gives bounded range [0, mask]
+word64_and_le :: Word64# -> Bool
+word64_and_le x = isTrue# (leWord64# (and64# x (wordToWord64# 0xFFFF##)) (wordToWord64# 65535##)) -- True
+
+-- (31) IntAndOp (andI#): with non-negative constant mask gives range [0, mask]
+int_and_ge :: Int# -> Bool
+int_and_ge x = isTrue# (andI# x 0xFF# >=# 0#) -- True
+
+int_and_alts :: Int# -> Bool
+int_and_alts x = case andI# x 0xFF# of
+ 256# -> False -- unreachable: 256 > 255
+ 42# -> False -- reachable
+ _ -> True
+
+#if WORD_SIZE_IN_BITS >= 64
+-- On 64-bit platforms, Word# is 64-bit so 4294967296## (= 2^32) is a valid literal
+-- and Word32 ops produce a proper sub-range of Word#.
+
+-- (32) Narrow32WordOp: narrow32Word# result in [0, 4294967295] on 64-bit
+narrow32w_lt_ub :: Word# -> Bool
+narrow32w_lt_ub x = isTrue# (narrow32Word# x `ltWord#` 4294967296##) -- True
+
+-- (33) Word32ToWordOp: word32ToWord# result in [0, 4294967295] on 64-bit
+word32_lt_ub :: Word32# -> Bool
+word32_lt_ub x = isTrue# (word32ToWord# x `ltWord#` 4294967296##) -- True
+
+word32_ge_ub_false :: Word32# -> Bool
+word32_ge_ub_false x = isTrue# (word32ToWord# x `geWord#` 4294967296##) -- False
+
+-- (34) WordToWord32Op: word32ToWord# (wordToWord32# x) in [0, 4294967295] on 64-bit
+word_to_word32_lt :: Word# -> Bool
+word_to_word32_lt x = isTrue# (word32ToWord# (wordToWord32# x) `ltWord#` 4294967296##) -- True
+
+-- (35) Word32AddOp: plusWord32# result in [0, 4294967295] on 64-bit
+word32_add_lt_ub :: Word32# -> Word32# -> Bool
+word32_add_lt_ub x y = isTrue# (word32ToWord# (plusWord32# x y) `ltWord#` 4294967296##) -- True
+
+-- (36) Word32SubOp: subWord32# result in [0, 4294967295] on 64-bit
+word32_sub_lt_ub :: Word32# -> Word32# -> Bool
+word32_sub_lt_ub x y = isTrue# (word32ToWord# (subWord32# x y) `ltWord#` 4294967296##) -- True
+
+-- (37) VRA1 for narrow32Int# (unreachable alts outside [-2147483648, 2147483647])
+-- (literals 2147483648# and 3000000000# overflow Int# on 32-bit, so guarded by CPP)
+narrow32_alts :: Int# -> Bool
+narrow32_alts x = case narrow32Int# x of
+ 3000000000# -> False -- unreachable: 3000000000 > 2147483647
+ 2147483648# -> False -- unreachable: 2147483648 > 2147483647
+ 42# -> False -- reachable
+ _ -> True
+
+-- (38) VRA1 for word32ToWord# (unreachable alts outside [0, 4294967295])
+-- (literals 4294967296## etc. overflow Word# on 32-bit, so guarded by CPP)
+word32_alts :: Word32# -> Bool
+word32_alts x = case word32ToWord# x of
+ 5000000000## -> False -- unreachable: 5000000000 > 4294967295
+ 4294967296## -> False -- unreachable: 4294967296 > 4294967295
+ 42## -> False -- reachable
+ _ -> True
+#endif
=====================================
testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-32
=====================================
@@ -0,0 +1,103 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 128, types: 115, coercions: 0, joins: 0/0}
+
+narrow8_ge_lb = \ _ -> True
+
+narrow8_le_ub = narrow8_ge_lb
+
+narrow8_gt_ub_false = \ _ -> False
+
+narrow16_ge_lb = narrow8_ge_lb
+
+narrow16_le_ub = narrow8_ge_lb
+
+narrow8w_lt_ub = \ _ -> True
+
+narrow16w_lt_ub = narrow8w_lt_ub
+
+word16_lt_ub = \ _ -> True
+
+word16_ge_ub_false = \ _ -> False
+
+word_to_word8_lt = narrow8w_lt_ub
+
+word_to_word16_lt = narrow8w_lt_ub
+
+word8_to_int8_ge = \ _ -> True
+
+word16_to_int16_ge = word16_lt_ub
+
+int8_to_word8_le = \ _ -> True
+
+int16_to_word16_le = \ _ -> True
+
+word8_add_lt_256 = \ _ _ -> True
+
+word16_alts
+ = \ x ->
+ case word16ToWord# x of {
+ __DEFAULT -> True;
+ 42## -> False
+ }
+
+narrow8_alts
+ = \ x ->
+ case narrow8Int# x of {
+ __DEFAULT -> True;
+ 42# -> False
+ }
+
+word8_sub_lt_256 = word8_add_lt_256
+
+word16_add_lt_ub = \ _ _ -> True
+
+word16_sub_lt_ub = word16_add_lt_ub
+
+int8_add_ge_lb = \ _ _ -> True
+
+int8_sub_le_ub = int8_add_ge_lb
+
+int16_add_ge_lb = \ _ _ -> True
+
+int16_sub_le_ub = int16_add_ge_lb
+
+narrow32_ge_lb = narrow8_ge_lb
+
+narrow32_le_ub = narrow8_ge_lb
+
+word32_to_int32_ge = \ _ -> True
+
+int32_to_word32_le = \ _ -> True
+
+int32_add_ge_lb = \ _ _ -> True
+
+int32_sub_le_ub = int32_add_ge_lb
+
+word8_and_lt = word8_to_int8_ge
+
+word8_and_alts
+ = \ x ->
+ case word8ToWord# (andWord8# x 15#Word8) of {
+ __DEFAULT -> True;
+ 5## -> False
+ }
+
+word16_and_lt = word16_lt_ub
+
+word32_and_lt = word32_to_int32_ge
+
+word64_and_le = \ _ -> True
+
+int_and_ge = narrow8_ge_lb
+
+int_and_alts
+ = \ x ->
+ case andI# x 255# of {
+ __DEFAULT -> True;
+ 42# -> False
+ }
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/T25718c.stderr-ws-64
=====================================
@@ -0,0 +1,129 @@
+
+==================== Tidy Core ====================
+Result size of Tidy Core
+ = {terms: 161, types: 140, coercions: 0, joins: 0/0}
+
+narrow8_ge_lb = \ _ -> True
+
+narrow8_le_ub = narrow8_ge_lb
+
+narrow8_gt_ub_false = \ _ -> False
+
+narrow16_ge_lb = narrow8_ge_lb
+
+narrow16_le_ub = narrow8_ge_lb
+
+narrow8w_lt_ub = \ _ -> True
+
+narrow16w_lt_ub = narrow8w_lt_ub
+
+word16_lt_ub = \ _ -> True
+
+word16_ge_ub_false = \ _ -> False
+
+word_to_word8_lt = narrow8w_lt_ub
+
+word_to_word16_lt = narrow8w_lt_ub
+
+word8_to_int8_ge = \ _ -> True
+
+word16_to_int16_ge = word16_lt_ub
+
+int8_to_word8_le = \ _ -> True
+
+int16_to_word16_le = \ _ -> True
+
+word8_add_lt_256 = \ _ _ -> True
+
+word16_alts
+ = \ x ->
+ case word16ToWord# x of {
+ __DEFAULT -> True;
+ 42## -> False
+ }
+
+narrow8_alts
+ = \ x ->
+ case narrow8Int# x of {
+ __DEFAULT -> True;
+ 42# -> False
+ }
+
+word8_sub_lt_256 = word8_add_lt_256
+
+word16_add_lt_ub = \ _ _ -> True
+
+word16_sub_lt_ub = word16_add_lt_ub
+
+int8_add_ge_lb = \ _ _ -> True
+
+int8_sub_le_ub = int8_add_ge_lb
+
+int16_add_ge_lb = \ _ _ -> True
+
+int16_sub_le_ub = int16_add_ge_lb
+
+narrow32_ge_lb = narrow8_ge_lb
+
+narrow32_le_ub = narrow8_ge_lb
+
+word32_to_int32_ge = \ _ -> True
+
+int32_to_word32_le = \ _ -> True
+
+int32_add_ge_lb = \ _ _ -> True
+
+int32_sub_le_ub = int32_add_ge_lb
+
+word8_and_lt = word8_to_int8_ge
+
+word8_and_alts
+ = \ x ->
+ case word8ToWord# (andWord8# x 15#Word8) of {
+ __DEFAULT -> True;
+ 5## -> False
+ }
+
+word16_and_lt = word16_lt_ub
+
+word32_and_lt = word32_to_int32_ge
+
+word64_and_le = \ _ -> True
+
+int_and_ge = narrow8_ge_lb
+
+int_and_alts
+ = \ x ->
+ case andI# x 255# of {
+ __DEFAULT -> True;
+ 42# -> False
+ }
+
+narrow32w_lt_ub = narrow8w_lt_ub
+
+word32_lt_ub = word32_to_int32_ge
+
+word32_ge_ub_false = \ _ -> False
+
+word_to_word32_lt = narrow8w_lt_ub
+
+word32_add_lt_ub = \ _ _ -> True
+
+word32_sub_lt_ub = word32_add_lt_ub
+
+narrow32_alts
+ = \ x ->
+ case narrow32Int# x of {
+ __DEFAULT -> True;
+ 42# -> False
+ }
+
+word32_alts
+ = \ x ->
+ case word32ToWord# x of {
+ __DEFAULT -> True;
+ 42## -> False
+ }
+
+
+
=====================================
testsuite/tests/simplCore/should_compile/all.T
=====================================
@@ -594,3 +594,8 @@ test('T26805', [grep_errmsg(r'fromInteger')], compile, ['-O -dno-typeable-binds
test('T26826', normal, compile, ['-O'])
test('T26903', [grep_errmsg(r'reverse')], compile, ['-O -dno-typeable-binds -ddump-simpl -dsuppress-uniques -dsuppress-all'])
test('T18032', normal, compile, ['-O -dsuppress-all -dsuppress-uniques -dno-typeable-binds -ddump-simpl'])
+test('T25718', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
+test('T25718a', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
+test('T25718b', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
+test('T25718c', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
+test('T19166', normal, compile, ['-O -ddump-simpl -dsuppress-uniques -dsuppress-all -dno-typeable-binds'])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c6d262aaea235dc142fe8d56704150…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c6d262aaea235dc142fe8d56704150…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/supersven/correctly_propagate_host-build-target] 44 commits: base: fix redundant imports in GHC.Internal.Weak.Finalize
by Sven Tennie (@supersven) 26 Mar '26
by Sven Tennie (@supersven) 26 Mar '26
26 Mar '26
Sven Tennie pushed to branch wip/supersven/correctly_propagate_host-build-target at Glasgow Haskell Compiler / GHC
Commits:
12a706cf by Cheng Shao at 2026-03-14T16:37:54-04:00
base: fix redundant imports in GHC.Internal.Weak.Finalize
This patch fixes redundant imports in GHC.Internal.Weak.Finalize that
causes a regression in bootstrapping head from 9.14 with validate
flavours. Fixes #27026.
- - - - -
b5d39cad by Matthew Pickering at 2026-03-14T16:38:37-04:00
Use explicit syntax rather than pure
- - - - -
43638643 by Andreas Klebinger at 2026-03-15T18:15:48-04:00
Configure: Fix check for --target support in stage0 CC
The check FP_PROG_CC_LINKER_TARGET used $CC unconditionally to check for
--target support. However this fails for the stage0 config where the C
compiler used is not $CC but $CC_STAGE0.
Since we already pass the compiler under test into the macro I simply
changed it to use that instead.
Fixes #26999
- - - - -
18fd0df6 by Simon Hengel at 2026-03-15T18:16:33-04:00
Fix typo in recursive_do.rst
- - - - -
86bd9bfc by fendor at 2026-03-17T23:46:09-04:00
Introduce `-fimport-loaded-targets` GHCi flag
This new flag automatically adds all loaded targets to the GHCi session
by adding an `InteractiveImport` for the loaded targets.
By default, this flag is disabled, as it potentially increases memory-usage.
This interacts with the flag `-fno-load-initial-targets` as follows:
* If no module is loaded, no module is added as an interactive import.
* If a reload loads up to a module, all loaded modules are added as
interactive imports.
* Unloading modules removes them from the interactive context.
Fixes #26866 by rendering the use of a `-ghci-script` to achieve the
same thing redundant.
- - - - -
e3d4c1bb by mniip at 2026-03-17T23:47:03-04:00
ghc-internal: Remove GHC.Internal.Data.Eq
It served no purpose other than being a re-export.
- - - - -
6f4f6cf0 by mniip at 2026-03-17T23:47:03-04:00
ghc-internal: Refine GHC.Internal.Base imports
Removed re-exports from GHC.Internal.Base. This reveals some modules
that don't actually use anything *defined* in GHC.Internal.Base, and
that can be pushed down a little in the import graph.
Replaced most imports of GHC.Internal.Base with non-wildcard imports
from modules where the identifiers are actually defined.
Part of #26834
Metric Decrease:
T5321FD
- - - - -
7fb51f54 by mangoiv at 2026-03-17T23:48:00-04:00
ci: clone, don't copy when creating the cabal cache
Also removed WINDOWS_HOST variable detected via uname - we now just
check whether the CI job has windows in its name. This works because we
only ever care about it if the respective job is not a cross job. We
also statically detect darwin cross jobs in the same way. We only ever have
darwin -> darwin cross jobs so this is enough to detect the host
reliably.
- - - - -
f8817879 by mangoiv at 2026-03-17T23:48:44-04:00
ci: mark size_hello_artifact fragile on darwin x86
The size of the x86_64 hello artifact is not stable which results in flaky testruns.
Resolves #26814
- - - - -
e34cb6da by Adam Gundry at 2026-03-20T12:20:00-04:00
ghci: Mention active language edition in startup banner
Per GHC proposal 632, this makes the GHCi startup banner include
the active language edition, plus an indication of whether this
was the default (as opposed to being explicitly selected via an
option such as `-XGHC2024`). For example:
```
$ ghci
GHCi, version 9.14.1: https://www.haskell.org/ghc/ :? for help
Using default language edition: GHC2024
ghci>
```
Fixes #26037.
- - - - -
52c3e6ba by sheaf at 2026-03-20T12:21:09-04:00
Improve incomplete record selector warnings
This commit stops GHC from emitting spurious incomplete record selector
warnings for bare selectors/projections such as .fld
There are two places we currently emit incomplete record selector
warnings:
1. In the desugarer, when we see a record selector or an occurrence
of 'getField'. Here, we can use pattern matching information to
ensure we don't give false positives.
2. In the typechecker, which might sometimes give false positives but
can emit warnings in cases that the pattern match checker would
otherwise miss.
This is explained in Note [Detecting incomplete record selectors]
in GHC.HsToCore.Pmc.
Now, we obviously don't want to emit the same error twice, and generally
we prefer (1), as those messages contain fewer false positives. So we
suppress (2) when we are sure we are going to emit (1); the logic for
doing so is in GHC.Tc.Instance.Class.warnIncompleteRecSel,
and works by looking at the CtOrigin.
Now, the issue was that this logic handled explicit record selectors as
well as overloaded record field selectors such as "x.r" (which turns
into a simple GetFieldOrigin CtOrigin), but it didn't properly handle
record projectors like ".fld" or ".fld1.fld2" (which result in other
CtOrigins such as 'RecordFieldProjectionOrigin').
To solve this problem, we re-use the 'isHasFieldOrigin' introduced in
fbdc623a (slightly adjusted).
On the way, we also had to update the desugarer with special handling
for the 'ExpandedThingTc' case in 'ds_app', to make sure that
'ds_app_var' sees all the type arguments to 'getField' in order for it
to indeed emit warnings like in (1).
Fixes #26686
- - - - -
309d7e87 by Cheng Shao at 2026-03-20T12:21:53-04:00
rts: opportunistically grow the MutableByteArray# in-place in resizeMutableByteArray#
Following !15234, this patch improves `resizeMutableByteArray#` memory
efficiency by growing the `MutableByteArray#` in-place if possible,
addressing an old todo comment here. Also adds a new test case
`resizeMutableByteArrayInPlace` that stresses this behavior.
- - - - -
7d4ef162 by Matthew Craven at 2026-03-20T12:22:47-04:00
Change representation of floating point literals
This commit changes the representation of floating point literals
throughough the compiler, in particular in Core and Cmm.
The Rational type is deficient for this purpose, dealing poorly
with NaN, +/-Infinity, and negative zero. Instead, the new module
GHC.Types.Literal.Floating uses the host Float/Double type to represent
NaNs, infinities and negative zero. It also contains a Rational
constructor, for the benefit of -fexcess-precision.
Other changes:
- Remove Note [negative zero] and related code
This also removes the restrictions on constant-folding of division
by zero, and should make any problems with NaN/Infinity more obvious.
- Use -0.0 as the additive identity for Core constant folding rules
for floating-point addition, fixing #21227.
- Manual worker-wrapper for GHC.Float.rationalToDouble. This is
intended to prevent the compiler's WW on this function from
interfering with constant-folding. This change means that we now
avoid allocating a box for the result of a 'realToFrac' call in
T10359.
- Combine floatDecodeOp and doubleDecodeOp.
This change also fixes a bug in doubleDecodeOp wherein it
would incorrectly produce an Int# instead of an Int64#
literal for the mantissa component with 64-bit targets.
- Use Float/Double for assembly immediates, and update the X86 and
PowerPC backends to properly handle special values such as NaN and
infinity.
- Allow 'rational_to' to handle zero denominators, fixing a
TODO in GHC.Core.Opt.ConstantFold.
Fixes #8364 #9811 #18897 #21227
Progress towards #26919
Metric Decrease:
T10359
Co-authored-by: sheaf <sam.derbyshire(a)gmail.com>
-------------------------
Metric Decrease:
T1969
T5321FD
-------------------------
- - - - -
80e2dd4f by Zubin Duggal at 2026-03-20T12:23:33-04:00
compiler/ffi: Collapse void pointer chains in capi wrappers
New gcc/clang treat -Wincompatible-pointer-types as an error by
default. Since C only allows implicit conversion from void*, not void**,
capi wrappers for functions taking e.g. abstract** would fail to compile
when the Haskell type Ptr (Ptr Abstract) was naively translated to void**.
Collapse nested void pointers to a single void* when the pointee type
has no known C representation.
Fixes #26852
- - - - -
1c50bd7b by Luite Stegeman at 2026-03-20T12:24:37-04:00
Move some functions related to pointer tagging to a separate module
- - - - -
bfd7aafd by Luite Stegeman at 2026-03-20T12:24:37-04:00
Branchless unpacking for enumeration types
Change unpacking for enumeration types to go to Word8#/Word16#/Word#
directly instead of going through an intermediate unboxed sum. This
allows us to do a branchless conversion using DataToTag and TagToEnum.
Fixes #26970
- - - - -
72b20fc0 by Luite Stegeman at 2026-03-20T12:25:30-04:00
bytecode: Carefully SLIDE off the end of a stack chunk
The SLIDE bytecode instruction was not checking for stack chunk
boundaries and could corrupt the stack underflow frame, leading
to crashes.
We add a check to use safe writes if we cross the chunk boundary
and also handle stack underflow if Sp is advanced past the underflow
frame.
fix #27001
- - - - -
2e22b43c by Cheng Shao at 2026-03-20T12:26:14-04:00
ghci: serialize BCOByteArray buffer directly when possible
This patch changes the `Binary` instances of `BCOByteArray` to
directly serialize the underlying buffer when possible, while also
taking into account the issue of host-dependent `Word` width. See
added comments and amended `Note [BCOByteArray serialization]` for
detailed explanation. Closes #27020.
- - - - -
89d9ba37 by Sylvain Henry at 2026-03-20T12:27:34-04:00
JS: replace BigInt with Number arithmetic for 32/64-bit quot/rem (#23597)
Replace BigInt-based implementations of quotWord32, remWord32,
quotRemWord32, quotRem2Word32, quotWord64, remWord64, quotInt64, and
remInt64 with pure Number (double/integer) arithmetic to avoid the
overhead of BigInt promotion.
- - - - -
ae4ddd60 by Sylvain Henry at 2026-03-20T12:28:28-04:00
Core: add constant-folding rules for Addr# eq/ne (#18032)
- - - - -
3e767f98 by Matthew Pickering at 2026-03-20T12:29:11-04:00
Use OsPath rather than FilePath in Downsweep cache
This gets us one step closure to uniformly using `OsPath` in the
compiler.
- - - - -
2c57de29 by Cheng Shao at 2026-03-20T12:29:55-04:00
hadrian: fix ghc-in-ghci flavour stage0 shared libraries
This patch fixes missing stage0 shared libraries in hadrian
ghc-in-ghci flavour, which was accidentally dropped in
669d09f950a6e88b903d9fd8a7571531774d4d5d and resulted in a regression
in HLS support on linux/macos. Fixes #27057.
- - - - -
5b1be555 by Sylvain Henry at 2026-03-20T12:30:48-04:00
JS: install rts/Types.h header file (#27033)
It was an omission, making HsFFI.h not usable with GHC using the JS
backend.
- - - - -
b883f08f by Cheng Shao at 2026-03-20T12:31:33-04:00
hadrian: don't compile RTS with -Winline
This patch removes `-Winline` from cflags when compiling the RTS,
given that:
1. It generates a huge pile of spam and hurts developer experience
2. Whether inlining happens is highly dependent on toolchains,
flavours, etc, and it's not really an issue to fix if inlining
doesn't happen; it's a hint to the C compiler anyway.
Fixes #27060.
- - - - -
333387d6 by Cheng Shao at 2026-03-20T12:31:33-04:00
hadrian: compile libffi-clib with -Wno-deprecated-declarations
This patch adds `-Wno-deprecated-declarations` to cflags of
`libffi-clib`, given that it produces noise at compile-time that
aren't really our issue to fix anyway, it's from vendored libffi
source code.
- - - - -
67c47771 by Rodrigo Mesquita at 2026-03-20T12:32:17-04:00
Expose decodeStackWithIpe from ghc-experimental
This decoding is useful to the debugger and it wasn't originally
exported as an oversight.
- - - - -
18513365 by Matthew Pickering at 2026-03-21T04:43:26-04:00
Add support for custom external interpreter commands
It can be useful for GHC API clients to implement their own external
interpreter commands.
For example, the debugger may want an efficient way to inspect the
stacks of the running threads in the external interpreter.
- - - - -
4636d906 by mangoiv at 2026-03-21T04:44:10-04:00
ci: remove obsolete fallback for old debian and ubuntu versions
- - - - -
2e3a2805 by mangoiv at 2026-03-21T04:44:10-04:00
ci: drop ubuntu 18 and 20
Ubuntu 18 EOL: May 2023
Ubuntu 20 EOL: May 2025
We should probably not make another major release supporting these platforms.
Also updates the generator script.
Resolves #25876
- - - - -
de54e264 by Cheng Shao at 2026-03-21T17:52:08+01:00
rts: fix -Wcompare-distinct-pointer-types errors
This commit fixes `-Wcompare-distinct-pointer-types` errors in the RTS
which should have been caught by the `validate` flavour but was
warnings in CI due to the recent `+werror` regression.
- - - - -
b9bd73de by Cheng Shao at 2026-03-21T17:52:08+01:00
ghc-internal: fix unused imports
This commit fixes unused imports in `ghc-internal` which should have
been caught by the `validate` flavour but was warnings in CI due to
the recent `+werror` regression. Fixes #26987 #27059.
- - - - -
da946a16 by Cheng Shao at 2026-03-21T17:03:51+00:00
ghci: fix unused imports
This commit fixes unused imports in `ghci` which should have been
caught by the `validate` flavour but was warnings in CI due to the
recent `+werror` regression. Fixes #26987 #27059.
- - - - -
955b1cf8 by Cheng Shao at 2026-03-21T17:03:51+00:00
compiler: fix unused imports in GHC.Tc.Types.Origin
This commit fixes unused imports in `GHC.Tc.Types.Origin` which should
have been caught by the `validate` flavour but was warnings in CI due
to the recent `+werror` regression. Fixes #27059.
- - - - -
3b1aeb50 by Cheng Shao at 2026-03-21T17:03:51+00:00
hadrian: fix missing +werror in validate flavour
This patch fixes missing `+werror` in validate flavour, which was an
oversight in bb3a2ba1eefadf0b2ef4f39b31337a23eec67f29. Fixes #27066.
- - - - -
44f118f0 by Cheng Shao at 2026-03-22T04:54:01-04:00
ci: bump CACHE_REV and add the missing reminder
This patch bumps `CACHE_REV` to address recent `[Cabal-7159]` CI
errors due to stale cabal cache on some runners, and also adds a
reminder to remind future maintainers. Fixes #27075.
- - - - -
2a218737 by ARATA Mizuki at 2026-03-23T11:11:39-04:00
Add 128-bit SIMD support to AArch64 NCG
Changes:
- Add `Format` field to vector-capable instructions.
These instructions will emit `vN.4s` (for example) as a operand.
- Additional constructors for `Operand`:
`OpVecLane` represents a vector lane and will be emitted as `vN.<width>[<index>]` (`vN.s[3]` for example).
`OpScalarAsVec` represents a scalar, but printed as a vector lane like `vN.<width>[0]` (`vN.s[0]` for example).
- Integer quot/rem are implemented in C, like x86.
Closes #26536
Metric Increase:
T3294
- - - - -
5d6e2be9 by ARATA Mizuki at 2026-03-23T11:11:39-04:00
AArch64 NCG: Improve code generation for floating-point and vector constants
Some floating-point constants can be directly encoded using the FMOV instruction.
Similarly, a class of vectors with same values can be encoded using FMOV, MOVI, or MVNI.
- - - - -
c6d262aa by Simon Jakobi at 2026-03-23T11:12:22-04:00
Add regression test for #13729
Closes #13729.
- - - - -
5eba9454 by Matthew Pickering at 2026-03-26T06:02:20+00:00
packaging: correctly propagate build/host/target to bindist configure script
At the moment the host and target which we will produce a compiler for
is fixed at the initial configure time. Therefore we need to persist
the choice made at this time into the installation bindist as well so we
look for the right tools, with the right prefixes at install time.
In the future, we want to provide a bit more control about what kind of
bindist we produce so the logic about what the host/target will have to
be written by hadrian rather than persisted by the configure script. In
particular with cross compilers we want to either build a normal stage 2
cross bindist or a stage 3 bindist, which creates a bindist which has a
native compiler for the target platform.
Fixes #21970
Co-authored-by: Sven Tennie <sven.tennie(a)gmail.com>
- - - - -
1a92de0b by Sven Tennie at 2026-03-26T06:02:20+00:00
Cross --host and --target no longer required for cross (#21970)
We set sane defaults in the configure script. Thus, these paramenters
aren't required any longer.
- - - - -
304ecc11 by Sven Tennie at 2026-03-26T06:02:20+00:00
bindist: Propagate user set $LD to ghc-toolchain
Otherwise, ghc-toolchain wrongly emits `-fuse-ld` for cross-compilers.
- - - - -
7c38c127 by Sven Tennie at 2026-03-26T06:02:20+00:00
Respect user set CFLAGS, CXXFLAGS and LDFLAGS
These were ignored on installs.
- - - - -
a0fddba9 by Sven Tennie at 2026-03-26T06:02:20+00:00
Only add flags if they are new
This prevents duplicated when the user already set the arguments in
CXXFLAGS or CFLAGS.
- - - - -
29beaa36 by Sven Tennie at 2026-03-26T06:02:20+00:00
Revert "Only add flags if they are new"
This reverts commit 312deb98d69a80a3b1183188c92bf83c86644021.
- - - - -
442 changed files:
- .gitlab-ci.yml
- .gitlab/ci.sh
- .gitlab/generate-ci/flake.lock
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
- .gitlab/rel_eng/fetch-gitlab-artifacts/fetch_gitlab.py
- .gitlab/rel_eng/mk-ghcup-metadata/mk_ghcup_metadata.py
- compiler/CodeGen.Platform.h
- compiler/GHC/Builtin/Names.hs
- compiler/GHC/ByteCode/Asm.hs
- compiler/GHC/Cmm/CommonBlockElim.hs
- compiler/GHC/Cmm/Expr.hs
- compiler/GHC/Cmm/Opt.hs
- compiler/GHC/Cmm/Parser.y
- compiler/GHC/Cmm/Type.hs
- compiler/GHC/Cmm/Utils.hs
- compiler/GHC/CmmToAsm/AArch64/CodeGen.hs
- compiler/GHC/CmmToAsm/AArch64/Instr.hs
- compiler/GHC/CmmToAsm/AArch64/Ppr.hs
- compiler/GHC/CmmToAsm/AArch64/Regs.hs
- compiler/GHC/CmmToAsm/LA64/CodeGen.hs
- compiler/GHC/CmmToAsm/LA64/Ppr.hs
- compiler/GHC/CmmToAsm/LA64/Regs.hs
- compiler/GHC/CmmToAsm/PPC/CodeGen.hs
- compiler/GHC/CmmToAsm/PPC/Ppr.hs
- compiler/GHC/CmmToAsm/PPC/Regs.hs
- compiler/GHC/CmmToAsm/RV64/CodeGen.hs
- compiler/GHC/CmmToAsm/RV64/Ppr.hs
- compiler/GHC/CmmToAsm/RV64/Regs.hs
- compiler/GHC/CmmToAsm/Reg/Graph/TrivColorable.hs
- compiler/GHC/CmmToAsm/Wasm/FromCmm.hs
- compiler/GHC/CmmToAsm/X86/CodeGen.hs
- compiler/GHC/CmmToAsm/X86/Ppr.hs
- compiler/GHC/CmmToAsm/X86/Regs.hs
- compiler/GHC/CmmToC.hs
- compiler/GHC/CmmToLlvm/CodeGen.hs
- compiler/GHC/CmmToLlvm/Data.hs
- compiler/GHC/Core.hs
- compiler/GHC/Core/Make.hs
- compiler/GHC/Core/Opt/ConstantFold.hs
- compiler/GHC/Driver/Config/StgToCmm.hs
- compiler/GHC/Driver/Downsweep.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/Foreign/C.hs
- compiler/GHC/HsToCore/Match/Literal.hs
- compiler/GHC/HsToCore/Pmc.hs
- compiler/GHC/HsToCore/Pmc/Solver/Types.hs
- + compiler/GHC/Platform/Tag.hs
- compiler/GHC/Stg/Unarise.hs
- compiler/GHC/StgToByteCode.hs
- compiler/GHC/StgToCmm/Closure.hs
- compiler/GHC/StgToCmm/Expr.hs
- compiler/GHC/StgToCmm/Lit.hs
- compiler/GHC/StgToCmm/Prim.hs
- compiler/GHC/StgToJS/Literal.hs
- compiler/GHC/Tc/Errors.hs
- compiler/GHC/Tc/Instance/Class.hs
- compiler/GHC/Tc/TyCl/Build.hs
- compiler/GHC/Tc/Types/Origin.hs
- compiler/GHC/Types/Id/Make.hs
- compiler/GHC/Types/Literal.hs
- + compiler/GHC/Types/Literal/Floating.hs
- compiler/GHC/Types/RepType.hs
- compiler/GHC/Utils/Binary.hs
- compiler/ghc.cabal.in
- configure.ac
- distrib/configure.ac.in
- docs/users_guide/9.16.1-notes.rst
- docs/users_guide/exts/recursive_do.rst
- docs/users_guide/ghci.rst
- docs/users_guide/utils.py
- ghc/GHCi/UI.hs
- ghc/Main.hs
- hadrian/cabal.project
- hadrian/cfg/system.config.in
- hadrian/src/Oracles/Setting.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Settings/Default.hs
- hadrian/src/Settings/Flavours/GhcInGhci.hs
- hadrian/src/Settings/Flavours/Validate.hs
- hadrian/src/Settings/Packages.hs
- libraries/base/src/Control/Applicative.hs
- libraries/base/src/Data/Char.hs
- libraries/base/src/Data/Eq.hs
- libraries/base/src/Data/Semigroup.hs
- libraries/base/src/GHC/Base.hs
- libraries/base/src/GHC/Weak/Finalize.hs
- libraries/base/src/Prelude.hs
- libraries/ghc-experimental/ghc-experimental.cabal.in
- libraries/ghc-experimental/src/GHC/Profiling/Eras.hs
- + libraries/ghc-experimental/src/GHC/Stack/Decode/Experimental.hs
- libraries/ghc-internal/codepages/MakeTable.hs
- libraries/ghc-internal/ghc-internal.cabal.in
- libraries/ghc-internal/src/GHC/Internal/AllocationLimitHandler.hs
- libraries/ghc-internal/src/GHC/Internal/Arr.hs
- libraries/ghc-internal/src/GHC/Internal/Base.hs
- libraries/ghc-internal/src/GHC/Internal/Bits.hs
- libraries/ghc-internal/src/GHC/Internal/ByteOrder.hs
- libraries/ghc-internal/src/GHC/Internal/Char.hs
- libraries/ghc-internal/src/GHC/Internal/Clock.hsc
- libraries/ghc-internal/src/GHC/Internal/ClosureTypes.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/Bound.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/IO.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/POSIX.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/Signal.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/Sync.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/Windows.hs
- libraries/ghc-internal/src/GHC/Internal/ConsoleHandler.hsc
- libraries/ghc-internal/src/GHC/Internal/Control/Arrow.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Concurrent/MVar.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Exception/Base.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/Fail.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/Fix.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/IO/Class.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/ST/Imp.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/ST/Lazy/Imp.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Bits.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Data.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Dynamic.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Either.hs
- − libraries/ghc-internal/src/GHC/Internal/Data/Eq.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Foldable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Function.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Const.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Identity.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Utils.hs
- libraries/ghc-internal/src/GHC/Internal/Data/IORef.hs
- libraries/ghc-internal/src/GHC/Internal/Data/List.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Maybe.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Monoid.hs
- libraries/ghc-internal/src/GHC/Internal/Data/OldList.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Ord.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Proxy.hs
- libraries/ghc-internal/src/GHC/Internal/Data/STRef.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Semigroup/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Data/String.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Traversable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Type/Bool.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Type/Coercion.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Type/Equality.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Type/Ord.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Typeable.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Typeable/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Unique.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Version.hs
- libraries/ghc-internal/src/GHC/Internal/Debug/Trace.hs
- libraries/ghc-internal/src/GHC/Internal/Debug/Trace.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Encoding/UTF8.hs
- libraries/ghc-internal/src/GHC/Internal/Enum.hs
- libraries/ghc-internal/src/GHC/Internal/Environment.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Array.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Control.hs
- libraries/ghc-internal/src/GHC/Internal/Event/EPoll.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/IntVar.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Internal/Types.hs
- libraries/ghc-internal/src/GHC/Internal/Event/KQueue.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/Manager.hs
- libraries/ghc-internal/src/GHC/Internal/Event/PSQ.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Poll.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/Thread.hs
- libraries/ghc-internal/src/GHC/Internal/Event/TimeOut.hs
- libraries/ghc-internal/src/GHC/Internal/Event/TimerManager.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Unique.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Windows.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/Clock.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/ConsoleEvent.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/FFI.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/ManagedThreadPool.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Windows/Thread.hs
- libraries/ghc-internal/src/GHC/Internal/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs
- libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Exception/Context.hs
- libraries/ghc-internal/src/GHC/Internal/Exception/Type.hs
- libraries/ghc-internal/src/GHC/Internal/ExecutionStack.hs
- libraries/ghc-internal/src/GHC/Internal/ExecutionStack/Internal.hsc
- libraries/ghc-internal/src/GHC/Internal/Exts.hs
- libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs
- libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Fingerprint/Type.hs
- libraries/ghc-internal/src/GHC/Internal/Float.hs
- libraries/ghc-internal/src/GHC/Internal/Float/ConversionUtils.hs
- libraries/ghc-internal/src/GHC/Internal/Float/RealFracMethods.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/ConstPtr.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/Error.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/String.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/String/Encoding.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/Types.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/ForeignPtr/Imp.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Alloc.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Array.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Error.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Pool.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Utils.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Ptr.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Storable.hs
- libraries/ghc-internal/src/GHC/Internal/ForeignPtr.hs
- libraries/ghc-internal/src/GHC/Internal/ForeignSrcLang.hs
- libraries/ghc-internal/src/GHC/Internal/Functor/ZipList.hs
- libraries/ghc-internal/src/GHC/Internal/GHCi.hs
- libraries/ghc-internal/src/GHC/Internal/GHCi/Helpers.hs
- libraries/ghc-internal/src/GHC/Internal/Generics.hs
- libraries/ghc-internal/src/GHC/Internal/Heap/Closures.hs
- libraries/ghc-internal/src/GHC/Internal/Heap/InfoTable.hsc
- libraries/ghc-internal/src/GHC/Internal/Heap/InfoTable/Types.hsc
- libraries/ghc-internal/src/GHC/Internal/Heap/InfoTableProf.hsc
- libraries/ghc-internal/src/GHC/Internal/Heap/ProfInfo/Types.hs
- libraries/ghc-internal/src/GHC/Internal/IO.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Buffer.hs
- libraries/ghc-internal/src/GHC/Internal/IO/BufferedIO.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Device.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/CodePage.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/CodePage/API.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/CodePage/Table.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/Failure.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/Iconv.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/Latin1.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/Types.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/UTF16.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/UTF32.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/UTF8.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs-boot
- libraries/ghc-internal/src/GHC/Internal/IO/FD.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/FD.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Internals.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Lock.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Lock/Flock.hsc
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Lock/LinuxOFD.hsc
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Lock/NoOp.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Lock/Windows.hsc
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Types.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Windows.hs
- libraries/ghc-internal/src/GHC/Internal/IO/IOMode.hs
- libraries/ghc-internal/src/GHC/Internal/IO/SubSystem.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Unsafe.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Windows/Encoding.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Windows/Handle.hsc
- libraries/ghc-internal/src/GHC/Internal/IOArray.hs
- libraries/ghc-internal/src/GHC/Internal/IORef.hs
- libraries/ghc-internal/src/GHC/Internal/InfoProv.hs
- libraries/ghc-internal/src/GHC/Internal/InfoProv/Types.hsc
- libraries/ghc-internal/src/GHC/Internal/Int.hs
- libraries/ghc-internal/src/GHC/Internal/IsList.hs
- libraries/ghc-internal/src/GHC/Internal/Ix.hs
- libraries/ghc-internal/src/GHC/Internal/JS/Foreign/Callback.hs
- libraries/ghc-internal/src/GHC/Internal/JS/Prim/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/JS/Prim/Internal/Build.hs
- libraries/ghc-internal/src/GHC/Internal/LanguageExtensions.hs
- libraries/ghc-internal/src/GHC/Internal/Lexeme.hs
- libraries/ghc-internal/src/GHC/Internal/List.hs
- libraries/ghc-internal/src/GHC/Internal/MVar.hs
- libraries/ghc-internal/src/GHC/Internal/Num.hs
- libraries/ghc-internal/src/GHC/Internal/Numeric.hs
- libraries/ghc-internal/src/GHC/Internal/OverloadedLabels.hs
- libraries/ghc-internal/src/GHC/Internal/Pack.hs
- libraries/ghc-internal/src/GHC/Internal/Profiling.hs
- libraries/ghc-internal/src/GHC/Internal/Ptr.hs
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags/Test.hsc
- libraries/ghc-internal/src/GHC/Internal/Read.hs
- libraries/ghc-internal/src/GHC/Internal/Real.hs
- libraries/ghc-internal/src/GHC/Internal/ST.hs
- libraries/ghc-internal/src/GHC/Internal/STM.hs
- libraries/ghc-internal/src/GHC/Internal/STRef.hs
- libraries/ghc-internal/src/GHC/Internal/Show.hs
- libraries/ghc-internal/src/GHC/Internal/Stable.hs
- libraries/ghc-internal/src/GHC/Internal/StableName.hs
- libraries/ghc-internal/src/GHC/Internal/Stack.hs
- libraries/ghc-internal/src/GHC/Internal/Stack.hs-boot
- libraries/ghc-internal/src/GHC/Internal/Stack/Annotation.hs
- libraries/ghc-internal/src/GHC/Internal/Stack/CCS.hsc
- libraries/ghc-internal/src/GHC/Internal/Stack/CloneStack.hs
- libraries/ghc-internal/src/GHC/Internal/Stack/Constants.hsc
- libraries/ghc-internal/src/GHC/Internal/Stack/ConstantsProf.hsc
- libraries/ghc-internal/src/GHC/Internal/Stack/Decode.hs
- libraries/ghc-internal/src/GHC/Internal/StaticPtr.hs
- libraries/ghc-internal/src/GHC/Internal/StaticPtr/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Stats.hsc
- libraries/ghc-internal/src/GHC/Internal/Storable.hs
- libraries/ghc-internal/src/GHC/Internal/System/Environment.hs
- libraries/ghc-internal/src/GHC/Internal/System/Environment/Blank.hsc
- libraries/ghc-internal/src/GHC/Internal/System/Environment/ExecutablePath.hsc
- libraries/ghc-internal/src/GHC/Internal/System/IO.hs
- libraries/ghc-internal/src/GHC/Internal/System/IO/Error.hs
- libraries/ghc-internal/src/GHC/Internal/System/Mem.hs
- libraries/ghc-internal/src/GHC/Internal/System/Posix/Internals.hs
- libraries/ghc-internal/src/GHC/Internal/System/Posix/Types.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lift.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Monad.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
- libraries/ghc-internal/src/GHC/Internal/Text/ParserCombinators/ReadP.hs
- libraries/ghc-internal/src/GHC/Internal/Text/ParserCombinators/ReadPrec.hs
- libraries/ghc-internal/src/GHC/Internal/Text/Read.hs
- libraries/ghc-internal/src/GHC/Internal/Text/Read/Lex.hs
- libraries/ghc-internal/src/GHC/Internal/TopHandler.hs
- libraries/ghc-internal/src/GHC/Internal/TypeLits.hs
- libraries/ghc-internal/src/GHC/Internal/TypeLits/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/TypeNats.hs
- libraries/ghc-internal/src/GHC/Internal/TypeNats/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Bits.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/DerivedCoreProperties.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/GeneralCategory.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/SimpleLowerCaseMapping.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/SimpleTitleCaseMapping.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Char/UnicodeData/SimpleUpperCaseMapping.hs
- libraries/ghc-internal/src/GHC/Internal/Unsafe/Coerce.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Conc.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Conc/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Exports.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Flag.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs
- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs
- libraries/ghc-internal/src/GHC/Internal/Weak.hs
- libraries/ghc-internal/src/GHC/Internal/Weak/Finalize.hs
- libraries/ghc-internal/src/GHC/Internal/Windows.hs
- libraries/ghc-internal/src/GHC/Internal/Word.hs
- libraries/ghc-internal/tools/ucd2haskell/exe/UCD2Haskell/ModuleGenerators.hs
- libraries/ghci/GHCi/CreateBCO.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/ResolvedBCO.hs
- libraries/ghci/GHCi/Run.hs
- libraries/ghci/GHCi/Server.hs
- m4/fp_prog_cc_linker_target.m4
- m4/fptools_set_platform_vars.m4
- m4/ghc_toolchain.m4
- rts/Interpreter.c
- rts/PrimOps.cmm
- rts/include/stg/Prim.h
- rts/js/arith.js
- rts/prim/vectorQuotRem.c
- rts/rts.cabal
- + testsuite/tests/bytecode/T27001.hs
- + testsuite/tests/bytecode/T27001.stdout
- testsuite/tests/bytecode/all.T
- + testsuite/tests/codeGen/should_run/T21227.hs
- + testsuite/tests/codeGen/should_run/T21227.stdout
- + testsuite/tests/codeGen/should_run/T9811.hs
- + testsuite/tests/codeGen/should_run/T9811.stdout
- testsuite/tests/codeGen/should_run/all.T
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/driver/T13729/A/A.cabal
- + testsuite/tests/driver/T13729/A/Setup.hs
- + testsuite/tests/driver/T13729/A/TH.hs
- + testsuite/tests/driver/T13729/A/Types1.hs
- + testsuite/tests/driver/T13729/A/Types2.hs
- + testsuite/tests/driver/T13729/B/B.cabal
- + testsuite/tests/driver/T13729/B/Main.hs
- + testsuite/tests/driver/T13729/B/Setup.hs
- + testsuite/tests/driver/T13729/Makefile
- + testsuite/tests/driver/T13729/Setup.hs
- + testsuite/tests/driver/T13729/all.T
- + testsuite/tests/ffi/should_compile/T26852.h
- + testsuite/tests/ffi/should_compile/T26852.hs
- + testsuite/tests/ffi/should_compile/T26852.stderr
- testsuite/tests/ffi/should_compile/all.T
- + testsuite/tests/ghci/custom-external-interpreter-commands/Main.hs
- + testsuite/tests/ghci/custom-external-interpreter-commands/all.T
- + testsuite/tests/ghci/custom-external-interpreter-commands/custom-external-interpreter-commands.stdout
- testsuite/tests/ghci/prog-mhu005/Makefile
- testsuite/tests/ghci/prog-mhu005/all.T
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005b.script
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005b.stdout
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005c.script
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005c.stderr
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005c.stdout
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005d.script
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005d.stderr
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005d.stdout
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005e.script
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005e.stderr
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005e.stdout
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005f.script
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005f.stderr
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005f.stdout
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005g.script
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005g.stderr
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005g.stdout
- testsuite/tests/ghci/prog022/Makefile
- testsuite/tests/ghci/prog022/all.T
- + testsuite/tests/ghci/prog022/ghci.prog022c.script
- + testsuite/tests/ghci/prog022/ghci.prog022c.stderr
- + testsuite/tests/ghci/prog022/ghci.prog022c.stdout
- + testsuite/tests/ghci/prog022/ghci.prog022d.script
- + testsuite/tests/ghci/prog022/ghci.prog022d.stderr
- + testsuite/tests/ghci/prog022/ghci.prog022d.stdout
- + testsuite/tests/ghci/prog022/ghci.prog022e.script
- + testsuite/tests/ghci/prog022/ghci.prog022e.stderr
- + testsuite/tests/ghci/prog022/ghci.prog022e.stdout
- + testsuite/tests/ghci/prog022/ghci.prog022f.script
- + testsuite/tests/ghci/prog022/ghci.prog022f.stderr
- + testsuite/tests/ghci/prog022/ghci.prog022f.stdout
- testsuite/tests/ghci/should_run/BinaryArray.hs
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout
- testsuite/tests/interface-stability/ghc-experimental-exports.stdout-mingw32
- testsuite/tests/interface-stability/template-haskell-exports.stdout
- + testsuite/tests/javascript/js-c-sources/T27033.hs
- + testsuite/tests/javascript/js-c-sources/T27033.stdout
- + testsuite/tests/javascript/js-c-sources/T27033_c.c
- + testsuite/tests/javascript/js-c-sources/T27033_js.js
- testsuite/tests/javascript/js-c-sources/all.T
- testsuite/tests/numeric/should_run/T7014.hs
- + testsuite/tests/overloadedrecflds/should_compile/T26686.hs
- + testsuite/tests/overloadedrecflds/should_compile/T26686.stderr
- testsuite/tests/overloadedrecflds/should_compile/all.T
- testsuite/tests/perf/size/all.T
- testsuite/tests/profiling/should_run/callstack001.stdout
- testsuite/tests/profiling/should_run/callstack002.stderr
- testsuite/tests/profiling/should_run/callstack002.stdout
- testsuite/tests/rts/all.T
- + testsuite/tests/rts/resizeMutableByteArrayInPlace.hs
- + testsuite/tests/simd/should_run/FloatConstant.hs
- + testsuite/tests/simd/should_run/FloatConstant.stdout
- + testsuite/tests/simd/should_run/IntConstant.hs
- + testsuite/tests/simd/should_run/IntConstant.stdout
- testsuite/tests/simd/should_run/all.T
- testsuite/tests/simd/should_run/int16x8_shuffle.hs
- testsuite/tests/simd/should_run/int16x8_shuffle.stdout
- testsuite/tests/simd/should_run/int16x8_shuffle_baseline.hs
- testsuite/tests/simd/should_run/int16x8_shuffle_baseline.stdout
- testsuite/tests/simd/should_run/int8x16_shuffle.hs
- testsuite/tests/simd/should_run/int8x16_shuffle.stdout
- testsuite/tests/simd/should_run/int8x16_shuffle_baseline.hs
- testsuite/tests/simd/should_run/int8x16_shuffle_baseline.stdout
- testsuite/tests/simd/should_run/simd013C.c
- + testsuite/tests/simplCore/should_compile/T18032.hs
- + testsuite/tests/simplCore/should_compile/T18032.stderr
- testsuite/tests/simplCore/should_compile/all.T
- testsuite/tests/simplStg/should_run/all.T
- + testsuite/tests/simplStg/should_run/unpack_enum.hs
- + testsuite/tests/simplStg/should_run/unpack_enum.stdout
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f93c3056a1f46874a501915e05cbcc…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/f93c3056a1f46874a501915e05cbcc…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Zubin pushed new branch wip/9.12.4-final at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/9.12.4-final
You're receiving this email because of your account on gitlab.haskell.org.
1
0
[Git][ghc/ghc][wip/spj-reinstallable-base] Add known-key imports for ghc-internal [skip ci]
by Simon Peyton Jones (@simonpj) 26 Mar '26
by Simon Peyton Jones (@simonpj) 26 Mar '26
26 Mar '26
Simon Peyton Jones pushed to branch wip/spj-reinstallable-base at Glasgow Haskell Compiler / GHC
Commits:
62767da4 by Simon Peyton Jones at 2026-03-26T00:40:53+00:00
Add known-key imports for ghc-internal [skip ci]
- - - - -
79 changed files:
- libraries/base/src/GHC/KnownKeyNames.hs
- libraries/base/src/GHC/RTS/Flags.hs
- libraries/ghc-internal/src/GHC/Internal/AllocationLimitHandler.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/Bound.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/IO.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/Signal.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/Sync.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Concurrent/MVar.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/Fix.hs
- libraries/ghc-internal/src/GHC/Internal/Control/Monad/ST/Imp.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Data.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Const.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Functor/Identity.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Monoid.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Type/Coercion.hs
- libraries/ghc-internal/src/GHC/Internal/Data/Version.hs
- libraries/ghc-internal/src/GHC/Internal/Debug/Trace.hs
- libraries/ghc-internal/src/GHC/Internal/Environment.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Control.hs
- libraries/ghc-internal/src/GHC/Internal/Event/EPoll.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/Internal.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Internal/Types.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Poll.hsc
- libraries/ghc-internal/src/GHC/Internal/Event/Thread.hs
- libraries/ghc-internal/src/GHC/Internal/Event/TimerManager.hs
- libraries/ghc-internal/src/GHC/Internal/Exception/Backtrace.hs
- libraries/ghc-internal/src/GHC/Internal/ExecutionStack/Internal.hsc
- libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/Error.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/String.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/C/String/Encoding.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/ForeignPtr/Imp.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Alloc.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Array.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Error.hs
- libraries/ghc-internal/src/GHC/Internal/Foreign/Marshal/Utils.hs
- libraries/ghc-internal/src/GHC/Internal/ForeignPtr.hs
- libraries/ghc-internal/src/GHC/Internal/ForeignSrcLang.hs
- libraries/ghc-internal/src/GHC/Internal/Functor/ZipList.hs
- libraries/ghc-internal/src/GHC/Internal/GHCi/Helpers.hs
- libraries/ghc-internal/src/GHC/Internal/Heap/InfoTable.hsc
- libraries/ghc-internal/src/GHC/Internal/Heap/InfoTable/Types.hsc
- libraries/ghc-internal/src/GHC/Internal/Heap/InfoTableProf.hsc
- libraries/ghc-internal/src/GHC/Internal/IO/Buffer.hs
- libraries/ghc-internal/src/GHC/Internal/IO/BufferedIO.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/Failure.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/Iconv.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Encoding/Types.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Exception.hs
- libraries/ghc-internal/src/GHC/Internal/IO/FD.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/FD.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Internals.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Lock/Flock.hsc
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Lock/LinuxOFD.hsc
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Text.hs
- libraries/ghc-internal/src/GHC/Internal/IO/Handle/Types.hs
- libraries/ghc-internal/src/GHC/Internal/InfoProv/Types.hsc
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags.hsc
- libraries/ghc-internal/src/GHC/Internal/RTS/Flags/Test.hsc
- libraries/ghc-internal/src/GHC/Internal/Stack/CCS.hsc
- libraries/ghc-internal/src/GHC/Internal/Stack/CloneStack.hs
- libraries/ghc-internal/src/GHC/Internal/Stack/Decode.hs
- libraries/ghc-internal/src/GHC/Internal/StaticPtr.hs
- libraries/ghc-internal/src/GHC/Internal/Stats.hsc
- libraries/ghc-internal/src/GHC/Internal/System/Environment.hs
- libraries/ghc-internal/src/GHC/Internal/System/Environment/Blank.hsc
- libraries/ghc-internal/src/GHC/Internal/System/Environment/ExecutablePath.hsc
- libraries/ghc-internal/src/GHC/Internal/System/IO.hs
- libraries/ghc-internal/src/GHC/Internal/System/IO/Error.hs
- libraries/ghc-internal/src/GHC/Internal/System/Posix/Internals.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lib.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Lift.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
- libraries/ghc-internal/src/GHC/Internal/TopHandler.hs
- libraries/ghc-internal/src/GHC/Internal/Unicode/Version.hs
- libraries/ghc-internal/src/GHC/Internal/Weak/Finalize.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/62767da4ba792c1665f70ae5ef3eb5b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/62767da4ba792c1665f70ae5ef3eb5b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Teo Camarasu pushed new branch wip/T26913 at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/T26913
You're receiving this email because of your account on gitlab.haskell.org.
1
0