WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

Commit edca1594 authored by qinsoon's avatar qinsoon
Browse files

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 { ...@@ -321,6 +321,16 @@ impl <'a> InstructionSelection {
} else { } else {
unimplemented!(); 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} => { Instruction_::Select{cond, true_val, false_val} => {
...@@ -2507,20 +2517,20 @@ impl <'a> InstructionSelection { ...@@ -2507,20 +2517,20 @@ impl <'a> InstructionSelection {
self.start_block(format!("{}_allocsmall", node.id())); self.start_block(format!("{}_allocsmall", node.id()));
// alloc small here // 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()); self.backend.emit_jmp(blk_alloc_large_end.clone());
// finishing current block // finishing current block
self.finish_block(); self.finish_block();
// alloc_large: // alloc_large:
self.start_block(blk_alloc_large.clone()); 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(); self.finish_block();
// alloc_large_end: // alloc_large_end:
self.start_block(blk_alloc_large_end.clone()); self.start_block(blk_alloc_large_end.clone());
tmp_res self.get_result_value(node)
} }
} }
......
...@@ -659,3 +659,283 @@ fn sge_i32_branch() -> VM { ...@@ -659,3 +659,283 @@ fn sge_i32_branch() -> VM {
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