diff --git a/llvm_emulator/stepper.py b/llvm_emulator/stepper.py index 61cf031..aeb641d 100644 --- a/llvm_emulator/stepper.py +++ b/llvm_emulator/stepper.py @@ -25,6 +25,9 @@ class Garbage(Enum): return '<>' +builtins = ['allocRecord', 'initArray'] + + def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap, tdecs, fdecs, call_res): if len(insns) == 0: @@ -33,6 +36,23 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap, ssa_target, next_insn = insns[0] insns_rest = insns[1:] + def store_in_ssa(res, insns_rest, terminator, blocks, stack_frames, ssa_env, heap, + call_res): + if ssa_target is not None: + if ssa_target in ssa_env: + err('Cannot assign to variable twice: {}' + .format(ssa_target)) + elif res is None: + err('Cannot assign empty value to %{}' + .format(ssa_target)) + else: + # TODO + print('%{} <- {}' + .format(ssa_target, res)) + ssa_env[ssa_target] = res + + return insns_rest, terminator, blocks, stack_frames, ssa_env, heap, call_res + # TODO print('Evaluating {}' .format(ll.insn2s(next_insn))) @@ -128,11 +148,26 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap, arguments_v = [eval_oper(oper, ssa_env, global_env) for ty, oper in arguments] - try: + if callee.val in fdecs: function = fdecs[callee.val] - except KeyError: + elif callee.val in builtins: + res, new_heap, should_exit = emulate_builtin(callee.val, arguments_v, ssa_env, + heap) + if should_exit: + new_insns = [(None, ll.CallResult(res))] + new_terminator = None + new_blocks = {} + new_ssa_env = ssa_env + new_stack_frames = [] + new_call_res = [] + return (new_insns, new_terminator, new_blocks, new_stack_frames, + new_ssa_env, heap, new_call_res) + else: + return store_in_ssa(res, insns_rest, terminator, blocks, stack_frames, + ssa_env, new_heap, call_res) + else: err('Could not find function {} in environment:\n{}' - .format(callee.val, list(fdecs.keys()))) + .format(callee.val, list(fdecs.keys()) + builtins)) return insns_rest, terminator, blocks, stack_frames, ssa_env, heap, call_res parameters = function.parameters @@ -214,20 +249,8 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap, 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)) - elif res is None: - err('Cannot assign empty value to %{}' - .format(ssa_target)) - else: - # TODO - print('%{} <- {}' - .format(ssa_target, res)) - ssa_env[ssa_target] = res - - return insns_rest, terminator, blocks, stack_frames, ssa_env, heap, call_res + return store_in_ssa(res, insns_rest, terminator, blocks, stack_frames, ssa_env, heap, + call_res) def terminate(terminator, blocks, stack_frames, ssa_env, global_env, heap, call_res): @@ -503,6 +526,71 @@ def alloc_globals(gdecls, heap): return global_env +def emulate_builtin(name, arguments_v, ssa_env, heap): + new_heap = heap + res = None + should_exit = False + if name == 'allocRecord': + if len(arguments_v) != 1: + err('Number of arguments to {} should be 1' + .format(name)) + else: + size = max(arguments_v[0], 1) + print('Allocating {} cells' + .format(size)) + res = len(heap) + for i in range(size): + heap.append(Garbage.GARBAGE) + elif name == 'initArray': + if len(arguments_v) != 3: + err('Number of arguments to {} should be 3' + .format(name)) + else: + num_elements = arguments_v[0] + cells_per_element = arguments_v[1] + init_ptr = arguments_v[2] + print('Allocating {} + {} + {} (size + pointer + content) cells' + .format(1, 1, num_elements * cells_per_element)) + struct_begin = len(heap) + heap.append(num_elements) + heap.append(Garbage.GARBAGE) # pointer to array contents + array_begin = len(heap) + heap[struct_begin + 1] = array_begin + init_val = [heap[init_ptr + j] + for j in range(cells_per_element)] + if len(init_val) == 1: + init_val_s = init_val[0] + else: + init_val_s = '{{}}'.format(', '.join(init_val)) + + for i in range(num_elements): + array_last = len(heap) + for j in init_val: + heap.append(j) + + if num_elements <= 0: + array_init_s = 'No elements initialized for zero length array' + else: + array_init_s = ('heap[{}..{}] <- heap[{}] = {}' + .format(array_begin, array_last, + init_ptr, init_val_s)) + # TODO + print('heap[{}] <- {}, heap[{}] <- {}, --- {}' + .format(struct_begin, num_elements, + struct_begin + 1, array_begin, + array_init_s)) + res = struct_begin + elif name in builtins: + TODO('Have not implemented builtin function {}, yet.' + .format(name)) + else: + err('Unknown builtin function {}.' + .format(name)) + return None, heap + + return res, new_heap, should_exit + + def auto_step(ast, function_name='tigermain', function_args=[1234, 5678]): tdecls = ast.tdecls fdecls = ast.fdecls