Note [ANF-ising literal string arguments]
Consider a Core program like,
data Foo = Foo Addr#
foo = Foo "turtle"#
String literals are non-trivial, see 'GHC.Types.Literal.litIsTrivial', hence
they are non-atomic in STG.
With -O1, FloatOut is likely to have floated most of these strings to top-level,
not least to give CSE a chance to deduplicate strings early (before the
linker, that is).
(Notable exceptions seem to be applications of 'unpackAppendCString#'.)
But with -O0, there is no FloatOut, so CorePrep must do the ANFisation to
s = "turtle"#
foo = Foo s
(String literals are the only kind of binding allowed at top-level and hence
their `FloatInfo` is `TopLvlFloatable`.)
This appears to lead to bad code if the arg is under a lambda, because CorePrep
doesn't float out of RHSs, e.g., (T23270)
foo x = ... patError "turtle"# ...
==> foo x = ... case "turtle"# of s { __DEFAULT -> petError s } ...
This looks bad because it evals an HNF on every call.
But actually, it doesn't, because "turtle"# is already an HNF. Here is the Cmm:
[section ""cstring" . cB4_str" {
cB4_str:
I8[] "turtle"
}
...
_sAG::I64 = cB4_str;
R2 = _sAG::I64;
Sp = Sp + 8;
call Control.Exception.Base.patError_info(R2) args: 8, res: 0, upd: 8;
Wrinkles:
(FS1) We detect string literals in `cpeBind Rec{}` and float them out anyway;
otherwise we'd try to bind a string literal in a letrec, violating
Note [Core letrec invariant]. Since we know that literals don't have
free variables, we float further.
Arguably, we could just as well relax the letrec invariant for
string literals, or anthing that is a value (lifted or not).
This is tracked in #24036. References 1
- Core letrec invariant GHC.Core
Referenced by 2
- GHC.CoreToStg.Prep call site ×2