void test_variable_range_spans_two_basic_blocks(void) { struct basic_block *bb1, *bb2; struct compilation_unit *cu; struct var_info *r1, *r2; struct insn *insn[4]; cu = compilation_unit_alloc(&method); r1 = get_var(cu); r2 = get_var(cu); bb1 = get_basic_block(cu, 0, 2); bb2 = get_basic_block(cu, 2, 4); bb_add_successor(bb1, bb2); insn[2] = imm_insn(INSN_SETL, 0x02, r2); bb_add_insn(bb2, insn[2]); insn[3] = arithmetic_insn(INSN_ADD, r1, r2, r2); bb_add_insn(bb2, insn[3]); insn[0] = imm_insn(INSN_SETL, 0x01, r1); bb_add_insn(bb1, insn[0]); insn[1] = branch_insn(INSN_JMP, bb2); bb_add_insn(bb1, insn[1]); compute_insn_positions(cu); analyze_liveness(cu); assert_defines(bb1, r1); assert_defines(bb2, r2); assert_uses(bb2, r1); assert_live_range(r1->interval, 0, 4); assert_live_range(r2->interval, 2, 4); assert_ptr_equals(insn[0], r1->interval->insn_array[0]); assert_ptr_equals(insn[1], r1->interval->insn_array[1]); assert_ptr_equals(insn[2], r1->interval->insn_array[2]); assert_ptr_equals(insn[3], r1->interval->insn_array[3]); assert_ptr_equals(insn[2], r2->interval->insn_array[0]); assert_ptr_equals(insn[3], r2->interval->insn_array[1]); free_compilation_unit(cu); }
int convert_tableswitch(struct parse_context *ctx) { struct tableswitch_info info; struct tableswitch *table; struct basic_block *master_bb; struct basic_block *default_bb; struct basic_block *b1; struct basic_block *b2; get_tableswitch_info(ctx->code, ctx->offset, &info); ctx->buffer->pos += info.insn_size; default_bb = find_bb(ctx->cu, ctx->offset + info.default_target); if (!default_bb) goto fail_default_bb; master_bb = ctx->bb; b1 = bb_split(master_bb, master_bb->end); b2 = bb_split(b1, master_bb->end); assert(b1 && b2); master_bb->has_branch = true; b1->has_branch = true; b2->has_branch = true; bb_add_successor(master_bb, default_bb ); bb_add_successor(master_bb, b1); bb_add_successor(b1, default_bb ); bb_add_successor(b1, b2); for (unsigned int i = 0; i < info.count; i++) { struct basic_block *target_bb; int32_t target; target = read_s32(info.targets + i * 4); target_bb = find_bb(ctx->cu, ctx->offset + target); if (!bb_successors_contains(b2, target_bb)) bb_add_successor(b2, target_bb); } table = alloc_tableswitch(&info, ctx->cu, b2, ctx->offset); if (!table) return -ENOMEM; struct statement *if_lesser_stmt; struct statement *if_greater_stmt; struct statement *stmt; struct expression *pure_index; pure_index = get_pure_expr(ctx, stack_pop(ctx->bb->mimic_stack)); if_lesser_stmt = branch_if_lesser_stmt(default_bb, pure_index, info.low); if (!if_lesser_stmt) goto fail_lesser_stmt; expr_get(pure_index); if_greater_stmt = branch_if_greater_stmt(default_bb, pure_index, info.high); if (!if_greater_stmt) goto fail_greater_stmt; stmt = alloc_statement(STMT_TABLESWITCH); if (!stmt) goto fail_stmt; expr_get(pure_index); stmt->index = &pure_index->node; stmt->table = table; do_convert_statement(master_bb, if_lesser_stmt, ctx->offset); do_convert_statement(b1, if_greater_stmt, ctx->offset); do_convert_statement(b2, stmt, ctx->offset); return 0; fail_stmt: free_statement(if_greater_stmt); fail_greater_stmt: free_statement(if_lesser_stmt); fail_lesser_stmt: free_tableswitch(table); fail_default_bb: return -1; }
int convert_lookupswitch(struct parse_context *ctx) { struct lookupswitch_info info; struct lookupswitch *table; struct basic_block *master_bb; struct basic_block *default_bb; struct basic_block *b1; get_lookupswitch_info(ctx->code, ctx->offset, &info); ctx->buffer->pos += info.insn_size; default_bb = find_bb(ctx->cu, ctx->offset + info.default_target); if (!default_bb) goto fail_default_bb; master_bb = ctx->bb; b1 = bb_split(master_bb, master_bb->end); assert(b1); b1->has_branch = true; bb_add_successor(master_bb, default_bb ); bb_add_successor(master_bb, b1); for (unsigned int i = 0; i < info.count; i++) { struct basic_block *target_bb; int32_t target; target = read_lookupswitch_target(&info, i); target_bb = find_bb(ctx->cu, ctx->offset + target); if (!bb_successors_contains(b1, target_bb)) bb_add_successor(b1, target_bb); } table = alloc_lookupswitch(&info, ctx->cu, b1, ctx->offset); if (!table) return -ENOMEM; struct statement *if_null_stmt; struct statement *stmt; struct expression *key; struct expression *bsearch; struct expression *pure_bsearch; key = stack_pop(ctx->bb->mimic_stack); bsearch = lookupswitch_bsearch_expr(key, table); if (!bsearch) return -1; pure_bsearch = get_pure_expr(ctx, bsearch); if_null_stmt = branch_if_null_stmt(default_bb, pure_bsearch); if (!if_null_stmt) goto fail_null_stmt; stmt = alloc_statement(STMT_LOOKUPSWITCH_JUMP); if (!stmt) goto fail_stmt; expr_get(pure_bsearch); stmt->lookupswitch_target = &pure_bsearch->node; convert_statement(ctx, if_null_stmt); do_convert_statement(b1, stmt, ctx->offset); return 0; fail_stmt: free_statement(if_null_stmt); fail_null_stmt: free_lookupswitch(table); fail_default_bb: return -1; }