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
96 changes: 70 additions & 26 deletions cmd/gravity/src/codegen/func.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use crate::{
go::{
comment,
imports::{
ERRORS_NEW, WAZERO_API_DECODE_F32, WAZERO_API_DECODE_F64, WAZERO_API_DECODE_I32,
WAZERO_API_DECODE_U32, WAZERO_API_ENCODE_F32, WAZERO_API_ENCODE_F64,
WAZERO_API_ENCODE_I32,
ERRORS_NEW, UTF8_VALID_RUNE, WAZERO_API_DECODE_F32, WAZERO_API_DECODE_F64,
WAZERO_API_DECODE_I32, WAZERO_API_DECODE_U32, WAZERO_API_ENCODE_F32,
WAZERO_API_ENCODE_F64,
},
GoIdentifier, GoResult, GoType, Operand,
},
Expand Down Expand Up @@ -1183,7 +1183,16 @@ impl Bindgen for Func<'_> {
$module_handle.Memory().WriteUint64Le($ptr+$offset, $tag)
}
}
Instruction::I32FromChar => todo!("implement instruction: {inst:?}"),
Instruction::I32FromChar => {
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := uint32($operand)
}
results.push(Operand::SingleValue(value))
}
Instruction::I64FromU64 => {
// I64FromU64 is a no-op reinterpretation (same 64-bit value,
// different signedness). Use uint64() identity cast — int64()
Expand All @@ -1199,27 +1208,24 @@ impl Bindgen for Func<'_> {
results.push(Operand::SingleValue(value.into()));
}
Instruction::I64FromS64 => {
// Go's int64 -> uint64 conversion keeps the two's-complement
// bits, which is the i64 the canonical ABI expects.
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := $operand
$(&value) := uint64($operand)
}
results.push(Operand::SingleValue(value.into()));
}
Instruction::I32FromS32 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := $WAZERO_API_ENCODE_I32($operand)
}
results.push(Operand::SingleValue(value))
}
// All of these values should fit in Go's `int32` type which allows a safe cast
Instruction::I32FromU16
// Go's integer conversion to uint32 sign-extends the signed types
// and zero-extends the unsigned ones, which is how the canonical
// ABI widens them to an i32. The result is the uint32 a host
// function returns, and uint64(result) equals api.EncodeI32 when
// CallWasm passes it to an export.
Instruction::I32FromS32
| Instruction::I32FromU16
| Instruction::I32FromS16
| Instruction::I32FromU8
| Instruction::I32FromS8 => {
Expand All @@ -1228,27 +1234,41 @@ impl Bindgen for Func<'_> {
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$(&value) := $WAZERO_API_ENCODE_I32(int32($operand))
$(&value) := uint32($operand)
}
results.push(Operand::SingleValue(value))
}
// A host function returns float32 and float64 directly, while
// CallWasm needs the IEEE bits in a uint64.
Instruction::CoreF32FromF32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := $WAZERO_API_ENCODE_F32($operand)
match self.direction {
Direction::Export => quote_in! { self.body =>
$['\r']
$result := $WAZERO_API_ENCODE_F32($operand)
},
Direction::Import { .. } => quote_in! { self.body =>
$['\r']
$result := $operand
},
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::CoreF64FromF64 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := $WAZERO_API_ENCODE_F64($operand)
match self.direction {
Direction::Export => quote_in! { self.body =>
$['\r']
$result := $WAZERO_API_ENCODE_F64($operand)
},
Direction::Import { .. } => quote_in! { self.body =>
$['\r']
$result := $operand
},
};
results.push(Operand::SingleValue(result.into()));
}
Expand Down Expand Up @@ -1306,7 +1326,16 @@ impl Bindgen for Func<'_> {
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::S64FromI64 => todo!("implement instruction: {inst:?}"),
Instruction::S64FromI64 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := int64($operand)
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::U64FromI64 => {
let tmp = self.tmp();
let value = format!("value{tmp}");
Expand All @@ -1317,7 +1346,22 @@ impl Bindgen for Func<'_> {
}
results.push(Operand::SingleValue(value.into()));
}
Instruction::CharFromI32 => todo!("implement instruction: {inst:?}"),
Instruction::CharFromI32 => {
// The canonical ABI rejects surrogates and values above
// U+10FFFF when lifting a char.
let tmp = self.tmp();
let result = &format!("result{tmp}");
let operand = &operands[0];
quote_in! { self.body =>
$['\r']
$result := rune($operand)
if !$UTF8_VALID_RUNE($result) {
$(comment(["TODO(#8): Return an error if the return type allows it"]))
panic($ERRORS_NEW("invalid char value encountered"))
}
};
results.push(Operand::SingleValue(result.into()));
}
Instruction::F32FromCoreF32 => {
let tmp = self.tmp();
let result = &format!("result{tmp}");
Expand Down
1 change: 1 addition & 0 deletions cmd/gravity/src/go/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ pub static WAZERO_API_ENCODE_F64: GoImport =
pub static WAZERO_API_DECODE_F64: GoImport =
GoImport("github.com/tetratelabs/wazero/api", "DecodeF64");
pub static REFLECT_VALUE_OF: GoImport = GoImport("reflect", "ValueOf");
pub static UTF8_VALID_RUNE: GoImport = GoImport("unicode/utf8", "ValidRune");
7 changes: 6 additions & 1 deletion cmd/gravity/src/go/type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pub enum GoType {
Float32,
/// 64-bit floating point
Float64,
/// Unicode code point (`rune`, an alias of `int32`)
Rune,
/// String type
String,
/// Error type (represents Result<None, String>)
Expand Down Expand Up @@ -90,7 +92,8 @@ impl GoType {
| GoType::Int32
| GoType::Int64
| GoType::Float32
| GoType::Float64 => false,
| GoType::Float64
| GoType::Rune => false,

// String and slices allocate memory and need cleanup
GoType::String | GoType::Slice(_) => true,
Expand Down Expand Up @@ -150,6 +153,7 @@ impl FormatInto<Go> for &GoType {
GoType::Int64 => tokens.append(static_literal("int64")),
GoType::Float32 => tokens.append(static_literal("float32")),
GoType::Float64 => tokens.append(static_literal("float64")),
GoType::Rune => tokens.append(static_literal("rune")),
GoType::String => tokens.append(static_literal("string")),
GoType::Error => tokens.append(static_literal("error")),
GoType::Interface => tokens.append(static_literal("interface{}")),
Expand Down Expand Up @@ -211,6 +215,7 @@ mod tests {
(GoType::Int64, "int64"),
(GoType::Float32, "float32"),
(GoType::Float64, "float64"),
(GoType::Rune, "rune"),
(GoType::String, "string"),
(GoType::Error, "error"),
(GoType::Interface, "interface{}"),
Expand Down
5 changes: 1 addition & 4 deletions cmd/gravity/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,7 @@ pub fn resolve_type(typ: &Type, resolve: &Resolve) -> GoType {
Type::S64 => GoType::Int64,
Type::F32 => GoType::Float32,
Type::F64 => GoType::Float64,
Type::Char => {
// Is this a Go "rune"?
todo!("TODO(#6): resolve char type")
}
Type::Char => GoType::Rune,
Type::String => GoType::String,
Type::ErrorContext => todo!("TODO(#4): implement error context conversion"),

Expand Down
Loading
Loading