def find_all_cell_types_from_module(module, modules, primitive_cells):
    """ Determine all of the cells types used in this module.

    This includes children of this module, and also includes primitive_cells.
    The primitive_cells lists is used to determine when this search should
    stop and not examine within a cell.  This is to prevent exposing yosys
    internal logic (e.g. specify cells) to the output logical netlist.

    Returns a set of all cell types uses within the specified module.

    """
    cells_in_module = set()

    assert module in modules

    module_data = modules[module]
    for cell_name, cell_data in module_data['cells'].items():
        cell_type = cell_data['type']

        cells_in_module.add(cell_type)

        if cell_type not in primitive_cells:
            cells_in_module |= find_all_cell_types_from_module(
                cell_type, modules, primitive_cells)

    return cells_in_module