Skip to content

Commit d47b6c5

Browse files
author
Guy Bedford
authored
gen-guest-c: scalar enum result -> bool return, ok & err ptrs (#450)
1 parent 1899a1d commit d47b6c5

3 files changed

Lines changed: 166 additions & 127 deletions

File tree

crates/gen-guest-c/src/lib.rs

Lines changed: 138 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ struct CSig {
6262
enum Scalar {
6363
Void,
6464
OptionBool(Type),
65-
ResultEnum { err: TypeId, max_err: usize },
65+
Result(bool),
6666
Type(Type),
6767
}
6868

@@ -399,24 +399,19 @@ impl Return {
399399
return;
400400
}
401401

402-
// Unpack `result<T, E>` returns where `E` looks like an enum
403-
// so we can return that in the scalar return and have `T` get
404-
// returned through the normal returns.
402+
// Unpack a result as a boolean return type, with two
403+
// return pointers for ok and err values
405404
TypeDefKind::Result(r) => {
406-
if let Some(Type::Id(err)) = r.err {
407-
if let TypeDefKind::Enum(enum_) = &iface.types[err].kind {
408-
self.scalar = Some(Scalar::ResultEnum {
409-
err,
410-
max_err: enum_.cases.len(),
411-
});
412-
if let Some(ok) = r.ok {
413-
self.retptrs.push(ok);
414-
}
415-
return;
416-
}
405+
let mut has_ok_type = false;
406+
if let Some(ok) = r.ok {
407+
has_ok_type = true;
408+
self.retptrs.push(ok);
417409
}
418-
419-
// fall through to the return pointer case
410+
if let Some(err) = r.err {
411+
self.retptrs.push(err);
412+
}
413+
self.scalar = Some(Scalar::Result(has_ok_type));
414+
return;
420415
}
421416

422417
// These types are always returned indirectly.
@@ -612,13 +607,6 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
612607
i,
613608
);
614609
}
615-
uwriteln!(
616-
self.src.h_defs,
617-
"#define {}_RESULT_{}_OK {}",
618-
self.name.to_shouty_snake_case(),
619-
name.to_shouty_snake_case(),
620-
int_max_str(enum_.tag())
621-
);
622610

623611
self.types
624612
.insert(id, mem::replace(&mut self.src.h_defs, prev));
@@ -869,13 +857,17 @@ impl InterfaceGenerator<'_> {
869857
self.gen.names.insert(&name).expect("duplicate symbols");
870858

871859
let start = self.src.h_fns.len();
860+
let mut result_rets = false;
861+
let mut result_rets_has_ok_type = false;
872862

873863
let ret = self.classify_ret(func);
874864
match &ret.scalar {
875865
None | Some(Scalar::Void) => self.src.h_fns("void"),
876866
Some(Scalar::OptionBool(_id)) => self.src.h_fns("bool"),
877-
Some(Scalar::ResultEnum { err, .. }) => {
878-
self.print_ty(SourceType::HFns, &Type::Id(*err))
867+
Some(Scalar::Result(has_ok_type)) => {
868+
result_rets = true;
869+
result_rets_has_ok_type = *has_ok_type;
870+
self.src.h_fns("bool");
879871
}
880872
Some(Scalar::Type(ty)) => self.print_ty(SourceType::HFns, ty),
881873
}
@@ -905,7 +897,14 @@ impl InterfaceGenerator<'_> {
905897
}
906898
self.print_ty(SourceType::HFns, ty);
907899
self.src.h_fns(" *");
908-
let name: String = if single_ret {
900+
let name: String = if result_rets {
901+
assert!(i <= 1);
902+
if i == 0 && result_rets_has_ok_type {
903+
"ret".into()
904+
} else {
905+
"err".into()
906+
}
907+
} else if single_ret {
909908
"ret".into()
910909
} else {
911910
format!("ret{}", i)
@@ -1420,6 +1419,7 @@ struct FunctionBindgen<'a, 'b> {
14201419
payloads: Vec<String>,
14211420
params: Vec<String>,
14221421
wasm_return: Option<String>,
1422+
ret_store_cnt: usize,
14231423
}
14241424

14251425
impl<'a, 'b> FunctionBindgen<'a, 'b> {
@@ -1439,6 +1439,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
14391439
payloads: Vec::new(),
14401440
params: Vec::new(),
14411441
wasm_return: None,
1442+
ret_store_cnt: 0,
14421443
}
14431444
}
14441445

@@ -1470,11 +1471,16 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
14701471
);
14711472
}
14721473

1473-
fn store_in_retptrs(&mut self, operands: &[String]) {
1474-
assert_eq!(operands.len(), self.sig.retptrs.len());
1475-
for (op, ptr) in operands.iter().zip(self.sig.retptrs.clone()) {
1476-
self.store_op(op, &format!("*{}", ptr));
1477-
}
1474+
fn store_in_retptr(&mut self, operand: &String) {
1475+
self.store_op(
1476+
operand,
1477+
&format!("*{}", self.sig.retptrs[self.ret_store_cnt]),
1478+
);
1479+
self.ret_store_cnt = self.ret_store_cnt + 1;
1480+
}
1481+
1482+
fn check_all_retptrs_written(&self) {
1483+
assert!(self.ret_store_cnt == self.sig.retptrs.len());
14781484
}
14791485
}
14801486

@@ -2162,88 +2168,120 @@ impl Bindgen for FunctionBindgen<'_, '_> {
21622168
);
21632169
results.push(option_ret);
21642170
}
2165-
Some(Scalar::ResultEnum { err, max_err }) => {
2171+
Some(Scalar::Result(has_ok_type)) => {
2172+
let result_ty = self
2173+
.gen
2174+
.type_string(func.results.iter_types().next().unwrap());
21662175
let ret = self.locals.tmp("ret");
2167-
let mut ok_names = Vec::new();
2168-
for ty in self.sig.ret.retptrs.iter() {
2169-
let val = self.locals.tmp("ok");
2176+
let mut ret_iter = self.sig.ret.retptrs.iter();
2177+
uwriteln!(self.src, "{result_ty} {ret};");
2178+
let ok_name = if *has_ok_type {
2179+
if let Some(ty) = ret_iter.next() {
2180+
let val = self.locals.tmp("ok");
2181+
if args.len() > 0 {
2182+
uwrite!(args, ", ");
2183+
}
2184+
uwrite!(args, "&{val}");
2185+
let ty = self.gen.type_string(ty);
2186+
uwriteln!(self.src, "{} {};", ty, val);
2187+
Some(val)
2188+
} else {
2189+
None
2190+
}
2191+
} else {
2192+
None
2193+
};
2194+
let err_name = if let Some(ty) = ret_iter.next() {
2195+
let val = self.locals.tmp("err");
21702196
if args.len() > 0 {
2171-
args.push_str(", ");
2197+
uwrite!(args, ", ")
21722198
}
2173-
args.push_str("&");
2174-
args.push_str(&val);
2199+
uwrite!(args, "&{val}");
21752200
let ty = self.gen.type_string(ty);
21762201
uwriteln!(self.src, "{} {};", ty, val);
2177-
ok_names.push(val);
2202+
Some(val)
2203+
} else {
2204+
None
2205+
};
2206+
assert!(ret_iter.next().is_none());
2207+
uwrite!(self.src, "");
2208+
uwriteln!(self.src, "{ret}.is_err = {}({args});", self.sig.name);
2209+
2210+
if let Some(err_name) = err_name {
2211+
uwriteln!(
2212+
self.src,
2213+
"if ({ret}.is_err) {{
2214+
{ret}.val.err = {err_name};
2215+
}}",
2216+
);
2217+
}
2218+
if let Some(ok_name) = ok_name {
2219+
uwriteln!(
2220+
self.src,
2221+
"if (!{ret}.is_err) {{
2222+
{ret}.val.ok = {ok_name};
2223+
}}"
2224+
);
2225+
} else {
2226+
uwrite!(self.src, "\n");
2227+
}
2228+
results.push(ret);
2229+
}
2230+
}
2231+
}
2232+
Instruction::Return { .. } if self.gen.in_import => {
2233+
match self.sig.ret.scalar {
2234+
None => {
2235+
for op in operands.iter() {
2236+
self.store_in_retptr(op);
2237+
}
2238+
}
2239+
Some(Scalar::Void) => {
2240+
assert!(operands.is_empty());
2241+
}
2242+
Some(Scalar::Type(_)) => {
2243+
assert_eq!(operands.len(), 1);
2244+
self.src.push_str("return ");
2245+
self.src.push_str(&operands[0]);
2246+
self.src.push_str(";\n");
2247+
}
2248+
Some(Scalar::OptionBool(_)) => {
2249+
assert_eq!(operands.len(), 1);
2250+
let variant = &operands[0];
2251+
self.store_in_retptr(&format!("{}.val", variant));
2252+
self.src.push_str("return ");
2253+
self.src.push_str(&variant);
2254+
self.src.push_str(".is_some;\n");
2255+
}
2256+
Some(Scalar::Result(has_ok_type)) => {
2257+
assert_eq!(operands.len(), 1);
2258+
let variant = &operands[0];
2259+
assert!(self.sig.retptrs.len() <= 2);
2260+
uwriteln!(self.src, "if (!{}.is_err) {{", variant);
2261+
if self.sig.retptrs.len() == 2 {
2262+
self.store_in_retptr(&format!("{}.val.ok", variant));
2263+
} else if self.sig.retptrs.len() == 1 && has_ok_type {
2264+
self.store_in_retptr(&format!("{}.val.ok", variant));
21782265
}
2179-
let err_ty = self.gen.type_string(&Type::Id(*err));
21802266
uwriteln!(
21812267
self.src,
2182-
"{} {} = {}({});",
2183-
err_ty,
2184-
ret,
2185-
self.sig.name,
2186-
args,
2268+
" return 0;
2269+
}} else {{"
21872270
);
2188-
let result_ty = self
2189-
.gen
2190-
.type_string(func.results.iter_types().next().unwrap());
2191-
let result_ret = self.locals.tmp("ret");
2192-
uwrite!(
2271+
if self.sig.retptrs.len() == 2 {
2272+
self.store_in_retptr(&format!("{}.val.err", variant));
2273+
} else if self.sig.retptrs.len() == 1 && !has_ok_type {
2274+
self.store_in_retptr(&format!("{}.val.err", variant));
2275+
}
2276+
uwriteln!(
21932277
self.src,
2194-
"
2195-
{ty} {ret};
2196-
if ({tag} <= {max}) {{
2197-
{ret}.is_err = true;
2198-
{ret}.val.err = {tag};
2199-
}} else {{
2200-
{ret}.is_err = false;
2201-
{set_ok}
2202-
}}
2203-
",
2204-
ty = result_ty,
2205-
ret = result_ret,
2206-
tag = ret,
2207-
max = max_err,
2208-
set_ok = if self.sig.ret.retptrs.len() == 0 {
2209-
String::new()
2210-
} else {
2211-
let name = ok_names.pop().unwrap();
2212-
format!("{}.val.ok = {};", result_ret, name)
2213-
},
2278+
" return 1;
2279+
}}"
22142280
);
2215-
results.push(result_ret);
22162281
}
22172282
}
2283+
self.check_all_retptrs_written();
22182284
}
2219-
Instruction::Return { .. } if self.gen.in_import => match self.sig.ret.scalar {
2220-
None => self.store_in_retptrs(operands),
2221-
Some(Scalar::Void) => {
2222-
assert!(operands.is_empty());
2223-
}
2224-
Some(Scalar::Type(_)) => {
2225-
assert_eq!(operands.len(), 1);
2226-
self.src.push_str("return ");
2227-
self.src.push_str(&operands[0]);
2228-
self.src.push_str(";\n");
2229-
}
2230-
Some(Scalar::OptionBool(_)) => {
2231-
assert_eq!(operands.len(), 1);
2232-
let variant = &operands[0];
2233-
self.store_in_retptrs(&[format!("{}.val", variant)]);
2234-
self.src.push_str("return ");
2235-
self.src.push_str(&variant);
2236-
self.src.push_str(".is_some;\n");
2237-
}
2238-
Some(Scalar::ResultEnum { .. }) => {
2239-
assert_eq!(operands.len(), 1);
2240-
let variant = &operands[0];
2241-
if self.sig.retptrs.len() > 0 {
2242-
self.store_in_retptrs(&[format!("{}.val.ok", variant)]);
2243-
}
2244-
uwriteln!(self.src, "return {}.is_err ? {0}.val.err : -1;", variant);
2245-
}
2246-
},
22472285
Instruction::Return { amt, .. } => {
22482286
assert!(*amt <= 1);
22492287
if *amt == 1 {
@@ -2407,15 +2445,6 @@ fn int_repr(ty: Int) -> &'static str {
24072445
}
24082446
}
24092447

2410-
fn int_max_str(ty: Int) -> String {
2411-
match ty {
2412-
Int::U8 => u8::MAX.to_string(),
2413-
Int::U16 => u16::MAX.to_string(),
2414-
Int::U32 => u32::MAX.to_string(),
2415-
Int::U64 => u64::MAX.to_string(),
2416-
}
2417-
}
2418-
24192448
fn flags_repr(f: &Flags) -> Int {
24202449
match f.repr() {
24212450
FlagsRepr::U8 => Int::U8,

tests/runtime/flavorful/wasm.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,16 @@ void flavorful_test_imports() {
6161
flavorful_string_free(&b);
6262
}
6363

64-
assert(imports_errno_result() == IMPORTS_MY_ERRNO_B);
64+
{
65+
imports_my_errno_t errno;
66+
assert(imports_errno_result(&errno));
67+
assert(errno == IMPORTS_MY_ERRNO_B);
68+
}
6569

66-
assert(imports_errno_result() == IMPORTS_RESULT_MY_ERRNO_OK);
70+
{
71+
imports_my_errno_t errno;
72+
assert(imports_errno_result(&errno) == 0);
73+
}
6774

6875
{
6976
flavorful_string_t a;
@@ -176,8 +183,9 @@ bool flavorful_f_list_in_variant3(flavorful_list_in_variant3_t *a, flavorful_str
176183
return true;
177184
}
178185

179-
flavorful_my_errno_t flavorful_errno_result(void) {
180-
return FLAVORFUL_MY_ERRNO_B;
186+
bool flavorful_errno_result(flavorful_my_errno_t *err) {
187+
*err = FLAVORFUL_MY_ERRNO_B;
188+
return true;
181189
}
182190

183191
void flavorful_list_typedefs(flavorful_list_typedef_t *a, flavorful_list_typedef3_t *c, flavorful_list_typedef2_t *ret0, flavorful_list_typedef3_t *ret1) {

0 commit comments

Comments
 (0)