GitLab will be upgraded on June 2nd 2020 at 2.00 pm (AEDT) to 3.00 pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to local Gitlab admin team.

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
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// a pointer to asm label of serialized vm
//extern void* vm;
// a pointer to the symbol table I generate
extern void* mu_sym_table_root;
void * mu_sym_table = NULL;
extern int32_t mu_retval;
int32_t muentry_get_retval(){
return mu_retval;
}
unsigned long * get_sym_table_root(){
return (unsigned long *) &mu_sym_table_root;
}
char * get_sym_table_pointer(){
return (char *) &mu_sym_table;
}
// a function to return a pointer to serialized vm, to rust
char * get_vm_pointer(unsigned long idx){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_vm_pointer: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == idx){
return current_root[2];
}
else{
current_root += 4;
}
}
return NULL;
}
// This function returns 0 if test type is integer and 1 if test type is float
// for integer tests use =>
// get_input_value(,,)
// get_output_value(,,)
// for float tests use =>
// get_fp_input_value(,,)
// get_fp_output_value(,,)
// And these functions are common for both types =>
// get_number_of_testcases()
// get_number_of_input()
// get_number_of_outputs()
unsigned long get_type_of_testcases(unsigned long test_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_type_of_testcases: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long type_of_testcases = test_root[0];
unsigned long number_of_testcases = test_root[1]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[2]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[3];
return type_of_testcases;
}
else{
current_root += 4;
}
}
return 0;
}
unsigned long get_number_of_testcases(unsigned long test_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_number_of_testcases: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long type_of_testcases = test_root[0];
unsigned long number_of_testcases = test_root[1]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[2]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[3];
return number_of_testcases;
}
else{
current_root += 4;
}
}
return 0;
}
unsigned long get_number_of_inputs(unsigned long test_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_number_of_inputs: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long number_of_testcases = test_root[1]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[2]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[3];
return number_of_inputs;
}
else{
current_root += 4;
}
}
return 0;
}
unsigned long get_number_of_outputs(unsigned long test_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_number_of_outputs: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long number_of_testcases = test_root[0]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[1]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[2];
return number_of_outputs;
}
else{
current_root += 4;
}
}
return 0;
}
// specific to integer tests
long get_input_value(unsigned long test_index, unsigned long testcase_index, unsigned long input_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_input_value: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long number_of_testcases = test_root[1]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[2]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[3];
if ( testcase_index < (number_of_testcases+1) ){
unsigned long exact_index = 4;
exact_index += (testcase_index) * (number_of_inputs+number_of_outputs);
exact_index += (input_index - 1);
return test_root[exact_index];
}
else{
printf("get_input_value: testcase_index out of range!\n");
return 0;
}
}
else{
current_root += 4;
}
}
return 0;
}
int get_output_value(unsigned long test_index, unsigned long testcase_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_output_value: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long number_of_testcases = test_root[1]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[2]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[3];
// for tests which don't have a return value
if (number_of_testcases == 0)
return 0;
if ( testcase_index < (number_of_testcases) ){
unsigned long exact_index = 4;
exact_index += (testcase_index) * (number_of_inputs+number_of_outputs);
exact_index += (number_of_inputs);
return test_root[exact_index];
}
else{
printf("get_output_value: testcase_index out of range!\n");
// printf("%d\n", testcase_index);
return 0;
}
}
else{
current_root += 4;
}
}
return 0;
}
// specific to float tests
double get_fp_input_value(unsigned long test_index, unsigned long testcase_index, unsigned long input_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_input_value: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long number_of_testcases = test_root[1]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[2]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[3];
double * fp_test_root = (double *)(&test_root[4]);
if ( testcase_index < (number_of_testcases+1) ){
unsigned long exact_index = 0;
exact_index += (testcase_index) * (number_of_inputs+number_of_outputs);
exact_index += (input_index - 1);
return fp_test_root[exact_index];
}
else{
printf("get_fp_input_value: testcase_index out of range!\n");
return 0;
}
}
else{
current_root += 4;
}
}
return 0;
}
double get_fp_output_value(unsigned long test_index, unsigned long testcase_index){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_output_value: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long ii;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
if( current_root[0] == test_index){
// pointer to testcase data for current test_index is found
unsigned long * test_root = (unsigned long *) current_root[3];
unsigned long number_of_testcases = test_root[1]; // first cell is the number of testcases
unsigned long number_of_inputs = test_root[2]; // second cell is the number of inputs for this test
unsigned long number_of_outputs = test_root[3];
double * fp_test_root = (double *)(&test_root[4]);
// for tests which don't have a return value
if (number_of_testcases == 0)
return 0;
if ( testcase_index < (number_of_testcases) ){
unsigned long exact_index = 0;
exact_index += (testcase_index) * (number_of_inputs+number_of_outputs);
exact_index += (number_of_inputs);
return fp_test_root[exact_index];
}
else{
printf("get_output_value: testcase_index out of range!\n");
// printf("%d\n", testcase_index);
return 0;
}
}
else{
current_root += 4;
}
}
return 0;
}
unsigned long get_number_of_tests(){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("get_number_of_tests: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
return (unsigned long) current_root[0];
}
// a function to resolve symbol names to their address, using mu_sym_table\
// which is valued by the c_resolve_sym function, according to \
// mu_sym_table_root
// actually this function will search for the symbol in one idX_sym_table
void * resolve_symbol_in_current_context(const unsigned char * input_symbol_name){
unsigned long i = 0, j=0;
unsigned long num_of_syms = 0;
unsigned long cur_len = 0;
unsigned long input_len = 0;
unsigned char cur_char = 0;
unsigned long cur_add = 0;
unsigned char is_different = 0;
while(input_symbol_name[input_len] != 0){
input_len++;
}
if( (mu_sym_table == NULL) || (input_len == 0)){
printf("**********\n****ERROR!!!****\nC_RESOLVE_SYMBOL: extern mu sym table is null!\n*********\n");
assert(0);
}
// a copy of mu_sym_table, to keep mu_sym_table from changing
// unsigned char * sym_table_current = (unsigned char *) get_sym_table_pointer();
unsigned char * sym_table_current = (unsigned char *) mu_sym_table;
// printf("C_RESOLVE_SYMBOL --> Step 1\n");
// printf("C_RESOLVE_SYMBOL --> Current mu_sym_table = %p\n", sym_table_current);
// printf("C_RESOLVE_SYMBOL --> Current vm = %p\n", get_vm_pointer());
// read the total number of symbols from the first line of sym table
num_of_syms = *((unsigned long*)sym_table_current);
// printf("RESOLVE_SYM --> number of symbols = %d\n", num_of_syms);
// go 8 bytes forward, to skip the current .quad
sym_table_current += 8;
for(i=0; i<num_of_syms; i++){
is_different = 0;
// length of the symbol we are going to check
cur_len = *((unsigned long*)sym_table_current);
if(cur_len != input_len){
sym_table_current += 8; //cur_len
sym_table_current += 8; //cur_add
sym_table_current += cur_len; //length of cur_name
// printf("*** Sym name doesn't match! ***\n");
continue;
}
sym_table_current += 8;
// printf("Sym_Tbl current Len = %d\n", cur_len);
for(j=0; j<cur_len; j++){
cur_char = *((unsigned char*)sym_table_current);
sym_table_current += 1;
// printf("Sym_Tbl read char = %d , input symbol current char = %d\n", cur_char, input_symbol_name[j]);
if(cur_char == input_symbol_name[j]){
continue;
}
else{
is_different = 1;
sym_table_current += ((cur_len-j)-1);
break;
}
}
if(is_different == 1){
// skip the 64b address in current location and continue to the next sym in table
// printf("*** Sym name doesn't match! ***\n");
sym_table_current += 8;
continue;
}
else{
// printf("*** Sym name = %s! Sym Address = %llu***\n", input_symbol_name, *((long*) sym_table_current));
// printf("*** Last char = %c\n", sym_table_current[-1]);
// for(j=0; j<8; j++){
// printf("*** Last char = %c\n", sym_table_current[j]);
// }
unsigned long result = 0;
unsigned long shifter=1;
unsigned int ii=0, jj=0;
for (ii=0; ii<8; ii++){
shifter = 1;
for(jj=0; jj<ii; jj++)
shifter = shifter * 256;
result += ((sym_table_current[ii]%256)* shifter);
// printf("Char = %x\n", (sym_table_current[ii]%256));
// printf("Result = %llu\n", result);
}
// printf("*** going to return {-%llu-}\n", result);
return ((void*) result);
}
}
return NULL;
}
void * c_resolve_symbol(const unsigned char * input_symbol_name){
unsigned long * current_root = get_sym_table_root();
if(current_root == NULL){
printf("c_resolve_symbol: SYM TABLE ROOT IS NULL\n\n");
assert(0);
}
unsigned long idX = 0;
unsigned long ii;
unsigned long * table_pointer = NULL;
// get the total number of idXs
unsigned long num_of_idXs = (unsigned long) current_root[0];
// go to next unsigned long, which is the first idX
current_root++;
for (ii=0; ii<num_of_idXs; ii++){
idX = current_root[0];
table_pointer = current_root[1];
mu_sym_table = table_pointer;
table_pointer = resolve_symbol_in_current_context(input_symbol_name);
if(table_pointer == NULL){
current_root += 4;
continue;
}
break;
}
return table_pointer;
}
......@@ -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<