Skip to content

Conversation

@indietyp
Copy link
Member

@indietyp indietyp commented Nov 30, 2025

🌟 What is the purpose of this PR?

This PR adds a Dead Block Elimination (DBE) pass to the MIR compiler that physically removes unreachable basic blocks from the control-flow graph and compacts the remaining blocks to eliminate gaps in the ID space. This complements the existing CfgSimplify pass which marks unreachable blocks with TerminatorKind::Unreachable but doesn't remove them.

screenshot.2025-11-30T22-14-43.png

🔍 What does this change?

  • Adds a new DeadBlockElimination pass that removes unreachable blocks and compacts the block ID space
  • Integrates DBE into the CfgSimplify pass to run after simplifications are applied
  • Adds utility methods to IdVec: swap_remove, swap, and truncate to support block compaction
  • Adds comprehensive tests for the DBE pass covering various scenarios
  • Updates existing test snapshots to reflect the new behavior

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • do not affect the execution graph

🛡 What tests cover this?

  • Comprehensive test suite for the DBE pass covering various scenarios:
    • All blocks reachable
    • Single unreachable block at the end
    • Unreachable block in the middle requiring ID remapping
    • Multiple consecutive unreachable blocks
    • Scattered unreachable blocks requiring complex remapping
    • Switch target remapping
    • Block parameters preservation
    • Unreachable chains of blocks

@vercel vercel bot temporarily deployed to Preview – petrinaut November 30, 2025 21:14 Inactive
@indietyp indietyp changed the title BE-221: Implement DBE (Dead Block Elimination) BE-221: HashQL: Implement DBE (Dead Block Elimination) Nov 30, 2025
@indietyp indietyp force-pushed the bm/be-222-hashql-remove-span-from-type-environment branch from 352124e to 5f61470 Compare November 30, 2025 21:17
@indietyp indietyp force-pushed the bm/be-221-hashql-dead-block-elimination branch from 86dab2a to cb9a789 Compare November 30, 2025 21:17
@vercel vercel bot temporarily deployed to Preview – petrinaut November 30, 2025 21:17 Inactive
@codecov
Copy link

codecov bot commented Nov 30, 2025

Codecov Report

❌ Patch coverage is 98.91697% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 57.80%. Comparing base (dffec8d) to head (1b3b01b).

Files with missing lines Patch % Lines
...bs/@local/hashql/mir/src/pass/transform/dbe/mod.rs 95.23% 3 Missing ⚠️
Additional details and impacted files
@@                  Coverage Diff                   @@
##           graphite-base/8135    #8135      +/-   ##
======================================================
+ Coverage               57.66%   57.80%   +0.14%     
======================================================
  Files                    1164     1166       +2     
  Lines                  108845   109121     +276     
  Branches                 4956     4963       +7     
======================================================
+ Hits                    62767    63081     +314     
+ Misses                  45346    45306      -40     
- Partials                  732      734       +2     
Flag Coverage Δ
rust.hashql-compiletest 49.36% <ø> (ø)
rust.hashql-core 82.46% <ø> (ø)
rust.hashql-mir 83.59% <98.91%> (+1.74%) ⬆️
rust.hashql-syntax-jexpr 94.00% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

TimDiekmann
TimDiekmann previously approved these changes Dec 1, 2025
@graphite-app graphite-app bot changed the base branch from bm/be-222-hashql-remove-span-from-type-environment to graphite-base/8135 December 1, 2025 10:12
@indietyp indietyp force-pushed the bm/be-221-hashql-dead-block-elimination branch from 1b3b01b to 8e73fae Compare December 1, 2025 10:44
@vercel vercel bot temporarily deployed to Preview – petrinaut December 1, 2025 10:44 Inactive
@github-actions github-actions bot dismissed TimDiekmann’s stale review December 1, 2025 10:44

Your organization requires reapproval when changes are made, so Graphite has dismissed approvals. See the output of git range-diff at https://github.com/hashintel/hash/actions/runs/19819864150

@graphite-app graphite-app bot changed the base branch from graphite-base/8135 to main December 1, 2025 10:44
@graphite-app
Copy link
Contributor

graphite-app bot commented Dec 1, 2025

Merge activity

  • Dec 1, 10:44 AM UTC: Graphite rebased this pull request, because this pull request is set to merge when ready.

@github-actions
Copy link
Contributor

github-actions bot commented Dec 1, 2025

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$29.0 \mathrm{ms} \pm 133 \mathrm{μs}\left({\color{gray}1.23 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.33 \mathrm{ms} \pm 16.4 \mathrm{μs}\left({\color{gray}2.41 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$13.6 \mathrm{ms} \pm 79.1 \mathrm{μs}\left({\color{red}6.52 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$44.2 \mathrm{ms} \pm 301 \mathrm{μs}\left({\color{gray}0.607 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$14.7 \mathrm{ms} \pm 87.0 \mathrm{μs}\left({\color{gray}2.79 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$25.0 \mathrm{ms} \pm 144 \mathrm{μs}\left({\color{gray}-0.210 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$26.9 \mathrm{ms} \pm 112 \mathrm{μs}\left({\color{lightgreen}-39.686 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$5.16 \mathrm{ms} \pm 31.8 \mathrm{μs}\left({\color{lightgreen}-52.465 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$17.3 \mathrm{ms} \pm 98.6 \mathrm{μs}\left({\color{lightgreen}-46.390 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.79 \mathrm{ms} \pm 18.4 \mathrm{μs}\left({\color{gray}1.73 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.88 \mathrm{ms} \pm 14.0 \mathrm{μs}\left({\color{gray}-0.944 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.29 \mathrm{ms} \pm 15.0 \mathrm{μs}\left({\color{gray}-1.107 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.24 \mathrm{ms} \pm 22.9 \mathrm{μs}\left({\color{gray}-1.049 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.50 \mathrm{ms} \pm 14.9 \mathrm{μs}\left({\color{gray}0.994 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$4.05 \mathrm{ms} \pm 19.5 \mathrm{μs}\left({\color{gray}-0.531 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.46 \mathrm{ms} \pm 20.6 \mathrm{μs}\left({\color{red}5.22 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.39 \mathrm{ms} \pm 15.8 \mathrm{μs}\left({\color{gray}0.156 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$3.95 \mathrm{ms} \pm 21.6 \mathrm{μs}\left({\color{gray}-1.947 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.55 \mathrm{ms} \pm 13.9 \mathrm{μs}\left({\color{gray}4.16 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.53 \mathrm{ms} \pm 12.9 \mathrm{μs}\left({\color{gray}4.98 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.59 \mathrm{ms} \pm 11.4 \mathrm{μs}\left({\color{gray}3.77 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.78 \mathrm{ms} \pm 15.8 \mathrm{μs}\left({\color{gray}3.44 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.68 \mathrm{ms} \pm 17.1 \mathrm{μs}\left({\color{gray}4.62 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.87 \mathrm{ms} \pm 16.0 \mathrm{μs}\left({\color{gray}3.04 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$2.99 \mathrm{ms} \pm 15.4 \mathrm{μs}\left({\color{red}6.42 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.60 \mathrm{ms} \pm 11.3 \mathrm{μs}\left({\color{gray}3.81 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$2.83 \mathrm{ms} \pm 13.5 \mathrm{μs}\left({\color{red}8.27 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.27 \mathrm{ms} \pm 12.9 \mathrm{μs}\left({\color{gray}2.45 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.86 \mathrm{ms} \pm 17.9 \mathrm{μs}\left({\color{red}5.18 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$3.06 \mathrm{ms} \pm 11.2 \mathrm{μs}\left({\color{gray}4.56 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.29 \mathrm{ms} \pm 16.1 \mathrm{μs}\left({\color{red}7.92 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.85 \mathrm{ms} \pm 12.0 \mathrm{μs}\left({\color{red}5.97 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.12 \mathrm{ms} \pm 15.7 \mathrm{μs}\left({\color{red}5.47 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$40.4 \mathrm{ms} \pm 162 \mathrm{μs}\left({\color{gray}3.59 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$87.7 \mathrm{ms} \pm 470 \mathrm{μs}\left({\color{red}46.9 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$44.3 \mathrm{ms} \pm 194 \mathrm{μs}\left({\color{gray}0.144 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$46.9 \mathrm{ms} \pm 244 \mathrm{μs}\left({\color{gray}0.359 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$55.9 \mathrm{ms} \pm 318 \mathrm{μs}\left({\color{gray}-4.755 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$41.1 \mathrm{ms} \pm 165 \mathrm{μs}\left({\color{gray}-1.450 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$500 \mathrm{ms} \pm 835 \mathrm{μs}\left({\color{red}133 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$102 \mathrm{ms} \pm 520 \mathrm{μs}\left({\color{gray}1.64 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$86.5 \mathrm{ms} \pm 362 \mathrm{μs}\left({\color{gray}1.69 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$295 \mathrm{ms} \pm 831 \mathrm{μs}\left({\color{gray}-0.589 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$15.0 \mathrm{ms} \pm 86.1 \mathrm{μs}\left({\color{gray}-0.263 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$15.1 \mathrm{ms} \pm 65.1 \mathrm{μs}\left({\color{gray}-1.161 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$15.5 \mathrm{ms} \pm 87.2 \mathrm{μs}\left({\color{gray}0.305 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$15.1 \mathrm{ms} \pm 81.5 \mathrm{μs}\left({\color{gray}-0.733 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$18.7 \mathrm{ms} \pm 89.6 \mathrm{μs}\left({\color{gray}0.758 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$15.4 \mathrm{ms} \pm 80.2 \mathrm{μs}\left({\color{gray}2.68 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$15.0 \mathrm{ms} \pm 62.3 \mathrm{μs}\left({\color{gray}-0.372 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$15.2 \mathrm{ms} \pm 80.2 \mathrm{μs}\left({\color{gray}0.686 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$15.8 \mathrm{ms} \pm 76.5 \mathrm{μs}\left({\color{gray}0.113 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$22.6 \mathrm{ms} \pm 162 \mathrm{μs}\left({\color{gray}-1.460 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$30.8 \mathrm{ms} \pm 288 \mathrm{μs}\left({\color{gray}1.54 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$30.4 \mathrm{ms} \pm 348 \mathrm{μs}\left({\color{gray}0.774 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$30.6 \mathrm{ms} \pm 307 \mathrm{μs}\left({\color{lightgreen}-5.110 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$30.9 \mathrm{ms} \pm 294 \mathrm{μs}\left({\color{gray}-3.893 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$30.3 \mathrm{ms} \pm 318 \mathrm{μs}\left({\color{gray}-0.062 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$29.3 \mathrm{ms} \pm 290 \mathrm{μs}\left({\color{lightgreen}-6.050 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$30.9 \mathrm{ms} \pm 284 \mathrm{μs}\left({\color{lightgreen}-6.796 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$29.8 \mathrm{ms} \pm 318 \mathrm{μs}\left({\color{gray}-1.207 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$30.8 \mathrm{ms} \pm 315 \mathrm{μs}\left({\color{gray}-2.226 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$9.06 \mathrm{ms} \pm 48.4 \mathrm{μs}\left({\color{gray}0.670 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$58.0 \mathrm{ms} \pm 422 \mathrm{μs}\left({\color{gray}1.39 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$110 \mathrm{ms} \pm 508 \mathrm{μs}\left({\color{gray}0.685 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$63.4 \mathrm{ms} \pm 321 \mathrm{μs}\left({\color{gray}0.981 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$71.5 \mathrm{ms} \pm 383 \mathrm{μs}\left({\color{gray}0.021 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$81.8 \mathrm{ms} \pm 399 \mathrm{μs}\left({\color{gray}0.460 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$88.4 \mathrm{ms} \pm 410 \mathrm{μs}\left({\color{gray}0.085 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$52.6 \mathrm{ms} \pm 330 \mathrm{μs}\left({\color{gray}1.59 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$81.6 \mathrm{ms} \pm 308 \mathrm{μs}\left({\color{gray}-0.638 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$59.5 \mathrm{ms} \pm 391 \mathrm{μs}\left({\color{gray}2.49 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$68.0 \mathrm{ms} \pm 367 \mathrm{μs}\left({\color{gray}1.58 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$70.5 \mathrm{ms} \pm 370 \mathrm{μs}\left({\color{gray}1.73 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$70.1 \mathrm{ms} \pm 297 \mathrm{μs}\left({\color{gray}0.793 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$145 \mathrm{ms} \pm 557 \mathrm{μs}\left({\color{gray}1.39 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$141 \mathrm{ms} \pm 580 \mathrm{μs}\left({\color{gray}-0.996 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$42.6 \mathrm{ms} \pm 227 \mathrm{μs}\left({\color{lightgreen}-59.083 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$572 \mathrm{ms} \pm 1.24 \mathrm{ms}\left({\color{gray}-0.304 \mathrm{\%}}\right) $$ Flame Graph

@indietyp indietyp requested a review from TimDiekmann December 1, 2025 13:04
@indietyp indietyp added this pull request to the merge queue Dec 1, 2025
Merged via the queue into main with commit 30dd4a0 Dec 1, 2025
93 of 111 checks passed
@indietyp indietyp deleted the bm/be-221-hashql-dead-block-elimination branch December 1, 2025 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests type/eng > backend Owned by the @backend team

Development

Successfully merging this pull request may close these issues.

3 participants