diff options
| author | Andrew Martin <andrew.thaddeus@gmail.com> | 2019-11-13 11:20:05 -0500 |
|---|---|---|
| committer | Marge Bot <ben+marge-bot@smart-cactus.org> | 2020-05-23 13:37:01 -0400 |
| commit | 49301ad6226d9a83d110bee8c419615dd94f5ded (patch) | |
| tree | 907c00e2c81d1f2025ad569cedf2bc39833bcb07 /compiler/GHC/Core | |
| parent | d830bbc9921bcc59164a0a18f0e0874ae4ce226e (diff) | |
| download | haskell-49301ad6226d9a83d110bee8c419615dd94f5ded.tar.gz | |
Implement cstringLength# and FinalPtr
This function and its accompanying rule resolve issue #5218.
A future PR to the bytestring library will make the internal
Data.ByteString.Internal.unsafePackAddress compute string length
with cstringLength#. This will improve the status quo because it is
eligible for constant folding.
Additionally, introduce a new data constructor to ForeignPtrContents
named FinalPtr. This additional data constructor, when used in the
IsString instance for ByteString, leads to more Core-to-Core
optimization opportunities, fewer runtime allocations, and smaller
binaries.
Also, this commit re-exports all the functions from GHC.CString
(including cstringLength#) in GHC.Exts. It also adds a new test
driver. This test driver is used to perform substring matches on Core
that is dumped after all the simplifier passes. In this commit, it is
used to check that constant folding of cstringLength# works.
Diffstat (limited to 'compiler/GHC/Core')
| -rw-r--r-- | compiler/GHC/Core/Opt/ConstantFold.hs | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/compiler/GHC/Core/Opt/ConstantFold.hs b/compiler/GHC/Core/Opt/ConstantFold.hs index 7c18f27003..65c9ed3896 100644 --- a/compiler/GHC/Core/Opt/ConstantFold.hs +++ b/compiler/GHC/Core/Opt/ConstantFold.hs @@ -66,6 +66,7 @@ import qualified Data.ByteString as BS import Data.Int import Data.Ratio import Data.Word +import Data.Maybe (fromMaybe) {- Note [Constant folding] @@ -1257,6 +1258,8 @@ builtinRules ru_nargs = 4, ru_try = match_append_lit }, BuiltinRule { ru_name = fsLit "EqString", ru_fn = eqStringName, ru_nargs = 2, ru_try = match_eq_string }, + BuiltinRule { ru_name = fsLit "CStringLength", ru_fn = cstringLengthName, + ru_nargs = 1, ru_try = match_cstring_length }, BuiltinRule { ru_name = fsLit "Inline", ru_fn = inlineIdName, ru_nargs = 2, ru_try = \_ _ _ -> match_inline }, BuiltinRule { ru_name = fsLit "MagicDict", ru_fn = idName magicDictId, @@ -1477,6 +1480,30 @@ match_eq_string _ id_unf _ match_eq_string _ _ _ _ = Nothing +----------------------------------------------------------------------- +-- Illustration of this rule: +-- +-- cstringLength# "foobar"# --> 6 +-- cstringLength# "fizz\NULzz"# --> 4 +-- +-- Nota bene: Addr# literals are suffixed by a NUL byte when they are +-- compiled to read-only data sections. That's why cstringLength# is +-- well defined on Addr# literals that do not explicitly have an embedded +-- NUL byte. +-- +-- See GHC issue #5218, MR 2165, and bytestring PR 191. This is particularly +-- helpful when using OverloadedStrings to create a ByteString since the +-- function computing the length of such ByteStrings can often be constant +-- folded. +match_cstring_length :: RuleFun +match_cstring_length env id_unf _ [lit1] + | Just (LitString str) <- exprIsLiteral_maybe id_unf lit1 + -- If elemIndex returns Just, it has the index of the first embedded NUL + -- in the string. If no NUL bytes are present (the common case) then use + -- full length of the byte string. + = let len = fromMaybe (BS.length str) (BS.elemIndex 0 str) + in Just (Lit (mkLitInt (roPlatform env) (fromIntegral len))) +match_cstring_length _ _ _ _ = Nothing --------------------------------------------------- -- The rule is this: |
