Beispiel #1
0
void test_instruction_positions_are_computed_in_basic_block_order(void)
{
	struct compilation_unit *cu = compilation_unit_alloc(&method);
	struct basic_block *b1, *b2;
	struct insn *insns[4];
	unsigned long i;

	for (i = 0; i < ARRAY_SIZE(insns); i++)
		insns[i] = alloc_insn(INSN_ADD);

	b1 = get_basic_block(cu, 0, ARRAY_SIZE(insns)/2);
	for (i = 0 ; i < ARRAY_SIZE(insns) / 2; i++)
		bb_add_insn(b1, insns[i]);

	b2 = get_basic_block(cu, ARRAY_SIZE(insns) / 2, ARRAY_SIZE(insns));
	for (i = ARRAY_SIZE(insns) / 2 ; i < ARRAY_SIZE(insns); i++)
		bb_add_insn(b2, insns[i]);

	compute_insn_positions(cu);

	for (i = 0; i < ARRAY_SIZE(insns); i++)
		assert_int_equals(i * 2, insns[i]->lir_pos);

	free_compilation_unit(cu);
}
Beispiel #2
0
void test_no_basic_block_when_offset_out_of_range(void)
{
	struct compilation_unit *cu = compilation_unit_alloc(&method);
	struct basic_block *block = alloc_basic_block(cu, 1, 2);

	list_add_tail(&block->bb_list_node, &cu->bb_list);
	assert_ptr_equals(NULL, find_bb(cu, 0));
	assert_ptr_equals(NULL, find_bb(cu, 2));

	free_compilation_unit(cu);
}
Beispiel #3
0
void test_reload_insn_is_inserted_at_the_beginning_of_the_interval_if_necessary(void)
{
        struct compilation_unit *cu;
        struct insn *insn_array[2];
        struct var_info *r1, *r2;
        struct basic_block *bb;
	struct insn *insn;

        cu = compilation_unit_alloc(&method);
        r1 = get_var(cu, J_INT);
        r2 = get_var(cu, J_INT);

        insn_array[0] = arithmetic_insn(INSN_ADD, r1, r1, r1);
        insn_array[1] = arithmetic_insn(INSN_ADD, r2, r2, r2);

        bb = get_basic_block(cu, 0, 2);
        bb_add_insn(bb, insn_array[0]);
        bb_add_insn(bb, insn_array[1]);

	r1->interval->spill_reload_reg.interval = r1->interval;
	r2->interval->spill_reload_reg.interval = r2->interval;

	r2->interval->flags |= INTERVAL_FLAG_NEED_RELOAD;
	r2->interval->spill_parent = r1->interval;

	compute_insn_positions(cu);
	analyze_liveness(cu);
	insert_spill_reload_insns(cu);

	/*
	 * A reload instruction is inserted at the beginning.
	 */
	insn = list_first_entry(&bb->insn_list, struct insn, insn_list_node);
	assert_ld_insn(INSN_LD_LOCAL, r2->interval->reg, r1->interval->spill_slot, insn);

	/*
	 * Second instruction stays the same.
	 */
	insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node);
	assert_ptr_equals(insn_array[0], insn);

	/*
	 * Last instruction stays the same. 
	 */
	insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node);
	assert_ptr_equals(insn_array[1], insn);

	free_compilation_unit(cu);
}
Beispiel #4
0
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);
}
Beispiel #5
0
void test_spill_insn_is_inserted_at_the_end_of_the_interval_if_necessary(void)
{
        struct compilation_unit *cu;
        struct insn *insn_array[2];
        struct var_info *r1, *r2;
        struct basic_block *bb;
	struct insn *insn;

        cu = compilation_unit_alloc(&method);
        r1 = get_var(cu);
        r2 = get_var(cu);

        insn_array[0] = arithmetic_insn(INSN_ADD, r1, r1, r1);
        insn_array[1] = arithmetic_insn(INSN_ADD, r2, r2, r2);

        bb = get_basic_block(cu, 0, 2);
        bb_add_insn(bb, insn_array[0]);
        bb_add_insn(bb, insn_array[1]);

	r1->interval->need_spill = true;

	compute_insn_positions(cu);
	analyze_liveness(cu);
	insert_spill_reload_insns(cu);

	/*
	 * First instruction stays the same. 
	 */
	insn = list_first_entry(&bb->insn_list, struct insn, insn_list_node);
	assert_ptr_equals(insn_array[0], insn);

	/*
	 * Last instruction stays the same. 
	 */
	insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node);
	assert_ptr_equals(insn_array[1], insn);

	/*
	 * A spill instruction is inserted after the interval end.
	 */ 
	insn = list_next_entry(&insn->insn_list_node, struct insn, insn_list_node);
	assert_st_insn(INSN_ST_LOCAL, r1->interval->spill_slot, r1->interval->reg, insn);

	free_compilation_unit(cu);
}
Beispiel #6
0
void test_empty_interval_is_never_spilled(void)
{
	struct compilation_unit *cu;
	struct basic_block *bb;
	struct var_info *r1;

	cu = compilation_unit_alloc(&method);
	bb = get_basic_block(cu, 0, 2);

	r1 = get_var(cu);
	r1->interval->need_spill = true;

	compute_insn_positions(cu);
	analyze_liveness(cu);
	insert_spill_reload_insns(cu);

	free_compilation_unit(cu);
}
Beispiel #7
0
void test_find_basic_block(void)
{
	struct basic_block *b1;
	struct basic_block *b2;
	struct basic_block *b3;
	struct compilation_unit *cu = compilation_unit_alloc(&method);

	b1 = alloc_basic_block(cu, 0, 3);
	b2 = alloc_basic_block(cu, 3, 5);
	b3 = alloc_basic_block(cu, 5, 6);

	list_add_tail(&b1->bb_list_node, &cu->bb_list);
	list_add_tail(&b2->bb_list_node, &cu->bb_list);
	list_add_tail(&b3->bb_list_node, &cu->bb_list);

	assert_ptr_equals(b1, find_bb(cu, 2));
	assert_ptr_equals(b2, find_bb(cu, 3));
	assert_ptr_equals(b3, find_bb(cu, 5));

	free_compilation_unit(cu);
}
Beispiel #8
0
void test_variable_range_limited_to_basic_block(void)
{
	struct compilation_unit *cu;
	struct var_info *r1, *r2;
	struct basic_block *bb;
	struct insn *insn[3];

	cu = compilation_unit_alloc(&method);
	r1 = get_var(cu);
	r2 = get_var(cu);

	bb = get_basic_block(cu, 0, 3);

	insn[0] = imm_insn(INSN_SETL, 0x01, r1);
	bb_add_insn(bb, insn[0]);

	insn[1] = imm_insn(INSN_SETL, 0x02, r2);
	bb_add_insn(bb, insn[1]);

	insn[2] = arithmetic_insn(INSN_ADD, r1, r2, r2);
	bb_add_insn(bb, insn[2]);

	compute_insn_positions(cu);
	analyze_liveness(cu);

	assert_defines(bb, r1);
	assert_defines(bb, r2);

	assert_live_range(r1->interval, 0, 3);
	assert_live_range(r2->interval, 1, 3);

	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[1], r2->interval->insn_array[0]);
	assert_ptr_equals(insn[2], r2->interval->insn_array[1]);

	free_compilation_unit(cu);
}
Beispiel #9
0
void test_honors_fixed_interval_register_constraint_for_overlapping_intervals(void)
{
	struct compilation_unit *cu;
	struct var_info *v1, *v2;

	cu = compilation_unit_alloc(&method);

	v1 = get_fixed_var(cu, R0);
	v1->interval->range.start = 0;
	v1->interval->range.end   = 2;

	v2 = get_var(cu);
	v2->interval->range.start = 0;
	v2->interval->range.end   = 2;

	allocate_registers(cu);

	assert_int_equals(R0, v1->interval->reg);
	assert_int_equals(R1, v2->interval->reg);

	free_compilation_unit(cu);
}
Beispiel #10
0
static void
assert_emit_target_for_backward_branches(unsigned char expected_prefix,
					 unsigned char expected_opc,
					 enum insn_type insn_type)
{
	struct basic_block *target_bb;
	struct compilation_unit *cu;
	struct var_info *eax, *ebx;

	cu = compilation_unit_alloc(&method);
	eax = get_fixed_var(cu, MACH_REG_EAX);
	ebx = get_fixed_var(cu, MACH_REG_EBX);

	target_bb = get_basic_block(cu, 0, 1);

	bb_add_insn(target_bb, imm_reg_insn(INSN_ADD_IMM_REG, 0x01, eax));
	assert_emits_branch_target(expected_prefix, expected_opc, 0xf8, 0xff, 0xff, 0xff, target_bb, insn_type);

	bb_add_insn(target_bb, imm_reg_insn(INSN_ADD_IMM_REG, 0x02, ebx));
	assert_emits_branch_target(expected_prefix, expected_opc, 0xf5, 0xff, 0xff, 0xff, target_bb, insn_type);

	free_compilation_unit(cu);
}
Beispiel #11
0
static void
assert_backpatches_unresolved_branches_when_emitting_target(
		unsigned char expected_prefix,
		unsigned char expected_opc,
		enum insn_type insn_type)
{
	struct basic_block *target_bb, *branch_bb;
	struct compilation_unit *cu;
	struct var_info *eax;

	cu = compilation_unit_alloc(&method);
	eax = get_fixed_var(cu, MACH_REG_EAX);

	branch_bb = get_basic_block(cu, 0, 1);
	target_bb = get_basic_block(cu, 1, 2);

	bb_add_insn(branch_bb, branch_insn(insn_type, target_bb));
	assert_backpatches_branches(expected_prefix, expected_opc, 0x00, branch_bb, target_bb);

	bb_add_insn(branch_bb, imm_reg_insn(INSN_ADD_IMM_REG, 0x01, eax));
	assert_backpatches_branches(expected_prefix, expected_opc, 0x03, branch_bb, target_bb);

	free_compilation_unit(cu);
}