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());