Skip to content
Merged
Show file tree
Hide file tree
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
23 changes: 23 additions & 0 deletions xls/dslx/get_conversion_records.cc
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,28 @@ class ConversionRecordVisitor : public AstNodeVisitorWithDefault {
VLOG(5) << "No calls to parametric proc " << p->name_def()->ToString();
return absl::OkStatus();
}

XLS_ASSIGN_OR_RETURN(std::vector<InterpValue> spawns,
proc_owner_ti->GetProcDefSpawnsFrom(p));
for (const InterpValue& external_initializer : spawns) {
const ProcDef* spawnee =
external_initializer.GetProcInitializerOrDie().proc_def();
if (spawnee->owner() == p->owner()) {
continue;
}

// Proc is outside this module; get additional conversion records from
// its spawning and add to our list of records.
XLS_ASSIGN_OR_RETURN(
ProcInitializerWithTypeInfo canonical_initializer,
proc_owner_ti->GetCanonicalProcInitializer(external_initializer));
ConversionRecordVisitor visitor(
spawnee->owner(), canonical_initializer.next_type_info,
include_tests_, proc_id_factory_, top_, resolved_proc_alias_,
records_, processed_invocations_);
XLS_RETURN_IF_ERROR(spawnee->Accept(&visitor));
}

for (const ProcInitializerWithTypeInfo& canonical_initializer :
canonical_initializers) {
// TODO: https://github.com/google/xls/issues/4125 - Exclude test-only
Expand All @@ -409,6 +431,7 @@ class ConversionRecordVisitor : public AstNodeVisitorWithDefault {
canonical_initializer));
records_.push_back(std::move(cr));
}

return absl::OkStatus();
}

Expand Down
2 changes: 1 addition & 1 deletion xls/dslx/ir_convert/function_converter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3749,7 +3749,7 @@ absl::Status FunctionConverter::InitProcDefBuilder(const ProcDef* proc_def,

XLS_ASSIGN_OR_RETURN(
std::string mangled_name,
MangleDslxName(module_->name(), proc_def->identifier(),
MangleDslxName(proc_def->owner()->name(), proc_def->identifier(),
CallingConvention::kProcNext, parametric_keys, &env));
auto unique_builder =
std::make_unique<ProcBuilder>(NewStyleProc{}, mangled_name, package());
Expand Down
69 changes: 69 additions & 0 deletions xls/dslx/ir_convert/ir_converter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2679,6 +2679,75 @@ impl Main {
ExpectIr(converted);
}

TEST_F(IrConverterTest, SpawnImportedProcDef) {
auto import_data = CreateImportDataForTest();

std::string_view kImported = R"(
#![feature(explicit_state_access)]

pub proc P {
c_out: chan<u32> out,
i: u32,
}

impl P {
fn new(c_out: chan<u32> out) -> Self {
P { c_out: c_out, i: 0 }
}

fn next(self) {
let last_i = read(self.i);
send(join(), self.c_out, last_i);
write(self.i, last_i + 1);
}
}
)";

XLS_EXPECT_OK(
ParseAndTypecheck(kImported, "imported.x", "imported", &import_data));

constexpr std::string_view kProgram = R"(
#![feature(explicit_state_access)]

import imported;

proc C {
c_in: chan<u32> in,
i: u32,
}

impl C {
fn new(c_in: chan<u32> in) -> Self {
C { c_in: c_in, i: 0 }
}
fn next(self) {
let last_i = read(self.i);
let (tok1, e) = recv(join(), self.c_in);
write(self.i, e + last_i);
}
}

proc Main {}

impl Main {
fn new() -> Self {
let (c_out, c_in) = chan<u32>("my_chan");
imported::P::new(c_out).spawn();
let c = C::new(c_in);
c.spawn();
Main {}
}

fn next(self) {}
}
)";

XLS_ASSERT_OK_AND_ASSIGN(
std::string converted,
ConvertModuleForTest(kProgram, kProcScopedChannelOptions, &import_data));
ExpectIr(converted);
}

TEST_F(IrConverterTest, SendIfRecvIf) {
constexpr std::string_view program = R"(proc producer {
c: chan<u32> out;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package test_module

file_number 0 "test_module.x"
file_number 1 "imported.x"

proc __imported__P_next<_c_out: bits[32] out>(__i: bits[32], init={0}) {
chan_interface _c_out(direction=send, kind=streaming, strictness=proven_mutually_exclusive, flow_control=ready_valid, flop_kind=none)
literal.32: bits[1] = literal(value=1, id=32)
literal.33: bits[1] = literal(value=0, id=33)
not.36: bits[1] = not(literal.32, id=36)
not.37: bits[1] = not(literal.33, id=37)
__token: token = literal(value=token, id=31)
or.38: bits[1] = or(not.36, not.37, id=38)
not.48: bits[1] = not(literal.32, id=48)
or.40: bits[1] = or(literal.33, literal.32, id=40)
literal.34: bits[1] = literal(value=0, id=34)
__i__1: bits[32] = state_read(state_element=__i, predicate=literal.32, id=41)
assert.39: token = assert(__token, or.38, message="State element read after read in same activation.", id=39)
or.49: bits[1] = or(not.48, or.40, id=49)
not.51: bits[1] = not(literal.32, id=51)
not.52: bits[1] = not(literal.34, id=52)
last_i: bits[32] = identity(__i__1, id=42)
literal.46: bits[32] = literal(value=1, id=46)
after_all.44: token = after_all(id=44)
assert.50: token = assert(assert.39, or.49, message="State element written before read in same activation.", id=50)
or.53: bits[1] = or(not.51, not.52, id=53)
__i: bits[32] = state_read(state_element=__i, id=35)
add.47: bits[32] = add(last_i, literal.46, id=47)
or.43: bits[1] = or(literal.33, literal.32, id=43)
send.45: token = send(after_all.44, last_i, predicate=literal.32, channel=_c_out, id=45)
assert.54: token = assert(assert.50, or.53, message="State element written after write in same activation.", id=54)
or.55: bits[1] = or(literal.34, literal.32, id=55)
next_value.56: () = next_value(param=__i, value=add.47, predicate=literal.32, id=56)
tuple.57: () = tuple(id=57)
tuple.58: () = tuple(id=58)
}

proc __test_module__C_next<_c_in: bits[32] in>(__i: bits[32], init={0}) {
chan_interface _c_in(direction=receive, kind=streaming, strictness=proven_mutually_exclusive, flow_control=ready_valid, flop_kind=none)
literal.2: bits[1] = literal(value=1, id=2)
literal.3: bits[1] = literal(value=0, id=3)
not.6: bits[1] = not(literal.2, id=6)
not.7: bits[1] = not(literal.3, id=7)
after_all.14: token = after_all(id=14)
__token: token = literal(value=token, id=1)
or.8: bits[1] = or(not.6, not.7, id=8)
not.20: bits[1] = not(literal.2, id=20)
or.10: bits[1] = or(literal.3, literal.2, id=10)
literal.4: bits[1] = literal(value=0, id=4)
receive.15: (token, bits[32]) = receive(after_all.14, predicate=literal.2, channel=_c_in, id=15)
__i__1: bits[32] = state_read(state_element=__i, predicate=literal.2, id=11)
assert.9: token = assert(__token, or.8, message="State element read after read in same activation.", id=9)
or.21: bits[1] = or(not.20, or.10, id=21)
not.23: bits[1] = not(literal.2, id=23)
not.24: bits[1] = not(literal.4, id=24)
e: bits[32] = tuple_index(receive.15, index=1, id=18)
last_i: bits[32] = identity(__i__1, id=12)
assert.22: token = assert(assert.9, or.21, message="State element written before read in same activation.", id=22)
or.25: bits[1] = or(not.23, not.24, id=25)
__i: bits[32] = state_read(state_element=__i, id=5)
add.19: bits[32] = add(e, last_i, id=19)
or.13: bits[1] = or(literal.3, literal.2, id=13)
tuple_index.16: token = tuple_index(receive.15, index=0, id=16)
tok1: token = tuple_index(receive.15, index=0, id=17)
assert.26: token = assert(assert.22, or.25, message="State element written after write in same activation.", id=26)
or.27: bits[1] = or(literal.4, literal.2, id=27)
next_value.28: () = next_value(param=__i, value=add.19, predicate=literal.2, id=28)
tuple.29: () = tuple(id=29)
tuple.30: () = tuple(id=30)
}

proc __test_module__Main_next<>() {
chan _my_chan(bits[32], id=0, kind=streaming, ops=send_receive, flow_control=ready_valid, strictness=proven_mutually_exclusive)
chan_interface _my_chan(direction=send, kind=streaming, strictness=proven_mutually_exclusive, flow_control=none, flop_kind=none)
chan_interface _my_chan(direction=receive, kind=streaming, strictness=proven_mutually_exclusive, flow_control=none, flop_kind=none)
proc_instantiation __imported__P_next_inst(_my_chan, proc=__imported__P_next)
proc_instantiation __test_module__C_next_inst(_my_chan, proc=__test_module__C_next)
__token: token = literal(value=token, id=59)
literal.60: bits[1] = literal(value=1, id=60)
tuple.61: () = tuple(id=61)
}
60 changes: 60 additions & 0 deletions xls/dslx/type_system_v2/typecheck_module_v2_proc_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -647,5 +647,65 @@ impl Loopback {
"chan(uN[32], dir=out) }) -> ()")));
}

TEST(TypecheckV2Test, SpawnImportedProcDef) {
std::string_view kImported = R"(
#![feature(explicit_state_access)]

pub proc P {
c_out: chan<u32> out,
i: u32,
}

impl P {
fn new(c_out: chan<u32> out) -> Self {
P { c_out: c_out, i: 0 }
}

fn next(self) {
let last_i = read(self.i);
send(join(), self.c_out, last_i);
write(self.i, last_i + 1);
}
}
)";

constexpr std::string_view kProgram = R"(
#![feature(explicit_state_access)]

import imported;
proc C {
c_in: chan<u32> in,
i: u32,
}

impl C {
fn new(c_in: chan<u32> in) -> Self {
C { c_in: c_in, i: 0 }
}
fn next(self) {
let last_i = read(self.i);
let (tok1, e) = recv(join(), self.c_in);
write(self.i, e + last_i);
}
}

proc Main {}

impl Main {
fn new() -> Self {
let (c_out, c_in) = chan<u32>("my_chan");
imported::P::new(c_out).spawn();
let c = C::new(c_in);
c.spawn();
Main {}
}
}
)";

ImportData import_data = CreateImportDataForTest();
XLS_EXPECT_OK(TypecheckV2(kImported, "imported", &import_data).status());
XLS_EXPECT_OK(TypecheckV2(kProgram, "main", &import_data));
}

} // namespace
} // namespace xls::dslx
Loading