@@ -75,6 +75,17 @@ impl std::fmt::Debug for Op {
7575 Self :: CAR_LAST => write ! ( f, "CarLast({}, {})" , self . a( ) , self . b( ) ) ,
7676 Self :: CDR_LAST => write ! ( f, "CdrLast({}, {})" , self . a( ) , self . b( ) ) ,
7777 Self :: CONS_MOVE => write ! ( f, "ConsMove({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
78+ Self :: ADD_INT => write ! ( f, "AddInt({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
79+ Self :: SUB_INT => write ! ( f, "SubInt({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
80+ Self :: MUL_INT => write ! ( f, "MulInt({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
81+ Self :: ADD_INT_IMM => write ! ( f, "AddIntImm({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) as i8 ) ,
82+ Self :: SUB_INT_IMM => write ! ( f, "SubIntImm({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) as i8 ) ,
83+ Self :: LT_INT => write ! ( f, "LtInt({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
84+ Self :: LE_INT => write ! ( f, "LeInt({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
85+ Self :: GT_INT => write ! ( f, "GtInt({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
86+ Self :: GE_INT => write ! ( f, "GeInt({}, {}, {})" , self . a( ) , self . b( ) , self . c( ) ) ,
87+ Self :: JUMP_IF_LE_INT_IMM => write ! ( f, "JumpIfLeIntImm({}, {}, {})" , self . a( ) , self . b( ) as i8 , self . c( ) as i8 ) ,
88+ Self :: JUMP_IF_GT_INT_IMM => write ! ( f, "JumpIfGtIntImm({}, {}, {})" , self . a( ) , self . b( ) as i8 , self . c( ) as i8 ) ,
7889 _ => write ! ( f, "Unknown(0x{:08x})" , self . 0 ) ,
7990 }
8091 }
@@ -146,6 +157,21 @@ impl Op {
146157 // If B & 0x80, move from car register (B & 0x7F); if C & 0x80, move from cdr register (C & 0x7F)
147158 pub const CONS_MOVE : u8 = 54 ; // ABC: dest, car|0x80?, cdr|0x80? - cons with optional moves
148159
160+ // Unboxed integer opcodes - skip type checking for known integer operands
161+ // These are emitted when the compiler can prove both operands are integers
162+ pub const ADD_INT : u8 = 55 ; // ABC: dest, left, right - integer add (no type check)
163+ pub const SUB_INT : u8 = 56 ; // ABC: dest, left, right - integer sub (no type check)
164+ pub const MUL_INT : u8 = 57 ; // ABC: dest, left, right - integer mul (no type check)
165+ pub const ADD_INT_IMM : u8 = 58 ; // ABC: dest, src, imm (C is i8) - integer add immediate
166+ pub const SUB_INT_IMM : u8 = 59 ; // ABC: dest, src, imm (C is i8) - integer sub immediate
167+ pub const LT_INT : u8 = 60 ; // ABC: dest, left, right - integer less than
168+ pub const LE_INT : u8 = 61 ; // ABC: dest, left, right - integer less or equal
169+ pub const GT_INT : u8 = 62 ; // ABC: dest, left, right - integer greater than
170+ pub const GE_INT : u8 = 63 ; // ABC: dest, left, right - integer greater or equal
171+ // Combined compare-and-jump for integers (most common loop pattern)
172+ pub const JUMP_IF_LE_INT_IMM : u8 = 64 ; // ABC: src, imm (i8), offset (i8) - jump if src <= imm
173+ pub const JUMP_IF_GT_INT_IMM : u8 = 65 ; // ABC: src, imm (i8), offset (i8) - jump if src > imm (for opposite)
174+
149175 // ========== Constructors ==========
150176
151177 /// Create ABC format instruction: [opcode:8][A:8][B:8][C:8]
@@ -497,6 +523,63 @@ impl Op {
497523 Self :: abc ( Self :: CONS_MOVE , dest, car_with_flag, cdr_with_flag)
498524 }
499525
526+ // ========== Unboxed integer opcodes ==========
527+
528+ #[ inline( always) ]
529+ pub const fn add_int ( dest : Reg , left : Reg , right : Reg ) -> Self {
530+ Self :: abc ( Self :: ADD_INT , dest, left, right)
531+ }
532+
533+ #[ inline( always) ]
534+ pub const fn sub_int ( dest : Reg , left : Reg , right : Reg ) -> Self {
535+ Self :: abc ( Self :: SUB_INT , dest, left, right)
536+ }
537+
538+ #[ inline( always) ]
539+ pub const fn mul_int ( dest : Reg , left : Reg , right : Reg ) -> Self {
540+ Self :: abc ( Self :: MUL_INT , dest, left, right)
541+ }
542+
543+ #[ inline( always) ]
544+ pub const fn add_int_imm ( dest : Reg , src : Reg , imm : i8 ) -> Self {
545+ Self :: abc ( Self :: ADD_INT_IMM , dest, src, imm as u8 )
546+ }
547+
548+ #[ inline( always) ]
549+ pub const fn sub_int_imm ( dest : Reg , src : Reg , imm : i8 ) -> Self {
550+ Self :: abc ( Self :: SUB_INT_IMM , dest, src, imm as u8 )
551+ }
552+
553+ #[ inline( always) ]
554+ pub const fn lt_int ( dest : Reg , left : Reg , right : Reg ) -> Self {
555+ Self :: abc ( Self :: LT_INT , dest, left, right)
556+ }
557+
558+ #[ inline( always) ]
559+ pub const fn le_int ( dest : Reg , left : Reg , right : Reg ) -> Self {
560+ Self :: abc ( Self :: LE_INT , dest, left, right)
561+ }
562+
563+ #[ inline( always) ]
564+ pub const fn gt_int ( dest : Reg , left : Reg , right : Reg ) -> Self {
565+ Self :: abc ( Self :: GT_INT , dest, left, right)
566+ }
567+
568+ #[ inline( always) ]
569+ pub const fn ge_int ( dest : Reg , left : Reg , right : Reg ) -> Self {
570+ Self :: abc ( Self :: GE_INT , dest, left, right)
571+ }
572+
573+ #[ inline( always) ]
574+ pub const fn jump_if_le_int_imm ( src : Reg , imm : i8 , offset : i8 ) -> Self {
575+ Self :: abc ( Self :: JUMP_IF_LE_INT_IMM , src, imm as u8 , offset as u8 )
576+ }
577+
578+ #[ inline( always) ]
579+ pub const fn jump_if_gt_int_imm ( src : Reg , imm : i8 , offset : i8 ) -> Self {
580+ Self :: abc ( Self :: JUMP_IF_GT_INT_IMM , src, imm as u8 , offset as u8 )
581+ }
582+
500583 // ========== Jump patching helpers ==========
501584
502585 /// Check if this is a jump instruction (for patching)
@@ -509,6 +592,7 @@ impl Op {
509592 || op == Self :: JUMP_IF_LT_IMM || op == Self :: JUMP_IF_LE_IMM
510593 || op == Self :: JUMP_IF_GT_IMM || op == Self :: JUMP_IF_GE_IMM
511594 || op == Self :: JUMP_IF_NIL || op == Self :: JUMP_IF_NOT_NIL
595+ || op == Self :: JUMP_IF_LE_INT_IMM || op == Self :: JUMP_IF_GT_INT_IMM
512596 }
513597
514598 /// Patch the offset of a jump instruction
@@ -586,7 +670,8 @@ impl Chunk {
586670 if target < self . code . len ( ) {
587671 jump_targets[ target] = true ;
588672 }
589- } else if opcode >= Op :: JUMP_IF_LT && opcode <= Op :: JUMP_IF_GE_IMM {
673+ } else if ( opcode >= Op :: JUMP_IF_LT && opcode <= Op :: JUMP_IF_GE_IMM )
674+ || opcode == Op :: JUMP_IF_LE_INT_IMM || opcode == Op :: JUMP_IF_GT_INT_IMM {
590675 // These use i8 offset in C byte
591676 let offset = op. c ( ) as i8 as isize ;
592677 let target = ( i as isize + 1 + offset) as usize ;
@@ -613,9 +698,15 @@ impl Chunk {
613698 ever_live |= 1u128 << op. c ( ) ;
614699 }
615700 Op :: ADD_IMM | Op :: SUB_IMM |
616- Op :: LT_IMM | Op :: LE_IMM | Op :: GT_IMM | Op :: GE_IMM => {
701+ Op :: LT_IMM | Op :: LE_IMM | Op :: GT_IMM | Op :: GE_IMM |
702+ Op :: ADD_INT_IMM | Op :: SUB_INT_IMM => {
617703 ever_live |= 1u128 << op. b ( ) ;
618704 }
705+ Op :: ADD_INT | Op :: SUB_INT | Op :: MUL_INT |
706+ Op :: LT_INT | Op :: LE_INT | Op :: GT_INT | Op :: GE_INT => {
707+ ever_live |= 1u128 << op. b ( ) ;
708+ ever_live |= 1u128 << op. c ( ) ;
709+ }
619710 Op :: SET_GLOBAL | Op :: RETURN => {
620711 ever_live |= 1u128 << op. a ( ) ;
621712 }
@@ -628,7 +719,8 @@ impl Chunk {
628719 ever_live |= 1u128 << op. b ( ) ;
629720 }
630721 Op :: JUMP_IF_LT_IMM | Op :: JUMP_IF_LE_IMM |
631- Op :: JUMP_IF_GT_IMM | Op :: JUMP_IF_GE_IMM => {
722+ Op :: JUMP_IF_GT_IMM | Op :: JUMP_IF_GE_IMM |
723+ Op :: JUMP_IF_LE_INT_IMM | Op :: JUMP_IF_GT_INT_IMM => {
632724 ever_live |= 1u128 << op. a ( ) ;
633725 }
634726 _ => { }
@@ -717,7 +809,9 @@ impl Chunk {
717809 // ===== ABC-format arithmetic/comparison (read B, C; write A) =====
718810
719811 Op :: ADD | Op :: SUB | Op :: MUL | Op :: DIV | Op :: MOD |
720- Op :: LT | Op :: LE | Op :: GT | Op :: GE | Op :: EQ | Op :: NE => {
812+ Op :: LT | Op :: LE | Op :: GT | Op :: GE | Op :: EQ | Op :: NE |
813+ Op :: ADD_INT | Op :: SUB_INT | Op :: MUL_INT |
814+ Op :: LT_INT | Op :: LE_INT | Op :: GT_INT | Op :: GE_INT => {
721815 let dest = op. a ( ) ;
722816 let b = op. b ( ) ;
723817 let c = op. c ( ) ;
@@ -729,7 +823,8 @@ impl Chunk {
729823 // ===== Immediate variants (read B only) =====
730824
731825 Op :: ADD_IMM | Op :: SUB_IMM |
732- Op :: LT_IMM | Op :: LE_IMM | Op :: GT_IMM | Op :: GE_IMM => {
826+ Op :: LT_IMM | Op :: LE_IMM | Op :: GT_IMM | Op :: GE_IMM |
827+ Op :: ADD_INT_IMM | Op :: SUB_INT_IMM => {
733828 let dest = op. a ( ) ;
734829 let src = op. b ( ) ;
735830 live &= !( 1u128 << dest) ;
@@ -773,7 +868,8 @@ impl Chunk {
773868 }
774869
775870 Op :: JUMP_IF_LT_IMM | Op :: JUMP_IF_LE_IMM |
776- Op :: JUMP_IF_GT_IMM | Op :: JUMP_IF_GE_IMM => {
871+ Op :: JUMP_IF_GT_IMM | Op :: JUMP_IF_GE_IMM |
872+ Op :: JUMP_IF_LE_INT_IMM | Op :: JUMP_IF_GT_INT_IMM => {
777873 let src = op. a ( ) ;
778874 live |= 1u128 << src;
779875 }
0 commit comments