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.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 6e2649fe authored by qinsoon's avatar qinsoon
Browse files

Merge branch 'develop' into issue82-inf-loop-in-peephole

parents 6007d267 6d862159
......@@ -42,6 +42,28 @@ test:cargo:runtime:
script:
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 ./test-release --color=always test_runtime 2> /dev/null
.build_muc: &build_muc |
if [ -d "tests/test_muc/mu-tool-compiler" ]; then rm -Rf tests/test_muc/mu-tool-compiler; fi
cd tests/test_muc
git clone https://gitlab.anu.edu.au/mu/mu-tool-compiler
cd mu-tool-compiler
mkdir lib
ln -s $MU_ZEBU/target/release/libmu.so lib/
make
cd ..
testmuc:test_simple:
stage: test
script:
- *build_muc
- LD_LIBRARY_PATH=mu-tool-compiler/lib/ MUC=mu-tool-compiler/muc python2 -m pytest test_simple.py -v
testmuc:test_swapstack:
stage: test
script:
- *build_muc
- LD_LIBRARY_PATH=mu-tool-compiler/lib/ MUC=mu-tool-compiler/muc python2 -m pytest test_thread_and_stack.py -v
testjit:milestones:
stage: test
script:
......@@ -60,6 +82,8 @@ testjit:cmpops:
testjit:controlflow:
stage: test
script:
# run this test under test_jit directory
# as a C source file is expected in a relative path to current working directory
- cd tests/test_jit
- RUST_BACKTRACE=1 pytest test_controlflow.py -v --color=yes
......
......@@ -22,6 +22,8 @@ extern crate gcc;
#[cfg(target_arch = "x86_64")]
fn main() {
gcc::Build::new()
.flag("-O3")
.flag("-c")
.file("src/runtime/runtime_c_x64_sysv.c")
.compile("libruntime_c.a");
......@@ -39,6 +41,8 @@ fn main() {
#[cfg(target_arch = "aarch64")]
fn main() {
gcc::Build::new()
.flag("-O3")
.flag("-c")
.file("src/runtime/runtime_c_aarch64_sysv.c")
.compile("libruntime_c.a");
......
......@@ -55,5 +55,5 @@ else
git -C ./RPySOM submodule init
git -C ./RPySOM submodule update
fi
pytest test_*.py -v --color=yes 2>&1 | tee $MU_ZEBU/pytest_out.txt
shopt -s extglob
pytest ./test_!(pypy).py -v --color=yes 2>&1 | tee $MU_ZEBU/pytest_out.txt
......@@ -26,4 +26,5 @@ lazy_static = "*"
log = "*"
simple_logger = "*"
rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", version = ">= 0.0.5" }
regex = "*"
#rodal = { path = "../../../rodal_test/rodal", version = ">= 0.0.5" }
......@@ -63,6 +63,20 @@ impl Instruction {
use inst::Instruction_::*;
match self.v {
Return(_) |
ThreadExit |
Throw(_) |
TailCall(_) |
Branch1(_) |
Branch2 { .. } |
Watchpoint { .. } |
WPBranch { .. } |
Call { .. } |
CCall { .. } |
SwapStackExc { .. } |
SwapStackKill { .. } |
Switch { .. } |
ExnInstruction { .. } => true,
BinOp(_, _, _) |
BinOpWithStatus(_, _, _, _) |
CmpOp(_, _, _) |
......@@ -78,8 +92,7 @@ impl Instruction {
NewHybrid(_, _) |
AllocAHybrid(_, _) |
NewStack(_) |
NewThread(_, _) |
NewThreadExn(_, _) |
NewThread { .. } |
NewFrameCursor(_) |
GetIRef(_) |
GetFieldIRef { .. } |
......@@ -105,20 +118,10 @@ impl Instruction {
CommonInst_Tr64ToTag(_) |
Move(_) |
PrintHex(_) |
SetRetval(_) => false,
Return(_) |
ThreadExit |
Throw(_) |
TailCall(_) |
Branch1(_) |
Branch2 { .. } |
Watchpoint { .. } |
WPBranch { .. } |
Call { .. } |
CCall { .. } |
SwapStack { .. } |
Switch { .. } |
ExnInstruction { .. } => true
SetRetval(_) |
KillStack(_) |
CurrentStack |
SwapStackExpr { .. } => false
}
}
......@@ -135,58 +138,65 @@ impl Instruction {
use inst::Instruction_::*;
match self.v {
BinOp(_, _, _) => false,
BinOpWithStatus(_, _, _, _) => false,
CmpOp(_, _, _) => false,
ConvOp { .. } => false,
ExprCall { .. } => true,
ExprCCall { .. } => true,
Load { .. } => true,
Store { .. } => true,
CmpXchg { .. } => true,
AtomicRMW { .. } => true,
New(_) => true,
AllocA(_) => true,
NewHybrid(_, _) => true,
AllocAHybrid(_, _) => true,
NewStack(_) => true,
NewThread(_, _) => true,
NewThreadExn(_, _) => true,
NewFrameCursor(_) => true,
GetIRef(_) => false,
GetFieldIRef { .. } => false,
GetElementIRef { .. } => false,
ShiftIRef { .. } => false,
GetVarPartIRef { .. } => false,
Fence(_) => true,
Return(_) => true,
ThreadExit => true,
Throw(_) => true,
TailCall(_) => true,
Branch1(_) => true,
Branch2 { .. } => true,
Select { .. } => false,
Watchpoint { .. } => true,
WPBranch { .. } => true,
Call { .. } => true,
CCall { .. } => true,
SwapStack { .. } => true,
Switch { .. } => true,
ExnInstruction { .. } => true,
CommonInst_GetThreadLocal => true,
CommonInst_SetThreadLocal(_) => true,
CommonInst_Pin(_) | CommonInst_Unpin(_) | CommonInst_GetAddr(_) => true,
CommonInst_Tr64IsFp(_) | CommonInst_Tr64IsInt(_) | CommonInst_Tr64IsRef(_) => false,
CommonInst_Tr64FromFp(_) | CommonInst_Tr64FromInt(_) | CommonInst_Tr64FromRef(_, _) => {
false
}
ExprCall { .. } |
ExprCCall { .. } |
Load { .. } |
Store { .. } |
CmpXchg { .. } |
AtomicRMW { .. } |
New(_) |
AllocA(_) |
NewHybrid(_, _) |
AllocAHybrid(_, _) |
NewStack(_) |
NewThread { .. } |
NewFrameCursor(_) |
Fence(_) |
Return(_) |
ThreadExit |
Throw(_) |
TailCall(_) |
Branch1(_) |
Branch2 { .. } |
Watchpoint { .. } |
WPBranch { .. } |
Call { .. } |
CCall { .. } |
SwapStackExpr { .. } |
SwapStackExc { .. } |
SwapStackKill { .. } |
Switch { .. } |
ExnInstruction { .. } |
CommonInst_GetThreadLocal |
CommonInst_SetThreadLocal(_) |
CommonInst_Pin(_) |
CommonInst_Unpin(_) |
CommonInst_GetAddr(_) |
PrintHex(_) |
SetRetval(_) |
KillStack(_) => true,
BinOp(_, _, _) |
BinOpWithStatus(_, _, _, _) |
CmpOp(_, _, _) |
ConvOp { .. } |
GetIRef(_) |
GetFieldIRef { .. } |
GetElementIRef { .. } |
ShiftIRef { .. } |
GetVarPartIRef { .. } |
Select { .. } |
CommonInst_Tr64IsFp(_) |
CommonInst_Tr64IsInt(_) |
CommonInst_Tr64IsRef(_) |
CommonInst_Tr64FromFp(_) |
CommonInst_Tr64FromInt(_) |
CommonInst_Tr64FromRef(_, _) |
CommonInst_Tr64ToFp(_) |
CommonInst_Tr64ToInt(_) |
CommonInst_Tr64ToRef(_) |
CommonInst_Tr64ToTag(_) => false,
Move(_) => false,
PrintHex(_) => true,
SetRetval(_) => true
CommonInst_Tr64ToTag(_) |
Move(_) |
CurrentStack => false
}
}
......@@ -199,9 +209,8 @@ impl Instruction {
Watchpoint { .. } |
Call { .. } |
CCall { .. } |
SwapStack { .. } |
SwapStackExc { .. } |
ExnInstruction { .. } => true,
BinOp(_, _, _) |
BinOpWithStatus(_, _, _, _) |
CmpOp(_, _, _) |
......@@ -217,8 +226,7 @@ impl Instruction {
NewHybrid(_, _) |
AllocAHybrid(_, _) |
NewStack(_) |
NewThread(_, _) |
NewThreadExn(_, _) |
NewThread { .. } |
NewFrameCursor(_) |
GetIRef(_) |
GetFieldIRef { .. } |
......@@ -252,7 +260,11 @@ impl Instruction {
CommonInst_Tr64ToTag(_) |
Move(_) |
PrintHex(_) |
SetRetval(_) => false
SetRetval(_) |
KillStack(_) |
CurrentStack |
SwapStackExpr { .. } |
SwapStackKill { .. } => false
}
}
......@@ -269,9 +281,8 @@ impl Instruction {
Watchpoint { ref resume, .. } |
Call { ref resume, .. } |
CCall { ref resume, .. } |
SwapStack { ref resume, .. } |
SwapStackExc { ref resume, .. } |
ExnInstruction { ref resume, .. } => Some(resume.exn_dest.target),
BinOp(_, _, _) |
BinOpWithStatus(_, _, _, _) |
CmpOp(_, _, _) |
......@@ -287,8 +298,7 @@ impl Instruction {
NewHybrid(_, _) |
AllocAHybrid(_, _) |
NewStack(_) |
NewThread(_, _) |
NewThreadExn(_, _) |
NewThread { .. } |
NewFrameCursor(_) |
GetIRef(_) |
GetFieldIRef { .. } |
......@@ -322,7 +332,11 @@ impl Instruction {
CommonInst_Tr64ToTag(_) |
Move(_) |
PrintHex(_) |
SetRetval(_) => None
SetRetval(_) |
KillStack(_) |
CurrentStack |
SwapStackExpr { .. } |
SwapStackKill { .. } => None
}
}
......@@ -433,13 +447,20 @@ pub enum Instruction_ {
/// args: functionref of the entry function
NewStack(OpIndex),
/// kill the given Mu stack
KillStack(OpIndex),
/// return stackref for the current stack
CurrentStack,
/// create a new Mu thread, yields thread reference
/// args: stackref of a Mu stack, a list of arguments
NewThread(OpIndex, Vec<OpIndex>), // stack, args
/// create a new Mu thread, yields thread reference (thread resumes with exceptional value)
/// args: stackref of a Mu stack, an exceptional value
NewThreadExn(OpIndex, OpIndex), // stack, exception
NewThread {
stack: OpIndex,
thread_local: Option<OpIndex>,
is_exception: bool,
args: Vec<OpIndex>
},
/// create a frame cursor reference
/// args: stackref of a Mu stack
......@@ -539,15 +560,29 @@ pub enum Instruction_ {
resume: ResumptionData
},
/// swapstack. swap current Mu stack with the named Mu stack,
/// and continue with specified resumption
SwapStack {
/// A swap stack with an exception clause (i.e. uses the RET_WITH form)
SwapStackExc {
stack: OpIndex,
is_exception: bool,
args: Vec<OpIndex>,
resume: ResumptionData
},
/// A swap stack without an exception clause that is not a terminator
/// (i.e. uses the RET_WITH form)
SwapStackExpr {
stack: OpIndex,
is_exception: bool,
args: Vec<OpIndex>
},
/// A swapstack without an exception clause that is a terminator (i.e. one with KILL_OLD)
SwapStackKill {
stack: OpIndex,
is_exception: bool,
args: Vec<OpIndex>
},
/// a multiway branch
Switch {
cond: OpIndex,
......@@ -685,17 +720,24 @@ impl Instruction_ {
&Instruction_::AllocA(ref ty) => format!("ALLOCA {}", ty),
&Instruction_::NewHybrid(ref ty, len) => format!("NEWHYBRID {} {}", ty, ops[len]),
&Instruction_::AllocAHybrid(ref ty, len) => format!("ALLOCAHYBRID {} {}", ty, ops[len]),
&Instruction_::NewStack(func) => format!("NEWSTACK {}", ops[func]),
&Instruction_::NewThread(stack, ref args) => {
&Instruction_::NewStack(func) => format!("NEW_STACK {}", ops[func]),
&Instruction_::NewThread {
stack,
thread_local,
is_exception,
ref args
} => {
let thread_local = thread_local
.map(|t| format!("{}", ops[t]))
.unwrap_or("NULL".to_string());
format!(
"NEWTHREAD {} PASS_VALUES {}",
"SWAPSTACK {} THREADLOCAL({}) {} {}",
ops[stack],
op_vector_str(args, ops)
thread_local,
is_exception,
op_vector_str(args, ops),
)
}
&Instruction_::NewThreadExn(stack, exn) => {
format!("NEWTHREAD {} THROW_EXC {}", ops[stack], ops[exn])
}
&Instruction_::NewFrameCursor(stack) => format!("NEWFRAMECURSOR {}", ops[stack]),
&Instruction_::GetIRef(reference) => format!("GETIREF {}", ops[reference]),
&Instruction_::GetFieldIRef {
......@@ -731,6 +773,8 @@ impl Instruction_ {
&Instruction_::Return(ref vals) => format!("RET {}", op_vector_str(vals, ops)),
&Instruction_::ThreadExit => "THREADEXIT".to_string(),
&Instruction_::CurrentStack => "CURRENT_STACK".to_string(),
&Instruction_::KillStack(s) => format!("RET {}", ops[s]),
&Instruction_::Throw(exn_obj) => format!("THROW {}", ops[exn_obj]),
&Instruction_::TailCall(ref call) => format!("TAILCALL {}", call.debug_str(ops)),
&Instruction_::Branch1(ref dest) => format!("BRANCH {}", dest.debug_str(ops)),
......@@ -797,7 +841,19 @@ impl Instruction_ {
ref data,
ref resume
} => format!("CCALL {} {}", data.debug_str(ops), resume.debug_str(ops)),
&Instruction_::SwapStack {
&Instruction_::SwapStackExpr {
stack,
is_exception,
ref args
} => {
format!(
"SWAPSTACK {} {} {}",
ops[stack],
is_exception,
op_vector_str(args, ops),
)
}
&Instruction_::SwapStackExc {
stack,
is_exception,
ref args,
......@@ -811,6 +867,20 @@ impl Instruction_ {
resume.debug_str(ops)
)
}
&Instruction_::SwapStackKill {
stack,
is_exception,
ref args
} => {
format!(
"SWAPSTACK {} {} {}",
ops[stack],
is_exception,
op_vector_str(args, ops),
)
}
&Instruction_::Switch {
cond,
ref default,
......@@ -948,7 +1018,7 @@ impl fmt::Debug for BinOpStatus {
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum MemoryOrder {
NotAtomic,
Relaxed,
......
......@@ -795,7 +795,7 @@ impl BlockContent {
}
Instruction_::Call { ref resume, .. } |
Instruction_::CCall { ref resume, .. } |
Instruction_::SwapStack { ref resume, .. } |
Instruction_::SwapStackExc { ref resume, .. } |
Instruction_::ExnInstruction { ref resume, .. } => {
let mut live_outs = vec![];
live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
......@@ -1012,6 +1012,23 @@ impl Value {
}
}
pub fn is_const_zero(&self) -> bool {
match self.v {
Value_::Constant(Constant::Int(val)) if val == 0 => true,
Value_::Constant(Constant::Double(val)) if val == 0f64 => true,
Value_::Constant(Constant::Float(val)) if val == 0f32 => true,
Value_::Constant(Constant::IntEx(ref vec)) => {
if vec.iter().all(|x| *x == 0) {
true
} else {
false
}
}
Value_::Constant(Constant::NullRef) => true,
_ => false
}
}
/// disguises a value as another type.
/// This is usually used for treat an integer type as an integer of a different length
/// This method is unsafe
......@@ -1077,7 +1094,7 @@ impl Value {
}
}
const DISPLAY_ID: bool = false;
const DISPLAY_ID: bool = true;
const DISPLAY_TYPE: bool = true;
const PRINT_ABBREVIATE_NAME: bool = true;
......@@ -1469,7 +1486,8 @@ pub fn mangle_name(name: MuName) -> MuName {
"__mu_".to_string() + name.as_str()
}
// WARNING: This only reverses mangle_name above when no warning is issued)
/// demangles a Mu name
// WARNING: This only reverses mangle_name above when no warning is issued)
pub fn demangle_name(mut name: MuName) -> MuName {
let name = if cfg!(target_os = "macos") && name.starts_with("___mu_") {
name.split_off(1)
......@@ -1492,57 +1510,28 @@ pub fn demangle_name(mut name: MuName) -> MuName {
name
}
// TODO: Why the hell isn't this working?
pub fn demangle_text(text: String) -> String {
let text = text.as_bytes();
let n = text.len();
let mut output = String::new();
extern crate regex;
// We have a mangled name
let mut last_i = 0; // The last i value that we dumped to output
let mut i = 0;
// TODO: this should work for utf-8 stuff right? (sinces all mangled names are in ascii)
while i < n {
let c = text[i] as char;
// We're at the beginining of the string
// wait for a word boundry
if c.is_alphanumeric() || c == '_' {
// We just found a mangled name
if text[i..].starts_with("__mu_".as_bytes()) {
output += std::str::from_utf8(&text[last_i..i]).unwrap();
let start = i;
// Find the end of the name
while i < n {
let c = text[i] as char;
if !c.is_alphanumeric() && c != '_' {
break; // We found the end!
}
i += 1;
}
/// identifies mu names and demangles them
pub fn demangle_text(text: String) -> String {
use self::regex::Regex;
output +=
demangle_name(String::from_utf8(text[start..i].to_vec()).unwrap()).as_str();
// Skip to the end of the name
last_i = i;
continue;
} else {
// Skip to the end of this alphanumeric sequence
while i < n {
let c = text[i] as char;
if !c.is_alphanumeric() && c != '_' {
break; // We found the end!
}
i += 1;
}
}
lazy_static!{
static ref IDENT_NAME: Regex = if cfg!(target_os = "macos") {
Regex::new(r"___mu_\w+").unwrap()
} else {
Regex::new(r"__mu_\w+").unwrap()
};
}
continue;
}
// Not the start of mangled name, continue
i += 1;
let mut res = text.clone();
for cap in IDENT_NAME.captures_iter(&text) {
let name = cap.get(0).unwrap().as_str().to_string();
let demangled = demangle_name(name.clone());
res = res.replacen(&name, &demangled, 1);
}
// Return output plus whatever is left of the string
output + std::str::from_utf8(&text[last_i..n]).unwrap()
res
}
......
......@@ -33,6 +33,7 @@
#[macro_use]
extern crate rodal;
extern crate log;
extern crate simple_logger;
#[macro_use]
extern crate lazy_static;
......
......@@ -1037,52 +1037,6 @@ impl ASMCodeGen {
self.cur_mut().code.push(ASMInst::symbolic(code));
}
fn add_asm_call(
&mut self,
code: String,
potentially_excepting: Option<MuName>,
arguments: Vec<P<Value>>,
target: Option<(MuID, ASMLocation)>
) {
// a call instruction will use all the argument registers
// do not need
let mut uses: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new();
if target.is_some() {
let (id, loc) = target.unwrap();
uses.insert(id, vec![loc]);
}
for arg in arguments {
uses.insert(arg.id(), vec![]);
}
let mut defines: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new();
for reg in CALLER_SAVED_GPRS.iter() {
if !defines.contains_key(&reg.id()) {
defines.insert(reg.id(), vec![]);