Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions main/2026/CG-2026-06-30.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,120 @@ To be filled in after the meeting.

### Attendees

- Thomas Lively
- Robin Freyler
- Alex Crichton
- Paul Osborne
- Matthias Liedtke
- Jakob Kummerow
- Sam Clegg
- Heejin Ahn
- Ryan Diaz
- Keith Miller
- Ryan Hunt
- Shravan Narayan
- Emanuel Ziegler
- Paolo Severini
- Conrad Watt
- Zalim Bashorov
- Yury Delendik
- Michael Ficarra
- Brendan Dahl
- Steven Fontanella
- Rezvan Mahdavi Hezaveh
- Aleksandr Shefer
- Luke Wagner
- Julien Pages
- Ben Visness

### Proposals and discussions

#### Wide Arithmetic and BigInt addition: potential design tweaks (Jakob Kummerow, 30 mins)

JK presenting [slides]() TODO link

### Closure

MF (chat): would i1 also be useful as a packed field type?

JK: We could use it anywhere. It would be up to engines whether they want to take advantage of it. Thye could also use 8 or 32 bits. It could also be useful in future proposals.

AC: I would be worried about adding an i1 type because of potential future complexity. Worried about combinatoric complexity of future optimizations, packed representations. Timeline-wise, I expect this would be significantly more than 1 month, more like a year. Also there is a lot of extra fuzzing, tooling complexity. I still feel i1 is a little too heavy. Also there's a question of how the performance will work out. LLVM wants to chain i1 and add-with-carry operations as closely as possible. It assumes it sits in a register. It's not clear Wasm engines would match that if they're pulling it out of the flags register all the time.

JK: For me, i1 is a specific tool for a niche purpose. We're not duplicating all instructions. We can discuss how many cases we want to make useful, e.g. struct fields, but that can be case-by-case and the spec doesn't need to say.

JK: The i1 would be in a general-purpose register. We would run an analysis pass to determine which values use at most the low bit and codegen accordingly. LLVM could do the same. You cannot carry the value in a flags register from one loop iteration to the next anyway.

AC: Even if we use it in only niche ways, we still have to expose and support it everywhere, e.g. in Wasm libraries.

JK: It's valid to just take it almost as an alias for i32.

KM: I was thinking about it as a flags value that is opaque and then there is some way to extract values. People will assume that they can use i1 as a general bool. A more general "flags" type could be more general and match status registers. That could be a better value-add than just a range value on an integer.

JK: There are certainly other options. We could add general bit-range annotations. But anything more complex like that would benefit from motivating use cases. The use case for i1 is very clear. I'm skeptical of "flags" because of Alex's earlier experience with trying it that way. Given the way wasm tools and engines work, it is difficult to expect operations to stay next to each other.

KM: But it would still be semantically correct, just slow.

JK: But then what's the point. We're not making those assumptions in the i1 design because we would always be extracting the bit value. It's not worth it to try tricks with the flags registers, etc. because the loop structure will mess it up.

KM: Maybe I'm missing something, but doesn't adc read the carry flag, so you need to be careful anyway?

JK: The idea is that the adc wasm instruction will lower to a sequence that puts the value in the flags register and then does the ARM adc. Even in optimizing compilers. We want the compilers to remain as simple as possible.

RF (chat): Given that Wasm operators such as `i32_lt_s` etc.. return `i32` adding an `i1` would yield asymmetry as those operators would likely also profit from an `i1` type. A more consistent design would use `i32` instead of `i1` and Wasm runtimes could “simply” infer that the returned `i32` values of the wide-arithmetic operators are within range of `0..1`.

JK: Yes, we could do (or could have done) something like that. This shows that engines can just represent the i1s as an i32. It's ok if we don't do this specialization in practice.

BV: Then why introduce i1 at all?

JK: Inside the code sequence for this single Wasm instruction, it is useful for performance.

RF (chat): That wasn’t what I meant with the question above. I mean: why cannot we use `i32` for the `add_with_carry`? Analysis is usually local and a Wasm runtime should be able to easily infer the 0..1 range of the returned `i32` carry, right?

JK: Yes. The question is whether we want to burden the engine or the toolchain with that analysis.

AC: If adc takes i32 inputs and the third input is treated as a boolean, then a baseline compiler could check its range at runtime.

JK: But the test would be too slow, so we would want to just do an extra addition.

AC: This is assuming the check is part of the semantics of the 3-input instruction.

JK: We could also have a full 3-way i64 add that would lower to 3 additions. Optimizing compilers could do the analysis to optimize it, but then then engines are still doing the analysis.

TL: Wouldn't be able to use i1 broadly in the optimizer if we couldn't refine i32.eqz and friends to return i1.

MF (chat): Instead of thinking of it as an i1, where people would expect more int-like operations (and could argue that i32 serves the same purpose), we could instead have it be an opaque carry type that is used exclusively in these operations.

RF (chat): If the carry was an `i32` it would very nicely play with checks using the carry such as `br_if`, `if`, `i32.eqz` etc..

AC: … the add128s produce optimal codegen?

JK: Yes, but only if we do an analysis. Adding i1 lets toolchains do the analysis instead.

AC: In my experience this analysis is very similar to all the other analysis and codegen optimizations we're already doing, at least in Cranelift and Wasmtime.

JK: I agree that optimizing out the zero inputs is easy, doing the loop-aware analysis to determine the range is the new part that you need for optimal codegen.

TL: Straw poll for a temperature check?

| SF | F | N | A | SA |
|----|---|---|---|----|
| 2 | 4 | 9 | 4 | 1 |

RH: One thing that would be helpful for me would be to have this written down so I can take the time to think through it.

JK: I can make an issue.

AC: Clearly not consensus for or against. We could split the proposal and just add the noncontroversial instructions.

TL: We could, but there is a cost to having more proposals. I hope we can decide this quickly so that isn't necessary.

JK: One note, I don't think it would fall on Alex to do the toolchain work.

TL: Anyone want to see prototyping to help decide?

JK: I would want to see a prototype in LLVM to convince me that this is worth it.

KM (chat): FWIW, I generally think having binaryen do optimizations so engines don't is the best case. AFAIK, nearly every major toolchain uses binaryen at some point (maybe this is wrong) so only one place has to worry about the optimization (rather than N engines or M toolchains). But in this case I worry about the long term type system sustainability of i1.

TL: The next steps are for Jakob to write an issue and for the LLVM and Binaryen code owners to discuss their available capacity and come back to share a plan for prototyping the design change.