@@ -39,16 +39,22 @@ class ARTIQIRGenerator(algorithm.Visitor):
39
39
set of variables that will be resolved in global scope
40
40
:ivar current_block: (:class:`ir.BasicBlock`)
41
41
basic block to which any new instruction will be appended
42
- :ivar current_env: (:class:`ir.Environment `)
42
+ :ivar current_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment `)
43
43
the chained function environment, containing variables that
44
44
can become upvalues
45
- :ivar current_private_env: (:class:`ir.Environment `)
45
+ :ivar current_private_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment `)
46
46
the private function environment, containing internal state
47
47
:ivar current_assign: (:class:`ir.Value` or None)
48
48
the right-hand side of current assignment statement, or
49
49
a component of a composite right-hand side when visiting
50
50
a composite left-hand side, such as, in ``x, y = z``,
51
51
the 2nd tuple element when visting ``y``
52
+ :ivar current_assert_env: (:class:`ir.Alloc` of type :class:`ir.TEnvironment`)
53
+ the environment where the individual components of current assert
54
+ statement are stored until display
55
+ :ivar current_assert_subexprs: (list of (:class:`ast.AST`, string))
56
+ the mapping from components of current assert statement to the names
57
+ their values have in :ivar:`current_assert_env`
52
58
:ivar break_target: (:class:`ir.BasicBlock` or None)
53
59
the basic block to which ``break`` will transfer control
54
60
:ivar continue_target: (:class:`ir.BasicBlock` or None)
@@ -72,6 +78,8 @@ def __init__(self, module_name, engine):
72
78
self .current_env = None
73
79
self .current_private_env = None
74
80
self .current_assign = None
81
+ self .current_assert_env = None
82
+ self .current_assert_subexprs = None
75
83
self .break_target = None
76
84
self .continue_target = None
77
85
self .return_target = None
@@ -203,7 +211,7 @@ def visit_function(self, node, is_lambda):
203
211
self .append (ir .SetLocal (env , arg_name , args [index ]))
204
212
for index , (arg_name , env_default_name ) in enumerate (zip (typ .optargs , defaults )):
205
213
default = self .append (ir .GetLocal (self .current_env , env_default_name ))
206
- value = self .append (ir .Builtin ("unwrap " , [optargs [index ], default ],
214
+ value = self .append (ir .Builtin ("unwrap_or " , [optargs [index ], default ],
207
215
typ .optargs [arg_name ]))
208
216
self .append (ir .SetLocal (env , arg_name , value ))
209
217
@@ -736,7 +744,7 @@ def visit_TupleT(self, node):
736
744
for index , elt_node in enumerate (node .elts ):
737
745
self .current_assign = \
738
746
self .append (ir .GetAttr (old_assign , index ,
739
- name = "{}.{}" .format (old_assign .name , index )),
747
+ name = "{}.e {}" .format (old_assign .name , index )),
740
748
loc = elt_node .loc )
741
749
self .visit (elt_node )
742
750
finally :
@@ -805,18 +813,26 @@ def body_gen(index):
805
813
def visit_BoolOpT (self , node ):
806
814
blocks = []
807
815
for value_node in node .values :
816
+ value_head = self .current_block
808
817
value = self .visit (value_node )
809
- blocks .append ((value , self .current_block ))
818
+ self .instrument_assert (value_node , value )
819
+ value_tail = self .current_block
820
+
821
+ blocks .append ((value , value_head , value_tail ))
810
822
self .current_block = self .add_block ()
811
823
812
824
tail = self .current_block
813
825
phi = self .append (ir .Phi (node .type ))
814
- for ((value , block ), next_block ) in zip (blocks , [b for (v ,b ) in blocks [1 :]] + [tail ]):
815
- phi .add_incoming (value , block )
816
- if isinstance (node .op , ast .And ):
817
- block .append (ir .BranchIf (value , next_block , tail ))
826
+ for ((value , value_head , value_tail ), (next_value_head , next_value_tail )) in \
827
+ zip (blocks , [(h ,t ) for (v ,h ,t ) in blocks [1 :]] + [(tail , tail )]):
828
+ phi .add_incoming (value , value_tail )
829
+ if next_value_head != tail :
830
+ if isinstance (node .op , ast .And ):
831
+ value_tail .append (ir .BranchIf (value , next_value_head , tail ))
832
+ else :
833
+ value_tail .append (ir .BranchIf (value , tail , next_value_head ))
818
834
else :
819
- block .append (ir .BranchIf ( value , tail , next_block ))
835
+ value_tail .append (ir .Branch ( tail ))
820
836
return phi
821
837
822
838
def visit_UnaryOpT (self , node ):
@@ -1005,7 +1021,7 @@ def polymorphic_compare_pair_inclusion(self, op, needle, haystack):
1005
1021
ir .Constant (False , builtins .TBool ())))
1006
1022
result = self .append (ir .Select (result , on_step ,
1007
1023
ir .Constant (False , builtins .TBool ())))
1008
- elif builtins .isiterable (haystack .type ):
1024
+ elif builtins .is_iterable (haystack .type ):
1009
1025
length = self .iterable_len (haystack )
1010
1026
1011
1027
cmp_result = loop_body2 = None
@@ -1068,8 +1084,10 @@ def visit_CompareT(self, node):
1068
1084
# of comparisons.
1069
1085
blocks = []
1070
1086
lhs = self .visit (node .left )
1087
+ self .instrument_assert (node .left , lhs )
1071
1088
for op , rhs_node in zip (node .ops , node .comparators ):
1072
1089
rhs = self .visit (rhs_node )
1090
+ self .instrument_assert (rhs_node , rhs )
1073
1091
result = self .polymorphic_compare_pair (op , lhs , rhs )
1074
1092
blocks .append ((result , self .current_block ))
1075
1093
self .current_block = self .add_block ()
@@ -1079,7 +1097,10 @@ def visit_CompareT(self, node):
1079
1097
phi = self .append (ir .Phi (node .type ))
1080
1098
for ((value , block ), next_block ) in zip (blocks , [b for (v ,b ) in blocks [1 :]] + [tail ]):
1081
1099
phi .add_incoming (value , block )
1082
- block .append (ir .BranchIf (value , next_block , tail ))
1100
+ if next_block != tail :
1101
+ block .append (ir .BranchIf (value , next_block , tail ))
1102
+ else :
1103
+ block .append (ir .Branch (tail ))
1083
1104
return phi
1084
1105
1085
1106
def visit_builtin_call (self , node ):
@@ -1211,6 +1232,79 @@ def visit_CallT(self, node):
1211
1232
self .current_block = after_invoke
1212
1233
return invoke
1213
1234
1235
+ def instrument_assert (self , node , value ):
1236
+ if self .current_assert_env is not None :
1237
+ if isinstance (value , ir .Constant ):
1238
+ return # don't display the values of constants
1239
+
1240
+ if any ([algorithm .compare (node , subexpr )
1241
+ for (subexpr , name ) in self .current_assert_subexprs ]):
1242
+ return # don't display the same subexpression twice
1243
+
1244
+ name = self .current_assert_env .type .add ("subexpr" , ir .TOption (node .type ))
1245
+ value_opt = self .append (ir .Alloc ([value ], ir .TOption (node .type )),
1246
+ loc = node .loc )
1247
+ self .append (ir .SetLocal (self .current_assert_env , name , value_opt ),
1248
+ loc = node .loc )
1249
+ self .current_assert_subexprs .append ((node , name ))
1250
+
1251
+ def visit_Assert (self , node ):
1252
+ try :
1253
+ assert_env = self .current_assert_env = \
1254
+ self .append (ir .Alloc ([], ir .TEnvironment ({}), name = "assertenv" ))
1255
+ assert_subexprs = self .current_assert_subexprs = []
1256
+ init = self .current_block
1257
+
1258
+ prehead = self .current_block = self .add_block ()
1259
+ cond = self .visit (node .test )
1260
+ head = self .current_block
1261
+ finally :
1262
+ self .current_assert_env = None
1263
+ self .current_assert_subexprs = None
1264
+
1265
+ for subexpr_node , subexpr_name in assert_subexprs :
1266
+ empty = init .append (ir .Alloc ([], ir .TOption (subexpr_node .type )))
1267
+ init .append (ir .SetLocal (assert_env , subexpr_name , empty ))
1268
+ init .append (ir .Branch (prehead ))
1269
+
1270
+ if_failed = self .current_block = self .add_block ()
1271
+
1272
+ if node .msg :
1273
+ explanation = node .msg .s
1274
+ else :
1275
+ explanation = node .loc .source ()
1276
+ self .append (ir .Builtin ("printf" , [
1277
+ ir .Constant ("assertion failed at %s: %s\n " , builtins .TStr ()),
1278
+ ir .Constant (str (node .loc .begin ()), builtins .TStr ()),
1279
+ ir .Constant (str (explanation ), builtins .TStr ()),
1280
+ ], builtins .TNone ()))
1281
+
1282
+ for subexpr_node , subexpr_name in assert_subexprs :
1283
+ subexpr_head = self .current_block
1284
+ subexpr_value_opt = self .append (ir .GetLocal (assert_env , subexpr_name ))
1285
+ subexpr_cond = self .append (ir .Builtin ("is_some" , [subexpr_value_opt ],
1286
+ builtins .TBool ()))
1287
+
1288
+ subexpr_body = self .current_block = self .add_block ()
1289
+ self .append (ir .Builtin ("printf" , [
1290
+ ir .Constant (" (%s) = " , builtins .TStr ()),
1291
+ ir .Constant (subexpr_node .loc .source (), builtins .TStr ())
1292
+ ], builtins .TNone ()))
1293
+ subexpr_value = self .append (ir .Builtin ("unwrap" , [subexpr_value_opt ],
1294
+ subexpr_node .type ))
1295
+ self .polymorphic_print ([subexpr_value ], separator = "" , suffix = "\n " )
1296
+ subexpr_postbody = self .current_block
1297
+
1298
+ subexpr_tail = self .current_block = self .add_block ()
1299
+ self .append (ir .Branch (subexpr_tail ), block = subexpr_postbody )
1300
+ self .append (ir .BranchIf (subexpr_cond , subexpr_body , subexpr_tail ), block = subexpr_head )
1301
+
1302
+ self .append (ir .Builtin ("abort" , [], builtins .TNone ()))
1303
+ self .append (ir .Unreachable ())
1304
+
1305
+ tail = self .current_block = self .add_block ()
1306
+ self .append (ir .BranchIf (cond , tail , if_failed ), block = head )
1307
+
1214
1308
def polymorphic_print (self , values , separator , suffix = "" ):
1215
1309
format_string = ""
1216
1310
args = []
0 commit comments