Handle signature() for more libcalls (#6174)
* Handle signature() for more libcalls This is necessary to be able to call them in the interpreter. All the remaining libcalls which signature() doesn't handle are never used in clif ir. Only in code compiled by a backend. * Fix libcall declarations in cranelift-frontend * Add function signatures * Use correct pointer type instead of I64
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
//! Naming well-known routines in the runtime library.
|
//! Naming well-known routines in the runtime library.
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ir::{types, AbiParam, ExternalName, FuncRef, Function, Signature},
|
ir::{types, AbiParam, ExternalName, FuncRef, Function, Signature, Type},
|
||||||
isa::CallConv,
|
isa::CallConv,
|
||||||
};
|
};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
@@ -119,7 +119,7 @@ impl LibCall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a [Signature] for the function targeted by this [LibCall].
|
/// Get a [Signature] for the function targeted by this [LibCall].
|
||||||
pub fn signature(&self, call_conv: CallConv) -> Signature {
|
pub fn signature(&self, call_conv: CallConv, pointer_type: Type) -> Signature {
|
||||||
use types::*;
|
use types::*;
|
||||||
let mut sig = Signature::new(call_conv);
|
let mut sig = Signature::new(call_conv);
|
||||||
|
|
||||||
@@ -140,13 +140,32 @@ impl LibCall {
|
|||||||
sig.params.push(AbiParam::new(ty));
|
sig.params.push(AbiParam::new(ty));
|
||||||
sig.returns.push(AbiParam::new(ty));
|
sig.returns.push(AbiParam::new(ty));
|
||||||
}
|
}
|
||||||
LibCall::Probestack
|
LibCall::Memcpy | LibCall::Memmove => {
|
||||||
| LibCall::Memcpy
|
// void* memcpy(void *dest, const void *src, size_t count);
|
||||||
| LibCall::Memset
|
// void* memmove(void* dest, const void* src, size_t count);
|
||||||
| LibCall::Memmove
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
| LibCall::Memcmp
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
| LibCall::ElfTlsGetAddr
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
| LibCall::ElfTlsGetOffset => unimplemented!(),
|
sig.returns.push(AbiParam::new(pointer_type));
|
||||||
|
}
|
||||||
|
LibCall::Memset => {
|
||||||
|
// void *memset(void *dest, int ch, size_t count);
|
||||||
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
|
sig.params.push(AbiParam::new(I32));
|
||||||
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
|
sig.returns.push(AbiParam::new(pointer_type));
|
||||||
|
}
|
||||||
|
LibCall::Memcmp => {
|
||||||
|
// void* memcpy(void *dest, const void *src, size_t count);
|
||||||
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
|
sig.params.push(AbiParam::new(pointer_type));
|
||||||
|
sig.returns.push(AbiParam::new(I32))
|
||||||
|
}
|
||||||
|
|
||||||
|
LibCall::Probestack | LibCall::ElfTlsGetAddr | LibCall::ElfTlsGetOffset => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sig
|
sig
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ fn emit_vm_call(
|
|||||||
|
|
||||||
// TODO avoid recreating signatures for every single Libcall function.
|
// TODO avoid recreating signatures for every single Libcall function.
|
||||||
let call_conv = CallConv::for_libcall(flags, CallConv::triple_default(triple));
|
let call_conv = CallConv::for_libcall(flags, CallConv::triple_default(triple));
|
||||||
let sig = libcall.signature(call_conv);
|
let sig = libcall.signature(call_conv, types::I64);
|
||||||
let caller_conv = ctx.abi().call_conv(ctx.sigs());
|
let caller_conv = ctx.abi().call_conv(ctx.sigs());
|
||||||
|
|
||||||
if !ctx.sigs().have_abi_sig_for_signature(&sig) {
|
if !ctx.sigs().have_abi_sig_for_signature(&sig) {
|
||||||
|
|||||||
@@ -629,7 +629,7 @@ impl Context for IsleContext<'_, '_, MInst, X64Backend> {
|
|||||||
|
|
||||||
fn libcall_1(&mut self, libcall: &LibCall, a: Reg) -> Reg {
|
fn libcall_1(&mut self, libcall: &LibCall, a: Reg) -> Reg {
|
||||||
let call_conv = self.lower_ctx.abi().call_conv(self.lower_ctx.sigs());
|
let call_conv = self.lower_ctx.abi().call_conv(self.lower_ctx.sigs());
|
||||||
let ret_ty = libcall.signature(call_conv).returns[0].value_type;
|
let ret_ty = libcall.signature(call_conv, I64).returns[0].value_type;
|
||||||
let output_reg = self.lower_ctx.alloc_tmp(ret_ty).only_reg().unwrap();
|
let output_reg = self.lower_ctx.alloc_tmp(ret_ty).only_reg().unwrap();
|
||||||
|
|
||||||
emit_vm_call(
|
emit_vm_call(
|
||||||
@@ -647,7 +647,7 @@ impl Context for IsleContext<'_, '_, MInst, X64Backend> {
|
|||||||
|
|
||||||
fn libcall_3(&mut self, libcall: &LibCall, a: Reg, b: Reg, c: Reg) -> Reg {
|
fn libcall_3(&mut self, libcall: &LibCall, a: Reg, b: Reg, c: Reg) -> Reg {
|
||||||
let call_conv = self.lower_ctx.abi().call_conv(self.lower_ctx.sigs());
|
let call_conv = self.lower_ctx.abi().call_conv(self.lower_ctx.sigs());
|
||||||
let ret_ty = libcall.signature(call_conv).returns[0].value_type;
|
let ret_ty = libcall.signature(call_conv, I64).returns[0].value_type;
|
||||||
let output_reg = self.lower_ctx.alloc_tmp(ret_ty).only_reg().unwrap();
|
let output_reg = self.lower_ctx.alloc_tmp(ret_ty).only_reg().unwrap();
|
||||||
|
|
||||||
emit_vm_call(
|
emit_vm_call(
|
||||||
|
|||||||
@@ -753,6 +753,7 @@ impl<'a> FunctionBuilder<'a> {
|
|||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.returns.push(AbiParam::new(pointer_type));
|
||||||
self.import_signature(s)
|
self.import_signature(s)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -853,6 +854,7 @@ impl<'a> FunctionBuilder<'a> {
|
|||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
s.params.push(AbiParam::new(types::I32));
|
s.params.push(AbiParam::new(types::I32));
|
||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.returns.push(AbiParam::new(pointer_type));
|
||||||
self.import_signature(s)
|
self.import_signature(s)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -949,6 +951,7 @@ impl<'a> FunctionBuilder<'a> {
|
|||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
s.params.push(AbiParam::new(pointer_type));
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.returns.push(AbiParam::new(pointer_type));
|
||||||
self.import_signature(s)
|
self.import_signature(s)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1283,15 +1286,15 @@ mod tests {
|
|||||||
check(
|
check(
|
||||||
&func,
|
&func,
|
||||||
"function %sample() -> i32 system_v {
|
"function %sample() -> i32 system_v {
|
||||||
sig0 = (i64, i64, i64) system_v
|
sig0 = (i64, i64, i64) -> i64 system_v
|
||||||
fn0 = %Memcpy sig0
|
fn0 = %Memcpy sig0
|
||||||
|
|
||||||
block0:
|
block0:
|
||||||
|
v4 = iconst.i64 0
|
||||||
|
v1 -> v4
|
||||||
v3 = iconst.i64 0
|
v3 = iconst.i64 0
|
||||||
v1 -> v3
|
v0 -> v3
|
||||||
v2 = iconst.i64 0
|
v2 = call fn0(v1, v0, v1) ; v1 = 0, v0 = 0, v1 = 0
|
||||||
v0 -> v2
|
|
||||||
call fn0(v1, v0, v1) ; v1 = 0, v0 = 0, v1 = 0
|
|
||||||
return v1 ; v1 = 0
|
return v1 ; v1 = 0
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
@@ -1393,16 +1396,16 @@ block0:
|
|||||||
check(
|
check(
|
||||||
&func,
|
&func,
|
||||||
"function %sample() -> i32 system_v {
|
"function %sample() -> i32 system_v {
|
||||||
sig0 = (i64, i64, i64) system_v
|
sig0 = (i64, i64, i64) -> i64 system_v
|
||||||
fn0 = %Memcpy sig0
|
fn0 = %Memcpy sig0
|
||||||
|
|
||||||
block0:
|
block0:
|
||||||
|
v5 = iconst.i64 0
|
||||||
|
v1 -> v5
|
||||||
v4 = iconst.i64 0
|
v4 = iconst.i64 0
|
||||||
v1 -> v4
|
v0 -> v4
|
||||||
v3 = iconst.i64 0
|
|
||||||
v0 -> v3
|
|
||||||
v2 = iconst.i64 8192
|
v2 = iconst.i64 8192
|
||||||
call fn0(v1, v0, v2) ; v1 = 0, v0 = 0, v2 = 8192
|
v3 = call fn0(v1, v0, v2) ; v1 = 0, v0 = 0, v2 = 8192
|
||||||
return v1 ; v1 = 0
|
return v1 ; v1 = 0
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
@@ -1478,16 +1481,16 @@ block0:
|
|||||||
check(
|
check(
|
||||||
&func,
|
&func,
|
||||||
"function %sample() -> i32 system_v {
|
"function %sample() -> i32 system_v {
|
||||||
sig0 = (i64, i32, i64) system_v
|
sig0 = (i64, i32, i64) -> i64 system_v
|
||||||
fn0 = %Memset sig0
|
fn0 = %Memset sig0
|
||||||
|
|
||||||
block0:
|
block0:
|
||||||
v4 = iconst.i64 0
|
v5 = iconst.i64 0
|
||||||
v0 -> v4
|
v0 -> v5
|
||||||
v1 = iconst.i8 1
|
v1 = iconst.i8 1
|
||||||
v2 = iconst.i64 8192
|
v2 = iconst.i64 8192
|
||||||
v3 = uextend.i32 v1 ; v1 = 1
|
v3 = uextend.i32 v1 ; v1 = 1
|
||||||
call fn0(v0, v3, v2) ; v0 = 0, v2 = 8192
|
v4 = call fn0(v0, v3, v2) ; v0 = 0, v2 = 8192
|
||||||
return v0 ; v0 = 0
|
return v0 ; v0 = 0
|
||||||
}
|
}
|
||||||
",
|
",
|
||||||
|
|||||||
@@ -1863,7 +1863,11 @@ where
|
|||||||
.libcalls
|
.libcalls
|
||||||
.iter()
|
.iter()
|
||||||
.map(|libcall| {
|
.map(|libcall| {
|
||||||
let signature = libcall.signature(lib_callconv);
|
let pointer_type = Type::int_with_byte_size(
|
||||||
|
self.target_triple.pointer_width().unwrap().bytes().into(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let signature = libcall.signature(lib_callconv, pointer_type);
|
||||||
let name = ExternalName::LibCall(*libcall);
|
let name = ExternalName::LibCall(*libcall);
|
||||||
(name, signature)
|
(name, signature)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use crate::frame::Frame;
|
|||||||
use crate::interpreter::LibCallHandler;
|
use crate::interpreter::LibCallHandler;
|
||||||
use cranelift_codegen::data_value::DataValue;
|
use cranelift_codegen::data_value::DataValue;
|
||||||
use cranelift_codegen::ir::{
|
use cranelift_codegen::ir::{
|
||||||
ExternalName, FuncRef, Function, GlobalValue, LibCall, MemFlags, Signature, StackSlot, Type,
|
types, ExternalName, FuncRef, Function, GlobalValue, LibCall, MemFlags, Signature, StackSlot,
|
||||||
Value,
|
Type, Value,
|
||||||
};
|
};
|
||||||
use cranelift_codegen::isa::CallConv;
|
use cranelift_codegen::isa::CallConv;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
@@ -96,7 +96,8 @@ impl<'a> InterpreterFunctionRef<'a> {
|
|||||||
match self {
|
match self {
|
||||||
InterpreterFunctionRef::Function(f) => f.stencil.signature.clone(),
|
InterpreterFunctionRef::Function(f) => f.stencil.signature.clone(),
|
||||||
// CallConv here is sort of irrelevant, since we don't use it for anything
|
// CallConv here is sort of irrelevant, since we don't use it for anything
|
||||||
InterpreterFunctionRef::LibCall(lc) => lc.signature(CallConv::SystemV),
|
// FIXME handle non-64bit systems
|
||||||
|
InterpreterFunctionRef::LibCall(lc) => lc.signature(CallConv::SystemV, types::I64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user