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:
bjorn3
2023-04-11 18:50:41 +02:00
committed by GitHub
parent 52440f0fc8
commit 0478ead3f8
6 changed files with 57 additions and 30 deletions

View File

@@ -1,7 +1,7 @@
//! Naming well-known routines in the runtime library.
use crate::{
ir::{types, AbiParam, ExternalName, FuncRef, Function, Signature},
ir::{types, AbiParam, ExternalName, FuncRef, Function, Signature, Type},
isa::CallConv,
};
use core::fmt;
@@ -119,7 +119,7 @@ impl 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::*;
let mut sig = Signature::new(call_conv);
@@ -140,13 +140,32 @@ impl LibCall {
sig.params.push(AbiParam::new(ty));
sig.returns.push(AbiParam::new(ty));
}
LibCall::Probestack
| LibCall::Memcpy
| LibCall::Memset
| LibCall::Memmove
| LibCall::Memcmp
| LibCall::ElfTlsGetAddr
| LibCall::ElfTlsGetOffset => unimplemented!(),
LibCall::Memcpy | LibCall::Memmove => {
// void* memcpy(void *dest, const void *src, size_t count);
// void* memmove(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(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

View File

@@ -150,7 +150,7 @@ fn emit_vm_call(
// TODO avoid recreating signatures for every single Libcall function.
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());
if !ctx.sigs().have_abi_sig_for_signature(&sig) {

View File

@@ -629,7 +629,7 @@ impl Context for IsleContext<'_, '_, MInst, X64Backend> {
fn libcall_1(&mut self, libcall: &LibCall, a: Reg) -> Reg {
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();
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 {
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();
emit_vm_call(

View File

@@ -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.returns.push(AbiParam::new(pointer_type));
self.import_signature(s)
};
@@ -853,6 +854,7 @@ impl<'a> FunctionBuilder<'a> {
s.params.push(AbiParam::new(pointer_type));
s.params.push(AbiParam::new(types::I32));
s.params.push(AbiParam::new(pointer_type));
s.returns.push(AbiParam::new(pointer_type));
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.returns.push(AbiParam::new(pointer_type));
self.import_signature(s)
};
@@ -1283,15 +1286,15 @@ mod tests {
check(
&func,
"function %sample() -> i32 system_v {
sig0 = (i64, i64, i64) system_v
sig0 = (i64, i64, i64) -> i64 system_v
fn0 = %Memcpy sig0
block0:
v4 = iconst.i64 0
v1 -> v4
v3 = iconst.i64 0
v1 -> v3
v2 = iconst.i64 0
v0 -> v2
call fn0(v1, v0, v1) ; v1 = 0, v0 = 0, v1 = 0
v0 -> v3
v2 = call fn0(v1, v0, v1) ; v1 = 0, v0 = 0, v1 = 0
return v1 ; v1 = 0
}
",
@@ -1393,16 +1396,16 @@ block0:
check(
&func,
"function %sample() -> i32 system_v {
sig0 = (i64, i64, i64) system_v
sig0 = (i64, i64, i64) -> i64 system_v
fn0 = %Memcpy sig0
block0:
v5 = iconst.i64 0
v1 -> v5
v4 = iconst.i64 0
v1 -> v4
v3 = iconst.i64 0
v0 -> v3
v0 -> v4
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
}
",
@@ -1478,16 +1481,16 @@ block0:
check(
&func,
"function %sample() -> i32 system_v {
sig0 = (i64, i32, i64) system_v
sig0 = (i64, i32, i64) -> i64 system_v
fn0 = %Memset sig0
block0:
v4 = iconst.i64 0
v0 -> v4
v5 = iconst.i64 0
v0 -> v5
v1 = iconst.i8 1
v2 = iconst.i64 8192
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
}
",

View File

@@ -1863,7 +1863,11 @@ where
.libcalls
.iter()
.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);
(name, signature)
})

View File

@@ -5,8 +5,8 @@ use crate::frame::Frame;
use crate::interpreter::LibCallHandler;
use cranelift_codegen::data_value::DataValue;
use cranelift_codegen::ir::{
ExternalName, FuncRef, Function, GlobalValue, LibCall, MemFlags, Signature, StackSlot, Type,
Value,
types, ExternalName, FuncRef, Function, GlobalValue, LibCall, MemFlags, Signature, StackSlot,
Type, Value,
};
use cranelift_codegen::isa::CallConv;
use smallvec::SmallVec;
@@ -96,7 +96,8 @@ impl<'a> InterpreterFunctionRef<'a> {
match self {
InterpreterFunctionRef::Function(f) => f.stencil.signature.clone(),
// 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),
}
}
}