1+ // instructions.rs
12// spell-checker: disable
23use super :: { JitCompileError , JitSig , JitType } ;
34use alloc:: collections:: BTreeSet ;
5+ use alloc:: rc:: Rc ;
46use cranelift:: codegen:: ir:: FuncRef ;
57use cranelift:: prelude:: * ;
68use num_traits:: cast:: ToPrimitive ;
@@ -15,26 +17,37 @@ enum CustomTrapCode {
1517 /// Raised when shifting by a negative number
1618 NegativeShiftCount = 1 ,
1719}
18-
20+ #[ derive( Debug ) ]
21+ enum ObjectKind {
22+ Opaque ,
23+ Tuple ( Rc < TupleShape > ) ,
24+ }
25+ #[ derive( Debug ) ]
26+ enum ElementShape {
27+ Scalar ( JitType ) ,
28+ Object ( Rc < ObjectKind > ) ,
29+ }
30+ #[ derive( Debug ) ]
31+ struct TupleShape ( Vec < ElementShape > ) ;
1932#[ derive( Clone ) ]
2033enum Local {
2134 Scalar {
2235 var : Variable ,
2336 ty : JitType ,
2437 } ,
25- Tuple {
26- elements : Vec < Local > ,
27- } ,
38+ Object {
39+ var : Variable ,
40+ kind : Rc < ObjectKind > ,
41+ }
2842}
29-
3043#[ derive( Debug ) ]
3144enum JitValue {
3245 Int ( Value ) ,
3346 Float ( Value ) ,
3447 Bool ( Value ) ,
3548 None ,
3649 Null ,
37- Tuple ( Vec < Self > ) ,
50+ Object ( Value , Rc < ObjectKind > ) ,
3851 FuncRef ( FuncRef ) ,
3952}
4053
@@ -44,6 +57,7 @@ impl JitValue {
4457 JitType :: Int => Self :: Int ( val) ,
4558 JitType :: Float => Self :: Float ( val) ,
4659 JitType :: Bool => Self :: Bool ( val) ,
60+ JitType :: Object => Self :: Object ( val, Rc :: new ( ObjectKind :: Opaque ) ) ,
4761 }
4862 }
4963
@@ -52,14 +66,16 @@ impl JitValue {
5266 Self :: Int ( _) => Some ( JitType :: Int ) ,
5367 Self :: Float ( _) => Some ( JitType :: Float ) ,
5468 Self :: Bool ( _) => Some ( JitType :: Bool ) ,
55- Self :: None | Self :: Null | Self :: Tuple ( _) | Self :: FuncRef ( _) => None ,
69+ Self :: Object ( _, _) => Some ( JitType :: Object ) ,
70+ Self :: None | Self :: Null | Self :: FuncRef ( _) => None ,
5671 }
5772 }
5873
5974 fn into_value ( self ) -> Option < Value > {
6075 match self {
6176 Self :: Int ( val) | Self :: Float ( val) | Self :: Bool ( val) => Some ( val) ,
62- Self :: None | Self :: Null | Self :: Tuple ( _) | Self :: FuncRef ( _) => None ,
77+ Self :: Object ( val, _) => Some ( val) ,
78+ Self :: None | Self :: Null | Self :: FuncRef ( _) => None ,
6379 }
6480 }
6581}
@@ -75,17 +91,17 @@ pub(crate) struct FunctionCompiler<'a, 'b> {
7591 stack : Vec < JitValue > ,
7692 variables : Box < [ Option < Local > ] > ,
7793 label_to_block : HashMap < Label , Block > ,
78- tuple_pool : Vec < Vec < JitValue > > ,
94+ alloc_func : FuncRef ,
7995 pub ( crate ) sig : JitSig ,
8096}
81-
8297impl < ' a , ' b > FunctionCompiler < ' a , ' b > {
8398 pub ( crate ) fn new (
8499 builder : & ' a mut FunctionBuilder < ' b > ,
85100 num_variables : usize ,
86101 arg_types : & [ JitType ] ,
87102 ret_type : Option < JitType > ,
88103 entry_block : Block ,
104+ alloc_func : FuncRef ,
89105 ) -> Self {
90106 let mut compiler = Self {
91107 builder,
@@ -96,7 +112,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
96112 args : arg_types. to_vec ( ) ,
97113 ret : ret_type,
98114 } ,
99- tuple_pool : Vec :: new ( ) ,
115+ alloc_func ,
100116 } ;
101117 let params = compiler. builder . func . dfg . block_params ( entry_block) . to_vec ( ) ;
102118 for ( i, ( ty, val) ) in arg_types. iter ( ) . zip ( params) . enumerate ( ) {
@@ -120,12 +136,10 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
120136 value : JitValue ,
121137 ) -> Result < Local , JitCompileError > {
122138 match value {
123- JitValue :: Tuple ( elements) => {
124- let mut locals = Vec :: with_capacity ( elements. len ( ) ) ;
125- for element in elements {
126- locals. push ( Self :: local_from_value ( builder, element) ?) ;
127- }
128- Ok ( Local :: Tuple { elements : locals } )
139+ JitValue :: Object ( ptr, kind) => {
140+ let var = builder. declare_var ( types:: I64 ) ;
141+ builder. def_var ( var, ptr) ;
142+ Ok ( Local :: Object { var, kind } )
129143 }
130144
131145 scalar => {
@@ -144,26 +158,16 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
144158 ty. clone ( ) ,
145159 builder. use_var ( * var) ,
146160 ) ) ,
147- Local :: Tuple { elements } => {
148- let mut values = Vec :: with_capacity ( elements. len ( ) ) ;
149- for element in elements {
150- values. push ( Self :: local_to_value ( builder, element) ?) ;
151- }
152- Ok ( JitValue :: Tuple ( values) )
153- }
161+ Local :: Object { var, kind } => Ok ( JitValue :: Object ( builder. use_var ( * var) , kind. clone ( ) ) ) ,
154162 }
155163 }
156-
157164 fn store_variable ( & mut self , idx : oparg:: VarNum , val : JitValue ) -> Result < ( ) , JitCompileError > {
158165 #[ expect( clippy:: mut_mut, reason = "This seems like a false positive" ) ]
159166 let builder = & mut self . builder ;
160-
161167 let local = Self :: local_from_value ( builder, val) ?;
162168 self . variables [ idx] = Some ( local) ;
163-
164169 Ok ( ( ) )
165170 }
166-
167171 fn boolean_val ( & mut self , val : JitValue ) -> Result < Value , JitCompileError > {
168172 match val {
169173 JitValue :: Float ( val) => {
@@ -178,8 +182,8 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
178182 }
179183 JitValue :: Bool ( val) => Ok ( val) ,
180184 JitValue :: None => Ok ( self . builder . ins ( ) . iconst ( types:: I8 , 0 ) ) ,
181- JitValue :: Null | JitValue :: Tuple ( _) | JitValue :: FuncRef ( _) => {
182- Err ( JitCompileError :: NotSupported )
185+ JitValue :: Null | JitValue :: FuncRef ( _) | JitValue :: Object ( _ , _) => {
186+ Err ( JitCompileError :: NotSupported )
183187 }
184188 }
185189 }
@@ -279,7 +283,6 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
279283 if label_targets. contains ( & label) {
280284 // Create or get the block for this label:
281285 let target_block = self . get_or_create_block ( label) ;
282-
283286 // If the current block isn't terminated, add a fallthrough jump
284287 if let Some ( cur) = self . builder . current_block ( )
285288 && cur != target_block
@@ -360,41 +363,75 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
360363 }
361364 BorrowedConstant :: Tuple { elements } => {
362365 let mut vals = Vec :: new ( ) ;
363-
364366 for el in elements {
365367 let b = el. borrow_constant ( ) ;
366368 let res = self . prepare_const ( b) ?;
367369 vals. push ( res) ;
368370 }
369-
370- JitValue :: Tuple ( vals )
371+ let ( ptr , shape ) = self . build_heap_tuple ( vals ) ? ;
372+ JitValue :: Object ( ptr , Rc :: new ( ObjectKind :: Tuple ( shape ) ) )
371373 }
372374 BorrowedConstant :: None => JitValue :: None ,
373375 _ => return Err ( JitCompileError :: NotSupported ) ,
374376 } ;
375377 Ok ( value)
376378 }
377-
378- fn tuple_alloc ( & mut self , elements : Vec < JitValue > ) -> Value {
379- let idx = self . tuple_pool . len ( ) ;
380- self . tuple_pool . push ( elements) ;
381-
382- let ptr_val = self . builder . ins ( ) . iconst ( types:: I64 , idx as i64 ) ;
383- ptr_val
379+ fn build_heap_tuple ( & mut self , elements : Vec < JitValue > ) -> Result < ( Value , Rc < TupleShape > ) , JitCompileError > {
380+ let len_val = self . builder . ins ( ) . iconst ( types:: I64 , elements. len ( ) as i64 ) ;
381+ let call = self . builder . ins ( ) . call ( self . alloc_func , & [ len_val] ) ;
382+ let ptr = self . builder . inst_results ( call) [ 0 ] ;
383+ let mut shape = Vec :: with_capacity ( elements. len ( ) ) ;
384+ for ( i, element) in elements. into_iter ( ) . enumerate ( ) {
385+ let offset = 8 + 8 * i as i32 ;
386+ match element {
387+ JitValue :: Object ( val, kind) => {
388+ self . builder . ins ( ) . store ( MemFlags :: new ( ) , val, ptr, offset) ;
389+ shape. push ( ElementShape :: Object ( kind) ) ;
390+ }
391+ scalar => {
392+ let ty = scalar. to_jit_type ( ) . ok_or ( JitCompileError :: NotSupported ) ?;
393+ let val = scalar. into_value ( ) . unwrap ( ) ;
394+ self . builder . ins ( ) . store ( MemFlags :: new ( ) , val, ptr, offset) ;
395+ shape. push ( ElementShape :: Scalar ( ty) ) ;
396+ }
397+ }
398+ }
399+ Ok ( ( ptr, Rc :: new ( TupleShape ( shape) ) ) )
400+ }
401+ fn unpack_heap_tuple ( & mut self , ptr : Value , shape : & TupleShape ) -> Vec < JitValue > {
402+ let mut values = Vec :: with_capacity ( shape. 0 . len ( ) ) ;
403+ for ( i, element_shape) in shape. 0 . iter ( ) . enumerate ( ) {
404+ let offset = 8 + 8 * i as i32 ;
405+ let value = match element_shape {
406+ ElementShape :: Scalar ( ty) => {
407+ let val = self . builder . ins ( ) . load ( ty. to_cranelift ( ) , MemFlags :: new ( ) , ptr, offset) ;
408+ JitValue :: from_type_and_value ( ty. clone ( ) , val)
409+ }
410+ ElementShape :: Object ( kind) => {
411+ let val = self . builder . ins ( ) . load ( types:: I64 , MemFlags :: new ( ) , ptr, offset) ;
412+ JitValue :: Object ( val, kind. clone ( ) )
413+ }
414+ } ;
415+ values. push ( value) ;
416+ }
417+ values
384418 }
385-
386419 fn return_value ( & mut self , val : JitValue ) -> Result < ( ) , JitCompileError > {
387- let cr_val = match val {
388- JitValue :: Tuple ( elements) => self . tuple_alloc ( elements) ,
389- _ => val. into_value ( ) . ok_or ( JitCompileError :: NotSupported ) ?,
420+ let ( cr_val, ret_ty) = match val {
421+ JitValue :: Int ( v) => ( v, JitType :: Int ) ,
422+ JitValue :: Float ( v) => ( v, JitType :: Float ) ,
423+ JitValue :: Bool ( v) => ( v, JitType :: Bool ) ,
424+ JitValue :: Object ( p, _) => ( p, JitType :: Object ) ,
425+ //JitValue::None => (self.none_ptr(), JitType::Object),
426+ _ => return Err ( JitCompileError :: NotSupported ) ,
390427 } ;
391428
392429 // single abi type
393430 if self . sig . ret . is_none ( ) {
394- self . sig . ret = Some ( JitType :: Int ) ;
431+ self . sig . ret = Some ( ret_ty . clone ( ) ) ;
395432 self . builder . func . signature
396433 . returns
397- . push ( AbiParam :: new ( types :: I64 ) ) ;
434+ . push ( AbiParam :: new ( ret_ty . to_cranelift ( ) ) ) ;
398435 }
399436
400437 self . builder . ins ( ) . return_ ( & [ cr_val] ) ;
@@ -573,7 +610,8 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
573610 }
574611 Instruction :: BuildTuple { count } => {
575612 let elements = self . pop_multiple ( count. get ( arg) as usize ) ;
576- self . stack . push ( JitValue :: Tuple ( elements) ) ;
613+ let ( ptr, shape) = self . build_heap_tuple ( elements) ?;
614+ self . stack . push ( JitValue :: Object ( ptr, Rc :: new ( ObjectKind :: Tuple ( shape) ) ) ) ;
577615 Ok ( ( ) )
578616 }
579617 Instruction :: Call { argc } => {
@@ -584,7 +622,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
584622 let arg = self . stack . pop ( ) . ok_or ( JitCompileError :: BadBytecode ) ?;
585623 args. push ( arg. into_value ( ) . unwrap ( ) ) ;
586624 }
587-
625+
588626 // Pop self_or_null (should be Null for JIT-compiled recursive calls)
589627 let self_or_null = self . stack . pop ( ) . ok_or ( JitCompileError :: BadBytecode ) ?;
590628 if !matches ! ( self_or_null, JitValue :: Null ) {
@@ -791,17 +829,8 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
791829 let local = self . variables [ load_idx]
792830 . as_ref ( )
793831 . ok_or ( JitCompileError :: BadBytecode ) ?;
794- match local {
795- Local :: Scalar { var, ty } => {
796- self . stack . push ( JitValue :: from_type_and_value (
797- ty. clone ( ) ,
798- self . builder . use_var ( * var) ,
799- ) ) ;
800- } ,
801- Local :: Tuple { elements : _} => {
802- self . stack . push ( Self :: local_to_value ( self . builder , local) ?) ;
803- }
804- }
832+ let value = Self :: local_to_value ( self . builder , local) ?;
833+ self . stack . push ( value) ;
805834 Ok ( ( ) )
806835 }
807836 Instruction :: StoreFastStoreFast { var_nums } => {
@@ -848,23 +877,23 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
848877 }
849878 Instruction :: UnpackSequence { count } => {
850879 let val = self . stack . pop ( ) . ok_or ( JitCompileError :: BadBytecode ) ?;
851-
852- let elements = match val {
853- JitValue :: Tuple ( elements) => elements,
880+ let ( ptr, shape) = match val {
881+ JitValue :: Object ( ptr, kind) => match & * kind {
882+ ObjectKind :: Tuple ( shape) => ( ptr, shape. clone ( ) ) ,
883+ _ => return Err ( JitCompileError :: NotSupported ) ,
884+ } ,
854885 _ => return Err ( JitCompileError :: NotSupported ) ,
855886 } ;
856-
857- if elements. len ( ) != count. get ( arg) as usize {
887+ if shape. 0 . len ( ) != count. get ( arg) as usize {
858888 return Err ( JitCompileError :: NotSupported ) ;
859889 }
860-
890+ let elements = self . unpack_heap_tuple ( ptr , & shape ) ;
861891 self . stack . extend ( elements. into_iter ( ) . rev ( ) ) ;
862892 Ok ( ( ) )
863893 }
864894 _ => Err ( JitCompileError :: NotSupported ) ,
865895 }
866896 }
867-
868897 fn compile_sub ( & mut self , a : Value , b : Value ) -> Value {
869898 let ( out, carry) = self . builder . ins ( ) . ssub_overflow ( a, b) ;
870899 self . builder . ins ( ) . trapnz ( carry, TrapCode :: INTEGER_OVERFLOW ) ;
@@ -1320,6 +1349,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
13201349 self . builder . ins ( ) . jump ( merge_block, & [ nan_f. into ( ) ] ) ;
13211350
13221351 self . builder . switch_to_block ( continue_neg_inf) ;
1352+
13231353 // b is an integer here; convert b_floor to an i64.
13241354 let b_i64 = self . builder . ins ( ) . fcvt_to_sint ( i64_ty, b_floor) ;
13251355 let one_i = self . builder . ins ( ) . iconst ( i64_ty, 1 ) ;
@@ -1339,7 +1369,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
13391369 even_block,
13401370 & [ inf_f. into ( ) ] ,
13411371 ) ;
1342-
1372+
13431373 self . builder . switch_to_block ( odd_block) ;
13441374 let phi_neg_inf = self . builder . block_params ( odd_block) [ 0 ] ;
13451375 self . builder . ins ( ) . jump ( merge_block, & [ phi_neg_inf. into ( ) ] ) ;
@@ -1358,7 +1388,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
13581388 self . builder
13591389 . ins ( )
13601390 . brif ( cmp_lt, a_neg_block, & [ ] , a_pos_block, & [ ] ) ;
1361-
1391+
13621392 // ----- Case: a > 0: Compute a^b = exp(b * ln(a)) using double–double arithmetic.
13631393 self . builder . switch_to_block ( a_pos_block) ;
13641394 let ln_a_dd = self . dd_ln ( a) ;
@@ -1396,7 +1426,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
13961426 let remainder = self . builder . ins ( ) . band ( b_i64, one_i) ;
13971427 let zero_i = self . builder . ins ( ) . iconst ( i64_ty, 0 ) ;
13981428 let is_odd = self . builder . ins ( ) . icmp ( IntCC :: NotEqual , remainder, zero_i) ;
1399-
1429+
14001430 let odd_block = self . builder . create_block ( ) ;
14011431 let even_block = self . builder . create_block ( ) ;
14021432 // Append block parameters for both branches:
@@ -1512,7 +1542,7 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
15121542 let is_odd = self . builder . ins ( ) . icmp_imm ( IntCC :: Equal , is_odd, 1 ) ;
15131543 let mul_result = self . builder . ins ( ) . imul ( result_phi, base_phi) ;
15141544 let new_result = self . builder . ins ( ) . select ( is_odd, mul_result, result_phi) ;
1515-
1545+
15161546 // Square the base and divide exponent by 2
15171547 let squared_base = self . builder . ins ( ) . imul ( base_phi, base_phi) ;
15181548 let new_exp = self . builder . ins ( ) . sshr_imm ( exp_phi, 1 ) ;
@@ -1531,7 +1561,8 @@ impl<'a, 'b> FunctionCompiler<'a, 'b> {
15311561 self . builder . seal_block ( loop_block) ;
15321562 self . builder . seal_block ( continue_block) ;
15331563 self . builder . seal_block ( exit_block) ;
1534-
1564+
15351565 res
15361566 }
1537- }
1567+
1568+ }
0 commit comments