forked from M-Labs/nac3
core: add RustRange
This commit is contained in:
parent
a6e1d354b6
commit
b38d9000f8
|
@ -46,4 +46,9 @@ extern "C"
|
||||||
{
|
{
|
||||||
return range::len(start, stop, step);
|
return range::len(start, stop, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t __nac3_range_len_i64(int64_t start, int64_t stop, int64_t step)
|
||||||
|
{
|
||||||
|
return range::len(start, stop, step);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -609,18 +609,30 @@ pub fn setup_irrt_exceptions<'ctx>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_nac3_range_len_i32<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_range_len<'ctx, G: CodeGenerator + ?Sized, N: IntKind<'ctx>>(
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
start: Instance<'ctx, Int<Int32>>,
|
int_kind: N,
|
||||||
stop: Instance<'ctx, Int<Int32>>,
|
start: IntValue<'ctx>,
|
||||||
step: Instance<'ctx, Int<Int32>>,
|
stop: IntValue<'ctx>,
|
||||||
) -> Instance<'ctx, Int<Int32>> {
|
step: IntValue<'ctx>,
|
||||||
CallFunction::begin(generator, ctx, "__nac3_range_len_i32")
|
) -> Instance<'ctx, Int<N>> {
|
||||||
|
let start = Int(int_kind).check_value(generator, ctx.ctx, start).unwrap();
|
||||||
|
let stop = Int(int_kind).check_value(generator, ctx.ctx, stop).unwrap();
|
||||||
|
let step = Int(int_kind).check_value(generator, ctx.ctx, step).unwrap();
|
||||||
|
|
||||||
|
let bit_width = int_kind.get_int_type(generator, ctx.ctx).get_bit_width();
|
||||||
|
let func_name = match bit_width {
|
||||||
|
32 => "__nac3_range_len_i32",
|
||||||
|
64 => "__nac3_range_len_i64",
|
||||||
|
_ => panic!("{bit_width}-bits ints not supported"), // We could add more variants when necessary.
|
||||||
|
};
|
||||||
|
|
||||||
|
CallFunction::begin(generator, ctx, func_name)
|
||||||
.arg(start)
|
.arg(start)
|
||||||
.arg(stop)
|
.arg(stop)
|
||||||
.arg(step)
|
.arg(step)
|
||||||
.returning_auto("range_len")
|
.returning("range_len", Int(int_kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call_nac3_ndarray_util_assert_shape_no_negative<'ctx, G: CodeGenerator + ?Sized>(
|
pub fn call_nac3_ndarray_util_assert_shape_no_negative<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use inkwell::{values::IntValue, IntPredicate};
|
use inkwell::{values::IntValue, IntPredicate};
|
||||||
|
|
||||||
use crate::codegen::{irrt::call_nac3_range_len_i32, model::*, CodeGenContext, CodeGenerator};
|
use crate::codegen::{irrt::call_nac3_range_len, model::*, CodeGenContext, CodeGenerator};
|
||||||
|
|
||||||
use super::any::AnyObject;
|
use super::any::AnyObject;
|
||||||
|
|
||||||
|
@ -63,6 +63,45 @@ pub fn assert_range_step_non_zero<'ctx, G: CodeGenerator + ?Sized>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A Rust structure that has [`Range`] utilities and looks like a [`Range`] but
|
||||||
|
/// `start`, `stop` and `step` are held by LLVM registers only.
|
||||||
|
///
|
||||||
|
/// This structure exists because many implementations use [`Range`] utilities but
|
||||||
|
/// it might not be good to alloca an actual [`Range`] value on the stack in order
|
||||||
|
/// to perform calculations.
|
||||||
|
pub struct RustRange<'ctx, N: IntKind<'ctx>> {
|
||||||
|
pub start: Instance<'ctx, Int<N>>,
|
||||||
|
pub stop: Instance<'ctx, Int<N>>,
|
||||||
|
pub step: Instance<'ctx, Int<N>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ctx, N: IntKind<'ctx>> RustRange<'ctx, N> {
|
||||||
|
pub fn assert_step_non_zero<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
) {
|
||||||
|
assert_range_step_non_zero(generator, ctx, self.step.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate the `len()` of this range.
|
||||||
|
pub fn len<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
) -> Instance<'ctx, Int<N>> {
|
||||||
|
let int_kind = self.start.model.0;
|
||||||
|
call_nac3_range_len(
|
||||||
|
generator,
|
||||||
|
ctx,
|
||||||
|
int_kind,
|
||||||
|
self.start.value,
|
||||||
|
self.stop.value,
|
||||||
|
self.step.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: `RangeObject` in the future will have range32, range64
|
// TODO: `RangeObject` in the future will have range32, range64
|
||||||
|
|
||||||
/// A NAC3 Python range object.
|
/// A NAC3 Python range object.
|
||||||
|
@ -84,14 +123,24 @@ impl<'ctx> RangeObject<'ctx> {
|
||||||
RangeObject { instance }
|
RangeObject { instance }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert into a [`RustRange`].
|
||||||
|
pub fn as_rust_range<G: CodeGenerator + ?Sized>(
|
||||||
|
&self,
|
||||||
|
generator: &mut G,
|
||||||
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
|
) -> RustRange<'ctx, Int32> {
|
||||||
|
let (start, stop, step) = self.instance.destructure(generator, ctx);
|
||||||
|
RustRange { start, stop, step }
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the `len()` of this range.
|
/// Get the `len()` of this range.
|
||||||
pub fn len<G: CodeGenerator + ?Sized>(
|
pub fn len<G: CodeGenerator + ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
generator: &mut G,
|
generator: &mut G,
|
||||||
ctx: &mut CodeGenContext<'ctx, '_>,
|
ctx: &mut CodeGenContext<'ctx, '_>,
|
||||||
) -> Instance<'ctx, Int<Int32>> {
|
) -> Instance<'ctx, Int<Int32>> {
|
||||||
let (start, stop, step) = self.instance.destructure(generator, ctx);
|
let range = self.as_rust_range(generator, ctx);
|
||||||
assert_range_step_non_zero(generator, ctx, step.value);
|
range.assert_step_non_zero(generator, ctx);
|
||||||
call_nac3_range_len_i32(generator, ctx, start, stop, step)
|
range.len(generator, ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue