Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[enhancement] non-mutually-exclusive sends on channel should be reported before codegen #1900

Open
proppy opened this issue Jan 30, 2025 · 1 comment
Labels
dslx DSLX (domain specific language) implementation / front-end enhancement New feature or request ir 🧦 sox ux User experience (end-user invoking XLS and its related tools)

Comments

@proppy
Copy link
Member

proppy commented Jan 30, 2025

What's hard to do? (limit 100 words)

Currently it's hard to realize that a given DSLX w/ non-mutually-exclusive sends operation will not produce valid hardware without running codegen.

Example:

The following DSLX code w/ non-mutually-exclusive sends:

proc Foo {
  some_chan: chan<bool> out;

  init {
    token()
  }

  config(some_chan: chan<bool> out) {
    (some_chan,)
  }

  next(state: token) {
    let tok1 = send(state, some_chan, true);
    let tok2 = send(state, some_chan, false);
    join(tok1, tok2)
  }
}

#[test_proc]
proc FooTest {
    some_chan: chan<bool> in;
    terminator: chan<bool> out;
    
    init {
    }

    config(terminator: chan<bool> out) {
        let (some_chan_out, some_chan_in) = chan<bool>("some_chan");
        spawn Foo(some_chan_out);
        (some_chan_in, terminator)
    }

    next(state: ()) {
        let tok = token();
        let (tok, b) = recv(tok, some_chan);
        assert_eq(b, true);
        let (tok, b) = recv(tok, some_chan);        
        assert_eq(b, false);
        send(tok, terminator, true);
    }
}

will pass interpreter tests:

[ RUN UNITTEST  ] FooTest
[            OK ]
[===============] 1 test(s) ran; 0 failed; 0 skipped.

be convertable to IR:

package b

file_number 0 "/tmp/b.x"

chan b__some_chan(bits[1], id=0, kind=streaming, ops=send_only, flow_control=ready_valid, strictness=proven_mutually_exclusive, metadata="""""")

proc __b__Foo_0_next(__state: token, init={token}) {
  __state: token = state_read(state_element=__state, id=2)
  literal.4: bits[1] = literal(value=1, id=4, pos=[(0,12,38)])
  literal.3: bits[1] = literal(value=1, id=3)
  literal.6: bits[1] = literal(value=0, id=6, pos=[(0,13,38)])
  tok1: token = send(__state, literal.4, predicate=literal.3, channel=b__some_chan, id=5)
  tok2: token = send(__state, literal.6, predicate=literal.3, channel=b__some_chan, id=7)
  after_all.8: token = after_all(tok1, tok2, id=8)
  __token: token = literal(value=token, id=1)
  next_value.9: () = next_value(param=__state, value=after_all.8, id=9)
}

and optimized:

package b

file_number 0 "/tmp/b.x"

chan b__some_chan(bits[1], id=0, kind=streaming, ops=send_only, flow_control=ready_valid, strictness=proven_mutually_exclusive, metadata="""""")

top proc __b__Foo_0_next(__state: token, init={token}) {
  __state: token = state_read(state_element=__state, id=2)
  literal.4: bits[1] = literal(value=1, id=4, pos=[(0,12,38)])
  literal.6: bits[1] = literal(value=0, id=6, pos=[(0,13,38)])
  tok1: token = send(__state, literal.4, channel=b__some_chan, id=12)
  tok2: token = send(__state, literal.6, channel=b__some_chan, id=13)
  after_all.8: token = after_all(tok1, tok2, id=8)
  next_value.9: () = next_value(param=__state, value=after_all.8, id=9)
}

but will fail codegen:

Error: INTERNAL: Multiple sends associated with the same channel 'b__some_chan':

Send node with no known provenance: tok1: token = send(__state, literal.4, channel=b__some_chan, id=12)

Send node with no known provenance: tok2: token = send(__state, literal.6, channel=b__some_chan, id=13)

Current best alternative workaround (limit 100 words)

Always run the XLS toolchain all the way to codegen to detect non-mutually exclusive sends, potentially slowing down the dev cycle.

Your view of the "best case XLS enhancement" (limit 100 words)

A runtime would be reported when running tests and additional IR verification passes (when applicable) would be run on the various intermediate form of the IR (non-optimized, optimized, scheduled, block).

@proppy proppy added enhancement New feature or request dslx DSLX (domain specific language) implementation / front-end ux User experience (end-user invoking XLS and its related tools) 🧦 sox labels Jan 30, 2025
@proppy proppy added the ir label Jan 30, 2025
@ericastor
Copy link
Collaborator

At first glance, this seems difficult; we can't actually finish merging operations on proven_mutually_exclusive channels until after scheduling has finished.

A better solution might be to make the other strictnesses more accessible - likely including switching the default to either arbitrary_static_order or total_order. Doing this without imposing a substantial QoR penalty almost certainly requires us to put off adapter introduction until after scheduling (and the mutual-exclusion analysis pass), then generating adapters that are optimized for the context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dslx DSLX (domain specific language) implementation / front-end enhancement New feature or request ir 🧦 sox ux User experience (end-user invoking XLS and its related tools)
Projects
Status: No status
Development

No branches or pull requests

2 participants