GitLab will be upgraded to the 12.10.14-ce.0 on 28 Sept 2020 at 2.00pm (AEDT) to 2.30pm (AEDT). During the update, GitLab and Mattermost services will not be available. If you have any concerns with this, please talk to us at N110 (b) CSIT building.

...
 
Commits (19)
#!/usr/bin/python3
import subprocess, sys
a = sys.argv[:]
a[0] = 'clang'
o = a[:]
try:
i = a.index('-o')
f = a[i+1]
if not f.endswith('.o'):
raise ValueError
f = f.replace('.o', '.ll')
a[i+1] = f
a.extend(['-S', '-emit-llvm'])
e = subprocess.call(a) # compile to llvm
if e != 0:
sys.exit(e)
o.remove('-O3')
o.append('-O0')
for i, v in enumerate(o):
if v.endswith('.c'):
o[i] = f
except ValueError as valerr:
pass
sys.exit(subprocess.call(o))
# 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.
alloc:
iterations: 50
benchmark:
name: micro/alloc
args:
- 1 # scale factor
- 5000000
callback:
name: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetalloc.py
compiler:
flags:
- --gc=none
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
c_O3:
language:
name: rpython
backend: c
source: targetalloc.py
compiler:
flags:
- --gc=none
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetalloc.py
compiler:
pypydir: $PYPY_MU
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
btree:
benchmark:
name: game/binarytrees
args:
- 15 # depth
iterations: 50
callback: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetbtree.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
c_O3:
language:
name: rpython
backend: c
source: targetbtree.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetbtree.py
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
compare:
- - rpyc_no_gc
- rpyzebu
# The first custom (in this case 2000) is the recursion depth
# the second argument means:
# 0 don't throw an exception, but still have a catch block at the top
# 1 do throw an exception at the bottom of the recursion (to be caught by the top)
# 2 don't throw an exception, with no catch block
# the third argument is the scale factor
except:
benchmark:
name: micro/except
args:
- 26000
- 1
- 1
iterations: 50
callback:
name: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetexcept.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
c_O3:
language:
name: rpython
backend: c
source: targetexcept.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetexcept.py
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
pypydir: $PYPY_MU
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
fannkuchredux:
benchmark:
name: game/fannkuchredux
args:
- 10
iterations: 50
callback: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetfannkuchredux.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
c_O3:
language:
name: rpython
backend: c
source: targetfannkuchredux.py
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetfannkuchredux.py
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
compare:
- - rpyc_no_gc
- rpyzebu
fib:
iterations: 50
benchmark:
name: micro/fib
args:
- 1 # scale factor
- 36
callback:
name: clock
environ:
PYPY_USESSION_DIR: ci # controls where PyPy puts usession directory
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetfib.py
compiler:
flags:
- --gc=none
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
c_O3:
language:
name: rpython
backend: c
source: targetfib.py
compiler:
flags:
- --gc=none
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetfib.py
compiler:
pypydir: $PYPY_MU
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compare:
- - rpyc_O3
- rpyzebu
nbody:
benchmark:
name: game/nbody
args:
- 500000
iterations: 50
callback: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetnbody.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
c_O3:
language:
name: rpython
backend: c
source: targetnbody.py
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetnbody.py
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
pidigits:
benchmark:
name: game/pidigits
args:
- 1000000 # depth
iterations: 50
callback: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetpidigits.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
c_O3:
language:
name: rpython
backend: c
source: targetpidigits.py
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetpidigits.py
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
# NOTE: the scale factor of this test is specified at compile time
quicksort:
benchmark:
name: micro/quicksort
iterations: 50
callback:
name: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetquicksort.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
args:
- &scale_factor 1000
c_O3:
language:
name: rpython
backend: c
source: targetquicksort.py
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
args:
- *scale_factor
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetquicksort.py
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
args:
- *scale_factor
som:
iterations: 50
benchmark:
name: SOM
args:
- 5 # scale factor
- -cp
- $RPYSOM/Smalltalk
- $RPYSOM/TestSuite/TestHarness.som
callback: clock
environ:
PYPY_USESSION_DIR: ci
PYTHONPATH: $RPYSOM/src
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetrpysom.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
flags:
- --gc=none
c_O3:
language:
name: rpython
backend: c
source: targetrpysom.py
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
flags:
- --gc=none
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetrpysom.py
environ:
ZEBU_BUILD: "release"
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
vmargs:
- --gc-immixspace-size=1024288000
- --gc-lospace-size=204587600
spectralnorm:
benchmark:
name: game/spectralnorm
args:
- 1000 # depth
iterations: 50
callback: clock
environ:
PYPY_USESSION_DIR: ci
tasks:
c_O0:
language:
name: rpython
backend: c
source: targetspectralnorm.py
environ:
CC: $MU_ZEBU/clang-O3-O0
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
c_O3:
language:
name: rpython
backend: c
source: targetspectralnorm.py
environ:
PYPY_C_CLANG_OPT_FLAG: -O3
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
flags:
- --gc=none
zebu:
language:
name: rpython
backend: mu
impl: zebu
source: targetspectralnorm.py
environ:
PYPY_USESSION_BASENAME: "${MUBENCH_TASKSET_NAME}_${MUBENCH_TASK_NAME}"
compiler:
vmargs:
- --gc-immixspace-size=524288000 # 500M
- --gc-lospace-size=104587600 # 100M
......@@ -2583,7 +2583,7 @@ impl CodeGenerator for ASMCodeGen {
) -> Option<ValueLocation> {
trace_emit!("\tBR {}({:?})", func, args);
let (reg1, id1, loc1) = self.prepare_reg(func, 3 + 1);
let (reg1, id1, loc1) = self.prepare_reg(func, 11 + 1);
let asm = format!("/*CALL*/ BR {}", reg1);
self.internal_call(callsite, asm, pe, args, ret, Some((id1, loc1)), may_return)
}
......@@ -3545,11 +3545,11 @@ pub fn emit_code(fv: &mut MuFunctionVersion, vm: &VM) {
}
}
// min alignment as 4 bytes
// min alignment is 16 bytes
const MIN_ALIGN: ByteSize = 4;
fn check_min_align(align: ByteSize) -> ByteSize {
if align > MIN_ALIGN {
if align < MIN_ALIGN {
MIN_ALIGN
} else {
align
......@@ -3698,8 +3698,11 @@ pub fn emit_context_with_reloc(
for obj_dump in objects.values() {
write_align(&mut file, 8);
// .bytes xx,xx,xx,xx (between mem_start to reference_addr)
write_data_bytes(&mut file, obj_dump.mem_start, obj_dump.reference_addr);
if vm.vm_options.flag_use_alloc {
// Write object header
// .bytes xx,xx,xx,xx (between mem_start to reference_addr)
write_data_bytes(&mut file, obj_dump.mem_start, obj_dump.reference_addr);
}
if global_addr_id_map.contains_key(&obj_dump.reference_addr) {
let global_id = global_addr_id_map.get(&obj_dump.reference_addr).unwrap();
......
......@@ -1428,12 +1428,12 @@ impl<'a> InstructionSelection {
trace!("instsel on THREADEXIT");
// emit a call to swap_back_to_native_stack(sp_loc: Address)
let tmp = make_temporary(f_context, UINT64_TYPE.clone(), vm);
// get thread local and add offset to get sp_loc
let tl = self.emit_get_threadlocal(f_context, vm);
emit_load_base_offset(
self.backend.as_mut(),
&tl,
&tl,
&tmp,
&MU_TL,
*thread::NATIVE_SP_LOC_OFFSET as i64,
f_context,
vm
......@@ -1441,7 +1441,7 @@ impl<'a> InstructionSelection {
self.emit_runtime_entry(
&entrypoints::THREAD_EXIT,
vec![tl.clone()],
vec![tmp.clone()],
None,
Some(node),
f_context,
......@@ -1488,16 +1488,13 @@ impl<'a> InstructionSelection {
Instruction_::CurrentStack => {
trace!("instsel on CURRENT_STACK");
// get thread local
let tl = self.emit_get_threadlocal(f_context, vm);
let tmp_res = self.get_result_value(node, 0);
// load [tl + STACK_OFFSET] -> tmp_res
emit_load_base_offset(
self.backend.as_mut(),
&tmp_res,
&tl,
&MU_TL,
*thread::STACK_OFFSET as i64,
f_context,
vm
......@@ -1506,15 +1503,13 @@ impl<'a> InstructionSelection {
Instruction_::CommonInst_GetThreadLocal => {
trace!("instsel on GETTHREADLOCAL");
// get thread local
let tl = self.emit_get_threadlocal(f_context, vm);
let tmp_res = self.get_result_value(node, 0);
// load [tl + USER_TLS_OFFSET] -> tmp_res
emit_load_base_offset(
self.backend.as_mut(),
&tmp_res,
&tl,
&MU_TL,
*thread::USER_TLS_OFFSET as i64,
f_context,
vm
......@@ -1530,13 +1525,10 @@ impl<'a> InstructionSelection {
let tmp_op = self.emit_ireg(op, f_content, f_context, vm);
// get thread local
let tl = self.emit_get_threadlocal(f_context, vm);
// store tmp_op -> [tl + USER_TLS_OFFSTE]
emit_store_base_offset(
self.backend.as_mut(),
&tl,
&MU_TL,
*thread::USER_TLS_OFFSET as i64,
&tmp_op,
f_context,
......@@ -1580,62 +1572,52 @@ impl<'a> InstructionSelection {
Instruction_::New(ref ty) => {
trace!("instsel on NEW");
if cfg!(debug_assertions) {
match ty.v {
MuType_::Hybrid(_) => {
panic!("cannot use NEW for hybrid, use NEWHYBRID instead")
}
_ => {}
}
}
let tmp_res = self.get_result_value(node, 0);
let ty_info = vm.get_backend_type_info(ty.id());
let size = ty_info.size;
let ty_align = ty_info.alignment;
let size = make_value_int_const(ty_info.size as u64, vm);
let const_size = make_value_int_const(size as u64, vm);
let tmp_allocator = self.emit_get_allocator(f_context, vm);
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
const_size,
ty_align,
node,
f_context,
vm
);
if !vm.vm_options.flag_use_alloc {
self.emit_runtime_entry(
&entrypoints::MALLOC,
vec![size],
Some(vec![tmp_res]),
Some(node),
f_context,
vm
);
} else {
let tmp_allocator = self.emit_get_allocator(f_context, vm);
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
size,
ty_align,
node,
f_context,
vm
);
// ASM: call muentry_init_object(%allocator, %tmp_res, %encode)
let encode =
make_value_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
self.emit_runtime_entry(
&entrypoints::INIT_OBJ,
vec![tmp_allocator.clone(), tmp_res.clone(), encode],
None,
Some(node),
f_context,
vm
);
let encode = make_value_int_const(
mm::get_gc_type_encode(ty_info.gc_type.id),
vm
);
self.emit_runtime_entry(
&entrypoints::INIT_OBJ,
vec![tmp_allocator.clone(), tmp_res.clone(), encode],
None,
Some(node),
f_context,
vm
);
}
}
Instruction_::NewHybrid(ref ty, var_len) => {
trace!("instsel on NEWHYBRID");
if cfg!(debug_assertions) {
match ty.v {
MuType_::Hybrid(_) => {}
_ => {
panic!(
"NEWHYBRID is only for allocating hybrid types, \
use NEW for others"
)
}
}
}
let ty_info = vm.get_backend_type_info(ty.id());
let ty_align = ty_info.alignment;
let fix_part_size = ty_info.size;
let var_ty_size = ty_info.elem_size.unwrap();
let ty_align = ty_info.alignment;
// actual size = fix_part_size + var_ty_size * len
let (actual_size, length) = {
......@@ -1650,15 +1632,16 @@ impl<'a> InstructionSelection {
make_value_int_const(var_len as u64, vm)
)
} else {
let var_len = self.emit_ireg(var_len, f_content, f_context, vm);
emit_zext(self.backend.as_mut(), &var_len); // this will zero
let tmp_actual_size =
make_temporary(f_context, UINT64_TYPE.clone(), vm);
let tmp_var_len = self.emit_ireg(var_len, f_content, f_context, vm);
// tmp_actual_size = tmp_var_len*var_ty_size
// tmp_actual_size = var_len*var_ty_size
emit_mul_u64(
self.backend.as_mut(),
&tmp_actual_size,
&tmp_var_len,
&cast_value(&var_len, &UINT64_TYPE),
var_ty_size as u64
);
// tmp_actual_size = tmp_var_len*var_ty_size + fix_part_size
......@@ -1668,31 +1651,47 @@ impl<'a> InstructionSelection {
&tmp_actual_size,
fix_part_size as u64
);
(tmp_actual_size, tmp_var_len)
(tmp_actual_size, var_len)
}
};
let tmp_allocator = self.emit_get_allocator(f_context, vm);
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
actual_size,
ty_align,
node,
f_context,
vm
);
if !vm.vm_options.flag_use_alloc {
let tmp_res = self.get_result_value(node, 0);
// ASM: call muentry_init_object(%allocator, %tmp_res, %encode)
let encode =
make_value_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
self.emit_runtime_entry(
&entrypoints::INIT_HYBRID,
vec![tmp_allocator.clone(), tmp_res.clone(), encode, length],
None,
Some(node),
f_context,
vm
);
self.emit_runtime_entry(
&entrypoints::MALLOC,
vec![actual_size],
Some(vec![tmp_res]),
Some(node),
f_context,
vm
);
} else {
let tmp_allocator = self.emit_get_allocator(f_context, vm);
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
actual_size,
ty_align,
node,
f_context,
vm
);
// ASM: call muentry_init_object(%allocator, %tmp_res, %encode)
let encode = make_value_int_const(
mm::get_gc_type_encode(ty_info.gc_type.id),
vm
);
self.emit_runtime_entry(
&entrypoints::INIT_HYBRID,
vec![tmp_allocator.clone(), tmp_res.clone(), encode, length],
None,
Some(node),
f_context,
vm
);
}
}
Instruction_::AllocA(ref ty) => {
......@@ -2706,6 +2705,7 @@ impl<'a> InstructionSelection {
let reg_op2 = self.emit_ireg(&ops[op2], f_content, f_context, vm);
if output_status {
// TODO: Zero extend operands?
self.backend.emit_ands(&res, &reg_op1, &reg_op2);
} else {
self.backend.emit_and(&res, &reg_op1, &reg_op2);
......@@ -3685,16 +3685,13 @@ impl<'a> InstructionSelection {
}
fn emit_get_allocator(&mut self, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
// ASM: %tl = get_thread_local()
let tmp_tl = self.emit_get_threadlocal(f_context, vm);
// ASM: lea [%tl + allocator_offset] -> %tmp_allocator
let allocator_offset = *thread::ALLOCATOR_OFFSET;
let tmp_allocator = make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
emit_add_u64(
self.backend.as_mut(),
&tmp_allocator,
&tmp_tl,
&MU_TL,
allocator_offset as u64
);
tmp_allocator
......@@ -3756,20 +3753,6 @@ impl<'a> InstructionSelection {
}
}
// This generates code identical to (though it may use different registers)
// the function muentry_get_thread_local
fn emit_get_threadlocal(&mut self, f_context: &mut FunctionContext, vm: &VM) -> P<Value> {
let mut rets = self.emit_runtime_entry(
&entrypoints::GET_THREAD_LOCAL,
vec![],
None,
None,
f_context,
vm
);
rets.pop().unwrap()
}
// ret: Option<Vec<P<Value>>
// if ret is Some, return values will put stored in given temporaries
// otherwise create temporaries
......@@ -3869,7 +3852,7 @@ impl<'a> InstructionSelection {
// Return in a sequence of FPRs
get_alias_for_length(RETURN_FPRS[0].id(), get_bit_size(t, vm) / hfa_n)
} else if size <= 8 {
// Return in a singe GRP
// Return in a singe GPR
get_alias_for_length(RETURN_GPRS[0].id(), get_bit_size(t, vm))
} else if size <= 16 {
// Return in 2 GPRs
......@@ -4508,14 +4491,12 @@ impl<'a> InstructionSelection {
// Compute all the arguments...
let mut arg_values = self.emit_arg_values(&args, ops, f_content, f_context, vm);
let tl = self.emit_get_threadlocal(f_context, vm);
let cur_stackref = make_temporary(f_context, STACKREF_TYPE.clone(), vm);
// Load the current stackref
emit_load_base_offset(
self.backend.as_mut(),
&cur_stackref,
&tl,
&MU_TL,
*thread::STACK_OFFSET as i64,
f_context,
vm
......@@ -4525,7 +4506,7 @@ impl<'a> InstructionSelection {
let swapee = self.emit_ireg(&ops[swapee], f_content, f_context, vm);
emit_store_base_offset(
self.backend.as_mut(),
&tl,
&MU_TL,
*thread::STACK_OFFSET as i64,
&swapee,
f_context,
......@@ -4636,19 +4617,8 @@ impl<'a> InstructionSelection {
}
}
if is_exception {
// Reserve space on the new stack for the exception handling routine to store
// callee saved registers
emit_sub_u64(
self.backend.as_mut(),
&SP,
&SP,
(WORD_SIZE * CALLEE_SAVED_COUNT) as u64
);
} else {
// Restore the FP and LR from the old stack
self.backend.emit_pop_pair(&FP, &LR, &SP);
}
let potentially_excepting = Self::get_potentially_excepting(resumption, f_content);
......@@ -4656,28 +4626,44 @@ impl<'a> InstructionSelection {
let callsite = {
if vm.is_doing_jit() {
unimplemented!()
}
if is_exception {
// Reserve space on the new stack for the exception handling routine to store
// callee saved registers
emit_sub_u64(
self.backend.as_mut(),
&SP,
&SP,
(WORD_SIZE * CALLEE_SAVED_COUNT) as u64
);
emit_store_base_offset(self.backend.as_mut(), &SP, 64, &MU_TL, f_context, vm);
// Throw an exception, don't call the swapee's resumption point
self.backend.emit_b_call(
callsite_label,
entrypoints::THROW_EXCEPTION_INTERNAL.aot.to_relocatable(),
potentially_excepting,
arg_regs,
ALL_USABLE_MACHINE_REGS.to_vec(),
true,
false
)
} else {
if is_exception {
// Throw an exception, don't call the swapee's resumption point
self.backend.emit_b_call(
callsite_label,
entrypoints::THROW_EXCEPTION_INTERNAL.aot.to_relocatable(),
potentially_excepting,
arg_regs,
ALL_USABLE_MACHINE_REGS.to_vec(),
true,
false
)
} else {
self.backend.emit_br_call(
callsite_label,
&LR,
potentially_excepting,
arg_regs,
ALL_USABLE_MACHINE_REGS.to_vec(),
false
)
}
let res = make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
self.backend.emit_mov_imm(&LR, 0);
// Restore the FP and resumption point from the old stack
self.backend.emit_pop_pair(&FP, &res, &SP);
self.backend.emit_br_call(
callsite_label,
&res,
potentially_excepting,
arg_regs,
ALL_USABLE_MACHINE_REGS.to_vec(),
false
)
}
};
......@@ -5936,11 +5922,10 @@ impl<'a> InstructionSelection {
vm: &VM
) {
// get thread local and add offset to get exception_obj
let tl = self.emit_get_threadlocal(f_context, vm);
emit_load_base_offset(
self.backend.as_mut(),
exception_arg,
&tl,
&MU_TL,
*thread::EXCEPTION_OBJ_OFFSET as i64,
f_context,
vm
......
......@@ -148,6 +148,9 @@ ALIAS!(X29 -> FP);
// Link Register (not supposed to be used for any other purpose)
ALIAS!(X30 -> LR);
// Mu thread local
ALIAS!(X28 -> MU_TL);
lazy_static! {
pub static ref GPR_ALIAS_TABLE : LinkedHashMap<MuID, Vec<P<Value>>> = {
let mut ret = LinkedHashMap::new();
......@@ -356,7 +359,7 @@ lazy_static! {
X7.clone()
];
pub static ref CALLEE_SAVED_GPRS : [P<Value>; 10] = [
pub static ref CALLEE_SAVED_GPRS : [P<Value>; 9] = [
X19.clone(),
X20.clone(),
X21.clone(),
......@@ -366,7 +369,7 @@ lazy_static! {
X25.clone(),
X26.clone(),
X27.clone(),
X28.clone(),
// X28.clone(), // Mu Thread Local Register
// Note: These two are technically CALLEE saved but need to be dealt with specially
//X29.clone(), // Frame Pointer
......@@ -745,7 +748,7 @@ lazy_static! {
X25.clone(),
X26.clone(),
X27.clone(),
X28.clone(),
//X28.clone(), Mu thread-local
//X29.clone(), // Frame Pointer
//X30.clone(), // Link Register
];
......
......@@ -4231,9 +4231,11 @@ pub fn emit_context_with_reloc(
for obj_dump in objects.values() {
write_align(&mut file, 8);
// write object metadata
// .bytes xx,xx,xx,xx (between mem_start to reference_addr)
write_data_bytes(&mut file, obj_dump.mem_start, obj_dump.reference_addr);
if vm.vm_options.flag_use_alloc {
// Write object header
// .bytes xx,xx,xx,xx (between mem_start to reference_addr)
write_data_bytes(&mut file, obj_dump.mem_start, obj_dump.reference_addr);
}
// if this object is a global cell, we add labels so it can be accessed
if global_addr_id_map.contains_key(&obj_dump.reference_addr) {
......
......@@ -1726,30 +1726,44 @@ impl<'a> InstructionSelection {
let ty_align = ty_info.alignment;
let const_size = self.make_int_const(size as u64, vm);
// get allocator
let tmp_allocator = self.emit_get_allocator(node, f_content, f_context, vm);
// allocate
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
const_size,
ty_align,
node,
f_content,
f_context,
vm
);
// muentry_init_object(%allocator, %tmp_res, %encode)
let encode =
self.make_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
self.emit_runtime_entry(
&entrypoints::INIT_OBJ,
vec![tmp_allocator.clone(), tmp_res.clone(), encode],
None,
Some(node),
f_content,
f_context,
vm
);
if !vm.vm_options.flag_use_alloc {
let tmp_res = self.get_result_value(node);
self.emit_runtime_entry(
&entrypoints::MALLOC,
vec![const_size],
Some(vec![tmp_res]),
Some(node),
f_content,
f_context,
vm
);
} else {
// get allocator
let tmp_allocator =
self.emit_get_allocator(node, f_content, f_context, vm);
// allocate
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
const_size,
ty_align,
node,
f_content,
f_context,
vm
);
// muentry_init_object(%allocator, %tmp_res, %encode)
let encode =
self.make_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
self.emit_runtime_entry(
&entrypoints::INIT_OBJ,
vec![tmp_allocator.clone(), tmp_res.clone(), encode],
None,
Some(node),
f_content,
f_context,
vm
);
}
}
Instruction_::NewHybrid(ref ty, var_len) => {
......@@ -1829,29 +1843,43 @@ impl<'a> InstructionSelection {
}
};
let tmp_allocator = self.emit_get_allocator(node, f_content, f_context, vm);
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
actual_size,
ty_align,
node,
f_content,
f_context,
vm
);
if !vm.vm_options.flag_use_alloc {
let tmp_res = self.get_result_value(node);
self.emit_runtime_entry(
&entrypoints::MALLOC,
vec![actual_size],
Some(vec![tmp_res]),
Some(node),
f_content,
f_context,
vm
);
} else {
let tmp_allocator =
self.emit_get_allocator(node, f_content, f_context, vm);
let tmp_res = self.emit_alloc_sequence(
tmp_allocator.clone(),
actual_size,
ty_align,
node,
f_content,
f_context,
vm
);
// muentry_init_object(%allocator, %tmp_res, %encode)
let encode =
self.make_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
self.emit_runtime_entry(
&entrypoints::INIT_HYBRID,
vec![tmp_allocator.clone(), tmp_res.clone(), encode, length],
None,
Some(node),
f_content,
f_context,
vm
);
// muentry_init_object(%allocator, %tmp_res, %encode)
let encode =
self.make_int_const(mm::get_gc_type_encode(ty_info.gc_type.id), vm);
self.emit_runtime_entry(
&entrypoints::INIT_HYBRID,
vec![tmp_allocator.clone(), tmp_res.clone(), encode, length],
None,
Some(node),
f_content,
f_context,
vm
);
}
}
/*Instruction_::AllocA(ref ty) => {
......
......@@ -217,7 +217,7 @@ fn compute_immediate_dominators(dominators: &LinkedMultiMap<MuName, MuName>)
}
}
assert_eq!(immediate_doms.len(), dominators.len() - 1); // entry block does not have idom
//assert_eq!(immediate_doms.len(), dominators.len() - 1); // entry block does not have idom
immediate_doms
}
......
......@@ -39,45 +39,49 @@
FP .req X29
LR .req X30
.macro push_pair src1 src2 stack=SP
STP \src2 , \src1, [ \stack ,#-16]!
.macro push_pair src1 src2 i stack=SP
STP \src2 , \src1, [ \stack, #-16*(\i+1)]
.endm
.macro pop_pair dest1 dest2 stack=SP
LDP \dest1 , \dest2 , [ \stack ],#16
.macro pop_pair dest1 dest2 i stack=SP
LDP \dest1 , \dest2 , [ \stack, #16*\i]
.endm
.macro enter_frame
push_pair LR, FP
MOV FP, SP
STP FP, LR, [SP, #-16]!
MOV FP, SP
.endm
.macro exit_frame
pop_pair FP, LR
LDP FP, LR, [SP], #16
.endm
.macro push_callee_saved stack=SP
push_pair X19, X20, \stack
push_pair X21, X22, \stack
push_pair X23, X24, \stack
push_pair X25, X26, \stack
push_pair X27, X28, \stack
push_pair X19, X20, 0, \stack
push_pair X21, X22, 1, \stack
push_pair X23, X24, 2, \stack
push_pair X25, X26, 3, \stack
push_pair X27, X28, 4, \stack
push_pair D8, D9, \stack
push_pair D10, D11, \stack
push_pair D12, D13, \stack
push_pair D14, D15, \stack
push_pair D8, D9, 5, \stack
push_pair D10, D11, 6, \stack
push_pair D12, D13, 7, \stack
push_pair D14, D15, 8, \stack
SUB \stack, \stack, #16*9
.endm
.macro pop_callee_saved stack=SP
pop_pair D15, D14, \stack
pop_pair D13, D12, \stack
pop_pair D11, D10, \stack
pop_pair D9, D8, \stack
pop_pair D15, D14, 0, \stack
pop_pair D13, D12, 1, \stack
pop_pair D11, D10, 2, \stack
pop_pair D9, D8, 3, \stack
pop_pair X28, X27, 4, \stack
pop_pair X26, X25, 5, \stack
pop_pair X24, X23, 6, \stack
pop_pair X22, X21, 7, \stack
pop_pair X20, X19, 8, \stack
pop_pair X28, X27, \stack
pop_pair X26, X25, \stack
pop_pair X24, X23, \stack
pop_pair X22, X21, \stack
pop_pair X20, X19, \stack
ADD \stack, \stack, #16*9
.endm
\ No newline at end of file
......@@ -116,6 +116,11 @@ lazy_static! {
"muentry_unpin_object",
vec![ADDRESS_TYPE.clone()],
vec![]);
pub static ref MALLOC : RuntimeEntrypoint = RuntimeEntrypoint::new(
"alloc_mem_zero",
vec![UINT64_TYPE.clone()],
vec![ADDRESS_TYPE.clone()]);
}
// decl: exception.rs
......
......@@ -77,7 +77,7 @@ pub extern "C" fn throw_exception_internal(exception_obj: Address, frame_cursor:
let callsite_info = {
let table_entry = compiled_callsite_table.get(&callsite);
if table_entry.is_none() {
if previous_frame_pointer.is_zero() || table_entry.is_none() {
// we are not dealing with native frames for unwinding stack
// See Issue #42
error!(
......
......@@ -27,27 +27,39 @@ end_func get_current_frame_bp
# X0
begin_func muentry_throw_exception
# save all callee-saved registers and pass tham as argument 2
push_pair LR, FP
MOV FP, SP
enter_frame
push_callee_saved
MOV X1, FP // X1 is the frame pointer
BL throw_exception_internal
# won't return
end_func muentry_throw_exception
# _exception_restore(dest: Address, frame_cursor: *const Word, sp: Address) -> !
# exception_restore(dest: Address, frame_cursor: *const Word, sp: Address) -> !
# X0 X1 X2
begin_func exception_restore
SUB X1, X1, #144 // Skip to the bottom of the frame cursor
// load each callee saved register relative to the stack pointer
pop_callee_saved X1
pop_pair FP, LR, X1
MOV SP, X2
BR X0
SUB X1, X1, #144 // Skip to the bottom of the frame cursor
// load each callee saved register relative to the stack pointer
pop_pair D15, D14, 0, X1
pop_pair D13, D12, 1, X1
pop_pair D11, D10, 2, X1
pop_pair D9, D8, 3, X1
pop_pair X28, X27, 4, X1
pop_pair X26, X25, 5, X1
pop_pair X24, X23, 6, X1
pop_pair X22, X21, 7, X1
pop_pair X20, X19, 8, X1
ADD X1, X1, #144 // Skip to the top of the frame cursor
LDP FP, LR, [X1], #16
MOV SP, X2
BR X0
end_func exception_restore
# starts a muthread that passes values to the target
# muthread_start_normal(new_sp: Address, old_sp_loc: Address)
# X0 , X1
# muthread_start_normal(new_sp: Address, old_sp_loc: Address, mu_tls: Address)
# X0 , X1, X2
begin_func muthread_start_normal
enter_frame
push_callee_saved
......@@ -59,6 +71,9 @@ begin_func muthread_start_normal
// Swap to the new stack
MOV SP, X0
// Load the new mu_tls values
MOV X28, X2
// Pop the argument registers from the new stack
LDP D1, D0, [SP, #14*8 ]
LDP D3, D2, [SP, #12*8 ]
......@@ -71,13 +86,14 @@ begin_func muthread_start_normal
ADD SP, SP, #16*8
// Jump to the new stack
exit_frame
BR LR
LDP FP, X8, [SP], #16 // X8 is a random register
MOV LR, 0 // Incase it tries to return
BR X8
end_func muthread_start_normal
# starts a muthread with an exception thrown
# muthread_start_exceptional(exception: Address, new_sp: Address, old_sp_loc: &mut Adress)
# X0 X1 X2
# muthread_start_exceptional(exception: Address, new_sp: Address, old_sp_loc: &mut Adress, mu_tls: Address)
# X0 X1 X2 , x3
begin_func muthread_start_exceptional
enter_frame
push_callee_saved
......@@ -88,7 +104,10 @@ begin_func muthread_start_exceptional
// Swap to the new stack
MOV SP, X1
SUB SP, SP, #144 // Alocate space for callee saved registers
STR X3, [SP, #64] // Save the mu_tls value to the slot for x28
B throw_exception_internal
// We won't be coming back...
end_func muthread_start_exceptional
......@@ -103,5 +122,5 @@ begin_func muentry_thread_exit
// Do the inverse of 'muthread_*'
pop_callee_saved
exit_frame
BR LR
RET
end_func muentry_thread_exit
......@@ -82,3 +82,7 @@ int32_t c_check_result() {
char * alloc_mem(size_t size){
return (char *) malloc(size);
}
void* alloc_mem_zero(size_t size){
return calloc(size, 1);
}
......@@ -54,3 +54,7 @@ void* resolve_symbol(const char* sym) {
// printf("%s\n", sym);
return dlsym(RTLD_DEFAULT, sym);
}
void* alloc_mem_zero(size_t size){
return calloc(size, 1);
}
......@@ -386,8 +386,13 @@ extern "C" {
/// args:
/// new_sp: stack pointer for the mu stack
/// old_sp_loc: the location to store native stack pointer so we can later swap back
fn muthread_start_normal(new_sp: Address, old_sp_loc: Address);
fn muthread_start_exceptional(exception: Address, new_sp: Address, old_sp_loc: Address);
fn muthread_start_normal(new_sp: Address, old_sp_loc: Address, mu_tls: Address);
fn muthread_start_exceptional(
exception: Address,
new_sp: Address,
old_sp_loc: Address,
mu_tls: Address
);
/// gets base poniter for current frame
pub fn get_current_frame_bp() -> Address;
......@@ -459,9 +464,7 @@ impl MuThread {
) {
// set up arguments on stack
stack.setup_args(vals);
let (join_handle, _) =
MuThread::mu_thread_launch(vm.next_id(), stack, threadlocal, None, vm.clone());
vm.push_join_handle(join_handle);
MuThread::mu_thread_launch(vm.next_id(), stack, threadlocal, None, vm.clone());
}
/// creates and launches a mu thread, returns a JoinHandle and address to its MuThread structure
......@@ -471,44 +474,48 @@ impl MuThread {
user_tls: Address,
exception: Option<Address>,
vm: Arc<VM>
) -> (JoinHandle<()>, *mut MuThread) {
) -> *mut MuThread {
let new_sp = stack.sp;
// The conversions between boxes and ptrs are needed here as a '*mut MuThread* can't be
// sent between threads but a Box can. Also converting a Box to a ptr consumes it.
let muthread_ptr = Box::into_raw(Box::new(
MuThread::new(id, mm::new_mutator(), stack, user_tls, vm)
));
let muthread_ptr = Box::into_raw(Box::new(MuThread::new(
id,
mm::new_mutator(),
stack,
user_tls,
vm.clone()
)));
let muthread = unsafe { Box::from_raw(muthread_ptr) };
(
match thread::Builder::new()
.name(format!("Mu Thread #{}", id))
.spawn(move || {
let muthread = Box::into_raw(muthread);
// set thread local
unsafe { set_thread_local(muthread) };
let addr = unsafe { muentry_get_thread_local() };
let sp_threadlocal_loc = addr + *NATIVE_SP_LOC_OFFSET;
debug!("new sp: 0x{:x}", new_sp);
debug!("sp_store: 0x{:x}", sp_threadlocal_loc);
unsafe {
match exception {
Some(e) => muthread_start_exceptional(e, new_sp, sp_threadlocal_loc),
None => muthread_start_normal(new_sp, sp_threadlocal_loc)
}
// Thread finished, delete it's data
Box::from_raw(muthread);
let join_handle = match thread::Builder::new()
.name(format!("Mu Thread #{}", id))
.spawn(move || {
let muthread = Box::into_raw(muthread);
// set thread local
unsafe { set_thread_local(muthread) };
let addr = unsafe { muentry_get_thread_local() };
let sp_threadlocal_loc = addr + *NATIVE_SP_LOC_OFFSET;
debug!("new sp: 0x{:x}", new_sp);
debug!("sp_store: 0x{:x}", sp_threadlocal_loc);
unsafe {
match exception {
Some(e) => muthread_start_exceptional(e, new_sp, sp_threadlocal_loc, addr),
None => muthread_start_normal(new_sp, sp_threadlocal_loc, addr)
}
}) {
Ok(handle) => handle,
Err(_) => panic!("failed to create a thread")
},
muthread_ptr
)
// Thread finished, delete it's data
Box::from_raw(muthread);
}
}) {
Ok(handle) => handle,
Err(_) => panic!("failed to create a thread")
};
vm.push_join_handle(join_handle);
muthread_ptr
}
/// creates metadata for a Mu thread
......@@ -672,15 +679,13 @@ pub unsafe extern "C" fn muentry_new_thread_exceptional(
exception: Address
) -> *mut MuThread {
let vm = MuThread::current_mut().vm.clone();
let (join_handle, muthread) = MuThread::mu_thread_launch(
MuThread::mu_thread_launch(
vm.next_id(),
Box::from_raw(stack),
thread_local,
Some(exception),
vm.clone()
);
vm.push_join_handle(join_handle);
muthread
)
}
// Creates a new thread
......@@ -690,13 +695,11 @@ pub unsafe extern "C" fn muentry_new_thread_normal(
thread_local: Address
) -> *mut MuThread {
let vm = MuThread::current_mut().vm.clone();
let (join_handle, muthread) = MuThread::mu_thread_launch(
MuThread::mu_thread_launch(
vm.next_id(),