packages feed

futhark 0.7.3 → 0.7.4

raw patch · 7 files changed

+327/−75 lines, 7 filesdep +aesondep −jsondep ~base

Dependencies added: aeson

Dependencies removed: json

Dependency ranges changed: base

Files

futhark.cabal view
@@ -2,10 +2,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 3b4f60b44c2ac9e9de368d6116299bafb8b535f9a6ae7a26613bca65b22ad1d9+-- hash: 27326a3d0b5daec736d8b0de8fda5938beaf2ee6e75215a5cfb6a29b1008afb0  name:           futhark-version:        0.7.3+version:        0.7.4 synopsis:       An optimising compiler for a functional, array-oriented language. description:    See the website at https://futhark-lang.org category:       Language@@ -36,6 +36,7 @@     rts/csharp/panic.cs     rts/csharp/reader.cs     rts/csharp/scalar.cs+    rts/futhark-doc/style.css     rts/python/__init__.py     rts/python/memory.py     rts/python/opencl.py@@ -312,7 +313,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -333,7 +335,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -370,7 +371,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -391,7 +393,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -428,7 +429,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -449,7 +451,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -486,7 +487,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -507,7 +509,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -544,7 +545,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -565,7 +567,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -602,7 +603,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -623,7 +625,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -660,7 +661,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -681,7 +683,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -718,7 +719,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -739,7 +741,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -776,7 +777,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -797,7 +799,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -834,7 +835,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -855,7 +857,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -892,7 +893,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -913,7 +915,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16@@ -950,7 +951,8 @@       Paths_futhark   ghc-options: -Wall -Wcompat -Wredundant-constraints -Wincomplete-record-updates -Wmissing-export-lists -threaded -rtsopts "-with-rtsopts=-N -qg"   build-depends:-      ansi-terminal >=0.6.3.1+      aeson+    , ansi-terminal >=0.6.3.1     , array >=0.4     , base >=4 && <5     , bifunctors >=5.4.2@@ -971,7 +973,6 @@     , http-client >=0.5.7.0     , http-client-tls >=0.3.5.1     , http-conduit >=2.2.4-    , json     , language-c-quote >=0.12     , mainland-pretty >=0.6.1     , markdown >=0.1.16
+ rts/futhark-doc/style.css view
@@ -0,0 +1,226 @@+body {+    background-color: #fff9e5;+    font-family: sans-serif;+    padding: 0px;+    margin: 0px;+    margin-top: 0em;+    margin-left: 0em;+    margin-right: 0em;+    overflow-y: scroll;+    line-height: 1.4;+}++h1 {+    margin-top: 0;+    display: inline;+}++h2 {+    margin-bottom: 1ex;+    font-size: 2em;+    color: #5f021f;+}++h3 {+    font-size: 1em;+    color: #5f021f;+}++p {+    max-width: 65em;+}++td {+    vertical-align: top;+}++#header {+    color: #fff9e5;+    background: #5f0220;+    padding-left: 1em;+}++#navigation {+    float: right;+    vertical-align: centre;+}++#navigation ol {+    display: block;+}++#navigation li {+  display: inline;+  list-style-type: none;+  border-left: 1px solid #fff9e5;+  padding-left: 1em;+  padding-right: 1em;+}++#navigation a, #navigation a:visited {+    color: #fff9e5;+    text-decoration: none;+}++#content {+    display: flex;+}++main {+    padding-left: 1em;+    padding-right: 1em;+    width: 100%;+}++#abstract {+    margin-bottom: 2ex;+}++#footer {+    color: #fff9e5;+    background: #5f0220;+    padding-left: 1em;+    padding-right: 1em;+}++#footer a, #footer a:visited {+    color: #fff9e5;+}++@media (max-width:950px) {+    #filenav {+        display: none;+    }+}++#filenav {+    color: #fff9e5;+    background: #5f0220;+    padding-left: 1em;+    padding-right: 1em;+}++#filenav a:hover {+    background: #fff9e5;+    display: block;+    color: #5f0220;+}++#filenav a, #footer a:visited {+    color: #fff9e5;+    text-decoration: none;+}++#filenav > ul {+    list-style: none;+    padding: 0;+    font-family: monospace;+    font-weight: bold;+}++.file_desc {+    /* Hack to avoid breaking a file description across multiple columns+       on the contents page. */+    display: table;+    width: 100%;+}++@media (min-width:950px) {+    .file_list {+        columns: 3;+    }++    .file_list > dd {+        break-before: avoid;+    }+}++.keyword {+    font-weight: bold;+}++.specs {+    margin-left: 2ex;+    border-collapse: collapse;+}++.specs tr:hover td {+    background: #ccc;+}++.spec_eql {+    text-align: right;+}++.decl_description {+    margin-bottom: 2ex;+}++.decl_name {+    font-weight: bold;+}++.desc_header {+    background: #ffcc7a;+    font-family: monospace;+    border-top: 1px solid #5f021f;+}++.desc_doc {+    margin-left: 2ex;+}++.synopsis_link {+    font-weight: bold;+    text-decoration: none;+    font-size: 1.3em;+    width: 2ex;+    display: inline-block;+}++.self_link {+    text-decoration: none;+}++#module {+    font-family: monospace;+    white-space: pre;+    display: block;+    unicode-bidi: embed;+}++#doc_index thead {+    font-weight: bold;+}++#doc_index td {+    padding-right: 1em;+}++.doc_index_name {+    font-family: monospace;+}++.doc_index_namespace {+    font-style: italic;+}++.doc_index_initial {+    font-size: 2em;+    font-weight: bold;+}++.doc_index_initial a, .doc_index_initial a:visited {+    color: #5f0220;+}++#doc_index_list li {+  display: inline;+  list-style-type: none;+  padding-right: 1em;+}++#doc_index_list a, #doc_index_list a:visited {+    color: #5f0220;+    text-decoration: none;+}
src/Futhark/CodeGen/ImpGen/Kernels/ToOpenCL.hs view
@@ -580,10 +580,10 @@ transposeKernelAndGroupSize :: ImpOpenCL.Exp -> ImpOpenCL.Exp -> ImpOpenCL.Exp                             -> ([ImpOpenCL.Exp], [ImpOpenCL.Exp]) transposeKernelAndGroupSize num_arrays x_elems y_elems =-  ([x_elems `roundUpTo` transposeBlockDim ,-    y_elems `roundUpTo` transposeBlockDim,+  ([(x_elems `roundUpTo` transposeBlockDim) *+    (y_elems `roundUpTo` transposeBlockDim) *     num_arrays],-   [transposeBlockDim, transposeBlockDim, 1])+   [transposeBlockDim * transposeBlockDim])  roundUpTo :: ImpOpenCL.Exp -> ImpOpenCL.Exp -> ImpOpenCL.Exp roundUpTo x y = x + ((y - (x `impRem` y)) `impRem` y)
src/Futhark/CodeGen/OpenCL/Kernels.hs view
@@ -89,37 +89,44 @@   case transpose_type of     TransposeNormal ->       bigKernel []-      [C.cexp|get_global_id(0)|]-      [C.cexp|get_global_id(1)|]-      [C.cexp|get_group_id(1) * FUT_BLOCK_DIM + get_local_id(0)|]-      [C.cexp|get_group_id(0) * FUT_BLOCK_DIM + get_local_id(1)|]+      [C.cexp|global_id_x|]+      [C.cexp|global_id_y|]+      [C.cexp|group_id_y * FUT_BLOCK_DIM + local_id_x|]+      [C.cexp|group_id_x * FUT_BLOCK_DIM + local_id_y|]+      (toNumGroups [C.cexp|width|])+      (toNumGroups [C.cexp|height|])     TransposeLowWidth ->       bigKernel [C.cparams|uint muly|]-      [C.cexp|get_group_id(0) * FUT_BLOCK_DIM + (get_local_id(0) / muly)|]-      [C.cexp|get_group_id(1) * FUT_BLOCK_DIM * muly-           + get_local_id(1)-           + (get_local_id(0) % muly) * FUT_BLOCK_DIM+      [C.cexp|group_id_x * FUT_BLOCK_DIM + (local_id_x / muly)|]+      [C.cexp|group_id_y * FUT_BLOCK_DIM * muly+           + local_id_y+           + (local_id_x % muly) * FUT_BLOCK_DIM           |]-      [C.cexp|get_group_id(1) * FUT_BLOCK_DIM * muly-           + get_local_id(0)-           + (get_local_id(1) % muly) * FUT_BLOCK_DIM|]-      [C.cexp|get_group_id(0) * FUT_BLOCK_DIM + (get_local_id(1) / muly)|]+      [C.cexp|group_id_y * FUT_BLOCK_DIM * muly+           + local_id_x+           + (local_id_y % muly) * FUT_BLOCK_DIM|]+      [C.cexp|group_id_x * FUT_BLOCK_DIM + (local_id_y / muly)|]+      (toNumGroups [C.cexp|width|])+      (toNumGroups [C.cexp|(height + muly - 1) / muly|])     TransposeLowHeight ->       bigKernel [C.cparams|uint mulx|]-      [C.cexp|get_group_id(0) * FUT_BLOCK_DIM * mulx-           + get_local_id(0)-           + (get_local_id(1) % mulx) * FUT_BLOCK_DIM+      [C.cexp|group_id_x * FUT_BLOCK_DIM * mulx+           + local_id_x+           + (local_id_y % mulx) * FUT_BLOCK_DIM           |]-      [C.cexp|get_group_id(1) * FUT_BLOCK_DIM + (get_local_id(1) / mulx)|]-      [C.cexp|get_group_id(1) * FUT_BLOCK_DIM + (get_local_id(0) / mulx)|]-      [C.cexp|get_group_id(0) * FUT_BLOCK_DIM * mulx-           + get_local_id(1)-           + (get_local_id(0) % mulx) * FUT_BLOCK_DIM+      [C.cexp|group_id_y * FUT_BLOCK_DIM + (local_id_y / mulx)|]+      [C.cexp|group_id_y * FUT_BLOCK_DIM + (local_id_x / mulx)|]+      [C.cexp|group_id_x * FUT_BLOCK_DIM * mulx+           + local_id_y+           + (local_id_x % mulx) * FUT_BLOCK_DIM            |]+      (toNumGroups [C.cexp|(width + mulx - 1) / mulx|])+      (toNumGroups [C.cexp|height|])     TransposeSmall ->       smallKernel   where-    bigKernel extraparams x_in_index y_in_index x_out_index y_out_index =+    toNumGroups e = [C.cexp|($exp:e + FUT_BLOCK_DIM - 1) / FUT_BLOCK_DIM|]+    bigKernel extraparams x_in_index y_in_index x_out_index y_out_index ngrpx ngrpy =       [C.cfun|        // This kernel is optimized to ensure all global reads and writes are coalesced,        // and to avoid bank conflicts in shared memory.  The shared memory array is sized@@ -129,6 +136,21 @@        // Note that input_size/output_size may not equal width*height if we are dealing with        // a truncated array - this happens sometimes for coalescing optimisations.        __kernel void $id:kernel_name($params:params) {+         uint num_groups_y = $exp:ngrpy;+         uint num_groups_x = $exp:ngrpx;+         uint num_groups_z = ((uint)get_num_groups(0)) /  (num_groups_y * num_groups_x);++         uint local_id_y = ((uint)get_local_id(0)) / FUT_BLOCK_DIM;+         uint local_id_x = ((uint)get_local_id(0)) % FUT_BLOCK_DIM;+         uint group_id_z = ((uint)get_group_id(0)) / (num_groups_y * num_groups_x);+         uint group_id_yx = ((uint)get_group_id(0)) % (num_groups_y * num_groups_x);+         uint group_id_y = group_id_yx / num_groups_x;+         uint group_id_x = group_id_yx % num_groups_x;++         uint global_id_z = group_id_z;+         uint global_id_y = group_id_y * FUT_BLOCK_DIM + local_id_y;+         uint global_id_x = group_id_x * FUT_BLOCK_DIM + local_id_x;+          uint x_index;          uint y_index;          uint our_array_offset;@@ -138,7 +160,7 @@          idata += idata_offset/sizeof($ty:elem_type);           // Adjust the input and output arrays for the third dimension.-         our_array_offset = get_global_id(2) * width * height;+         our_array_offset = global_id_z * width * height;          odata += our_array_offset;          idata += our_array_offset; @@ -150,7 +172,7 @@           if(x_index < width && y_index < height && index_in < input_size)          {-             block[get_local_id(1)*(FUT_BLOCK_DIM+1)+get_local_id(0)] = idata[index_in];+             block[local_id_y*(FUT_BLOCK_DIM+1)+local_id_x] = idata[index_in];          }           barrier(CLK_LOCAL_MEM_FENCE);@@ -163,7 +185,7 @@           if(x_index < height && y_index < width && index_out < output_size)          {-             odata[index_out] = block[get_local_id(0)*(FUT_BLOCK_DIM+1)+get_local_id(1)];+             odata[index_out] = block[local_id_x*(FUT_BLOCK_DIM+1)+local_id_y];          }        }|]            where params = [C.cparams|__global $ty:elem_type *odata,@@ -205,4 +227,4 @@            if (get_global_id(0) < input_size) {                odata[index_out] = idata[index_in];            }-         }|]+}|]
src/Futhark/Internalise/Defunctionalise.hs view
@@ -451,9 +451,12 @@       return ([], e, sv) defuncLet _ [] body (Info rettype) = do   (body', sv) <- defuncExp body-  case sv of-    Dynamic _ -> return ([], body', Dynamic $ fromStruct $ removeShapeAnnotations rettype)-    _         -> return ([], body', sv)+  return ([], body', imposeType sv rettype )+  where imposeType Dynamic{} t =+          Dynamic $ fromStruct $ removeShapeAnnotations t+        imposeType (RecordSV fs1) (Record fs2) =+          RecordSV $ M.toList $ M.intersectionWith imposeType (M.fromList fs1) fs2+        imposeType sv _ = sv  -- | Defunctionalize an application expression at a given depth of application. -- Calls to dynamic (first-order) functions are preserved at much as possible,@@ -476,7 +479,7 @@        -- Inline certain trivial lifted functions immediately.  This is       -- purely an optimisation to avoid having the rest of the-      -- compiler spend a lot if time processing them (they will end+      -- compiler spend a lot of time processing them (they will end       -- up being inlined later anyway).  We also try to simplify away       -- some let-bindings, to make the generated code look slightly       -- more comprehensible.
src/Language/Futhark/Parser/Parser.y view
@@ -277,10 +277,10 @@       : val id TypeParams ':' TypeExpDecl         { let L loc (ID name) = $2           in ValSpec name $3 $5 Nothing (srcspan $1 $>) }-      | val BindingBinOp ':' TypeExpDecl-        { ValSpec $2 [] $4 Nothing (srcspan $1 $>) }-      | val BindingUnOp ':' TypeExpDecl-        { ValSpec $2 [] $4 Nothing (srcspan $1 $>) }+      | val BindingBinOp TypeParams ':' TypeExpDecl+        { ValSpec $2 $3 $5 Nothing (srcspan $1 $>) }+      | val BindingUnOp TypeParams ':' TypeExpDecl+        { ValSpec $2 $3 $5 Nothing (srcspan $1 $>) }       | TypeAbbr         { TypeAbbrSpec $1 }       | type id TypeParams
src/futhark-bench.hs view
@@ -14,6 +14,7 @@ import Data.Maybe import Data.Semigroup ((<>)) import Data.List+import qualified Data.Map as M import qualified Data.Text as T import qualified Data.Text.IO as T import qualified Data.Text.Encoding as T@@ -25,7 +26,7 @@ import System.Timeout import System.Process.ByteString (readProcessWithExitCode) import System.Exit-import qualified Text.JSON as JSON+import qualified Data.Aeson as JSON import Text.Printf import Text.Regex.TDFA @@ -56,24 +57,23 @@ data DataResult = DataResult String (Either T.Text ([RunResult], T.Text)) data BenchResult = BenchResult FilePath [DataResult] -resultsToJSON :: [BenchResult] -> JSON.JSValue-resultsToJSON = JSON.JSObject . JSON.toJSObject . map benchResultToJSObject+resultsToJSON :: [BenchResult] -> JSON.Value+resultsToJSON = JSON.toJSON . M.fromList . map benchResultToJSObject   where benchResultToJSObject           :: BenchResult-          -> (String, JSON.JSValue)+          -> (String, JSON.Value)         benchResultToJSObject (BenchResult prog rs) =-          (prog, JSON.JSObject $ JSON.toJSObject-                 [("datasets", JSON.JSObject $ JSON.toJSObject $-                               map dataResultToJSObject rs)])+          (prog, JSON.toJSON $ M.fromList+                 [("datasets" :: String, M.fromList $ map dataResultToJSObject rs)])         dataResultToJSObject           :: DataResult-          -> (String, JSON.JSValue)+          -> (String, JSON.Value)         dataResultToJSObject (DataResult desc (Left err)) =-          (desc, JSON.showJSON err)+          (desc, JSON.toJSON $ show err)         dataResultToJSObject (DataResult desc (Right (runtimes, progerr))) =-          (desc, JSON.JSObject $ JSON.toJSObject-                 [("runtimes", JSON.showJSON $ map runMicroseconds runtimes),-                  ("stderr", JSON.showJSON progerr)])+          (desc, JSON.toJSON $ M.fromList+                 [("runtimes" :: String, JSON.toJSON $ map runMicroseconds runtimes),+                  ("stderr", JSON.toJSON $ show progerr)])  fork :: (a -> IO b) -> a -> IO (MVar b) fork f x = do cell <- newEmptyMVar@@ -107,7 +107,7 @@   results <- concat <$> mapM (runBenchmark opts) compiled_benchmarks   case optJSON opts of     Nothing -> return ()-    Just file -> writeFile file $ JSON.encode $ resultsToJSON results+    Just file -> LBS.writeFile file $ JSON.encode $ resultsToJSON results   when (anyFailed results) exitFailure    where ignored f = any (`match` f) $ optIgnoreFiles opts