@@ -140,7 +140,7 @@ pub fn exec_mul(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) {
140140}
141141
142142/// DIV: R[A] = R[B] / R[C]
143- /// Division always returns float in Lua
143+ /// OPTIMIZED: If both are integers and division is exact, return integer
144144pub fn exec_div ( vm : & mut LuaVM , instr : u32 , pc : & mut usize , base_ptr : usize ) {
145145 let a = Instruction :: get_a ( instr) as usize ;
146146 let b = Instruction :: get_b ( instr) as usize ;
@@ -151,6 +151,21 @@ pub fn exec_div(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) {
151151 let left = * reg_base. add ( b) ;
152152 let right = * reg_base. add ( c) ;
153153
154+ let combined_tags = ( left. primary | right. primary ) & TYPE_MASK ;
155+
156+ // Fast path: both integers - check if division is exact
157+ if combined_tags == TAG_INTEGER {
158+ let l = left. secondary as i64 ;
159+ let r = right. secondary as i64 ;
160+ if r != 0 && l % r == 0 {
161+ // Exact division - return integer
162+ * vm. register_stack . as_mut_ptr ( ) . add ( base_ptr + a) = LuaValue :: integer ( l / r) ;
163+ * pc += 1 ;
164+ return ;
165+ }
166+ }
167+
168+ // Slow path: convert to float
154169 let left_tag = left. primary & TYPE_MASK ;
155170 let right_tag = right. primary & TYPE_MASK ;
156171
@@ -224,6 +239,7 @@ pub fn exec_idiv(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) {
224239}
225240
226241/// MOD: R[A] = R[B] % R[C]
242+ /// OPTIMIZED: Returns integer when both operands are integers
227243pub fn exec_mod ( vm : & mut LuaVM , instr : u32 , pc : & mut usize , base_ptr : usize ) {
228244 let a = Instruction :: get_a ( instr) as usize ;
229245 let b = Instruction :: get_b ( instr) as usize ;
@@ -242,6 +258,7 @@ pub fn exec_mod(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) {
242258 return ; // Mod by zero - let MMBIN handle
243259 }
244260 let l = left. secondary as i64 ;
261+ // Integer modulo always returns integer
245262 LuaValue :: integer ( l. rem_euclid ( r) )
246263 } else {
247264 let left_tag = left. primary & TYPE_MASK ;
@@ -263,8 +280,14 @@ pub fn exec_mod(vm: &mut LuaVM, instr: u32, pc: &mut usize, base_ptr: usize) {
263280 return ;
264281 } ;
265282
266- let result = l_float - ( l_float / r_float) . floor ( ) * r_float;
267- LuaValue :: number ( result)
283+ let float_result = l_float - ( l_float / r_float) . floor ( ) * r_float;
284+ // Check if result is an integer
285+ if float_result. fract ( ) == 0.0 && float_result. is_finite ( )
286+ && float_result >= i64:: MIN as f64 && float_result <= i64:: MAX as f64 {
287+ LuaValue :: integer ( float_result as i64 )
288+ } else {
289+ LuaValue :: number ( float_result)
290+ }
268291 } ;
269292
270293 * vm. register_stack . as_mut_ptr ( ) . add ( base_ptr + a) = result;
@@ -525,7 +548,7 @@ pub fn exec_mulk(
525548}
526549
527550/// MODK: R[A] = R[B] % K[C]
528- /// OPTIMIZED: Uses cached constants_ptr for direct constant access
551+ /// OPTIMIZED: Returns integer when result is integer
529552#[ inline( always) ]
530553pub fn exec_modk (
531554 vm : & mut LuaVM ,
@@ -540,11 +563,9 @@ pub fn exec_modk(
540563
541564 unsafe {
542565 let left = * vm. register_stack . as_ptr ( ) . add ( base_ptr + b) ;
543-
544- // FAST PATH: Direct constant access via cached pointer
545566 let constant = * ( * frame_ptr) . constants_ptr . add ( c) ;
546567
547- // Integer % Integer fast path
568+ // Integer % Integer fast path - always returns integer
548569 if left. primary == TAG_INTEGER && constant. primary == TAG_INTEGER {
549570 let r = constant. secondary as i64 ;
550571 if r == 0 {
@@ -559,10 +580,15 @@ pub fn exec_modk(
559580 return ;
560581 }
561582
562- // Float % Float
583+ // Float % Float - check if result is integer
563584 if let ( Some ( l) , Some ( r) ) = ( left. as_number ( ) , constant. as_number ( ) ) {
564- let result = l - ( l / r) . floor ( ) * r;
565- * vm. register_stack . as_mut_ptr ( ) . add ( base_ptr + a) = LuaValue :: number ( result) ;
585+ let float_result = l - ( l / r) . floor ( ) * r;
586+ if float_result. fract ( ) == 0.0 && float_result. is_finite ( )
587+ && float_result >= i64:: MIN as f64 && float_result <= i64:: MAX as f64 {
588+ * vm. register_stack . as_mut_ptr ( ) . add ( base_ptr + a) = LuaValue :: integer ( float_result as i64 ) ;
589+ } else {
590+ * vm. register_stack . as_mut_ptr ( ) . add ( base_ptr + a) = LuaValue :: number ( float_result) ;
591+ }
566592 * pc += 1 ;
567593 }
568594 }
@@ -603,7 +629,7 @@ pub fn exec_powk(
603629}
604630
605631/// DIVK: R[A] = R[B] / K[C]
606- /// OPTIMIZED: Uses cached constants_ptr for direct constant access
632+ /// OPTIMIZED: Returns integer when division is exact
607633#[ inline( always) ]
608634pub fn exec_divk (
609635 vm : & mut LuaVM ,
@@ -618,10 +644,19 @@ pub fn exec_divk(
618644
619645 unsafe {
620646 let left = * vm. register_stack . as_ptr ( ) . add ( base_ptr + b) ;
621-
622- // FAST PATH: Direct constant access via cached pointer
623647 let constant = * ( * frame_ptr) . constants_ptr . add ( c) ;
624648
649+ // Fast path: both integers - check if division is exact
650+ if left. primary == TAG_INTEGER && constant. primary == TAG_INTEGER {
651+ let l = left. secondary as i64 ;
652+ let r = constant. secondary as i64 ;
653+ if r != 0 && l % r == 0 {
654+ * vm. register_stack . as_mut_ptr ( ) . add ( base_ptr + a) = LuaValue :: integer ( l / r) ;
655+ * pc += 1 ;
656+ return ;
657+ }
658+ }
659+
625660 let l_float = match left. as_number ( ) {
626661 Some ( n) => n,
627662 None => return ,
0 commit comments