def _run_variadic_bitwise( op: str, model: delay_model_pb2.DelayModel, stub: synthesis_service_pb2_grpc.SynthesisServiceStub) -> None: """Characterize variadic bitwise ops.""" # Add op_model to protobuf message add_op_model = model.op_models.add(op=op) expr = add_op_model.estimator.regression.expressions.add() expr.factor.source = delay_model_pb2.DelayFactor.OPERAND_BIT_COUNT expr.factor.operand_number = 0 op = ENUM2NAME_MAP[op] # Compute samples widths = get_bit_widths() arity = list(range(2, 8)) combs = itertools.product(widths, arity) results = [] for bit_count, arity in combs: op_type = f'bits[{bit_count}]' ir_text = op_module_generator.generate_ir_package( op, op_type, (op_type, ) * arity) result = _synthesize_ir(stub, ir_text, op, bit_count, (bit_count, ) * arity) results.append(result) model.data_points.extend(results)
def _run_extension( op: str, model: delay_model_pb2.DelayModel, stub: synthesis_service_pb2_grpc.SynthesisServiceStub) -> None: """Characterize extension ops (sign- and zero-).""" # Add op_model to protobuf message add_op_model = model.op_models.add(op=op) expression = add_op_model.estimator.regression.expressions.add() expression.factor.source = delay_model_pb2.DelayFactor.OPERAND_BIT_COUNT expression.factor.operand_number = 0 op = ENUM2NAME_MAP[op] # Compute samples widths = get_bit_widths() combs = filter(lambda b: b[1] > b[0], itertools.product(widths, widths)) results = [] for bit_count, new_bit_count in combs: op_type = f'bits[{bit_count}]' ret_type = f'bits[{new_bit_count}]' ir_text = op_module_generator.generate_ir_package(op, ret_type, (op_type, ), attributes=[ ('new_bit_count', new_bit_count) ]) result = _synthesize_ir(stub, ir_text, op, new_bit_count, (bit_count, 64)) results.append(result) model.data_points.extend(results)
def test_8_bit_add_verilog(self): ir_text = opgen.generate_ir_package('add', output_type='bits[8]', operand_types=('bits[8]', 'bits[8]')) verilog_text = opgen.generate_verilog_module('add_module', ir_text).verilog_text self.assertIn('module add_module', verilog_text) self.assertIn('p0_op0 + p0_op1', verilog_text)
def test_mixed_width_mul(self): self.assertEqual( """package umul_characterization fn main(op0: bits[27], op1: bits[5]) -> bits[42] { ret umul.1: bits[42] = umul(op0, op1) }""", opgen.generate_ir_package('umul', output_type='bits[42]', operand_types=('bits[27]', 'bits[5]')))
def test_8_bit_add(self): self.assertEqual( """package add_characterization fn main(op0: bits[8], op1: bits[8]) -> bits[8] { ret add.1: bits[8] = add(op0, op1) }""", opgen.generate_ir_package('add', output_type='bits[8]', operand_types=('bits[8]', 'bits[8]')))
def test_sign_extend(self): self.assertEqual( """package sign_ext_characterization fn main(op0: bits[16]) -> bits[32] { ret sign_ext.1: bits[32] = sign_ext(op0, new_bit_count=32) }""", opgen.generate_ir_package('sign_ext', output_type='bits[32]', operand_types=('bits[16]', ), attributes=(('new_bit_count', '32'), )))
def test_array_update(self): self.assertEqual( """package array_update_characterization fn main(op0: bits[17][42], op1: bits[3], op2: bits[17]) -> bits[17][42] { ret array_update.1: bits[17][42] = array_update(op0, op1, op2) }""", opgen.generate_ir_package('array_update', output_type='bits[17][42]', operand_types=('bits[17][42]', 'bits[3]', 'bits[17]')))
def test_array_index(self): self.assertEqual( """package array_index_characterization fn main(op0: bits[17][42][10], op1: bits[32], op2: bits[3]) -> bits[17] { ret result: bits[17] = array_index(op0, indices=[op1, op2]) }""", opgen.generate_ir_package('array_index', output_type='bits[17]', operand_types=('bits[17][42][10]', 'bits[32]', 'bits[3]')))
def test_select_with_default(self): self.assertEqual( """package sel_characterization fn main(op0: bits[2], op1: bits[32], op2: bits[32], op3: bits[32]) -> bits[32] { ret result: bits[32] = sel(op0, cases=[op1, op2], default=op3) }""", opgen.generate_ir_package('sel', output_type='bits[32]', operand_types=('bits[2]', 'bits[32]', 'bits[32]', 'bits[32]')))
def test_add_with_literal_operand(self): self.assertEqual( """package add_characterization fn main(op0: bits[32]) -> bits[32] { literal.1: bits[32] = literal(value=0xd82c07cd) ret add.2: bits[32] = add(op0, literal.1) }""", opgen.generate_ir_package('add', output_type='bits[32]', operand_types=('bits[32]', 'bits[32]'), literal_operand=1))
def test_parallel_add_verilog(self): add8_ir = opgen.generate_ir_package('add', output_type='bits[8]', operand_types=('bits[8]', 'bits[8]')) add16_ir = opgen.generate_ir_package('add', output_type='bits[16]', operand_types=('bits[16]', 'bits[16]')) add24_ir = opgen.generate_ir_package('add', output_type='bits[24]', operand_types=('bits[24]', 'bits[24]')) modules = (opgen.generate_verilog_module('add8_module', add8_ir), opgen.generate_verilog_module('add16_module', add16_ir), opgen.generate_verilog_module('add24_module', add24_ir)) parallel_module = opgen.generate_parallel_module(modules, 'foo') self.assertEqual( parallel_module, runfiles.get_contents_as_text( 'xls/delay_model/testdata/parallel_op_module.vtxt'))
def test_array_update_with_literal_operand(self): self.assertEqual( """package array_update_characterization fn main(op1: bits[3], op2: bits[17]) -> bits[17][4] { literal.1: bits[17][4] = literal(value=[0x1b058, 0xc53e, 0x18412, 0x1c7ce]) ret array_update.2: bits[17][4] = array_update(literal.1, op1, op2) }""", opgen.generate_ir_package('array_update', output_type='bits[17][4]', operand_types=('bits[17][4]', 'bits[3]', 'bits[17]'), literal_operand=0))
def _generate_sources( self, op: op_pb2.OpProto, operand_types: Iterable[xls_type_pb2.TypeProto], output_type: xls_type_pb2.TypeProto) -> Tuple[str, str]: """Generates XLS IR and netlist sources for a single LEC execution. This function creates IR and a netlist for the given op and argument/output types, suitable as inputs to a LEC operation. Currently, this only supports a single op (per the internal operation of op_module_generator). In the future, it will likely be useful to see how execution time scales with operation composition. Args: op: The XLS IR opcode for which to generate sources. operand_types: The types of the arguments to use for this op execution. output_type: The type of the operation output. Returns: A tuple of IR and netlist sources for executing the given operation as text. """ op_name = op_pb2.OpProto.Name(op)[3:].lower() operand_type_strs = [ self._proto_to_ir_type(ot) for ot in operand_types ] ir_text = op_module_generator.generate_ir_package( op_name, self._proto_to_ir_type(output_type), operand_type_strs, [], None) verilog_text = op_module_generator.generate_verilog_module( self._MODULE_NAME, ir_text).verilog_text creds = client_credentials.get_credentials() netlist_text = None with grpc.secure_channel(self._synthesis_server_address, creds) as channel: grpc.channel_ready_future(channel).result() stub = synthesis_service_pb2_grpc.SynthesisServiceStub(channel) request = synthesis_pb2.CompileRequest() logging.vlog(logging.INFO, 'Module text:\n %s', verilog_text) request.module_text = verilog_text request.top_module_name = self._MODULE_NAME # We're always going to be in a single cycle. request.target_frequency_hz = 1 response = stub.Compile(request) netlist_text = response.netlist return (ir_text, netlist_text)
def _synthesize_op_and_make_bare_data_point( op: str, kop: str, op_type: str, operand_types: List[str], stub: synthesis_service_pb2_grpc.SynthesisServiceStub, attributes: Sequence[Tuple[str, str]] = (), literal_operand: Optional[int] = None) -> delay_model_pb2.DataPoint: """Characterize an operation via synthesis server. Sets the area and op of the data point but not any other information about the node / operands. Args: op: Operation name to use for generating an IR package; e.g. 'add'. kop: Operation name to emit into datapoints, generally in kConstant form for use in the delay model; e.g. 'kAdd'. op_type: The type of the operation result. operand_types: The type of each operation. stub: Handle to the synthesis server. attributes: Attributes to include in the operation mnemonic. For example, "new_bit_count" in extend operations. Forwarded to generate_ir_package. literal_operand: Optionally specifies that the given operand number should be substituted with a randomly generated literal instead of a function parameter. Forwarded to generate_ir_package. Returns: datapoint produced via the synthesis server with the area and op (but no other fields) set. """ ir_text = op_module_generator.generate_ir_package(op, op_type, operand_types, attributes, literal_operand) module_name_safe_op_type = op_type.replace('[', '_').replace(']', '') module_name = f'{op}_{module_name_safe_op_type}' mod_generator_result = op_module_generator.generate_verilog_module( module_name, ir_text) top_name = module_name + '_wrapper' verilog_text = op_module_generator.generate_parallel_module( [mod_generator_result], top_name) response = _synth(stub, verilog_text, top_name) result = delay_model_pb2.DataPoint() _record_area(response, result) result.operation.op = kop return result
def _run_shift(op: str, model: delay_model_pb2.DelayModel, data_points: Dict[str, Set[str]], stub: synthesis_service_pb2_grpc.SynthesisServiceStub) -> None: """Characterize shift ops.""" # Add op_model to protobuf message add_op_model = model.op_models.add(op=op) expr = add_op_model.estimator.regression.expressions.add() expr.factor.source = delay_model_pb2.DelayFactor.OPERAND_BIT_COUNT expr.factor.operand_number = 0 op = ENUM2NAME_MAP[op] # Compute samples for bit_count in get_bit_widths(): op_type = f'bits[{bit_count}]' ir_text = op_module_generator.generate_ir_package( op, op_type, (op_type, op_type)) _synthesize_ir(stub, model, data_points, ir_text, op, bit_count, (bit_count, ))
def _run_arithmetic_unary( op: str, model: delay_model_pb2.DelayModel, stub: synthesis_service_pb2_grpc.SynthesisServiceStub) -> None: """Characterize unary ops.""" # Add op_model to protobuf message add_op_model = model.op_models.add(op=op) expr = add_op_model.estimator.regression.expressions.add() expr.factor.source = delay_model_pb2.DelayFactor.OPERAND_BIT_COUNT expr.factor.operand_number = 0 op = ENUM2NAME_MAP[op] results = [] for bit_count in get_bit_widths(): op_type = f'bits[{bit_count}]' ir_text = op_module_generator.generate_ir_package( op, op_type, (op_type, )) result = _synthesize_ir(stub, ir_text, op, bit_count, (bit_count, )) results.append(result) model.data_points.extend(results)
def test_invalid_ir(self): with self.assertRaisesRegex(Exception, 'does not match expected type'): opgen.generate_ir_package('and', output_type='bits[17]', operand_types=('bits[123]', 'bits[17]'))
def test_select_invalid_selector_type(self): with self.assertRaises(ValueError): opgen.generate_ir_package('sel', output_type='bits[32]', operand_types=('bits[1][2]', 'bits[32]', 'bits[32]'))