21
21
RType , RInstance , RTuple , RArray , RVoid , is_bool_rprimitive , is_int_rprimitive ,
22
22
is_short_int_rprimitive , is_none_rprimitive , object_rprimitive , bool_rprimitive ,
23
23
short_int_rprimitive , int_rprimitive , void_rtype , pointer_rprimitive , is_pointer_rprimitive ,
24
- bit_rprimitive , is_bit_rprimitive
24
+ bit_rprimitive , is_bit_rprimitive , is_fixed_width_rtype
25
25
)
26
26
27
27
if TYPE_CHECKING :
@@ -90,6 +90,9 @@ def terminator(self) -> 'ControlOp':
90
90
ERR_FALSE : Final = 2
91
91
# Always fails
92
92
ERR_ALWAYS : Final = 3
93
+ # Like ERR_MAGIC, but the magic return overlaps with a possible return value, and
94
+ # an extra PyErr_Occurred() check is also required
95
+ ERR_MAGIC_OVERLAPPING : Final = 4
93
96
94
97
# Hack: using this line number for an op will suppress it in tracebacks
95
98
NO_TRACEBACK_LINE_NO = - 10000
@@ -489,14 +492,17 @@ class Call(RegisterOp):
489
492
The call target can be a module-level function or a class.
490
493
"""
491
494
492
- error_kind = ERR_MAGIC
493
-
494
495
def __init__ (self , fn : 'FuncDecl' , args : Sequence [Value ], line : int ) -> None :
495
- super ().__init__ (line )
496
496
self .fn = fn
497
497
self .args = list (args )
498
498
assert len (self .args ) == len (fn .sig .args )
499
499
self .type = fn .sig .ret_type
500
+ ret_type = fn .sig .ret_type
501
+ if not ret_type .error_overlap :
502
+ self .error_kind = ERR_MAGIC
503
+ else :
504
+ self .error_kind = ERR_MAGIC_OVERLAPPING
505
+ super ().__init__ (line )
500
506
501
507
def sources (self ) -> List [Value ]:
502
508
return list (self .args [:])
@@ -508,14 +514,11 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
508
514
class MethodCall (RegisterOp ):
509
515
"""Native method call obj.method(arg, ...)"""
510
516
511
- error_kind = ERR_MAGIC
512
-
513
517
def __init__ (self ,
514
518
obj : Value ,
515
519
method : str ,
516
520
args : List [Value ],
517
521
line : int = - 1 ) -> None :
518
- super ().__init__ (line )
519
522
self .obj = obj
520
523
self .method = method
521
524
self .args = args
@@ -524,7 +527,13 @@ def __init__(self,
524
527
method_ir = self .receiver_type .class_ir .method_sig (method )
525
528
assert method_ir is not None , "{} doesn't have method {}" .format (
526
529
self .receiver_type .name , method )
527
- self .type = method_ir .ret_type
530
+ ret_type = method_ir .ret_type
531
+ self .type = ret_type
532
+ if not ret_type .error_overlap :
533
+ self .error_kind = ERR_MAGIC
534
+ else :
535
+ self .error_kind = ERR_MAGIC_OVERLAPPING
536
+ super ().__init__ (line )
528
537
529
538
def sources (self ) -> List [Value ]:
530
539
return self .args [:] + [self .obj ]
@@ -605,8 +614,11 @@ def __init__(self, obj: Value, attr: str, line: int, *, borrow: bool = False) ->
605
614
self .attr = attr
606
615
assert isinstance (obj .type , RInstance ), 'Attribute access not supported: %s' % obj .type
607
616
self .class_type = obj .type
608
- self .type = obj .type .attr_type (attr )
609
- self .is_borrowed = borrow
617
+ attr_type = obj .type .attr_type (attr )
618
+ self .type = attr_type
619
+ if is_fixed_width_rtype (attr_type ):
620
+ self .error_kind = ERR_NEVER
621
+ self .is_borrowed = borrow and attr_type .is_refcounted
610
622
611
623
def sources (self ) -> List [Value ]:
612
624
return [self .obj ]
@@ -829,12 +841,14 @@ class Unbox(RegisterOp):
829
841
representation. Only supported for types with an unboxed representation.
830
842
"""
831
843
832
- error_kind = ERR_MAGIC
833
-
834
844
def __init__ (self , src : Value , typ : RType , line : int ) -> None :
835
- super ().__init__ (line )
836
845
self .src = src
837
846
self .type = typ
847
+ if not typ .error_overlap :
848
+ self .error_kind = ERR_MAGIC
849
+ else :
850
+ self .error_kind = ERR_MAGIC_OVERLAPPING
851
+ super ().__init__ (line )
838
852
839
853
def sources (self ) -> List [Value ]:
840
854
return [self .src ]
@@ -924,22 +938,20 @@ class Truncate(RegisterOp):
924
938
925
939
Truncate a value from type with more bits to type with less bits.
926
940
927
- Both src_type and dst_type should be non-reference counted integer
928
- types or bool. Note that int_rprimitive is reference counted so
929
- it should never be used here.
941
+ dst_type and src_type can be native integer types, bools or tagged
942
+ integers. Tagged integers should have the tag bit unset.
930
943
"""
931
944
932
945
error_kind = ERR_NEVER
933
946
934
947
def __init__ (self ,
935
948
src : Value ,
936
- src_type : RType ,
937
949
dst_type : RType ,
938
950
line : int = - 1 ) -> None :
939
951
super ().__init__ (line )
940
952
self .src = src
941
- self .src_type = src_type
942
953
self .type = dst_type
954
+ self .src_type = src .type
943
955
944
956
def sources (self ) -> List [Value ]:
945
957
return [self .src ]
@@ -951,6 +963,41 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
951
963
return visitor .visit_truncate (self )
952
964
953
965
966
+ class Extend (RegisterOp ):
967
+ """result = extend src from src_type to dst_type
968
+
969
+ Extend a value from a type with fewer bits to a type with more bits.
970
+
971
+ dst_type and src_type can be native integer types, bools or tagged
972
+ integers. Tagged integers should have the tag bit unset.
973
+
974
+ If 'signed' is true, perform sign extension. Otherwise, the result will be
975
+ zero extended.
976
+ """
977
+
978
+ error_kind = ERR_NEVER
979
+
980
+ def __init__ (self ,
981
+ src : Value ,
982
+ dst_type : RType ,
983
+ signed : bool ,
984
+ line : int = - 1 ) -> None :
985
+ super ().__init__ (line )
986
+ self .src = src
987
+ self .type = dst_type
988
+ self .src_type = src .type
989
+ self .signed = signed
990
+
991
+ def sources (self ) -> List [Value ]:
992
+ return [self .src ]
993
+
994
+ def stolen (self ) -> List [Value ]:
995
+ return []
996
+
997
+ def accept (self , visitor : 'OpVisitor[T]' ) -> T :
998
+ return visitor .visit_extend (self )
999
+
1000
+
954
1001
class LoadGlobal (RegisterOp ):
955
1002
"""Load a low-level global variable/pointer.
956
1003
@@ -1035,6 +1082,11 @@ def accept(self, visitor: 'OpVisitor[T]') -> T:
1035
1082
return visitor .visit_int_op (self )
1036
1083
1037
1084
1085
+ # We can't have this in the IntOp class body, because of
1086
+ # https://github.com/mypyc/mypyc/issues/932.
1087
+ int_op_to_id : Final = {op : op_id for op_id , op in IntOp .op_str .items ()}
1088
+
1089
+
1038
1090
class ComparisonOp (RegisterOp ):
1039
1091
"""Low-level comparison op for integers and pointers.
1040
1092
@@ -1076,6 +1128,15 @@ class ComparisonOp(RegisterOp):
1076
1128
UGE : '>=' ,
1077
1129
}
1078
1130
1131
+ signed_ops : Final = {
1132
+ '==' : EQ ,
1133
+ '!=' : NEQ ,
1134
+ '<' : SLT ,
1135
+ '>' : SGT ,
1136
+ '<=' : SLE ,
1137
+ '>=' : SGE ,
1138
+ }
1139
+
1079
1140
def __init__ (self , lhs : Value , rhs : Value , op : int , line : int = - 1 ) -> None :
1080
1141
super ().__init__ (line )
1081
1142
self .type = bit_rprimitive
@@ -1327,6 +1388,10 @@ def visit_call_c(self, op: CallC) -> T:
1327
1388
def visit_truncate (self , op : Truncate ) -> T :
1328
1389
raise NotImplementedError
1329
1390
1391
+ @abstractmethod
1392
+ def visit_extend (self , op : Extend ) -> T :
1393
+ raise NotImplementedError
1394
+
1330
1395
@abstractmethod
1331
1396
def visit_load_global (self , op : LoadGlobal ) -> T :
1332
1397
raise NotImplementedError
0 commit comments