Add bzero glue and preliminary code for dynamic size/align calculations.

This commit is contained in:
Graydon Hoare 2011-01-18 15:38:35 -08:00
parent b86e8115d7
commit e92298187b
2 changed files with 174 additions and 15 deletions
src/comp
back
middle

@ -63,6 +63,10 @@ fn memcpy_glue_name() -> str {
ret "rust_memcpy_glue";
}
fn bzero_glue_name() -> str {
ret "rust_bzero_glue";
}
fn upcall_glue_name(int n) -> str {
ret "rust_upcall_" + util.common.istr(n);
}

@ -52,7 +52,8 @@ type glue_fns = rec(ValueRef activate_glue,
ValueRef exit_task_glue,
vec[ValueRef] upcall_glues,
ValueRef no_op_type_glue,
ValueRef memcpy_glue);
ValueRef memcpy_glue,
ValueRef bzero_glue);
tag arity { nullary; n_ary; }
type tag_info = rec(type_handle th,
@ -632,19 +633,110 @@ fn find_scope_cx(@block_ctxt cx) -> @block_ctxt {
}
}
fn size_of(TypeRef t) -> ValueRef {
fn umax(@block_ctxt cx, ValueRef a, ValueRef b) -> ValueRef {
auto cond = cx.build.ICmp(lib.llvm.LLVMIntULT, a, b);
ret cx.build.Select(cond, b, a);
}
fn align_to(@block_ctxt cx, ValueRef off, ValueRef align) -> ValueRef {
auto mask = cx.build.Sub(align, C_int(1));
auto bumped = cx.build.Add(off, mask);
ret cx.build.And(bumped, cx.build.Not(mask));
}
fn llsize_of(TypeRef t) -> ValueRef {
ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMSizeOf(t), T_int(), False);
}
fn align_of(TypeRef t) -> ValueRef {
fn llalign_of(TypeRef t) -> ValueRef {
ret llvm.LLVMConstIntCast(lib.llvm.llvm.LLVMAlignOf(t), T_int(), False);
}
fn size_of(@block_ctxt cx, @ty.t t) -> ValueRef {
if (!ty.type_has_dynamic_size(t)) {
ret llsize_of(type_of(cx.fcx.ccx, t));
}
ret dynamic_size_of(cx, t);
}
fn align_of(@block_ctxt cx, @ty.t t) -> ValueRef {
if (!ty.type_has_dynamic_size(t)) {
ret llalign_of(type_of(cx.fcx.ccx, t));
}
ret dynamic_align_of(cx, t);
}
fn dynamic_size_of(@block_ctxt cx, @ty.t t) -> ValueRef {
alt (t.struct) {
case (ty.ty_param(?p)) {
auto szptr = field_of_tydesc(cx, t, abi.tydesc_field_size);
ret cx.build.Load(szptr);
}
case (ty.ty_tup(?elts)) {
//
// C padding rules:
//
//
// - Pad after each element so that next element is aligned.
// - Pad after final structure member so that whole structure
// is aligned to max alignment of interior.
//
auto off = C_int(0);
auto max_align = C_int(1);
for (@ty.t e in elts) {
auto elt_align = align_of(cx, e);
auto elt_size = size_of(cx, e);
auto aligned_off = align_to(cx, off, elt_align);
off = cx.build.Add(aligned_off, elt_size);
max_align = umax(cx, max_align, elt_align);
}
off = align_to(cx, off, max_align);
ret off;
}
case (ty.ty_rec(?flds)) {
auto off = C_int(0);
auto max_align = C_int(1);
for (ty.field f in flds) {
auto elt_align = align_of(cx, f.ty);
auto elt_size = size_of(cx, f.ty);
auto aligned_off = align_to(cx, off, elt_align);
off = cx.build.Add(aligned_off, elt_size);
max_align = umax(cx, max_align, elt_align);
}
off = align_to(cx, off, max_align);
ret off;
}
}
}
fn dynamic_align_of(@block_ctxt cx, @ty.t t) -> ValueRef {
alt (t.struct) {
case (ty.ty_param(?p)) {
auto aptr = field_of_tydesc(cx, t, abi.tydesc_field_align);
ret cx.build.Load(aptr);
}
case (ty.ty_tup(?elts)) {
auto a = C_int(1);
for (@ty.t e in elts) {
a = umax(cx, a, align_of(cx, e));
}
ret a;
}
case (ty.ty_rec(?flds)) {
auto a = C_int(1);
for (ty.field f in flds) {
a = umax(cx, a, align_of(cx, f.ty));
}
ret a;
}
}
}
fn trans_malloc_inner(@block_ctxt cx, TypeRef llptr_ty) -> result {
auto llbody_ty = lib.llvm.llvm.LLVMGetElementType(llptr_ty);
// FIXME: need a table to collect tydesc globals.
auto tydesc = C_int(0);
auto sz = size_of(llbody_ty);
auto sz = llsize_of(llbody_ty);
auto sub = trans_upcall(cx, "upcall_malloc", vec(sz, tydesc));
sub.val = sub.bcx.build.IntToPtr(sub.val, llptr_ty);
ret sub;
@ -699,8 +791,8 @@ fn make_tydesc(@crate_ctxt cx, @ty.t t) {
auto pvoid = T_ptr(T_i8());
auto glue_fn_ty = T_ptr(T_fn(vec(T_taskptr(), pvoid), T_void()));
auto tydesc = C_struct(vec(C_null(pvoid),
size_of(llty),
align_of(llty),
llsize_of(llty),
llalign_of(llty),
take_glue, // take_glue_off
drop_glue, // drop_glue_off
C_null(glue_fn_ty), // free_glue_off
@ -1146,7 +1238,7 @@ fn iter_sequence(@block_ctxt cx,
C_int(abi.vec_elt_fill)));
auto llunit_ty = type_of(cx.fcx.ccx, elt_ty);
auto unit_sz = size_of(llunit_ty);
auto unit_sz = size_of(cx, elt_ty);
auto len = cx.build.Load(lenptr);
if (trailing_null) {
@ -1249,6 +1341,15 @@ fn call_memcpy(@block_ctxt cx,
vec(dst_ptr, src_ptr, size)));
}
fn call_bzero(@block_ctxt cx,
ValueRef dst,
ValueRef n_bytes) -> result {
auto dst_ptr = cx.build.PointerCast(dst, T_ptr(T_i8()));
auto size = cx.build.IntCast(n_bytes, T_int());
ret res(cx, cx.build.FastCall(cx.fcx.ccx.glues.bzero_glue,
vec(dst_ptr, size)));
}
fn memcpy_ty(@block_ctxt cx,
ValueRef dst,
ValueRef src,
@ -1901,7 +2002,7 @@ impure fn trans_index(@block_ctxt cx, &ast.span sp, @ast.expr base,
auto v = lv.val;
auto llunit_ty = node_type(cx.fcx.ccx, ann);
auto unit_sz = size_of(llunit_ty);
auto unit_sz = size_of(cx, node_ann_type(cx.fcx.ccx, ann));
auto scaled_ix = ix.bcx.build.Mul(ix.val, unit_sz);
auto lim = ix.bcx.build.GEP(v, vec(C_int(0), C_int(abi.vec_elt_fill)));
@ -2374,7 +2475,7 @@ impure fn trans_vec(@block_ctxt cx, vec[@ast.expr] args,
}
auto llunit_ty = type_of(cx.fcx.ccx, unit_ty);
auto unit_sz = size_of(llunit_ty);
auto unit_sz = size_of(cx, unit_ty);
auto data_sz = llvm.LLVMConstMul(C_int(_vec.len[@ast.expr](args) as int),
unit_sz);
@ -2681,9 +2782,15 @@ impure fn trans_stmt(@block_ctxt cx, &ast.stmt s) -> result {
sub = copy_ty(sub.bcx, true, llptr, sub.val, ty);
}
case (_) {
auto llty = type_of(cx.fcx.ccx, ty);
auto null = lib.llvm.llvm.LLVMConstNull(llty);
sub = res(cx, cx.build.Store(null, llptr));
if (middle.ty.type_has_dynamic_size(ty)) {
auto llsz = size_of(cx, ty);
sub = call_bzero(cx, llptr, llsz);
} else {
auto llty = type_of(cx.fcx.ccx, ty);
auto null = lib.llvm.llvm.LLVMConstNull(llty);
sub = res(cx, cx.build.Store(null, llptr));
}
}
}
}
@ -2779,8 +2886,14 @@ impure fn trans_block(@block_ctxt cx, &ast.block b) -> result {
auto bcx = cx;
for each (@ast.local local in block_locals(b)) {
auto ty = node_type(cx.fcx.ccx, local.ann);
auto val = bcx.build.Alloca(ty);
auto t = node_ann_type(cx.fcx.ccx, local.ann);
auto val = C_int(0);
if (ty.type_has_dynamic_size(t)) {
auto n = size_of(bcx, t);
val = bcx.build.ArrayAlloca(T_i8(), n);
} else {
val = bcx.build.Alloca(type_of(cx.fcx.ccx, t));
}
cx.fcx.lllocals.insert(local.id, val);
}
auto r = res(bcx, C_nil());
@ -3684,6 +3797,47 @@ fn make_memcpy_glue(ModuleRef llmod) -> ValueRef {
ret fun;
}
fn make_bzero_glue(ModuleRef llmod) -> ValueRef {
// We're not using the LLVM memset intrinsic. Same as with memcpy.
auto p8 = T_ptr(T_i8());
auto ty = T_fn(vec(p8, T_int()), T_void());
auto fun = decl_fastcall_fn(llmod, abi.bzero_glue_name(), ty);
auto initbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("init"));
auto hdrbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("hdr"));
auto loopbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("loop"));
auto endbb = llvm.LLVMAppendBasicBlock(fun, _str.buf("end"));
auto dst = llvm.LLVMGetParam(fun, 0u);
auto count = llvm.LLVMGetParam(fun, 1u);
// Init block.
auto ib = new_builder(initbb);
auto ip = ib.Alloca(T_int());
ib.Store(C_int(0), ip);
ib.Br(hdrbb);
// Loop-header block
auto hb = new_builder(hdrbb);
auto i = hb.Load(ip);
hb.CondBr(hb.ICmp(lib.llvm.LLVMIntEQ, count, i), endbb, loopbb);
// Loop-body block
auto lb = new_builder(loopbb);
i = lb.Load(ip);
lb.Store(C_integral(0, T_i8()), lb.GEP(dst, vec(i)));
lb.Store(lb.Add(i, C_int(1)), ip);
lb.Br(hdrbb);
// End block
auto eb = new_builder(endbb);
eb.RetVoid();
ret fun;
}
fn make_glues(ModuleRef llmod) -> @glue_fns {
ret @rec(activate_glue = decl_glue(llmod, abi.activate_glue_name()),
yield_glue = decl_glue(llmod, abi.yield_glue_name()),
@ -3704,7 +3858,8 @@ fn make_glues(ModuleRef llmod) -> @glue_fns {
_vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
abi.n_upcall_glues as uint),
no_op_type_glue = make_no_op_type_glue(llmod),
memcpy_glue = make_memcpy_glue(llmod));
memcpy_glue = make_memcpy_glue(llmod),
bzero_glue = make_bzero_glue(llmod));
}
fn trans_crate(session.session sess, @ast.crate crate, str output,