diff options
Diffstat (limited to 'compiler/sizealignoffsetimpl.nim')
-rw-r--r-- | compiler/sizealignoffsetimpl.nim | 191 |
1 files changed, 108 insertions, 83 deletions
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim index baa2c40f9..1dd481ec0 100644 --- a/compiler/sizealignoffsetimpl.nim +++ b/compiler/sizealignoffsetimpl.nim @@ -12,7 +12,7 @@ proc align(address, alignment: BiggestInt): BiggestInt = result = (address + (alignment - 1)) and not (alignment - 1) -proc align(address, alignment: int): int = +proc align(address, alignment: int32): int32 = result = (address + (alignment - 1)) and not (alignment - 1) const @@ -29,26 +29,26 @@ proc raiseIllegalTypeRecursion() = raise newException(IllegalTypeRecursionError, "illegal type recursion") type - OffsetAccum = object - maxAlign: int - offset: int + OffsetAccum* = object + maxAlign*: int32 + offset*: int32 -proc inc(arg: var OffsetAccum; value: int) = +proc inc*(arg: var OffsetAccum; value: int32) = if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion() if value == szUnknownSize or arg.offset == szUnknownSize: arg.offset = szUnknownSize else: arg.offset += value -proc alignmentMax(a,b: int): int = +proc alignmentMax(a, b: int32): int32 = if unlikely(a == szIllegalRecursion or b == szIllegalRecursion): raiseIllegalTypeRecursion() if a == szUnknownSize or b == szUnknownSize: szUnknownSize else: - max(a,b) + max(a, b) -proc align(arg: var OffsetAccum; value: int) = - if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion() +proc align*(arg: var OffsetAccum; value: int32) = + if unlikely(value == szIllegalRecursion): raiseIllegalTypeRecursion() if value == szUnknownSize or arg.maxAlign == szUnknownSize or arg.offset == szUnknownSize: arg.maxAlign = szUnknownSize arg.offset = szUnknownSize @@ -65,7 +65,7 @@ proc mergeBranch(arg: var OffsetAccum; value: OffsetAccum) = arg.offset = max(arg.offset, value.offset) arg.maxAlign = max(arg.maxAlign, value.maxAlign) -proc finish(arg: var OffsetAccum): int = +proc finish(arg: var OffsetAccum): int32 = if arg.maxAlign == szUnknownSize or arg.offset == szUnknownSize: result = szUnknownSize arg.offset = szUnknownSize @@ -73,7 +73,7 @@ proc finish(arg: var OffsetAccum): int = result = align(arg.offset, arg.maxAlign) - arg.offset arg.offset += result -proc computeSizeAlign(conf: ConfigRef; typ: PType) +proc computeSizeAlign*(conf: ConfigRef; typ: PType) proc computeSubObjectAlign(conf: ConfigRef; n: PNode): BiggestInt = ## returns object alignment @@ -112,7 +112,7 @@ proc setOffsetsToUnknown(n: PNode) = for i in 0..<n.safeLen: setOffsetsToUnknown(n[i]) -proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum) = +proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bool; accum: var OffsetAccum) = ## ``offset`` is the offset within the object, after the node has been written, no padding bytes added ## ``align`` maximum alignment from all sub nodes assert n != nil @@ -122,42 +122,43 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a of nkRecCase: assert(n[0].kind == nkSym) computeObjectOffsetsFoldFunction(conf, n[0], packed, accum) - var maxChildAlign: int = if accum.offset == szUnknownSize: szUnknownSize else: 1 + var maxChildAlign = if accum.offset == szUnknownSize: szUnknownSize.int32 else: 1'i32 if not packed: for i in 1..<n.len: let child = n[i] case child.kind of nkOfBranch, nkElse: # offset parameter cannot be known yet, it needs to know the alignment first - let align = int(computeSubObjectAlign(conf, n[i].lastSon)) + let align = int32(computeSubObjectAlign(conf, n[i].lastSon)) maxChildAlign = alignmentMax(maxChildAlign, align) else: internalError(conf, "computeObjectOffsetsFoldFunction(record case branch)") if maxChildAlign == szUnknownSize: setOffsetsToUnknown(n) - accum.offset = szUnknownSize + accum.offset = szUnknownSize accum.maxAlign = szUnknownSize else: - # the union neds to be aligned first, before the offsets can be assigned + # the union needs to be aligned first, before the offsets can be assigned accum.align(maxChildAlign) let accumRoot = accum # copy, because each branch should start af the same offset for i in 1..<n.len: - var branchAccum = accumRoot + var branchAccum = OffsetAccum(offset: accumRoot.offset, maxAlign: 1) computeObjectOffsetsFoldFunction(conf, n[i].lastSon, packed, branchAccum) + discard finish(branchAccum) accum.mergeBranch(branchAccum) of nkRecList: for i, child in n.sons: computeObjectOffsetsFoldFunction(conf, child, packed, accum) of nkSym: - var size = szUnknownSize - var align = szUnknownSize + var size = szUnknownSize.int32 + var align = szUnknownSize.int32 if n.sym.bitsize == 0: # 0 represents bitsize not set computeSizeAlign(conf, n.sym.typ) - size = n.sym.typ.size.int - align = if packed: 1 else: n.sym.typ.align.int + size = n.sym.typ.size.int32 + align = if packed: 1 else: n.sym.typ.align.int32 accum.align(align) if n.sym.alignment > 0: - accum.align(n.sym.alignment) + accum.align(n.sym.alignment.int32) n.sym.offset = accum.offset accum.inc(size) else: @@ -173,20 +174,21 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo localError(conf, n.info, "Illegal use of ``case`` in union type.") of nkRecList: let accumRoot = accum # copy, because each branch should start af the same offset - for i, child in n.sons: - var branchAccum = accumRoot + for child in n.sons: + var branchAccum = OffsetAccum(offset: accumRoot.offset, maxAlign: 1) computeUnionObjectOffsetsFoldFunction(conf, child, packed, branchAccum) + discard finish(branchAccum) accum.mergeBranch(branchAccum) of nkSym: - var size = szUnknownSize - var align = szUnknownSize + var size = szUnknownSize.int32 + var align = szUnknownSize.int32 if n.sym.bitsize == 0: # 0 represents bitsize not set computeSizeAlign(conf, n.sym.typ) - size = n.sym.typ.size.int - align = if packed: 1 else: n.sym.typ.align.int + size = n.sym.typ.size.int32 + align = if packed: 1 else: n.sym.typ.align.int32 accum.align(align) if n.sym.alignment > 0: - accum.align(n.sym.alignment) + accum.align(n.sym.alignment.int32) n.sym.offset = accum.offset accum.inc(size) else: @@ -194,6 +196,11 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bo accum.offset = szUnknownSize proc computeSizeAlign(conf: ConfigRef; typ: PType) = + template setSize(typ, s) = + typ.size = s + typ.align = s + typ.paddingAtEnd = 0 + ## computes and sets ``size`` and ``align`` members of ``typ`` assert typ != nil let hasSize = typ.size != szUncomputedSize @@ -240,8 +247,8 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = else: typ.size = conf.target.ptrSize typ.align = int16(conf.target.ptrSize) - of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray: - let base = typ.lastSon + of tyCstring, tySequence, tyPtr, tyRef, tyVar, tyLent: + let base = typ.last if base == typ: # this is not the correct location to detect ``type A = ptr A`` typ.size = szIllegalRecursion @@ -255,17 +262,21 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.size = conf.target.ptrSize of tyArray: - computeSizeAlign(conf, typ[1]) - let elemSize = typ[1].size + computeSizeAlign(conf, typ.elementType) + let elemSize = typ.elementType.size + let len = lengthOrd(conf, typ.indexType) if elemSize < 0: typ.size = elemSize typ.align = int16(elemSize) + elif len < 0: + typ.size = szUnknownSize + typ.align = szUnknownSize else: - typ.size = toInt64Checked(lengthOrd(conf, typ[0]) * int32(elemSize), szTooBigSize) - typ.align = typ[1].align + typ.size = toInt64Checked(len * int32(elemSize), szTooBigSize) + typ.align = typ.elementType.align of tyUncheckedArray: - let base = typ.lastSon + let base = typ.last computeSizeAlign(conf, base) typ.size = 0 typ.align = base.align @@ -275,25 +286,25 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.size = 4 # use signed int32 typ.align = 4 else: - let length = toInt64(lastOrd(conf, typ)) # BUGFIX: use lastOrd! - if length + 1 < `shl`(1, 8): + let lastOrd = toInt64(lastOrd(conf, typ)) # BUGFIX: use lastOrd! + if lastOrd < `shl`(1, 8): typ.size = 1 typ.align = 1 - elif length + 1 < `shl`(1, 16): + elif lastOrd < `shl`(1, 16): typ.size = 2 typ.align = 2 - elif length + 1 < `shl`(BiggestInt(1), 32): + elif lastOrd < `shl`(BiggestInt(1), 32): typ.size = 4 typ.align = 4 else: typ.size = 8 typ.align = int16(conf.floatInt64Align) of tySet: - if typ[0].kind == tyGenericParam: + if typ.elementType.kind == tyGenericParam: typ.size = szUncomputedSize typ.align = szUncomputedSize else: - let length = toInt64(lengthOrd(conf, typ[0])) + let length = toInt64(lengthOrd(conf, typ.elementType)) if length <= 8: typ.size = 1 typ.align = 1 @@ -308,27 +319,26 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.align = int16(conf.floatInt64Align) elif align(length, 8) mod 8 == 0: typ.size = align(length, 8) div 8 - typ.align = int16(conf.floatInt64Align) + typ.align = 1 else: typ.size = align(length, 8) div 8 + 1 - typ.align = int16(conf.floatInt64Align) + typ.align = 1 of tyRange: - computeSizeAlign(conf, typ[0]) - typ.size = typ[0].size - typ.align = typ[0].align - typ.paddingAtEnd = typ[0].paddingAtEnd + computeSizeAlign(conf, typ.elementType) + typ.size = typ.elementType.size + typ.align = typ.elementType.align + typ.paddingAtEnd = typ.elementType.paddingAtEnd of tyTuple: try: var accum = OffsetAccum(maxAlign: 1) - for i in 0..<typ.len: - let child = typ[i] + for i, child in typ.ikids: computeSizeAlign(conf, child) accum.align(child.align) if typ.n != nil: # is named tuple (has field symbols)? let sym = typ.n[i].sym sym.offset = accum.offset - accum.inc(int(child.size)) + accum.inc(int32(child.size)) typ.paddingAtEnd = int16(accum.finish()) typ.size = if accum.offset == 0: 1 else: accum.offset typ.align = int16(accum.maxAlign) @@ -340,27 +350,27 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = of tyObject: try: var accum = - if typ[0] != nil: + if typ.baseClass != nil: # compute header size - var st = typ[0] + var st = typ.baseClass while st.kind in skipPtrs: - st = st[^1] + st = st.skipModifier computeSizeAlign(conf, st) if conf.backend == backendCpp: OffsetAccum( - offset: int(st.size) - int(st.paddingAtEnd), + offset: int32(st.size) - int32(st.paddingAtEnd), maxAlign: st.align ) else: OffsetAccum( - offset: int(st.size), + offset: int32(st.size), maxAlign: st.align ) elif isObjectWithTypeFieldPredicate(typ): # this branch is taken for RootObj OffsetAccum( - offset: conf.target.intSize, - maxAlign: conf.target.intSize + offset: conf.target.intSize.int32, + maxAlign: conf.target.intSize.int32 ) else: OffsetAccum(maxAlign: 1) @@ -369,14 +379,19 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo localError(conf, info, "union type may not have an object header") accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize) - elif tfPacked in typ.flags: - computeUnionObjectOffsetsFoldFunction(conf, typ.n, true, accum) else: - computeUnionObjectOffsetsFoldFunction(conf, typ.n, false, accum) + computeUnionObjectOffsetsFoldFunction(conf, typ.n, tfPacked in typ.flags, accum) elif tfPacked in typ.flags: accum.maxAlign = 1 computeObjectOffsetsFoldFunction(conf, typ.n, true, accum) else: + if typ.baseClass == nil and lacksMTypeField(typ) and typ.n.len == 1 and + typ.n[0].kind == nkSym and + typ.n[0].sym.typ.skipTypes(abstractInst).kind == tyUncheckedArray: + # a dummy field is generated for an object with a single field + # with an UncheckedArray type + assert accum.offset == 0 + accum.offset = 1 computeObjectOffsetsFoldFunction(conf, typ.n, false, accum) let paddingAtEnd = int16(accum.finish()) if typ.sym != nil and @@ -394,24 +409,24 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.align = szIllegalRecursion typ.paddingAtEnd = szIllegalRecursion of tyInferred: - if typ.len > 1: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + if typ.hasElementType: + computeSizeAlign(conf, typ.last) + typ.size = typ.last.size + typ.align = typ.last.align + typ.paddingAtEnd = typ.last.paddingAtEnd of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink, tyOwned: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + computeSizeAlign(conf, typ.skipModifier) + typ.size = typ.skipModifier.size + typ.align = typ.skipModifier.align + typ.paddingAtEnd = typ.last.paddingAtEnd of tyTypeClasses: if typ.isResolvedUserTypeClass: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + computeSizeAlign(conf, typ.last) + typ.size = typ.last.size + typ.align = typ.last.align + typ.paddingAtEnd = typ.last.paddingAtEnd else: typ.size = szUnknownSize typ.align = szUnknownSize @@ -424,21 +439,30 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) = typ.paddingAtEnd = typ.base.paddingAtEnd of tyForward: - # is this really illegal recursion, or maybe just unknown? - typ.size = szIllegalRecursion - typ.align = szIllegalRecursion - typ.paddingAtEnd = szIllegalRecursion + typ.size = szUnknownSize + typ.align = szUnknownSize + typ.paddingAtEnd = szUnknownSize of tyStatic: if typ.n != nil: - computeSizeAlign(conf, typ.lastSon) - typ.size = typ.lastSon.size - typ.align = typ.lastSon.align - typ.paddingAtEnd = typ.lastSon.paddingAtEnd + computeSizeAlign(conf, typ.last) + typ.size = typ.last.size + typ.align = typ.last.align + typ.paddingAtEnd = typ.last.paddingAtEnd else: typ.size = szUnknownSize typ.align = szUnknownSize typ.paddingAtEnd = szUnknownSize + of tyInt, tyUInt: + setSize typ, conf.target.intSize.int16 + of tyBool, tyChar, tyUInt8, tyInt8: + setSize typ, 1 + of tyInt16, tyUInt16: + setSize typ, 2 + of tyInt32, tyUInt32, tyFloat32: + setSize typ, 4 + of tyInt64, tyUInt64, tyFloat64, tyFloat: + setSize typ, 8 else: typ.size = szUnknownSize typ.align = szUnknownSize @@ -476,7 +500,7 @@ template foldOffsetOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode = ## Returns an int literal node of the given offsetof expression in `n`. ## Falls back to `fallback`, if the `offsetof` expression can't be processed. let config = conf - let node : PNode = n + let node = n var dotExpr: PNode block findDotExpr: if node[1].kind == nkDotExpr: @@ -484,6 +508,7 @@ template foldOffsetOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode = elif node[1].kind == nkCheckedFieldExpr: dotExpr = node[1][0] else: + dotExpr = nil localError(config, node.info, "can't compute offsetof on this ast") assert dotExpr != nil |