GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

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