@@ -589,17 +589,21 @@ def binary_op(self,
589
589
assert target , 'Unsupported binary operation: %s' % op
590
590
return target
591
591
592
- def check_tagged_short_int (self , val : Value , line : int ) -> Value :
593
- """Check if a tagged integer is a short integer"""
592
+ def check_tagged_short_int (self , val : Value , line : int , negated : bool = False ) -> Value :
593
+ """Check if a tagged integer is a short integer.
594
+
595
+ Return the result of the check (value of type 'bit').
596
+ """
594
597
int_tag = self .add (LoadInt (1 , line , rtype = c_pyssize_t_rprimitive ))
595
598
bitwise_and = self .binary_int_op (c_pyssize_t_rprimitive , val ,
596
599
int_tag , BinaryIntOp .AND , line )
597
600
zero = self .add (LoadInt (0 , line , rtype = c_pyssize_t_rprimitive ))
598
- check = self .comparison_op (bitwise_and , zero , ComparisonOp .EQ , line )
601
+ op = ComparisonOp .NEQ if negated else ComparisonOp .EQ
602
+ check = self .comparison_op (bitwise_and , zero , op , line )
599
603
return check
600
604
601
605
def compare_tagged (self , lhs : Value , rhs : Value , op : str , line : int ) -> Value :
602
- """Compare two tagged integers using given op """
606
+ """Compare two tagged integers using given operator (value context). """
603
607
# generate fast binary logic ops on short ints
604
608
if is_short_int_rprimitive (lhs .type ) and is_short_int_rprimitive (rhs .type ):
605
609
return self .comparison_op (lhs , rhs , int_comparison_op_mapping [op ][0 ], line )
@@ -610,13 +614,11 @@ def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value:
610
614
if op in ("==" , "!=" ):
611
615
check = check_lhs
612
616
else :
613
- # for non-equal logical ops(less than, greater than, etc.), need to check both side
617
+ # for non-equality logical ops (less/ greater than, etc.), need to check both sides
614
618
check_rhs = self .check_tagged_short_int (rhs , line )
615
619
check = self .binary_int_op (bit_rprimitive , check_lhs ,
616
620
check_rhs , BinaryIntOp .AND , line )
617
- branch = Branch (check , short_int_block , int_block , Branch .BOOL )
618
- branch .negated = False
619
- self .add (branch )
621
+ self .add (Branch (check , short_int_block , int_block , Branch .BOOL ))
620
622
self .activate_block (short_int_block )
621
623
eq = self .comparison_op (lhs , rhs , op_type , line )
622
624
self .add (Assign (result , eq , line ))
@@ -636,6 +638,60 @@ def compare_tagged(self, lhs: Value, rhs: Value, op: str, line: int) -> Value:
636
638
self .goto_and_activate (out )
637
639
return result
638
640
641
+ def compare_tagged_condition (self ,
642
+ lhs : Value ,
643
+ rhs : Value ,
644
+ op : str ,
645
+ true : BasicBlock ,
646
+ false : BasicBlock ,
647
+ line : int ) -> None :
648
+ """Compare two tagged integers using given operator (conditional context).
649
+
650
+ Assume lhs and and rhs are tagged integers.
651
+
652
+ Args:
653
+ lhs: Left operand
654
+ rhs: Right operand
655
+ op: Operation, one of '==', '!=', '<', '<=', '>', '<='
656
+ true: Branch target if comparison is true
657
+ false: Branch target if comparison is false
658
+ """
659
+ is_eq = op in ("==" , "!=" )
660
+ if ((is_short_int_rprimitive (lhs .type ) and is_short_int_rprimitive (rhs .type ))
661
+ or (is_eq and (is_short_int_rprimitive (lhs .type ) or
662
+ is_short_int_rprimitive (rhs .type )))):
663
+ # We can skip the tag check
664
+ check = self .comparison_op (lhs , rhs , int_comparison_op_mapping [op ][0 ], line )
665
+ self .add (Branch (check , true , false , Branch .BOOL ))
666
+ return
667
+ op_type , c_func_desc , negate_result , swap_op = int_comparison_op_mapping [op ]
668
+ int_block , short_int_block = BasicBlock (), BasicBlock ()
669
+ check_lhs = self .check_tagged_short_int (lhs , line , negated = True )
670
+ if is_eq or is_short_int_rprimitive (rhs .type ):
671
+ self .add (Branch (check_lhs , int_block , short_int_block , Branch .BOOL ))
672
+ else :
673
+ # For non-equality logical ops (less/greater than, etc.), need to check both sides
674
+ rhs_block = BasicBlock ()
675
+ self .add (Branch (check_lhs , int_block , rhs_block , Branch .BOOL ))
676
+ self .activate_block (rhs_block )
677
+ check_rhs = self .check_tagged_short_int (rhs , line , negated = True )
678
+ self .add (Branch (check_rhs , int_block , short_int_block , Branch .BOOL ))
679
+ # Arbitrary integers (slow path)
680
+ self .activate_block (int_block )
681
+ if swap_op :
682
+ args = [rhs , lhs ]
683
+ else :
684
+ args = [lhs , rhs ]
685
+ call = self .call_c (c_func_desc , args , line )
686
+ if negate_result :
687
+ self .add (Branch (call , false , true , Branch .BOOL ))
688
+ else :
689
+ self .add (Branch (call , true , false , Branch .BOOL ))
690
+ # Short integers (fast path)
691
+ self .activate_block (short_int_block )
692
+ eq = self .comparison_op (lhs , rhs , op_type , line )
693
+ self .add (Branch (eq , true , false , Branch .BOOL ))
694
+
639
695
def compare_strings (self , lhs : Value , rhs : Value , op : str , line : int ) -> Value :
640
696
"""Compare two strings"""
641
697
compare_result = self .call_c (unicode_compare , [lhs , rhs ], line )
0 commit comments