Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support larger bit field #528

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 54 additions & 29 deletions src/generator/codegen.jl
Original file line number Diff line number Diff line change
Expand Up @@ -311,9 +311,10 @@ function _emit_getproperty_ptr!(body, root_cursor, cursor, options)
offset = getOffsetOf(getCursorType(root_cursor), n)
if isBitField(field_cursor)
w = getFieldDeclBitWidth(field_cursor)
@assert w <= 32 # Bit fields should not be larger than int(32 bits)
d, r = divrem(offset, 32)
ex = :(f === $(QuoteNode(fsym)) && return (Ptr{$ty}(x + $(4d)), $r, $w))
iszero(w) && continue
d, r = divrem(offset, 8)
@assert r + w <= 128 "Cannot handle bitfield larger than 128 bits"
ex = :(f === $(QuoteNode(fsym)) && return Ptr{$ty}(x + $d), $r, $w)
else
d = offset ÷ 8
ex = :(f === $(QuoteNode(fsym)) && return Ptr{$ty}(x + $d))
Expand All @@ -335,9 +336,17 @@ function emit_getproperty_ptr!(dag, node, options)
end

function rm_line_num_node!(ex::Expr)
filter!(ex.args) do arg
arg isa Expr && rm_line_num_node!(arg)
!isa(arg, LineNumberNode)
if ex.head == :macrocall
ex.args[2] = nothing
for i = 3:length(ex.args)
arg = ex.args[i]
arg isa Expr && rm_line_num_node!(arg)
end
else
filter!(ex.args) do arg
arg isa Expr && rm_line_num_node!(arg)
!isa(arg, LineNumberNode)
end
end
return ex
end
Expand All @@ -352,10 +361,8 @@ function emit_getproperty!(dag, node, options)
load_expr = :(GC.@preserve r unsafe_load(fptr))
load_expr.args[2] = nothing

load_base_expr = :(GC.@preserve r unsafe_load(baseptr32))
load_base_expr = :(GC.@preserve r unsafe_load(baseptr))
load_base_expr.args[2] = nothing
load_next_expr = :(GC.@preserve r unsafe_load(baseptr32 + 4))
load_next_expr.args[2] = nothing

if is_bitfield_type(node.type)
ex = quote
Expand All @@ -364,13 +371,22 @@ function emit_getproperty!(dag, node, options)
else
baseptr, offset, width = fptr
ty = eltype(baseptr)
baseptr32 = convert(Ptr{UInt32}, baseptr)
u64 = $load_base_expr
if offset + width > 32
u64 |= ($load_next_expr) << 32
sz = offset + width
uty = if sz <= 8
UInt8
elseif sz <= 16
UInt16
elseif sz <= 32
UInt32
elseif sz <= 64
UInt64
elseif sz <= 128
UInt128
end
u64 = (u64 >> offset) & ((1 << width) - 1)
return u64 % ty
baseptr = convert(Ptr{uty}, baseptr)
v = $load_base_expr
mask = (one(uty) << width) - 0x1
return ((v >> offset) & mask) % ty
end
end
else
Expand Down Expand Up @@ -399,19 +415,25 @@ function emit_setproperty!(dag, node, options)
$store_expr
else
baseptr, offset, width = fptr
baseptr32 = convert(Ptr{UInt32}, baseptr)
u64 = unsafe_load(baseptr32)
straddle = offset + width > 32
if straddle
u64 |= unsafe_load(baseptr32 + 4) << 32
end
mask = ((1 << width) - 1)
u64 &= ~(mask << offset)
u64 |= (unsigned(v) & mask) << offset
unsafe_store!(baseptr32, u64 & typemax(UInt32))
if straddle
unsafe_store!(baseptr32 + 4, u64 >> 32)
ty = eltype(baseptr)
sz = offset + width
uty = if sz <= 8
UInt8
elseif sz <= 16
UInt16
elseif sz <= 32
UInt32
elseif sz <= 64
UInt64
elseif sz <= 128
UInt128
end
baseptr = convert(Ptr{uty}, baseptr)
mask = (one(uty) << width) - 0x1
v0 = unsafe_load(baseptr)
v0 &= ~(mask << offset)
v0 |= (unsigned(v) & mask) << offset
unsafe_store!(baseptr, v0)
end
end
rm_line_num_node!(body)
Expand All @@ -431,7 +453,6 @@ function get_names_types(root_cursor, cursor, options)
for field_cursor in field_cursors
n = name(field_cursor)
if isempty(n)
_emit_getproperty_ptr!(root_cursor, field_cursor, options)
continue
end
fsym = make_symbol_safe(n)
Expand Down Expand Up @@ -489,10 +510,14 @@ end
function emit_constructor!(dag, node::ExprNode{<:StructLayout}, options)
sym = make_symbol_safe(node.id)
fsyms, tys = get_names_types(node.cursor, node.cursor, options)
valassign = :(GC.@preserve ref begin
$((:(ptr.$fsym = $fsym) for fsym in fsyms)...)
end)
valassign.args[2] = nothing
body = quote
ref = Ref{$sym}()
ptr = Base.unsafe_convert(Ptr{$sym}, ref)
$((:(ptr.$fsym = $fsym) for fsym in fsyms)...)
$valassign
ref[]
end

Expand Down
22 changes: 22 additions & 0 deletions test/bitfield/bitfield.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,25 @@ struct Mirror toMirror(const struct BitField *src) {
dst.f = src->f;
return dst;
}

struct LargeBitField toLargeBitfield(const struct LargeMirror *src) {
struct LargeBitField dst;
dst.a = src->a;
dst.b = src->b;
dst.c = src->c;
dst.d = src->d;
dst.e = src->e;
dst.f = src->f;
return dst;
}

struct LargeMirror toLargeMirror(const struct LargeBitField *src) {
struct LargeMirror dst;
dst.a = src->a;
dst.b = src->b;
dst.c = src->c;
dst.d = src->d;
dst.e = src->e;
dst.f = src->f;
return dst;
}
20 changes: 20 additions & 0 deletions test/bitfield/bitfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,27 @@ struct Mirror {
unsigned int f;
};

struct LargeBitField {
double a;
short b;
unsigned long long c : 16;
unsigned long long d : 48;
char e;
int f;
};

struct LargeMirror {
double a;
short b;
unsigned long long c;
unsigned long long d;
char e;
int f;
};

struct BitField toBitfield(const struct Mirror *mirror);
struct Mirror toMirror(const struct BitField *bf);
struct LargeBitField toLargeBitfield(const struct LargeMirror *mirror);
struct LargeMirror toLargeMirror(const struct LargeBitField *bf);

#endif /* BITFIELD */
13 changes: 12 additions & 1 deletion test/test_bitfield.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ end
function test_libbitfield()
bf = Ref(LibBitField.BitField(Int8(10), 1.5, Int32(1e6), Int32(-4), Int32(7), UInt32(3)))
m = Ref(LibBitField.Mirror(10, 1.5, 1e6, -4, 7, 3))
GC.@preserve bf m begin
lbf = Ref(LibBitField.LargeBitField(1.5, Int16(10000), UInt64(1023), UInt64(Int64(2)^40 - 1), Int8(-73), Int32(1234567)))
lm = Ref(LibBitField.LargeMirror(1.5, 10000, 1023, Int64(2)^40 - 1, Int8(-73), Int32(1234567)))
GC.@preserve bf m lbf lm begin
pbf = Ptr{LibBitField.BitField}(pointer_from_objref(bf))
pm = Ptr{LibBitField.Mirror}(pointer_from_objref(m))
@test LibBitField.toMirror(bf) == m[]
Expand All @@ -80,6 +82,15 @@ function test_libbitfield()
@test LibBitField.toBitfield(m).d == bf[].d
@test LibBitField.toBitfield(m).e == bf[].e
@test LibBitField.toBitfield(m).f == bf[].f
plbf = Ptr{LibBitField.LargeBitField}(pointer_from_objref(lbf))
plm = Ptr{LibBitField.LargeMirror}(pointer_from_objref(lm))
@test LibBitField.toLargeMirror(lbf) == lm[]
@test LibBitField.toLargeBitfield(lm).a == lbf[].a
@test LibBitField.toLargeBitfield(lm).b == lbf[].b
@test LibBitField.toLargeBitfield(lm).c == lbf[].c
@test LibBitField.toLargeBitfield(lm).d == lbf[].d
@test LibBitField.toLargeBitfield(lm).e == lbf[].e
@test LibBitField.toLargeBitfield(lm).f == lbf[].f
end
end

Expand Down
Loading