Esempio n. 1
0
def emit_level1_hashtable(cpumode, level1, offt, fmt):
    """
    Emit a level 1 hash table for `cpumode`.
    """
    hash_table = compute_quadratic(
            level1.tables.values(),
            lambda level2: level2.ty.number)

    with fmt.indented(
            'pub static LEVEL1_{}: [Level1Entry<{}>; {}] = ['
            .format(cpumode.name.upper(), offt, len(hash_table)), '];'):
        for level2 in hash_table:
            if level2:
                l2l = int(math.log(level2.hash_table_len, 2))
                assert l2l > 0, "Hash table too small"
                fmt.line(
                        'Level1Entry ' +
                        '{{ ty: types::{}, log2len: {}, offset: {:#08x} }},'
                        .format(
                            level2.ty.name.upper(),
                            l2l,
                            level2.hash_table_offset))
            else:
                # Empty entry.
                fmt.line(
                        'Level1Entry ' +
                        '{ ty: types::VOID, log2len: 0, offset: 0 },')
Esempio n. 2
0
def emit_level1_hashtable(cpumode, level1, offt, fmt):
    """
    Emit a level 1 hash table for `cpumode`.
    """
    hash_table = compute_quadratic(
            level1.tables.values(),
            lambda level2: level2.ty.number)

    with fmt.indented(
            'pub static LEVEL1_{}: [Level1Entry<{}>; {}] = ['
            .format(cpumode.name.upper(), offt, len(hash_table)), '];'):
        for level2 in hash_table:
            if level2:
                l2l = int(math.log(level2.hash_table_len, 2))
                assert l2l > 0, "Hash table too small"
                fmt.line(
                        'Level1Entry ' +
                        '{{ ty: types::{}, log2len: {}, offset: {:#08x} }},'
                        .format(
                            level2.ty.name.upper(),
                            l2l,
                            level2.hash_table_offset))
            else:
                # Empty entry.
                fmt.line(
                        'Level1Entry ' +
                        '{ ty: types::VOID, log2len: 0, offset: 0 },')
Esempio n. 3
0
def gen_opcodes(groups, fmt):
    """
    Generate opcode enumerations.

    Return a list of all instructions.
    """

    fmt.doc_comment('An instruction opcode.')
    fmt.doc_comment('')
    fmt.doc_comment('All instructions from all supported ISAs are present.')
    fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
    instrs = []
    with fmt.indented('pub enum Opcode {', '}'):
        fmt.doc_comment('An invalid opcode.')
        fmt.line('NotAnOpcode,')
        for g in groups:
            for i in g.instructions:
                instrs.append(i)
                i.number = len(instrs)
                fmt.doc_comment('`{}`. ({})'.format(i, i.format.name))
                # Document polymorphism.
                if i.is_polymorphic:
                    if i.use_typevar_operand:
                        fmt.doc_comment('Type inferred from {}.'.format(
                            i.ins[i.format.typevar_operand]))
                # Enum variant itself.
                fmt.line(i.camel_name + ',')
    fmt.line()

    # Generate a private opcode_format table.
    with fmt.indented(
            'const OPCODE_FORMAT: [InstructionFormat; {}] = ['.format(
                len(instrs)), '];'):
        for i in instrs:
            fmt.format('InstructionFormat::{}, // {}', i.format.name, i.name)
    fmt.line()

    # Generate a private opcode_name function.
    with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
        with fmt.indented('match opc {', '}'):
            fmt.line('Opcode::NotAnOpcode => "<not an opcode>",')
            for i in instrs:
                fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
    fmt.line()

    # Generate an opcode hash table for looking up opcodes by name.
    hash_table = constant_hash.compute_quadratic(
        instrs, lambda i: constant_hash.simple_hash(i.name))
    with fmt.indented(
            'const OPCODE_HASH_TABLE: [Opcode; {}] = ['.format(
                len(hash_table)), '];'):
        for i in hash_table:
            if i is None:
                fmt.line('Opcode::NotAnOpcode,')
            else:
                fmt.format('Opcode::{},', i.camel_name)
    fmt.line()
    return instrs
Esempio n. 4
0
def emit_level1_hashtable(cpumode, level1, offt, fmt):
    # type: (CPUMode, Level1Table, str, srcgen.Formatter) -> None  # noqa
    """
    Emit a level 1 hash table for `cpumode`.
    """
    def hash_func(level2):
        # type: (Level2Table) -> int
        return level2.ty.number if level2.ty is not None else 0
    hash_table = compute_quadratic(level1.tables.values(), hash_func)

    with fmt.indented(
            'pub static LEVEL1_{}: [Level1Entry<{}>; {}] = ['
            .format(cpumode.name.upper(), offt, len(hash_table)), '];'):
        for level2 in hash_table:
            # Empty hash table entry. Include the default legalization action.
            if not level2:
                fmt.format(
                        'Level1Entry {{ ty: ir::types::VOID, log2len: !0, '
                        'offset: 0, legalize: {} }},',
                        level1.legalize_code)
                continue

            if level2.ty is not None:
                tyname = level2.ty.rust_name()
            else:
                tyname = 'ir::types::VOID'

            lcode = cpumode.isa.legalize_code(level2.legalize)

            # Empty level 2 table: Only a specialized legalization action, no
            # actual table.
            # Set an offset that is out of bounds, but make sure it doesn't
            # overflow its type when adding `1<<log2len`.
            if level2.is_empty():
                fmt.format(
                        'Level1Entry {{ '
                        'ty: {}, log2len: 0, offset: !0 - 1, '
                        'legalize: {} }}, // {}',
                        tyname, lcode, level2.legalize)
                continue

            # Proper level 2 hash table.
            l2l = int(math.log(level2.hash_table_len, 2))
            assert l2l > 0, "Level2 hash table too small"
            fmt.format(
                    'Level1Entry {{ '
                    'ty: {}, log2len: {}, offset: {:#08x}, '
                    'legalize: {} }}, // {}',
                    tyname, l2l, level2.hash_table_offset,
                    lcode, level2.legalize)
Esempio n. 5
0
    def layout_hashtable(self, level2_hashtables, level2_doc):
        """
        Compute the hash table mapping opcode -> enclist.

        Append the hash table to `level2_hashtables` and record the offset.
        """
        hash_table = compute_quadratic(self.lists.values(),
                                       lambda enclist: enclist.inst.number)

        self.hash_table_offset = len(level2_hashtables)
        self.hash_table_len = len(hash_table)

        level2_doc[self.hash_table_offset].append(
            '{:06x}: {}, {} entries'.format(self.hash_table_offset,
                                            self.ty.name, self.hash_table_len))
        level2_hashtables.extend(hash_table)
Esempio n. 6
0
def gen_descriptors(sgrp, fmt):
    """
    Generate the DESCRIPTORS and ENUMERATORS tables.
    """

    enums = UniqueSeqTable()

    with fmt.indented(
            'static DESCRIPTORS: [detail::Descriptor; {}] = ['.format(
                len(sgrp.settings)), '];'):
        for idx, setting in enumerate(sgrp.settings):
            setting.descriptor_index = idx
            with fmt.indented('detail::Descriptor {', '},'):
                fmt.line('name: "{}",'.format(setting.name))
                fmt.line('offset: {},'.format(setting.byte_offset))
                if isinstance(setting, BoolSetting):
                    fmt.line(
                        'detail: detail::Detail::Bool {{ bit: {} }},'.format(
                            setting.bit_offset))
                elif isinstance(setting, NumSetting):
                    fmt.line('detail: detail::Detail::Num,')
                elif isinstance(setting, EnumSetting):
                    offs = enums.add(setting.values)
                    fmt.line('detail: detail::Detail::Enum ' +
                             '{{ last: {}, enumerators: {} }},'.format(
                                 len(setting.values) - 1, offs))
                else:
                    raise AssertionError("Unknown setting kind")

    with fmt.indented(
            'static ENUMERATORS: [&\'static str; {}] = ['.format(
                len(enums.table)), '];'):
        for txt in enums.table:
            fmt.line('"{}",'.format(txt))

    def hash_setting(s):
        return constant_hash.simple_hash(s.name)

    hash_table = constant_hash.compute_quadratic(sgrp.settings, hash_setting)
    with fmt.indented(
            'static HASH_TABLE: [u16; {}] = ['.format(len(hash_table)), '];'):
        for h in hash_table:
            if h is None:
                fmt.line('0xffff,')
            else:
                fmt.line('{},'.format(h.descriptor_index))
Esempio n. 7
0
    def layout_hashtable(self, level2_hashtables, level2_doc):
        """
        Compute the hash table mapping opcode -> enclist.

        Append the hash table to `level2_hashtables` and record the offset.
        """
        hash_table = compute_quadratic(
                self.lists.values(),
                lambda enclist: enclist.inst.number)

        self.hash_table_offset = len(level2_hashtables)
        self.hash_table_len = len(hash_table)

        level2_doc[self.hash_table_offset].append(
                '{:06x}: {}, {} entries'.format(
                    self.hash_table_offset,
                    self.ty.name,
                    self.hash_table_len))
        level2_hashtables.extend(hash_table)
Esempio n. 8
0
    def layout_hashtable(self, level2_hashtables, level2_doc):
        # type: (List[EncList], DefaultDict[int, List[str]]) -> None
        """
        Compute the hash table mapping opcode -> enclist.

        Append the hash table to `level2_hashtables` and record the offset.
        """
        def hash_func(enclist):
            # type: (EncList) -> int
            return enclist.inst.number

        hash_table = compute_quadratic(self.lists.values(), hash_func)

        self.hash_table_offset = len(level2_hashtables)
        self.hash_table_len = len(hash_table)

        level2_doc[self.hash_table_offset].append(
            '{:06x}: {}, {} entries'.format(self.hash_table_offset, self.ty,
                                            self.hash_table_len))
        level2_hashtables.extend(hash_table)
Esempio n. 9
0
def gen_descriptors(sgrp, fmt):
    """
    Generate the DESCRIPTORS and ENUMERATORS tables.
    """

    enums = UniqueSeqTable()

    with fmt.indented("static DESCRIPTORS: [detail::Descriptor; {}] = [".format(len(sgrp.settings)), "];"):
        for idx, setting in enumerate(sgrp.settings):
            setting.descriptor_index = idx
            with fmt.indented("detail::Descriptor {", "},"):
                fmt.line('name: "{}",'.format(setting.name))
                fmt.line("offset: {},".format(setting.byte_offset))
                if isinstance(setting, BoolSetting):
                    fmt.line("detail: detail::Detail::Bool {{ bit: {} }},".format(setting.bit_offset))
                elif isinstance(setting, NumSetting):
                    fmt.line("detail: detail::Detail::Num,")
                elif isinstance(setting, EnumSetting):
                    offs = enums.add(setting.values)
                    fmt.line(
                        "detail: detail::Detail::Enum "
                        + "{{ last: {}, enumerators: {} }},".format(len(setting.values) - 1, offs)
                    )
                else:
                    raise AssertionError("Unknown setting kind")

    with fmt.indented("static ENUMERATORS: [&'static str; {}] = [".format(len(enums.table)), "];"):
        for txt in enums.table:
            fmt.line('"{}",'.format(txt))

    def hash_setting(s):
        return constant_hash.simple_hash(s.name)

    hash_table = constant_hash.compute_quadratic(sgrp.settings, hash_setting)
    with fmt.indented("static HASH_TABLE: [u16; {}] = [".format(len(hash_table)), "];"):
        for h in hash_table:
            if h is None:
                fmt.line("0xffff,")
            else:
                fmt.line("{},".format(h.descriptor_index))
Esempio n. 10
0
def gen_opcodes(groups, fmt):
    # type: (Sequence[InstructionGroup], srcgen.Formatter) -> Sequence[Instruction]  # noqa
    """
    Generate opcode enumerations.

    Return a list of all instructions.
    """

    fmt.doc_comment('''
                    An instruction opcode.

                    All instructions from all supported ISAs are present.
                    ''')
    fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]')
    instrs = []

    # We explicitly set the discriminant of the first variant to 1, which
    # allows us to take advantage of the NonZero optimization, meaning that
    # wrapping enums can use the 0 discriminant instead of increasing the size
    # if the whole type, and so SIZEOF(Option<Opcode>>) == SIZEOF(Opcode)
    is_first_opcode = True
    with fmt.indented('pub enum Opcode {', '}'):
        for g in groups:
            for i in g.instructions:
                instrs.append(i)
                i.number = len(instrs)
                fmt.doc_comment('`{}`. ({})'.format(i, i.format.name))
                # Document polymorphism.
                if i.is_polymorphic:
                    if i.use_typevar_operand:
                        opnum = i.value_opnums[i.format.typevar_operand]
                        fmt.doc_comment('Type inferred from {}.'.format(
                            i.ins[opnum]))
                # Enum variant itself.
                if is_first_opcode:
                    fmt.line(i.camel_name + ' = 1,')
                    is_first_opcode = False
                else:
                    fmt.line(i.camel_name + ',')
    fmt.line()

    with fmt.indented('impl Opcode {', '}'):
        for attr in sorted(Instruction.ATTRIBS.keys()):
            fmt.doc_comment(Instruction.ATTRIBS[attr])
            with fmt.indented('pub fn {}(self) -> bool {{'.format(attr), '}'):
                m = srcgen.Match('self')
                for i in instrs:
                    if getattr(i, attr):
                        m.arm('Opcode::' + i.camel_name, [], 'true')
                m.arm('_', [], 'false')
                fmt.match(m)
            fmt.line()
    fmt.line()

    # Generate a private opcode_format table.
    with fmt.indented(
            'const OPCODE_FORMAT: [InstructionFormat; {}] = ['.format(
                len(instrs)), '];'):
        for i in instrs:
            fmt.format('InstructionFormat::{}, // {}', i.format.name, i.name)
    fmt.line()

    # Generate a private opcode_name function.
    with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
        m = srcgen.Match('opc')
        for i in instrs:
            m.arm('Opcode::' + i.camel_name, [], '"{}"'.format(i.name))
        fmt.match(m)
    fmt.line()

    # Generate an opcode hash table for looking up opcodes by name.
    hash_table = constant_hash.compute_quadratic(
        instrs, lambda i: constant_hash.simple_hash(i.name))
    with fmt.indented(
            'const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = ['.format(
                len(hash_table)), '];'):
        for i in hash_table:
            if i is None:
                fmt.line('None,')
            else:
                fmt.format('Some(Opcode::{}),', i.camel_name)
    fmt.line()
    return instrs
Esempio n. 11
0
def gen_descriptors(sgrp, fmt):
    # type: (SettingGroup, srcgen.Formatter) -> None
    """
    Generate the DESCRIPTORS, ENUMERATORS, and PRESETS tables.
    """

    enums = UniqueSeqTable()

    with fmt.indented(
            'static DESCRIPTORS: [detail::Descriptor; {}] = ['
            .format(len(sgrp.settings) + len(sgrp.presets)),
            '];'):
        for idx, setting in enumerate(sgrp.settings):
            setting.descriptor_index = idx
            with fmt.indented('detail::Descriptor {', '},'):
                fmt.line('name: "{}",'.format(setting.name))
                fmt.line('offset: {},'.format(setting.byte_offset))
                if isinstance(setting, BoolSetting):
                    fmt.line(
                            'detail: detail::Detail::Bool {{ bit: {} }},'
                            .format(setting.bit_offset))
                elif isinstance(setting, NumSetting):
                    fmt.line('detail: detail::Detail::Num,')
                elif isinstance(setting, EnumSetting):
                    offs = enums.add(setting.values)
                    fmt.line(
                            'detail: detail::Detail::Enum ' +
                            '{{ last: {}, enumerators: {} }},'
                            .format(len(setting.values)-1, offs))
                else:
                    raise AssertionError("Unknown setting kind")

        for idx, preset in enumerate(sgrp.presets):
            preset.descriptor_index = len(sgrp.settings) + idx
            with fmt.indented('detail::Descriptor {', '},'):
                fmt.line('name: "{}",'.format(preset.name))
                fmt.line('offset: {},'.format(idx * sgrp.settings_size))
                fmt.line('detail: detail::Detail::Preset,')

    with fmt.indented(
            'static ENUMERATORS: [&str; {}] = ['
            .format(len(enums.table)),
            '];'):
        for txt in enums.table:
            fmt.line('"{}",'.format(txt))

    def hash_setting(s):
        # type: (Union[Setting, Preset]) -> int
        return constant_hash.simple_hash(s.name)

    hash_elems = []  # type: List[Union[Setting, Preset]]
    hash_elems.extend(sgrp.settings)
    hash_elems.extend(sgrp.presets)
    hash_table = constant_hash.compute_quadratic(hash_elems, hash_setting)
    with fmt.indented(
            'static HASH_TABLE: [u16; {}] = ['
            .format(len(hash_table)),
            '];'):
        for h in hash_table:
            if h is None:
                fmt.line('0xffff,')
            else:
                fmt.line('{},'.format(h.descriptor_index))

    with fmt.indented(
            'static PRESETS: [(u8, u8); {}] = ['
            .format(len(sgrp.presets) * sgrp.settings_size),
            '];'):
        for preset in sgrp.presets:
            fmt.comment(preset.name)
            for mask, value in preset.layout():
                fmt.format('(0b{:08b}, 0b{:08b}),', mask, value)
Esempio n. 12
0
def gen_descriptors(sgrp, fmt):
    # type: (SettingGroup, srcgen.Formatter) -> None
    """
    Generate the DESCRIPTORS, ENUMERATORS, and PRESETS tables.
    """

    enums = UniqueSeqTable()

    with fmt.indented(
            'static DESCRIPTORS: [detail::Descriptor; {}] = ['
            .format(len(sgrp.settings) + len(sgrp.presets)),
            '];'):
        for idx, setting in enumerate(sgrp.settings):
            setting.descriptor_index = idx
            with fmt.indented('detail::Descriptor {', '},'):
                fmt.line('name: "{}",'.format(setting.name))
                fmt.line('offset: {},'.format(setting.byte_offset))
                if isinstance(setting, BoolSetting):
                    fmt.line(
                            'detail: detail::Detail::Bool {{ bit: {} }},'
                            .format(setting.bit_offset))
                elif isinstance(setting, NumSetting):
                    fmt.line('detail: detail::Detail::Num,')
                elif isinstance(setting, EnumSetting):
                    offs = enums.add(setting.values)
                    fmt.line(
                            'detail: detail::Detail::Enum ' +
                            '{{ last: {}, enumerators: {} }},'
                            .format(len(setting.values)-1, offs))
                else:
                    raise AssertionError("Unknown setting kind")

        for idx, preset in enumerate(sgrp.presets):
            preset.descriptor_index = len(sgrp.settings) + idx
            with fmt.indented('detail::Descriptor {', '},'):
                fmt.line('name: "{}",'.format(preset.name))
                fmt.line('offset: {},'.format(idx * sgrp.settings_size))
                fmt.line('detail: detail::Detail::Preset,')

    with fmt.indented(
            'static ENUMERATORS: [&str; {}] = ['
            .format(len(enums.table)),
            '];'):
        for txt in enums.table:
            fmt.line('"{}",'.format(txt))

    def hash_setting(s):
        # type: (Union[Setting, Preset]) -> int
        return constant_hash.simple_hash(s.name)

    hash_elems = []  # type: List[Union[Setting, Preset]]
    hash_elems.extend(sgrp.settings)
    hash_elems.extend(sgrp.presets)
    hash_table = constant_hash.compute_quadratic(hash_elems, hash_setting)
    with fmt.indented(
            'static HASH_TABLE: [u16; {}] = ['
            .format(len(hash_table)),
            '];'):
        for h in hash_table:
            if h is None:
                fmt.line('0xffff,')
            else:
                fmt.line('{},'.format(h.descriptor_index))

    with fmt.indented(
            'static PRESETS: [(u8, u8); {}] = ['
            .format(len(sgrp.presets) * sgrp.settings_size),
            '];'):
        for preset in sgrp.presets:
            fmt.comment(preset.name)
            for mask, value in preset.layout():
                fmt.format('(0b{:08b}, 0b{:08b}),', mask, value)
Esempio n. 13
0
def gen_opcodes(groups, fmt):
    # type: (Sequence[InstructionGroup], srcgen.Formatter) -> Sequence[Instruction]  # noqa
    """
    Generate opcode enumerations.

    Return a list of all instructions.
    """

    fmt.doc_comment('''
                    An instruction opcode.

                    All instructions from all supported ISAs are present.
                    ''')
    fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]')
    instrs = []

    # We explicitly set the discriminant of the first variant to 1, which
    # allows us to take advantage of the NonZero optimization, meaning that
    # wrapping enums can use the 0 discriminant instead of increasing the size
    # if the whole type, and so SIZEOF(Option<Opcode>>) == SIZEOF(Opcode)
    is_first_opcode = True
    with fmt.indented('pub enum Opcode {', '}'):
        for g in groups:
            for i in g.instructions:
                instrs.append(i)
                i.number = len(instrs)
                fmt.doc_comment('`{}`. ({})'.format(i, i.format.name))
                # Document polymorphism.
                if i.is_polymorphic:
                    if i.use_typevar_operand:
                        opnum = i.value_opnums[i.format.typevar_operand]
                        fmt.doc_comment(
                                'Type inferred from {}.'
                                .format(i.ins[opnum]))
                # Enum variant itself.
                if is_first_opcode:
                    fmt.line(i.camel_name + ' = 1,')
                    is_first_opcode = False
                else:
                    fmt.line(i.camel_name + ',')
    fmt.line()

    with fmt.indented('impl Opcode {', '}'):
        for attr in sorted(Instruction.ATTRIBS.keys()):
            fmt.doc_comment(Instruction.ATTRIBS[attr])
            with fmt.indented('pub fn {}(self) -> bool {{'
                              .format(attr), '}'):
                with fmt.indented('match self {', '}'):
                    for i in instrs:
                        if getattr(i, attr):
                            fmt.format(
                                    'Opcode::{} => true,',
                                    i.camel_name, i.name)

                    fmt.line('_ => false,')
            fmt.line()
    fmt.line()

    # Generate a private opcode_format table.
    with fmt.indented(
            'const OPCODE_FORMAT: [InstructionFormat; {}] = ['
            .format(len(instrs)),
            '];'):
        for i in instrs:
            fmt.format(
                    'InstructionFormat::{}, // {}',
                    i.format.name, i.name)
    fmt.line()

    # Generate a private opcode_name function.
    with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
        with fmt.indented('match opc {', '}'):
            for i in instrs:
                fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
    fmt.line()

    # Generate an opcode hash table for looking up opcodes by name.
    hash_table = constant_hash.compute_quadratic(
            instrs,
            lambda i: constant_hash.simple_hash(i.name))
    with fmt.indented(
            'const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = ['
            .format(len(hash_table)), '];'):
        for i in hash_table:
            if i is None:
                fmt.line('None,')
            else:
                fmt.format('Some(Opcode::{}),', i.camel_name)
    fmt.line()
    return instrs
Esempio n. 14
0
def gen_opcodes(groups, fmt):
    """
    Generate opcode enumerations.

    Return a list of all instructions.
    """

    fmt.doc_comment('An instruction opcode.')
    fmt.doc_comment('')
    fmt.doc_comment('All instructions from all supported ISAs are present.')
    fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
    instrs = []

    # We explicitly set the discriminant of the first variant to 1, which
    # allows us to take advantage of the NonZero optimization, meaning that
    # wrapping enums can use the 0 discriminant instead of increasing the size
    # if the whole type, and so SIZEOF(Option<Opcode>>) == SIZEOF(Opcode)
    is_first_opcode = True
    with fmt.indented('pub enum Opcode {', '}'):
        for g in groups:
            for i in g.instructions:
                instrs.append(i)
                i.number = len(instrs)
                fmt.doc_comment('`{}`. ({})'.format(i, i.format.name))
                # Document polymorphism.
                if i.is_polymorphic:
                    if i.use_typevar_operand:
                        fmt.doc_comment('Type inferred from {}.'.format(
                            i.ins[i.format.typevar_operand]))
                # Enum variant itself.
                if is_first_opcode:
                    fmt.line(i.camel_name + ' = 1,')
                    is_first_opcode = False
                else:
                    fmt.line(i.camel_name + ',')
    fmt.line()

    with fmt.indented('impl Opcode {', '}'):
        attrs = [{
            'name': 'is_branch',
            'comment': 'True for all branch instructions.'
        }, {
            'name': 'is_terminator',
            'comment': 'True for instructions that terminate EBB.'
        }, {
            'name': 'can_trap',
            'comment': 'True if instruction could trap.'
        }]

        for attr in attrs:
            if attr != attrs[0]:
                fmt.line()

            fmt.doc_comment(attr['comment'])
            with fmt.indented(
                    'pub fn {}(self) -> bool {{'.format(attr['name']), '}'):
                with fmt.indented('match self {', '}'):
                    for i in instrs:
                        if getattr(i, attr['name']):
                            fmt.format('Opcode::{} => true,', i.camel_name,
                                       i.name)

                    fmt.line('_ => false')

    # Generate a private opcode_format table.
    with fmt.indented(
            'const OPCODE_FORMAT: [InstructionFormat; {}] = ['.format(
                len(instrs)), '];'):
        for i in instrs:
            fmt.format('InstructionFormat::{}, // {}', i.format.name, i.name)
    fmt.line()

    # Generate a private opcode_name function.
    with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
        with fmt.indented('match opc {', '}'):
            for i in instrs:
                fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
    fmt.line()

    # Generate an opcode hash table for looking up opcodes by name.
    hash_table = constant_hash.compute_quadratic(
        instrs, lambda i: constant_hash.simple_hash(i.name))
    with fmt.indented(
            'const OPCODE_HASH_TABLE: [Option<Opcode>; {}] = ['.format(
                len(hash_table)), '];'):
        for i in hash_table:
            if i is None:
                fmt.line('None,')
            else:
                fmt.format('Some(Opcode::{}),', i.camel_name)
    fmt.line()
    return instrs
Esempio n. 15
0
def gen_opcodes(groups, fmt):
    """
    Generate opcode enumerations.

    Return a list of all instructions.
    """

    fmt.doc_comment('An instruction opcode.')
    fmt.doc_comment('')
    fmt.doc_comment('All instructions from all supported ISAs are present.')
    fmt.line('#[derive(Copy, Clone, PartialEq, Eq, Debug)]')
    instrs = []
    with fmt.indented('pub enum Opcode {', '}'):
        fmt.doc_comment('An invalid opcode.')
        fmt.line('NotAnOpcode,')
        for g in groups:
            for i in g.instructions:
                instrs.append(i)
                i.number = len(instrs)
                fmt.doc_comment('`{}`. ({})'.format(i, i.format.name))
                # Document polymorphism.
                if i.is_polymorphic:
                    if i.use_typevar_operand:
                        fmt.doc_comment(
                                'Type inferred from {}.'
                                .format(i.ins[i.format.typevar_operand]))
                # Enum variant itself.
                fmt.line(i.camel_name + ',')
    fmt.line()

    # Generate a private opcode_format table.
    with fmt.indented(
            'const OPCODE_FORMAT: [InstructionFormat; {}] = ['
            .format(len(instrs)),
            '];'):
        for i in instrs:
            fmt.format(
                    'InstructionFormat::{}, // {}',
                    i.format.name, i.name)
    fmt.line()

    # Generate a private opcode_name function.
    with fmt.indented('fn opcode_name(opc: Opcode) -> &\'static str {', '}'):
        with fmt.indented('match opc {', '}'):
            fmt.line('Opcode::NotAnOpcode => "<not an opcode>",')
            for i in instrs:
                fmt.format('Opcode::{} => "{}",', i.camel_name, i.name)
    fmt.line()

    # Generate an opcode hash table for looking up opcodes by name.
    hash_table = constant_hash.compute_quadratic(
            instrs,
            lambda i: constant_hash.simple_hash(i.name))
    with fmt.indented(
            'const OPCODE_HASH_TABLE: [Opcode; {}] = ['
            .format(len(hash_table)), '];'):
        for i in hash_table:
            if i is None:
                fmt.line('Opcode::NotAnOpcode,')
            else:
                fmt.format('Opcode::{},', i.camel_name)
    fmt.line()
    return instrs