Skip to content

Commit e189ccd

Browse files
committed
Add support for libcalls in codegen
These are special function calls that backends can emit for operations not natively supported by their target processor (e.g., 64-bit divisions on 32-bit targets or bit-manipulation operations on older x86 CPUs). They end up being surfaced as their own relocation targets in the final code blob. Note that while libcalls are now supported throughout both the rust and C APIs, nothing actually produces or consumes them at the moment.
1 parent c2479ed commit e189ccd

5 files changed

Lines changed: 38 additions & 3 deletions

File tree

c-api/include/spidir/codegen.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ enum spidir_reloc_target_kind {
4747
/// The relocation refers to an internal function, accessible via the
4848
/// `target.external` relocation field.
4949
SPIDIR_RELOC_TARGET_EXTERNAL_FUNCTION,
50+
/// The relocation refers to a target-specific library call used to
51+
/// implement a certain operation. See individual backend definitions for
52+
/// possible values.
53+
SPIDIR_RELOC_TARGET_LIBCALL,
5054
/// The relocation refers to the function's constant pool.
5155
SPIDIR_RELOC_TARGET_CONSTPOOL,
5256
};
@@ -56,17 +60,23 @@ enum spidir_reloc_target_kind {
5660
/// See the `SPIDIR_RELOC_TARGET_` constants for possible values.
5761
typedef uint8_t spidir_reloc_target_kind_t;
5862

63+
/// Represents the different kinds of library calls a target may emit in the
64+
/// generated code. See individual backend definitions for possible values.
65+
typedef uint32_t spidir_libcall_kind_t;
66+
5967
/// Represents a relocation in generated code. Relocations can refer either to
6068
/// other functions or to the function's constant pool.
6169
typedef struct spidir_codegen_reloc {
6270
/// The addend for this relocation.
6371
/// The exact meaning of this field depends on the target architecture and
6472
/// the value of the `kind` field.
6573
int64_t addend;
66-
/// The target function of this relocation, if it refers to a function.
74+
/// The target function of this relocation, if it refers to a function or
75+
/// libcall.
6776
union {
6877
spidir_function_t internal;
6978
spidir_extern_function_t external;
79+
spidir_libcall_kind_t libcall;
7080
} target;
7181
/// The offset in the generated code to which the relocation applies.
7282
uint32_t offset;

crates/bindings/src/types.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,14 @@ pub struct ApiValue(pub u32);
3535
#[repr(C)]
3636
pub struct ApiPhi(pub u32);
3737

38+
pub type ApiLibcallKind = u32;
39+
3840
#[derive(Clone, Copy)]
3941
#[repr(C)]
4042
pub union ApiRelocTarget {
4143
internal: ApiFunction,
4244
external: ApiExternFunction,
45+
libcall: ApiLibcallKind,
4346
}
4447

4548
#[derive(Clone, Copy)]
@@ -109,7 +112,8 @@ const SPIDIR_MEM_SIZE_8: u8 = 3;
109112

110113
const SPIDIR_RELOC_TARGET_INTERNAL_FUNCTION: u8 = 0;
111114
const SPIDIR_RELOC_TARGET_EXTERNAL_FUNCTION: u8 = 1;
112-
const SPIDIR_RELOC_TARGET_CONSTPOOL: u8 = 2;
115+
const SPIDIR_RELOC_TARGET_LIBCALL: u8 = 3;
116+
const SPIDIR_RELOC_TARGET_CONSTPOOL: u8 = 3;
113117

114118
pub unsafe fn value_list_from_api(
115119
arg_count: usize,
@@ -289,6 +293,10 @@ pub fn reloc_to_api(reloc: &Reloc) -> ApiReloc {
289293
external: extern_function_to_api(func),
290294
},
291295
),
296+
RelocTarget::LibCall(kind) => (
297+
SPIDIR_RELOC_TARGET_LIBCALL,
298+
ApiRelocTarget { libcall: kind.0 },
299+
),
292300
RelocTarget::ConstantPool => (
293301
SPIDIR_RELOC_TARGET_CONSTPOOL,
294302
ApiRelocTarget {

crates/codegen-test-tools/src/disasm.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use capstone::{
99
},
1010
};
1111
use codegen::{
12-
code_buffer::{CodeBlob, RelocKind, RelocTarget},
12+
code_buffer::{CodeBlob, LibCallKind, RelocKind, RelocTarget},
1313
target::x64::{RELOC_ABS64, RELOC_PC32},
1414
};
1515
use ir::{module::ModuleMetadata, write::quote_ident};
@@ -53,6 +53,7 @@ pub fn disasm_code(
5353
RelocTarget::Function(func) => {
5454
quote_ident(&module_metadata.resolve_funcref(func).name)
5555
}
56+
RelocTarget::LibCall(kind) => libcall_name(kind).into(),
5657
RelocTarget::ConstantPool => "<CP>".into(),
5758
};
5859

@@ -108,4 +109,8 @@ fn reloc_name(reloc: RelocKind) -> String {
108109
}
109110
}
110111

112+
fn libcall_name(libcall: LibCallKind) -> String {
113+
format!("libcall:{}", libcall.0)
114+
}
115+
111116
const CP_CHUNK_SIZE: usize = 8;

crates/codegen-test-tools/src/exec.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ fn relocate_buf(
193193
)
194194
})? as u64
195195
}
196+
RelocTarget::LibCall(_) => bail!("unknown libcall kind"),
196197
RelocTarget::ConstantPool => {
197198
buf.as_ptr() as u64
198199
+ constpool_off as u64

crates/codegen/src/code_buffer.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ use crate::constpool::{Constant, ConstantPoolBuilder};
1414
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1515
pub struct RelocKind(pub u8);
1616

17+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18+
pub struct LibCallKind(pub u32);
19+
1720
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1821
pub struct RawReloc<T> {
1922
pub kind: RelocKind,
@@ -25,6 +28,7 @@ pub struct RawReloc<T> {
2528
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2629
pub enum BufferRelocTarget {
2730
Function(FunctionRef),
31+
LibCall(LibCallKind),
2832
Constant(Constant),
2933
}
3034

@@ -33,6 +37,7 @@ type BufferReloc = RawReloc<BufferRelocTarget>;
3337
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
3438
pub enum RelocTarget {
3539
Function(FunctionRef),
40+
LibCall(LibCallKind),
3641
ConstantPool,
3742
}
3843

@@ -273,6 +278,12 @@ impl<F: FixupKind> CodeBuffer<F> {
273278
target: RelocTarget::Function(func),
274279
addend: reloc.addend,
275280
},
281+
BufferRelocTarget::LibCall(kind) => Reloc {
282+
kind: reloc.kind,
283+
offset: reloc.offset,
284+
target: RelocTarget::LibCall(kind),
285+
addend: reloc.addend,
286+
},
276287
BufferRelocTarget::Constant(constant) => {
277288
let offset = constpool.offsets[constant];
278289
Reloc {

0 commit comments

Comments
 (0)