Skip to content

Commit 96c2532

Browse files
committed
C: Use pointer types
Teach the C backend to use C pointer types. This is similar to bytecodealliance#870 for Rust. C is less concerned about provenance, but it makes the ABI easier to understand and reduces the amount of casting needed in the generated code. While here, I also optimized the code for list deallocation slightly.
1 parent 70ab122 commit 96c2532

File tree

2 files changed

+55
-48
lines changed

2 files changed

+55
-48
lines changed

crates/c/src/lib.rs

+41-34
Original file line numberDiff line numberDiff line change
@@ -1455,12 +1455,17 @@ impl InterfaceGenerator<'_> {
14551455
}
14561456

14571457
TypeDefKind::List(t) => {
1458+
self.src.c_helpers("size_t list_len = ptr->len;\n");
1459+
uwriteln!(self.src.c_helpers, "if (list_len > 0) {{");
1460+
let mut t_name = String::new();
1461+
self.gen.push_type_name(t, &mut t_name);
14581462
self.src
1459-
.c_helpers("for (size_t i = 0; i < ptr->len; i++) {\n");
1460-
self.free(t, "&ptr->ptr[i]");
1463+
.c_helpers(&format!("{t_name} *list_ptr = ptr->ptr;\n"));
1464+
self.src
1465+
.c_helpers("for (size_t i = 0; i < list_len; i++) {\n");
1466+
self.free(t, "&list_ptr[i]");
14611467
self.src.c_helpers("}\n");
1462-
uwriteln!(self.src.c_helpers, "if (ptr->len > 0) {{");
1463-
uwriteln!(self.src.c_helpers, "free(ptr->ptr);");
1468+
uwriteln!(self.src.c_helpers, "free(list_ptr);");
14641469
uwriteln!(self.src.c_helpers, "}}");
14651470
}
14661471

@@ -2111,13 +2116,13 @@ impl Bindgen for FunctionBindgen<'_, '_> {
21112116
self.import_return_pointer_area_size = self.import_return_pointer_area_size.max(size);
21122117
self.import_return_pointer_area_align =
21132118
self.import_return_pointer_area_align.max(align);
2114-
uwriteln!(self.src, "int32_t {} = (int32_t) &ret_area;", ptr);
2119+
uwriteln!(self.src, "uint8_t *{} = (uint8_t *) &ret_area;", ptr);
21152120
} else {
21162121
self.gen.gen.return_pointer_area_size = self.gen.gen.return_pointer_area_size.max(size);
21172122
self.gen.gen.return_pointer_area_align =
21182123
self.gen.gen.return_pointer_area_align.max(align);
21192124
// Declare a statically-allocated return area.
2120-
uwriteln!(self.src, "int32_t {} = (int32_t) &RET_AREA;", ptr);
2125+
uwriteln!(self.src, "uint8_t *{} = (uint8_t *) &RET_AREA;", ptr);
21212126
}
21222127

21232128
ptr
@@ -2562,23 +2567,23 @@ impl Bindgen for FunctionBindgen<'_, '_> {
25622567
Instruction::EnumLift { .. } => results.push(operands.pop().unwrap()),
25632568

25642569
Instruction::ListCanonLower { .. } | Instruction::StringLower { .. } => {
2565-
results.push(format!("(int32_t) ({}).ptr", operands[0]));
2566-
results.push(format!("(int32_t) ({}).len", operands[0]));
2570+
results.push(format!("(uint8_t *) ({}).ptr", operands[0]));
2571+
results.push(format!("({}).len", operands[0]));
25672572
}
25682573
Instruction::ListCanonLift { element, ty, .. } => {
25692574
self.assert_no_droppable_borrows("list", &Type::Id(*ty));
25702575

25712576
let list_name = self.gen.gen.type_name(&Type::Id(*ty));
25722577
let elem_name = self.gen.gen.type_name(element);
25732578
results.push(format!(
2574-
"({}) {{ ({}*)({}), (size_t)({}) }}",
2579+
"({}) {{ ({}*)({}), ({}) }}",
25752580
list_name, elem_name, operands[0], operands[1]
25762581
));
25772582
}
25782583
Instruction::StringLift { .. } => {
25792584
let list_name = self.gen.gen.type_name(&Type::String);
25802585
results.push(format!(
2581-
"({}) {{ ({}*)({}), (size_t)({}) }}",
2586+
"({}) {{ ({}*)({}), ({}) }}",
25822587
list_name,
25832588
self.gen.gen.char_type(),
25842589
operands[0],
@@ -2588,8 +2593,8 @@ impl Bindgen for FunctionBindgen<'_, '_> {
25882593

25892594
Instruction::ListLower { .. } => {
25902595
let _body = self.blocks.pop().unwrap();
2591-
results.push(format!("(int32_t) ({}).ptr", operands[0]));
2592-
results.push(format!("(int32_t) ({}).len", operands[0]));
2596+
results.push(format!("(uint8_t *) ({}).ptr", operands[0]));
2597+
results.push(format!("({}).len", operands[0]));
25932598
}
25942599

25952600
Instruction::ListLift { element, ty, .. } => {
@@ -2599,7 +2604,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
25992604
let list_name = self.gen.gen.type_name(&Type::Id(*ty));
26002605
let elem_name = self.gen.gen.type_name(element);
26012606
results.push(format!(
2602-
"({}) {{ ({}*)({}), (size_t)({}) }}",
2607+
"({}) {{ ({}*)({}), ({}) }}",
26032608
list_name, elem_name, operands[0], operands[1]
26042609
));
26052610
}
@@ -2841,22 +2846,22 @@ impl Bindgen for FunctionBindgen<'_, '_> {
28412846
}
28422847
}
28432848

2844-
Instruction::I32Load { offset }
2845-
| Instruction::PointerLoad { offset }
2846-
| Instruction::LengthLoad { offset } => {
2847-
self.load("int32_t", *offset, operands, results)
2848-
}
2849+
Instruction::I32Load { offset } => self.load("int32_t", *offset, operands, results),
28492850
Instruction::I64Load { offset } => self.load("int64_t", *offset, operands, results),
28502851
Instruction::F32Load { offset } => self.load("float", *offset, operands, results),
28512852
Instruction::F64Load { offset } => self.load("double", *offset, operands, results),
2852-
Instruction::I32Store { offset }
2853-
| Instruction::PointerStore { offset }
2854-
| Instruction::LengthStore { offset } => self.store("int32_t", *offset, operands),
2853+
Instruction::PointerLoad { offset } => {
2854+
self.load("uint8_t *", *offset, operands, results)
2855+
}
2856+
Instruction::LengthLoad { offset } => self.load("size_t", *offset, operands, results),
2857+
Instruction::I32Store { offset } => self.store("int32_t", *offset, operands),
28552858
Instruction::I64Store { offset } => self.store("int64_t", *offset, operands),
28562859
Instruction::F32Store { offset } => self.store("float", *offset, operands),
28572860
Instruction::F64Store { offset } => self.store("double", *offset, operands),
28582861
Instruction::I32Store8 { offset } => self.store("int8_t", *offset, operands),
28592862
Instruction::I32Store16 { offset } => self.store("int16_t", *offset, operands),
2863+
Instruction::PointerStore { offset } => self.store("uint8_t *", *offset, operands),
2864+
Instruction::LengthStore { offset } => self.store("size_t", *offset, operands),
28602865

28612866
Instruction::I32Load8U { offset } => {
28622867
self.load_ext("uint8_t", *offset, operands, results)
@@ -2872,11 +2877,11 @@ impl Bindgen for FunctionBindgen<'_, '_> {
28722877
}
28732878

28742879
Instruction::GuestDeallocate { .. } => {
2875-
uwriteln!(self.src, "free((void*) ({}));", operands[0]);
2880+
uwriteln!(self.src, "free({});", operands[0]);
28762881
}
28772882
Instruction::GuestDeallocateString => {
28782883
uwriteln!(self.src, "if (({}) > 0) {{", operands[1]);
2879-
uwriteln!(self.src, "free((void*) ({}));", operands[0]);
2884+
uwriteln!(self.src, "free({});", operands[0]);
28802885
uwriteln!(self.src, "}}");
28812886
}
28822887
Instruction::GuestDeallocateVariant { blocks } => {
@@ -2897,19 +2902,19 @@ impl Bindgen for FunctionBindgen<'_, '_> {
28972902
Instruction::GuestDeallocateList { element } => {
28982903
let (body, results) = self.blocks.pop().unwrap();
28992904
assert!(results.is_empty());
2900-
let ptr = self.locals.tmp("ptr");
29012905
let len = self.locals.tmp("len");
2902-
uwriteln!(self.src, "int32_t {ptr} = {};", operands[0]);
2903-
uwriteln!(self.src, "int32_t {len} = {};", operands[1]);
2906+
uwriteln!(self.src, "size_t {len} = {};", operands[1]);
2907+
uwriteln!(self.src, "if ({len} > 0) {{");
2908+
let ptr = self.locals.tmp("ptr");
2909+
uwriteln!(self.src, "uint8_t *{ptr} = {};", operands[0]);
29042910
let i = self.locals.tmp("i");
2905-
uwriteln!(self.src, "for (int32_t {i} = 0; {i} < {len}; {i}++) {{");
2911+
uwriteln!(self.src, "for (size_t {i} = 0; {i} < {len}; {i}++) {{");
29062912
let size = self.gen.gen.sizes.size(element);
2907-
uwriteln!(self.src, "int32_t base = {ptr} + {i} * {size};");
2913+
uwriteln!(self.src, "uint8_t *base = {ptr} + {i} * {size};");
29082914
uwriteln!(self.src, "(void) base;");
29092915
uwrite!(self.src, "{body}");
29102916
uwriteln!(self.src, "}}");
2911-
uwriteln!(self.src, "if ({len} > 0) {{");
2912-
uwriteln!(self.src, "free((void*) ({ptr}));");
2917+
uwriteln!(self.src, "free({ptr});");
29132918
uwriteln!(self.src, "}}");
29142919
}
29152920

@@ -2935,14 +2940,16 @@ fn perform_cast(op: &str, cast: &Bitcast) -> String {
29352940
Bitcast::I32ToI64 | Bitcast::LToI64 | Bitcast::PToP64 => {
29362941
format!("(int64_t) {}", op)
29372942
}
2938-
Bitcast::I64ToI32 | Bitcast::I64ToL | Bitcast::P64ToP => {
2943+
Bitcast::I64ToI32 | Bitcast::I64ToL => {
29392944
format!("(int32_t) {}", op)
29402945
}
29412946
Bitcast::I64ToP64 | Bitcast::P64ToI64 => {
29422947
format!("{}", op)
29432948
}
2944-
Bitcast::I32ToP
2945-
| Bitcast::PToI32
2949+
Bitcast::P64ToP | Bitcast::I32ToP => {
2950+
format!("(uint8_t *) {}", op)
2951+
}
2952+
Bitcast::PToI32
29462953
| Bitcast::I32ToL
29472954
| Bitcast::LToI32
29482955
| Bitcast::LToP
@@ -3031,7 +3038,7 @@ fn wasm_type(ty: WasmType) -> &'static str {
30313038
WasmType::I64 => "int64_t",
30323039
WasmType::F32 => "float",
30333040
WasmType::F64 => "double",
3034-
WasmType::Pointer => "uintptr_t",
3041+
WasmType::Pointer => "uint8_t *",
30353042
WasmType::PointerOrI64 => "int64_t",
30363043
WasmType::Length => "size_t",
30373044
}

crates/core/src/abi.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -84,32 +84,32 @@ def_instruction! {
8484

8585
// Memory load/store instructions
8686

87-
/// Pops an `i32` from the stack and loads a little-endian `i32` from
87+
/// Pops a pointer from the stack and loads a little-endian `i32` from
8888
/// it, using the specified constant offset.
8989
I32Load { offset: i32 } : [1] => [1],
90-
/// Pops an `i32` from the stack and loads a little-endian `i8` from
90+
/// Pops a pointer from the stack and loads a little-endian `i8` from
9191
/// it, using the specified constant offset. The value loaded is the
9292
/// zero-extended to 32-bits
9393
I32Load8U { offset: i32 } : [1] => [1],
94-
/// Pops an `i32` from the stack and loads a little-endian `i8` from
94+
/// Pops a pointer from the stack and loads a little-endian `i8` from
9595
/// it, using the specified constant offset. The value loaded is the
9696
/// sign-extended to 32-bits
9797
I32Load8S { offset: i32 } : [1] => [1],
98-
/// Pops an `i32` from the stack and loads a little-endian `i16` from
98+
/// Pops a pointer from the stack and loads a little-endian `i16` from
9999
/// it, using the specified constant offset. The value loaded is the
100100
/// zero-extended to 32-bits
101101
I32Load16U { offset: i32 } : [1] => [1],
102-
/// Pops an `i32` from the stack and loads a little-endian `i16` from
102+
/// Pops a pointer from the stack and loads a little-endian `i16` from
103103
/// it, using the specified constant offset. The value loaded is the
104104
/// sign-extended to 32-bits
105105
I32Load16S { offset: i32 } : [1] => [1],
106-
/// Pops an `i32` from the stack and loads a little-endian `i64` from
106+
/// Pops a pointer from the stack and loads a little-endian `i64` from
107107
/// it, using the specified constant offset.
108108
I64Load { offset: i32 } : [1] => [1],
109-
/// Pops an `i32` from the stack and loads a little-endian `f32` from
109+
/// Pops a pointer from the stack and loads a little-endian `f32` from
110110
/// it, using the specified constant offset.
111111
F32Load { offset: i32 } : [1] => [1],
112-
/// Pops an `i32` from the stack and loads a little-endian `f64` from
112+
/// Pops a pointer from the stack and loads a little-endian `f64` from
113113
/// it, using the specified constant offset.
114114
F64Load { offset: i32 } : [1] => [1],
115115

@@ -118,27 +118,27 @@ def_instruction! {
118118
/// Like `I32Load` or `I64Load`, but for loading array length values.
119119
LengthLoad { offset: i32 } : [1] => [1],
120120

121-
/// Pops an `i32` address from the stack and then an `i32` value.
121+
/// Pops a pointer from the stack and then an `i32` value.
122122
/// Stores the value in little-endian at the pointer specified plus the
123123
/// constant `offset`.
124124
I32Store { offset: i32 } : [2] => [0],
125-
/// Pops an `i32` address from the stack and then an `i32` value.
125+
/// Pops a pointer from the stack and then an `i32` value.
126126
/// Stores the low 8 bits of the value in little-endian at the pointer
127127
/// specified plus the constant `offset`.
128128
I32Store8 { offset: i32 } : [2] => [0],
129-
/// Pops an `i32` address from the stack and then an `i32` value.
129+
/// Pops a pointer from the stack and then an `i32` value.
130130
/// Stores the low 16 bits of the value in little-endian at the pointer
131131
/// specified plus the constant `offset`.
132132
I32Store16 { offset: i32 } : [2] => [0],
133-
/// Pops an `i32` address from the stack and then an `i64` value.
133+
/// Pops a pointer from the stack and then an `i64` value.
134134
/// Stores the value in little-endian at the pointer specified plus the
135135
/// constant `offset`.
136136
I64Store { offset: i32 } : [2] => [0],
137-
/// Pops an `i32` address from the stack and then an `f32` value.
137+
/// Pops a pointer from the stack and then an `f32` value.
138138
/// Stores the value in little-endian at the pointer specified plus the
139139
/// constant `offset`.
140140
F32Store { offset: i32 } : [2] => [0],
141-
/// Pops an `i32` address from the stack and then an `f64` value.
141+
/// Pops a pointer from the stack and then an `f64` value.
142142
/// Stores the value in little-endian at the pointer specified plus the
143143
/// constant `offset`.
144144
F64Store { offset: i32 } : [2] => [0],

0 commit comments

Comments
 (0)