forked from nulang-org/nulang
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcranelift_utils.rs
More file actions
101 lines (90 loc) · 4.11 KB
/
Copy pathcranelift_utils.rs
File metadata and controls
101 lines (90 loc) · 4.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! Shared Cranelift CLIF emission helpers used by both JIT and AOT backends.
//!
//! This module eliminates ~60 lines of duplicated constants and helper functions
//! between `src/jit/typed_compiler.rs` and `src/aot/codegen.rs`.
use crate::types::Capability;
use crate::value_layout::{PAYLOAD_MASK, SIGN_BIT, TAG_BOOL, TAG_INT, TAG_NIL};
use cranelift::prelude::*;
use cranelift_frontend::FunctionBuilder;
// ---------------------------------------------------------------------------
// Constants — cast once here, import everywhere
// ---------------------------------------------------------------------------
pub const TAG_INT_I64: i64 = TAG_INT as i64;
pub const TAG_BOOL_I64: i64 = TAG_BOOL as i64;
pub const TAG_NIL_I64: i64 = TAG_NIL as i64;
pub const PAYLOAD_MASK_I64: i64 = PAYLOAD_MASK as i64;
pub const SIGN_BIT_I64: i64 = SIGN_BIT as i64;
pub const SIGN_EXTEND: i64 = 0xFFFF_0000_0000_0000u64 as i64;
// ---------------------------------------------------------------------------
// Payload extraction
// ---------------------------------------------------------------------------
/// Extract the 48-bit payload from a tagged i64 value.
///
/// Emits: `band(raw, PAYLOAD_MASK)` — zeroes out the upper 16 tag bits.
#[inline]
pub fn emit_extract_payload(builder: &mut FunctionBuilder, raw: Value) -> Value {
let mask = builder.ins().iconst(types::I64, PAYLOAD_MASK_I64);
builder.ins().band(raw, mask)
}
// ---------------------------------------------------------------------------
// Sign extension
// ---------------------------------------------------------------------------
/// Sign-extend a 48-bit payload to 64 bits.
///
/// Emits the equivalent of the runtime `sext48` function directly in CLIF:
/// ```clif
/// payload = band(raw, PAYLOAD_MASK)
/// sign_bit = band(raw, SIGN_BIT)
/// is_neg = icmp ne, sign_bit, 0
/// extended = bor(payload, 0xFFFF_0000_0000_0000)
/// result = select is_neg, extended, payload
/// ```
///
/// This is a key optimization: instead of a runtime helper call, the sign
/// extension happens inline with ~5 CLIF instructions.
#[inline]
pub fn emit_sext48(builder: &mut FunctionBuilder, raw: Value) -> Value {
let payload = emit_extract_payload(builder, raw);
let sign_mask = builder.ins().iconst(types::I64, SIGN_BIT_I64);
let sign_bit = builder.ins().band(raw, sign_mask);
let zero = builder.ins().iconst(types::I64, 0);
let is_negative = builder.ins().icmp(IntCC::NotEqual, sign_bit, zero);
let sign_extend_const = builder.ins().iconst(types::I64, SIGN_EXTEND);
let extended = builder.ins().bor(payload, sign_extend_const);
builder.ins().select(is_negative, extended, payload)
}
// ---------------------------------------------------------------------------
// Tagging
// ---------------------------------------------------------------------------
/// Re-tag an i64 value into a NaN-tagged integer.
///
/// Emits: `bor(TAG_INT, band(value, PAYLOAD_MASK))`
#[inline]
pub fn emit_tag_int(builder: &mut FunctionBuilder, value: Value) -> Value {
let tag = builder.ins().iconst(types::I64, TAG_INT_I64);
let mask = builder.ins().iconst(types::I64, PAYLOAD_MASK_I64);
let masked = builder.ins().band(value, mask);
builder.ins().bor(tag, masked)
}
/// Tag a boolean comparison result (i8 from icmp/fcmp) as a NaN-tagged Bool.
///
/// Emits: `select cond, TAG_BOOL|1, TAG_BOOL|0`
/// Uses the more efficient 2-iconst + select pattern (from aot/codegen.rs).
#[inline]
pub fn emit_tag_bool(builder: &mut FunctionBuilder, cond: Value) -> Value {
let true_val = builder.ins().iconst(types::I64, TAG_BOOL_I64 | 1);
let false_val = builder.ins().iconst(types::I64, TAG_BOOL_I64 | 0);
builder.ins().select(cond, true_val, false_val)
}
/// Build MemFlags for a heap operation given the source register's capability.
/// val/box → readonly (loads can be CSE'd). iso/LinearIso → no special flags
/// (Cranelift 0.132 needs AliasRegion for true noalias).
#[inline]
pub fn memflags_for_capability(cap: Capability) -> MemFlags {
let mut flags = MemFlags::new();
match cap {
Capability::Val | Capability::Box => { flags.set_readonly(); }
_ => {}
}
flags
}