1*99e0aae7SDavid Rees# Copyright 2019 Google LLC 2*99e0aae7SDavid Rees# 3*99e0aae7SDavid Rees# Licensed under the Apache License, Version 2.0 (the "License"); 4*99e0aae7SDavid Rees# you may not use this file except in compliance with the License. 5*99e0aae7SDavid Rees# You may obtain a copy of the License at 6*99e0aae7SDavid Rees# 7*99e0aae7SDavid Rees# https://www.apache.org/licenses/LICENSE-2.0 8*99e0aae7SDavid Rees# 9*99e0aae7SDavid Rees# Unless required by applicable law or agreed to in writing, software 10*99e0aae7SDavid Rees# distributed under the License is distributed on an "AS IS" BASIS, 11*99e0aae7SDavid Rees# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*99e0aae7SDavid Rees# See the License for the specific language governing permissions and 13*99e0aae7SDavid Rees# limitations under the License. 14*99e0aae7SDavid Rees 15*99e0aae7SDavid Rees"""Tests for util.traverse_ir.""" 16*99e0aae7SDavid Rees 17*99e0aae7SDavid Reesimport collections 18*99e0aae7SDavid Rees 19*99e0aae7SDavid Reesimport unittest 20*99e0aae7SDavid Rees 21*99e0aae7SDavid Reesfrom compiler.util import ir_data 22*99e0aae7SDavid Reesfrom compiler.util import ir_data_utils 23*99e0aae7SDavid Reesfrom compiler.util import traverse_ir 24*99e0aae7SDavid Rees 25*99e0aae7SDavid Rees_EXAMPLE_IR = ir_data_utils.IrDataSerializer.from_json(ir_data.EmbossIr, """{ 26*99e0aae7SDavid Rees"module": [ 27*99e0aae7SDavid Rees { 28*99e0aae7SDavid Rees "type": [ 29*99e0aae7SDavid Rees { 30*99e0aae7SDavid Rees "structure": { 31*99e0aae7SDavid Rees "field": [ 32*99e0aae7SDavid Rees { 33*99e0aae7SDavid Rees "location": { 34*99e0aae7SDavid Rees "start": { "constant": { "value": "0" } }, 35*99e0aae7SDavid Rees "size": { "constant": { "value": "8" } } 36*99e0aae7SDavid Rees }, 37*99e0aae7SDavid Rees "type": { 38*99e0aae7SDavid Rees "atomic_type": { 39*99e0aae7SDavid Rees "reference": { 40*99e0aae7SDavid Rees "canonical_name": { 41*99e0aae7SDavid Rees "module_file": "", 42*99e0aae7SDavid Rees "object_path": ["UInt"] 43*99e0aae7SDavid Rees } 44*99e0aae7SDavid Rees } 45*99e0aae7SDavid Rees } 46*99e0aae7SDavid Rees }, 47*99e0aae7SDavid Rees "name": { "name": { "text": "field1" } } 48*99e0aae7SDavid Rees }, 49*99e0aae7SDavid Rees { 50*99e0aae7SDavid Rees "location": { 51*99e0aae7SDavid Rees "start": { "constant": { "value": "8" } }, 52*99e0aae7SDavid Rees "size": { "constant": { "value": "16" } } 53*99e0aae7SDavid Rees }, 54*99e0aae7SDavid Rees "type": { 55*99e0aae7SDavid Rees "array_type": { 56*99e0aae7SDavid Rees "base_type": { 57*99e0aae7SDavid Rees "atomic_type": { 58*99e0aae7SDavid Rees "reference": { 59*99e0aae7SDavid Rees "canonical_name": { 60*99e0aae7SDavid Rees "module_file": "", 61*99e0aae7SDavid Rees "object_path": ["UInt"] 62*99e0aae7SDavid Rees } 63*99e0aae7SDavid Rees } 64*99e0aae7SDavid Rees } 65*99e0aae7SDavid Rees }, 66*99e0aae7SDavid Rees "element_count": { "constant": { "value": "8" } } 67*99e0aae7SDavid Rees } 68*99e0aae7SDavid Rees }, 69*99e0aae7SDavid Rees "name": { "name": { "text": "field2" } } 70*99e0aae7SDavid Rees } 71*99e0aae7SDavid Rees ] 72*99e0aae7SDavid Rees }, 73*99e0aae7SDavid Rees "name": { "name": { "text": "Foo" } }, 74*99e0aae7SDavid Rees "subtype": [ 75*99e0aae7SDavid Rees { 76*99e0aae7SDavid Rees "structure": { 77*99e0aae7SDavid Rees "field": [ 78*99e0aae7SDavid Rees { 79*99e0aae7SDavid Rees "location": { 80*99e0aae7SDavid Rees "start": { "constant": { "value": "24" } }, 81*99e0aae7SDavid Rees "size": { "constant": { "value": "32" } } 82*99e0aae7SDavid Rees }, 83*99e0aae7SDavid Rees "type": { 84*99e0aae7SDavid Rees "atomic_type": { 85*99e0aae7SDavid Rees "reference": { 86*99e0aae7SDavid Rees "canonical_name": { 87*99e0aae7SDavid Rees "module_file": "", 88*99e0aae7SDavid Rees "object_path": ["UInt"] 89*99e0aae7SDavid Rees } 90*99e0aae7SDavid Rees } 91*99e0aae7SDavid Rees } 92*99e0aae7SDavid Rees }, 93*99e0aae7SDavid Rees "name": { "name": { "text": "bar_field1" } } 94*99e0aae7SDavid Rees }, 95*99e0aae7SDavid Rees { 96*99e0aae7SDavid Rees "location": { 97*99e0aae7SDavid Rees "start": { "constant": { "value": "32" } }, 98*99e0aae7SDavid Rees "size": { "constant": { "value": "320" } } 99*99e0aae7SDavid Rees }, 100*99e0aae7SDavid Rees "type": { 101*99e0aae7SDavid Rees "array_type": { 102*99e0aae7SDavid Rees "base_type": { 103*99e0aae7SDavid Rees "array_type": { 104*99e0aae7SDavid Rees "base_type": { 105*99e0aae7SDavid Rees "atomic_type": { 106*99e0aae7SDavid Rees "reference": { 107*99e0aae7SDavid Rees "canonical_name": { 108*99e0aae7SDavid Rees "module_file": "", 109*99e0aae7SDavid Rees "object_path": ["UInt"] 110*99e0aae7SDavid Rees } 111*99e0aae7SDavid Rees } 112*99e0aae7SDavid Rees } 113*99e0aae7SDavid Rees }, 114*99e0aae7SDavid Rees "element_count": { "constant": { "value": "16" } } 115*99e0aae7SDavid Rees } 116*99e0aae7SDavid Rees }, 117*99e0aae7SDavid Rees "automatic": { } 118*99e0aae7SDavid Rees } 119*99e0aae7SDavid Rees }, 120*99e0aae7SDavid Rees "name": { "name": { "text": "bar_field2" } } 121*99e0aae7SDavid Rees } 122*99e0aae7SDavid Rees ] 123*99e0aae7SDavid Rees }, 124*99e0aae7SDavid Rees "name": { "name": { "text": "Bar" } } 125*99e0aae7SDavid Rees } 126*99e0aae7SDavid Rees ] 127*99e0aae7SDavid Rees }, 128*99e0aae7SDavid Rees { 129*99e0aae7SDavid Rees "enumeration": { 130*99e0aae7SDavid Rees "value": [ 131*99e0aae7SDavid Rees { 132*99e0aae7SDavid Rees "name": { "name": { "text": "ONE" } }, 133*99e0aae7SDavid Rees "value": { "constant": { "value": "1" } } 134*99e0aae7SDavid Rees }, 135*99e0aae7SDavid Rees { 136*99e0aae7SDavid Rees "name": { "name": { "text": "TWO" } }, 137*99e0aae7SDavid Rees "value": { 138*99e0aae7SDavid Rees "function": { 139*99e0aae7SDavid Rees "function": "ADDITION", 140*99e0aae7SDavid Rees "args": [ 141*99e0aae7SDavid Rees { "constant": { "value": "1" } }, 142*99e0aae7SDavid Rees { "constant": { "value": "1" } } 143*99e0aae7SDavid Rees ], 144*99e0aae7SDavid Rees "function_name": { "text": "+" } 145*99e0aae7SDavid Rees } 146*99e0aae7SDavid Rees } 147*99e0aae7SDavid Rees } 148*99e0aae7SDavid Rees ] 149*99e0aae7SDavid Rees }, 150*99e0aae7SDavid Rees "name": { "name": { "text": "Bar" } } 151*99e0aae7SDavid Rees } 152*99e0aae7SDavid Rees ], 153*99e0aae7SDavid Rees "source_file_name": "t.emb" 154*99e0aae7SDavid Rees }, 155*99e0aae7SDavid Rees { 156*99e0aae7SDavid Rees "type": [ 157*99e0aae7SDavid Rees { 158*99e0aae7SDavid Rees "external": { }, 159*99e0aae7SDavid Rees "name": { 160*99e0aae7SDavid Rees "name": { "text": "UInt" }, 161*99e0aae7SDavid Rees "canonical_name": { "module_file": "", "object_path": ["UInt"] } 162*99e0aae7SDavid Rees }, 163*99e0aae7SDavid Rees "attribute": [ 164*99e0aae7SDavid Rees { 165*99e0aae7SDavid Rees "name": { "text": "statically_sized" }, 166*99e0aae7SDavid Rees "value": { "expression": { "boolean_constant": { "value": true } } } 167*99e0aae7SDavid Rees }, 168*99e0aae7SDavid Rees { 169*99e0aae7SDavid Rees "name": { "text": "size_in_bits" }, 170*99e0aae7SDavid Rees "value": { "expression": { "constant": { "value": "64" } } } 171*99e0aae7SDavid Rees } 172*99e0aae7SDavid Rees ] 173*99e0aae7SDavid Rees } 174*99e0aae7SDavid Rees ], 175*99e0aae7SDavid Rees "source_file_name": "" 176*99e0aae7SDavid Rees } 177*99e0aae7SDavid Rees] 178*99e0aae7SDavid Rees}""") 179*99e0aae7SDavid Rees 180*99e0aae7SDavid Rees 181*99e0aae7SDavid Reesdef _count_entries(sequence): 182*99e0aae7SDavid Rees counts = collections.Counter() 183*99e0aae7SDavid Rees for entry in sequence: 184*99e0aae7SDavid Rees counts[entry] += 1 185*99e0aae7SDavid Rees return counts 186*99e0aae7SDavid Rees 187*99e0aae7SDavid Rees 188*99e0aae7SDavid Reesdef _record_constant(constant, constant_list): 189*99e0aae7SDavid Rees constant_list.append(int(constant.value)) 190*99e0aae7SDavid Rees 191*99e0aae7SDavid Rees 192*99e0aae7SDavid Reesdef _record_field_name_and_constant(constant, constant_list, field): 193*99e0aae7SDavid Rees constant_list.append((field.name.name.text, int(constant.value))) 194*99e0aae7SDavid Rees 195*99e0aae7SDavid Rees 196*99e0aae7SDavid Reesdef _record_file_name_and_constant(constant, constant_list, source_file_name): 197*99e0aae7SDavid Rees constant_list.append((source_file_name, int(constant.value))) 198*99e0aae7SDavid Rees 199*99e0aae7SDavid Rees 200*99e0aae7SDavid Reesdef _record_location_parameter_and_constant(constant, constant_list, 201*99e0aae7SDavid Rees location=None): 202*99e0aae7SDavid Rees constant_list.append((location, int(constant.value))) 203*99e0aae7SDavid Rees 204*99e0aae7SDavid Rees 205*99e0aae7SDavid Reesdef _record_kind_and_constant(constant, constant_list, type_definition): 206*99e0aae7SDavid Rees if type_definition.HasField("enumeration"): 207*99e0aae7SDavid Rees constant_list.append(("enumeration", int(constant.value))) 208*99e0aae7SDavid Rees elif type_definition.HasField("structure"): 209*99e0aae7SDavid Rees constant_list.append(("structure", int(constant.value))) 210*99e0aae7SDavid Rees elif type_definition.HasField("external"): 211*99e0aae7SDavid Rees constant_list.append(("external", int(constant.value))) 212*99e0aae7SDavid Rees else: 213*99e0aae7SDavid Rees assert False, "Shouldn't be here." 214*99e0aae7SDavid Rees 215*99e0aae7SDavid Rees 216*99e0aae7SDavid Reesclass TraverseIrTest(unittest.TestCase): 217*99e0aae7SDavid Rees 218*99e0aae7SDavid Rees def test_filter_on_type(self): 219*99e0aae7SDavid Rees constants = [] 220*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 221*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.NumericConstant], _record_constant, 222*99e0aae7SDavid Rees parameters={"constant_list": constants}) 223*99e0aae7SDavid Rees self.assertEqual( 224*99e0aae7SDavid Rees _count_entries([0, 8, 8, 8, 16, 24, 32, 16, 32, 320, 1, 1, 1, 64]), 225*99e0aae7SDavid Rees _count_entries(constants)) 226*99e0aae7SDavid Rees 227*99e0aae7SDavid Rees def test_filter_on_type_in_type(self): 228*99e0aae7SDavid Rees constants = [] 229*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 230*99e0aae7SDavid Rees _EXAMPLE_IR, 231*99e0aae7SDavid Rees [ir_data.Function, ir_data.Expression, ir_data.NumericConstant], 232*99e0aae7SDavid Rees _record_constant, 233*99e0aae7SDavid Rees parameters={"constant_list": constants}) 234*99e0aae7SDavid Rees self.assertEqual([1, 1], constants) 235*99e0aae7SDavid Rees 236*99e0aae7SDavid Rees def test_filter_on_type_star_type(self): 237*99e0aae7SDavid Rees struct_constants = [] 238*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 239*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.Structure, ir_data.NumericConstant], 240*99e0aae7SDavid Rees _record_constant, 241*99e0aae7SDavid Rees parameters={"constant_list": struct_constants}) 242*99e0aae7SDavid Rees self.assertEqual(_count_entries([0, 8, 8, 8, 16, 24, 32, 16, 32, 320]), 243*99e0aae7SDavid Rees _count_entries(struct_constants)) 244*99e0aae7SDavid Rees enum_constants = [] 245*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 246*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.Enum, ir_data.NumericConstant], _record_constant, 247*99e0aae7SDavid Rees parameters={"constant_list": enum_constants}) 248*99e0aae7SDavid Rees self.assertEqual(_count_entries([1, 1, 1]), _count_entries(enum_constants)) 249*99e0aae7SDavid Rees 250*99e0aae7SDavid Rees def test_filter_on_not_type(self): 251*99e0aae7SDavid Rees notstruct_constants = [] 252*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 253*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.NumericConstant], _record_constant, 254*99e0aae7SDavid Rees skip_descendants_of=(ir_data.Structure,), 255*99e0aae7SDavid Rees parameters={"constant_list": notstruct_constants}) 256*99e0aae7SDavid Rees self.assertEqual(_count_entries([1, 1, 1, 64]), 257*99e0aae7SDavid Rees _count_entries(notstruct_constants)) 258*99e0aae7SDavid Rees 259*99e0aae7SDavid Rees def test_field_is_populated(self): 260*99e0aae7SDavid Rees constants = [] 261*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 262*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.Field, ir_data.NumericConstant], 263*99e0aae7SDavid Rees _record_field_name_and_constant, 264*99e0aae7SDavid Rees parameters={"constant_list": constants}) 265*99e0aae7SDavid Rees self.assertEqual(_count_entries([ 266*99e0aae7SDavid Rees ("field1", 0), ("field1", 8), ("field2", 8), ("field2", 8), 267*99e0aae7SDavid Rees ("field2", 16), ("bar_field1", 24), ("bar_field1", 32), 268*99e0aae7SDavid Rees ("bar_field2", 16), ("bar_field2", 32), ("bar_field2", 320) 269*99e0aae7SDavid Rees ]), _count_entries(constants)) 270*99e0aae7SDavid Rees 271*99e0aae7SDavid Rees def test_file_name_is_populated(self): 272*99e0aae7SDavid Rees constants = [] 273*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 274*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.NumericConstant], _record_file_name_and_constant, 275*99e0aae7SDavid Rees parameters={"constant_list": constants}) 276*99e0aae7SDavid Rees self.assertEqual(_count_entries([ 277*99e0aae7SDavid Rees ("t.emb", 0), ("t.emb", 8), ("t.emb", 8), ("t.emb", 8), ("t.emb", 16), 278*99e0aae7SDavid Rees ("t.emb", 24), ("t.emb", 32), ("t.emb", 16), ("t.emb", 32), 279*99e0aae7SDavid Rees ("t.emb", 320), ("t.emb", 1), ("t.emb", 1), ("t.emb", 1), ("", 64) 280*99e0aae7SDavid Rees ]), _count_entries(constants)) 281*99e0aae7SDavid Rees 282*99e0aae7SDavid Rees def test_type_definition_is_populated(self): 283*99e0aae7SDavid Rees constants = [] 284*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 285*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.NumericConstant], _record_kind_and_constant, 286*99e0aae7SDavid Rees parameters={"constant_list": constants}) 287*99e0aae7SDavid Rees self.assertEqual(_count_entries([ 288*99e0aae7SDavid Rees ("structure", 0), ("structure", 8), ("structure", 8), ("structure", 8), 289*99e0aae7SDavid Rees ("structure", 16), ("structure", 24), ("structure", 32), 290*99e0aae7SDavid Rees ("structure", 16), ("structure", 32), ("structure", 320), 291*99e0aae7SDavid Rees ("enumeration", 1), ("enumeration", 1), ("enumeration", 1), 292*99e0aae7SDavid Rees ("external", 64) 293*99e0aae7SDavid Rees ]), _count_entries(constants)) 294*99e0aae7SDavid Rees 295*99e0aae7SDavid Rees def test_keyword_args_dict_in_action(self): 296*99e0aae7SDavid Rees call_counts = {"populated": 0, "not": 0} 297*99e0aae7SDavid Rees 298*99e0aae7SDavid Rees def check_field_is_populated(node, **kwargs): 299*99e0aae7SDavid Rees del node # Unused. 300*99e0aae7SDavid Rees self.assertTrue(kwargs["field"]) 301*99e0aae7SDavid Rees call_counts["populated"] += 1 302*99e0aae7SDavid Rees 303*99e0aae7SDavid Rees def check_field_is_not_populated(node, **kwargs): 304*99e0aae7SDavid Rees del node # Unused. 305*99e0aae7SDavid Rees self.assertFalse("field" in kwargs) 306*99e0aae7SDavid Rees call_counts["not"] += 1 307*99e0aae7SDavid Rees 308*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 309*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.Field, ir_data.Type], check_field_is_populated) 310*99e0aae7SDavid Rees self.assertEqual(7, call_counts["populated"]) 311*99e0aae7SDavid Rees 312*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 313*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.Enum, ir_data.EnumValue], 314*99e0aae7SDavid Rees check_field_is_not_populated) 315*99e0aae7SDavid Rees self.assertEqual(2, call_counts["not"]) 316*99e0aae7SDavid Rees 317*99e0aae7SDavid Rees def test_pass_only_to_sub_nodes(self): 318*99e0aae7SDavid Rees constants = [] 319*99e0aae7SDavid Rees 320*99e0aae7SDavid Rees def pass_location_down(field): 321*99e0aae7SDavid Rees return { 322*99e0aae7SDavid Rees "location": (int(field.location.start.constant.value), 323*99e0aae7SDavid Rees int(field.location.size.constant.value)) 324*99e0aae7SDavid Rees } 325*99e0aae7SDavid Rees 326*99e0aae7SDavid Rees traverse_ir.fast_traverse_ir_top_down( 327*99e0aae7SDavid Rees _EXAMPLE_IR, [ir_data.NumericConstant], 328*99e0aae7SDavid Rees _record_location_parameter_and_constant, 329*99e0aae7SDavid Rees incidental_actions={ir_data.Field: pass_location_down}, 330*99e0aae7SDavid Rees parameters={"constant_list": constants, "location": None}) 331*99e0aae7SDavid Rees self.assertEqual(_count_entries([ 332*99e0aae7SDavid Rees ((0, 8), 0), ((0, 8), 8), ((8, 16), 8), ((8, 16), 8), ((8, 16), 16), 333*99e0aae7SDavid Rees ((24, 32), 24), ((24, 32), 32), ((32, 320), 16), ((32, 320), 32), 334*99e0aae7SDavid Rees ((32, 320), 320), (None, 1), (None, 1), (None, 1), (None, 64) 335*99e0aae7SDavid Rees ]), _count_entries(constants)) 336*99e0aae7SDavid Rees 337*99e0aae7SDavid Rees 338*99e0aae7SDavid Reesif __name__ == "__main__": 339*99e0aae7SDavid Rees unittest.main() 340