mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44:33 +00:00
implement signed integer extension operations
This commit is contained in:
parent
26ef2bd46b
commit
0e71e0d1b1
3 changed files with 90 additions and 9 deletions
|
@ -1728,6 +1728,26 @@ impl<'a, I: ImportDispatcher> Instance<'a, I> {
|
||||||
self.value_store
|
self.value_store
|
||||||
.push(Value::F64(f64::from_ne_bytes(x.to_ne_bytes())));
|
.push(Value::F64(f64::from_ne_bytes(x.to_ne_bytes())));
|
||||||
}
|
}
|
||||||
|
I32EXTEND8S => {
|
||||||
|
let x = self.value_store.pop_i32()?;
|
||||||
|
self.value_store.push(Value::I32(x as i8 as i32));
|
||||||
|
}
|
||||||
|
I32EXTEND16S => {
|
||||||
|
let x = self.value_store.pop_i32()?;
|
||||||
|
self.value_store.push(Value::I32(x as i16 as i32));
|
||||||
|
}
|
||||||
|
I64EXTEND8S => {
|
||||||
|
let x = self.value_store.pop_i64()?;
|
||||||
|
self.value_store.push(Value::I64(x as i8 as i64));
|
||||||
|
}
|
||||||
|
I64EXTEND16S => {
|
||||||
|
let x = self.value_store.pop_i64()?;
|
||||||
|
self.value_store.push(Value::I64(x as i16 as i64));
|
||||||
|
}
|
||||||
|
I64EXTEND32S => {
|
||||||
|
let x = self.value_store.pop_i64()?;
|
||||||
|
self.value_store.push(Value::I64(x as i32 as i64));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(debug_string) = &self.debug_string {
|
if let Some(debug_string) = &self.debug_string {
|
||||||
|
|
|
@ -247,3 +247,48 @@ fn test_f64reinterpreti64() {
|
||||||
Value::F64(0.01171875),
|
Value::F64(0.01171875),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_i32extend8s() {
|
||||||
|
test_op_example(
|
||||||
|
I32EXTEND8S,
|
||||||
|
[Value::from(0xFFu32 as i32)],
|
||||||
|
Value::I32(0xFFFFFFFFu32 as i32),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_i32extend16s() {
|
||||||
|
test_op_example(
|
||||||
|
I32EXTEND16S,
|
||||||
|
[Value::from(0xFFFFu32)],
|
||||||
|
Value::I32(0xFFFFFFFFu32 as i32),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_i64extend8s() {
|
||||||
|
test_op_example(
|
||||||
|
I64EXTEND8S,
|
||||||
|
[Value::from(0xFFu64 as i64)],
|
||||||
|
Value::I64(u64::MAX as i64),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_i64extend16s() {
|
||||||
|
test_op_example(
|
||||||
|
I64EXTEND16S,
|
||||||
|
[Value::from(0xFFFFu64 as i64)],
|
||||||
|
Value::I64(u64::MAX as i64),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_i64extend32s() {
|
||||||
|
test_op_example(
|
||||||
|
I64EXTEND32S,
|
||||||
|
[Value::from(0xFFFFFFFFu64 as i64)],
|
||||||
|
Value::I64(u64::MAX as i64),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -185,6 +185,12 @@ pub enum OpCode {
|
||||||
I64REINTERPRETF64 = 0xbd,
|
I64REINTERPRETF64 = 0xbd,
|
||||||
F32REINTERPRETI32 = 0xbe,
|
F32REINTERPRETI32 = 0xbe,
|
||||||
F64REINTERPRETI64 = 0xbf,
|
F64REINTERPRETI64 = 0xbf,
|
||||||
|
|
||||||
|
I32EXTEND8S = 0xc0,
|
||||||
|
I32EXTEND16S = 0xc1,
|
||||||
|
I64EXTEND8S = 0xc2,
|
||||||
|
I64EXTEND16S = 0xc3,
|
||||||
|
I64EXTEND32S = 0xc4,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const LOOKUP_TABLE: [Option<OpCode>; 256] = {
|
pub const LOOKUP_TABLE: [Option<OpCode>; 256] = {
|
||||||
|
@ -366,11 +372,21 @@ pub const LOOKUP_TABLE: [Option<OpCode>; 256] = {
|
||||||
result[0xbe] = Some(F32REINTERPRETI32);
|
result[0xbe] = Some(F32REINTERPRETI32);
|
||||||
result[0xbf] = Some(F64REINTERPRETI64);
|
result[0xbf] = Some(F64REINTERPRETI64);
|
||||||
|
|
||||||
|
result[0xc0] = Some(I32EXTEND8S);
|
||||||
|
result[0xc1] = Some(I32EXTEND16S);
|
||||||
|
result[0xc2] = Some(I64EXTEND8S);
|
||||||
|
result[0xc3] = Some(I64EXTEND16S);
|
||||||
|
result[0xc4] = Some(I64EXTEND32S);
|
||||||
|
|
||||||
result
|
result
|
||||||
};
|
};
|
||||||
|
|
||||||
impl From<u8> for OpCode {
|
impl From<u8> for OpCode {
|
||||||
fn from(value: u8) -> Self {
|
fn from(value: u8) -> Self {
|
||||||
|
if false {
|
||||||
|
// considerably faster in practice
|
||||||
|
unsafe { std::mem::transmute(value) }
|
||||||
|
} else {
|
||||||
// invalid instruction bytes can be genuine because we don't support all instructions, and
|
// invalid instruction bytes can be genuine because we don't support all instructions, and
|
||||||
// new ones get added or stabilized. It could also be a bug in the interpreter, e.g. some
|
// new ones get added or stabilized. It could also be a bug in the interpreter, e.g. some
|
||||||
// opcode does not move the instruction pointer correctly.
|
// opcode does not move the instruction pointer correctly.
|
||||||
|
@ -379,6 +395,7 @@ impl From<u8> for OpCode {
|
||||||
Some(op) => op,
|
Some(op) => op,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
|
@ -468,9 +485,8 @@ fn immediates_for(op: OpCode) -> Result<OpImmediates, String> {
|
||||||
| I64EXTENDUI32 | I64TRUNCSF32 | I64TRUNCUF32 | I64TRUNCSF64 | I64TRUNCUF64
|
| I64EXTENDUI32 | I64TRUNCSF32 | I64TRUNCUF32 | I64TRUNCSF64 | I64TRUNCUF64
|
||||||
| F32CONVERTSI32 | F32CONVERTUI32 | F32CONVERTSI64 | F32CONVERTUI64 | F32DEMOTEF64
|
| F32CONVERTSI32 | F32CONVERTUI32 | F32CONVERTSI64 | F32CONVERTUI64 | F32DEMOTEF64
|
||||||
| F64CONVERTSI32 | F64CONVERTUI32 | F64CONVERTSI64 | F64CONVERTUI64 | F64PROMOTEF32
|
| F64CONVERTSI32 | F64CONVERTUI32 | F64CONVERTSI64 | F64CONVERTUI64 | F64PROMOTEF32
|
||||||
| I32REINTERPRETF32 | I64REINTERPRETF64 | F32REINTERPRETI32 | F64REINTERPRETI64 => {
|
| I32REINTERPRETF32 | I64REINTERPRETF64 | F32REINTERPRETI32 | F64REINTERPRETI64
|
||||||
NoImmediate
|
| I32EXTEND8S | I32EXTEND16S | I64EXTEND8S | I64EXTEND16S | I64EXTEND32S => NoImmediate,
|
||||||
}
|
|
||||||
|
|
||||||
// Catch-all in case of an invalid cast from u8 to OpCode while parsing binary
|
// Catch-all in case of an invalid cast from u8 to OpCode while parsing binary
|
||||||
// (rustc keeps this code, I verified in Compiler Explorer)
|
// (rustc keeps this code, I verified in Compiler Explorer)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue