Commit 99a65c69 authored by Yi Lin's avatar Yi Lin

Merge branch 'develop' into 'master'

merge with develop: support for int128, remove unnecessary RwLocks, changed CI stages, capable of running SOM interpreter

See merge request !8
parents bc43c9ea f28b96b1
Pipeline #521 passed with stages
in 58 minutes and 15 seconds
......@@ -11,8 +11,10 @@ Cargo.lock
*.pyc
*.o
*.dylib
mu-client-pypy
**mu-client-pypy**
**RPySOM**
.gitignore
cmake-build-debug/*
Notes/*
CMakeLists.txt
\ No newline at end of file
CMakeLists.txt
*.iml
# This file is a template, and might need editing before it works on your project.
# Unofficial language image. Look for the different tagged releases at:
# https://hub.docker.com/r/scorpil/rust/tags/
image: "qinsoon/ubuntu-zebu-test:lastest"
image: "qinsoon/ubuntu-zebu-test:latest"
# Optional: Pick zero or more services to be used on all builds.
# Only needed when using a docker container to run your tests in.
......@@ -18,36 +18,60 @@ image: "qinsoon/ubuntu-zebu-test:lastest"
#- apt-get install -yqq --no-install-recommends build-essential
# Use cargo to test the project
cache:
key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME"
paths:
- .cargo/registry/cache
- .cargo/registry/index
- target
- Cargo.lock
# cache:
# key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME"
# paths:
# - .cargo/registry/cache
# - .cargo/registry/index
# - target
# - Cargo.lock
stages:
- build
- test
build_vm:
stage: build
script:
- rustc --version
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo build --release
build_test:
stage: build
script:
- rustc --version
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test --release --no-run
artifacts:
paths:
- target/release/libmu.so
- target/release/libmu.a
before_script:
- time CARGO_HOME=.cargo RUST_BACKTRACE=1 CC=clang cargo test --no-run
- export PATH=$PATH:/root/.cargo/bin
- export MU_ZEBU=$CI_PROJECT_DIR
- export ZEBU_BUILD=release
- export CARGO_HOME=.cargo
- export CC=clang
test:cargo:api:
stage: test
script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_api 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_api 2> /dev/null
test:cargo:ir:
stage: test
script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_ir 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_ir 2> /dev/null
test:cargo:compiler:
stage: test
script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_compiler 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_compiler 2> /dev/null
test:cargo:runtime:
stage: test
script:
- CARGO_HOME=.cargo RUST_BACKTRACE=1 RUST_TEST_THREADS=1 CC=clang cargo test test_runtime 2> /dev/null
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 cargo test --release test_runtime 2> /dev/null
testjit:milestones:
stage: test
......@@ -98,17 +122,24 @@ testjit:otherops:
testjit:rpython:
stage: test
script:
- if [ -d "tests/test_jit/mu-client-pypy" ]; then rm -Rf tests/test_jit/mu-client-pypy; fi
- git clone https://gitlab.anu.edu.au/mu/mu-client-pypy.git tests/test_jit/mu-client-pypy
- cd tests/test_jit/mu-client-pypy
- git checkout mu-rewrite
- git apply pypy.patch
- cd $CI_PROJECT_DIR/tests/test_jit
- LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy MU_ZEBU=$CI_PROJECT_DIR pytest test_rpython*.py -v
cache:
key: "$CI_BUILD_STAGE/$CI_BUILD_REF_NAME"
paths:
- .cargo/registry/cache
- .cargo/registry/index
- target
- Cargo.lock
- tests/test_jit/mu-client-pypy
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy pytest test_rpython*.py -v
testjit:som:
stage: test
script:
- if [ -d "tests/test_jit/RPySOM" ]; then rm -Rf tests/test_jit/RPySOM; fi
- git clone https://github.com/microvm/RPySOM.git tests/test_jit/RPySOM
- cd tests/test_jit/RPySOM; git submodule init; git submodule update; cd $CI_PROJECT_DIR
- if [ -d "tests/test_jit/mu-client-pypy" ]; then rm -Rf tests/test_jit/mu-client-pypy; fi
- git clone https://gitlab.anu.edu.au/mu/mu-client-pypy.git tests/test_jit/mu-client-pypy
- cd tests/test_jit/mu-client-pypy
- git checkout mu-rewrite
- git apply pypy.patch
- cd $CI_PROJECT_DIR/tests/test_jit
- MU_LOG_LEVEL=info LD_LIBRARY_PATH=. RUST_BACKTRACE=1 PYTHONPATH=mu-client-pypy:RPySOM/src RPYSOM=RPySOM pytest test_som.py -v
\ No newline at end of file
......@@ -33,4 +33,5 @@ rustc-serialize = "*"
time = "0.1.34"
maplit = "0.1.4"
docopt = "0.6"
petgraph = "0.4.1"
\ No newline at end of file
petgraph = "0.4.1"
extprim = "*"
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="RUST_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python">
<configuration sdkName="" />
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/benches" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Rust &lt;mu&gt;" level="project" />
<orderEntry type="library" name="Cargo &lt;mu&gt;" level="project" />
</component>
</module>
\ No newline at end of file
......@@ -7,14 +7,13 @@ use ir_semantics;
use utils::vec_utils;
use std::fmt;
use std::sync::RwLock;
#[derive(Debug)]
// this implements RustcEncodable, RustcDecodable, Clone and Display
pub struct Instruction {
pub hdr: MuEntityHeader,
pub value : Option<Vec<P<Value>>>,
pub ops : RwLock<Vec<P<TreeNode>>>,
pub ops : Vec<P<TreeNode>>,
pub v: Instruction_
}
......@@ -27,7 +26,7 @@ impl Encodable for Instruction {
try!(s.emit_struct_field("hdr", 0, |s| self.hdr.encode(s)));
try!(s.emit_struct_field("value", 1, |s| self.value.encode(s)));
let ops = &self.ops.read().unwrap();
let ref ops = self.ops;
try!(s.emit_struct_field("ops", 2, |s| ops.encode(s)));
try!(s.emit_struct_field("v", 3, |s| self.v.encode(s)));
......@@ -50,7 +49,7 @@ impl Decodable for Instruction {
Ok(Instruction{
hdr: hdr,
value: value,
ops: RwLock::new(ops),
ops: ops,
v: v
})
})
......@@ -62,13 +61,20 @@ impl Clone for Instruction {
Instruction {
hdr: self.hdr.clone(),
value: self.value.clone(),
ops: RwLock::new(self.ops.read().unwrap().clone()),
ops: self.ops.clone(),
v: self.v.clone()
}
}
}
impl Instruction {
pub fn clone_with_id(&self, new_id: MuID) -> Instruction {
let mut clone = self.clone();
clone.hdr = self.hdr.clone_with_id(new_id);
clone
}
pub fn has_exception_clause(&self) -> bool {
ir_semantics::is_potentially_excepting_instruction(&self.v)
}
......@@ -133,7 +139,7 @@ impl Instruction {
impl fmt::Display for Instruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let ops = &self.ops.read().unwrap();
let ref ops = self.ops;
if self.value.is_some() {
write!(f, "{} = {}", vec_utils::as_str(self.value.as_ref().unwrap()), self.v.debug_str(ops))
} else {
......
......@@ -242,7 +242,7 @@ impl MuFunctionVersion {
for inst in block_content.body.iter() {
match inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap();
let ref ops = inst.ops;
match inst.v {
Instruction_::ExprCall{ref data, ..}
......@@ -358,6 +358,16 @@ impl FunctionContent {
None => panic!("cannot find block #{}", id)
}
}
pub fn get_block_by_name(&self, name: String) -> &Block {
for block in self.blocks.values() {
if block.name().unwrap() == name {
return block;
}
}
panic!("cannot find block {}", name)
}
}
#[derive(Default, Debug, RustcEncodable, RustcDecodable)]
......@@ -535,7 +545,7 @@ impl BlockContent {
match last_inst.v {
TreeNode_::Instruction(ref inst) => {
let ops = inst.ops.read().unwrap();
let ref ops = inst.ops;
match inst.v {
Instruction_::Return(_)
| Instruction_::ThreadExit
......@@ -702,16 +712,17 @@ impl Value {
_ => false
}
}
pub fn is_int_reg(&self) -> bool {
pub fn is_reg(&self) -> bool {
match self.v {
Value_::SSAVar(_) => {
if is_scalar(&self.ty) && !is_fp(&self.ty) {
true
} else {
false
}
}
Value_::SSAVar(_) => true,
_ => false
}
}
pub fn is_const(&self) -> bool {
match self.v {
Value_::Constant(_) => true,
_ => false
}
}
......@@ -724,21 +735,6 @@ impl Value {
})
}
pub fn is_fp_reg(&self) -> bool {
match self.v {
Value_::SSAVar(_) => {
if is_scalar(&self.ty) && is_fp(&self.ty) {
true
} else {
false
}
},
Value_::Constant(Constant::Double(_)) => true,
Value_::Constant(Constant::Float(_)) => true,
_ => false
}
}
pub fn is_int_const(&self) -> bool {
match self.v {
Value_::Constant(Constant::Int(_)) => true,
......@@ -761,6 +757,13 @@ impl Value {
_ => None
}
}
pub fn extract_memory_location(&self) -> Option<MemoryLocation> {
match self.v {
Value_::Memory(ref loc) => Some(loc.clone()),
_ => None
}
}
}
const DISPLAY_ID : bool = true;
......@@ -826,7 +829,10 @@ pub struct SSAVarEntry {
use_count: AtomicUsize,
// this field is only used during TreeGeneration pass
expr: Option<Instruction>
expr: Option<Instruction>,
// some ssa vars (such as int128) needs to be split into smaller vars
split: Option<Vec<P<Value>>>
}
impl Encodable for SSAVarEntry {
......@@ -836,6 +842,7 @@ impl Encodable for SSAVarEntry {
let count = self.use_count.load(Ordering::SeqCst);
try!(s.emit_struct_field("use_count", 1, |s| s.emit_usize(count)));
try!(s.emit_struct_field("expr", 2, |s| self.expr.encode(s)));
try!(s.emit_struct_field("split", 3, |s| self.split.encode(s)));
Ok(())
})
}
......@@ -844,14 +851,16 @@ impl Encodable for SSAVarEntry {
impl Decodable for SSAVarEntry {
fn decode<D: Decoder>(d: &mut D) -> Result<SSAVarEntry, D::Error> {
d.read_struct("SSAVarEntry", 3, |d| {
let val = try!(d.read_struct_field("val", 0, |d| Decodable::decode(d)));
let val = try!(d.read_struct_field("val", 0, |d| Decodable::decode(d)));
let count = try!(d.read_struct_field("use_count", 1, |d| d.read_usize()));
let expr = try!(d.read_struct_field("expr", 2, |d| Decodable::decode(d)));
let expr = try!(d.read_struct_field("expr", 2, |d| Decodable::decode(d)));
let split = try!(d.read_struct_field("split", 3, |d| Decodable::decode(d)));
let ret = SSAVarEntry {
val: val,
use_count: ATOMIC_USIZE_INIT,
expr: expr
expr: expr,
split: split
};
ret.use_count.store(count, Ordering::SeqCst);
......@@ -866,7 +875,8 @@ impl SSAVarEntry {
let ret = SSAVarEntry {
val: val,
use_count: ATOMIC_USIZE_INIT,
expr: None
expr: None,
split: None
};
ret.use_count.store(0, Ordering::SeqCst);
......@@ -902,6 +912,16 @@ impl SSAVarEntry {
debug_assert!(self.has_expr());
self.expr.take().unwrap()
}
pub fn has_split(&self) -> bool {
self.split.is_some()
}
pub fn set_split(&mut self, vec: Vec<P<Value>>) {
self.split = Some(vec);
}
pub fn get_split(&self) -> &Option<Vec<P<Value>>> {
&self.split
}
}
impl fmt::Display for SSAVarEntry {
......@@ -913,6 +933,7 @@ impl fmt::Display for SSAVarEntry {
#[derive(Debug, Clone, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Constant {
Int(u64),
IntEx(Vec<u64>),
Float(f32),
Double(f64),
// IRef(Address),
......@@ -929,6 +950,7 @@ impl fmt::Display for Constant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&Constant::Int(v) => write!(f, "{}", v as i64),
&Constant::IntEx(ref v) => write!(f, "IntEx {:?}", v),
&Constant::Float(v) => write!(f, "{}", v),
&Constant::Double(v) => write!(f, "{}", v),
// &Constant::IRef(v) => write!(f, "{}", v),
......@@ -1163,6 +1185,13 @@ impl MuEntityHeader {
None => None
}
}
pub fn clone_with_id(&self, new_id: MuID) -> MuEntityHeader {
let mut clone = self.clone();
clone.id = new_id;
clone
}
}
impl PartialEq for MuEntityHeader {
......
......@@ -59,6 +59,7 @@ lazy_static! {
UINT128_TYPE.clone(),
FLOAT_TYPE.clone(),
DOUBLE_TYPE.clone(),
FLOAT_TYPE.clone(),
VOID_TYPE.clone()
];
}
......@@ -103,28 +104,166 @@ impl MuType {
}
}
pub fn get_struct_hybrid_tag(&self) -> Option<MuName> {
pub fn is_ref(&self) -> bool {
match self.v {
MuType_::Hybrid(ref name)
| MuType_::Struct(ref name) => Some(name.clone()),
_ => None
MuType_::Ref(_) => true,
_ => false
}
}
pub fn is_ref(&self) -> bool {
pub fn is_iref(&self) -> bool {
match self.v {
MuType_::Ref(_) => true,
MuType_::IRef(_) => true,
_ => false
}
}
pub fn is_iref(&self) -> bool {
pub fn is_fp(&self) -> bool {
match self.v {
MuType_::Float | MuType_::Double => true,
_ => false
}
}
pub fn is_float(&self) -> bool {
match self.v {
MuType_::Float => true,
_ => false
}
}
pub fn is_double(&self) -> bool {
match self.v {
MuType_::Double => true,
_ => false
}
}
/// is a type raw pointer?
pub fn is_ptr(&self) -> bool {
match self.v {
MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
_ => false
}
}
/// this a type reference type (located in heap)?
pub fn is_reference(&self) -> bool {
match self.v {
MuType_::Ref(_)
| MuType_::IRef(_)
| MuType_::WeakRef(_) => true,
_ => false
}
}
/// this is a aggregated type (consited of other types)
pub fn is_aggregate(&self) -> bool {
match self.v {
MuType_::Struct(_)
| MuType_::Hybrid(_)
| MuType_::Array(_, _) => true,
_ => false
}
}
/// is a type scalar type?
pub fn is_scalar(&self) -> bool {
match self.v {
MuType_::Int(_)
| MuType_::Float
| MuType_::Double
| MuType_::Ref(_)
| MuType_::IRef(_)
| MuType_::WeakRef(_)
| MuType_::FuncRef(_)
| MuType_::UFuncPtr(_)
| MuType_::ThreadRef
| MuType_::StackRef
| MuType_::Tagref64
| MuType_::UPtr(_) => true,
_ => false
}
}
/// is a type traced by the garbage collector?
/// Note: An aggregated type is traced if any of its part is traced.
pub fn is_traced(&self) -> bool {
match self.v {
MuType_::Ref(_) => true,
MuType_::IRef(_) => true,
MuType_::WeakRef(_) => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => elem_ty.is_traced(),
MuType_::ThreadRef
| MuType_::StackRef
| MuType_::Tagref64 => true,
MuType_::Hybrid(ref tag) => {
let map = HYBRID_TAG_MAP.read().unwrap();
let hybrid_ty = map.get(tag).unwrap();
let ref fix_tys = hybrid_ty.fix_tys;
let ref var_ty = hybrid_ty.var_ty;
var_ty.is_traced() ||
fix_tys.into_iter().map(|ty| ty.is_traced())
.fold(false, |ret, this| ret || this)
},
MuType_::Struct(ref tag) => {
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys;
field_tys.into_iter().map(|ty| ty.is_traced())
.fold(false, |ret, this| ret || this)
},
_ => false
}
}
/// is a type native safe?
/// Note: An aggregated type is native safe if all of its parts are native safe.
pub fn is_native_safe(&self) -> bool {
match self.v {
MuType_::Int(_) => true,
MuType_::Float => true,
MuType_::Double => true,
MuType_::Void => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => elem_ty.is_native_safe(),
MuType_::UPtr(_) => true,
MuType_::UFuncPtr(_) => true,
MuType_::Hybrid(ref tag) => {
let map = HYBRID_TAG_MAP.read().unwrap();
let hybrid_ty = map.get(tag).unwrap();
let ref fix_tys = hybrid_ty.fix_tys;
let ref var_ty = hybrid_ty.var_ty;
var_ty.is_native_safe() &&
fix_tys.into_iter().map(|ty| ty.is_native_safe())
.fold(true, |ret, this| ret && this)
},
MuType_::Struct(ref tag) => {
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys;
field_tys.into_iter().map(|ty| ty.is_native_safe())
.fold(true, |ret, this| ret && this)
},
_ => false
}
}
pub fn get_struct_hybrid_tag(&self) -> Option<MuName> {
match self.v {
MuType_::Hybrid(ref name)
| MuType_::Struct(ref name) => Some(name.clone()),
_ => None
}
}
pub fn get_elem_ty(&self) -> Option<P<MuType>> {
match self.v {
MuType_::Array(ref elem_ty, _) => Some(elem_ty.clone()),
......@@ -475,131 +614,6 @@ impl MuType_ {
}
}
/// is a type floating-point type?
pub fn is_fp(ty: &MuType) -> bool {
match ty.v {
MuType_::Float | MuType_::Double => true,
_ => false
}
}
/// is a type raw pointer?
pub fn is_ptr(ty: &MuType) -> bool {
match ty.v {
MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
_ => false
}
}
/// this a type reference type (located in heap)?
pub fn is_reference(ty: &MuType) -> bool {
match ty.v {
MuType_::Ref(_)
| MuType_::IRef(_)
| MuType_::WeakRef(_) => true,
_ => false
}
}
/// this is a aggregated type (consited of other types)
pub fn is_aggregate(ty: &MuType) -> bool {
match ty.v {
MuType_::Struct(_)
| MuType_::Hybrid(_)
| MuType_::Array(_, _) => true,
_ => false
}
}
/// is a type scalar type?
pub fn is_scalar(ty: &MuType) -> bool {
match ty.v {
MuType_::Int(_)
| MuType_::Float
| MuType_::Double
| MuType_::Ref(_)
| MuType_::IRef(_)
| MuType_::WeakRef(_)
| MuType_::FuncRef(_)
| MuType_::UFuncPtr(_)
| MuType_::ThreadRef
| MuType_::StackRef
| MuType_::Tagref64
| MuType_::UPtr(_) => true,
_ => false
}
}
/// is a type traced by the garbage collector?
/// Note: An aggregated type is traced if any of its part is traced.
pub fn is_traced(ty: &MuType) -> bool {
match ty.v {
MuType_::Ref(_) => true,
MuType_::IRef(_) => true,
MuType_::WeakRef(_) => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => is_traced(elem_ty),
MuType_::ThreadRef
| MuType_::StackRef
| MuType_::Tagref64 => true,
MuType_::Hybrid(ref tag) => {
let map = HYBRID_TAG_MAP.read().unwrap();
let hybrid_ty = map.get(tag).unwrap();
let ref fix_tys = hybrid_ty.fix_tys;
let ref var_ty = hybrid_ty.var_ty;
is_traced(var_ty) ||
fix_tys.into_iter().map(|ty| is_traced(ty))
.fold(false, |ret, this| ret || this)
},
MuType_::Struct(ref tag) => {
let map = STRUCT_TAG_MAP.read().unwrap();
let struct_ty = map.get(tag).unwrap();
let ref field_tys = struct_ty.tys;
field_tys.into_iter().map(|ty| is_traced(&ty))
.fold(false, |ret, this| ret || this)
},
_ => false
}
}
/// is a type native safe?
/// Note: An aggregated type is native safe if all of its parts are native safe.
pub fn is_native_safe(ty: &MuType) -> bool {
match ty.v {
MuType_::Int(_) => true,
MuType_::Float => true,
MuType_::Double => true,
MuType_::Void => true,
MuType_::Array(ref elem_ty, _)
| MuType_::Vector(ref elem_ty, _) => is_native_safe(elem_ty),
MuType_::UPtr(_) => true,
MuType_::UFuncPtr(_) => true,
MuType_::Hybrid(ref tag) => {
let map = HYBRID_TAG_MAP.read().unwrap();
let hybrid_ty = map.get(tag).unwrap();
let ref fix_tys = hybrid_ty.fix_tys;
let ref var_ty = hybrid_ty.var_ty;
is_native_safe(var_ty) &&