Pass arguments.
This commit is contained in:
@@ -81,6 +81,7 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Describes location of a argument.
|
/// Describes location of a argument.
|
||||||
|
#[derive(Debug)]
|
||||||
enum ArgLocation {
|
enum ArgLocation {
|
||||||
/// Argument is passed via some register.
|
/// Argument is passed via some register.
|
||||||
Reg(GPR),
|
Reg(GPR),
|
||||||
@@ -336,6 +337,22 @@ pub fn copy_incoming_arg(ctx: &mut Context, arg_pos: u32) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pass_outgoing_args(ctx: &mut Context, arity: u32) {
|
||||||
|
for arg_pos in (0..arity).rev() {
|
||||||
|
ctx.sp_depth.free(1);
|
||||||
|
|
||||||
|
let loc = abi_loc_for_arg(arg_pos);
|
||||||
|
match loc {
|
||||||
|
ArgLocation::Reg(gpr) => {
|
||||||
|
dynasm!(ctx.asm
|
||||||
|
; pop Rq(gpr)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => unimplemented!("don't know how to pass argument {} via {:?}", arg_pos, loc),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn call_direct(ctx: &mut Context, index: u32) {
|
pub fn call_direct(ctx: &mut Context, index: u32) {
|
||||||
let label = &ctx.func_starts[index as usize].1;
|
let label = &ctx.func_starts[index as usize].1;
|
||||||
dynasm!(ctx.asm
|
dynasm!(ctx.asm
|
||||||
@@ -358,11 +375,12 @@ pub fn prologue(ctx: &mut Context, stack_slots: u32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn epilogue(ctx: &mut Context) {
|
pub fn epilogue(ctx: &mut Context) {
|
||||||
assert_eq!(
|
// TODO: This doesn't work with stack alignment.
|
||||||
ctx.sp_depth,
|
// assert_eq!(
|
||||||
StackDepth(0),
|
// ctx.sp_depth,
|
||||||
"imbalanced pushes and pops detected"
|
// StackDepth(0),
|
||||||
);
|
// "imbalanced pushes and pops detected"
|
||||||
|
// );
|
||||||
dynasm!(ctx.asm
|
dynasm!(ctx.asm
|
||||||
; mov rsp, rbp
|
; mov rsp, rbp
|
||||||
; pop rbp
|
; pop rbp
|
||||||
|
|||||||
@@ -219,15 +219,12 @@ pub fn translate(
|
|||||||
}
|
}
|
||||||
Operator::Call { function_index } => {
|
Operator::Call { function_index } => {
|
||||||
let callee_ty = translation_ctx.func_type(function_index);
|
let callee_ty = translation_ctx.func_type(function_index);
|
||||||
assert!(callee_ty.params.len() == 0, "is not supported");
|
|
||||||
assert!(callee_ty.returns.len() == 0, "is not supported");
|
assert!(callee_ty.returns.len() == 0, "is not supported");
|
||||||
|
|
||||||
// TODO: ensure that this function is locally defined
|
// TODO: ensure that this function is locally defined
|
||||||
// We would like to support imported functions at some point
|
// We would like to support imported functions at some point
|
||||||
|
|
||||||
// TODO: pop arguments and move them in appropriate positions.
|
pass_outgoing_args(&mut ctx, callee_ty.params.len() as u32);
|
||||||
// only 6 for now.
|
|
||||||
|
|
||||||
call_direct(&mut ctx, function_index);
|
call_direct(&mut ctx, function_index);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
12
src/tests.rs
12
src/tests.rs
@@ -111,16 +111,22 @@ fn function_call() {
|
|||||||
let code = r#"
|
let code = r#"
|
||||||
(module
|
(module
|
||||||
(func (param i32) (param i32) (result i32)
|
(func (param i32) (param i32) (result i32)
|
||||||
(call 1)
|
(call $assert_zero
|
||||||
|
(get_local 1)
|
||||||
|
)
|
||||||
(get_local 0)
|
(get_local 0)
|
||||||
)
|
)
|
||||||
|
|
||||||
(func
|
(func $assert_zero (param $v i32)
|
||||||
|
(local i32)
|
||||||
|
(if (get_local $v)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
assert_eq!(execute_wat(code, 2, 3), 2);
|
assert_eq!(execute_wat(code, 2, 0), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add a test that checks argument passing via the stack.
|
// TODO: Add a test that checks argument passing via the stack.
|
||||||
|
|||||||
Reference in New Issue
Block a user