Commit 6e2649fe authored by qinsoon's avatar qinsoon

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

parents 6007d267 6d862159
...@@ -42,6 +42,28 @@ test:cargo:runtime: ...@@ -42,6 +42,28 @@ test:cargo:runtime:
script: script:
- RUST_BACKTRACE=1 RUST_TEST_THREADS=1 ./test-release --color=always test_runtime 2> /dev/null - 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: testjit:milestones:
stage: test stage: test
script: script:
...@@ -60,6 +82,8 @@ testjit:cmpops: ...@@ -60,6 +82,8 @@ testjit:cmpops:
testjit:controlflow: testjit:controlflow:
stage: test stage: test
script: 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 - cd tests/test_jit
- RUST_BACKTRACE=1 pytest test_controlflow.py -v --color=yes - RUST_BACKTRACE=1 pytest test_controlflow.py -v --color=yes
......
...@@ -22,6 +22,8 @@ extern crate gcc; ...@@ -22,6 +22,8 @@ extern crate gcc;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
fn main() { fn main() {
gcc::Build::new() gcc::Build::new()
.flag("-O3")
.flag("-c")
.file("src/runtime/runtime_c_x64_sysv.c") .file("src/runtime/runtime_c_x64_sysv.c")
.compile("libruntime_c.a"); .compile("libruntime_c.a");
...@@ -39,6 +41,8 @@ fn main() { ...@@ -39,6 +41,8 @@ fn main() {
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
fn main() { fn main() {
gcc::Build::new() gcc::Build::new()
.flag("-O3")
.flag("-c")
.file("src/runtime/runtime_c_aarch64_sysv.c") .file("src/runtime/runtime_c_aarch64_sysv.c")
.compile("libruntime_c.a"); .compile("libruntime_c.a");
......
...@@ -55,5 +55,5 @@ else ...@@ -55,5 +55,5 @@ else
git -C ./RPySOM submodule init git -C ./RPySOM submodule init
git -C ./RPySOM submodule update git -C ./RPySOM submodule update
fi fi
shopt -s extglob
pytest test_*.py -v --color=yes 2>&1 | tee $MU_ZEBU/pytest_out.txt pytest ./test_!(pypy).py -v --color=yes 2>&1 | tee $MU_ZEBU/pytest_out.txt
...@@ -26,4 +26,5 @@ lazy_static = "*" ...@@ -26,4 +26,5 @@ lazy_static = "*"
log = "*" log = "*"
simple_logger = "*" simple_logger = "*"
rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", version = ">= 0.0.5" } rodal = { git = "https://gitlab.anu.edu.au/mu/rodal", version = ">= 0.0.5" }
regex = "*"
#rodal = { path = "../../../rodal_test/rodal", version = ">= 0.0.5" } #rodal = { path = "../../../rodal_test/rodal", version = ">= 0.0.5" }
This diff is collapsed.
...@@ -795,7 +795,7 @@ impl BlockContent { ...@@ -795,7 +795,7 @@ impl BlockContent {
} }
Instruction_::Call { ref resume, .. } | Instruction_::Call { ref resume, .. } |
Instruction_::CCall { ref resume, .. } | Instruction_::CCall { ref resume, .. } |
Instruction_::SwapStack { ref resume, .. } | Instruction_::SwapStackExc { ref resume, .. } |
Instruction_::ExnInstruction { ref resume, .. } => { Instruction_::ExnInstruction { ref resume, .. } => {
let mut live_outs = vec![]; let mut live_outs = vec![];
live_outs.append(&mut resume.normal_dest.get_arguments(&ops)); live_outs.append(&mut resume.normal_dest.get_arguments(&ops));
...@@ -1012,6 +1012,23 @@ impl Value { ...@@ -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. /// disguises a value as another type.
/// This is usually used for treat an integer type as an integer of a different length /// This is usually used for treat an integer type as an integer of a different length
/// This method is unsafe /// This method is unsafe
...@@ -1077,7 +1094,7 @@ impl Value { ...@@ -1077,7 +1094,7 @@ impl Value {
} }
} }
const DISPLAY_ID: bool = false; const DISPLAY_ID: bool = true;
const DISPLAY_TYPE: bool = true; const DISPLAY_TYPE: bool = true;
const PRINT_ABBREVIATE_NAME: bool = true; const PRINT_ABBREVIATE_NAME: bool = true;
...@@ -1469,7 +1486,8 @@ pub fn mangle_name(name: MuName) -> MuName { ...@@ -1469,7 +1486,8 @@ pub fn mangle_name(name: MuName) -> MuName {
"__mu_".to_string() + name.as_str() "__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 { pub fn demangle_name(mut name: MuName) -> MuName {
let name = if cfg!(target_os = "macos") && name.starts_with("___mu_") { let name = if cfg!(target_os = "macos") && name.starts_with("___mu_") {
name.split_off(1) name.split_off(1)
...@@ -1492,57 +1510,28 @@ pub fn demangle_name(mut name: MuName) -> MuName { ...@@ -1492,57 +1510,28 @@ pub fn demangle_name(mut name: MuName) -> MuName {
name name
} }
// TODO: Why the hell isn't this working? extern crate regex;
pub fn demangle_text(text: String) -> String {
let text = text.as_bytes();
let n = text.len();
let mut output = String::new();
// We have a mangled name /// identifies mu names and demangles them
let mut last_i = 0; // The last i value that we dumped to output pub fn demangle_text(text: String) -> String {
let mut i = 0; use self::regex::Regex;
// 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;
}
output += lazy_static!{
demangle_name(String::from_utf8(text[start..i].to_vec()).unwrap()).as_str(); static ref IDENT_NAME: Regex = if cfg!(target_os = "macos") {
// Skip to the end of the name Regex::new(r"___mu_\w+").unwrap()
last_i = i; } else {
continue; Regex::new(r"__mu_\w+").unwrap()
} 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;
}
}
continue; let mut res = text.clone();
} for cap in IDENT_NAME.captures_iter(&text) {
// Not the start of mangled name, continue let name = cap.get(0).unwrap().as_str().to_string();
i += 1; 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 @@ ...@@ -33,6 +33,7 @@
#[macro_use] #[macro_use]
extern crate rodal; extern crate rodal;
extern crate log;
extern crate simple_logger; extern crate simple_logger;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
......
...@@ -1037,52 +1037,6 @@ impl ASMCodeGen { ...@@ -1037,52 +1037,6 @@ impl ASMCodeGen {
self.cur_mut().code.push(ASMInst::symbolic(code)); 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![]);
}
}
for reg in CALLER_SAVED_FPRS.iter() {
if !defines.contains_key(&reg.id()) {
defines.insert(reg.id(), vec![]);
}
}
self.add_asm_inst_internal(
code,
defines,
uses,
false,
{
if potentially_excepting.is_some() {
ASMBranchTarget::PotentiallyExcepting(potentially_excepting.unwrap())
} else {
ASMBranchTarget::None
}
},
None
)
}
fn add_asm_inst( fn add_asm_inst(
&mut self, &mut self,
code: String, code: String,
...@@ -1147,6 +1101,7 @@ impl ASMCodeGen { ...@@ -1147,6 +1101,7 @@ impl ASMCodeGen {
trace!("asm: {}", demangle_text(code.clone())); trace!("asm: {}", demangle_text(code.clone()));
trace!(" defines: {:?}", defines); trace!(" defines: {:?}", defines);
trace!(" uses: {:?}", uses); trace!(" uses: {:?}", uses);
trace!(" target: {:?}", target);
let mc = self.cur_mut(); let mc = self.cur_mut();
// put the instruction // put the instruction
...@@ -2162,6 +2117,57 @@ impl ASMCodeGen { ...@@ -2162,6 +2117,57 @@ impl ASMCodeGen {
self.add_asm_inst(asm, ignore_zero_register(id1, vec![loc1]), uses, false) self.add_asm_inst(asm, ignore_zero_register(id1, vec![loc1]), uses, false)
} }
fn internal_call(
&mut self,
callsite: Option<String>,
code: String,
pe: Option<MuName>,
args: Vec<P<Value>>,
ret: Vec<P<Value>>,
target: Option<(MuID, ASMLocation)>,
may_return: bool
) -> Option<ValueLocation> {
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 args {
uses.insert(arg.id(), vec![]);
}
let mut defines: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new();
for ret in ret.iter() {
defines.insert(ret.id(), vec![]);
}
self.add_asm_inst_internal(
code,
defines,
uses,
false,
{
if pe.is_some() {
ASMBranchTarget::PotentiallyExcepting(pe.unwrap())
} else if may_return {
ASMBranchTarget::None
} else {
ASMBranchTarget::Return
}
},
None
);
if callsite.is_some() {
let callsite_symbol = mangle_name(callsite.as_ref().unwrap().clone());
self.add_asm_symbolic(directive_globl(callsite_symbol.clone()));
self.add_asm_symbolic(format!("{}:", callsite_symbol.clone()));
Some(ValueLocation::Relocatable(RegGroup::GPR, callsite.unwrap()))
} else {
None
}
}
fn emit_ldr_spill(&mut self, dest: Reg, src: Mem) { fn emit_ldr_spill(&mut self, dest: Reg, src: Mem) {
self.internal_load("LDR", dest, src, false, true, false); self.internal_load("LDR", dest, src, false, true, false);
} }
...@@ -2395,12 +2401,13 @@ impl CodeGenerator for ASMCodeGen { ...@@ -2395,12 +2401,13 @@ impl CodeGenerator for ASMCodeGen {
fn emit_bl( fn emit_bl(
&mut self, &mut self,
callsite: String, callsite: Option<String>,
func: MuName, func: MuName,
pe: Option<MuName>, pe: Option<MuName>,
args: Vec<P<Value>>, args: Vec<P<Value>>,
ret: Vec<P<Value>>,
is_native: bool is_native: bool
) -> ValueLocation { ) -> Option<ValueLocation> {
if is_native { if is_native {
trace_emit!("\tBL /*C*/ {}({:?})", func, args); trace_emit!("\tBL /*C*/ {}({:?})", func, args);
} else { } else {
...@@ -2413,34 +2420,27 @@ impl CodeGenerator for ASMCodeGen { ...@@ -2413,34 +2420,27 @@ impl CodeGenerator for ASMCodeGen {
mangle_name(func) mangle_name(func)
}; };
let mut ret = ret;
ret.push(LR.clone());
let asm = format!("BL {}", func); let asm = format!("BL {}", func);
self.add_asm_call(asm, pe, args, None); self.internal_call(callsite, asm, pe, args, ret, None, true)
let callsite_symbol = mangle_name(callsite.clone());
self.add_asm_symbolic(directive_globl(callsite_symbol.clone()));
self.add_asm_symbolic(format!("{}:", callsite_symbol.clone()));
ValueLocation::Relocatable(RegGroup::GPR, callsite)
} }
fn emit_blr( fn emit_blr(
&mut self, &mut self,
callsite: String, callsite: Option<String>,
func: Reg, func: Reg,
pe: Option<MuName>, pe: Option<MuName>,
args: Vec<P<Value>> args: Vec<P<Value>>,
) -> ValueLocation { ret: Vec<P<Value>>
) -> Option<ValueLocation> {
trace_emit!("\tBLR {}({:?})", func, args); trace_emit!("\tBLR {}({:?})", func, args);
let mut ret = ret;
ret.push(LR.clone());
let (reg1, id1, loc1) = self.prepare_reg(func, 3 + 1); let (reg1, id1, loc1) = self.prepare_reg(func, 3 + 1);
let asm = format!("BLR {}", reg1); let asm = format!("BLR {}", reg1);
self.add_asm_call(asm, pe, args, Some((id1, loc1))); self.internal_call(callsite, asm, pe, args, ret, Some((id1, loc1)), true)
let callsite_symbol = mangle_name(callsite.clone());
self.add_asm_symbolic(directive_globl(callsite_symbol.clone()));
self.add_asm_symbolic(format!("{}:", callsite_symbol.clone()));
ValueLocation::Relocatable(RegGroup::GPR, callsite)
} }
...@@ -2458,23 +2458,33 @@ impl CodeGenerator for ASMCodeGen { ...@@ -2458,23 +2458,33 @@ impl CodeGenerator for ASMCodeGen {
None None
); );
} }
fn emit_b_func(&mut self, func_name: MuName, args: Vec<P<Value>>) {
trace_emit!("\tB {}({:?})", func_name, args);
let asm = format!("/*TAILCALL*/ B {}", mangle_name(func_name.clone())); fn emit_b_call(
let mut uses: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new(); &mut self,
for arg in args { callsite: Option<String>,
uses.insert(arg.id(), vec![]); func: MuName,
pe: Option<MuName>,
args: Vec<P<Value>>,
ret: Vec<P<Value>>,
is_native: bool,
may_return: bool
) -> Option<ValueLocation> {
if is_native {
trace_emit!("\tB /*C*/ {}({:?})", func, args);
} else {
trace_emit!("\tB {}({:?})", func, args);
} }
self.add_asm_inst_internal(
asm, let func = if is_native {
linked_hashmap!{}, "/*C*/".to_string() + func.as_str()
uses, } else {
false, mangle_name(func)
ASMBranchTarget::Return, };
None
); let asm = format!("/*CALL*/ B {}", func);
self.internal_call(callsite, asm, pe, args, ret, None, may_return)
} }
fn emit_b_cond(&mut self, cond: &str, dest_name: MuName) { fn emit_b_cond(&mut self, cond: &str, dest_name: MuName) {
trace_emit!("\tB.{} {}", cond, dest_name); trace_emit!("\tB.{} {}", cond, dest_name);
...@@ -2503,35 +2513,23 @@ impl CodeGenerator for ASMCodeGen { ...@@ -2503,35 +2513,23 @@ impl CodeGenerator for ASMCodeGen {
None None
); );
} }
fn emit_br_func(&mut self, func_address: Reg, args: Vec<P<Value>>) {
trace_emit!("\tBR {}({:?})", func_address, args);
let (reg1, id1, loc1) = self.prepare_reg(func_address, 2 + 1);
let asm = format!("/*TAILCALL*/ BR {}", reg1);
fn emit_br_call(
&mut self,
callsite: Option<String>,
func: Reg,
pe: Option<MuName>,
args: Vec<P<Value>>,
ret: Vec<P<Value>>,
may_return: bool
) -> Option<ValueLocation> {
trace_emit!("\tBR {}({:?})", func, args);
let mut added_id1 = false; let (reg1, id1, loc1) = self.prepare_reg(func, 3 + 1);
let mut uses: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new(); let asm = format!("/*CALL*/ BR {}", reg1);
for arg in args { self.internal_call(callsite, asm, pe, args, ret, Some((id1, loc1)), may_return)
if arg.id() == id1 {
uses.insert(arg.id(), vec![loc1.clone()]);
added_id1 = true;
} else {
uses.insert(arg.id(), vec![]);
}
}
if !added_id1 {
uses.insert(id1, vec![loc1]);
}
self.add_asm_inst_internal(
asm,
linked_hashmap!{},
uses,
false,
ASMBranchTarget::Return,
None
);
} }
fn emit_cbnz(&mut self, src: Reg, dest_name: MuName) { fn emit_cbnz(&mut self, src: Reg, dest_name: MuName) {
self.internal_branch_op("CBNZ", src, dest_name); self.internal_branch_op("CBNZ", src, dest_name);
} }
......
...@@ -120,26 +120,45 @@ pub trait CodeGenerator { ...@@ -120,26 +120,45 @@ pub trait CodeGenerator {
// Calls // Calls
fn emit_bl( fn emit_bl(
&mut self, &mut self,
callsite: String, callsite: Option<String>,
func: MuName, func: MuName,
pe: Option<MuName>, pe: Option<MuName>,
args: Vec<P<Value>>, args: Vec<P<Value>>,
ret: Vec<P<Value>>,
is_native: bool is_native: bool
) -> ValueLocation; ) -> Option<ValueLocation>;
fn emit_blr( fn emit_blr(
&mut self, &mut self,
callsite: String, callsite: Option<String>,
func: Reg, func: Reg,
pe: Option<MuName>, pe: Option<MuName>,
args: Vec<P<Value>> args: Vec<P<Value>>,
) -> ValueLocation; ret: Vec<P<Value>>
) -> Option<ValueLocation>;
// Branches // Branches
fn emit_b(&mut self, dest_name: MuName); fn emit_b(&mut self, dest_name: MuName);
fn emit_b_func(&mut self, func: MuName, args: Vec<P<Value>>); // For tail calls
fn emit_b_cond(&mut self, cond: &str, dest_name: MuName); fn emit_b_cond(&mut self, cond: &str, dest_name: MuName);
fn emit_br(&mut self, dest_address: Reg); fn emit_br(&mut self, dest_address: Reg);
fn emit_br_func(&mut self, func_address: Reg, args: Vec<P<Value>>); // For tail calls fn emit_b_call(
&mut self,
callsite: Option<String>,
func: MuName,
pe: Option<MuName>,
args: Vec<P<Value>>,
ret: Vec<P<Value>>,
is_native: bool,
may_return: bool
) -> Option<ValueLocation>;
fn emit_br_call(
&mut self,
callsite: Option<String>,
func: Reg,
pe: Option<MuName>,
args: Vec<P<Value>>,
ret: Vec<P<Value>>,
may_return: bool
) -> Option<ValueLocation>;
fn emit_ret(&mut self, src: Reg); fn emit_ret(&mut self, src: Reg);
fn emit_cbnz(&mut self, src: Reg, dest_name: MuName); fn emit_cbnz(&mut self, src: Reg, dest_name: MuName);
......
This diff is collapsed.
...@@ -1199,7 +1199,8 @@ impl ASMCodeGen { ...@@ -1199,7 +1199,8 @@ impl ASMCodeGen {
&mut self, &mut self,
code: String, code: String,
potentially_excepting: Option<MuName>, potentially_excepting: Option<MuName>,
arguments: Vec<P<Value>>, use_vec: Vec<P<Value>>,
def_vec: Vec<P<Value>>,
target: Option<(MuID, ASMLocation)> target: Option<(MuID, ASMLocation)>
) { ) {
let mut uses: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new(); let mut uses: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new();
...@@ -1207,20 +1208,13 @@ impl ASMCodeGen { ...@@ -1207,20 +1208,13 @@ impl ASMCodeGen {
let (id, loc) = target.unwrap(); let (id, loc) = target.unwrap();
uses.insert(id, vec![loc]); uses.insert(id, vec![loc]);
} }
for arg in arguments { for u in use_vec {
uses.insert(arg.id(), vec![]); uses.insert(u.id(), vec![]);
} }
let mut defines: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new(); let mut defines: LinkedHashMap<MuID, Vec<ASMLocation>> = LinkedHashMap::new();
for reg in x86_64::CALLER_SAVED_GPRS.iter() { for d in def_vec {
if !defines.contains_key(&reg.id()) {