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

implement sizeof and alignof operator #5664

Closed
wants to merge 42 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
7ceb7ab
basic refactor
krux02 Apr 5, 2017
ccbd9e8
renamed computeSizeAux→computeSizeAndAlign
krux02 Apr 5, 2017
9ccfeb3
fix bug in times.nim
krux02 Apr 5, 2017
892bc99
format code
krux02 Apr 5, 2017
037c9c0
more refactoring
krux02 Apr 5, 2017
f3476a1
some work in progress
krux02 Apr 6, 2017
2f560f0
code reduction
krux02 Apr 8, 2017
e0334ab
WIP
krux02 Apr 11, 2017
cb14a8c
WIP
krux02 Apr 19, 2017
181a06d
add todo
krux02 May 4, 2017
376f22a
make bug visible
krux02 Apr 19, 2017
a0b17bc
a big step for me a small step for humanity
krux02 Apr 19, 2017
72d5d0d
my test now passes
krux02 Apr 19, 2017
aad3c89
removed debug information
krux02 Apr 19, 2017
db15fcc
removed old tsizeof.nim
krux02 Apr 19, 2017
a9eff03
move tsizeof into tests folder
krux02 Apr 19, 2017
7092c97
move size align offset into its own file
krux02 Apr 19, 2017
d6041b0
tsizeof now almost works for packed types
krux02 May 9, 2017
3dadd53
some renaming
krux02 May 19, 2017
802dc5d
fixes for breaking change of do notation
krux02 Jun 13, 2017
63a3a8f
WIP with debug output, and amend to trigger tests
krux02 Jul 14, 2017
e0e8e37
added bug
krux02 Sep 13, 2017
7a9419b
hard to find bug fixed, but still bugged
krux02 Sep 14, 2017
3e1800b
Merge branch 'devel' into sizeof-alignof
krux02 Aug 4, 2018
e7cf79d
post merge fix 1
krux02 Aug 4, 2018
8280f04
minimal fixes
krux02 Aug 5, 2018
9582a45
Merge branch 'devel' into sizeof-alignof
krux02 Aug 7, 2018
cbe99e1
fix for enum alignment
krux02 Aug 7, 2018
b302fd3
instance test size packed and unpacked
krux02 Aug 7, 2018
9b2aa8d
remove dead code, and make compilation fail at WIP
krux02 Aug 7, 2018
04c0a55
Merge branch 'devel' into sizeof-alignof
krux02 Oct 5, 2018
5f81489
update sizeof test, put back sizeof fallback
krux02 Oct 5, 2018
bf7db99
this should make tests on osx green
krux02 Oct 8, 2018
2cda6c4
Delete rodread.nim
krux02 Oct 8, 2018
1cd7a84
Delete rodwrite.nim
krux02 Oct 8, 2018
cda1ab4
better sizeof for imported types
krux02 Oct 8, 2018
209e8c0
remove debug output
krux02 Oct 8, 2018
2afcc69
let casting of imported types be a problem of the backend
krux02 Oct 9, 2018
c746166
detect illegal recursion in partially imported types
krux02 Oct 10, 2018
f7ad91b
sizeof unchecked array ;)
krux02 Oct 10, 2018
7a56147
Merge branch 'devel' into sizeof-alignof
krux02 Oct 10, 2018
b0b1b36
recursive tuples are detected again
krux02 Oct 11, 2018
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
10 changes: 3 additions & 7 deletions compiler/ast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,8 @@ type
TMagic* = enum # symbols that require compiler magic:
mNone,
mDefined, mDefinedInScope, mCompiles, mArrGet, mArrPut, mAsgn,
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mAddr, mType, mTypeOf,
mLow, mHigh, mSizeOf, mAlignOf, mOffsetOf, mTypeTrait,
mIs, mOf, mAddr, mType, mTypeOf,
mRoof, mPlugin, mEcho, mShallowCopy, mSlurp, mStaticExec, mStatic,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mInc, mDec, mOrd,
Expand Down Expand Up @@ -698,11 +699,6 @@ const
mConStrStr, mAppendStrCh, mAppendStrStr, mAppendSeqElem,
mInRange, mInSet, mRepr,
mCopyStr, mCopyStrLast}
# magics that require special semantic checking and
# thus cannot be overloaded (also documented in the spec!):
SpecialSemMagics* = {
mDefined, mDefinedInScope, mCompiles, mLow, mHigh, mSizeOf, mIs, mOf,
mShallowCopy, mExpandToAst, mParallel, mSpawn, mAstToStr}

type
PNode* = ref TNode
Expand Down Expand Up @@ -1274,7 +1270,7 @@ proc newType*(kind: TTypeKind, owner: PSym): PType =
result.kind = kind
result.owner = owner
result.size = -1
result.align = 2 # default alignment
result.align = -1 # default alignment
result.id = getID()
result.lockLevel = UnspecifiedLockLevel
when debugIds:
Expand Down
2 changes: 1 addition & 1 deletion compiler/canonicalizer.nim
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ proc encodeType(w: PRodWriter, t: PType, result: var string) =
if t.size != - 1:
add(result, '/')
encodeVBiggestInt(t.size, result)
if t.align != 2:
if t.align != - 1:
add(result, '=')
encodeVInt(t.align, result)
encodeLoc(w, t.loc, result)
Expand Down
1 change: 1 addition & 0 deletions compiler/condsyms.nim
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ proc initDefines*(symbols: StringTableRef) =
defineSymbol("nimtypedescfixed")
defineSymbol("nimKnowsNimvm")
defineSymbol("nimArrIdx")
defineSymbol("nimHasalignOf")
defineSymbol("nimImmediateDeprecated")
defineSymbol("nimNewShiftOps")
defineSymbol("nimDistros")
Expand Down
2 changes: 0 additions & 2 deletions compiler/jsgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1759,7 +1759,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
of mIsNil: unaryExpr(p, n, r, "", "($1 === null)")
of mEnumToStr: genRepr(p, n, r)
of mNew, mNewFinalize: genNew(p, n)
of mSizeOf: r.res = rope(getSize(p.config, n.sons[1].typ))
of mChr, mArrToSeq: gen(p, n.sons[1], r) # nothing to do
of mOrd: genOrd(p, n, r)
of mLengthStr, mLengthSeq, mLengthOpenArray, mLengthArray:
Expand Down Expand Up @@ -2356,4 +2355,3 @@ proc myOpen(graph: ModuleGraph; s: PSym): PPassContext =
result = newModule(graph, s)

const JSgenPass* = makePass(myOpen, myProcess, myClose)

4 changes: 3 additions & 1 deletion compiler/pragmas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -803,9 +803,11 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
if sym.typ == nil: invalidPragma(c, it)
var size = expectIntLit(c, it)
if not isPowerOfTwo(size) or size <= 0 or size > 8:
localError(c.config, it.info, "power of two expected")
localError(c.config, it.info, "size may only be 1, 2, 4 or 8")
else:
sym.typ.size = size
# TODO, this is not correct
sym.typ.align = int16(size)
of wNodecl:
noVal(c, it)
incl(sym.loc.flags, lfNoDecl)
Expand Down
15 changes: 4 additions & 11 deletions compiler/semexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ proc isCastable(conf: ConfigRef; dst, src: PType): bool =
var dstSize, srcSize: BiggestInt
dstSize = computeSize(conf, dst)
srcSize = computeSize(conf, src)
if dstSize == -3 or srcSize == -3: # szUnknownSize
# The Nim compiler can't detect if it's legal or not.
# Just assume the programmer knows what he is doing.
return true
if dstSize < 0:
result = false
elif srcSize < 0:
Expand Down Expand Up @@ -308,15 +312,6 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
localError(c.config, n.info, "invalid argument for: " & opToStr[m])
result = n

proc semSizeof(c: PContext, n: PNode): PNode =
if sonsLen(n) != 2:
localError(c.config, n.info, errXExpectsTypeOrValue % "sizeof")
else:
n.sons[1] = semExprWithType(c, n.sons[1], {efDetermineType})
#restoreOldStyleType(n.sons[1])
n.typ = getSysType(c.graph, n.info, tyInt)
result = n

proc fixupStaticType(c: PContext, n: PNode) =
# This proc can be applied to evaluated expressions to assign
# them a static type.
Expand Down Expand Up @@ -1958,7 +1953,6 @@ proc setMs(n: PNode, s: PSym): PNode =

proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
# this is a hotspot in the compiler!
# DON'T forget to update ast.SpecialSemMagics if you add a magic here!
result = n
case s.magic # magics that need special treatment
of mAddr:
Expand All @@ -1975,7 +1969,6 @@ proc semMagic(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
of mCompiles: result = semCompiles(c, setMs(n, s), flags)
#of mLow: result = semLowHigh(c, setMs(n, s), mLow)
#of mHigh: result = semLowHigh(c, setMs(n, s), mHigh)
of mSizeOf: result = semSizeof(c, setMs(n, s))
of mIs: result = semIs(c, setMs(n, s), flags)
#of mOf: result = semOf(c, setMs(n, s))
of mShallowCopy: result = semShallowCopy(c, n, flags)
Expand Down
12 changes: 0 additions & 12 deletions compiler/semfold.nim
Original file line number Diff line number Diff line change
Expand Up @@ -646,18 +646,6 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
of mNone:
# If it has no sideEffect, it should be evaluated. But not here.
return
of mSizeOf:
var a = n.sons[1]
if computeSize(g.config, a.typ) < 0:
localError(g.config, a.info, "cannot evaluate 'sizeof' because its type is not defined completely")
result = nil
elif skipTypes(a.typ, typedescInst+{tyRange, tyArray}).kind in
IntegralTypes+NilableTypes+{tySet}:
#{tyArray,tyObject,tyTuple}:
result = newIntNodeT(getSize(g.config, a.typ), n, g)
else:
result = nil
# XXX: size computation for complex types is still wrong
of mLow:
result = newIntNodeT(firstOrd(g.config, n.sons[1].typ), n, g)
of mHigh:
Expand Down
57 changes: 55 additions & 2 deletions compiler/semmagic.nim
Original file line number Diff line number Diff line change
Expand Up @@ -307,15 +307,68 @@ proc semOf(c: PContext, n: PNode): PNode =

proc magicsAfterOverloadResolution(c: PContext, n: PNode,
flags: TExprFlags): PNode =
## This is the preferred code point to implement magics.
## This function basically works like a macro, with the difference
## that it is implemented in the compiler and not on the nimvm.
## ``c`` the current module, a symbol table to a very good approximation
## ``n`` the ast like it would be passed to a real macro
## ``flags`` Some flags for more contextual information on how the
## "macro" is calld.

case n[0].sym.magic
of mAddr:
checkSonsLen(n, 2, c.config)
result = semAddr(c, n.sons[1], n[0].sym.name.s == "unsafeAddr")
of mTypeOf:
checkSonsLen(n, 2, c.config)
result = semTypeOf(c, n.sons[1])
of mArrGet: result = semArrGet(c, n, flags)
of mArrPut: result = semArrPut(c, n, flags)
of mSizeOf:
# TODO there is no proper way to find out if a type cannot be queried for the size.
let size = getSize(c.config, n[1].typ)
# We just assume here that the type might come from the c backend
if size == szUnknownSize:
# Forward to the c code generation to emit a `sizeof` in the C code.
result = n
elif size >= 0:
Copy link
Member

@timotheecour timotheecour Oct 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will that work with incomplete types that have at least 1 field?

type
  MyStruct {.importc: "MyStruct".} = object
    field1: int
    # missing field2

see also #9250 for a more robust solution (that can be implemented after your PR)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

originally I was looking at the wrong location for the importc flag. Now it should work properly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@krux02 is my assessment in #9250 correct that currently you must pessimistically reject computing sizeof for any type annotated as importc ? feel free to comment in #9250

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are correct.

result = newIntNode(nkIntLit, size)
result.info = n.info
result.typ = n.typ
else:

localError(c.config, n.info, "cannot evaluate 'sizeof' because its type is not defined completely")

result = nil


of mAlignOf:
result = newIntNode(nkIntLit, getAlign(c.config, n[1].typ))
result.info = n.info
result.typ = n.typ
of mOffsetOf:
var dotExpr: PNode

block findDotExpr:
if n[1].kind == nkDotExpr:
dotExpr = n[1]
elif n[1].kind == nkCheckedFieldExpr:
dotExpr = n[1][0]
else:
illFormedAst(n, c.config)

assert dotExpr != nil

let value = dotExpr[0]
let member = dotExpr[1]

discard computeSize(c.config, value.typ)

result = newIntNode(nkIntLit, member.sym.offset)
result.info = n.info
result.typ = n.typ
of mArrGet:
result = semArrGet(c, n, flags)
of mArrPut:
result = semArrPut(c, n, flags)
of mAsgn:
if n[0].sym.name.s == "=":
result = semAsgnOpr(c, n)
Expand Down
1 change: 0 additions & 1 deletion compiler/semtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1848,4 +1848,3 @@ proc semGenericParamList(c: PContext, n: PNode, father: PType = nil): PNode =
s.position = result.len
addSon(result, newSymNode(s))
if sfGenSym notin s.flags: addDecl(c, s)

1 change: 0 additions & 1 deletion compiler/sigmatch.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2612,4 +2612,3 @@ tests:

yes int, ordinal
no string, ordinal

Loading