GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

Commit 91515294 authored by Isaac Oscar Gariano's avatar Isaac Oscar Gariano

Merge branch 'develop' of gitlab.anu.edu.au:mu/mu-impl-fast into develop

parents 13805e3a d0129c29
......@@ -29,8 +29,9 @@ are not compliant to Mu spec.
## Building
You will need:
* rust version 1.18 (03fc9d622 2017-06-06)
* rust version 1.19 (0ade33941 2017-07-17)
* clang 4.0+
* cmake 3.8+ (we do not depend on cmake, but some Rust crates use it)
* internet connection (as Rust will download dependencies)
To build Zebu with release build,
......
......@@ -139,6 +139,14 @@ impl MuType {
}
}
/// is this type an integer type?
pub fn is_int(&self) -> bool {
match self.v {
MuType_::Int(_) => true,
_ => false
}
}
/// is this type a floating point type? (float/double)
pub fn is_fp(&self) -> bool {
match self.v {
......
......@@ -1896,6 +1896,48 @@ impl ASMCodeGen {
)
}
/// emits a move instruction (reg64/32 -> fpr)
fn internal_mov_bitcast_fpr_r(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
trace!("emit: {} {} -> {}", inst, src, dest);
let (reg1, id1, loc1) = self.prepare_reg(src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_fpreg(dest, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{}", inst, reg1, reg2);
self.add_asm_inst(
asm,
linked_hashmap!{
id2 => vec![loc2]
},
linked_hashmap!{
id1 => vec![loc1]
},
false
)
}
/// emits a move instruction (fpr -> reg64/32)
fn internal_mov_bitcast_r_fpr(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
trace!("emit: {} {} -> {}", inst, src, dest);
let (reg1, id1, loc1) = self.prepare_fpreg(src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{}", inst, reg1, reg2);
self.add_asm_inst(
asm,
linked_hashmap!{
id2 => vec![loc2]
},
linked_hashmap!{
id1 => vec![loc1]
},
false
)
}
/// emits a move instruction (reg -> reg)
fn internal_mov_r_r(&mut self, inst: &str, dest: &P<Value>, src: &P<Value>) {
let len = check_op_len(dest);
......@@ -2241,6 +2283,28 @@ impl ASMCodeGen {
)
}
/// emits a truncate instruction (fpreg -> fpreg)
fn internal_fp_trunc(&mut self, inst: &str, dest: Reg, src: Reg) {
let inst = inst.to_string();
trace!("emit: {} {} -> {}", inst, src, dest);
let (reg1, id1, loc1) = self.prepare_fpreg(src, inst.len() + 1);
let (reg2, id2, loc2) = self.prepare_fpreg(dest, inst.len() + 1 + reg1.len() + 1);
let asm = format!("{} {},{}", inst, reg1, reg2);
self.add_asm_inst(
asm,
linked_hashmap!{
id2 => vec![loc2]
},
linked_hashmap!{
id1 => vec![loc1]
},
false
)
}
/// emits a store instruction to store a spilled register
fn emit_spill_store_gpr(&mut self, dest: Mem, src: Reg) {
self.internal_mov_mem_r("mov", dest, src, true, false)
......@@ -2447,23 +2511,19 @@ impl CodeGenerator for ASMCodeGen {
}
fn emit_mov_fpr_r64(&mut self, dest: Reg, src: Reg) {
trace!("emit: movq {} -> {}", src, dest);
self.internal_mov_bitcast_fpr_r("movq", dest, src)
}
let (reg1, id1, loc1) = self.prepare_reg(src, 5);
let (reg2, id2, loc2) = self.prepare_fpreg(dest, 5 + reg1.len() + 1);
fn emit_mov_fpr_r32(&mut self, dest: Reg, src: Reg) {
self.internal_mov_bitcast_fpr_r("movd", dest, src)
}
let asm = format!("movq {},{}", reg1, reg2);
fn emit_mov_r64_fpr(&mut self, dest: Reg, src: Reg) {
self.internal_mov_bitcast_r_fpr("movq", dest, src)
}
self.add_asm_inst(
asm,
linked_hashmap!{
id2 => vec![loc2]
},
linked_hashmap!{
id1 => vec![loc1]
},
false
)
fn emit_mov_r32_fpr(&mut self, dest: Reg, src: Reg) {
self.internal_mov_bitcast_r_fpr("movd", dest, src)
}
fn emit_mov_r_imm(&mut self, dest: &P<Value>, src: i32) {
......@@ -3508,6 +3568,15 @@ impl CodeGenerator for ASMCodeGen {
self.internal_fpr_to_gpr("cvttss2si", dest, src);
}
// convert - fp trunc
fn emit_cvtsd2ss_f32_f64(&mut self, dest: Reg, src: Reg) {
self.internal_fp_trunc("cvtsd2ss", dest, src)
}
fn emit_cvtss2sd_f64_f32(&mut self, dest: Reg, src: Reg) {
self.internal_fp_trunc("cvtss2sd", dest, src)
}
// unpack low data - interleave low byte
fn emit_punpckldq_f64_mem128(&mut self, dest: Reg, src: Mem) {
trace!("emit: punpckldq {} {} -> {}", src, dest, dest);
......
......@@ -70,8 +70,11 @@ pub trait CodeGenerator {
// mov imm64 to r64
fn emit_mov_r64_imm64(&mut self, dest: Reg, src: i64);
// mov r64 to fpr
// bitcast between int and floatpoint of same length
fn emit_mov_fpr_r64(&mut self, dest: Reg, src: Reg);
fn emit_mov_fpr_r32(&mut self, dest: Reg, src: Reg);
fn emit_mov_r64_fpr(&mut self, dest: Reg, src: Reg);
fn emit_mov_r32_fpr(&mut self, dest: Reg, src: Reg);
fn emit_mov_r_imm(&mut self, dest: Reg, src: i32);
fn emit_mov_r_mem(&mut self, dest: Reg, src: Mem); // load
......@@ -302,6 +305,10 @@ pub trait CodeGenerator {
fn emit_cvtsi2ss_f32_r(&mut self, dest: Reg, src: Reg);
fn emit_cvtss2si_r_f32(&mut self, dest: Reg, src: Reg);
// fp trunc
fn emit_cvtsd2ss_f32_f64(&mut self, dest: Reg, src: Reg);
fn emit_cvtss2sd_f64_f32(&mut self, dest: Reg, src: Reg);
// used for unsigned int to fp conversion
fn emit_cvttsd2si_r_f64(&mut self, dest: Reg, src: Reg);
......
......@@ -1349,7 +1349,94 @@ impl<'a> InstructionSelection {
panic!("expect double or float")
}
}
_ => unimplemented!()
op::ConvOp::FPTRUNC => {
let tmp_res = self.get_result_value(node);
assert!(
self.match_fpreg(op),
"unexpected op (expected fpreg): {}",
op
);
let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);
if from_ty.is_double() && to_ty.is_float() {
self.backend.emit_cvtsd2ss_f32_f64(&tmp_res, &tmp_op);
} else {
panic!(
"FPTRUNC from {} to {} is not supported \
(only support FPTRUNC from double to float)",
from_ty,
to_ty
);
}
}
op::ConvOp::FPEXT => {
let tmp_res = self.get_result_value(node);
assert!(
self.match_fpreg(op),
"unexpected op (expected fpreg): {}",
op
);
let tmp_op = self.emit_fpreg(op, f_content, f_context, vm);
if from_ty.is_float() && to_ty.is_double() {
self.backend.emit_cvtss2sd_f64_f32(&tmp_res, &tmp_op);
} else {
panic!(
"FPEXT from {} to {} is not supported\
(only support FPEXT from float to double)",
from_ty,
to_ty
);
}
}
op::ConvOp::BITCAST => {
let tmp_res = self.get_result_value(node);
let tmp_op = if self.match_fpreg(op) {
self.emit_fpreg(op, f_content, f_context, vm)
} else if self.match_ireg(op) {
self.emit_ireg(op, f_content, f_context, vm)
} else {
panic!("expected op for BITCAST (expected ireg/fpreg): {}", op)
};
let ref from_ty = tmp_op.ty;
let ref to_ty = tmp_res.ty;
let from_ty_size = vm.get_backend_type_size(from_ty.id());
let to_ty_size = vm.get_backend_type_size(to_ty.id());
assert!(
from_ty_size == to_ty_size,
"BITCAST only works between int/fp of same length"
);
assert!(
from_ty_size == 8 || from_ty_size == 4,
"BITCAST only works for int32/float or int64/double"
);
if from_ty.is_fp() && to_ty.is_int() {
if from_ty_size == 8 {
self.backend.emit_mov_r64_fpr(&tmp_res, &tmp_op);
} else if from_ty_size == 4 {
self.backend.emit_mov_r32_fpr(&tmp_res, &tmp_op);
} else {
unreachable!()
}
} else if from_ty.is_int() && to_ty.is_fp() {
if from_ty_size == 8 {
self.backend.emit_mov_fpr_r64(&tmp_res, &tmp_op);
} else if from_ty_size == 4 {
self.backend.emit_mov_fpr_r32(&tmp_res, &tmp_op);
} else {
unreachable!()
}
} else {
panic!(
"expected BITCAST between int and fp,\
found {} and {}",
from_ty,
to_ty
)
}
}
}
}
......
......@@ -311,7 +311,7 @@ pub fn start_trace(
lo_space: Arc<FreeListSpace>
) {
// creates root deque
let (mut worker, stealer) = deque();
let (worker, stealer) = deque();
while !work_stack.is_empty() {
worker.push(work_stack.pop().unwrap());
......
......@@ -104,6 +104,17 @@ fn link_executable_internal(
cc.arg("-lm");
cc.arg("-lpthread");
cc.arg("-lz");
} else if cfg!(target_os = "macos") {
cc.arg("-liconv");
cc.arg("-framework");
cc.arg("Security");
cc.arg("-framework");
cc.arg("CoreFoundation");
cc.arg("-lz");
cc.arg("-lSystem");
cc.arg("-lresolv");
cc.arg("-lc");
cc.arg("-lm");
}
// all the source code
......
......@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#![allow(unused_macros)]
macro_rules! typedef {
// int, floating point
(($vm: expr) $name: ident = mu_int($len: expr)) => {
......
......@@ -114,3 +114,57 @@ fn truncate_then_call() -> VM {
vm
}
#[test]
fn test_bitcast_f32_to_u32() {
let lib = linkutils::aot::compile_fnc("bitcast_f32_to_u32", &bitcast_f32_to_u32);
unsafe {
use std::f32;
let bitcast_f32_to_u32: libloading::Symbol<unsafe extern "C" fn(f32) -> u32> =
lib.get(b"bitcast_f32_to_u32").unwrap();
let res = bitcast_f32_to_u32(f32::MAX);
println!("bitcast_f32_to_u32(f32::MAX) = {}", res);
assert!(res == 2139095039u32);
let res = bitcast_f32_to_u32(3.1415926f32);
println!("bitcast_f32_to_u32(PI) = {}", res);
assert!(res == 1078530010u32);
}
}
fn bitcast_f32_to_u32() -> VM {
let vm = VM::new();
typedef! ((vm) float = mu_float);
typedef! ((vm) u32 = mu_int(32));
funcsig! ((vm) sig = (float) -> (u32));
funcdecl! ((vm) <sig> bitcast_f32_to_u32);
funcdef! ((vm) <sig> bitcast_f32_to_u32 VERSION bitcast_f32_to_u32_v1);
// blk entry
block! ((vm, bitcast_f32_to_u32_v1) blk_entry);
ssa! ((vm, bitcast_f32_to_u32_v1) <float> f);
ssa! ((vm, bitcast_f32_to_u32_v1) <u32> i);
inst! ((vm, bitcast_f32_to_u32_v1) blk_entry_bitcast:
i = CONVOP (ConvOp::BITCAST) <float u32> f
);
inst! ((vm, bitcast_f32_to_u32_v1) blk_entry_ret:
RET (i)
);
define_block!((vm, bitcast_f32_to_u32_v1) blk_entry(f) {
blk_entry_bitcast, blk_entry_ret
});
define_func_ver!((vm) bitcast_f32_to_u32_v1 (entry: blk_entry) {
blk_entry
});
vm
}
\ No newline at end of file
......@@ -875,3 +875,113 @@ fn fp_arraysum() -> VM {
vm
}
#[test]
fn test_double_to_float() {
let lib = linkutils::aot::compile_fnc("double_to_float", &double_to_float);
unsafe {
use std::f64;
let double_to_float: libloading::Symbol<unsafe extern "C" fn(f64) -> f32> =
lib.get(b"double_to_float").unwrap();
let res = double_to_float(0f64);
println!("double_fo_float(0) = {}", res);
assert!(res == 0f32);
let res = double_to_float(1f64);
println!("double_fo_float(1) = {}", res);
assert!(res == 1f32);
let res = double_to_float(f64::MAX);
println!("double_to_float(f64::MAX) = {}", res);
assert!(res.is_infinite());
}
}
fn double_to_float() -> VM {
let vm = VM::new();
typedef! ((vm) double = mu_double);
typedef! ((vm) float = mu_float);
funcsig! ((vm) sig = (double) -> (float));
funcdecl! ((vm) <sig> double_to_float);
funcdef! ((vm) <sig> double_to_float VERSION double_to_float_v1);
// blk entry
block! ((vm, double_to_float_v1) blk_entry);
ssa! ((vm, double_to_float_v1) <double> d);
ssa! ((vm, double_to_float_v1) <float> f);
inst! ((vm, double_to_float_v1) blk_entry_fptrunc:
f = CONVOP (ConvOp::FPTRUNC) <double float> d
);
inst! ((vm, double_to_float_v1) blk_entry_ret:
RET (f)
);
define_block!((vm, double_to_float_v1) blk_entry(d) {
blk_entry_fptrunc, blk_entry_ret
});
define_func_ver!((vm) double_to_float_v1 (entry: blk_entry) {
blk_entry
});
vm
}
#[test]
fn test_float_to_double() {
let lib = linkutils::aot::compile_fnc("float_to_double", &float_to_double);
unsafe {
let float_to_double: libloading::Symbol<unsafe extern "C" fn(f32) -> f64> =
lib.get(b"float_to_double").unwrap();
let res = float_to_double(0f32);
println!("float_to_double(0) = {}", 0);
assert!(res == 0f64);
let res = float_to_double(1f32);
println!("float_to_double(1) = {}", 0);
assert!(res == 1f64);
}
}
fn float_to_double() -> VM {
let vm = VM::new();
typedef! ((vm) double = mu_double);
typedef! ((vm) float = mu_float);
funcsig! ((vm) sig = (float) -> (double));
funcdecl! ((vm) <sig> float_to_double);
funcdef! ((vm) <sig> float_to_double VERSION float_to_double_v1);
// blk entry
block! ((vm, float_to_double_v1) blk_entry);
ssa! ((vm, float_to_double_v1) <double> d);
ssa! ((vm, float_to_double_v1) <float> f);
inst! ((vm, float_to_double_v1) blk_entry_fpext:
d = CONVOP (ConvOp::FPEXT) <float double> f
);
inst! ((vm, float_to_double_v1) blk_entry_ret:
RET (d)
);
define_block!((vm, float_to_double_v1) blk_entry(f) {
blk_entry_fpext, blk_entry_ret
});
define_func_ver!((vm) float_to_double_v1 (entry: blk_entry) {
blk_entry
});
vm
}
......@@ -24,12 +24,6 @@ macro_rules! assert_type (
)
);
macro_rules! println_type (
($test:expr) => (
println!("{}", $test)
)
);
/// create one of each MuType
fn create_types() -> Vec<P<MuType>> {
let mut types = vec![];
......
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