refactor(codegen): parameterise the copy-pasted IR-emission families
Emitted IR is byte-identical for every case — proven by the IR-pin
suites (eq_primitives_pin, ord_int_intercept_ir_pin, the raw_buf_*
and drop/leak pins) and the full e2e suite, all green.
intercepts.rs:
- The twelve emit_rawbuf_{new,get,set,size}_{int,float,bool} functions
were copy-paste across three element types, differing only in the
element width (8/8/1) and the LLVM load/store type (i64/double/i1).
Collapsed to four parameterised cores; the element variants are thin
call sites passing the (width, type) pair.
- Replaced the repeated, off-by-one-prone parameter-SSA extraction
idiom (`locals[n-2]`, `locals[n-1]`) with an Emitter::last_param_ssas
helper.
- Factored the shared IR-Str bytes GEP out of emit_eq_str /
emit_compare_str into emit_str_bytes_gep.
drop.rs:
- The three emit_*_drop_fn_for_type methods shared one wrapping shape
(monomorphic short-circuit, else loop over instantiations dispatching
to a *_for_instantiation helper); hoisted into emit_drop_fn_wrapper
taking the per-instantiation emitter as a fn pointer.
- emit_flat_intrinsic_drop_fn / _partial_drop_fn differed only in the
symbol prefix and an ignored mask param; merged into one inner
emitter.
No INTERCEPTS-registry or (intrinsic)-marker changes.
This commit is contained in:
@@ -293,26 +293,36 @@ pub(crate) fn check_sig(
|
||||
// replaced by `Ok(())` because the shim wraps the bool.
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
/// Emit the `getelementptr inbounds i8, ptr <src>, i64 8` that walks
|
||||
/// an IR-Str pointer (which lands on the `len` field of the packed
|
||||
/// slab) forward to its bytes pointer, returning the fresh SSA holding
|
||||
/// the result. Shared by `emit_eq_str` / `emit_compare_str`. Because
|
||||
/// `fresh_ssa` allocates sequentially, calling this twice in a row
|
||||
/// yields the same `%vK`, `%vK+1` pair — and the same two GEP lines in
|
||||
/// the same order — as the inlined form it replaces, so the emitted IR
|
||||
/// is byte-identical.
|
||||
fn emit_str_bytes_gep(emitter: &mut Emitter<'_>, src: &str) -> String {
|
||||
let bytes = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {bytes} = getelementptr inbounds i8, ptr {src}, i64 8\n"
|
||||
));
|
||||
bytes
|
||||
}
|
||||
|
||||
pub(crate) fn emit_eq_str(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
// The two params are the two most recently pushed locals;
|
||||
// `emit_fn` populated `self.locals` from `f.params` before
|
||||
// dispatching here. Pull their SSA names without assuming
|
||||
// a specific surface-level binder name.
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
// IR-Str pointers now land on the
|
||||
// `len`-field of the packed-struct slab; @ail_str_eq's
|
||||
// strcmp-based body needs the bytes pointer 8 bytes
|
||||
// further on.
|
||||
let a_bytes = emitter.fresh_ssa();
|
||||
let b_bytes = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {a_bytes} = getelementptr inbounds i8, ptr {a_ssa}, i64 8\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(
|
||||
" {b_bytes} = getelementptr inbounds i8, ptr {b_ssa}, i64 8\n"
|
||||
));
|
||||
let a_bytes = emit_str_bytes_gep(emitter, &a_ssa);
|
||||
let b_bytes = emit_str_bytes_gep(emitter, &b_ssa);
|
||||
let dst = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {dst} = call zeroext i1 @ail_str_eq(ptr {a_bytes}, ptr {b_bytes})\n"
|
||||
@@ -324,9 +334,9 @@ pub(crate) fn emit_eq_str(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_compare_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
emitter.emit_compare_ladder(
|
||||
&format!("icmp slt i64 {a_ssa}, {b_ssa}"),
|
||||
&format!("icmp eq i64 {a_ssa}, {b_ssa}"),
|
||||
@@ -335,9 +345,9 @@ pub(crate) fn emit_compare_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_compare_bool(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
emitter.emit_compare_ladder(
|
||||
&format!("icmp ult i1 {a_ssa}, {b_ssa}"),
|
||||
&format!("icmp eq i1 {a_ssa}, {b_ssa}"),
|
||||
@@ -346,21 +356,15 @@ pub(crate) fn emit_compare_bool(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_compare_str(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
// IR-Str pointers now land on the
|
||||
// `len`-field of the packed-struct slab; @ail_str_compare's
|
||||
// strcmp-based body needs the bytes pointer 8 bytes
|
||||
// further on.
|
||||
let a_bytes = emitter.fresh_ssa();
|
||||
let b_bytes = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {a_bytes} = getelementptr inbounds i8, ptr {a_ssa}, i64 8\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(
|
||||
" {b_bytes} = getelementptr inbounds i8, ptr {b_ssa}, i64 8\n"
|
||||
));
|
||||
let a_bytes = emit_str_bytes_gep(emitter, &a_ssa);
|
||||
let b_bytes = emit_str_bytes_gep(emitter, &b_ssa);
|
||||
let cmp_res = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {cmp_res} = call i32 @ail_str_compare(ptr {a_bytes}, ptr {b_bytes})\n"
|
||||
@@ -373,9 +377,9 @@ pub(crate) fn emit_compare_str(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_eq_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = icmp eq i64 {a_ssa}, {b_ssa}\n"
|
||||
@@ -387,9 +391,9 @@ pub(crate) fn emit_eq_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_eq_bool(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = icmp eq i1 {a_ssa}, {b_ssa}\n"
|
||||
@@ -411,9 +415,9 @@ pub(crate) fn emit_eq_unit(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_float_eq(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = fcmp oeq double {a_ssa}, {b_ssa}\n"
|
||||
@@ -427,9 +431,9 @@ pub(crate) fn emit_float_eq(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
pub(crate) fn emit_float_ne(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
// `fcmp une` ("unordered or not-equal"), not `one`,
|
||||
// mirroring float-semantics.md: NaN != NaN must be true.
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = fcmp une double {a_ssa}, {b_ssa}\n"
|
||||
@@ -441,9 +445,9 @@ pub(crate) fn emit_float_ne(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_float_lt(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = fcmp olt double {a_ssa}, {b_ssa}\n"
|
||||
@@ -455,9 +459,9 @@ pub(crate) fn emit_float_lt(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_float_le(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = fcmp ole double {a_ssa}, {b_ssa}\n"
|
||||
@@ -469,9 +473,9 @@ pub(crate) fn emit_float_le(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_float_gt(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = fcmp ogt double {a_ssa}, {b_ssa}\n"
|
||||
@@ -483,9 +487,9 @@ pub(crate) fn emit_float_gt(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
}
|
||||
|
||||
pub(crate) fn emit_float_ge(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let a_ssa = emitter.locals[n - 2].1.clone();
|
||||
let b_ssa = emitter.locals[n - 1].1.clone();
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let a_ssa = params[0].clone();
|
||||
let b_ssa = params[1].clone();
|
||||
let r = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(
|
||||
" {r} = fcmp oge double {a_ssa}, {b_ssa}\n"
|
||||
@@ -543,15 +547,23 @@ pub(crate) fn emit_ne_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
// `@ailang_rc_alloc` is hardcoded (not `alloc.fn_name()`).
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// --- Int variants (element type i64, width 8) ---
|
||||
// Parameterised cores. The three element variants (Int, Float, Bool)
|
||||
// differ in exactly two axes: the per-element byte width used in the
|
||||
// index `mul` / capacity `mul` (Int=8, Float=8, Bool=1) and the LLVM
|
||||
// load/store type used by `get`/`set` (Int=i64, Float=double, Bool=i1).
|
||||
// `new`/`size` carry only the width axis (their slab header is always
|
||||
// i64). Each core emits the IR for one operation; the public per-type
|
||||
// wrappers below pass the right `(width, elem_ty)` pair, so the emitted
|
||||
// IR for every variant is byte-identical to the pre-dedup form.
|
||||
|
||||
pub(crate) fn emit_rawbuf_new_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let cap = emitter.locals[n - 1].1.clone(); // i64 capacity
|
||||
fn emit_rawbuf_new(emitter: &mut Emitter<'_>, elem_width: u64) -> Result<()> {
|
||||
let cap = emitter.last_param_ssas(1)[0].clone(); // i64 capacity
|
||||
let elems_bytes = emitter.fresh_ssa();
|
||||
let total = emitter.fresh_ssa();
|
||||
let slab = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {elems_bytes} = mul i64 {cap}, 8\n"));
|
||||
emitter
|
||||
.body
|
||||
.push_str(&format!(" {elems_bytes} = mul i64 {cap}, {elem_width}\n"));
|
||||
emitter.body.push_str(&format!(" {total} = add i64 {elems_bytes}, 8\n"));
|
||||
emitter
|
||||
.body
|
||||
@@ -563,49 +575,56 @@ pub(crate) fn emit_rawbuf_new_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_get_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let b = emitter.locals[n - 2].1.clone();
|
||||
let i = emitter.locals[n - 1].1.clone();
|
||||
fn emit_rawbuf_get(
|
||||
emitter: &mut Emitter<'_>,
|
||||
elem_width: u64,
|
||||
elem_ty: &str,
|
||||
) -> Result<()> {
|
||||
let params = emitter.last_param_ssas(2);
|
||||
let b = params[0].clone();
|
||||
let i = params[1].clone();
|
||||
let off = emitter.fresh_ssa();
|
||||
let byteoff = emitter.fresh_ssa();
|
||||
let ptr = emitter.fresh_ssa();
|
||||
let v = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, 8\n"));
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, {elem_width}\n"));
|
||||
emitter.body.push_str(&format!(" {byteoff} = add i64 {off}, 8\n"));
|
||||
emitter.body.push_str(&format!(
|
||||
" {ptr} = getelementptr inbounds i8, ptr {b}, i64 {byteoff}\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(" {v} = load i64, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" ret i64 {v}\n"));
|
||||
emitter.body.push_str(&format!(" {v} = load {elem_ty}, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" ret {elem_ty} {v}\n"));
|
||||
emitter.body.push_str("}\n\n");
|
||||
emitter.block_terminated = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_set_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let b = emitter.locals[n - 3].1.clone();
|
||||
let i = emitter.locals[n - 2].1.clone();
|
||||
let v = emitter.locals[n - 1].1.clone();
|
||||
fn emit_rawbuf_set(
|
||||
emitter: &mut Emitter<'_>,
|
||||
elem_width: u64,
|
||||
elem_ty: &str,
|
||||
) -> Result<()> {
|
||||
let params = emitter.last_param_ssas(3);
|
||||
let b = params[0].clone();
|
||||
let i = params[1].clone();
|
||||
let v = params[2].clone();
|
||||
let off = emitter.fresh_ssa();
|
||||
let byteoff = emitter.fresh_ssa();
|
||||
let ptr = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, 8\n"));
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, {elem_width}\n"));
|
||||
emitter.body.push_str(&format!(" {byteoff} = add i64 {off}, 8\n"));
|
||||
emitter.body.push_str(&format!(
|
||||
" {ptr} = getelementptr inbounds i8, ptr {b}, i64 {byteoff}\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(" store i64 {v}, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" store {elem_ty} {v}, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" ret ptr {b}\n"));
|
||||
emitter.body.push_str("}\n\n");
|
||||
emitter.block_terminated = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_size_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let b = emitter.locals[n - 1].1.clone();
|
||||
fn emit_rawbuf_size(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let b = emitter.last_param_ssas(1)[0].clone();
|
||||
let sz = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {sz} = load i64, ptr {b}\n"));
|
||||
emitter.body.push_str(&format!(" ret i64 {sz}\n"));
|
||||
@@ -614,122 +633,58 @@ pub(crate) fn emit_rawbuf_size_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// --- Int variants (element type i64, width 8) ---
|
||||
|
||||
pub(crate) fn emit_rawbuf_new_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
emit_rawbuf_new(emitter, 8)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_get_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
emit_rawbuf_get(emitter, 8, "i64")
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_set_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
emit_rawbuf_set(emitter, 8, "i64")
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_size_int(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
emit_rawbuf_size(emitter)
|
||||
}
|
||||
|
||||
// --- Float variants (element type double, width 8) ---
|
||||
|
||||
pub(crate) fn emit_rawbuf_new_float(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
// Header always i64; element width 8 — byte-identical to Int's new.
|
||||
emit_rawbuf_new_int(emitter)
|
||||
emit_rawbuf_new(emitter, 8)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_get_float(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let b = emitter.locals[n - 2].1.clone();
|
||||
let i = emitter.locals[n - 1].1.clone();
|
||||
let off = emitter.fresh_ssa();
|
||||
let byteoff = emitter.fresh_ssa();
|
||||
let ptr = emitter.fresh_ssa();
|
||||
let v = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, 8\n"));
|
||||
emitter.body.push_str(&format!(" {byteoff} = add i64 {off}, 8\n"));
|
||||
emitter.body.push_str(&format!(
|
||||
" {ptr} = getelementptr inbounds i8, ptr {b}, i64 {byteoff}\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(" {v} = load double, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" ret double {v}\n"));
|
||||
emitter.body.push_str("}\n\n");
|
||||
emitter.block_terminated = true;
|
||||
Ok(())
|
||||
emit_rawbuf_get(emitter, 8, "double")
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_set_float(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let b = emitter.locals[n - 3].1.clone();
|
||||
let i = emitter.locals[n - 2].1.clone();
|
||||
let v = emitter.locals[n - 1].1.clone();
|
||||
let off = emitter.fresh_ssa();
|
||||
let byteoff = emitter.fresh_ssa();
|
||||
let ptr = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, 8\n"));
|
||||
emitter.body.push_str(&format!(" {byteoff} = add i64 {off}, 8\n"));
|
||||
emitter.body.push_str(&format!(
|
||||
" {ptr} = getelementptr inbounds i8, ptr {b}, i64 {byteoff}\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(" store double {v}, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" ret ptr {b}\n"));
|
||||
emitter.body.push_str("}\n\n");
|
||||
emitter.block_terminated = true;
|
||||
Ok(())
|
||||
emit_rawbuf_set(emitter, 8, "double")
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_size_float(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
// Header always i64 — byte-identical to Int's size.
|
||||
emit_rawbuf_size_int(emitter)
|
||||
emit_rawbuf_size(emitter)
|
||||
}
|
||||
|
||||
// --- Bool variants (element type i1, width 1) ---
|
||||
|
||||
pub(crate) fn emit_rawbuf_new_bool(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let cap = emitter.locals[n - 1].1.clone(); // i64 capacity
|
||||
let elems_bytes = emitter.fresh_ssa();
|
||||
let total = emitter.fresh_ssa();
|
||||
let slab = emitter.fresh_ssa();
|
||||
// element width 1 byte for Bool.
|
||||
emitter.body.push_str(&format!(" {elems_bytes} = mul i64 {cap}, 1\n"));
|
||||
emitter.body.push_str(&format!(" {total} = add i64 {elems_bytes}, 8\n"));
|
||||
emitter
|
||||
.body
|
||||
.push_str(&format!(" {slab} = call ptr @ailang_rc_alloc(i64 {total})\n"));
|
||||
emitter.body.push_str(&format!(" store i64 {cap}, ptr {slab}\n"));
|
||||
emitter.body.push_str(&format!(" ret ptr {slab}\n"));
|
||||
emitter.body.push_str("}\n\n");
|
||||
emitter.block_terminated = true;
|
||||
Ok(())
|
||||
emit_rawbuf_new(emitter, 1)
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_get_bool(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let b = emitter.locals[n - 2].1.clone();
|
||||
let i = emitter.locals[n - 1].1.clone();
|
||||
let off = emitter.fresh_ssa();
|
||||
let byteoff = emitter.fresh_ssa();
|
||||
let ptr = emitter.fresh_ssa();
|
||||
let v = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, 1\n"));
|
||||
emitter.body.push_str(&format!(" {byteoff} = add i64 {off}, 8\n"));
|
||||
emitter.body.push_str(&format!(
|
||||
" {ptr} = getelementptr inbounds i8, ptr {b}, i64 {byteoff}\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(" {v} = load i1, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" ret i1 {v}\n"));
|
||||
emitter.body.push_str("}\n\n");
|
||||
emitter.block_terminated = true;
|
||||
Ok(())
|
||||
emit_rawbuf_get(emitter, 1, "i1")
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_set_bool(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
let n = emitter.locals.len();
|
||||
let b = emitter.locals[n - 3].1.clone();
|
||||
let i = emitter.locals[n - 2].1.clone();
|
||||
let v = emitter.locals[n - 1].1.clone();
|
||||
let off = emitter.fresh_ssa();
|
||||
let byteoff = emitter.fresh_ssa();
|
||||
let ptr = emitter.fresh_ssa();
|
||||
emitter.body.push_str(&format!(" {off} = mul i64 {i}, 1\n"));
|
||||
emitter.body.push_str(&format!(" {byteoff} = add i64 {off}, 8\n"));
|
||||
emitter.body.push_str(&format!(
|
||||
" {ptr} = getelementptr inbounds i8, ptr {b}, i64 {byteoff}\n"
|
||||
));
|
||||
emitter.body.push_str(&format!(" store i1 {v}, ptr {ptr}\n"));
|
||||
emitter.body.push_str(&format!(" ret ptr {b}\n"));
|
||||
emitter.body.push_str("}\n\n");
|
||||
emitter.block_terminated = true;
|
||||
Ok(())
|
||||
emit_rawbuf_set(emitter, 1, "i1")
|
||||
}
|
||||
|
||||
pub(crate) fn emit_rawbuf_size_bool(emitter: &mut Emitter<'_>) -> Result<()> {
|
||||
// Header always i64 — byte-identical to Int's size.
|
||||
emit_rawbuf_size_int(emitter)
|
||||
emit_rawbuf_size(emitter)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user