cranelift: Implement br_table on the interpreter
This commit is contained in:
committed by
Andrew Brown
parent
ebbe399725
commit
065190f975
148
cranelift/filetests/filetests/runtests/br_table.clif
Normal file
148
cranelift/filetests/filetests/runtests/br_table.clif
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
test interpret
|
||||||
|
test run
|
||||||
|
target aarch64
|
||||||
|
target s390x
|
||||||
|
|
||||||
|
|
||||||
|
function %br_table_i8(i8) -> i8 {
|
||||||
|
jt0 = jump_table [block1, block2, block2, block3]
|
||||||
|
|
||||||
|
block0(v0: i8):
|
||||||
|
br_table v0, block4, jt0
|
||||||
|
|
||||||
|
block1:
|
||||||
|
v1 = iconst.i8 1
|
||||||
|
jump block5(v1)
|
||||||
|
|
||||||
|
block2:
|
||||||
|
v2 = iconst.i8 2
|
||||||
|
jump block5(v2)
|
||||||
|
|
||||||
|
block3:
|
||||||
|
v3 = iconst.i8 3
|
||||||
|
jump block5(v3)
|
||||||
|
|
||||||
|
block4:
|
||||||
|
v4 = iconst.i8 4
|
||||||
|
jump block5(v4)
|
||||||
|
|
||||||
|
block5(v5: i8):
|
||||||
|
v6 = iadd.i8 v0, v5
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %br_table_i8(0) == 1
|
||||||
|
; run: %br_table_i8(1) == 3
|
||||||
|
; run: %br_table_i8(2) == 4
|
||||||
|
; run: %br_table_i8(3) == 6
|
||||||
|
; run: %br_table_i8(4) == 8
|
||||||
|
; run: %br_table_i8(5) == 9
|
||||||
|
; run: %br_table_i8(6) == 10
|
||||||
|
; run: %br_table_i8(-1) == 3
|
||||||
|
|
||||||
|
|
||||||
|
function %br_table_i16(i16) -> i16 {
|
||||||
|
jt0 = jump_table [block1, block2, block2, block3]
|
||||||
|
|
||||||
|
block0(v0: i16):
|
||||||
|
br_table v0, block4, jt0
|
||||||
|
|
||||||
|
block1:
|
||||||
|
v1 = iconst.i16 1
|
||||||
|
jump block5(v1)
|
||||||
|
|
||||||
|
block2:
|
||||||
|
v2 = iconst.i16 2
|
||||||
|
jump block5(v2)
|
||||||
|
|
||||||
|
block3:
|
||||||
|
v3 = iconst.i16 3
|
||||||
|
jump block5(v3)
|
||||||
|
|
||||||
|
block4:
|
||||||
|
v4 = iconst.i16 4
|
||||||
|
jump block5(v4)
|
||||||
|
|
||||||
|
block5(v5: i16):
|
||||||
|
v6 = iadd.i16 v0, v5
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %br_table_i16(0) == 1
|
||||||
|
; run: %br_table_i16(1) == 3
|
||||||
|
; run: %br_table_i16(2) == 4
|
||||||
|
; run: %br_table_i16(3) == 6
|
||||||
|
; run: %br_table_i16(4) == 8
|
||||||
|
; run: %br_table_i16(5) == 9
|
||||||
|
; run: %br_table_i16(6) == 10
|
||||||
|
; run: %br_table_i16(-1) == 3
|
||||||
|
|
||||||
|
|
||||||
|
function %br_table_i32(i32) -> i32 {
|
||||||
|
jt0 = jump_table [block1, block2, block2, block3]
|
||||||
|
|
||||||
|
block0(v0: i32):
|
||||||
|
br_table v0, block4, jt0
|
||||||
|
|
||||||
|
block1:
|
||||||
|
v1 = iconst.i32 1
|
||||||
|
jump block5(v1)
|
||||||
|
|
||||||
|
block2:
|
||||||
|
v2 = iconst.i32 2
|
||||||
|
jump block5(v2)
|
||||||
|
|
||||||
|
block3:
|
||||||
|
v3 = iconst.i32 3
|
||||||
|
jump block5(v3)
|
||||||
|
|
||||||
|
block4:
|
||||||
|
v4 = iconst.i32 4
|
||||||
|
jump block5(v4)
|
||||||
|
|
||||||
|
block5(v5: i32):
|
||||||
|
v6 = iadd.i32 v0, v5
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %br_table_i32(0) == 1
|
||||||
|
; run: %br_table_i32(1) == 3
|
||||||
|
; run: %br_table_i32(2) == 4
|
||||||
|
; run: %br_table_i32(3) == 6
|
||||||
|
; run: %br_table_i32(4) == 8
|
||||||
|
; run: %br_table_i32(5) == 9
|
||||||
|
; run: %br_table_i32(6) == 10
|
||||||
|
; run: %br_table_i32(-1) == 3
|
||||||
|
|
||||||
|
|
||||||
|
function %br_table_i64(i64) -> i64 {
|
||||||
|
jt0 = jump_table [block1, block2, block2, block3]
|
||||||
|
|
||||||
|
block0(v0: i64):
|
||||||
|
br_table v0, block4, jt0
|
||||||
|
|
||||||
|
block1:
|
||||||
|
v1 = iconst.i64 1
|
||||||
|
jump block5(v1)
|
||||||
|
|
||||||
|
block2:
|
||||||
|
v2 = iconst.i64 2
|
||||||
|
jump block5(v2)
|
||||||
|
|
||||||
|
block3:
|
||||||
|
v3 = iconst.i64 3
|
||||||
|
jump block5(v3)
|
||||||
|
|
||||||
|
block4:
|
||||||
|
v4 = iconst.i64 4
|
||||||
|
jump block5(v4)
|
||||||
|
|
||||||
|
block5(v5: i64):
|
||||||
|
v6 = iadd.i64 v0, v5
|
||||||
|
return v6
|
||||||
|
}
|
||||||
|
; run: %br_table_i64(0) == 1
|
||||||
|
; run: %br_table_i64(1) == 3
|
||||||
|
; run: %br_table_i64(2) == 4
|
||||||
|
; run: %br_table_i64(3) == 6
|
||||||
|
; run: %br_table_i64(4) == 8
|
||||||
|
; run: %br_table_i64(5) == 9
|
||||||
|
; run: %br_table_i64(6) == 10
|
||||||
|
; run: %br_table_i64(-1) == 3
|
||||||
@@ -217,6 +217,10 @@ impl<'a> State<'a, DataValue> for InterpreterState<'a> {
|
|||||||
self.functions
|
self.functions
|
||||||
.get_from_func_ref(func_ref, self.frame_stack.last().unwrap().function)
|
.get_from_func_ref(func_ref, self.frame_stack.last().unwrap().function)
|
||||||
}
|
}
|
||||||
|
fn get_current_function(&self) -> &'a Function {
|
||||||
|
self.current_frame().function
|
||||||
|
}
|
||||||
|
|
||||||
fn push_frame(&mut self, function: &'a Function) {
|
fn push_frame(&mut self, function: &'a Function) {
|
||||||
self.frame_stack.push(Frame::new(function));
|
self.frame_stack.push(Frame::new(function));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ use thiserror::Error;
|
|||||||
pub trait State<'a, V> {
|
pub trait State<'a, V> {
|
||||||
/// Retrieve a reference to a [Function].
|
/// Retrieve a reference to a [Function].
|
||||||
fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function>;
|
fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function>;
|
||||||
|
/// Retrieve a reference to the currently executing [Function].
|
||||||
|
fn get_current_function(&self) -> &'a Function;
|
||||||
/// Record that an interpreter has called into a new [Function].
|
/// Record that an interpreter has called into a new [Function].
|
||||||
fn push_frame(&mut self, function: &'a Function);
|
fn push_frame(&mut self, function: &'a Function);
|
||||||
/// Record that an interpreter has returned from a called [Function].
|
/// Record that an interpreter has returned from a called [Function].
|
||||||
@@ -92,6 +94,10 @@ where
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_current_function(&self) -> &'a Function {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn push_frame(&mut self, _function: &'a Function) {
|
fn push_frame(&mut self, _function: &'a Function) {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use cranelift_codegen::ir::{
|
|||||||
};
|
};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::ops::RangeFrom;
|
use std::ops::RangeFrom;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@@ -155,10 +156,25 @@ where
|
|||||||
Opcode::BrIcmp => branch_when(icmp(inst.cond_code().unwrap(), &arg(0)?, &arg(1)?)?)?,
|
Opcode::BrIcmp => branch_when(icmp(inst.cond_code().unwrap(), &arg(0)?, &arg(1)?)?)?,
|
||||||
Opcode::Brif => branch_when(state.has_iflag(inst.cond_code().unwrap()))?,
|
Opcode::Brif => branch_when(state.has_iflag(inst.cond_code().unwrap()))?,
|
||||||
Opcode::Brff => branch_when(state.has_fflag(inst.fp_cond_code().unwrap()))?,
|
Opcode::Brff => branch_when(state.has_fflag(inst.fp_cond_code().unwrap()))?,
|
||||||
Opcode::BrTable => unimplemented!("BrTable"),
|
Opcode::BrTable => {
|
||||||
Opcode::JumpTableEntry => unimplemented!("JumpTableEntry"),
|
if let InstructionData::BranchTable {
|
||||||
Opcode::JumpTableBase => unimplemented!("JumpTableBase"),
|
table, destination, ..
|
||||||
Opcode::IndirectJumpTableBr => unimplemented!("IndirectJumpTableBr"),
|
} = inst
|
||||||
|
{
|
||||||
|
let jt_data = &state.get_current_function().jump_tables[table];
|
||||||
|
|
||||||
|
// Convert to usize to remove negative indexes from the following operations
|
||||||
|
let jump_target = usize::try_from(arg(0)?.into_int()?)
|
||||||
|
.ok()
|
||||||
|
.and_then(|i| jt_data.as_slice().get(i))
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(destination);
|
||||||
|
|
||||||
|
ControlFlow::ContinueAt(jump_target, SmallVec::new())
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
Opcode::Trap => ControlFlow::Trap(CraneliftTrap::User(trap_code())),
|
Opcode::Trap => ControlFlow::Trap(CraneliftTrap::User(trap_code())),
|
||||||
Opcode::Debugtrap => ControlFlow::Trap(CraneliftTrap::Debug),
|
Opcode::Debugtrap => ControlFlow::Trap(CraneliftTrap::Debug),
|
||||||
Opcode::ResumableTrap => ControlFlow::Trap(CraneliftTrap::Resumable),
|
Opcode::ResumableTrap => ControlFlow::Trap(CraneliftTrap::Resumable),
|
||||||
@@ -632,6 +648,9 @@ where
|
|||||||
| Opcode::X86Palignr
|
| Opcode::X86Palignr
|
||||||
| Opcode::X86ElfTlsGetAddr
|
| Opcode::X86ElfTlsGetAddr
|
||||||
| Opcode::X86MachoTlsGetAddr => unimplemented!("x86 instruction: {}", inst.opcode()),
|
| Opcode::X86MachoTlsGetAddr => unimplemented!("x86 instruction: {}", inst.opcode()),
|
||||||
|
Opcode::JumpTableBase | Opcode::JumpTableEntry | Opcode::IndirectJumpTableBr => {
|
||||||
|
unimplemented!("Legacy instruction: {}", inst.opcode())
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user