# Writing unit tests for HLO passes There are different ways to write unit test for HLO passes. This page describes the preferred method to ensure consistency and readability. ## `FileCheck` with `CHECK` lines interleaved Most HLO passes can be tested using [`FileCheck`](https://llvm.org/docs/CommandGuide/FileCheck.html) tests. Interleave `CHECK` lines in input HLO module texts, and make sure to use `// CHECK` instead of `; CHECK` uniformly as the `FileCheck` delimiter. For example, you can re-write the [`fusion cc_test` for a `priotity_fusion` pass](https://github.com/openxla/xla/blob/fe30942a406659bff75399a2a10585bbd1287e07/xla/service/gpu/transforms/priority_fusion_test.cc#L133-L149) as follows: ``` TEST_F(PriorityFusionTest, FuseBroadcastIntoBitcastConsumers) { absl::string_view kHlo = R"( HloModule test_module // CHECK: ENTRY main ENTRY main { // CHECK-NEXT: %[[PARAM:.*]] = f32[96]{0} parameter(0) param_0 = f32[96]{0} parameter(0) broadcast = f32[8,96,128,7]{3,2,1,0} broadcast(param_0), dimensions={1} bitcast.6079.2 = f32[8,24,4,128,7]{4,3,2,1,0} bitcast(broadcast) // CHECK-NEXT: ROOT %{{.*}} fusion(%[[PARAM]]) {{.*}} ROOT transpose.1990.2 = f32[8,24,128,7,4]{4,3,2,1,0} transpose(bitcast.6079.2), dimensions={0,1,3,4,2} } )"; RunAndFilecheckHloRewrite(kHlo, std::move(priority_fusion_)); } ``` Note: Currently, the codebase has some tests where input HLO module and expected module are written separately. Inlining the `CHECK` lines is the preferred method for future tests. It enables better readability and a similar signature as MLIR based tests [like in `stablehlo_aggressive_folder.mlir`](https://github.com/openxla/stablehlo/blob/main/stablehlo/tests/transforms/stablehlo_aggressive_folder.mlir#L31-L39). ## `LIT` runner and `hlo-opt` Where feasible, use [`LIT`](https://llvm.org/docs/CommandGuide/lit.html) runner and `hlo-opt`, and place `CHECK` lines locally next to the input IR they correspond to. Again, make sure to use `// CHECK` instead of `; CHECK` as the delimiter. For example, some [GPU tests](https://github.com/openxla/xla/tree/main/xla/backends/gpu/tests) can be written as follows: ``` // RUN: hlo-opt %s --platform=gpu --stage=llvm-before-optimizations --xla_gpu_target_config_filename=%S/../../../backends/gpu/specs/%{GPU}.txtpb | FileCheck --check-prefixes=CHECK-%{PTX} %s HloModule Test, is_scheduled=true fused_computation { param_0 = f32[100,200]{1,0} parameter(0) ROOT b.1 = f32[200,100]{1,0} transpose(f32[100,200]{1,0} param_0), dimensions={1,0} } ENTRY main { a = f32[100, 200]{1,0} parameter(0) // CHECK-PTX: call void @llvm.nvvm.barrier0 // CHECK-GCN: call void @llvm.amdgcn.s.barrier ROOT wrapped_b = f32[200,100]{1,0} fusion(f32[100,200]{1,0} a), kind=kInput, calls=fused_computation } ``` ## Automated `CHECK`-generation script Writing test checks manually can be a lot of work, so it's often more practical to run an optimizer, read over the results to make sure they match expectations, and then convert the optimized HLO into `CHECK` directives. To simplify this process, you can use [`generate_hlo_test_checks.py`](https://github.com/openxla/xla/tree/main/xla/hlo/tools/generate_hlo_test_checks.py) to automatically insert generated `CHECK` directives above each test case in an HLO file. > IMPORTANT: This tool inherently assumes that the pass's current behavior is > correct, so make sure to look over the generated `CHECK` lines yourself and > confirm that they match the output you expect. ## (Don't) Graph traversal Refrain from writing tests that travel leaf nodes of the result graph and match with expected op. These tests are tedious to write, difficult to quickly read, and more difficult to debug and fix. Use one of the above options instead.