xref: /wasmtime-44.0.1/cranelift/docs/testing.md (revision c17a3d89)
13179dcf6SAlex Crichton# Testing Cranelift
23179dcf6SAlex Crichton
33179dcf6SAlex CrichtonCranelift is tested at multiple levels of abstraction and integration. When
43179dcf6SAlex Crichtonpossible, Rust unit tests are used to verify single functions and types. When
53179dcf6SAlex Crichtontesting the interaction between compiler passes, file-level tests are
63179dcf6SAlex Crichtonappropriate.
73179dcf6SAlex Crichton
83179dcf6SAlex Crichton## Rust tests
93179dcf6SAlex Crichton
103179dcf6SAlex CrichtonRust and Cargo have good support for testing. Cranelift uses unit tests, doc
113179dcf6SAlex Crichtontests, and integration tests where appropriate. The
123179dcf6SAlex Crichton[Rust By Example page on Testing] is a great illustration on how to write
133179dcf6SAlex Crichtoneach of these forms of test.
143179dcf6SAlex Crichton
153179dcf6SAlex Crichton[Rust By Example page on Testing]: https://doc.rust-lang.org/rust-by-example/testing.html
163179dcf6SAlex Crichton
173179dcf6SAlex Crichton## File tests
183179dcf6SAlex Crichton
193179dcf6SAlex CrichtonCompilers work with large data structures representing programs, and it quickly
203179dcf6SAlex Crichtongets unwieldy to generate test data programmatically. File-level tests make it
213179dcf6SAlex Crichtoneasier to provide substantial input functions for the compiler tests.
223179dcf6SAlex Crichton
233179dcf6SAlex CrichtonFile tests are `*.clif` files in the `filetests/` directory
243179dcf6SAlex Crichtonhierarchy. Each file has a header describing what to test followed by a number
253179dcf6SAlex Crichtonof input functions in the :doc:`Cranelift textual intermediate representation
263179dcf6SAlex Crichton<ir>`:
273179dcf6SAlex Crichton
283179dcf6SAlex Crichton.. productionlist::
293179dcf6SAlex Crichton    test_file     : test_header `function_list`
303179dcf6SAlex Crichton    test_header   : test_commands (`isa_specs` | `settings`)
313179dcf6SAlex Crichton    test_commands : test_command { test_command }
323179dcf6SAlex Crichton    test_command  : "test" test_name { option } "\n"
333179dcf6SAlex Crichton
343179dcf6SAlex CrichtonThe available test commands are described below.
353179dcf6SAlex Crichton
363179dcf6SAlex CrichtonMany test commands only make sense in the context of a target instruction set
373179dcf6SAlex Crichtonarchitecture. These tests require one or more ISA specifications in the test
383179dcf6SAlex Crichtonheader:
393179dcf6SAlex Crichton
403179dcf6SAlex Crichton.. productionlist::
413179dcf6SAlex Crichton    isa_specs     : { [`settings`] isa_spec }
423179dcf6SAlex Crichton    isa_spec      : "isa" isa_name { `option` } "\n"
433179dcf6SAlex Crichton
443179dcf6SAlex CrichtonThe options given on the `isa` line modify the ISA-specific settings defined in
453179dcf6SAlex Crichton`cranelift-codegen/meta-python/isa/*/settings.py`.
463179dcf6SAlex Crichton
473179dcf6SAlex CrichtonAll types of tests allow shared Cranelift settings to be modified:
483179dcf6SAlex Crichton
493179dcf6SAlex Crichton.. productionlist::
503179dcf6SAlex Crichton    settings      : { setting }
513179dcf6SAlex Crichton    setting       : "set" { option } "\n"
523179dcf6SAlex Crichton    option        : flag | setting "=" value
533179dcf6SAlex Crichton
543179dcf6SAlex CrichtonThe shared settings available for all target ISAs are defined in
553179dcf6SAlex Crichton`cranelift-codegen/meta-python/base/settings.py`.
563179dcf6SAlex Crichton
573179dcf6SAlex CrichtonThe `set` lines apply settings cumulatively:
583179dcf6SAlex Crichton
593179dcf6SAlex Crichton```
603179dcf6SAlex Crichton    test legalizer
613179dcf6SAlex Crichton    set opt_level=best
623179dcf6SAlex Crichton    set is_pic=1
63437f448aSAfonso Bordado    target riscv64
643179dcf6SAlex Crichton    set is_pic=0
65437f448aSAfonso Bordado    target riscv32 supports_m=false
663179dcf6SAlex Crichton
673179dcf6SAlex Crichton    function %foo() {}
683179dcf6SAlex Crichton```
693179dcf6SAlex Crichton
703179dcf6SAlex CrichtonThis example will run the legalizer test twice. Both runs will have
713179dcf6SAlex Crichton`opt_level=best`, but they will have different `is_pic` settings. The 32-bit
723179dcf6SAlex Crichtonrun will also have the RISC-V specific flag `supports_m` disabled.
733179dcf6SAlex Crichton
743179dcf6SAlex CrichtonThe filetests are run automatically as part of `cargo test`, and they can
753179dcf6SAlex Crichtonalso be run manually with the `clif-util test` command.
763179dcf6SAlex Crichton
77c0503455SNick FitzgeraldBy default, the test runner will spawn a thread pool with as many threads as
78c0503455SNick Fitzgeraldthere are logical CPUs. You can explicitly control how many threads are spawned
79c0503455SNick Fitzgeraldvia the `CRANELIFT_FILETESTS_THREADS` environment variable. For example, to
80c0503455SNick Fitzgeraldlimit the test runner to a single thread, use:
81c0503455SNick Fitzgerald
82c0503455SNick Fitzgerald```
83c0503455SNick Fitzgerald$ CRANELIFT_FILETESTS_THREADS=1 clif-util test path/to/file.clif
84c0503455SNick Fitzgerald```
85c0503455SNick Fitzgerald
863179dcf6SAlex Crichton### Filecheck
873179dcf6SAlex Crichton
883179dcf6SAlex CrichtonMany of the test commands described below use *filecheck* to verify their
893179dcf6SAlex Crichtonoutput. Filecheck is a Rust implementation of the LLVM tool of the same name.
903179dcf6SAlex CrichtonSee the `documentation <https://docs.rs/filecheck/>`_ for details of its syntax.
913179dcf6SAlex Crichton
923179dcf6SAlex CrichtonComments in `.clif` files are associated with the entity they follow.
933179dcf6SAlex CrichtonThis typically means an instruction or the whole function. Those tests that
943179dcf6SAlex Crichtonuse filecheck will extract comments associated with each function (or its
953179dcf6SAlex Crichtonentities) and scan them for filecheck directives. The test output for each
963179dcf6SAlex Crichtonfunction is then matched against the filecheck directives for that function.
973179dcf6SAlex Crichton
983179dcf6SAlex CrichtonComments appearing before the first function in a file apply to every function.
993179dcf6SAlex CrichtonThis is useful for defining common regular expression variables with the
1003179dcf6SAlex Crichton`regex:` directive, for example.
1013179dcf6SAlex Crichton
1023179dcf6SAlex CrichtonNote that LLVM's file tests don't separate filecheck directives by their
1033179dcf6SAlex Crichtonassociated function. It verifies the concatenated output against all filecheck
1043179dcf6SAlex Crichtondirectives in the test file. LLVM's :command:`FileCheck` command has a
1053179dcf6SAlex Crichton`CHECK-LABEL:` directive to help separate the output from different functions.
1063179dcf6SAlex CrichtonCranelift's tests don't need this.
1073179dcf6SAlex Crichton
1083179dcf6SAlex Crichton### `test cat`
1093179dcf6SAlex Crichton
1103179dcf6SAlex CrichtonThis is one of the simplest file tests, used for testing the conversion to and
1113179dcf6SAlex Crichtonfrom textual IR. The `test cat` command simply parses each function and
1123179dcf6SAlex Crichtonconverts it back to text again. The text of each function is then matched
1133179dcf6SAlex Crichtonagainst the associated filecheck directives.
1143179dcf6SAlex Crichton
1153179dcf6SAlex CrichtonExample:
1163179dcf6SAlex Crichton
1173179dcf6SAlex Crichton```
1183179dcf6SAlex Crichton    function %r1() -> i32, f32 {
119437f448aSAfonso Bordado    block1:
1203179dcf6SAlex Crichton        v10 = iconst.i32 3
1213179dcf6SAlex Crichton        v20 = f32const 0.0
1223179dcf6SAlex Crichton        return v10, v20
1233179dcf6SAlex Crichton    }
1243179dcf6SAlex Crichton    ; sameln: function %r1() -> i32, f32 {
125437f448aSAfonso Bordado    ; nextln: block0:
1263179dcf6SAlex Crichton    ; nextln:     v10 = iconst.i32 3
1273179dcf6SAlex Crichton    ; nextln:     v20 = f32const 0.0
1283179dcf6SAlex Crichton    ; nextln:     return v10, v20
1293179dcf6SAlex Crichton    ; nextln: }
1303179dcf6SAlex Crichton```
1313179dcf6SAlex Crichton
1323179dcf6SAlex Crichton### `test verifier`
1333179dcf6SAlex Crichton
1343179dcf6SAlex CrichtonRun each function through the IR verifier and check that it produces the
1353179dcf6SAlex Crichtonexpected error messages.
1363179dcf6SAlex Crichton
1373179dcf6SAlex CrichtonExpected error messages are indicated with an `error:` directive *on the
1383179dcf6SAlex Crichtoninstruction that produces the verifier error*. Both the error message and
1393179dcf6SAlex Crichtonreported location of the error is verified:
1403179dcf6SAlex Crichton
1413179dcf6SAlex Crichton```
1423179dcf6SAlex Crichton    test verifier
1433179dcf6SAlex Crichton
1443179dcf6SAlex Crichton    function %test(i32) {
145437f448aSAfonso Bordado        block0(v0: i32):
146437f448aSAfonso Bordado            jump block1       ; error: terminator
1473179dcf6SAlex Crichton            return
1483179dcf6SAlex Crichton    }
1493179dcf6SAlex Crichton```
1503179dcf6SAlex Crichton
1513179dcf6SAlex CrichtonThis example test passes if the verifier fails with an error message containing
1523179dcf6SAlex Crichtonthe sub-string `"terminator"` *and* the error is reported for the `jump`
1533179dcf6SAlex Crichtoninstruction.
1543179dcf6SAlex Crichton
1553179dcf6SAlex CrichtonIf a function contains no `error:` annotations, the test passes if the
1563179dcf6SAlex Crichtonfunction verifies correctly.
1573179dcf6SAlex Crichton
1583179dcf6SAlex Crichton### `test print-cfg`
1593179dcf6SAlex Crichton
1603179dcf6SAlex CrichtonPrint the control flow graph of each function as a Graphviz graph, and run
1613179dcf6SAlex Crichtonfilecheck over the result. See also the :command:`clif-util print-cfg`
1623179dcf6SAlex Crichtoncommand:
1633179dcf6SAlex Crichton
1643179dcf6SAlex Crichton```
1653179dcf6SAlex Crichton    ; For testing cfg generation. This code is nonsense.
1663179dcf6SAlex Crichton    test print-cfg
1673179dcf6SAlex Crichton    test verifier
1683179dcf6SAlex Crichton
1693179dcf6SAlex Crichton    function %nonsense(i32, i32) -> f32 {
1703179dcf6SAlex Crichton    ; check: digraph %nonsense {
1713179dcf6SAlex Crichton    ; regex: I=\binst\d+\b
172a5698cedSTrevor Elliott    ; check: label="{block0 | <$(BRIF=$I)>brif v1, block1(v2), block2 }"]
1733179dcf6SAlex Crichton
174437f448aSAfonso Bordado    block0(v0: i32, v1: i32):
1753179dcf6SAlex Crichton        v2 = iconst.i32 0
176a5698cedSTrevor Elliott        brif v1, block1(v2), block2  ; unordered: block0:$BRIF -> block1
177a5698cedSTrevor Elliott                                     ; unordered: block0:$BRIF -> block2
1783179dcf6SAlex Crichton
179437f448aSAfonso Bordado    block1(v5: i32):
1803179dcf6SAlex Crichton        return v0
1813179dcf6SAlex Crichton
182437f448aSAfonso Bordado    block2:
1833179dcf6SAlex Crichton        v100 = f32const 0.0
1843179dcf6SAlex Crichton        return v100
1853179dcf6SAlex Crichton    }
1863179dcf6SAlex Crichton```
1873179dcf6SAlex Crichton
1883179dcf6SAlex Crichton### `test domtree`
1893179dcf6SAlex Crichton
1903179dcf6SAlex CrichtonCompute the dominator tree of each function and validate it against the
1913179dcf6SAlex Crichton`dominates:` annotations::
1923179dcf6SAlex Crichton
1933179dcf6SAlex Crichton```
1943179dcf6SAlex Crichton    test domtree
1953179dcf6SAlex Crichton
1963179dcf6SAlex Crichton    function %test(i32) {
197437f448aSAfonso Bordado        block0(v0: i32):
198437f448aSAfonso Bordado            jump block1              ; dominates: block1
199437f448aSAfonso Bordado        block1:
200a5698cedSTrevor Elliott            brif v0, block2, block3  ; dominates: block2, block3
201437f448aSAfonso Bordado        block2:
202437f448aSAfonso Bordado            jump block3
203437f448aSAfonso Bordado        block3:
2043179dcf6SAlex Crichton            return
2053179dcf6SAlex Crichton    }
2063179dcf6SAlex Crichton```
2073179dcf6SAlex Crichton
208*c17a3d89STrevor ElliottEvery reachable basic block except for the entry block has an
2093179dcf6SAlex Crichton*immediate dominator* which is a jump or branch instruction. This test passes
2103179dcf6SAlex Crichtonif the `dominates:` annotations on the immediate dominator instructions are
2113179dcf6SAlex Crichtonboth correct and complete.
2123179dcf6SAlex Crichton
2133179dcf6SAlex CrichtonThis test also sends the computed CFG post-order through filecheck.
2143179dcf6SAlex Crichton
2153179dcf6SAlex Crichton### `test legalizer`
2163179dcf6SAlex Crichton
2173179dcf6SAlex CrichtonLegalize each function for the specified target ISA and run the resulting
2183179dcf6SAlex Crichtonfunction through filecheck. This test command can be used to validate the
2193179dcf6SAlex Crichtonencodings selected for legal instructions as well as the instruction
2203179dcf6SAlex Crichtontransformations performed by the legalizer.
2213179dcf6SAlex Crichton
2223179dcf6SAlex Crichton### `test regalloc`
2233179dcf6SAlex Crichton
2243179dcf6SAlex CrichtonTest the register allocator.
2253179dcf6SAlex Crichton
2263179dcf6SAlex CrichtonFirst, each function is legalized for the specified target ISA. This is
2273179dcf6SAlex Crichtonrequired for register allocation since the instruction encodings provide
2283179dcf6SAlex Crichtonregister class constraints to the register allocator.
2293179dcf6SAlex Crichton
2303179dcf6SAlex CrichtonSecond, the register allocator is run on the function, inserting spill code and
2313179dcf6SAlex Crichtonassigning registers and stack slots to all values.
2323179dcf6SAlex Crichton
2333179dcf6SAlex CrichtonThe resulting function is then run through filecheck.
2343179dcf6SAlex Crichton
2353179dcf6SAlex Crichton
2363179dcf6SAlex Crichton### `test simple-gvn`
2373179dcf6SAlex Crichton
2383179dcf6SAlex CrichtonTest the simple GVN pass.
2393179dcf6SAlex Crichton
2403179dcf6SAlex CrichtonThe simple GVN pass is run on each function, and then results are run
2413179dcf6SAlex Crichtonthrough filecheck.
2423179dcf6SAlex Crichton
2433179dcf6SAlex Crichton### `test licm`
2443179dcf6SAlex Crichton
2453179dcf6SAlex CrichtonTest the LICM pass.
2463179dcf6SAlex Crichton
2473179dcf6SAlex CrichtonThe LICM pass is run on each function, and then results are run
2483179dcf6SAlex Crichtonthrough filecheck.
2493179dcf6SAlex Crichton
2503179dcf6SAlex Crichton### `test dce`
2513179dcf6SAlex Crichton
2523179dcf6SAlex CrichtonTest the DCE pass.
2533179dcf6SAlex Crichton
2543179dcf6SAlex CrichtonThe DCE pass is run on each function, and then results are run
2553179dcf6SAlex Crichtonthrough filecheck.
2563179dcf6SAlex Crichton
2573179dcf6SAlex Crichton### `test shrink`
2583179dcf6SAlex Crichton
2593179dcf6SAlex CrichtonTest the instruction shrinking pass.
2603179dcf6SAlex Crichton
2613179dcf6SAlex CrichtonThe shrink pass is run on each function, and then results are run
2623179dcf6SAlex Crichtonthrough filecheck.
2633179dcf6SAlex Crichton
26491580155SJamey Sharp### `test simple_preopt`
2653179dcf6SAlex Crichton
2663179dcf6SAlex CrichtonTest the preopt pass.
2673179dcf6SAlex Crichton
2683179dcf6SAlex CrichtonThe preopt pass is run on each function, and then results are run
2693179dcf6SAlex Crichtonthrough filecheck.
2703179dcf6SAlex Crichton
2713179dcf6SAlex Crichton### `test compile`
2723179dcf6SAlex Crichton
2733179dcf6SAlex CrichtonTest the whole code generation pipeline.
2743179dcf6SAlex Crichton
2753179dcf6SAlex CrichtonEach function is passed through the full `Context::compile()` function
2763179dcf6SAlex Crichtonwhich is normally used to compile code. This type of test often depends
2773179dcf6SAlex Crichtonon assertions or verifier errors, but it is also possible to use
2783179dcf6SAlex Crichtonfilecheck directives which will be matched against the final form of the
2793179dcf6SAlex CrichtonCranelift IR right before binary machine code emission.
2803179dcf6SAlex Crichton
2813179dcf6SAlex Crichton### `test run`
2823179dcf6SAlex Crichton
2833179dcf6SAlex CrichtonCompile and execute a function.
2843179dcf6SAlex Crichton
285d6796d0dSAndrew BrownThis test command allows several directives:
286d6796d0dSAndrew Brown - to print the result of running a function to stdout, add a `print`
287d6796d0dSAndrew Brown directive and call the preceding function with arguments (see `%foo` in
288d6796d0dSAndrew Brown the example below); remember to enable `--nocapture` if running these
289d6796d0dSAndrew Brown tests through Cargo
290d6796d0dSAndrew Brown - to check the result of a function, add a `run` directive and call the
291d6796d0dSAndrew Brown preceding function with a comparison (`==` or `!=`) (see `%bar` below)
292d6796d0dSAndrew Brown - for backwards compatibility, to check the result of a function with a
293437f448aSAfonso Bordado `() -> i*` signature, only the `run` directive is required, with no
294437f448aSAfonso Bordado invocation or comparison (see `%baz` below);  a non zero value is
295437f448aSAfonso Bordado interpreted as a successful test execution, whereas a zero value is
296d6796d0dSAndrew Brown interpreted as a failed test.
2973179dcf6SAlex Crichton
298d1aa86f9SAlex CrichtonCurrently a `target` is required but is only used to indicate whether the host
299d6796d0dSAndrew Brownplatform can run the test and currently only the architecture is filtered. The
300d1aa86f9SAlex Crichtonhost platform's native target will be used to actually compile the test.
301d1aa86f9SAlex Crichton
3023179dcf6SAlex CrichtonExample:
3033179dcf6SAlex Crichton
3043179dcf6SAlex Crichton```
3053179dcf6SAlex Crichton    test run
306d1aa86f9SAlex Crichton    target x86_64
3073179dcf6SAlex Crichton
308d6796d0dSAndrew Brown    ; how to print the results of a function
309d6796d0dSAndrew Brown    function %foo() -> i32 {
310d6796d0dSAndrew Brown    block0:
311d6796d0dSAndrew Brown        v0 = iconst.i32 42
312d6796d0dSAndrew Brown        return v0
313d6796d0dSAndrew Brown    }
314d6796d0dSAndrew Brown    ; print: %foo()
315d6796d0dSAndrew Brown
316d6796d0dSAndrew Brown    ; how to check the results of a function
317d6796d0dSAndrew Brown    function %bar(i32) -> i32 {
318d6796d0dSAndrew Brown    block0(v0:i32):
319d6796d0dSAndrew Brown        v1 = iadd_imm v0, 1
320d6796d0dSAndrew Brown        return v1
321d6796d0dSAndrew Brown    }
322d6796d0dSAndrew Brown    ; run: %bar(1) == 2
323d6796d0dSAndrew Brown
324d6796d0dSAndrew Brown    ; legacy method of checking the results of a function
325437f448aSAfonso Bordado    function %baz() -> i8 {
326d6796d0dSAndrew Brown    block0:
327437f448aSAfonso Bordado        v0 = iconst.i8 1
3283179dcf6SAlex Crichton        return v0
3293179dcf6SAlex Crichton    }
3303179dcf6SAlex Crichton    ; run
3313179dcf6SAlex Crichton```
332