diff --git a/stepper.py b/stepper.py new file mode 100644 index 0000000..008e09c --- /dev/null +++ b/stepper.py @@ -0,0 +1,143 @@ +import ll +import parser + +def TODO(msg): + print('TODO, not implemented yet at {}' + .format(msg)) + +def err(msg): + print('ERROR: {}' + .format(msg)) + +def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, memory, + tdecs, fdecs, call_res): + if len(insns) == 0: + return terminate(terminator, blocks, stack_frames, ssa_env, global_env, memory) + ssa_target, next_insn = insns[0] + insns_rest = insns[1:] + + # TODO + print('Evaluating {}' + .format(ll.insn2s(next_insn))) + + res = None + if isinstance(next_insn, ll.Binop): + bop = next_insn.bop + ty = next_insn.ty + left = next_insn.left + right = next_insn.right + left_v = eval_oper(left, ssa_env, global_env) + right_v = eval_oper(right, ssa_env, global_env) + res = eval_binop(bop, left_v, right_v) + + # TODO + print('{} {}, {}' + .format(bop, left_v, right_v)) + else: + err('Unknown LLVM instruction: {}' + .format(next_insn)) + + if ssa_target is not None: + if ssa_target in ssa_env: + err('Cannot assign to variable twice: {}' + .format(ssa_target)) + else: + # TODO + print('%{} <- {}' + .format(ssa_target, res)) + ssa_env[ssa_target] = res + + return insns_rest, terminator, blocks, stack_frames, ssa_env, memory, None + + +def terminate(terminator, blocks, stack_frames, ssa_env, global_env, memory): + if isinstance(terminator, ll.Ret): + oper = terminator.oper + if oper is None: + oper_v = None + else: + oper_v = eval_oper(oper, ssa_env, global_env) + if len(stack_frames) == 0: + return [], None, [], [], ssa_env, memory, oper_v + else: + new_insns, new_terminator, new_blocks, new_ssa_env = stack_frames[0] + new_stack_frames = stack_frames[1:] + return (new_insns, new_terminator, new_blocks, new_stack_frames, + new_ssa_env, memory, oper_v) + else: + err('Unknown LLVM terminator: {}' + .format(terminator)) + + +def eval_oper(operand, ssa_env, global_env): + if isinstance(operand, ll.Null): + return 0 + elif isinstance(operand, ll.Const): + return operand.val + elif isinstance(operand, ll.Gid): + TODO('eval_oper Gid') + elif isinstance(operand, ll.Id): + id = operand.val + try: + return ssa_env[id] + except KeyError: + err('Unable to find %{} in environment:\n{}' + .format(id, ssa_env)) + + +def eval_binop(bop, left, right): + if bop == 'add': + return left + right + else: + err('Unknown LLVM Binary operator: {}' + .format(bop)) + + + +def gogo(): + p = parser.LLVMParser() + p.build() + data = r''' +define i64 @tigermain (i64 %U_mainSL_8, i64 %U_mainDummy_9) { + %a = add i64 3, 5 ; please be 8 + %b = add i64 %a, %a + %c = add i64 %a, %b + %d = add i64 100, %c + ret i64 %d +} + ''' + + ast = p.parse(data) + + tdecs = ast.tdecls + fdecs = ast.fdecls + global_env = ast.gdecls + + tigermain = ast.fdecls['tigermain'] + first_block = tigermain.body.first_block + blocks = tigermain.body.named_blocks + insns = first_block.insns + terminator = first_block.terminator + stack_frames = [] + ssa_env = {} + # TODO: memory structure has not been decided yet + memory = [None] + call_res = None + + while True: + (insns, terminator, blocks, + stack_frames, ssa_env, memory, call_res) = step(insns, terminator, blocks, + stack_frames, ssa_env, + global_env, memory, tdecs, + fdecs, call_res) + + if terminator is None: + print('Stepping done! Final ssa_env:\n{}' + .format(ssa_env)) + print('Program resulted in {}'. + format(call_res)) + break + + +if __name__ == '__main__': + gogo()