This commit is contained in:
Andreas Rumpf 2018-12-30 02:45:34 +01:00
commit 062d7e3a39
2 changed files with 22 additions and 25 deletions

View file

@ -18,7 +18,7 @@ const
szIllegalRecursion* = -2 szIllegalRecursion* = -2
szUncomputedSize* = -1 szUncomputedSize* = -1
proc computeSizeAlign(conf: ConfigRef; typ: PType): void proc computeSizeAlign(conf: ConfigRef; typ: PType)
proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt = proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt =
## returns object alignment ## returns object alignment
@ -49,7 +49,8 @@ proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt =
else: else:
result = 1 result = 1
proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset: BiggestInt): tuple[offset, align: BiggestInt] = proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode,
initialOffset: BiggestInt): tuple[offset, align: BiggestInt] =
## ``offset`` is the offset within the object, after the node has been written, no padding bytes added ## ``offset`` is the offset within the object, after the node has been written, no padding bytes added
## ``align`` maximum alignment from all sub nodes ## ``align`` maximum alignment from all sub nodes
assert n != nil assert n != nil
@ -71,66 +72,52 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset:
of nkOfBranch, nkElse: of nkOfBranch, nkElse:
# offset parameter cannot be known yet, it needs to know the alignment first # offset parameter cannot be known yet, it needs to know the alignment first
let align = computeSubObjectAlign(conf, n.sons[i].lastSon) let align = computeSubObjectAlign(conf, n.sons[i].lastSon)
if align == szIllegalRecursion: if align == szIllegalRecursion:
result.offset = szIllegalRecursion result.offset = szIllegalRecursion
result.align = szIllegalRecursion result.align = szIllegalRecursion
return return
if align == szUnknownSize or maxChildAlign == szUnknownSize: if align == szUnknownSize or maxChildAlign == szUnknownSize:
maxChildAlign = szUnknownSize maxChildAlign = szUnknownSize
else: else:
maxChildAlign = max(maxChildAlign, align) maxChildAlign = max(maxChildAlign, align)
else: else:
internalError(conf, "computeObjectOffsetsFoldFunction(record case branch)") internalError(conf, "computeObjectOffsetsFoldFunction(record case branch)")
if maxChildAlign == szUnknownSize: if maxChildAlign == szUnknownSize:
result.align = szUnknownSize result.align = szUnknownSize
result.offset = szUnknownSize result.offset = szUnknownSize
else: else:
# the union neds to be aligned first, before the offsets can be assigned # the union neds to be aligned first, before the offsets can be assigned
let kindUnionOffset = align(kindOffset, maxChildAlign) let kindUnionOffset = align(kindOffset, maxChildAlign)
var maxChildOffset: BiggestInt = 0 var maxChildOffset: BiggestInt = 0
for i in 1 ..< sonsLen(n): for i in 1 ..< sonsLen(n):
let (offset, align) = computeObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, kindUnionOffset) let (offset, align) = computeObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, kindUnionOffset)
maxChildOffset = max(maxChildOffset, offset) maxChildOffset = max(maxChildOffset, offset)
result.align = max(kindAlign, maxChildAlign) result.align = max(kindAlign, maxChildAlign)
result.offset = maxChildOffset result.offset = maxChildOffset
of nkRecList: of nkRecList:
result.align = 1 # maximum of all member alignments result.align = 1 # maximum of all member alignments
var offset = initialOffset var offset = initialOffset
for i, child in n.sons: for i, child in n.sons:
let (new_offset, align) = computeObjectOffsetsFoldFunction(conf, child, offset) let (new_offset, align) = computeObjectOffsetsFoldFunction(conf, child, offset)
if new_offset == szIllegalRecursion: if new_offset == szIllegalRecursion:
result.offset = szIllegalRecursion result.offset = szIllegalRecursion
result.align = szIllegalRecursion result.align = szIllegalRecursion
return return
elif new_offset == szUnknownSize or offset == szUnknownSize: elif new_offset == szUnknownSize or offset == szUnknownSize:
# if anything is unknown, the rest becomes unknown as well # if anything is unknown, the rest becomes unknown as well
offset = szUnknownSize offset = szUnknownSize
result.align = szUnknownSize result.align = szUnknownSize
else: else:
offset = new_offset offset = new_offset
result.align = max(result.align, align) result.align = max(result.align, align)
# final alignment # final alignment
if offset == szUnknownSize: if offset == szUnknownSize:
result.offset = szUnknownSize result.offset = szUnknownSize
else: else:
result.offset = align(offset, result.align) result.offset = align(offset, result.align)
of nkSym: of nkSym:
var size = szUnknownSize var size = szUnknownSize
var align = szUnknownSize var align = szUnknownSize
if n.sym.bitsize == 0: # 0 represents bitsize not set if n.sym.bitsize == 0: # 0 represents bitsize not set
computeSizeAlign(conf, n.sym.typ) computeSizeAlign(conf, n.sym.typ)
size = n.sym.typ.size.int size = n.sym.typ.size.int
@ -155,7 +142,6 @@ proc computePackedObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOf
let kindOffset = computePackedObjectOffsetsFoldFunction(conf, n.sons[0], initialOffset, debug) let kindOffset = computePackedObjectOffsetsFoldFunction(conf, n.sons[0], initialOffset, debug)
# the union neds to be aligned first, before the offsets can be assigned # the union neds to be aligned first, before the offsets can be assigned
let kindUnionOffset = kindOffset let kindUnionOffset = kindOffset
var maxChildOffset: BiggestInt = kindUnionOffset var maxChildOffset: BiggestInt = kindUnionOffset
for i in 1 ..< sonsLen(n): for i in 1 ..< sonsLen(n):
let offset = computePackedObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, kindUnionOffset, debug) let offset = computePackedObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, kindUnionOffset, debug)
@ -168,11 +154,14 @@ proc computePackedObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOf
if result == szIllegalRecursion: if result == szIllegalRecursion:
break break
of nkSym: of nkSym:
if n.sym.bitsize == 0:
computeSizeAlign(conf, n.sym.typ) computeSizeAlign(conf, n.sym.typ)
n.sym.offset = initialOffset.int n.sym.offset = initialOffset.int
result = n.sym.offset + n.sym.typ.size result = n.sym.offset + n.sym.typ.size
else: else:
result = szUnknownSize result = szUnknownSize
else:
result = szUnknownSize
# TODO this one needs an alignment map of the individual types # TODO this one needs an alignment map of the individual types
@ -324,7 +313,6 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
var headerAlign: int16 var headerAlign: int16
if typ.sons[0] != nil: if typ.sons[0] != nil:
# compute header size # compute header size
if conf.cmd == cmdCompileToCpp: if conf.cmd == cmdCompileToCpp:
# if the target is C++ the members of this type are written # if the target is C++ the members of this type are written
# into the padding byets at the end of the parent type. At the # into the padding byets at the end of the parent type. At the
@ -364,7 +352,6 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.size = szUnknownSize typ.size = szUnknownSize
typ.align = szUnknownSize typ.align = szUnknownSize
return return
# header size is already in size from computeObjectOffsetsFoldFunction # header size is already in size from computeObjectOffsetsFoldFunction
# maxAlign is probably not changed at all from headerAlign # maxAlign is probably not changed at all from headerAlign
if tfPacked in typ.flags: if tfPacked in typ.flags:
@ -373,7 +360,6 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
else: else:
typ.align = int16(max(align, headerAlign)) typ.align = int16(max(align, headerAlign))
typ.size = align(offset, typ.align) typ.size = align(offset, typ.align)
of tyInferred: of tyInferred:
if typ.len > 1: if typ.len > 1:
computeSizeAlign(conf, typ.lastSon) computeSizeAlign(conf, typ.lastSon)

View file

@ -391,6 +391,17 @@ type
assert sizeof(Bar) == 12 assert sizeof(Bar) == 12
# bug #10082
type
A = int8 # change to int16 and get sizeof(C)==6
B = int16
C = object {.packed.}
d {.bitsize: 1.}: A
e {.bitsize: 7.}: A
f {.bitsize: 16.}: B
assert sizeof(C) == 3
if failed: if failed:
quit("FAIL") quit("FAIL")
else: else: