Commit edca1594 authored by qinsoon's avatar qinsoon

for branch2, always generate a fallthrough block to jump to the actually

fallthrough block (because it may be placed somewhereone else)
parent 565fdc2b
......@@ -321,6 +321,16 @@ impl <'a> InstructionSelection {
} else {
unimplemented!();
}
// it is possible that the fallthrough block is scheduled somewhere else
// we need to explicitly jump to it
self.finish_block();
let fallthrough_temp_block = format!("{}_{}_branch_fallthrough", self.current_fv_id, node.id());
self.start_block(fallthrough_temp_block);
let fallthrough_target = f_content.get_block(fallthrough_dest.target).name().unwrap();
self.backend.emit_jmp(fallthrough_target);
},
Instruction_::Select{cond, true_val, false_val} => {
......@@ -2507,20 +2517,20 @@ impl <'a> InstructionSelection {
self.start_block(format!("{}_allocsmall", node.id()));
// alloc small here
let tmp_res = self.emit_alloc_sequence_small(tmp_allocator.clone(), size.clone(), align, node, f_content, f_context, vm);
self.emit_alloc_sequence_small(tmp_allocator.clone(), size.clone(), align, node, f_content, f_context, vm);
self.backend.emit_jmp(blk_alloc_large_end.clone());
// finishing current block
self.finish_block();
// alloc_large:
self.start_block(blk_alloc_large.clone());
let tmp_res = self.emit_alloc_sequence_large(tmp_allocator.clone(), size, align, node, f_content, f_context, vm);
self.emit_alloc_sequence_large(tmp_allocator.clone(), size, align, node, f_content, f_context, vm);
self.finish_block();
// alloc_large_end:
self.start_block(blk_alloc_large_end.clone());
tmp_res
self.get_result_value(node)
}
}
......
......@@ -659,3 +659,283 @@ fn sge_i32_branch() -> VM {
vm
}
#[test]
fn test_branch2_eq_50p_1() {
let lib = testutil::compile_fnc("branch2_eq_50p_1", &branch2_eq_50p_1);
unsafe {
let branch2_eq_50p : libloading::Symbol<unsafe extern fn(u8) -> (u64)> = lib.get(b"branch2_eq_50p_1").unwrap();
let res = branch2_eq_50p(1);
println!("branch2_eq_50p(1) = {}", res);
assert!(res == 1);
let res = branch2_eq_50p(0);
println!("branch2_eq_50p(0) = {}", res);
assert!(res == 0);
}
}
fn branch2_eq_50p_1() -> VM {
let vm = VM::new();
typedef! ((vm) int1 = mu_int(1));
typedef! ((vm) int8 = mu_int(8));
typedef! ((vm) int64 = mu_int(64));
constdef! ((vm) <int8> int8_1 = Constant::Int(1));
constdef! ((vm) <int64> int64_0 = Constant::Int(0));
constdef! ((vm) <int64> int64_1 = Constant::Int(1));
funcsig! ((vm) sig = (int8) -> (int64));
funcdecl! ((vm) <sig> branch2_eq_50p_1);
funcdef! ((vm) <sig> branch2_eq_50p_1 VERSION branch2_eq_50p_1_v1);
// blk entry
block! ((vm, branch2_eq_50p_1_v1) blk_entry);
ssa! ((vm, branch2_eq_50p_1_v1) <int8> cond);
block! ((vm, branch2_eq_50p_1_v1) blk_true);
block! ((vm, branch2_eq_50p_1_v1) blk_false);
consta! ((vm, branch2_eq_50p_1_v1) int8_1_local = int8_1);
ssa! ((vm, branch2_eq_50p_1_v1) <int1> cmp_res);
inst! ((vm, branch2_eq_50p_1_v1) blk_entry_cmp:
cmp_res = CMPOP (CmpOp::EQ) cond int8_1_local
);
inst! ((vm, branch2_eq_50p_1_v1) blk_entry_branch2:
BRANCH2 (cmp_res)
IF (OP 0)
THEN blk_true (vec![]) WITH 0.5f32,
ELSE blk_false (vec![])
);
define_block!((vm, branch2_eq_50p_1_v1) blk_entry(cond) {
blk_entry_cmp,
blk_entry_branch2
});
// blk_true
consta! ((vm, branch2_eq_50p_1_v1) int64_1_local = int64_1);
consta! ((vm, branch2_eq_50p_1_v1) int64_0_local = int64_0);
inst! ((vm, branch2_eq_50p_1_v1) blk_true_ret:
RET (int64_1_local)
);
define_block!((vm, branch2_eq_50p_1_v1) blk_true() {
blk_true_ret
});
// blk_false
inst! ((vm, branch2_eq_50p_1_v1) blk_false_ret:
RET (int64_0_local)
);
define_block!((vm, branch2_eq_50p_1_v1) blk_false() {
blk_false_ret
});
define_func_ver!((vm) branch2_eq_50p_1_v1 (entry: blk_entry) {
blk_entry, blk_true, blk_false
});
vm
}
#[test]
fn test_branch2_eq_50p_2() {
let lib = testutil::compile_fnc("branch2_eq_50p_2", &branch2_eq_50p_2);
unsafe {
let branch2_eq_50p : libloading::Symbol<unsafe extern fn(u8) -> (u64)> = lib.get(b"branch2_eq_50p_2").unwrap();
let res = branch2_eq_50p(1);
println!("branch2_eq_50p(1) = {}", res);
assert!(res == 1);
let res = branch2_eq_50p(0);
println!("branch2_eq_50p(0) = {}", res);
assert!(res == 0);
}
}
fn branch2_eq_50p_2() -> VM {
let vm = VM::new();
typedef! ((vm) int1 = mu_int(1));
typedef! ((vm) int8 = mu_int(8));
typedef! ((vm) int64 = mu_int(64));
constdef! ((vm) <int8> int8_1 = Constant::Int(1));
constdef! ((vm) <int64> int64_0 = Constant::Int(0));
constdef! ((vm) <int64> int64_1 = Constant::Int(1));
funcsig! ((vm) sig = (int8) -> (int64));
funcdecl! ((vm) <sig> branch2_eq_50p_2);
funcdef! ((vm) <sig> branch2_eq_50p_2 VERSION branch2_eq_50p_2_v1);
// blk entry
block! ((vm, branch2_eq_50p_2_v1) blk_entry);
ssa! ((vm, branch2_eq_50p_2_v1) <int8> cond);
block! ((vm, branch2_eq_50p_2_v1) blk_true);
block! ((vm, branch2_eq_50p_2_v1) blk_false);
consta! ((vm, branch2_eq_50p_2_v1) int8_1_local = int8_1);
ssa! ((vm, branch2_eq_50p_2_v1) <int1> cmp_res);
inst! ((vm, branch2_eq_50p_2_v1) blk_entry_cmp:
cmp_res = CMPOP (CmpOp::EQ) cond int8_1_local
);
inst! ((vm, branch2_eq_50p_2_v1) blk_entry_branch2:
BRANCH2 (cmp_res)
IF (OP 0)
THEN blk_true (vec![]) WITH 0.5f32,
ELSE blk_false (vec![])
);
define_block!((vm, branch2_eq_50p_2_v1) blk_entry(cond) {
blk_entry_cmp,
blk_entry_branch2
});
// blk_true
consta! ((vm, branch2_eq_50p_2_v1) int64_1_local = int64_1);
consta! ((vm, branch2_eq_50p_2_v1) int64_0_local = int64_0);
inst! ((vm, branch2_eq_50p_2_v1) blk_true_ret:
RET (int64_1_local)
);
define_block!((vm, branch2_eq_50p_2_v1) blk_true() {
blk_true_ret
});
// blk_false
inst! ((vm, branch2_eq_50p_2_v1) blk_false_ret:
RET (int64_0_local)
);
define_block!((vm, branch2_eq_50p_2_v1) blk_false() {
blk_false_ret
});
define_func_ver!((vm) branch2_eq_50p_2_v1 (entry: blk_entry) {
blk_entry, blk_false, blk_true
});
vm
}
#[test]
fn test_branch2_high_prob_branch_cannot_fallthrough() {
let lib = testutil::compile_fnc("branch2", &branch2_high_prob_branch_cannot_fallthrough);
unsafe {
let branch2 : libloading::Symbol<unsafe extern fn(u8) -> (u64)> = lib.get(b"branch2").unwrap();
let res = branch2(1);
println!("branch2(1) = {}", res);
assert!(res == 1);
let res = branch2(0);
println!("branch2(0) = {}", res);
assert!(res == 0);
}
}
fn branch2_high_prob_branch_cannot_fallthrough() -> VM {
let vm = VM::new();
typedef! ((vm) int1 = mu_int(1));
typedef! ((vm) int8 = mu_int(8));
typedef! ((vm) int64 = mu_int(64));
constdef! ((vm) <int8> int8_1 = Constant::Int(1));
constdef! ((vm) <int64> int64_0 = Constant::Int(0));
constdef! ((vm) <int64> int64_1 = Constant::Int(1));
funcsig! ((vm) sig = (int8) -> (int64));
funcdecl! ((vm) <sig> branch2);
funcdef! ((vm) <sig> branch2 VERSION branch2_v1);
// blk entry
block! ((vm, branch2_v1) blk_entry);
ssa! ((vm, branch2_v1) <int8> blk_entry_arg);
consta! ((vm, branch2_v1) int64_0_local = int64_0);
consta! ((vm, branch2_v1) int64_1_local = int64_1);
// cmp1_res = EQ 0 1
ssa! ((vm, branch2_v1) <int1> cmp1_res);
inst! ((vm, branch2_v1) blk_entry_cmp:
cmp1_res = CMPOP (CmpOp::EQ) int64_0_local int64_1_local
);
// branch2 cmp1_res blk_true blk_check(blk_entry_arg)
block! ((vm, branch2_v1) blk_true);
block! ((vm, branch2_v1) blk_check);
inst! ((vm, branch2_v1) blk_entry_branch2:
BRANCH2 (cmp1_res, blk_entry_arg)
IF (OP 0)
THEN blk_true (vec![]) WITH 0.6f32,
ELSE blk_check (vec![1])
);
define_block!((vm, branch2_v1) blk_entry (blk_entry_arg) {
blk_entry_cmp, blk_entry_branch2
});
// blk_check
ssa! ((vm, branch2_v1) <int8> blk_check_arg);
// cmp2_res = EQ blk_check_arg 1
ssa! ((vm, branch2_v1) <int1> cmp2_res);
consta! ((vm, branch2_v1) int8_1_local = int8_1);
inst! ((vm, branch2_v1) blk_check_cmp:
cmp2_res = CMPOP (CmpOp::EQ) blk_check_arg int8_1_local
);
// branch2 cmp2_res blk_true blk_false
block! ((vm, branch2_v1) blk_false);
inst! ((vm, branch2_v1) blk_check_branch2:
BRANCH2 (cmp2_res)
IF (OP 0)
THEN blk_true (vec![]) WITH 0.6f32,
ELSE blk_false (vec![])
);
define_block!((vm, branch2_v1) blk_check (blk_check_arg) {
blk_check_cmp, blk_check_branch2
});
// blk_true
consta! ((vm, branch2_v1) int64_1_local = int64_1);
consta! ((vm, branch2_v1) int64_0_local = int64_0);
inst! ((vm, branch2_v1) blk_true_ret:
RET (int64_1_local)
);
define_block!((vm, branch2_v1) blk_true() {
blk_true_ret
});
// blk_false
inst! ((vm, branch2_v1) blk_false_ret:
RET (int64_0_local)
);
define_block!((vm, branch2_v1) blk_false() {
blk_false_ret
});
define_func_ver!((vm) branch2_v1 (entry: blk_entry) {
blk_entry, blk_check, blk_true, blk_false
});
vm
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment