diku-dk / futhark

:boom::computer::boom: A data-parallel functional programming language
http://futhark-lang.org
ISC License
2.38k stars 165 forks source link

Futhark does not run with GHC 9.8 #2105

Closed athas closed 6 months ago

athas commented 7 months ago

It fails with a <<loop>> error attributed to a CAF. In GHC lingo, a CAF is essentially a top level constant, but it does not necessarily correspond to a syntactic constant in the original program: a common source of CAFs is type class instance dictionary definitions. In particular, it can occur when such dictionaries are circular. I think GHC should statically rule out such cases, but there may be bugs in its checker. It's also possible that we are doing something wrong - we certainly have some very intricate instances, and as #1832 documents, we already did so something naughty once. By enabling profiling and passing -fprof-cafs to treat all CAFs as distinct (normally they are a single cost centre), I can cajole GHC into providing this error:

  Futhark.IR.SOACS.CAF:$fCheckableSOACS11
  --> evaluated by: Futhark.IR.SOACS.CAF:$fCheckableSOACS12
  --> evaluated by: Futhark.IR.SOACS.CAF:$fCheckableSOACS11
  --> evaluated by: Futhark.IR.SOACS.CAF:$fCheckableSOACS12
  --> evaluated by: Futhark.IR.SOACS.CAF:$fCheckableSOACS11

Checkable is a type class defined by the type checker and implemented in Futhark.IR.SOACS, and the problem certainly occurs at a point in the compilation pipeline when type checking may happen.

I don't have the time to investigate more right now, but obviously we need to ensure Futhark will work with GHC 9.8. If we're lucky, this is a known GHC bug that will be fixed with 9.8.2. If we're unlucky, it's a new GHC bug and we will have to try to cut down the entire compiler to a minimal example.

athas commented 6 months ago

I suspect the cause is the following circularity. In Futhark.IR.SOACS.SOAC there is an instance

instance (Aliased rep) => AliasedOp (SOAC rep) where

and in Futhark.IR.Aliases there is an instance

instance (ASTRep rep, AliasedOp (OpC rep (Aliases rep))) => Aliased (Aliases rep) where

where OpC SOACS (Aliases SOACS) is a type family application that resolves to SOAC (Aliases SOACS), meaning we get an instance context AliasedOp (SOAC (Aliases SOACS)).

But I have no clue how to fix it, or why this is even a problem.

The above is inspired by some refactoring that enabled me to get this stack trace:

*** Exception (reporting due to +RTS -xc): (THUNK_STATIC), stack trace:
  Futhark.IR.SOACS.CAF:$dAliasedOp_rnD9v
  --> evaluated by: Futhark.IR.SOACS.CAF:$fCheckableAliases2
  --> evaluated by: Futhark.IR.SOACS.CAF:$dAliasedOp_rnD9v
  --> evaluated by: Futhark.IR.SOACS.CAF:$fCheckableAliases2
  --> evaluated by: Futhark.IR.SOACS.CAF:$dAliasedOp_rnD9v
athas commented 6 months ago

Relevant core (slightly different names from a different build):

Rec {
-- RHS size: {terms: 2, types: 2, coercions: 0, joins: 0/0}
$dAliasedOp_rnup4 :: AliasedOp (SOAC (Aliases SOACS))
[GblId]
$dAliasedOp_rnup4
  = Futhark.IR.SOACS.SOAC.$fAliasedOpSOAC
      @(Aliases SOACS) Futhark.IR.SOACS.$fCheckableAliases2

-- RHS size: {terms: 3, types: 1, coercions: 5, joins: 0/0}
Futhark.IR.SOACS.$fCheckableAliases2 [Occ=LoopBreaker]
  :: Aliased (Aliases SOACS)
[GblId]
Futhark.IR.SOACS.$fCheckableAliases2
  = Futhark.IR.Aliases.$fAliasedAliases
      @SOACS
      Futhark.IR.SOACS.$fASTRepSOACS
      ($dAliasedOp_rnup4
       `cast` ((AliasedOp
                  (Sym (Futhark.IR.SOACS.D:R:OpCSOACS[0]) <Aliases SOACS>_N))_R
               :: AliasedOp (SOAC (Aliases SOACS))
                  ~R# AliasedOp (OpC SOACS (Aliases SOACS))))
end Rec }