def test_convert_jmpthenlabel_check():
    code = [
        p.LabelStmt("alreadySorted"),
        p.AssignOp(src="inbox", dst="emp"),
        p.IfOp("neg", [p.JumpOp("alreadySorted")], []),
        p.IfOp("ez", [p.JumpOp("alreadySorted")],
               [p.AssignOp(src="0", dst="emp")])
    ]
    expected_ast = [
        p.LabelStmt("alreadySorted"),
        p.AssignOp(src="inbox", dst="emp"),
        p.JumpCondOp(condition="jneg", label_name="alreadySorted"),
        # pass
        #    p.JumpOp("_hrm_endif_1"),
        # p.LabelStmt("_hrm_endif_1"),
        p.JumpCondOp(condition="jez", label_name="alreadySorted"),
        p.AssignOp(src="0", dst="emp")
        #    p.JumpOp("_hrm_unreachable"),
        # p.LabelStmt("_hrm_unreachable")
    ]
    result_ast = conversion.convert_ifnz_to_ifez(code)
    result_ast = conversion.convert_iftojump(result_ast)
    result_ast = conversion.compress_jumps(result_ast)
    result_ast = conversion.remove_unreachable_code(result_ast)

    ast = conversion.fix_jmp_then_label(result_ast)

    assert ast == expected_ast
Beispiel #2
0
def test_compress_jcond_single():
    start_ast = [
        parser.LabelStmt("start"),
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp("if", "ez"),
            parser.OutboxOp(),
            parser.JumpOp("endif"),
        parser.LabelStmt("if"),
            parser.JumpOp("start"),
        parser.LabelStmt("endif"),
        parser.OutboxOp()
    ]
    expected_ast = [
        parser.LabelStmt("start"),
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp("start", "ez"),
            parser.OutboxOp(),
            parser.JumpOp("endif"),
        parser.LabelStmt("if"),
            parser.JumpOp("start"),
        parser.LabelStmt("endif"),
        parser.OutboxOp()
    ]
    ast = compress_jumps(start_ast)
    assert ast == expected_ast
Beispiel #3
0
def test_convert_iftojump_nested():
    code = [
        p.IfOp("ez", [
            p.IfOp("ez", [p.AssignOp("inbox", "emp")], [p.OutboxOp()]),
        ], [
            p.IfOp("neg", [p.AssignOp("inbox", "emp")], [p.OutboxOp()])
        ])]
    expected_ast = [
        p.JumpCondOp(condition="jez", label_name="_hrm_1"),
          p.JumpCondOp(condition="jneg", label_name="_hrm_2"),
            p.OutboxOp(),
            p.JumpOp("_hrm_endif_2"),
          p.LabelStmt("_hrm_2"),
            p.AssignOp("inbox", "emp"),
          p.LabelStmt("_hrm_endif_2"),
       p.JumpOp("_hrm_endif_1"),
       p.LabelStmt("_hrm_1"),
          p.JumpCondOp(condition="jez", label_name="_hrm_3"),
            p.OutboxOp(),
            p.JumpOp("_hrm_endif_3"),
          p.LabelStmt("_hrm_3"),
            p.AssignOp("inbox", "emp"),
          p.LabelStmt("_hrm_endif_3"),
       p.LabelStmt("_hrm_endif_1")]
    ast = c.convert_iftojump(code)
    assert ast == expected_ast
Beispiel #4
0
def test_unreachable_condjumps():
    start_ast = [
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp("_hrm_1", "jez"),
        parser.OutboxOp(),
        parser.LabelStmt("_hrm_1"),
        parser.LabelStmt("_hrm_endif_1")
    ]
    expected_ast = [
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp("_hrm_unreachable", "jez"),
        parser.OutboxOp(),
        parser.LabelStmt("_hrm_unreachable")
    ]
    ast = remove_unreachable_code(start_ast)
    assert ast == expected_ast
Beispiel #5
0
    def convert_if(self, ifObj):
        def create_adhoc_assembler():
            new_assembler = Assembler()
            new_assembler.aliases = self.aliases
            new_assembler._gen_label_cnt = self._gen_label_cnt
            return new_assembler

        label_cnt = self._gen_label_cnt
        self._gen_label_cnt += 1

        true_branch_assembler = create_adhoc_assembler()
        true_branch_assembler.convert(ifObj.true_branch)
        self._gen_label_cnt = true_branch_assembler._gen_label_cnt

        false_branch_assembler = create_adhoc_assembler()
        false_branch_assembler.convert(ifObj.false_branch)
        self._gen_label_cnt = false_branch_assembler._gen_label_cnt

        self.convert_condjump(
            p.JumpCondOp("_hrm_" + str(label_cnt), "j" + ifObj.condition))
        for false_branch_codeline in false_branch_assembler.code:
            self.code.append(false_branch_codeline)
        self.convert_jump(p.JumpOp("_hrm_endif_" + str(label_cnt)))
        self.convert_label(p.LabelStmt("_hrm_" + str(label_cnt)))
        for true_branch_codeline in true_branch_assembler.code:
            self.code.append(true_branch_codeline)
        self.convert_label(p.LabelStmt("_hrm_endif_" + str(label_cnt)))
def test_convert_jmpthenlabel_conditionaljumps_multiple():
    start_ast = [
        p.JumpCondOp(condition="jneg", label_name="other"),
        p.JumpCondOp(condition="jez", label_name="output"),
        p.LabelStmt("output"),
        p.OutboxOp(),
        p.LabelStmt("other"),
        p.AssignOp(src="inbox", dst="emp")
    ]
    expected_ast = [
        p.JumpCondOp(condition="jneg", label_name="other"),
        p.OutboxOp(),
        p.LabelStmt("other"),
        p.AssignOp(src="inbox", dst="emp")
    ]
    ast = conversion.fix_jmp_then_label(start_ast)

    assert ast == expected_ast
def test_convert_jmpthenlabel_conditionaljumps_leading_to_same_instr():
    start_ast = [
        p.JumpCondOp(condition="ez", label_name="output"),
        p.LabelStmt("output"),
        p.OutboxOp()
    ]
    expected_ast = [p.OutboxOp()]
    ast = conversion.fix_jmp_then_label(start_ast)
    assert ast == expected_ast
Beispiel #8
0
def test_dont_optimize_conditional_jumps():
    """
    if ez then
        # nothing, but the `jez` must not be removed!
        # if removed, the program becomes only `outbox`,
        # that is incorrect.
    else
        outbox
    endif
    """
    start_ast = [
            parser.JumpCondOp(label_name='_hrm_1', condition='jez'),
            parser.OutboxOp(),
            parser.JumpOp(label_name="_hrm_endif_1"),
            parser.LabelStmt(label_name="_hrm_1"),
            parser.LabelStmt(label_name="_hrm_endif_1")
    ]
    ast = compress_jumps(start_ast)
    assert parser.JumpCondOp(label_name="_hrm_1", condition="jez") in ast
Beispiel #9
0
def test_jcond_avoid_loop():
    start_ast = [
        parser.LabelStmt("test"),
        parser.JumpCondOp("test", "ez"),
        parser.OutboxOp(),
        parser.JumpOp("test"),
    ]
    expected_ast = start_ast
    ast = compress_jumps(start_ast)
    assert ast == expected_ast
Beispiel #10
0
def test_convert_iftojump_onlytruebranch_consecutive():
    code = [
        p.IfOp("ez", [p.OutboxOp()], []),
        p.IfOp("ez", [p.OutboxOp()], [])]
    expected_ast = [
        # first IF
        p.JumpCondOp(condition="jez", label_name="_hrm_1"),
        p.JumpOp("_hrm_endif_1"),
        p.LabelStmt("_hrm_1"),
        p.OutboxOp(),
        p.LabelStmt("_hrm_endif_1"),
        # second IF
        p.JumpCondOp(condition="jez", label_name="_hrm_2"),
        p.JumpOp("_hrm_endif_2"),
        p.LabelStmt("_hrm_2"),
        p.OutboxOp(),
        p.LabelStmt("_hrm_endif_2")]
    ast = c.convert_iftojump(code)
    assert ast == expected_ast
Beispiel #11
0
def test_jcond_no_jump_in_false():
    start_ast = [
        parser.AssignOp("inbox", "emp"),
        parser.JumpCondOp(condition="ez", label_name="truebranch"),
        parser.OutboxOp(),
        parser.LabelStmt("truebranch"),
        parser.AddOp("tmp")
    ]

    ast = remove_unreachable_code(start_ast)
    assert ast == start_ast
Beispiel #12
0
def test_compress_jcond_no_compress():
    start_ast = [
        parser.JumpCondOp("label", "ez"),
          parser.OutboxOp(),
          parser.JumpOp("endif"),
        parser.LabelStmt("label"),
          parser.OutboxOp(),
        parser.LabelStmt("endif"),
        parser.OutboxOp()
    ]
    expected_ast = start_ast
    ast = compress_jumps(start_ast)
    assert ast == expected_ast
Beispiel #13
0
def test_no_operation_ignored_in_nonlooping_code():
    start_ast = [
        parser.JumpCondOp("_hrm_1", "jez"),
        parser.IncrOp("a_field"),
        parser.JumpOp("the_fence"),
        parser.LabelStmt("_hrm_1"),
        parser.IncrOp("b_field"),
        parser.LabelStmt("the_fence"),
        parser.IncrOp("c_field")
    ]
    ast = remove_unreachable_code(start_ast)
    assert parser.IncrOp("b_field") in start_ast
    assert parser.IncrOp("b_field") in ast
Beispiel #14
0
def test_dont_keep_only_last_label_on_instruction():
    start_ast = [
        parser.AssignOp(src='inbox', dst='emp'),
        parser.JumpCondOp(label_name='_hrm_1', condition='jez'),
        parser.OutboxOp(),
        parser.JumpOp(label_name="_hrm_endif_1"),
        parser.LabelStmt("_hrm_1"),
        parser.LabelStmt("_hrm_endif_1"),
        parser.AssignOp(src="inbox", dst="emp")
    ]
    ast = remove_unreachable_code(start_ast)
    assert parser.LabelStmt("_hrm_endif_1") in ast
    assert parser.LabelStmt("_hrm_1") in ast
Beispiel #15
0
def test_convert_iftojump_onlyfalsebranch():
    code = [
        p.IfOp("ez", [], [
            p.OutboxOp()
        ])]
    expected_ast = [
        p.JumpCondOp(condition="jez", label_name="_hrm_1"),
        p.OutboxOp(),
        p.JumpOp("_hrm_endif_1"),
        p.LabelStmt("_hrm_1"),
        p.LabelStmt("_hrm_endif_1")
    ]
    ast = c.convert_iftojump(code)
    assert ast == expected_ast
Beispiel #16
0
def test_jcond_lone_label():
    start_ast = [
        parser.LabelStmt("start"),
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp("if", "ez"),
            parser.JumpOp("start"),
            parser.JumpOp("_generated_endif"),
        parser.LabelStmt("if"),
            parser.JumpOp("start"),
        parser.LabelStmt("_generated_endif")
    ]
    expected_ast = [
        parser.LabelStmt("start"),
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp("start", "ez"),
            parser.JumpOp("start"),
            parser.JumpOp("_generated_endif"),
        parser.LabelStmt("if"),
            parser.JumpOp("start"),
        parser.LabelStmt("_generated_endif")
    ]
    ast = compress_jumps(start_ast)
    assert ast == expected_ast
Beispiel #17
0
def test_unreachable_jump_to_lone_label_in_jcond_false_path():
    start_ast = [
        parser.LabelStmt("start"),
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp(condition="ez", label_name="isZero"),
        parser.JumpOp("loneLabel"),
        parser.LabelStmt("isZero"),
        parser.OutboxOp(),
        parser.JumpOp("start"),
        parser.LabelStmt("loneLabel")
    ]
    expected_ast = [
        parser.LabelStmt("start"),
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp(condition="ez", label_name="isZero"),
        parser.JumpOp("_hrm_unreachable"),
        parser.LabelStmt("isZero"),
        parser.OutboxOp(),
        parser.JumpOp("start"),
        parser.LabelStmt("_hrm_unreachable")
    ]
    ast = remove_unreachable_code(start_ast)
    assert ast == expected_ast
Beispiel #18
0
def test_no_duplicated_labels_on_same_point():
    start_ast = [
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpOp("skip"),
        parser.LabelStmt("comehere"),
        parser.OutboxOp(),
        parser.LabelStmt("skip"),
        parser.JumpOp("comehere")
    ]
    ast = remove_unreachable_code(start_ast)

    comehere_counter = sum(1 for ast_item in ast \
                    if type(ast_item) == parser.LabelStmt \
                        and ast_item.label_name == "comehere")
    assert comehere_counter == 1

    start_ast = [
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpOp("comehere"),
        parser.LabelStmt("comehere"),
        parser.OutboxOp(),
        parser.LabelStmt("skip"),
        parser.JumpOp("comehere")
    ]
    ast = remove_unreachable_code(start_ast)

    comehere_counter = sum(1 for ast_item in ast \
                    if type(ast_item) == parser.LabelStmt \
                        and ast_item.label_name == "comehere")
    assert comehere_counter == 1

    start_ast = [
        parser.AssignOp(src="inbox", dst="emp"),
        parser.JumpCondOp("comehere", "jez"),
        parser.JumpOp("comehere"),
        parser.LabelStmt("comehere"),
        parser.OutboxOp(),
        parser.LabelStmt("skip"),
        parser.JumpOp("comehere")
    ]
    ast = remove_unreachable_code(start_ast)

    comehere_counter = sum(1 for ast_item in ast \
                    if type(ast_item) == parser.LabelStmt \
                        and ast_item.label_name == "comehere")
    assert comehere_counter == 1
def compress_jumps(ast):
    compressed_ast = []
    labels_positions, label_at_pos = labels_in_ast(ast)

    for index, ast_item in enumerate(ast):
        if type(ast_item) in [p.JumpOp, p.JumpCondOp]:
            jump_going_nowhere = False
            visited = [False for i in ast]
            _label = ast_item.label_name
            try:
                # get the first position executable by `_label`
                next_pos = labels_positions[_label]
            except KeyError:
                jump_going_nowhere = True
                # even though a jump, either conditional or unconditional, redirects to a label
                # that is _not_ associated to any instruction, removing conditional
                # jumps alters the logic of the program
                compressed_ast.append(ast_item)
                continue

            while type(ast[next_pos]) == p.JumpOp and \
                not visited[next_pos] and \
                not jump_going_nowhere:
                visited[next_pos] = True
                _label = ast[next_pos].label_name
                try:
                    next_pos = labels_positions[_label]
                except KeyError:
                    jump_going_nowhere = True

            if type(ast_item) == p.JumpOp:
                compressed_ast.append(p.JumpOp(_label))
            else:
                compressed_ast.append(p.JumpCondOp(_label, ast_item.condition))
        else:
            compressed_ast.append(ast_item)

    return compressed_ast
def _convert_iftojump(ast, if_counter=0):
    new_ast = []
    for ast_item in ast:
        if type(ast_item) == IfOp:
            if_counter = if_counter + 1
            new_ast.append(
                p.JumpCondOp(condition="j" + ast_item.condition,
                             label_name="_hrm_{0}".format(if_counter)))
            converted_false_branch, counter = _convert_iftojump(
                ast_item.false_branch, if_counter)
            for op in converted_false_branch:
                new_ast.append(op)
            new_ast.append(p.JumpOp("_hrm_endif_{0}".format(if_counter)))
            new_ast.append(p.LabelStmt("_hrm_{0}".format(if_counter)))
            converted_true_branch, counter = _convert_iftojump(
                ast_item.true_branch, counter)
            for op in converted_true_branch:
                new_ast.append(op)
            new_ast.append(p.LabelStmt("_hrm_endif_{0}".format(if_counter)))
            if_counter = counter
        else:
            new_ast.append(ast_item)
    return new_ast, if_counter
def test_jmp():
    code = [parser.JumpCondOp("test", "jez")]
    assert get_assembly(code) == [{"operation": "jez", "operand": {"Label": "test"}}]
def remove_unreachable_code(ast):
    minimized_ast = []
    labels_positions, label_at_pos = labels_in_ast(ast)

    # tree-like structure
    next_pointers = [None for instr in ast]
    visited = [False for instr in ast]
    assoc = [None for instr in ast]
    ic = 0
    jcond_stack = []
    last_was_jmp = False
    prev_ic = 0
    INSTRUCTIONS_NUM = len(ast)
    hrm_unreachable_used = False

    def next_ic_in_jcond_stack(jcond_stack):
        while jcond_stack:
            jcond_ic = jcond_stack.pop()
            _, maybe_ic = next_pointers[jcond_ic]
            if maybe_ic != None:
                return maybe_ic
        return None

    while ic < INSTRUCTIONS_NUM or jcond_stack:
        # if we reached the last instruction of the program,
        # but we still have some unexplored `jcond`s, we must explore
        # these "forgotten" paths too!
        if not (ic < INSTRUCTIONS_NUM) and jcond_stack:
            ic = next_ic_in_jcond_stack(jcond_stack) or ic
            if ic >= INSTRUCTIONS_NUM and not jcond_stack:
                break

        # read instruction
        instr = ast[ic]
        prev_ic = ic
        last_was_jmp = False
        if not visited[ic]:
            # S_notvis
            if type(instr) == p.LabelStmt:
                # S_label
                ic += 1
            else:
                visited[ic] = True
                if type(instr) == p.JumpOp:
                    # S_jmp
                    try:
                        _next_pos = labels_positions[instr.label_name]
                        if last_was_jmp:
                            next_pointers[prev_ic] = (_next_pos, -1)
                        else:
                            next_pointers[ic] = (_next_pos, -1)
                        if assoc[_next_pos] != None:
                            assoc[_next_pos].append(instr.label_name)
                        else:
                            assoc[_next_pos] = [instr.label_name]
                        ic = _next_pos
                        last_was_jmp = True
                    except KeyError:
                        _next_pos = ic
                        if last_was_jmp:
                            next_pointers[prev_ic] = (_next_pos, -1)
                        else:
                            next_pointers[ic] = (_next_pos, -1)
                        ast[ic] = p.JumpOp("_hrm_unreachable")
                        hrm_unreachable_used = True
                        ic = INSTRUCTIONS_NUM
                else:
                    if type(instr) == p.JumpCondOp:
                        # S_jcond
                        jcond_stack.append(ic)
                        try:
                            _jcond_pos = labels_positions[instr.label_name]
                            next_pointers[ic] = (ic + 1, _jcond_pos)
                            ic += 1
                            if assoc[_jcond_pos] != None:
                                assoc[_jcond_pos].append(instr.label_name)
                            else:
                                assoc[_jcond_pos] = [instr.label_name]
                        except KeyError:
                            _jcond_pos = None
                            ast[ic] = p.JumpCondOp("_hrm_unreachable",
                                                   instr.condition)
                            next_pointers[ic] = (ic + 1, _jcond_pos)
                            ic += 1
                            hrm_unreachable_used = True
                    else:
                        # S_normal
                        next_pointers[ic] = (ic + 1, -1)
                        ic += 1
        else:
            if not jcond_stack:
                break
            ic = next_ic_in_jcond_stack(jcond_stack) or ic

    minimized_ast = []
    for index, ast_item in enumerate(ast):
        if visited[index]:
            if assoc[index]:
                for label_name in sorted(set(assoc[index])):
                    minimized_ast.append(p.LabelStmt(label_name))
            minimized_ast.append(ast_item)

    if hrm_unreachable_used:
        minimized_ast.append(p.LabelStmt("_hrm_unreachable"))

    return minimized_ast