diff --git a/nac3core/irrt/irrt/range.hpp b/nac3core/irrt/irrt/range.hpp index 651cc597..c1d8fd26 100644 --- a/nac3core/irrt/irrt/range.hpp +++ b/nac3core/irrt/irrt/range.hpp @@ -46,4 +46,9 @@ extern "C" { 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); + } } \ No newline at end of file diff --git a/nac3core/src/codegen/irrt/mod.rs b/nac3core/src/codegen/irrt/mod.rs index c7fe3e01..5c18cdaf 100644 --- a/nac3core/src/codegen/irrt/mod.rs +++ b/nac3core/src/codegen/irrt/mod.rs @@ -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, ctx: &mut CodeGenContext<'ctx, '_>, - start: Instance<'ctx, Int>, - stop: Instance<'ctx, Int>, - step: Instance<'ctx, Int>, -) -> Instance<'ctx, Int> { - CallFunction::begin(generator, ctx, "__nac3_range_len_i32") + int_kind: N, + start: IntValue<'ctx>, + stop: IntValue<'ctx>, + step: IntValue<'ctx>, +) -> Instance<'ctx, Int> { + 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(stop) .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>( diff --git a/nac3core/src/codegen/object/range.rs b/nac3core/src/codegen/object/range.rs index 5ca84fca..127ad935 100644 --- a/nac3core/src/codegen/object/range.rs +++ b/nac3core/src/codegen/object/range.rs @@ -1,6 +1,6 @@ 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; @@ -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>, + pub stop: Instance<'ctx, Int>, + pub step: Instance<'ctx, Int>, +} + +impl<'ctx, N: IntKind<'ctx>> RustRange<'ctx, N> { + pub fn assert_step_non_zero( + &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( + &self, + generator: &mut G, + ctx: &mut CodeGenContext<'ctx, '_>, + ) -> Instance<'ctx, Int> { + 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 /// A NAC3 Python range object. @@ -84,14 +123,24 @@ impl<'ctx> RangeObject<'ctx> { RangeObject { instance } } + /// Convert into a [`RustRange`]. + pub fn as_rust_range( + &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. pub fn len( &self, generator: &mut G, ctx: &mut CodeGenContext<'ctx, '_>, ) -> Instance<'ctx, Int> { - let (start, stop, step) = self.instance.destructure(generator, ctx); - assert_range_step_non_zero(generator, ctx, step.value); - call_nac3_range_len_i32(generator, ctx, start, stop, step) + let range = self.as_rust_range(generator, ctx); + range.assert_step_non_zero(generator, ctx); + range.len(generator, ctx) } }