To protect your data, the CISO officer has suggested users to enable GitLab 2FA as soon as possible.

Commit 415d45e8 authored by qinsoon's avatar qinsoon
Browse files

Merge branch 'master' into open-source

parents 29759a3c 99a65c69
......@@ -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
......@@ -6,7 +6,6 @@ use op::*;
use utils::vec_utils;
use std::fmt;
use std::sync::RwLock;
/// Instruction represents a Mu instruction
#[derive(Debug)] // RustcEncodable, RustcDecodable, Clone and Display
......@@ -17,7 +16,7 @@ pub struct Instruction {
/// ops field list all the children nodes,
/// and in Instruction_, the children nodes are referred by indices
/// This design makes it easy for the compiler to iterate through all the children
pub ops : RwLock<Vec<P<TreeNode>>>,
pub ops : Vec<P<TreeNode>>,
/// used for pattern matching
pub v: Instruction_
}
......@@ -32,7 +31,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)));
......@@ -55,7 +54,7 @@ impl Decodable for Instruction {
Ok(Instruction{
hdr: hdr,
value: value,
ops: RwLock::new(ops),
ops: ops,
v: v
})
})
......@@ -67,13 +66,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
}
/// is this instruction the terminal inst of its block?
/// Terminal instructions end Mu blocks, and Mu block ends with a terminal instruction.
pub fn is_terminal_inst(&self) -> bool {
......@@ -249,7 +255,6 @@ impl Instruction {
/// returns exception target(block ID), returns None if this instruction does not have exceptional branch
pub fn get_exception_target(&self) -> Option<MuID> {
use inst::Instruction_::*;
match self.v {
Watchpoint {ref resume, ..}
| Call {ref resume, ..}
......@@ -308,7 +313,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 {
......
......@@ -249,7 +249,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, ..}
......@@ -364,6 +364,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)
}
}
/// FunctionContext contains compilation information about the function
......@@ -560,7 +570,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
......@@ -738,16 +748,17 @@ impl Value {
_ => false
}
}
pub fn is_int_reg(&self) -> bool {
pub fn is_reg(&self) -> bool {
match self.v {
Value_::SSAVar(_) => {
if self.ty.is_scalar() && !self.ty.is_fp() {
true
} else {
false
}
}
Value_::SSAVar(_) => true,
_ => false
}
}
pub fn is_const(&self) -> bool {
match self.v {
Value_::Constant(_) => true,
_ => false
}
}
......@@ -763,21 +774,6 @@ impl Value {
})
}
pub fn is_fp_reg(&self) -> bool {
match self.v {
Value_::SSAVar(_) => {
if self.ty.is_scalar() && self.ty.is_fp() {
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,
......@@ -800,6 +796,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;
......@@ -868,7 +871,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 {
......@@ -878,6 +884,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(())
})
}
......@@ -886,14 +893,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);
......@@ -908,7 +917,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);
......@@ -944,6 +954,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 {
......@@ -957,6 +977,7 @@ impl fmt::Display for SSAVarEntry {
pub enum Constant {
/// all integer constants are stored as u64
Int(u64),
IntEx(Vec<u64>),
/// float constants
Float(f32),
/// double constants
......@@ -977,6 +998,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),
......@@ -1227,6 +1249,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 {
......
......@@ -117,6 +117,22 @@ impl MuType {
}
}
/// is this type a float type (single-precision floating point)
pub fn is_float(&self) -> bool {
match self.v {
MuType_::Float => true,
_ => false
}
}
/// is this type a double type (double-precision floating point)
pub fn is_double(&self) -> bool {
match self.v {
MuType_::Double => true,
_ => false
}
}
/// is this type a scalar type?
pub fn is_scalar(&self) -> bool {
match self.v {
......@@ -173,6 +189,14 @@ impl MuType {
}
}
/// is a type raw pointer?
pub fn is_ptr(&self) -> bool {
match self.v {
MuType_::UPtr(_) | MuType_::UFuncPtr(_) => true,
_ => false
}
}
/// is this type an aggregated type? (consisted of other types)
pub fn is_aggregate(&self) -> bool {
match self.v {
......
......@@ -1561,6 +1561,43 @@ impl ASMCodeGen {
)
}
fn internal_triop_def_r_r_mr(&mut self, inst: &str, dest: Reg, src1: Reg, src2: Reg) {
let len = check_op_len(dest);
let inst = inst.to_string() + &op_postfix(len);
trace!("emit: {} {}, {}, {} -> {}", inst, dest, src1, src2, dest);
let mreg = self.prepare_machine_reg(src2);
let mreg_name = src2.name().unwrap();
let (reg1, id1, loc1) = self.prepare_reg(src1, inst.len() + 1 + 1 + mreg_name.len() + 1);
let (reg2, id2, loc2) = self.prepare_reg(dest, inst.len() + 1 + 1 + mreg_name.len() + 1 + reg1.len() + 1);
let asm = format!("{} %{},{},{}", inst, mreg_name, reg1, reg2);
self.add_asm_inst(
asm,
linked_hashmap!{
id2 => vec![loc2.clone()]
},
{
if id1 == id2 {
linked_hashmap! {
id1 => vec![loc1, loc2],
mreg => vec![]
}
} else {
linked_hashmap! {
id1 => vec![loc1],
id2 => vec![loc2],
mreg => vec![]
}
}
},
false
)
}
fn internal_mov_r64_imm64(&mut self, inst: &str, dest: &P<Value>, src: i64) {
let inst = inst.to_string() + &op_postfix(64);
trace!("emit: {} {} -> {}", inst, src, dest);
......@@ -1731,6 +1768,26 @@ impl ASMCodeGen {
)
}
fn internal_fp_mov_f_f(&mut self, inst: &str, dest: Reg, src: Reg) {
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
)
}
fn internal_fp_mov_f_mem(&mut self, inst: &str, dest: Reg, src: Mem,
is_spill_related: bool
) {
......@@ -1858,6 +1915,52 @@ impl ASMCodeGen {
unimplemented!()
}
fn internal_gpr_to_fpr(&mut self, inst: &str, dest: Reg, src: Reg) {
let len = check_op_len(src);
let inst = inst.to_string() + &op_postfix(len);
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
)
}
fn internal_fpr_to_gpr(&mut self, inst: &str, dest: Reg, src: Reg) {
let len = check_op_len(dest);
let inst = inst.to_string() + &op_postfix(len);
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
)
}
fn emit_spill_store_gpr(&mut self, dest: Mem, src: Reg) {
self.internal_mov_mem_r("mov", dest, src, true, false)
}
......@@ -2113,6 +2216,14 @@ impl CodeGenerator for ASMCodeGen {
self.internal_binop_no_def_mem_r("cmp", op1, op2)
}
fn emit_test_r_r(&mut self, op1: &P<Value>, op2: &P<Value>) {
self.internal_binop_no_def_r_r("test", op1, op2)
}
fn emit_test_imm_r(&mut self, op1: i32, op2: Reg) {
self.internal_binop_no_def_imm_r("test", op1, op2)
}
// mov
fn emit_mov_r64_imm64 (&mut self, dest: &P<Value>, src: i64) {
......@@ -2397,6 +2508,17 @@ impl CodeGenerator for ASMCodeGen {
self.internal_binop_def_r_mem("add", dest, src)
}
// adc
fn emit_adc_r_r (&mut self, dest: Reg, src: Reg) {
self.internal_binop_def_r_r("adc", dest, src)
}
fn emit_adc_r_mem(&mut self, dest: Reg, src: Mem) {
self.internal_binop_def_r_mem("adc", dest, src)
}
fn emit_adc_r_imm(&mut self, dest: Reg, src: i32) {
self.internal_binop_def_r_imm("adc", dest, src)
}
// sub
fn emit_sub_r_imm(&mut self, dest: Reg, src: i32) {
self.internal_binop_def_r_imm("sub", dest, src)
......@@ -2407,7 +2529,18 @@ impl CodeGenerator for ASMCodeGen {
fn emit_sub_r_mem(&mut self, dest: Reg, src: Mem) {
self.internal_binop_def_r_mem("sub", dest, src)