def convert_module_to_package( module: ast.Module, type_info: type_info_mod.TypeInfo, emit_positions: bool = True, traverse_tests: bool = False) -> ir_package.Package: """Converts the contents of a module to IR form. Args: module: Module to convert. type_info: Concrete type information used in conversion. emit_positions: Whether to emit positional metadata into the output IR. traverse_tests: Whether to convert functions called in DSLX test constructs. Note that this does NOT convert the test constructs themselves. Returns: The IR package that corresponds to this module. """ emitted = [] # type: List[Text] package = ir_package.Package(module.name) order = extract_conversion_order.get_order(module, type_info, type_info.get_imports(), traverse_tests) logging.vlog(3, 'Convert order: %s', pprint.pformat(order)) for record in order: emitted.append( _convert_one_function( package, record.m, record.f, record.type_info, symbolic_bindings=record.bindings, emit_positions=emit_positions)) verifier_mod.verify_package(package) return package
def test_invoke_adder_2_plus_3_eq_5(self): p = ir_package.Package('test_package') fb = function_builder.FunctionBuilder('add_wrapper', p) t = p.get_bits_type(32) x = fb.add_param('x', t) y = fb.add_param('y', t) fb.add_add(x, y) add_wrapper = fb.build() main_fb = function_builder.FunctionBuilder('main', p) two = main_fb.add_literal_bits(bits_mod.UBits(value=2, bit_count=32)) three = main_fb.add_literal_bits(bits_mod.UBits(value=3, bit_count=32)) observed = main_fb.add_invoke([two, three], add_wrapper) main_fb.add_eq( observed, main_fb.add_literal_bits(bits_mod.UBits(value=5, bit_count=32))) main_fb.build() self.assertMultiLineEqual( p.dump_ir(), """\ package test_package fn add_wrapper(x: bits[32], y: bits[32]) -> bits[32] { ret add.3: bits[32] = add(x, y, id=3) } fn main() -> bits[1] { literal.4: bits[32] = literal(value=2, id=4) literal.5: bits[32] = literal(value=3, id=5) invoke.6: bits[32] = invoke(literal.4, literal.5, to_apply=add_wrapper, id=6) literal.7: bits[32] = literal(value=5, id=7) ret eq.8: bits[1] = eq(invoke.6, literal.7, id=8) } """)
def test_generates_sources(self): p = package.Package('the_package') ir_text, netlist_text = self.lc._generate_sources( op_pb2.OpProto.OP_ADD, [p.get_bits_type(8), p.get_bits_type(8)], p.get_bits_type(8)) self.assertIn('ret add.1: bits[8]', ir_text) self.assertEqual(netlist_text, '// NETLIST')
def test_array_type(self): pkg = package.Package('pkg') bit_type = pkg.get_bits_type(4) t = pkg.get_array_type(3, bit_type) self.assertEqual(3, t.get_size()) self.assertEqual(4, t.get_element_type().get_bit_count())
def test_simple_build_and_dump_package(self): p = ir_package.Package('test_package') fileno = p.get_or_create_fileno('my_file.x') fb = function_builder.FunctionBuilder('test_function', p) t = p.get_bits_type(32) x = fb.add_param('x', t) lineno = fileno_mod.Lineno(42) colno = fileno_mod.Colno(64) loc = source_location.SourceLocation(fileno, lineno, colno) fb.add_or(x, x, loc=loc, name='my_or') fb.add_not(x, loc=loc, name='why_not') f = fb.build() self.assertEqual(f.name, 'test_function') self.assertEqual( f.dump_ir(), """\ fn test_function(x: bits[32]) -> bits[32] { my_or: bits[32] = or(x, x, id=2, pos=0,42,64) ret why_not: bits[32] = not(x, id=3, pos=0,42,64) } """) self.assertMultiLineEqual( p.dump_ir(), """\ package test_package fn test_function(x: bits[32]) -> bits[32] { my_or: bits[32] = or(x, x, id=2, pos=0,42,64) ret why_not: bits[32] = not(x, id=3, pos=0,42,64) } """)
def test_lec_smoke(self): p = package.Package('the_package') temp_dir = tempfile.TemporaryDirectory() results_path = os.path.join(temp_dir.name, 'results.textproto') num_iters = 16 byte_type = p.get_bits_type(8) self.lc.run( op=op_pb2.OpProto.OP_ADD, samples=[([byte_type, byte_type], byte_type)], num_iters=num_iters, cell_library_textproto=self.cell_lib_text, results_path=results_path, lec_fn=lambda a, b, c, d: True) # Open results, verify contents results = lec_characterizer_pb2.LecTiming() with gfile.open(results_path, 'r') as f: text_format.Parse(f.read(), results) self.assertEqual(results.ir_function, 'single_op_OP_ADD') self.assertLen(results.test_cases, 1) test_case = results.test_cases[0] self.assertLen(test_case.exec_times_us, num_iters)
def test_standard_pipeline(self): pkg = package.Package('pname') fb = function_builder.FunctionBuilder('main', pkg) fb.add_literal_bits(bits_mod.UBits(value=2, bit_count=32)) fb.build() self.assertFalse(standard_pipeline.run_standard_pass_pipeline(pkg))
def test_verify_function(self): pkg = package.Package('pname') builder = function_builder.FunctionBuilder('f_name', pkg) builder.add_param('x', pkg.get_bits_type(32)) builder.add_literal_value(ir_value.Value(bits.UBits(7, 8))) fn = builder.build() verifier.verify_function(fn)
def test_read_then_write(self): p = package.Package('the_package') temp_dir = tempfile.TemporaryDirectory() results_path = os.path.join(temp_dir.name, 'results.textproto') results = lec_characterizer_pb2.LecTiming() results.ir_function = 'single_op_OP_ADD' # Add one un-touched test case, and add one that should be appended to. proto_byte = xls_type_pb2.TypeProto() proto_byte.type_enum = xls_type_pb2.TypeProto.BITS proto_byte.bit_count = 8 proto_short = xls_type_pb2.TypeProto() proto_short.type_enum = xls_type_pb2.TypeProto.BITS proto_short.bit_count = 16 test_case = results.test_cases.add() param = test_case.function_type.parameters.add() param.CopyFrom(proto_short) param = test_case.function_type.parameters.add() param.CopyFrom(proto_short) test_case.function_type.return_type.CopyFrom(proto_short) test_case = results.test_cases.add() param = test_case.function_type.parameters.add() param.CopyFrom(proto_byte) param = test_case.function_type.parameters.add() param.CopyFrom(proto_byte) test_case.function_type.return_type.CopyFrom(proto_byte) test_case.exec_times_us.extend([1, 3, 7]) test_case.average_us = 3 with gfile.open(results_path, 'w') as f: f.write(text_format.MessageToString(results)) num_iters = 16 byte_type = p.get_bits_type(8) self.lc.run( op=op_pb2.OpProto.OP_ADD, samples=[([byte_type, byte_type], byte_type)], num_iters=num_iters, cell_library_textproto=self.cell_lib_text, results_path=results_path, lec_fn=lambda a, b, c, d: True) results = lec_characterizer_pb2.LecTiming() with gfile.open(results_path, 'r') as f: text_format.Parse(f.read(), results) self.assertEqual(results.ir_function, 'single_op_OP_ADD') self.assertLen(results.test_cases, 2) for test_case in results.test_cases: if test_case.function_type.return_type.bit_count == 16: self.assertEmpty(test_case.exec_times_us) else: self.assertLen(test_case.exec_times_us, 3 + num_iters)
def test_bvalue_methods(self): # This test is mainly about checking that pybind11 is able to map parameter # and return types properly. Because of this it's not necessary to check # the result at the end; that methods don't throw when called is enough. p = ir_package.Package('test_package') fb = function_builder.FunctionBuilder('test_function', p) x = fb.add_param('param_name', p.get_bits_type(32)) self.assertIn('param_name', str(x)) self.assertEqual(32, x.get_type().get_bit_count())
def test_pipeline_generator_with_clock_period(self): pkg = package.Package('pname') fb = function_builder.FunctionBuilder('main', pkg) fb.add_param('x', pkg.get_bits_type(32)) fb.build() module_signature = pipeline_generator.generate_pipelined_module_with_clock_period( pkg, 100, 'bar') self.assertIn('module bar', module_signature.verilog_text) self.assertIn('p0_x', module_signature.verilog_text) self.assertIn('p1_x', module_signature.verilog_text)
def test_generates_sources(self): server_path = runfiles.get_path('xls/synthesis/dummy_synthesis_server_main') port = portpicker.pick_unused_port() lc = lec_characterizer.LecCharacterizer( [server_path, '--port={}'.format(port)], port) p = package.Package('the_package') ir_text, netlist_text = lc._generate_sources( op_pb2.OpProto.OP_ADD, [p.get_bits_type(8), p.get_bits_type(8)], p.get_bits_type(8)) self.assertIn('ret add.1: bits[8]', ir_text) self.assertEqual(netlist_text, '// NETLIST')
def test_parse_value(self): p = package_mod.Package('test_package') u32 = p.get_bits_type(32) u8 = p.get_bits_type(8) t = p.get_tuple_type([u32, u8]) s = '({}, {})'.format(0xdeadbeef, 0xcd) v = ir_parser.Parser.parse_value(s, t) self.assertEqual(s, str(v)) v = ir_parser.Parser.parse_value('(0xdeadbeef, 0xcd)', t) self.assertEqual('(bits[32]:{}, bits[8]:{})'.format(0xdeadbeef, 0xcd), v.to_str())
def test_function_type(self): pkg = package.Package('pname') builder = function_builder.FunctionBuilder('f_name', pkg) builder.add_param('x', pkg.get_bits_type(32)) builder.add_literal_value(ir_value.Value(bits.UBits(7, 8))) fn = builder.build() fn_type = fn.get_type() self.assertIsInstance(fn_type, ir_type.FunctionType) self.assertIn('bits[32]', str(fn_type)) self.assertEqual(8, fn_type.return_type().get_bit_count()) self.assertEqual(1, fn_type.get_parameter_count()) self.assertEqual(32, fn_type.get_parameter_type(0).get_bit_count())
def convert_one_function(module: ast.Module, entry_function_name: Text, type_info: type_info_mod.TypeInfo, emit_positions: bool = True) -> Text: """Returns function named entry_function_name in module as IR text.""" package = ir_package.Package(module.name) _convert_one_function( package, module, module.get_function(entry_function_name), type_info, emit_positions=emit_positions) return package.dump_ir()
def test_pipeline_generator_with_n_stages(self): pkg = package.Package('pname') fb = function_builder.FunctionBuilder('main', pkg) fb.add_param('x', pkg.get_bits_type(32)) fb.build() module_signature = pipeline_generator.generate_pipelined_module_with_n_stages( pkg, 5, 'foo') self.assertIn('module foo', module_signature.verilog_text) self.assertIn('p0_x', module_signature.verilog_text) self.assertIn('p1_x', module_signature.verilog_text) self.assertIn('p2_x', module_signature.verilog_text) self.assertIn('p3_x', module_signature.verilog_text) self.assertIn('p4_x', module_signature.verilog_text)
def test_package_methods(self): pkg = package.Package('pkg') fb = function_builder.FunctionBuilder('f', pkg) fb.add_literal_value(ir_value.Value(bits.UBits(7, 8))) fb.build() self.assertIn('pkg', pkg.dump_ir()) self.assertIsInstance(pkg.get_bits_type(4), ir_type.BitsType) self.assertIsInstance(pkg.get_array_type(4, pkg.get_bits_type(4)), ir_type.ArrayType) self.assertIsInstance(pkg.get_tuple_type([pkg.get_bits_type(4)]), ir_type.TupleType) self.assertIsInstance(pkg.get_or_create_fileno('file'), fileno.Fileno) self.assertIsInstance(pkg.get_function('f'), function.Function) self.assertEqual(['f'], pkg.get_function_names())
def test_literal_array(self): p = ir_package.Package('test_package') fb = function_builder.FunctionBuilder('f', p) fb.add_literal_value( ir_value.Value.make_array([ ir_value.Value(bits_mod.UBits(value=5, bit_count=32)), ir_value.Value(bits_mod.UBits(value=6, bit_count=32)), ])) fb.build() self.assertMultiLineEqual( p.dump_ir(), """\ package test_package fn f() -> bits[32][2] { ret literal.1: bits[32][2] = literal(value=[5, 6], id=1) } """)
def test_type_polymorphism(self): # Verify that pybind11 knows to down-cast Type objects. pkg = package.Package('pkg') bits_type = pkg.get_bits_type(4) array_type = pkg.get_array_type(3, bits_type) tuple_type = pkg.get_tuple_type([bits_type]) self.assertIsInstance( pkg.get_array_type(1, bits_type).get_element_type(), ir_type.BitsType) self.assertIsInstance( pkg.get_array_type(1, array_type).get_element_type(), ir_type.ArrayType) self.assertIsInstance( pkg.get_array_type(1, tuple_type).get_element_type(), ir_type.TupleType)
def test_match_true(self): p = ir_package.Package('test_package') fb = function_builder.FunctionBuilder('f', p) pred_t = p.get_bits_type(1) expr_t = p.get_bits_type(32) pred_x = fb.add_param('pred_x', pred_t) x = fb.add_param('x', expr_t) pred_y = fb.add_param('pred_y', pred_t) y = fb.add_param('y', expr_t) default = fb.add_param('default', expr_t) fb.add_match_true([pred_x, pred_y], [x, y], default) fb.build() self.assertMultiLineEqual( p.dump_ir(), """\ package test_package fn f(pred_x: bits[1], x: bits[32], pred_y: bits[1], y: bits[32], default: bits[32]) -> bits[32] { concat.6: bits[2] = concat(pred_y, pred_x, id=6) one_hot.7: bits[3] = one_hot(concat.6, lsb_prio=true, id=7) ret one_hot_sel.8: bits[32] = one_hot_sel(one_hot.7, cases=[x, y, default], id=8) } """)
def test_verify_package(self): pkg = package.Package('pkg') verifier.verify_package(pkg)
def test_type(self): pkg = package.Package('pkg') t = pkg.get_bits_type(4) self.assertIn('4', str(t))
def test_bits_type(self): pkg = package.Package('pkg') t = pkg.get_bits_type(4) self.assertEqual(4, t.get_bit_count())
def test_all_add_methods(self): # This test is mainly about checking that pybind11 is able to map parameter # and return types properly. Because of this it's not necessary to check # the result at the end; that methods don't throw when called is enough. p = ir_package.Package('test_package') fileno = p.get_or_create_fileno('my_file.x') lineno = fileno_mod.Lineno(42) colno = fileno_mod.Colno(64) loc = source_location.SourceLocation(fileno, lineno, colno) fb = function_builder.FunctionBuilder('test_function', p) input_function_builder = function_builder.FunctionBuilder('fn', p) input_function_builder.add_literal_value( ir_value.Value(bits_mod.UBits(7, 8))) input_function = input_function_builder.build() single_zero_bit = fb.add_literal_value( ir_value.Value(bits_mod.UBits(value=0, bit_count=1))) t = p.get_bits_type(32) x = fb.add_param('x', t) fb.add_shra(x, x, loc=loc) fb.add_shra(x, x, loc=loc) fb.add_shrl(x, x, loc=loc) fb.add_shll(x, x, loc=loc) fb.add_or(x, x, loc=loc) fb.add_nary_or([x], loc=loc) fb.add_xor(x, x, loc=loc) fb.add_and(x, x, loc=loc) fb.add_smul(x, x, loc=loc) fb.add_umul(x, x, loc=loc) fb.add_udiv(x, x, loc=loc) fb.add_sub(x, x, loc=loc) fb.add_add(x, x, loc=loc) fb.add_concat([x], loc=loc) fb.add_ule(x, x, loc=loc) fb.add_ult(x, x, loc=loc) fb.add_uge(x, x, loc=loc) fb.add_ugt(x, x, loc=loc) fb.add_sle(x, x, loc=loc) fb.add_slt(x, x, loc=loc) fb.add_sge(x, x, loc=loc) fb.add_sgt(x, x, loc=loc) fb.add_eq(x, x, loc=loc) fb.add_ne(x, x, loc=loc) fb.add_neg(x, loc=loc) fb.add_not(x, loc=loc) fb.add_clz(x, loc=loc) fb.add_one_hot(x, lsb_or_msb.LsbOrMsb.LSB, loc=loc) fb.add_one_hot_sel(x, [x], loc=loc) fb.add_literal_bits(bits_mod.UBits(value=2, bit_count=32), loc=loc) fb.add_literal_value(ir_value.Value( bits_mod.UBits(value=5, bit_count=32)), loc=loc) fb.add_sel(x, x, x, loc=loc) fb.add_sel_multi(x, [x], x, loc=loc) fb.add_match_true([single_zero_bit], [x], x, loc=loc) tuple_node = fb.add_tuple([x], loc=loc) fb.add_array([x], t, loc=loc) fb.add_tuple_index(tuple_node, 0, loc=loc) fb.add_counted_for(x, 1, 1, input_function, [x], loc=loc) fb.add_map(fb.add_array([x], t, loc=loc), input_function, loc=loc) fb.add_invoke([x], input_function, loc=loc) fb.add_array_index(fb.add_array([x], t, loc=loc), x, loc=loc) fb.add_reverse(fb.add_array([x], t, loc=loc), loc=loc) fb.add_identity(x, loc=loc) fb.add_signext(x, 10, loc=loc) fb.add_zeroext(x, 10, loc=loc) fb.add_bit_slice(x, 4, 2, loc=loc) fb.build()
def build_function(name='function_name'): pkg = package.Package('pname') builder = function_builder.FunctionBuilder(name, pkg) builder.add_literal_value(value.Value(bits.UBits(7, 8))) return builder.build()