Skip to content

Commit 350e8ad

Browse files
authored
Initial fixed-length list implementation (#1277)
* more fixed size implementation * more fixed list implementation * test passes with modified wasmtime * document and compare test * returning a fixed size list works * re-enable normal parameters * clean up and use wac fork * another testcase passing * oh, two failing tests * integrate changes from symmetric branch * adapt and simplify C++ example * modernize code * linear code size for fixed size arrays (except when flattened) * fix element offset, missing code for c++, missing testing argument * leverage #1497 (wasmtime flags in test case) * standardize on fixed *length* lists name * another naming correction * standardize on iter_elem variable name * one file was missing in the last commit
1 parent 10291cd commit 350e8ad

File tree

15 files changed

+869
-44
lines changed

15 files changed

+869
-44
lines changed

Cargo.lock

Lines changed: 359 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/c/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,6 +1825,16 @@ impl<'a> wit_bindgen_core::AnonymousTypeGenerator<'a> for InterfaceGenerator<'a>
18251825
fn anonymous_type_type(&mut self, _id: TypeId, _ty: &Type, _docs: &Docs) {
18261826
todo!("print_anonymous_type for type");
18271827
}
1828+
1829+
fn anonymous_type_fixed_length_list(
1830+
&mut self,
1831+
_id: TypeId,
1832+
_ty: &Type,
1833+
_size: u32,
1834+
_docs: &Docs,
1835+
) {
1836+
todo!("print_anonymous_type for fixed length list");
1837+
}
18281838
}
18291839

18301840
pub enum CTypeNameInfo<'a> {

crates/core/src/abi.rs

Lines changed: 96 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,39 @@ def_instruction! {
309309
ty: TypeId,
310310
} : [2] => [1],
311311

312+
/// Pops all fields for a fixed list off the stack and then composes them
313+
/// into an array.
314+
FixedLengthListLift {
315+
element: &'a Type,
316+
size: u32,
317+
id: TypeId,
318+
} : [*size as usize] => [1],
319+
320+
/// Pops an array off the stack, decomposes the elements and then pushes them onto the stack.
321+
FixedLengthListLower {
322+
element: &'a Type,
323+
size: u32,
324+
id: TypeId,
325+
} : [1] => [*size as usize],
326+
327+
/// Pops an array and an address off the stack, passes each element to a block storing it
328+
FixedLengthListLowerToMemory {
329+
element: &'a Type,
330+
size: u32,
331+
id: TypeId,
332+
} : [2] => [0],
333+
334+
/// Pops base address, pushes an array
335+
///
336+
/// This will also pop a block from the block stack which is how to
337+
/// read each individual element from the list.
338+
FixedLengthListLiftFromMemory {
339+
element: &'a Type,
340+
size: u32,
341+
id: TypeId,
342+
} : [1] => [1],
343+
344+
312345
/// Pushes an operand onto the stack representing the list item from
313346
/// each iteration of the list.
314347
///
@@ -840,7 +873,7 @@ fn needs_deallocate(resolve: &Resolve, ty: &Type, what: Deallocate) -> bool {
840873
TypeDefKind::Flags(_) | TypeDefKind::Enum(_) => false,
841874
TypeDefKind::Future(_) | TypeDefKind::Stream(_) => what.handles(),
842875
TypeDefKind::Unknown => unreachable!(),
843-
TypeDefKind::FixedSizeList(..) => todo!(),
876+
TypeDefKind::FixedSizeList(t, _) => needs_deallocate(resolve, t, what),
844877
TypeDefKind::Map(..) => todo!(),
845878
},
846879

@@ -1564,7 +1597,21 @@ impl<'a, B: Bindgen> Generator<'a, B> {
15641597
});
15651598
}
15661599
TypeDefKind::Unknown => unreachable!(),
1567-
TypeDefKind::FixedSizeList(..) => todo!(),
1600+
TypeDefKind::FixedSizeList(ty, size) => {
1601+
self.emit(&FixedLengthListLower {
1602+
element: ty,
1603+
size: *size,
1604+
id,
1605+
});
1606+
let mut values = self
1607+
.stack
1608+
.drain(self.stack.len() - (*size as usize)..)
1609+
.collect::<Vec<_>>();
1610+
for value in values.drain(..) {
1611+
self.stack.push(value);
1612+
self.lower(ty);
1613+
}
1614+
}
15681615
TypeDefKind::Map(..) => todo!(),
15691616
},
15701617
}
@@ -1748,7 +1795,24 @@ impl<'a, B: Bindgen> Generator<'a, B> {
17481795
});
17491796
}
17501797
TypeDefKind::Unknown => unreachable!(),
1751-
TypeDefKind::FixedSizeList(..) => todo!(),
1798+
TypeDefKind::FixedSizeList(ty, size) => {
1799+
let temp = flat_types(self.resolve, ty, None).unwrap();
1800+
let flat_per_elem = temp.to_vec().len();
1801+
let flatsize = flat_per_elem * (*size as usize);
1802+
let mut lowered_args = self
1803+
.stack
1804+
.drain(self.stack.len() - flatsize..)
1805+
.collect::<Vec<_>>();
1806+
for _ in 0..*size {
1807+
self.stack.extend(lowered_args.drain(..flat_per_elem));
1808+
self.lift(ty);
1809+
}
1810+
self.emit(&FixedLengthListLift {
1811+
element: ty,
1812+
size: *size,
1813+
id,
1814+
});
1815+
}
17521816
TypeDefKind::Map(..) => todo!(),
17531817
},
17541818
}
@@ -1931,7 +1995,21 @@ impl<'a, B: Bindgen> Generator<'a, B> {
19311995
}
19321996

19331997
TypeDefKind::Unknown => unreachable!(),
1934-
TypeDefKind::FixedSizeList(..) => todo!(),
1998+
TypeDefKind::FixedSizeList(element, size) => {
1999+
// resembles write_list_to_memory
2000+
self.push_block();
2001+
self.emit(&IterElem { element });
2002+
self.emit(&IterBasePointer);
2003+
let elem_addr = self.stack.pop().unwrap();
2004+
self.write_to_memory(element, elem_addr, offset);
2005+
self.finish_block(0);
2006+
self.stack.push(addr);
2007+
self.emit(&FixedLengthListLowerToMemory {
2008+
element,
2009+
size: *size,
2010+
id,
2011+
});
2012+
}
19352013
TypeDefKind::Map(..) => todo!(),
19362014
},
19372015
}
@@ -2119,7 +2197,19 @@ impl<'a, B: Bindgen> Generator<'a, B> {
21192197
}
21202198

21212199
TypeDefKind::Unknown => unreachable!(),
2122-
TypeDefKind::FixedSizeList(..) => todo!(),
2200+
TypeDefKind::FixedSizeList(ty, size) => {
2201+
self.push_block();
2202+
self.emit(&IterBasePointer);
2203+
let elemaddr = self.stack.pop().unwrap();
2204+
self.read_from_memory(ty, elemaddr, offset);
2205+
self.finish_block(1);
2206+
self.stack.push(addr.clone());
2207+
self.emit(&FixedLengthListLiftFromMemory {
2208+
element: ty,
2209+
size: *size,
2210+
id,
2211+
});
2212+
}
21232213
TypeDefKind::Map(..) => todo!(),
21242214
},
21252215
}
@@ -2430,7 +2520,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
24302520
TypeDefKind::Future(_) => unreachable!(),
24312521
TypeDefKind::Stream(_) => unreachable!(),
24322522
TypeDefKind::Unknown => unreachable!(),
2433-
TypeDefKind::FixedSizeList(..) => todo!(),
2523+
TypeDefKind::FixedSizeList(_, _) => {}
24342524
TypeDefKind::Map(..) => todo!(),
24352525
},
24362526
}

crates/core/src/lib.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ pub trait AnonymousTypeGenerator<'a> {
196196
fn anonymous_type_option(&mut self, id: TypeId, ty: &Type, docs: &Docs);
197197
fn anonymous_type_result(&mut self, id: TypeId, ty: &Result_, docs: &Docs);
198198
fn anonymous_type_list(&mut self, id: TypeId, ty: &Type, docs: &Docs);
199+
fn anonymous_type_fixed_length_list(&mut self, id: TypeId, ty: &Type, size: u32, docs: &Docs);
199200
fn anonymous_type_future(&mut self, id: TypeId, ty: &Option<Type>, docs: &Docs);
200201
fn anonymous_type_stream(&mut self, id: TypeId, ty: &Option<Type>, docs: &Docs);
201202
fn anonymous_type_type(&mut self, id: TypeId, ty: &Type, docs: &Docs);
@@ -218,7 +219,9 @@ pub trait AnonymousTypeGenerator<'a> {
218219
TypeDefKind::Future(f) => self.anonymous_type_future(id, f, &ty.docs),
219220
TypeDefKind::Stream(s) => self.anonymous_type_stream(id, s, &ty.docs),
220221
TypeDefKind::Handle(handle) => self.anonymous_type_handle(id, handle, &ty.docs),
221-
TypeDefKind::FixedSizeList(..) => todo!(),
222+
TypeDefKind::FixedSizeList(t, size) => {
223+
self.anonymous_type_fixed_length_list(id, t, *size, &ty.docs)
224+
}
222225
TypeDefKind::Map(..) => todo!(),
223226
TypeDefKind::Unknown => unreachable!(),
224227
}

crates/core/src/types.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,9 @@ impl Types {
203203
// should use the same ownership semantics as `own<T>`
204204
info.has_own_handle = true;
205205
}
206-
TypeDefKind::FixedSizeList(..) => todo!(),
206+
TypeDefKind::FixedSizeList(ty, _) => {
207+
info = self.type_info(resolve, ty);
208+
}
207209
TypeDefKind::Map(..) => todo!(),
208210
TypeDefKind::Unknown => unreachable!(),
209211
}

crates/cpp/src/lib.rs

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct Includes {
7474
// needs wit types
7575
needs_wit: bool,
7676
needs_memory: bool,
77+
needs_array: bool,
7778
}
7879

7980
#[derive(Default)]
@@ -428,6 +429,9 @@ impl Cpp {
428429
if self.dependencies.needs_memory {
429430
self.include("<memory>");
430431
}
432+
if self.dependencies.needs_array {
433+
self.include("<array>");
434+
}
431435
if self.dependencies.needs_bit {
432436
self.include("<bit>");
433437
}
@@ -1698,7 +1702,13 @@ impl CppInterfaceGenerator<'_> {
16981702
TypeDefKind::Future(_) => todo!(),
16991703
TypeDefKind::Stream(_) => todo!(),
17001704
TypeDefKind::Type(ty) => self.type_name(ty, from_namespace, flavor),
1701-
TypeDefKind::FixedSizeList(_, _) => todo!(),
1705+
TypeDefKind::FixedSizeList(ty, size) => {
1706+
self.r#gen.dependencies.needs_array = true;
1707+
format!(
1708+
"std::array<{}, {size}>",
1709+
self.type_name(ty, from_namespace, flavor)
1710+
)
1711+
}
17021712
TypeDefKind::Map(_, _) => todo!(),
17031713
TypeDefKind::Unknown => todo!(),
17041714
},
@@ -2532,7 +2542,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
25322542
"auto base = {ptr} + i * {size};\n",
25332543
size = size.format(POINTER_SIZE_EXPRESSION)
25342544
));
2535-
self.push_str(&format!("auto&& IterElem = {val}[i];\n"));
2545+
self.push_str(&format!("auto&& iter_elem = {val}[i];\n"));
25362546
self.push_str(&format!("{}\n", body.0));
25372547
self.push_str("}\n");
25382548
if realloc.is_none() {
@@ -2648,7 +2658,94 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
26482658
results.push(move_if_necessary(&result));
26492659
}
26502660
}
2651-
abi::Instruction::IterElem { .. } => results.push("IterElem".to_string()),
2661+
abi::Instruction::FixedLengthListLift {
2662+
element,
2663+
size,
2664+
id: _,
2665+
} => {
2666+
let tmp = self.tmp();
2667+
let result = format!("result{tmp}");
2668+
let typename = self
2669+
.r#gen
2670+
.type_name(element, &self.namespace, Flavor::InStruct);
2671+
self.push_str(&format!("std::array<{typename}, {size}> {result} = {{",));
2672+
for a in operands.drain(0..(*size as usize)) {
2673+
self.push_str(&a);
2674+
self.push_str(", ");
2675+
}
2676+
self.push_str("};\n");
2677+
results.push(result);
2678+
}
2679+
abi::Instruction::FixedLengthListLiftFromMemory {
2680+
element,
2681+
size: elemsize,
2682+
id: _,
2683+
} => {
2684+
let body = self.blocks.pop().unwrap();
2685+
let tmp = self.tmp();
2686+
let vec = format!("array{tmp}");
2687+
let source = operands[0].clone();
2688+
let size = self.r#gen.sizes.size(element);
2689+
let size_str = size.format(POINTER_SIZE_EXPRESSION);
2690+
let typename = self
2691+
.r#gen
2692+
.type_name(element, &self.namespace, Flavor::InStruct);
2693+
let ptr_type = self.r#gen.r#gen.opts.ptr_type();
2694+
self.push_str(&format!("std::array<{typename}, {elemsize}> {vec};\n"));
2695+
self.push_str(&format!(
2696+
"{{
2697+
{ptr_type} outer_base = {source};\n"
2698+
));
2699+
let source: String = "outer_base".into();
2700+
// let vec: String = "outer_vec".into();
2701+
self.push_str(&format!("for (unsigned i = 0; i<{elemsize}; ++i) {{\n",));
2702+
self.push_str(&format!("{ptr_type} base = {source} + i * {size_str};\n"));
2703+
self.push_str(&body.0);
2704+
self.push_str(&format!("{vec}[i] = {};", body.1[0]));
2705+
self.push_str("\n}\n}\n");
2706+
results.push(vec);
2707+
}
2708+
abi::Instruction::FixedLengthListLower {
2709+
element: _,
2710+
size,
2711+
id: _,
2712+
} => {
2713+
for i in 0..(*size as usize) {
2714+
results.push(format!("{}[{i}]", operands[0]));
2715+
}
2716+
}
2717+
abi::Instruction::FixedLengthListLowerToMemory {
2718+
element,
2719+
size: elemsize,
2720+
id: _,
2721+
} => {
2722+
let body = self.blocks.pop().unwrap();
2723+
let vec = operands[0].clone();
2724+
let target = operands[1].clone();
2725+
let size = self.r#gen.sizes.size(element);
2726+
let size_str = size.format(POINTER_SIZE_EXPRESSION);
2727+
let typename = self
2728+
.r#gen
2729+
.type_name(element, &self.namespace, Flavor::InStruct);
2730+
let ptr_type = self.r#gen.r#gen.opts.ptr_type();
2731+
self.push_str(&format!(
2732+
"{{
2733+
{ptr_type} outer_base = {target};\n"
2734+
));
2735+
let target: String = "outer_base".into();
2736+
self.push_str(&format!(
2737+
"std::array<{typename}, {elemsize}>& outer_vec = {vec};\n"
2738+
));
2739+
let vec: String = "outer_vec".into();
2740+
self.push_str(&format!("for (unsigned i = 0; i<{vec}.size(); ++i) {{\n",));
2741+
self.push_str(&format!(
2742+
"{ptr_type} base = {target} + i * {size_str};
2743+
{typename}& iter_elem = {vec}[i];\n"
2744+
));
2745+
self.push_str(&body.0);
2746+
self.push_str("\n}\n}\n");
2747+
}
2748+
abi::Instruction::IterElem { .. } => results.push("iter_elem".to_string()),
26522749
abi::Instruction::IterBasePointer => results.push("base".to_string()),
26532750
abi::Instruction::RecordLower { record, .. } => {
26542751
let op = &operands[0];
@@ -3254,7 +3351,7 @@ impl<'a, 'b> Bindgen for FunctionBindgen<'a, 'b> {
32543351
self.src.push_str(">(");
32553352
}
32563353
if *amt == 1 {
3257-
if operands[0].starts_with("std::move(") {
3354+
if operands[0].starts_with("std::move(") && !operands[0].contains('.') {
32583355
// remove the std::move due to return value optimization (and complex rules about when std::move harms)
32593356
self.src.push_str(&operands[0][9..]);
32603357
} else {

crates/csharp/src/function.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,10 @@ impl Bindgen for FunctionBindgen<'_, '_> {
14451445
| Instruction::ErrorContextLower { .. }
14461446
| Instruction::ErrorContextLift { .. }
14471447
| Instruction::DropHandle { .. }
1448+
| Instruction::FixedLengthListLift { .. }
1449+
| Instruction::FixedLengthListLower { .. }
1450+
| Instruction::FixedLengthListLowerToMemory { .. }
1451+
| Instruction::FixedLengthListLiftFromMemory { .. }
14481452
=> {
14491453
dbg!(inst);
14501454
todo!()

crates/moonbit/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,10 @@ impl Bindgen for FunctionBindgen<'_, '_> {
26962696
Instruction::ErrorContextLower { .. }
26972697
| Instruction::ErrorContextLift { .. }
26982698
| Instruction::DropHandle { .. } => todo!(),
2699+
Instruction::FixedLengthListLift { .. } => todo!(),
2700+
Instruction::FixedLengthListLower { .. } => todo!(),
2701+
Instruction::FixedLengthListLowerToMemory { .. } => todo!(),
2702+
Instruction::FixedLengthListLiftFromMemory { .. } => todo!(),
26992703
}
27002704
}
27012705

0 commit comments

Comments
 (0)