Simon Jakobi pushed to branch wip/sjakobi/T18922-filecheck-llvm-poc at Glasgow Haskell Compiler / GHC

Commits:

8 changed files:

Changes:

  • configure.ac
    ... ... @@ -583,6 +583,20 @@ FIND_LLVM_PROG([LLVMAS], [clang], [$LlvmMinVersion], [$LlvmMaxVersion])
    583 583
     LlvmAsCmd="$LLVMAS"
    
    584 584
     AC_SUBST([LlvmAsCmd])
    
    585 585
     
    
    586
    +dnl ** Which LLVM FileCheck to use? (testsuite only)
    
    587
    +dnl --------------------------------------------------------------
    
    588
    +# CQ[filecheck-version-range]
    
    589
    +# Q: FileCheck is independent of the LLVM backend, so why the backend's
    
    590
    +#    LlvmMaxVersion as the upper bound, and what fixes the floor at 12?
    
    591
    +# A~ FIND_LLVM_PROG needs a finite range to enumerate the suffixed names
    
    592
    +#    (FileCheck-NN, FileCheckNN). The testsuite passes
    
    593
    +#    --allow-unused-prefixes, which appeared in LLVM 12.
    
    594
    +FileCheckMinVersion=12  # inclusive
    
    595
    +AC_ARG_VAR(FILECHECK,[Use as the path to LLVM's FileCheck, for the testsuite [default=autodetect]])
    
    596
    +FIND_LLVM_PROG([FILECHECK], [FileCheck], [$FileCheckMinVersion], [$LlvmMaxVersion])
    
    597
    +FileCheckCmd="$FILECHECK"
    
    598
    +AC_SUBST([FileCheckCmd])
    
    599
    +
    
    586 600
     dnl --------------------------------------------------------------
    
    587 601
     dnl End of configure script option section
    
    588 602
     dnl --------------------------------------------------------------
    
    ... ... @@ -1077,7 +1091,8 @@ echo "\
    1077 1091
           llc          : $LlcCmd
    
    1078 1092
           opt          : $OptCmd
    
    1079 1093
           llvm-as      : $LlvmAsCmd
    
    1080
    -      llvm-dlltool : $DlltoolCmd"
    
    1094
    +      llvm-dlltool : $DlltoolCmd
    
    1095
    +      FileCheck    : $FileCheckCmd"
    
    1081 1096
     
    
    1082 1097
     if test "$HSCOLOUR" = ""; then
    
    1083 1098
     echo "
    

  • hadrian/cfg/system.config.in
    ... ... @@ -23,6 +23,7 @@ makeinfo = @MAKEINFO@
    23 23
     bourne-shell   = @SH@
    
    24 24
     git            = @GIT@
    
    25 25
     cabal          = @CABAL@
    
    26
    +filecheck      = @FileCheckCmd@
    
    26 27
     
    
    27 28
     # Python 3 is required to run test driver.
    
    28 29
     # See: https://github.com/ghc/ghc/blob/master/testsuite/mk/boilerplate.mk#L220
    

  • hadrian/src/Oracles/Setting.hs
    ... ... @@ -62,6 +62,7 @@ data ProjectSetting =
    62 62
                  | HostPlatformFull
    
    63 63
                  | BourneShell
    
    64 64
                  | EmsdkVersion
    
    65
    +             | FileCheck
    
    65 66
     
    
    66 67
     -- | Things which configure how a specific stage is built
    
    67 68
     data BuildSetting =
    
    ... ... @@ -105,6 +106,7 @@ setting key = lookupSystemConfig $ case key of
    105 106
         HostPlatformFull   -> "host-platform-full"
    
    106 107
         BourneShell        -> "bourne-shell"
    
    107 108
         EmsdkVersion       -> "emsdk-version"
    
    109
    +    FileCheck          -> "filecheck"
    
    108 110
     
    
    109 111
     buildSetting :: BuildSetting -> Stage -> Action String
    
    110 112
     buildSetting key stage = tgtConfig stage $ case key of
    

  • hadrian/src/Settings/Builders/RunTest.hs
    ... ... @@ -238,6 +238,7 @@ runTestBuilderArgs = builder Testsuite ? do
    238 238
         (testEnv, testMetricsFile) <- expr . liftIO $
    
    239 239
             (,) <$> lookupEnv "TEST_ENV" <*> lookupEnv "METRICS_FILE"
    
    240 240
         perfBaseline <- expr . liftIO $ lookupEnv "PERF_BASELINE_COMMIT"
    
    241
    +    filecheck <- expr $ setting FileCheck
    
    241 242
         targetWrapper <- expr . liftIO $ lookupEnv "CROSS_EMULATOR"
    
    242 243
     
    
    243 244
         threads     <- shakeThreads <$> expr getShakeOptions
    
    ... ... @@ -282,6 +283,7 @@ runTestBuilderArgs = builder Testsuite ? do
    282 283
                 , arg "-e", arg $ "config.package_conf_cache_file=" ++ show pkgConfCacheFile
    
    283 284
     
    
    284 285
                 , arg "-e", arg $ "config.libdir=" ++ show libdir
    
    286
    +            , arg "-e", arg $ "config.filecheck=" ++ show filecheck
    
    285 287
     
    
    286 288
     
    
    287 289
                 , arg "-e", arg $ "config.have_interp=" ++ show withInterpreter
    

  • testsuite/driver/testglobals.py
    ... ... @@ -129,9 +129,9 @@ class TestConfig:
    129 129
             # Do we have a functional LLVM toolchain?
    
    130 130
             self.have_llvm = False
    
    131 131
     
    
    132
    -        # LLVM's FileCheck, for filecheck_stderr and filecheck_stdout
    
    133
    -        # (None: look for it when first needed, see find_filecheck)
    
    134
    -        self.filecheck = None # type: Optional[str]
    
    132
    +        # LLVM's FileCheck as found by configure, for filecheck_stderr and
    
    133
    +        # filecheck_stdout (empty: none found, see find_filecheck)
    
    134
    +        self.filecheck = ''
    
    135 135
     
    
    136 136
             # Do we have vanilla libraries?
    
    137 137
             self.have_vanilla = False
    

  • testsuite/driver/testlib.py
    ... ... @@ -1295,30 +1295,18 @@ def _filecheck(name, opts, kind, check_file, prefixes):
    1295 1295
         #    have_llvm() tests merely skip; is loud right for a tool only some
    
    1296 1296
         #    tests need?
    
    1297 1297
         if find_filecheck() is None:
    
    1298
    -        framework_fail(name, None, 'FileCheck not found: set FILECHECK or '
    
    1299
    -                       'config.filecheck, or run testsuite/driver/build_filecheck.py')
    
    1298
    +        framework_fail(name, None, 'FileCheck not found: pass FILECHECK=... to '
    
    1299
    +                       'configure, or run testsuite/driver/build_filecheck.py')
    
    1300 1300
             opts.skip = True
    
    1301 1301
         opts.filecheck[kind] = (name, check_file, prefixes or ['CHECK'])
    
    1302 1302
     
    
    1303
    -# CQ[filecheck-discovery]
    
    1304
    -# Q: should configure find FileCheck like llc (FIND_LLVM_PROG) and hadrian
    
    1305
    -#    pass it as config.filecheck, instead of this search from the driver?
    
    1306
    -# CQ[filecheck-version-range]
    
    1307
    -# Q: the versioned names mirror configure's LlvmMinVersion..LlvmMaxVersion;
    
    1308
    -#    which FileCheck versions do the tests actually require?
    
    1309 1303
     def find_filecheck() -> Optional[str]:
    
    1310
    -    if config.filecheck is None:
    
    1311
    -        built = config.top.parent / '_build' / 'filecheck' / 'bin' / 'FileCheck'
    
    1312
    -        candidates = [os.environ.get('FILECHECK'), str(built), 'FileCheck'] \
    
    1313
    -                     + ['FileCheck-%d' % v for v in range(23, 12, -1)]
    
    1314
    -        for c in candidates:
    
    1315
    -            found = shutil.which(c) if c else None
    
    1316
    -            if found:
    
    1317
    -                config.filecheck = found
    
    1318
    -                break
    
    1319
    -        else:
    
    1320
    -            config.filecheck = ''
    
    1321
    -    return config.filecheck or None
    
    1304
    +    built = config.top.parent / '_build' / 'filecheck' / 'bin' / 'FileCheck'
    
    1305
    +    for c in [os.environ.get('FILECHECK'), str(built), config.filecheck]:
    
    1306
    +        found = shutil.which(c) if c else None
    
    1307
    +        if found:
    
    1308
    +            return found
    
    1309
    +    return None
    
    1322 1310
     
    
    1323 1311
     def no_check_hp(name, opts):
    
    1324 1312
         opts.check_hp = False
    

  • testsuite/filecheck.md
    ... ... @@ -17,7 +17,7 @@ Installing FileCheck
    17 17
     Without a `FileCheck` binary every test that uses it is reported as a
    
    18 18
     framework failure and skipped:
    
    19 19
     
    
    20
    -    FileCheck not found: set FILECHECK or config.filecheck, or run
    
    20
    +    FileCheck not found: pass FILECHECK=... to configure, or run
    
    21 21
         testsuite/driver/build_filecheck.py
    
    22 22
     
    
    23 23
     Any LLVM 12 or newer should do. The directives and the regex dialect have not
    
    ... ... @@ -30,32 +30,49 @@ supported LLVM version range.
    30 30
     
    
    31 31
     In this order, taking the first that exists:
    
    32 32
     
    
    33
    -1. `config.filecheck`, which nothing in configure or hadrian sets yet. It can
    
    34
    -   be set with `-e config.filecheck=...` when invoking `runtests.py`
    
    35
    -   directly.
    
    36
    -2. The `FILECHECK` environment variable, a path or a command name.
    
    37
    -3. `_build/filecheck/bin/FileCheck` in the GHC tree, where
    
    33
    +1. The `FILECHECK` environment variable at test time, a path or a command
    
    34
    +   name.
    
    35
    +2. `_build/filecheck/bin/FileCheck` in the GHC tree, where
    
    38 36
        `build_filecheck.py` installs to.
    
    39
    -4. `FileCheck` on `PATH`, then `FileCheck-23` down to `FileCheck-13`, the
    
    40
    -   names Debian-style packages use.
    
    37
    +3. What `./configure` found, passed as `config.filecheck` by hadrian and by
    
    38
    +   `make -C testsuite/tests`, which reads it from `hadrian/cfg/system.config`.
    
    39
    +   Configure searches `PATH` the way it does for `llc`: `FileCheck-23` down
    
    40
    +   to `FileCheck-12` (the Debian and Ubuntu names), `FileCheck23` down to
    
    41
    +   `FileCheck12` (the FreeBSD names), then plain `FileCheck`, and rejects a
    
    42
    +   version outside that range. `./configure FILECHECK=/path/to/FileCheck`
    
    43
    +   overrides the search, which is needed where the binary is not on `PATH`
    
    44
    +   (Alpine, Homebrew). The result is in configure's summary under "Using
    
    45
    +   LLVM tools".
    
    41 46
     
    
    42 47
     ### Distribution packages
    
    43 48
     
    
    44 49
     Checked against the package file lists or build recipes on 2026-11-05, not by
    
    45
    -installing each one.
    
    50
    +installing each one. Versions below LLVM 12 do not work (see above).
    
    46 51
     
    
    47
    -| System | Package | Binary | Found automatically? |
    
    52
    +| System | Package | Binary | Found by configure? |
    
    48 53
     | --- | --- | --- | --- |
    
    49
    -| Debian, Ubuntu | `llvm-NN-tools` | `/usr/bin/FileCheck-NN` | yes |
    
    54
    +| Debian 11+, Ubuntu 20.04+ | `llvm-NN-tools` | `/usr/bin/FileCheck-NN` | yes |
    
    55
    +| Debian 9, 10, Ubuntu 18.04 | `llvm-NN-tools` from [apt.llvm.org](https://apt.llvm.org) | `/usr/bin/FileCheck-NN` | yes |
    
    50 56
     | Fedora | `llvm` | `/usr/bin/FileCheck` | yes |
    
    57
    +| Rocky 8, 9 | `llvm` | `/usr/bin/FileCheck` | yes |
    
    58
    +| Alpine 3.16+ | `llvmNN-test-utils` | `/usr/lib/llvmNN/bin/FileCheck` | no, pass `FILECHECK=` |
    
    51 59
     | Arch | `llvm` | `/usr/bin/FileCheck` | yes |
    
    52
    -| Homebrew | `llvm` (keg-only) | `$(brew --prefix llvm)/bin/FileCheck` | no, set `FILECHECK` |
    
    60
    +| Homebrew | `llvm` or `llvm@NN` (keg-only) | `$(brew --prefix llvm)/bin/FileCheck` | no, pass `FILECHECK=` |
    
    53 61
     | Nix | `llvmPackages.llvm` | `bin/FileCheck` of that package | yes, once in `PATH` |
    
    54
    -| FreeBSD | `llvmNN` (`LIT` option, on by default) | `/usr/local/bin/FileCheckNN` | no, set `FILECHECK` |
    
    55
    -| MSYS2 | `mingw-w64-<env>-llvm` | `FileCheck.exe` in the environment's `bin` | yes, in that shell |
    
    62
    +| FreeBSD, DragonFly | `llvmNN` (`LIT` option, on by default) | `/usr/local/bin/FileCheckNN` | yes |
    
    63
    +| MSYS2 (all environments, including CLANGARM64) | `mingw-w64-<env>-llvm` | `FileCheck.exe` in the environment's `bin` | yes, in that shell |
    
    56 64
     
    
    57
    -Not checked: the official `clang+llvm-*` release bindists (which GHC's CI
    
    58
    -images install LLVM from) and LLVM's Windows installer.
    
    65
    +The Debian and Ubuntu packages exist for amd64, i386, arm64, armhf, ppc64el,
    
    66
    +s390x, riscv64 and loong64 (loong64 in unstable only).
    
    67
    +
    
    68
    +Sources that do **not** ship FileCheck, so use the build script below:
    
    69
    +
    
    70
    +- the official `clang+llvm-*` release tarballs and the LLVM Windows
    
    71
    +  installer, which are built without `LLVM_INSTALL_UTILS`
    
    72
    +- llvm-mingw
    
    73
    +- MacPorts `llvm-NN`
    
    74
    +- OpenBSD's `devel/llvm`, which removes it on purpose
    
    75
    +- Alpine 3.12 to 3.15, whose only `-test-utils` package is LLVM 10
    
    59 76
     
    
    60 77
     The Debian package is the cheapest route: it is a few hundred kB and does not
    
    61 78
     pull in the rest of LLVM. For example, on Ubuntu 24.04:
    

  • testsuite/mk/test.mk
    ... ... @@ -284,6 +284,15 @@ RUNTEST_OPTS += --config 'stats_files_dir=$(TOP)/tests/perf/haddock'
    284 284
     
    
    285 285
     RUNTEST_OPTS += -e "config.stage=$(GhcStage)"
    
    286 286
     
    
    287
    +# CQ[filecheck-make-path]
    
    288
    +# Q: Why read hadrian's system.config here, when nothing else in the make
    
    289
    +#    path depends on ./configure having run?
    
    290
    +# A~ FileCheck is a testsuite tool, not a compiler setting, so ghc --info
    
    291
    +#    cannot supply it. An unconfigured tree yields an empty value and the
    
    292
    +#    driver falls back to $FILECHECK or _build/filecheck (see find_filecheck).
    
    293
    +FILECHECK ?= $(shell sed -n 's/^filecheck *= *//p' '$(TOP)/../hadrian/cfg/system.config' 2>/dev/null)
    
    294
    +RUNTEST_OPTS += -e 'config.filecheck=r"$(FILECHECK)"'
    
    295
    +
    
    287 296
     ifneq "$(METRICS_FILE)" ""
    
    288 297
     RUNTEST_OPTS +=  \
    
    289 298
     	--metrics-file "$(METRICS_FILE)"