Using Mu IR to give test inputs and read outputs: Bin Op tests work now.

parent c5863f83
# Copyright 2017 The Australian National University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Copyright 2017 The Australian National University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[package]
name = "mu"
version = "0.0.1"
......@@ -26,6 +26,7 @@ doctest = false
default = ["aot"]
aot = []
jit = []
sel4-rumprun = []
[build-dependencies]
gcc = "0.3"
......
......@@ -43,4 +43,23 @@ fn main() {
gcc::Config::new().flag("-O3").flag("-c")
.file("src/runtime/swap_stack_aarch64_sysv.S")
.compile("libswap_stack.a");
}
#[cfg(feature = "sel4-rumprun")]
#[cfg(target_arch = "x86_64")]
fn main() {
let mut compiler_name = String::new();
compiler_name.push_str("x86_64-rumprun-netbsd-gcc");
gcc::Config::new().flag("-O3").flag("-c")
.compiler(Path::new(compiler_name.as_str()))
.file("src/runtime/runtime_x64_sel4_rumprun_sysv.c")
.compile("libruntime.a");
gcc::Config::new().flag("-O3").flag("-c")
.compiler(Path::new(compiler_name.as_str()))
.file("src/runtime/swap_stack_x64_sysv.S")
.compile("libswap_stack.a");
gcc::Config::new().flag("-O3").flag("-c")
.compiler(Path::new(compiler_name.as_str()))
.file("c_helpers.c")
.compile("libc_helpers.a");
}
\ No newline at end of file
This diff is collapsed.
......@@ -142,7 +142,8 @@ impl Instruction {
| CommonInst_Pin(_)
| CommonInst_Unpin(_)
| Move(_)
| PrintHex(_) => None
| PrintHex(_)
| SetRetval(_) => None
}
}
......@@ -357,7 +358,8 @@ pub enum Instruction_ {
// internal use: mov from ops[0] to value
Move(OpIndex),
// internal use: print op as hex value
PrintHex(OpIndex)
PrintHex(OpIndex),
SetRetval(OpIndex)
}
impl Instruction_ {
......@@ -484,7 +486,9 @@ impl Instruction_ {
// move
&Instruction_::Move(from) => format!("MOVE {}", ops[from]),
// print hex
&Instruction_::PrintHex(i) => format!("PRINTHEX {}", ops[i])
&Instruction_::PrintHex(i) => format!("PRINTHEX {}", ops[i]),
// set retval
&Instruction_::SetRetval(val) => format!("SETRETVAL {}", ops[val])
}
}
}
......
......@@ -47,7 +47,8 @@ pub fn is_terminal_inst(inst: &Instruction_) -> bool {
| &CommonInst_Pin(_)
| &CommonInst_Unpin(_)
| &Move(_)
| &PrintHex(_) => false,
| &PrintHex(_)
| &SetRetval(_) => false,
&Return(_)
| &ThreadExit
| &Throw(_)
......@@ -114,7 +115,8 @@ pub fn has_side_effect(inst: &Instruction_) -> bool {
&CommonInst_Pin(_) => true,
&CommonInst_Unpin(_) => true,
&Move(_) => false,
&PrintHex(_) => true
&PrintHex(_) => true,
&SetRetval(_) => true
}
}
......@@ -164,6 +166,7 @@ pub fn is_potentially_excepting_instruction(inst: &Instruction_) -> bool {
| &CommonInst_Pin(_)
| &CommonInst_Unpin(_)
| &Move(_)
| &PrintHex(_) => false
| &PrintHex(_)
| &SetRetval(_) => false
}
}
\ No newline at end of file
......@@ -80,7 +80,8 @@ pub enum OpCode {
CommonInst_Unpin,
Move,
PrintHex
PrintHex,
SetRetval
}
pub fn pick_op_code_for_ssa(ty: &P<MuType>) -> OpCode {
......@@ -392,5 +393,6 @@ pub fn pick_op_code_for_inst(inst: &Instruction) -> OpCode {
Instruction_::CommonInst_Unpin(_) => OpCode::CommonInst_Unpin,
Instruction_::Move(_) => OpCode::Move,
Instruction_::PrintHex(_) => OpCode::PrintHex,
Instruction_::SetRetval(_) => OpCode::SetRetval,
}
}
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![warn(unused_imports)]
#![warn(unreachable_code)]
......@@ -1179,6 +1179,24 @@ impl <'a> InstructionSelection {
);
}
// Runtime Entry
Instruction_::SetRetval(index) => {
trace!("instsel on SETRETVAL");
let ref ops = inst.ops.read().unwrap();
let ref op = ops[index];
assert!(self.match_ireg(op));
let retval = self.emit_ireg(op, f_content, f_context, vm);
self.emit_runtime_entry(
&entrypoints::SET_RETVAL,
vec![op.clone_value()],
None,
Some(node), f_context, vm
);
}
_ => unimplemented!()
} // main switch
},
......
......@@ -3028,7 +3028,25 @@ impl CodeGenerator for ASMCodeGen {
ValueLocation::Relocatable(RegGroup::GPR, callsite)
}
#[cfg(feature = "sel4-rumprun")]
// exactly the same as Linux:
// generating Position-Independent Code using PLT
fn emit_call_near_rel32(&mut self, callsite: String, func: MuName, pe: Option<MuName>) -> ValueLocation {
trace!("emit: call {}", func);
let func = func + "@PLT";
let asm = format!("call {}", symbol(func));
self.add_asm_call(asm, pe);
let callsite_symbol = symbol(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_call_near_r64(&mut self, callsite: String, func: &P<Value>, pe: Option<MuName>) -> ValueLocation {
trace!("emit: call {}", func);
......@@ -3437,6 +3455,13 @@ fn write_align(f: &mut File, align: ByteSize) {
f.write_fmt(format_args!("\t.align {}\n", n)).unwrap();
}
// The alignment is exactly the same as Linux
#[cfg(feature = "sel4-rumprun")]
fn write_align(f: &mut File, align: ByteSize) {
use std::io::Write;
f.write_fmt(format_args!("\t.align {}\n", check_min_align(align))).unwrap();
}
fn write_const(f: &mut File, constant: P<Value>, loc: P<Value>) {
use std::io::Write;
......@@ -3689,6 +3714,12 @@ pub fn symbol(name: String) -> String {
pub fn symbol(name: String) -> String {
format!("_{}", name)
}
// same as Linux
#[cfg(feature = "sel4-rumprun")]
pub fn symbol(name: String) -> String {
name
}
#[allow(dead_code)]
#[cfg(target_os = "linux")]
......@@ -3700,6 +3731,12 @@ pub fn pic_symbol(name: String) -> String {
pub fn pic_symbol(name: String) -> String {
symbol(name)
}
// same as Linux
#[allow(dead_code)]
#[cfg(feature = "sel4-rumprun")]
pub fn pic_symbol(name: String) -> String {
format!("{}@GOTPCREL", name)
}
use compiler::machine_code::CompiledFunction;
......
......@@ -1444,7 +1444,24 @@ impl <'a> InstructionSelection {
Some(node), f_content, f_context, vm
);
}
Instruction_::SetRetval(index) => {
trace!("instsel on SETRETVAL");
let ref ops = inst.ops;
let ref op = ops[index];
assert!(self.match_ireg(op));
let retval = self.emit_ireg(op, f_content, f_context, vm);
self.emit_runtime_entry(
&entrypoints::SET_RETVAL,
vec![op.clone_value()],
None,
Some(node), f_content, f_context, vm
);
}
_ => unimplemented!()
} // main switch
},
......@@ -3932,6 +3949,9 @@ impl <'a> InstructionSelection {
} else if cfg!(target_os = "linux") {
let mem = self.get_mem_for_funcref(func_id, vm);
self.backend.emit_mov_r_mem(&tmp, &mem);
} else if cfg!(feature = "sel4-rumprun") {
let mem = self.get_mem_for_funcref(func_id, vm);
self.backend.emit_mov_r_mem(&tmp, &mem);
} else {
unimplemented!()
}
......@@ -4125,6 +4145,25 @@ impl <'a> InstructionSelection {
let actual_loc = self.make_temporary(f_context, pv.ty.clone(), vm);
self.emit_move_value_to_value(&actual_loc, &got_loc);
self.make_memory_op_base_offset(&actual_loc, 0, types::get_referent_ty(&pv.ty).unwrap(), vm)
} else if cfg!(feature = "sel4-rumprun") {
// for a(%RIP), we need to load its address from a@GOTPCREL(%RIP)
// then load from the address.
// asm_backend will emit a@GOTPCREL(%RIP) for a(%RIP)
let got_loc = P(Value {
hdr: MuEntityHeader::unnamed(vm.next_id()),
ty: pv.ty.clone(),
v: Value_::Memory(MemoryLocation::Symbolic {
base: Some(x86_64::RIP.clone()),
label: pv.name().unwrap(),
is_global: true
})
});
// mov (got_loc) -> actual_loc
let actual_loc = self.make_temporary(f_context, pv.ty.clone(), vm);
self.emit_move_value_to_value(&actual_loc, &got_loc);
self.make_memory_op_base_offset(&actual_loc, 0, types::get_referent_ty(&pv.ty).unwrap(), vm)
} else {
unimplemented!()
......@@ -4695,7 +4734,9 @@ impl <'a> InstructionSelection {
layout[index] as i32
}
// Primordial function name was added as part of the callsite label \
// because it avoids conflicts between labels of different tests
fn new_callsite_label(&mut self, cur_node: Option<&TreeNode>) -> String {
let ret = {
if cur_node.is_some() {
......
......@@ -529,6 +529,7 @@ pub fn estimate_insts_for_ir(inst: &Instruction) -> usize {
// others
Move(_) => 0,
PrintHex(_) => 10,
SetRetval(_) => 10,
ExnInstruction{ref inner, ..} => estimate_insts_for_ir(&inner)
}
}
......@@ -32,3 +32,14 @@ fn main() {
fn main() {
gcc::compile_library("libgc_clib_aarch64.a", &["src/heap/gc/clib_aarch64.S"]);
}
#[cfg(feature = "sel4-rumprun")]
#[cfg(target_arch = "x86_64")]
fn main() {
let mut compiler_name = String::new();
compiler_name.push_str("x86_64-rumprun-netbsd-gcc");
gcc::Config::new().flag("-O3").flag("-c")
.compiler(Path::new(compiler_name.as_str()))
.file("src/heap/gc/clib_x64_sel4_rumprun.c")
.compile("libgc_clib_x64_sel4_rumprun.a");
}
\ No newline at end of file
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
void* malloc_zero(size_t size) {
void* ret = malloc(size);
memset(ret, 0, size);
return ret;
}
uintptr_t immmix_get_stack_ptr() {
uintptr_t rsp;
// get current rsp, rbp (this C func frame)
__asm__(
"mov %%rsp, %0 \n"
: "=rm" (rsp)
);
return rsp;
}
int get_registers_count() {
return 16;
}
uintptr_t* get_registers () {
uintptr_t rax, rbx, rcx, rdx, rbp, rsp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15;
__asm__(
"mov %%rax, %0 \n"
"mov %%rbx, %1 \n"
"mov %%rcx, %2 \n"
"mov %%rdx, %3 \n"
"mov %%rbp, %4 \n"
"mov %%rsp, %5 \n"
"mov %%rsi, %5 \n"
"mov %%rdi, %6 \n"
"mov %%r8, %7 \n"
"mov %%r9, %8 \n"
"mov %%r10, %10\n"
"mov %%r11, %11\n"
"mov %%r12, %12\n"
"mov %%r13, %13\n"
"mov %%r14, %14\n"
"mov %%r15, %15\n"
: "=m" (rax),
"=m" (rbx),
"=m" (rcx),
"=m" (rdx),
"=m" (rbp),
"=m" (rsp),
"=m" (rsi),
"=m" (rdi),
"=m" (r8),
"=m" (r9),
"=m" (r10),
"=m" (r11),
"=m" (r12),
"=m" (r13),
"=m" (r14),
"=m" (r15)
:
:
);
uintptr_t* ret = (uintptr_t*) malloc(sizeof(uintptr_t) * 16);
ret[0] = rax;
ret[1] = rbx;
ret[2] = rcx;
ret[3] = rdx;
ret[4] = rbp;
ret[5] = rsp;
ret[6] = rsi;
ret[7] = rdi;
ret[8] = r8;
ret[9] = r9;
ret[10] = r10;
ret[11] = r11;
ret[12] = r12;
ret[13] = r13;
ret[14] = r14;
ret[15] = r15;
return ret;
}
// __thread uintptr_t low_water_mark;
int lwm_initialized = 0;
static pthread_key_t low_water_mark;
void set_low_water_mark () {
uintptr_t rsp;
if(lwm_initialized == 0){
lwm_initialized = 1;
int result = pthread_key_create(&low_water_mark, NULL);
if(result != 0){
printf("set_low_water_mark(): PThread key create failed with error code = %d\n", result);
assert(0);
}
}
// get current rsp, rbp (this C func frame)
__asm__(
"mov %%rsp, %0 \n"
: "=rm" (rsp)
);
int result = pthread_setspecific(low_water_mark, (const void *) rsp);
if(result != 0){
printf("set_low_water_mark(): PThread set specific failed with error code = %d\n", result);
assert(0);
}
}
uintptr_t get_low_water_mark() {
if(lwm_initialized == 0){
printf("get_low_water_mark(): PThread key MUST be initialized before first use!!\n");
}
void * result = pthread_getspecific(low_water_mark);
if(result == NULL){
printf("get_low_water_mark(): NO pthread key found for current thread!!\n");
assert(0);
}
return (uintptr_t) result;
}
......@@ -87,6 +87,18 @@ extern "C" {
fn get_registers_count() -> i32;
}
#[cfg(target_arch = "x86_64")]
#[cfg(feature = "sel4-rumprun")]
#[link(name = "gc_clib_x64_sel4_rumprun")]
extern "C" {
pub fn malloc_zero(size: usize) -> *const c_void;
fn immmix_get_stack_ptr() -> Address;
pub fn set_low_water_mark();
fn get_low_water_mark() -> Address;
fn get_registers() -> *const Address;
fn get_registers_count() -> i32;
}
pub fn stack_scan() -> Vec<ObjectReference> {
trace!("stack scanning...");
let stack_ptr : Address = unsafe {immmix_get_stack_ptr()};
......
# Copyright 2017 The Australian National University
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
// This file provides a template so that we can define functions in ASM and also
// let the symbols be recognised in both Linux and OSX
#define CNAME(n) n
.macro begin_func n
.text
.globl CNAME(\n)
.type CNAME(\n),@function
.balign 16
CNAME(\n):
.endm
.macro end_func n
.size CNAME(\n), .-CNAME(\n)
.endm
; vim: ft=asm
......@@ -42,7 +42,19 @@ lazy_static! {
aot: ValueLocation::Relocatable(RegGroup::GPR, String::from("muentry_get_thread_local")),
jit: RwLock::new(None),
};
// impl: runtime_x64_sysv.c
// decl: thread.rs
pub static ref SET_RETVAL : RuntimeEntrypoint = RuntimeEntrypoint {
sig: P(MuFuncSig {
hdr: MuEntityHeader::unnamed(ir::new_internal_id()),
ret_tys: vec![],
arg_tys: vec![UINT32_TYPE.clone()]
}),
aot: ValueLocation::Relocatable(RegGroup::GPR, String::from("muentry_set_retval")),
jit: RwLock::new(None)
};
// impl: swap_stack_x64_macos.s
// decl: thread.rs
pub static ref SWAP_BACK_TO_NATIVE_STACK : RuntimeEntrypoint = RuntimeEntrypoint {
......
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>
extern void* vm;
extern void mu_main(char*, int, char**);
extern int32_t c_check_result();
int main(int argc, char** argv) {
char* serialize_vm = (char*) &vm;
mu_main(serialize_vm, argc, argv);
assert(c_check_result() == 0);
}
......@@ -21,6 +21,7 @@ use utils::Address;
use std::fmt;
use std::os::raw::c_int;
use std::os::raw::c_long;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::ffi::CString;
......@@ -43,6 +44,7 @@ pub mod exception;
// consider using libloading crate instead of the raw c functions for dynalic libraries
// however i am not sure if libloading can load symbols from current process (not from an actual dylib)
// so here i use dlopen/dlsym from C
#[cfg(not(feature = "sel4-rumprun"))]
#[link(name="dl")]
extern "C" {
fn dlopen(filename: *const c_char, flags: isize) -> *const c_void;
......@@ -50,6 +52,7 @@ extern "C" {
fn dlerror() -> *const c_char;
}
#[cfg(not(feature = "sel4-rumprun"))]
pub fn resolve_symbol(symbol: String) -> Address {
use std::ptr;
......@@ -70,6 +73,45 @@ pub fn resolve_symbol(symbol: String) -> Address {
Address::from_ptr(ret)
}
// This function is specific to sel4-rumprun platform
// it replaces the resolve_symbol function provided by Linux and Mac
// all other platforms (except sel4-rumprun) already provide this function
#[cfg(feature = "sel4-rumprun")]
#[link(name="c_helpers")]
extern "C" {
fn c_resolve_symbol(symbol: *const c_char) -> *const c_void;
}
// Although it is possible to directly \
// compile, call and check results of Mu test functions \
// in Linux and Mac, but in-order to unify testing styles \
// I will use this C function to check the correctness of results
// *************************************************
// #[link(name="runtime")]
// extern "C" {
// fn c_check_result() -> c_long;
// }
//
// pub fn check_result() -> c_long {
// let result = unsafe { c_check_result() };
// result
// }
// *************************************************
// This code has been moved to thread.rs \
// due to the linkage with libruntime.a happenning there once
// TODO
// resolve symbol is different from the one used for Linux and Mac
#[cfg(feature = "sel4-rumprun")]
pub fn resolve_symbol(symbol: String) -> Address {
let ret = unsafe { c_resolve_symbol(CString::new(symbol.clone()).unwrap().as_ptr()) };
if ret.is_null() {
panic!("failed to resolve symbol: {}", symbol.clone());
}
debug!("Symbol -{}- resolved", symbol);
Address::from_ptr(ret)
}
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
......@@ -206,6 +248,7 @@ impl ValueLocation {
}
pub const PRIMORDIAL_ENTRY : &'static str = "src/runtime/main.c";
pub const TEST_PRIMORDIAL_ENTRY : &'static str = "src/runtime/main_test.c";
#[no_mangle]
pub extern fn mu_trace_level_log() {
......
......@@ -67,4 +67,14 @@ void* resolve_symbol(const char* sym) {
// B dlsym
// printf("%s\n", sym);
return dlsym(RTLD_DEFAULT, sym);
}
int32_t mu_retval;
void muentry_set_retval(int32_t x) {
mu_retval = x;
}
int32_t c_check_result() {
return mu_retval;
}
\ No newline at end of file
// Copyright 2017 The Australian National University
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software