Skip to content

Commit

Permalink
implement sizeof and alignof operator (manually squashed nim-lang#5664)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arne Döring authored and timotheecour committed Oct 13, 2018
1 parent d570dea commit 082612e
Show file tree
Hide file tree
Showing 18 changed files with 906 additions and 236 deletions.
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:
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

0 comments on commit 082612e

Please sign in to comment.