Commit a684c62a authored by Isaac Oscar Gariano's avatar Isaac Oscar Gariano

Updated type layout and ALLOCA implemenation

parent 7f88d839
......@@ -41,6 +41,7 @@ libloading = "*"
lazy_static = "*"
log = "*"
stderrlog = "*"
num = "*"
hprof = "*"
memmap = "*"
memsec = "0.1.9"
......
......@@ -2165,6 +2165,13 @@ impl CodeGenerator for ASMCodeGen {
let asm = format!("B {}", mangle_name(dest_name.clone()));
self.add_asm_inst_internal(asm, linked_hashmap!{}, linked_hashmap!{}, false, ASMBranchTarget::Unconditional(dest_name), None);
}
fn emit_b_func(&mut self, dest_name: MuName)
{
trace!("emit: \tB {}", dest_name);
let asm = format!("B {}", mangle_name(dest_name.clone()));
self.add_asm_inst_internal(asm, linked_hashmap!{}, linked_hashmap!{}, false, ASMBranchTarget::Return, None);
}
fn emit_b_cond(&mut self, cond: &str, dest_name: MuName)
{
trace!("emit: \tB.{} {}", cond, dest_name);
......@@ -2181,6 +2188,14 @@ impl CodeGenerator for ASMCodeGen {
let asm = format!("BR {}", reg1);
self.add_asm_inst_internal(asm, linked_hashmap!{}, linked_hashmap!{id1 => vec![loc1]}, false, ASMBranchTarget::UnconditionalReg(id1), None);
}
fn emit_br_func(&mut self, func_address: Reg)
{
trace!("emit: \tBR {}", dest_address);
let (reg1, id1, loc1) = self.prepare_reg(dest_address, 2 + 1);
let asm = format!("BR {}", reg1);
self.add_asm_inst_internal(asm, linked_hashmap!{}, linked_hashmap!{}, false, ASMBranchTarget::Return, None);
}
fn emit_cbnz(&mut self, src: Reg, dest_name: MuName) { self.internal_branch_op("CBNZ", src, dest_name); }
fn emit_cbz(&mut self, src: Reg, dest_name: MuName) { self.internal_branch_op("CBZ", src, dest_name); }
fn emit_tbnz(&mut self, src1: Reg, src2: u8, dest_name: MuName) { self.internal_branch_op_imm("TBNZ", src1, src2, dest_name); }
......
......@@ -110,8 +110,11 @@ pub trait CodeGenerator {
// Branches
fn emit_b(&mut self, dest_name: MuName);
fn emit_b_func(&mut self, func: MuName);
fn emit_b_cond(&mut self, cond: &str, dest_name: MuName);
fn emit_br(&mut self, dest_address: Reg);
fn emit_br_func(&mut self, func_address: Reg);
fn emit_ret(&mut self, src: Reg);
fn emit_cbnz(&mut self, src: Reg, dest_name: MuName);
fn emit_cbz(&mut self, src: Reg, dest_name: MuName);
......
......@@ -44,6 +44,7 @@ use std::collections::HashMap;
use std::collections::LinkedList;
use std::mem;
use std::any::Any;
use num::integer::lcm;
const INLINE_FASTPATH : bool = false;
......@@ -1171,16 +1172,7 @@ impl <'a> InstructionSelection {
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 = match ty.v {
MuType_::Hybrid(ref name) => {
let map_lock = HYBRID_TAG_MAP.read().unwrap();
let hybrid_ty_ = map_lock.get(name).unwrap();
let var_ty = hybrid_ty_.get_var_ty();
vm.get_backend_type_size((var_ty.id()))
},
_ => panic!("only expect HYBRID type here")
};
let var_ty_size = ty_info.elem_size.unwrap();
// actual size = fix_part_size + var_ty_size * len
let (actual_size, length) = {
......@@ -1256,7 +1248,6 @@ impl <'a> InstructionSelection {
},
_ => panic!("only expect HYBRID type here")
};
let res = self.get_result_value(node, 0);
let ref ops = inst.ops;
......@@ -1265,15 +1256,19 @@ impl <'a> InstructionSelection {
let var_len = node_imm_to_u64(var_len) as usize;
self.emit_alloca_const(&res, var_ty_size*var_len + fix_part_size, ty_align, f_context, vm, node);
} else {
assert!(ty_align % 16 == 0);
let align = lcm(ty_align, 16) as u64; // This is always going to be 16
assert!(align.is_power_of_two());
let var_len = self.emit_ireg(var_len, f_content, f_context, vm);
// set res to the total size of the object (i.e. var_ty_size*var_len + fix_part_size)
emit_madd_u64_u64(self.backend.as_mut(), &res, &var_len, f_context, vm, var_ty_size as u64, fix_part_size as u64);
// Grow the stack by 'res' bytes
self.backend.emit_sub(&SP, &SP, &res);
// Align the stack pointer down to the nearest multiple of 16
self.backend.emit_and_imm(&SP, &SP, !(16 - 1));
// Note: the SP can't be used as the source of the emit_and so we have to make a temporary
let tmp_sp = make_temporary(f_context, ADDRESS_TYPE.clone(), vm);
self.backend.emit_sub(&tmp_sp, &SP, &res);
// Align the stack pointer down to the nearest multiple of align (which should be a power of two)
self.backend.emit_and_imm(&SP, &tmp_sp, !(align - 1));
// Zero out 'res' bytes starting at the stack pointer
self.emit_runtime_entry(&entrypoints::MEM_ZERO, vec![SP.clone(), res.clone()], None, Some(node), f_context, vm);
......@@ -2751,28 +2746,33 @@ impl <'a> InstructionSelection {
}
fn emit_alloca_const(&mut self, res: &P<Value>, size: usize, align: usize, f_context: &mut FunctionContext, vm: &VM, node: &TreeNode) {
assert!(16 % align == 0);
let align = lcm(align, 16); // This is always going to be 16
// The stack pointer has to be 16 bytes aligned
let size = round_up(size, 16) as u64;
let alloc_size = round_up(size, align) as u64;
if size <= 64 {
// Note: this is the same threshold clang -O3 uses to decide whether to call memset
// Allocate 'size' bytes on the stack
emit_sub_u64(self.backend.as_mut(), &SP, &SP, size);
// Allocate 'alloc_size' bytes on the stack
emit_sub_u64(self.backend.as_mut(), &SP, &SP, alloc_size);
// Just push pairs of the zero register to the stack
// TODO: Optimise for the case where we don't need to zero initilise a multiple of 16-bytes
for i in 0..size/16 {
// Push pairs of 0's on the stack
let dest = make_value_base_offset(&SP, (16*i) as i64, &UINT128_TYPE, vm);
let dest = emit_mem(self.backend.as_mut(), &dest, get_type_alignment(&UINT128_TYPE, vm), f_context, vm);
self.backend.emit_stp(&dest, &XZR, &XZR);
}
let leftover = size % 16;
if leftover != 0 { // Push the remaining bytes we need to
let offset = 16*(size/16);
let src = cast_value(&XZR, &get_alignment_type(leftover.next_power_of_two()));
emit_store_base_offset(self.backend.as_mut(), &SP, offset as i64, &src, f_context, vm);
}
self.backend.emit_mov(&res, &SP);
} else {
// Allocate 'size' bytes on the stack
emit_sub_u64(self.backend.as_mut(), &res, &SP, size);
// Allocate 'alloc_size' bytes on the stack
emit_sub_u64(self.backend.as_mut(), &res, &SP, alloc_size);
self.emit_runtime_entry(&entrypoints::MEM_ZERO, vec![res.clone(), make_value_int_const(size as u64, vm)], None, Some(node), f_context, vm);
self.backend.emit_mov(&SP, &res);
};
......@@ -4210,8 +4210,8 @@ impl <'a> InstructionSelection {
}
// GETELEMIREF <T1 T2> opnd index = opnd + index*element_size(T1)
Instruction_::GetElementIRef{base, index, ..} => {
let element_type = ops[base].clone_value().ty.get_referent_ty().unwrap().get_elem_ty().unwrap();
let element_size = vm.get_backend_type_size(element_type.id());
let array_type = ops[base].clone_value().ty.get_referent_ty().unwrap();
let element_size = vm.get_backend_type_info(array_type.id()).elem_size.unwrap();
self.emit_shift_ref(&ops[base], &ops[index], element_size, f_content, f_context, vm)
}
......
......@@ -1467,9 +1467,9 @@ impl <'a> InstructionSelection {
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 = match ty_info.elem_padded_size {
let var_ty_size = match ty_info.elem_size {
Some(sz) => sz,
None => panic!("expect HYBRID type here with elem_padded_size, found {}", ty_info)
None => panic!("expect HYBRID type here with elem_size, found {}", ty_info)
};
// compute actual size (size = fix_part_size + var_ty_size * len)
......@@ -4580,9 +4580,9 @@ impl <'a> InstructionSelection {
Some(ty) => ty,
None => panic!("expected base in GetElemIRef to be type IRef, found {}", iref_array_ty)
};
let ele_ty_size = match vm.get_backend_type_info(array_ty.id()).elem_padded_size {
let ele_ty_size = match vm.get_backend_type_info(array_ty.id()).elem_size {
Some(sz) => sz,
None => panic!("array backend type should have a elem_padded_size, found {}", array_ty)
None => panic!("array backend type should have a elem_size, found {}", array_ty)
};
if self.match_iimm(index) {
......
This diff is collapsed.
......@@ -28,6 +28,7 @@ extern crate maplit;
#[macro_use]
extern crate field_offset;
extern crate extprim;
extern crate num;
#[macro_use]
pub extern crate ast;
......
......@@ -16,7 +16,19 @@ from util import execute, compile_bundle, load_bundle, get_function;
import pytest;
import ctypes;
# Tests that zebu can handle wierd, but valid mu names
def test_alloca_simple():
compile_bundle(
"""
.funcdef test_alloca_simple <main_sig>
{
entry(<int<32>>argc <uptr<uptr<char>>>argv):
a = ALLOCA <struct<int<64> double ref<void>>>
RET <int<32>>0
}
""", "test_alloca_simple");
assert(execute("test_alloca_simple") == 0);
def test_alloca():
lib = load_bundle(
"""
......@@ -54,4 +66,95 @@ def test_alloca():
""", "test_alloca");
alloca = get_function(lib.alloca, [ctypes.c_int64], ctypes.c_int64);
assert(alloca(-56) == -56);
\ No newline at end of file
assert(alloca(-56) == -56);
def test_allocahybrid_simple():
compile_bundle(
"""
.funcdef test_allocahybrid_simple <main_sig>
{
entry(<int<32>>argc <uptr<uptr<char>>>argv):
a = ALLOCAHYBRID <hybrid<int<1>> int<32>> argc
RET argc
}
""", "test_allocahybrid_simple");
assert(execute("test_allocahybrid_simple", ["1", "2", "3"]) == 4);
def test_allocahybrid():
lib = load_bundle(
"""
.typedef type = hybrid<int<1> int<64>>
.funcdef allocahybrid <(int<64>)->(int<64>)>
{
entry(<int<64>>n):
a = ALLOCAHYBRID <type int<64>> n
// Load the int<1> field to ai_int (as a 64-bit integer)
ai_ref = GETFIELDIREF <type 0> a
ai = LOAD <int<64>> ai_ref
ai_int = ZEXT <int<1> int<64>> ai
a_var = GETVARPARTIREF <type> a
n_zero = EQ <int<64>> n <int<64>>0
// If the hybrid is non empty, sum all of it's variable elements
BRANCH2 n_zero exit(ai_int) sum(a_var n ai_int)
// Sum 'sum' and the n elements of pos
// branch to exit with sum once finished
sum(<iref<int<64>>>pos <int<64>>n <int<64>>sum):
val = LOAD <int<64>> pos
new_pos = SHIFTIREF <int<64> int<1>> pos <int<1>>1
new_sum = ADD <int<64>> sum val
new_n = SUB <int<64>> n <int<64>>1
n_zero = EQ <int<64>> n <int<64>>0
BRANCH2 n_zero exit(new_sum) sum(new_pos new_n new_sum)
exit(<int<64>> sum):
RET sum
}
""", "test_alloca");
allocahybrid = get_function(lib.allocahybrid, [ctypes.c_int64], ctypes.c_int64);
assert(allocahybrid(57) == 0);
def test_allocahybrid_imm():
bundle_template = """
.typedef type = hybrid<int<1> int<64>>
.funcdef allocahybrid_imm <(int<64>)->(int<64>)>
{{
entry(<int<64>>n):
a = ALLOCAHYBRID <type int<64>> <int<64>>{}
// Load the int<1> field to ai_int (as a 64-bit integer)
ai_ref = GETFIELDIREF <type 0> a
ai = LOAD <int<64>> ai_ref
ai_int = ZEXT <int<1> int<64>> ai
a_var = GETVARPARTIREF <type> a
n_zero = EQ <int<64>> n <int<64>>0
// If the hybrid is non empty, sum all of it's variable elements
BRANCH2 n_zero exit(ai_int) sum(a_var n ai_int)
// Sum 'sum' and the n elements of pos
// branch to exit with sum once finished
sum(<iref<int<64>>>pos <int<64>>n <int<64>>sum):
val = LOAD <int<64>> pos
new_pos = SHIFTIREF <int<64> int<1>> pos <int<1>>1
new_sum = ADD <int<64>> sum val
new_n = SUB <int<64>> n <int<64>>1
n_zero = EQ <int<64>> n <int<64>>0
BRANCH2 n_zero exit(new_sum) sum(new_pos new_n new_sum)
exit(<int<64>> sum):
RET sum
}}
""";
def allocahybrid_imm(n): # type: (str) -> int
lib = load_bundle(bundle_template.format(n), "test_allocahybrid_{}".format(n));
return get_function(lib.allocahybrid_imm, [], ctypes.c_uint64)();
assert(allocahybrid_imm("16") == 0);
assert(allocahybrid_imm("0") == 0);
......@@ -69,4 +69,4 @@ def load_bundle(bundle, name): # type: (str, str) -> ctypes.CDLL
def get_function(func, argtypes, restype): # type: (ctypes._FuncPtr) -> (ctypes._FuncPtr)
func.argtypes = argtypes;
func.restype = restype;
return func;
\ No newline at end of file
return func;
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment