2021-10-08 23:21:36 +08:00
|
|
|
use inkwell::{values::BasicValueEnum, AddressSpace, AtomicOrdering};
|
2022-02-21 18:27:46 +08:00
|
|
|
use nac3core::codegen::CodeGenContext;
|
2021-10-08 23:21:36 +08:00
|
|
|
|
2023-10-23 13:35:29 +08:00
|
|
|
/// Functions for manipulating the timeline.
|
2021-10-08 23:21:36 +08:00
|
|
|
pub trait TimeFns {
|
2023-10-23 13:35:29 +08:00
|
|
|
|
|
|
|
/// Emits LLVM IR for `now_mu`.
|
2021-10-08 23:21:36 +08:00
|
|
|
fn emit_now_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>) -> BasicValueEnum<'ctx>;
|
2023-10-23 13:35:29 +08:00
|
|
|
|
|
|
|
/// Emits LLVM IR for `at_mu`.
|
2021-10-08 23:21:36 +08:00
|
|
|
fn emit_at_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, t: BasicValueEnum<'ctx>);
|
2023-10-23 13:35:29 +08:00
|
|
|
|
|
|
|
/// Emits LLVM IR for `delay_mu`.
|
2021-10-08 23:21:36 +08:00
|
|
|
fn emit_delay_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, dt: BasicValueEnum<'ctx>);
|
|
|
|
}
|
|
|
|
|
2021-11-13 12:10:55 +08:00
|
|
|
pub struct NowPinningTimeFns64 {}
|
|
|
|
|
|
|
|
// For FPGA design reasons, on VexRiscv with 64-bit data bus, the "now" CSR is split into two 32-bit
|
|
|
|
// values that are each padded to 64-bits.
|
|
|
|
impl TimeFns for NowPinningTimeFns64 {
|
|
|
|
fn emit_now_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>) -> BasicValueEnum<'ctx> {
|
2021-11-16 17:37:40 +08:00
|
|
|
let i64_type = ctx.ctx.i64_type();
|
|
|
|
let i32_type = ctx.ctx.i32_type();
|
|
|
|
let now = ctx
|
|
|
|
.module
|
|
|
|
.get_global("now")
|
|
|
|
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
2022-02-21 18:27:46 +08:00
|
|
|
let now_hiptr =
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::default()), "now.hi.addr");
|
|
|
|
|
2021-11-16 17:37:40 +08:00
|
|
|
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
|
|
|
let now_loptr = unsafe {
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now.lo.addr")
|
2021-11-16 17:37:40 +08:00
|
|
|
};
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
if let (BasicValueEnum::IntValue(now_hi), BasicValueEnum::IntValue(now_lo)) = (
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_load(now_hiptr, "now.hi"),
|
|
|
|
ctx.builder.build_load(now_loptr, "now.lo"),
|
2021-11-16 17:37:40 +08:00
|
|
|
) {
|
2023-10-23 13:35:29 +08:00
|
|
|
let zext_hi = ctx.builder.build_int_z_extend(now_hi, i64_type, "");
|
2021-11-16 17:37:40 +08:00
|
|
|
let shifted_hi = ctx.builder.build_left_shift(
|
|
|
|
zext_hi,
|
|
|
|
i64_type.const_int(32, false),
|
2023-10-23 13:35:29 +08:00
|
|
|
"",
|
2021-11-16 17:37:40 +08:00
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
let zext_lo = ctx.builder.build_int_z_extend(now_lo, i64_type, "");
|
|
|
|
ctx.builder.build_or(shifted_hi, zext_lo, "now_mu").into()
|
2021-11-16 17:37:40 +08:00
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
2021-11-13 12:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_at_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, t: BasicValueEnum<'ctx>) {
|
2021-11-16 17:37:40 +08:00
|
|
|
let i32_type = ctx.ctx.i32_type();
|
|
|
|
let i64_type = ctx.ctx.i64_type();
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2021-11-16 17:37:40 +08:00
|
|
|
let i64_32 = i64_type.const_int(32, false);
|
|
|
|
if let BasicValueEnum::IntValue(time) = t {
|
|
|
|
let time_hi = ctx.builder.build_int_truncate(
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_right_shift(time, i64_32, false, "time.hi"),
|
2021-11-16 17:37:40 +08:00
|
|
|
i32_type,
|
2023-10-23 13:35:29 +08:00
|
|
|
"",
|
2021-11-16 17:37:40 +08:00
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "time.lo");
|
2021-11-16 17:37:40 +08:00
|
|
|
let now = ctx
|
|
|
|
.module
|
|
|
|
.get_global("now")
|
|
|
|
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
|
|
|
let now_hiptr = ctx.builder.build_bitcast(
|
|
|
|
now,
|
2023-01-12 19:31:03 +08:00
|
|
|
i32_type.ptr_type(AddressSpace::default()),
|
2023-10-23 13:35:29 +08:00
|
|
|
"now.hi.addr",
|
2021-11-16 17:37:40 +08:00
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2021-11-16 17:37:40 +08:00
|
|
|
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
|
|
|
let now_loptr = unsafe {
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now.lo.addr")
|
2021-11-16 17:37:40 +08:00
|
|
|
};
|
|
|
|
ctx.builder
|
|
|
|
.build_store(now_hiptr, time_hi)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder
|
|
|
|
.build_store(now_loptr, time_lo)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
2021-11-13 12:10:55 +08:00
|
|
|
}
|
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
fn emit_delay_mu<'ctx, 'a>(
|
|
|
|
&self,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
dt: BasicValueEnum<'ctx>,
|
|
|
|
) {
|
2021-11-16 17:37:40 +08:00
|
|
|
let i64_type = ctx.ctx.i64_type();
|
|
|
|
let i32_type = ctx.ctx.i32_type();
|
|
|
|
let now = ctx
|
|
|
|
.module
|
|
|
|
.get_global("now")
|
|
|
|
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
2022-02-21 18:27:46 +08:00
|
|
|
let now_hiptr =
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_bitcast(now, i32_type.ptr_type(AddressSpace::default()), "now.hi.addr");
|
|
|
|
|
2021-11-16 17:37:40 +08:00
|
|
|
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
|
|
|
let now_loptr = unsafe {
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(2, false)], "now.lo.addr")
|
2021-11-16 17:37:40 +08:00
|
|
|
};
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2021-11-16 17:37:40 +08:00
|
|
|
if let (
|
|
|
|
BasicValueEnum::IntValue(now_hi),
|
|
|
|
BasicValueEnum::IntValue(now_lo),
|
2022-02-21 18:27:46 +08:00
|
|
|
BasicValueEnum::IntValue(dt),
|
2021-11-16 17:37:40 +08:00
|
|
|
) = (
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_load(now_hiptr, "now.hi"),
|
|
|
|
ctx.builder.build_load(now_loptr, "now.lo"),
|
2022-02-21 18:27:46 +08:00
|
|
|
dt,
|
2021-11-16 17:37:40 +08:00
|
|
|
) {
|
2023-10-23 13:35:29 +08:00
|
|
|
let zext_hi = ctx.builder.build_int_z_extend(now_hi, i64_type, "");
|
2021-11-16 17:37:40 +08:00
|
|
|
let shifted_hi = ctx.builder.build_left_shift(
|
|
|
|
zext_hi,
|
|
|
|
i64_type.const_int(32, false),
|
2023-10-23 13:35:29 +08:00
|
|
|
"",
|
2021-11-16 17:37:40 +08:00
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
let zext_lo = ctx.builder.build_int_z_extend(now_lo, i64_type, "");
|
|
|
|
let now_val = ctx.builder.build_or(shifted_hi, zext_lo, "now");
|
2022-02-21 18:27:46 +08:00
|
|
|
|
2023-10-23 13:35:29 +08:00
|
|
|
let time = ctx.builder.build_int_add(now_val, dt, "time");
|
2021-11-16 17:37:40 +08:00
|
|
|
let time_hi = ctx.builder.build_int_truncate(
|
2022-02-21 18:27:46 +08:00
|
|
|
ctx.builder.build_right_shift(
|
|
|
|
time,
|
|
|
|
i64_type.const_int(32, false),
|
|
|
|
false,
|
2023-10-23 13:35:29 +08:00
|
|
|
"",
|
2022-02-21 18:27:46 +08:00
|
|
|
),
|
2021-11-16 17:37:40 +08:00
|
|
|
i32_type,
|
2023-10-23 13:35:29 +08:00
|
|
|
"time.hi",
|
2021-11-16 17:37:40 +08:00
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "time.lo");
|
2022-02-21 18:27:46 +08:00
|
|
|
|
2021-11-16 17:37:40 +08:00
|
|
|
ctx.builder
|
|
|
|
.build_store(now_hiptr, time_hi)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder
|
|
|
|
.build_store(now_loptr, time_lo)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
};
|
2021-11-13 12:10:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub static NOW_PINNING_TIME_FNS_64: NowPinningTimeFns64 = NowPinningTimeFns64 {};
|
|
|
|
|
2021-10-08 23:21:36 +08:00
|
|
|
pub struct NowPinningTimeFns {}
|
|
|
|
|
|
|
|
impl TimeFns for NowPinningTimeFns {
|
|
|
|
fn emit_now_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>) -> BasicValueEnum<'ctx> {
|
|
|
|
let i64_type = ctx.ctx.i64_type();
|
|
|
|
let now = ctx
|
|
|
|
.module
|
|
|
|
.get_global("now")
|
|
|
|
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
|
|
|
let now_raw = ctx.builder.build_load(now.as_pointer_value(), "now");
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2021-10-08 23:21:36 +08:00
|
|
|
if let BasicValueEnum::IntValue(now_raw) = now_raw {
|
2021-11-06 23:00:18 +08:00
|
|
|
let i64_32 = i64_type.const_int(32, false);
|
2023-10-23 13:35:29 +08:00
|
|
|
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now.lo");
|
|
|
|
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now.hi");
|
|
|
|
ctx.builder.build_or(now_lo, now_hi, "now_mu").into()
|
2021-10-08 23:21:36 +08:00
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_at_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, t: BasicValueEnum<'ctx>) {
|
|
|
|
let i32_type = ctx.ctx.i32_type();
|
|
|
|
let i64_type = ctx.ctx.i64_type();
|
2021-11-06 23:00:18 +08:00
|
|
|
let i64_32 = i64_type.const_int(32, false);
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2021-10-08 23:21:36 +08:00
|
|
|
if let BasicValueEnum::IntValue(time) = t {
|
|
|
|
let time_hi = ctx.builder.build_int_truncate(
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_right_shift(time, i64_32, false, ""),
|
2021-10-08 23:21:36 +08:00
|
|
|
i32_type,
|
2023-10-23 13:35:29 +08:00
|
|
|
"time.hi",
|
2021-10-08 23:21:36 +08:00
|
|
|
);
|
|
|
|
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "now_trunc");
|
|
|
|
let now = ctx
|
|
|
|
.module
|
|
|
|
.get_global("now")
|
|
|
|
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
|
|
|
let now_hiptr = ctx.builder.build_bitcast(
|
|
|
|
now,
|
2023-01-12 19:31:03 +08:00
|
|
|
i32_type.ptr_type(AddressSpace::default()),
|
2023-10-23 13:35:29 +08:00
|
|
|
"now.hi.addr",
|
2021-10-08 23:21:36 +08:00
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2021-10-08 23:21:36 +08:00
|
|
|
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
|
|
|
let now_loptr = unsafe {
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false)], "now.lo.addr")
|
2021-10-08 23:21:36 +08:00
|
|
|
};
|
|
|
|
ctx.builder
|
|
|
|
.build_store(now_hiptr, time_hi)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder
|
|
|
|
.build_store(now_loptr, time_lo)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
fn emit_delay_mu<'ctx, 'a>(
|
|
|
|
&self,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
dt: BasicValueEnum<'ctx>,
|
|
|
|
) {
|
2021-10-08 23:21:36 +08:00
|
|
|
let i32_type = ctx.ctx.i32_type();
|
|
|
|
let i64_type = ctx.ctx.i64_type();
|
2021-11-06 23:00:18 +08:00
|
|
|
let i64_32 = i64_type.const_int(32, false);
|
2021-10-08 23:21:36 +08:00
|
|
|
let now = ctx
|
|
|
|
.module
|
|
|
|
.get_global("now")
|
|
|
|
.unwrap_or_else(|| ctx.module.add_global(i64_type, None, "now"));
|
2023-10-23 13:35:29 +08:00
|
|
|
let now_raw = ctx.builder.build_load(now.as_pointer_value(), "");
|
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
if let (BasicValueEnum::IntValue(now_raw), BasicValueEnum::IntValue(dt)) = (now_raw, dt) {
|
2023-10-23 13:35:29 +08:00
|
|
|
let now_lo = ctx.builder.build_left_shift(now_raw, i64_32, "now.lo");
|
|
|
|
let now_hi = ctx.builder.build_right_shift(now_raw, i64_32, false, "now.hi");
|
|
|
|
let now_val = ctx.builder.build_or(now_lo, now_hi, "now_val");
|
|
|
|
let time = ctx.builder.build_int_add(now_val, dt, "time");
|
2021-10-08 23:21:36 +08:00
|
|
|
let time_hi = ctx.builder.build_int_truncate(
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_right_shift(time, i64_32, false, "time.hi"),
|
2021-10-08 23:21:36 +08:00
|
|
|
i32_type,
|
|
|
|
"now_trunc",
|
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
let time_lo = ctx.builder.build_int_truncate(time, i32_type, "time.lo");
|
2021-10-08 23:21:36 +08:00
|
|
|
let now_hiptr = ctx.builder.build_bitcast(
|
|
|
|
now,
|
2023-01-12 19:31:03 +08:00
|
|
|
i32_type.ptr_type(AddressSpace::default()),
|
2023-10-23 13:35:29 +08:00
|
|
|
"now.hi.addr",
|
2021-10-08 23:21:36 +08:00
|
|
|
);
|
2023-10-23 13:35:29 +08:00
|
|
|
|
2021-10-08 23:21:36 +08:00
|
|
|
if let BasicValueEnum::PointerValue(now_hiptr) = now_hiptr {
|
|
|
|
let now_loptr = unsafe {
|
2023-10-23 13:35:29 +08:00
|
|
|
ctx.builder.build_gep(now_hiptr, &[i32_type.const_int(1, false)], "now.lo.addr")
|
2021-10-08 23:21:36 +08:00
|
|
|
};
|
|
|
|
ctx.builder
|
|
|
|
.build_store(now_hiptr, time_hi)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
ctx.builder
|
|
|
|
.build_store(now_loptr, time_lo)
|
|
|
|
.set_atomic_ordering(AtomicOrdering::SequentiallyConsistent)
|
|
|
|
.unwrap();
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub static NOW_PINNING_TIME_FNS: NowPinningTimeFns = NowPinningTimeFns {};
|
|
|
|
|
|
|
|
pub struct ExternTimeFns {}
|
|
|
|
|
|
|
|
impl TimeFns for ExternTimeFns {
|
|
|
|
fn emit_now_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>) -> BasicValueEnum<'ctx> {
|
2022-02-21 18:27:46 +08:00
|
|
|
let now_mu = ctx.module.get_function("now_mu").unwrap_or_else(|| {
|
|
|
|
ctx.module.add_function("now_mu", ctx.ctx.i64_type().fn_type(&[], false), None)
|
|
|
|
});
|
|
|
|
ctx.builder.build_call(now_mu, &[], "now_mu").try_as_basic_value().left().unwrap()
|
2021-10-08 23:21:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn emit_at_mu<'ctx, 'a>(&self, ctx: &mut CodeGenContext<'ctx, 'a>, t: BasicValueEnum<'ctx>) {
|
2022-02-21 18:27:46 +08:00
|
|
|
let at_mu = ctx.module.get_function("at_mu").unwrap_or_else(|| {
|
|
|
|
ctx.module.add_function(
|
|
|
|
"at_mu",
|
|
|
|
ctx.ctx.void_type().fn_type(&[ctx.ctx.i64_type().into()], false),
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
ctx.builder.build_call(at_mu, &[t.into()], "at_mu");
|
2021-10-08 23:21:36 +08:00
|
|
|
}
|
|
|
|
|
2022-02-21 18:27:46 +08:00
|
|
|
fn emit_delay_mu<'ctx, 'a>(
|
|
|
|
&self,
|
|
|
|
ctx: &mut CodeGenContext<'ctx, 'a>,
|
|
|
|
dt: BasicValueEnum<'ctx>,
|
|
|
|
) {
|
|
|
|
let delay_mu = ctx.module.get_function("delay_mu").unwrap_or_else(|| {
|
|
|
|
ctx.module.add_function(
|
|
|
|
"delay_mu",
|
|
|
|
ctx.ctx.void_type().fn_type(&[ctx.ctx.i64_type().into()], false),
|
|
|
|
None,
|
|
|
|
)
|
|
|
|
});
|
|
|
|
ctx.builder.build_call(delay_mu, &[dt.into()], "delay_mu");
|
2021-10-08 23:21:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub static EXTERN_TIME_FNS: ExternTimeFns = ExternTimeFns {};
|