Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

fix!: Allow Const and FuncDecl as children of Modules, Dataflow Parents, and CFG nodes #46

Merged
merged 3 commits into from
Jul 1, 2024

Conversation

doug-q
Copy link
Collaborator

@doug-q doug-q commented Jul 1, 2024

We take the opportunity to fix a bug where the promise to ignore duplicate calls to emit_func was not upheld, and to clean up the now unnecessary Emission.

Fixes #4 , although we go further than required by this issue.

BREAKING CHANGE: rename emit_global to emit_func. Replace Emission type with FatNode<FuncDefn>.

@doug-q doug-q requested a review from a team as a code owner July 1, 2024 09:33
@doug-q doug-q requested a review from croyzor July 1, 2024 09:33
@doug-q doug-q force-pushed the doug/allow-const-in-module branch from 5ec8d0e to 65e5d8c Compare July 1, 2024 09:36
@doug-q doug-q changed the title fix: Allow Const and FuncDecl as children of Modules, Dataflow Parents, and CFG nodes fix!: Allow Const and FuncDecl as children of Modules, Dataflow Parents, and CFG nodes Jul 1, 2024
@codecov-commenter
Copy link

codecov-commenter commented Jul 1, 2024

Codecov Report

Attention: Patch coverage is 90.52632% with 9 lines in your changes missing coverage. Please review.

Project coverage is 83.12%. Comparing base (8dcba0f) to head (cbf3b74).

Files Patch % Lines
src/emit.rs 63.63% 2 Missing and 2 partials ⚠️
src/emit/ops/cfg.rs 82.35% 1 Missing and 2 partials ⚠️
src/emit/ops.rs 66.66% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #46      +/-   ##
==========================================
+ Coverage   82.19%   83.12%   +0.93%     
==========================================
  Files          16       16              
  Lines        2190     2234      +44     
  Branches     2190     2234      +44     
==========================================
+ Hits         1800     1857      +57     
+ Misses        258      246      -12     
+ Partials      132      131       -1     
Flag Coverage Δ
rust 83.12% <90.52%> (+0.93%) ⬆️

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.

store { i32, {}, {} } %"12_01", { i32, {}, {} }* %"4_0", align 4
%"4_02" = load { i32, {}, {} }, { i32, {}, {} }* %"4_0", align 4
store { i32, {}, {} } %"4_02", { i32, {}, {} }* %"0", align 4
%"03" = load { i32, {}, {} }, { i32, {}, {} }* %"0", align 4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea why we end up with all these redundant store and load cycles?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we make no attempt to avoid them. Before we emit a node we load a value per input wire, then after we emit a node we store one value per output wire. Sometimes (for example Exit nodes) we even store and load to intermediate allocas that do not correspond to wires in the graph.

mem2reg removes these. There are(should be) no difficult cases because the value in the alloca is always unique.

We could potentially avoid emitting (most of) them, but this would make things more complicated.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! 😄

br label %2

0: ; preds = %2
%1 = extractvalue { {} } undef, 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea what's going on here? Just for my personal curiosity

Copy link
Collaborator Author

@doug-q doug-q Jul 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this corresponds to the let control = builder.add_load_value(Value::unary_unit_sum()); line. The out wire of this is of type "unary sum with one variant", which we encode in llvm as { {} }: a struct containing an empty struct. Normally Sum types also have an i32 tag, but when num_variants <= 1, we omit the tag. When we generate the code for the following switch, we "read the tag", which for this case(num_variants <= 1), just creates a value with constant value 0.

Obviously this looks dumb, it is the result of lowering the ops in a uniform way, with the goal of making the code here simple. The cost is that you generate dumb code. We do expect LLVM to be able to clean this up easily. In this case "dce" (dead-code-elimination) will delete %1 as it's unused and side-effect-free.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Doug, makes perfect sense!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, that's not quite the right explanation. When we switch at the end of a DataFlowBlock we must write to the RowMailBox of the target block. Note that this write has to happen AFTER the switch, because we only do it on the taken edge. When we write to that RowMailBox we first write each value in the Sum (which has a known variant tag because we are after the switch), then we write each of the "other inputs" (of the Output node in the Block we just left). So we extractvalue the struct of our variant from the struct representing the Sum. Then for each field in the struct, we extractvalue that and write it to the mail box. In this case, the struct of our variant is {} i.e. empty and there are no "other inputs", so the only thing we do is extractvalue the struct of our variant, which is what this line is.

@doug-q doug-q added this pull request to the merge queue Jul 1, 2024
Merged via the queue into main with commit a35ae75 Jul 1, 2024
10 checks passed
@doug-q doug-q deleted the doug/allow-const-in-module branch July 1, 2024 11:18
@hugrbot hugrbot mentioned this pull request Jul 1, 2024
github-merge-queue bot pushed a commit that referenced this pull request Jul 10, 2024
## 🤖 New release
* `hugr-llvm`: 0.1.0

<details><summary><i><b>Changelog</b></i></summary><p>

<blockquote>

## [0.1.0](https://github.com/CQCL/hugr-llvm/releases/tag/v0.1.0) -
2024-07-10

### Bug Fixes
- Syntax error
- sum type tag elision logic reversed
- [**breaking**] Allow Const and FuncDecl as children of Modules,
Dataflow Parents, and CFG nodes
([#46](#46))

### Documentation
- fix bad grammar ([#34](#34))

### New Features
- Emission for Call nodes
- Support  values
- add `get_extern_func`
([#28](#28))
- lower CFGs ([#26](#26))
- Add initial codegen extension for `prelude`
([#29](#29))
- [**breaking**] `Namer` optionally appends node index to mangled names.
([#32](#32))
- Implement lowerings for ieq,ilt_s,sub in int codegen extension
([#33](#33))
- Add initial `float` extension
([#31](#31))
- Emit more int comparison operators
([#47](#47))

### Refactor
- clean up fat.rs ([#38](#38))

### Testing
- add a test for sum type tags
- Add integration tests lowering guppy programs
([#35](#35))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/MarcoIeni/release-plz/).

---------

Co-authored-by: Douglas Wilson <douglas.wilson@quantinuum.com>
@hugrbot hugrbot mentioned this pull request Jul 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Implement emission for FuncDecl + scoped FuncDefn
3 participants