diff --git a/ll.py b/ll.py index 31d706a..45cbfa0 100644 --- a/ll.py +++ b/ll.py @@ -137,6 +137,13 @@ def insn2s(insn): return ('bitcast {} {} to {}' .format(ty2s(insn.from_ty), oper2s(insn.oper), ty2s(insn.to_ty))) + elif isinstance(insn, Gep): + return ('getelementptr {}, {} {}, {}' + .format(ty2s(insn.base_ty), ty2s(insn.oper_ty), + oper2s(insn.oper), + ', '.join('{} {}'.format(ty2s(t), oper2s(o)) + for t, o in insn.steps))) + elif isinstance(insn, Zext): return ('zext {} {} to {}' .format(ty2s(insn.from_ty), oper2s(insn.oper), diff --git a/stepper.py b/stepper.py index 1edf7e4..4493084 100644 --- a/stepper.py +++ b/stepper.py @@ -162,7 +162,33 @@ def step(insns, terminator, blocks, stack_frames, ssa_env, global_env, heap, print('bitcast {} {} to {}' .format(ll.ty2s(from_ty), oper_v, ll.ty2s(to_ty))) elif isinstance(next_insn, ll.Gep): - TODO('Gep') + res = 0 + base_ty = next_insn.base_ty + oper_ty = next_insn.oper_ty + oper = next_insn.oper + steps = next_insn.steps + + actual_base_ty = ty2base_ty(base_ty, tdecs) + actual_oper_ty = ty2base_ty(oper_ty, tdecs) + + if not isinstance(actual_oper_ty, ll.PointerType): + err('Type of main operand to getelementptr must be a pointer type. It was {}' + .format(ll.ty2s(actual_oper_ty))) + elif actual_base_ty != actual_oper_ty.inner_ty: + err(('Type of the main operand does not match the type getelementptr' + ' navigates through.\n' + ' Getelementptr type: {}\n' + ' Operand type: {}') + .format(ll.ty2s(actual_base_ty), ll.ty2s(actual_oper_ty.inner_ty))) + else: + oper_v = eval_oper(oper, ssa_env, global_env) + gep_res, formula = handle_gep(oper_v, actual_base_ty, steps, ssa_env, + global_env) + res = gep_res + + # TODO + print('Gep formula: {}' + .format(formula)) elif isinstance(next_insn, ll.Zext): oper = next_insn.oper from_ty = next_insn.from_ty @@ -346,6 +372,57 @@ def eval_icmp(cnd, left, right): return 0 +def handle_gep(starting_location, starting_type, starting_steps, ssa_env, global_env): + def visit(current_location, current_type, current_steps, current_formula): + if len(current_steps) == 0: + return current_location, current_formula + else: + s_ty, s_oper = current_steps[0] + s_oper_v = eval_oper(s_oper, ssa_env, global_env) + next_steps = current_steps[1:] + if isinstance(current_type, ll.StructType): + if not isinstance(s_oper, ll.Const): + err('Index into struct must be a constant. It was: {}' + .format(ll.oper2s(s_oper))) + return current_location, current_formula + ' + ???' + jumps = [base_ty2size(current_type.fields[i]) + for i in range(s_oper_v)] + next_location = current_location + sum(jumps) + next_type = current_type.fields[s_oper_v] + if len(jumps) > 0: + next_formula = ('{} + ({})' + .format(current_formula, + ' + '.join(map(str, jumps)))) + else: + next_formula = ('{} + 0' + .format(current_formula)) + + return visit(next_location, next_type, next_steps, next_formula) + elif isinstance(current_type, ll.ArrayType): + TODO('gep arrays') + return current_location, current_formula + ' + ???' + elif isinstance(current_type, ll.PointerType): + err(('Cannot use getelementptr to traverse pointers.' + ' Use Load, and getelementptr on the result from that' + ' to go through a pointer.')) + return current_location, current_formula + ' + ???' + else: + err('Unknown type to getelementptr on: {}' + .format(ll.ty2s(current_type))) + return current_location, current_formula + ' + ???' + + if len(starting_steps) == 0: + err('There must be at least one stepping argument to a getelementptr instruction') + return 0, '' + s_ty, s_oper = starting_steps[0] + s_oper_v = eval_oper(s_oper, ssa_env, global_env) + size = base_ty2size(starting_type) + next_location = starting_location + s_oper_v * size + formula = ('{} + {} * {}' + .format(starting_location, s_oper_v, size)) + return visit(next_location, starting_type, starting_steps[1:], formula) + + def ty2base_ty(ty, tdecs, seen=[]): if isinstance(ty, ll.SimpleType): return ty @@ -392,14 +469,14 @@ def gogo(): p = parser.LLVMParser() p.build() data = r''' -%T_tigermain = type { i64, i64 } +%T_tigermain = type { i64, i64, {i64, i64}, i64 } define i64 @tigermain (i64 %U_mainSL_8, i64 %U_mainDummy_9) { - %a = alloca i64 %t = alloca %T_tigermain + %a = getelementptr %T_tigermain, %T_tigermain* %t, i32 0, i32 2, i32 1 store i64 9, i64* %a - %b = load i64, i64* %a - ret i64 %b + %r = load i64, i64* %a + ret i64 %r } '''