Exemple #1
0
def disasm_op(name, op):
    (mnemonic, test, desc) = op
    is_fma = mnemonic[0] == '*'

    # Modifiers may be either direct (pos is not None) or indirect (pos is
    # None). If direct, we just do the bit lookup. If indirect, we use a LUT.

    body = ""
    skip_mods = []

    body += build_lut(mnemonic, desc, test)

    for ((mod, pos, width), default, opts) in desc.get('modifiers', []):
        if pos is not None:
            body += lut_template.render(field = mod, table = pretty_mods(opts, default), pos = pos, width = width) + "\n"

    # Mnemonic, followed by modifiers
    body += '    fputs("{}", fp);\n'.format(mnemonic)

    srcs = desc.get('srcs', [])

    for mod in desc.get('modifiers', []):
        # Skip per-source until next block
        if mod[0][0][-1] in "0123" and int(mod[0][0][-1]) < len(srcs):
            continue

        body += disasm_mod(mod, skip_mods)

    body += '    fputs(" ", fp);\n'
    body += '    bi_disasm_dest_{}(fp, next_regs, last);\n'.format('fma' if is_fma else 'add')

    # Next up, each source. Source modifiers are inserterd here

    for i, (pos, mask) in enumerate(srcs):
        body += '    fputs(", ", fp);\n'
        body += '    dump_src(fp, _BITS(bits, {}, 3), *srcs, branch_offset, consts, {});\n'.format(pos, "true" if is_fma else "false")

        # Error check if needed
        if (mask != 0xFF):
            body += '    if (!({} & (1 << _BITS(bits, {}, 3)))) fputs("(INVALID)", fp);\n'.format(hex(mask), pos, 3)

        # Print modifiers suffixed with this src number (e.g. abs0 for src0)
        for mod in desc.get('modifiers', []):
            if mod[0][0][-1] == str(i):
                body += disasm_mod(mod, skip_mods)

    # And each immediate
    for (imm, pos, width) in desc.get('immediates', []):
        body += '    fprintf(fp, ", {}:%u", _BITS(bits, {}, {}));\n'.format(imm, pos, width)

    # Attach a staging register if one is used
    if desc.get('staging'):
        body += '    fprintf(fp, ", @r%u", staging_register);\n'

    return disasm_op_template.render(c_name = opname_to_c(name), body = body)
Exemple #2
0
def decode_op(instructions, is_fma):
    # Filter out the desired execution unit
    options = [n for n in instructions.keys() if (n[0] == '*') == is_fma]

    # Sort by exact masks, descending
    MAX_MASK = (1 << (23 if is_fma else 20)) - 1
    options.sort(key=lambda n: (MAX_MASK ^ instructions[n][2]["exact"][0]))

    # Map to what we need to template
    mapped = [(opname_to_c(op), instructions[op][2]["exact"],
               reserved_masks(instructions[op])) for op in options]

    # Generate checks in order
    template = """void
bi_disasm_${unit}(FILE *fp, unsigned bits, struct bifrost_regs *srcs, struct bifrost_regs *next_regs, unsigned staging_register, unsigned branch_offset, struct bi_constants *consts, bool last)
{
    fputs("    ", fp);

% for (i, (name, (emask, ebits), derived)) in enumerate(options):
% if len(derived) > 0:
    ${"else " if i > 0 else ""}if (unlikely(((bits & ${hex(emask)}) == ${hex(ebits)})
% for (pos, width, reserved) in derived:
        && !(${hex(reserved)} & (1 << _BITS(bits, ${pos}, ${width})))
% endfor
    ))
% else:
    ${"else " if i > 0 else ""}if (unlikely(((bits & ${hex(emask)}) == ${hex(ebits)})))
% endif
        bi_disasm_${name}(fp, bits, srcs, next_regs, staging_register, branch_offset, consts, last);
% endfor
    else
        fprintf(fp, "INSTR_INVALID_ENC ${unit} %X", bits);

    fputs("\\n", fp);
}"""

    return Template(template).render(options=mapped,
                                     unit="fma" if is_fma else "add")
Exemple #3
0
def pack_variant(opname, states):
    # Expressions to be ORed together for the final pack, an array per state
    pack_exprs = [[hex(state[1]["exact"][1])] for state in states]

    # Computations which need to be done to encode first, across states
    common_body = []

    # Map from modifier names to a map from modifier values to encoded values
    # String -> { String -> Uint }. This can be shared across states since
    # modifiers are (except the pos values) constant across state.
    imm_map = {}

    # Pack sources. Offset over to deal with staging/immediate weirdness in our
    # IR (TODO: reorder sources upstream so this goes away). Note sources are
    # constant across states.
    staging = states[0][1].get("staging", "")
    offset = 0
    if staging in ["r", "rw"]:
        offset += 1

    pack_sources(states[0][1].get("srcs", []), common_body, pack_exprs, offset)

    modifiers_handled = []
    for st in states:
        for ((mod, _, width), default, opts) in st[1].get("modifiers", []):
            if mod in modifiers_handled:
                continue

            modifiers_handled.append(mod)

            if pack_modifier(mod, width, default, opts, common_body,
                             pack_exprs) is None:
                return None

            imm_map[mod] = {x: y for y, x in enumerate(opts)}

    for i, st in enumerate(states):
        for ((mod, pos, width), default, opts) in st[1].get("modifiers", []):
            if pos is not None:
                pack_exprs[i].append('({} << {})'.format(mod, pos))

    for ((src_a, src_b), cond, remap) in st[1].get("swaps", []):
        # Figure out which vars to swap, in order to swap the arguments. This
        # always includes the sources themselves, and may include source
        # modifiers (with the same source indices). We swap based on which
        # matches A, this is arbitrary but if we swapped both nothing would end
        # up swapping at all since it would swap back.

        vars_to_swap = ['src']
        for ((mod, _, width), default, opts) in st[1].get("modifiers", []):
            if mod[-1] in str(src_a):
                vars_to_swap.append(mod[0:-1])

        common_body.append(
            'if {}'.format(compile_s_expr(cond, imm_map, None)) + ' {')

        # Emit the swaps. We use a temp, and wrap in a block to avoid naming
        # collisions with multiple swaps. {{Doubling}} to escape the format.

        for v in vars_to_swap:
            common_body.append(
                '    {{ unsigned temp = {}{}; {}{} = {}{}; {}{} = temp; }}'.
                format(v, src_a, v, src_a, v, src_b, v, src_b))

        # Also, remap. Bidrectional swaps are explicit in the XML.
        for v in remap:
            maps = remap[v]
            imm = imm_map[v]

            for i, l in enumerate(maps):
                common_body.append('    {}if ({} == {}) {} = {};'.format(
                    '' if i == 0 else 'else ', v, imm[l], v, imm[maps[l]]))

        common_body.append('}')
        common_body.append('')

    for (name, pos, width) in st[1].get("immediates", []):
        if name not in IMMEDIATE_TABLE:
            return None

        common_body.append('unsigned {} = {};'.format(name,
                                                      IMMEDIATE_TABLE[name]))

        for st in pack_exprs:
            st.append('({} << {})'.format(name, pos))

    if staging == 'r':
        common_body.append('bi_read_staging_register(clause, ins);')
    elif staging == 'w':
        common_body.append('bi_write_staging_register(clause, ins);')
    elif staging == '':
        pass
    else:
        assert staging == 'rw'
        # XXX: register allocation requirement (!)
        common_body.append('bi_read_staging_register(clause, ins);')
        common_body.append('assert(ins->src[0] == ins->dest);')

    # After this, we have to branch off, since deriveds *do* vary based on state.
    state_body = [[] for s in states]

    for i, (_, st) in enumerate(states):
        for ((pos, width), exprs) in st.get("derived", []):
            pack_derived(pos, exprs, imm_map, state_body[i], pack_exprs[i])

    # How do we pick a state? Accumulate the conditions
    state_conds = [compile_s_expr(st[0], imm_map, None)
                   for st in states] if len(states) > 1 else [None]

    if state_conds == None:
        assert (states[0][0] == None)

    # Finally, we'll collect everything together
    return variant_template.render(name=opname_to_c(opname),
                                   states=zip(pack_exprs, state_body,
                                              state_conds),
                                   common_body=common_body,
                                   single_state=(len(states) == 1))