Nim/compiler/ccgexprs.nim
Zahary Karadjov 0b197ade6c Multiple C lines corresponding to a single nimrod line are joined together
This patch greatly improves the "step over" operation available in debuggers.
In practice, there are often 4-8 lines of C code generated for each nimrod line
Each such line will be responsible to a single step in the debugger that is
a) not expected by the user
b) taking the user to an incorrect line in the nimrod code

To keep this working, all code generation should use the rope formatting
facilities when producing new lines (i.e. $n and $N).
New semantics for the format string are introduced:
$n means "soft new line" that could be joined/broken when lineDir is enabled.
$N means "hard new line" that will always appear as a new line.

As an alternative to this approach, I also tested producing code like this:
#line "code.nim" 154
foo = bar; \
foo(bar) \

This is better for readability of the final output, but unfortunately it didn't
produce the desired result across all compilers/debuggers.
2011-09-20 14:11:06 +03:00

1858 lines
68 KiB
Nim
Executable file

#
#
# The Nimrod Compiler
# (c) Copyright 2011 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
proc lenField: PRope {.inline.} =
result = toRope(if gCmd != cmdCompileToCpp: "Sup.len" else: "len")
# -------------------------- constant expressions ------------------------
proc intLiteral(i: biggestInt): PRope =
if (i > low(int32)) and (i <= high(int32)):
result = toRope(i)
elif i == low(int32):
# Nimrod has the same bug for the same reasons :-)
result = toRope("(-2147483647 -1)")
elif i > low(int64):
result = ropef("IL64($1)", [toRope(i)])
else:
result = toRope("(IL64(-9223372036854775807) - IL64(1))")
proc int32Literal(i: Int): PRope =
if i == int(low(int32)):
result = toRope("(-2147483647 -1)")
else:
result = toRope(i)
proc genHexLiteral(v: PNode): PRope =
# hex literals are unsigned in C
# so we don't generate hex literals any longer.
if not (v.kind in {nkIntLit..nkInt64Lit}):
internalError(v.info, "genHexLiteral")
result = intLiteral(v.intVal)
proc getStrLit(m: BModule, s: string): PRope =
discard cgsym(m, "TGenericSeq")
result = con("TMP", toRope(getID()))
appf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
[result, makeCString(s), ToRope(len(s))])
proc genLiteral(p: BProc, v: PNode, ty: PType): PRope =
if ty == nil: internalError(v.info, "genLiteral: ty is nil")
case v.kind
of nkCharLit..nkInt64Lit:
case skipTypes(ty, abstractVarRange).kind
of tyChar, tyInt64, tyNil:
result = intLiteral(v.intVal)
of tyInt8:
result = ropef("((NI8) $1)", [intLiteral(biggestInt(int8(v.intVal)))])
of tyInt16:
result = ropef("((NI16) $1)", [intLiteral(biggestInt(int16(v.intVal)))])
of tyInt32:
result = ropef("((NI32) $1)", [intLiteral(biggestInt(int32(v.intVal)))])
of tyInt:
if (v.intVal >= low(int32)) and (v.intVal <= high(int32)):
result = int32Literal(int32(v.intVal))
else:
result = intLiteral(v.intVal)
of tyBool:
if v.intVal != 0: result = toRope("NIM_TRUE")
else: result = toRope("NIM_FALSE")
else:
result = ropef("(($1) $2)", [getTypeDesc(p.module,
skipTypes(ty, abstractVarRange)), intLiteral(v.intVal)])
of nkNilLit:
result = toRope("NIM_NIL")
of nkStrLit..nkTripleStrLit:
if skipTypes(ty, abstractVarRange).kind == tyString:
var id = NodeTableTestOrSet(p.module.dataCache, v, gid)
if id == gid:
# string literal not found in the cache:
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
[getStrLit(p.module, v.strVal)])
else:
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [toRope(id)])
else:
result = makeCString(v.strVal)
of nkFloatLit..nkFloat64Lit:
result = toRope(v.floatVal.ToStrMaxPrecision)
else:
InternalError(v.info, "genLiteral(" & $v.kind & ')')
result = nil
proc genLiteral(p: BProc, v: PNode): PRope =
result = genLiteral(p, v, v.typ)
proc bitSetToWord(s: TBitSet, size: int): BiggestInt =
result = 0
when true:
for j in countup(0, size - 1):
if j < len(s): result = result or `shl`(Ze64(s[j]), j * 8)
else:
# not needed, too complex thinking:
if CPU[platform.hostCPU].endian == CPU[targetCPU].endian:
for j in countup(0, size - 1):
if j < len(s): result = result or `shl`(Ze64(s[j]), j * 8)
else:
for j in countup(0, size - 1):
if j < len(s): result = result or `shl`(Ze64(s[j]), (Size - 1 - j) * 8)
proc genRawSetData(cs: TBitSet, size: int): PRope =
var frmt: TFormatStr
if size > 8:
result = ropef("{$n")
for i in countup(0, size - 1):
if i < size - 1:
# not last iteration?
if (i + 1) mod 8 == 0: frmt = "0x$1,$n"
else: frmt = "0x$1, "
else:
frmt = "0x$1}$n"
appf(result, frmt, [toRope(toHex(Ze64(cs[i]), 2))])
else:
result = intLiteral(bitSetToWord(cs, size))
# result := toRope('0x' + ToHex(bitSetToWord(cs, size), size * 2))
proc genSetNode(p: BProc, n: PNode): PRope =
var cs: TBitSet
var size = int(getSize(n.typ))
toBitSet(n, cs)
if size > 8:
var id = NodeTableTestOrSet(p.module.dataCache, n, gid)
result = con("TMP", toRope(id))
if id == gid:
# not found in cache:
inc(gid)
appf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
else:
result = genRawSetData(cs, size)
proc getStorageLoc(n: PNode): TStorageLoc =
case n.kind
of nkSym:
case n.sym.kind
of skParam, skForVar, skTemp:
result = OnStack
of skVar, skResult:
if sfGlobal in n.sym.flags: result = OnHeap
else: result = OnStack
of skConst:
if sfGlobal in n.sym.flags: result = OnHeap
else: result = OnUnknown
else: result = OnUnknown
of nkDerefExpr, nkHiddenDeref:
case n.sons[0].typ.kind
of tyVar: result = OnUnknown
of tyPtr: result = OnStack
of tyRef: result = OnHeap
else: InternalError(n.info, "getStorageLoc")
of nkBracketExpr, nkDotExpr, nkObjDownConv, nkObjUpConv:
result = getStorageLoc(n.sons[0])
else: result = OnUnknown
proc genRefAssign(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appf(p.s[cpsStmts], "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
elif dest.s == OnHeap:
# location is on heap
# now the writer barrier is inlined for performance:
#
# if afSrcIsNotNil in flags:
# UseMagic(p.module, 'nimGCref')
# appf(p.s[cpsStmts], 'nimGCref($1);$n', [rdLoc(src)])
# elif afSrcIsNil notin flags:
# UseMagic(p.module, 'nimGCref')
# appf(p.s[cpsStmts], 'if ($1) nimGCref($1);$n', [rdLoc(src)])
# if afDestIsNotNil in flags:
# UseMagic(p.module, 'nimGCunref')
# appf(p.s[cpsStmts], 'nimGCunref($1);$n', [rdLoc(dest)])
# elif afDestIsNil notin flags:
# UseMagic(p.module, 'nimGCunref')
# appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)])
# appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)])
if canFormAcycle(dest.t):
appcg(p.module, p.s[cpsStmts], "#asgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)])
else:
appcg(p.module, p.s[cpsStmts], "#asgnRefNoCycle((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)])
else:
appcg(p.module, p.s[cpsStmts], "#unsureAsgnRef((void**) $1, $2);$n",
[addrLoc(dest), rdLoc(src)])
proc genGenericAsgn(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# Consider:
# type TMyFastString {.shallow.} = string
# Due to the implementation of pragmas this would end up to set the
# tfShallow flag for the built-in string type too! So we check only
# here for this flag, where it is reasonably safe to do so
# (for objects, etc.):
if needToCopy notin flags or
tfShallow in skipTypes(dest.t, abstractVarRange).flags:
if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appcg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($3));$n",
[addrLoc(dest), addrLoc(src), rdLoc(dest)])
else:
appcg(p, cpsStmts, "#genericShallowAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else:
appcg(p, cpsStmts, "#genericAssign((void*)$1, (void*)$2, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
# This function replaces all other methods for generating
# the assignment operation in C.
if src.t != nil and src.t.kind == tyPtr:
# little HACK to support the new 'var T' as return type:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
return
var ty = skipTypes(dest.t, abstractVarRange)
case ty.kind
of tyRef:
genRefAssign(p, dest, src, flags)
of tySequence:
if needToCopy notin flags:
genRefAssign(p, dest, src, flags)
else:
appcg(p, cpsStmts, "#genericSeqAssign($1, $2, $3);$n",
[addrLoc(dest), rdLoc(src), genTypeInfo(p.module, dest.t)])
of tyString:
if needToCopy notin flags:
genRefAssign(p, dest, src, flags)
else:
if dest.s == OnStack or optRefcGC notin gGlobalOptions:
appcg(p, cpsStmts, "$1 = #copyString($2);$n", [rdLoc(dest), rdLoc(src)])
elif dest.s == OnHeap:
appcg(p, cpsStmts, "#asgnRefNoCycle((void**) $1, #copyString($2));$n",
[addrLoc(dest), rdLoc(src)])
else:
appcg(p, cpsStmts, "#unsureAsgnRef((void**) $1, #copyString($2));$n",
[addrLoc(dest), rdLoc(src)])
of tyTuple, tyObject:
# XXX: check for subtyping?
if needsComplexAssignment(dest.t):
genGenericAsgn(p, dest, src, flags)
else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyArray, tyArrayConstr:
if needsComplexAssignment(dest.t):
genGenericAsgn(p, dest, src, flags)
else:
appcg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1));$n",
[rdLoc(dest), rdLoc(src)])
of tyOpenArray:
# open arrays are always on the stack - really? What if a sequence is
# passed to an open array?
if needsComplexAssignment(dest.t):
appcg(p, cpsStmts, # XXX: is this correct for arrays?
"#genericAssignOpenArray((void*)$1, (void*)$2, $1Len0, $3);$n",
[addrLoc(dest), addrLoc(src), genTypeInfo(p.module, dest.t)])
else:
appcg(p, cpsStmts,
"memcpy((void*)$1, (NIM_CONST void*)$2, sizeof($1[0])*$1Len0);$n",
[rdLoc(dest), rdLoc(src)])
of tySet:
if mapType(ty) == ctArray:
appcg(p, cpsStmts, "memcpy((void*)$1, (NIM_CONST void*)$2, $3);$n",
[rdLoc(dest), rdLoc(src), toRope(getSize(dest.t))])
else:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
of tyPtr, tyPointer, tyChar, tyBool, tyProc, tyEnum, tyCString,
tyInt..tyFloat128, tyRange:
appcg(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
else: InternalError("genAssignment(" & $ty.kind & ')')
proc expr(p: BProc, e: PNode, d: var TLoc)
proc initLocExpr(p: BProc, e: PNode, result: var TLoc) =
initLoc(result, locNone, getUniqueType(e.typ), OnUnknown)
expr(p, e, result)
proc getDestLoc(p: BProc, d: var TLoc, typ: PType) =
if d.k == locNone: getTemp(p, typ, d)
proc putLocIntoDest(p: BProc, d: var TLoc, s: TLoc) =
if d.k != locNone:
if lfNoDeepCopy in d.flags: genAssignment(p, d, s, {})
else: genAssignment(p, d, s, {needToCopy})
else:
d = s # ``d`` is free, so fill it with ``s``
proc putIntoDest(p: BProc, d: var TLoc, t: PType, r: PRope) =
var a: TLoc
if d.k != locNone:
# need to generate an assignment here
initLoc(a, locExpr, getUniqueType(t), OnUnknown)
a.r = r
if lfNoDeepCopy in d.flags: genAssignment(p, d, a, {})
else: genAssignment(p, d, a, {needToCopy})
else:
# we cannot call initLoc() here as that would overwrite
# the flags field!
d.k = locExpr
d.t = getUniqueType(t)
d.r = r
d.a = -1
proc binaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
if d.k != locNone: InternalError(e.info, "binaryStmt")
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
appcg(p, cpsStmts, frmt, [rdLoc(a), rdLoc(b)])
proc unaryStmt(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
if (d.k != locNone): InternalError(e.info, "unaryStmt")
InitLocExpr(p, e.sons[1], a)
appcg(p, cpsStmts, frmt, [rdLoc(a)])
proc binaryStmtChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
if (d.k != locNone): InternalError(e.info, "binaryStmtChar")
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
appcg(p, cpsStmts, frmt, [rdCharLoc(a), rdCharLoc(b)])
proc binaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a), rdLoc(b)]))
proc binaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a), rdCharLoc(b)]))
proc unaryExpr(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
InitLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdLoc(a)]))
proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a: TLoc
InitLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)]))
proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const
prc: array[mAddi..mModi64, string] = ["addInt", "subInt", "mulInt",
"divInt", "modInt", "addInt64", "subInt64", "mulInt64", "divInt64",
"modInt64"]
opr: array[mAddi..mModi64, string] = ["+", "-", "*", "/", "%", "+", "-",
"*", "/", "%"]
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
var t = skipTypes(e.typ, abstractRange)
if optOverflowCheck notin p.options:
putIntoDest(p, d, e.typ, ropef("(NI$4)($2 $1 $3)", [toRope(opr[m]),
rdLoc(a), rdLoc(b), toRope(getSize(t) * 8)]))
else:
var storage: PRope
var size = getSize(t)
if size < platform.IntSize:
storage = toRope("NI")
else:
storage = getTypeDesc(p.module, t)
var tmp = getTempName()
appcg(p, cpsLocals, "$1 $2;$n", [storage, tmp])
appcg(p, cpsStmts, "$1 = #$2($3, $4);$n", [tmp, toRope(prc[m]),
rdLoc(a), rdLoc(b)])
if size < platform.IntSize or t.kind in {tyRange, tyEnum, tySet}:
appcg(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
[tmp, intLiteral(firstOrd(t)), intLiteral(lastOrd(t))])
putIntoDest(p, d, e.typ, ropef("(NI$1)($2)", [toRope(getSize(t)*8), tmp]))
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const
opr: array[mUnaryMinusI..mAbsI64, string] = [
mUnaryMinusI: "((NI$2)-($1))",
mUnaryMinusI64: "-($1)",
mAbsI: "(NI$2)abs($1)",
mAbsI64: "($1 > 0? ($1) : -($1))"]
var
a: TLoc
t: PType
assert(e.sons[1].typ != nil)
InitLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange)
if optOverflowCheck in p.options:
appcg(p, cpsStmts, "if ($1 == $2) #raiseOverflow();$n",
[rdLoc(a), intLiteral(firstOrd(t))])
putIntoDest(p, d, e.typ, ropef(opr[m], [rdLoc(a), toRope(getSize(t) * 8)]))
proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const
binArithTab: array[mAddF64..mXor, string] = [
"($1 + $2)", # AddF64
"($1 - $2)", # SubF64
"($1 * $2)", # MulF64
"($1 / $2)", # DivF64
"(NI$3)((NU$3)($1) >> (NU$3)($2))", # ShrI
"(NI$3)((NU$3)($1) << (NU$3)($2))", # ShlI
"(NI$3)($1 & $2)", # BitandI
"(NI$3)($1 | $2)", # BitorI
"(NI$3)($1 ^ $2)", # BitxorI
"(($1 <= $2) ? $1 : $2)", # MinI
"(($1 >= $2) ? $1 : $2)", # MaxI
"(NI64)((NU64)($1) >> (NU64)($2))", # ShrI64
"(NI64)((NU64)($1) << (NU64)($2))", # ShlI64
"($1 & $2)", # BitandI64
"($1 | $2)", # BitorI64
"($1 ^ $2)", # BitxorI64
"(($1 <= $2) ? $1 : $2)", # MinI64
"(($1 >= $2) ? $1 : $2)", # MaxI64
"(($1 <= $2) ? $1 : $2)", # MinF64
"(($1 >= $2) ? $1 : $2)", # MaxF64
"(NI$3)((NU$3)($1) + (NU$3)($2))", # AddU
"(NI$3)((NU$3)($1) - (NU$3)($2))", # SubU
"(NI$3)((NU$3)($1) * (NU$3)($2))", # MulU
"(NI$3)((NU$3)($1) / (NU$3)($2))", # DivU
"(NI$3)((NU$3)($1) % (NU$3)($2))", # ModU
"(NI64)((NU64)($1) + (NU64)($2))", # AddU64
"(NI64)((NU64)($1) - (NU64)($2))", # SubU64
"(NI64)((NU64)($1) * (NU64)($2))", # MulU64
"(NI64)((NU64)($1) / (NU64)($2))", # DivU64
"(NI64)((NU64)($1) % (NU64)($2))", # ModU64
"($1 == $2)", # EqI
"($1 <= $2)", # LeI
"($1 < $2)", # LtI
"($1 == $2)", # EqI64
"($1 <= $2)", # LeI64
"($1 < $2)", # LtI64
"($1 == $2)", # EqF64
"($1 <= $2)", # LeF64
"($1 < $2)", # LtF64
"((NU$3)($1) <= (NU$3)($2))", # LeU
"((NU$3)($1) < (NU$3)($2))", # LtU
"((NU64)($1) <= (NU64)($2))", # LeU64
"((NU64)($1) < (NU64)($2))", # LtU64
"($1 == $2)", # EqEnum
"($1 <= $2)", # LeEnum
"($1 < $2)", # LtEnum
"((NU8)($1) == (NU8)($2))", # EqCh
"((NU8)($1) <= (NU8)($2))", # LeCh
"((NU8)($1) < (NU8)($2))", # LtCh
"($1 == $2)", # EqB
"($1 <= $2)", # LeB
"($1 < $2)", # LtB
"($1 == $2)", # EqRef
"($1 == $2)", # EqProc
"($1 == $2)", # EqPtr
"($1 <= $2)", # LePtr
"($1 < $2)", # LtPtr
"($1 == $2)", # EqCString
"($1 != $2)"] # Xor
var
a, b: TLoc
s: biggestInt
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
# BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8
putIntoDest(p, d, e.typ,
ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s)]))
proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const
unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
"$1", # UnaryPlusI
"(NI$2)((NU$2) ~($1))", # BitnotI
"$1", # UnaryPlusI64
"~($1)", # BitnotI64
"$1", # UnaryPlusF64
"-($1)", # UnaryMinusF64
"($1 > 0? ($1) : -($1))", # AbsF64; BUGFIX: fabs() makes problems
# for Tiny C, so we don't use it
"((NI)(NU)(NU8)($1))", # mZe8ToI
"((NI64)(NU64)(NU8)($1))", # mZe8ToI64
"((NI)(NU)(NU16)($1))", # mZe16ToI
"((NI64)(NU64)(NU16)($1))", # mZe16ToI64
"((NI64)(NU64)(NU32)($1))", # mZe32ToI64
"((NI64)(NU64)(NU)($1))", # mZeIToI64
"((NI8)(NU8)(NU)($1))", # ToU8
"((NI16)(NU16)(NU)($1))", # ToU16
"((NI32)(NU32)(NU64)($1))", # ToU32
"((double) ($1))", # ToFloat
"((double) ($1))", # ToBiggestFloat
"float64ToInt32($1)", # ToInt XXX: this is not correct!
"float64ToInt64($1)"] # ToBiggestInt
var
a: TLoc
t: PType
assert(e.sons[1].typ != nil)
InitLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange)
putIntoDest(p, d, e.typ,
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8)]))
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
if mapType(e.sons[0].typ) == ctArray:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
expr(p, e.sons[0], d)
else:
initLocExpr(p, e.sons[0], a)
case skipTypes(a.t, abstractInst).kind
of tyRef:
d.s = OnHeap
of tyVar:
d.s = OnUnknown
of tyPtr:
d.s = OnUnknown # BUGFIX!
else: InternalError(e.info, "genDeref " & $a.t.kind)
putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
proc genAddr(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
if mapType(e.sons[0].typ) == ctArray:
expr(p, e.sons[0], d)
else:
InitLocExpr(p, e.sons[0], a)
putIntoDest(p, d, e.typ, addrLoc(a))
proc genRecordFieldAux(p: BProc, e: PNode, d, a: var TLoc): PType =
initLocExpr(p, e.sons[0], a)
if (e.sons[1].kind != nkSym): InternalError(e.info, "genRecordFieldAux")
if d.k == locNone: d.s = a.s
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
result = getUniqueType(a.t)
proc genRecordField(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
var ty = genRecordFieldAux(p, e, d, a)
var r = rdLoc(a)
var f = e.sons[1].sym
if ty.n == nil:
# we found a unique tuple type which lacks field information
# so we use Field$i
appf(r, ".Field$1", [toRope(f.position)])
putIntoDest(p, d, f.typ, r)
else:
var field: PSym = nil
while ty != nil:
if not (ty.kind in {tyTuple, tyObject}):
InternalError(e.info, "genRecordField")
field = lookupInRecord(ty.n, f.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup")
ty = GetUniqueType(ty.sons[0])
if field == nil: InternalError(e.info, "genRecordField")
if field.loc.r == nil: InternalError(e.info, "genRecordField")
appf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r)
proc genTupleElem(p: BProc, e: PNode, d: var TLoc) =
var
a: TLoc
i: int
initLocExpr(p, e.sons[0], a)
if d.k == locNone: d.s = a.s
discard getTypeDesc(p.module, a.t) # fill the record's fields.loc
var ty = getUniqueType(a.t)
var r = rdLoc(a)
case e.sons[1].kind
of nkIntLit..nkInt64Lit: i = int(e.sons[1].intVal)
else: internalError(e.info, "genTupleElem")
if ty.n != nil:
var field = ty.n.sons[i].sym
if field == nil: InternalError(e.info, "genTupleElem")
if field.loc.r == nil: InternalError(e.info, "genTupleElem")
appf(r, ".$1", [field.loc.r])
else:
appf(r, ".Field$1", [toRope(i)])
putIntoDest(p, d, ty.sons[i], r)
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc)
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
var
a, u, v, test: TLoc
f, field, op: PSym
ty: PType
r, strLit: PRope
id: int
it: PNode
if optFieldCheck in p.options:
ty = genRecordFieldAux(p, e.sons[0], d, a)
r = rdLoc(a)
f = e.sons[0].sons[1].sym
field = nil
while ty != nil:
assert(ty.kind in {tyTuple, tyObject})
field = lookupInRecord(ty.n, f.name)
if field != nil: break
if gCmd != cmdCompileToCpp: app(r, ".Sup")
ty = getUniqueType(ty.sons[0])
if field == nil: InternalError(e.info, "genCheckedRecordField")
if field.loc.r == nil:
InternalError(e.info, "genCheckedRecordField") # generate the checks:
for i in countup(1, sonsLen(e) - 1):
it = e.sons[i]
assert(it.kind == nkCall)
assert(it.sons[0].kind == nkSym)
op = it.sons[0].sym
if op.magic == mNot: it = it.sons[1]
assert(it.sons[2].kind == nkSym)
initLoc(test, locNone, it.typ, OnStack)
InitLocExpr(p, it.sons[1], u)
initLoc(v, locExpr, it.sons[2].typ, OnUnknown)
v.r = ropef("$1.$2", [r, it.sons[2].sym.loc.r])
genInExprAux(p, it, u, v, test)
id = NodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gid)
if id == gid: strLit = getStrLit(p.module, field.name.s)
else: strLit = con("TMP", toRope(id))
if op.magic == mNot:
appcg(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
[rdLoc(test), strLit])
else:
appcg(p, cpsStmts,
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
[rdLoc(test), strLit])
appf(r, ".$1", [field.loc.r])
putIntoDest(p, d, field.typ, r)
else:
genRecordField(p, e.sons[0], d)
proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b)
var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
var first = intLiteral(firstOrd(ty))
# emit range check:
if (optBoundsCheck in p.options):
if not isConstExpr(e.sons[1]):
# semantic pass has already checked for const index expressions
if firstOrd(ty) == 0:
if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
appcg(p, cpsStmts, "if ((NU)($1) > (NU)($2)) #raiseIndexError();$n",
[rdCharLoc(b), intLiteral(lastOrd(ty))])
else:
appcg(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
[rdCharLoc(b), first, intLiteral(lastOrd(ty))])
if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
ropef("$1[($2)-$3]", [rdLoc(a), rdCharLoc(b), first]))
proc genCStringElem(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b)
var ty = skipTypes(a.t, abstractVarRange)
if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
ropef("$1[$2]", [rdLoc(a), rdCharLoc(b)]))
proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b) # emit range check:
if optBoundsCheck in p.options:
appcg(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a)]) # BUGFIX: ``>=`` and not ``>``!
if d.k == locNone: d.s = a.s
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
ropef("$1[$2]", [rdLoc(a), rdCharLoc(b)]))
proc genSeqElem(p: BPRoc, e: PNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, e.sons[0], a)
initLocExpr(p, e.sons[1], b)
var ty = skipTypes(a.t, abstractVarRange)
if ty.kind in {tyRef, tyPtr}:
ty = skipTypes(ty.sons[0], abstractVarRange) # emit range check:
if (optBoundsCheck in p.options):
if ty.kind == tyString:
appcg(p, cpsStmts,
"if ((NU)($1) > (NU)($2->$3)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a), lenField()])
else:
appcg(p, cpsStmts,
"if ((NU)($1) >= (NU)($2->$3)) #raiseIndexError();$n",
[rdLoc(b), rdLoc(a), lenField()])
if d.k == locNone: d.s = OnHeap
if skipTypes(a.t, abstractVar).kind in {tyRef, tyPtr}:
a.r = ropef("(*$1)", [a.r])
putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
ropef("$1->data[$2]", [rdLoc(a), rdCharLoc(b)]))
proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
# how to generate code?
# 'expr1 and expr2' becomes:
# result = expr1
# fjmp result, end
# result = expr2
# end:
# ... (result computed)
# BUGFIX:
# a = b or a
# used to generate:
# a = b
# if a: goto end
# a = a
# end:
# now it generates:
# tmp = b
# if tmp: goto end
# tmp = a
# end:
# a = tmp
var
L: TLabel
tmp: TLoc
getTemp(p, e.typ, tmp) # force it into a temp!
expr(p, e.sons[1], tmp)
L = getLabel(p)
if m == mOr:
appf(p.s[cpsStmts], "if ($1) goto $2;$n", [rdLoc(tmp), L])
else:
appf(p.s[cpsStmts], "if (!($1)) goto $2;$n", [rdLoc(tmp), L])
expr(p, e.sons[2], tmp)
fixLabel(p, L)
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {}) # no need for deep copying
proc genIfExpr(p: BProc, n: PNode, d: var TLoc) =
#
# if (!expr1) goto L1;
# thenPart
# goto LEnd
# L1:
# if (!expr2) goto L2;
# thenPart2
# goto LEnd
# L2:
# elsePart
# Lend:
#
var
it: PNode
a, tmp: TLoc
Lend, Lelse: TLabel
getTemp(p, n.typ, tmp) # force it into a temp!
Lend = getLabel(p)
for i in countup(0, sonsLen(n) - 1):
it = n.sons[i]
case it.kind
of nkElifExpr:
initLocExpr(p, it.sons[0], a)
Lelse = getLabel(p)
appf(p.s[cpsStmts], "if (!$1) goto $2;$n", [rdLoc(a), Lelse])
expr(p, it.sons[1], tmp)
appf(p.s[cpsStmts], "goto $1;$n", [Lend])
fixLabel(p, Lelse)
of nkElseExpr:
expr(p, it.sons[0], tmp)
else: internalError(n.info, "genIfExpr()")
fixLabel(p, Lend)
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {}) # no need for deep copying
proc genEcho(p: BProc, n: PNode) =
# this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
# is threadsafe.
var args: PRope = nil
var a: TLoc
for i in countup(1, n.len-1):
initLocExpr(p, n.sons[i], a)
appf(args, ", ($1)->data", [rdLoc(a)])
appcg(p, cpsStmts, "printf($1$2);$n", [
makeCString(repeatStr(n.len-1, "%s") & tnl), args])
proc fixupCall(p: BProc, t: PNode, d: var TLoc, pl: PRope) =
var pl = pl
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(t) > 1: app(pl, ", ")
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ.sons[0], d)
app(pl, addrLoc(d))
app(pl, ")")
app(p.s[cpsStmts], pl)
appf(p.s[cpsStmts], ";$n")
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp))
app(pl, ")")
app(p.s[cpsStmts], pl)
appf(p.s[cpsStmts], ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
app(pl, ")")
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, nil, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
app(pl, ")")
app(p.s[cpsStmts], pl)
appf(p.s[cpsStmts], ";$n")
proc openArrayLoc(a: TLoc): PRope =
case skipTypes(a.t, abstractVar).kind
of tyOpenArray:
result = ropef("$1, $1Len0", [rdLoc(a)])
of tyString, tySequence:
result = ropef("$1->data, $1->$2", [rdLoc(a), lenField()])
of tyArray, tyArrayConstr:
result = ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))])
else: InternalError("openArrayLoc: " & typeToString(a.t))
proc genArg(p: BProc, n: PNode, param: PSym): PRope =
var a: TLoc
if skipTypes(param.typ, abstractVar).kind == tyOpenArray:
var n = if n.kind != nkHiddenAddr: n else: n.sons[0]
initLocExpr(p, n, a)
result = openArrayLoc(a)
elif ccgIntroducedPtr(param):
initLocExpr(p, n, a)
result = addrLoc(a)
else:
initLocExpr(p, n, a)
result = rdLoc(a)
proc genCall(p: BProc, t: PNode, d: var TLoc) =
var op, a: TLoc
# this is a hotspot in the compiler
initLocExpr(p, t.sons[0], op)
var pl = con(op.r, "(")
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
assert(typ.kind == tyProc)
var length = sonsLen(t)
for i in countup(1, length - 1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym)
app(pl, genArg(p, t.sons[i], typ.n.sons[i].sym))
else:
initLocExpr(p, t.sons[i], a) # generate expression for param
app(pl, rdLoc(a))
if i < length - 1: app(pl, ", ")
fixupCall(p, t, d, pl)
proc genInfixCall(p: BProc, t: PNode, d: var TLoc) =
var op, a: TLoc
initLocExpr(p, t.sons[0], op)
var pl: PRope = nil
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
assert(typ.kind == tyProc)
var length = sonsLen(t)
assert(sonsLen(typ) == sonsLen(typ.n))
var param = typ.n.sons[1].sym
app(pl, genArg(p, t.sons[1], param))
if skipTypes(param.typ, {tyGenericInst}).kind == tyPtr: app(pl, "->")
else: app(pl, ".")
app(pl, op.r)
app(pl, "(")
for i in countup(2, length - 1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i < sonsLen(typ):
assert(typ.n.sons[i].kind == nkSym)
app(pl, genArg(p, t.sons[i], typ.n.sons[i].sym))
else:
initLocExpr(p, t.sons[i], a) # generate expression for param
app(pl, rdLoc(a))
if i < length - 1: app(pl, ", ")
fixupCall(p, t, d, pl)
proc genNamedParamCall(p: BProc, t: PNode, d: var TLoc) =
# generates a crappy ObjC call
var op, a: TLoc
initLocExpr(p, t.sons[0], op)
var pl = toRope"["
var typ = t.sons[0].typ # getUniqueType() is too expensive here!
assert(typ.kind == tyProc)
var length = sonsLen(t)
assert(sonsLen(typ) == sonsLen(typ.n))
if length > 1:
app(pl, genArg(p, t.sons[1], typ.n.sons[1].sym))
app(pl, " ")
app(pl, op.r)
if length > 2:
app(pl, ": ")
app(pl, genArg(p, t.sons[2], typ.n.sons[2].sym))
for i in countup(3, length-1):
assert(sonsLen(typ) == sonsLen(typ.n))
if i >= sonsLen(typ):
InternalError(t.info, "varargs for objective C method?")
assert(typ.n.sons[i].kind == nkSym)
var param = typ.n.sons[i].sym
app(pl, " ")
app(pl, param.name.s)
app(pl, ": ")
app(pl, genArg(p, t.sons[i], param))
if typ.sons[0] != nil:
if isInvalidReturnType(typ.sons[0]):
if sonsLen(t) > 1: app(pl, " ")
# beware of 'result = p(result)'. We always allocate a temporary:
if d.k in {locTemp, locNone}:
# We already got a temp. Great, special case it:
if d.k == locNone: getTemp(p, typ.sons[0], d)
app(pl, "Result: ")
app(pl, addrLoc(d))
app(pl, "]")
app(p.s[cpsStmts], pl)
appf(p.s[cpsStmts], ";$n")
else:
var tmp: TLoc
getTemp(p, typ.sons[0], tmp)
app(pl, addrLoc(tmp))
app(pl, "]")
app(p.s[cpsStmts], pl)
appf(p.s[cpsStmts], ";$n")
genAssignment(p, d, tmp, {}) # no need for deep copying
else:
app(pl, "]")
if d.k == locNone: getTemp(p, typ.sons[0], d)
assert(d.t != nil) # generate an assignment to d:
var list: TLoc
initLoc(list, locCall, nil, OnUnknown)
list.r = pl
genAssignment(p, d, list, {}) # no need for deep copying
else:
app(pl, "]")
app(p.s[cpsStmts], pl)
appf(p.s[cpsStmts], ";$n")
proc genStrConcat(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code>
# s = 'Hello ' & name & ', how do you feel?' & 'z'
#
# <generated C code>
# {
# string tmp0;
# ...
# tmp0 = rawNewString(6 + 17 + 1 + s2->len);
# // we cannot generate s = rawNewString(...) here, because
# // ``s`` may be used on the right side of the expression
# appendString(tmp0, strlit_1);
# appendString(tmp0, name);
# appendString(tmp0, strlit_2);
# appendChar(tmp0, 'z');
# asgn(s, tmp0);
# }
var a, tmp: TLoc
getTemp(p, e.typ, tmp)
var L = 0
var appends: PRope = nil
var lens: PRope = nil
for i in countup(0, sonsLen(e) - 2):
# compute the length expression:
initLocExpr(p, e.sons[i + 1], a)
if skipTypes(e.sons[i + 1].Typ, abstractVarRange).kind == tyChar:
Inc(L)
appcg(p.module, appends, "#appendChar($1, $2);$n", [tmp.r, rdLoc(a)])
else:
if e.sons[i + 1].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 1].strVal))
else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appcg(p.module, appends, "#appendString($1, $2);$n", [tmp.r, rdLoc(a)])
appcg(p, cpsStmts, "$1 = #rawNewString($2$3);$n", [tmp.r, lens, toRope(L)])
app(p.s[cpsStmts], appends)
if d.k == locNone:
d = tmp
else:
genAssignment(p, d, tmp, {}) # no need for deep copying
proc genStrAppend(p: BProc, e: PNode, d: var TLoc) =
# <Nimrod code>
# s &= 'Hello ' & name & ', how do you feel?' & 'z'
# // BUG: what if s is on the left side too?
# <generated C code>
# {
# s = resizeString(s, 6 + 17 + 1 + name->len);
# appendString(s, strlit_1);
# appendString(s, name);
# appendString(s, strlit_2);
# appendChar(s, 'z');
# }
var
a, dest: TLoc
L: int
appends, lens: PRope
assert(d.k == locNone)
L = 0
appends = nil
lens = nil
initLocExpr(p, e.sons[1], dest)
for i in countup(0, sonsLen(e) - 3):
# compute the length expression:
initLocExpr(p, e.sons[i + 2], a)
if skipTypes(e.sons[i + 2].Typ, abstractVarRange).kind == tyChar:
Inc(L)
appcg(p.module, appends, "#appendChar($1, $2);$n",
[rdLoc(dest), rdLoc(a)])
else:
if e.sons[i + 2].kind in {nkStrLit..nkTripleStrLit}:
Inc(L, len(e.sons[i + 2].strVal))
else:
appf(lens, "$1->$2 + ", [rdLoc(a), lenField()])
appcg(p.module, appends, "#appendString($1, $2);$n",
[rdLoc(dest), rdLoc(a)])
appcg(p, cpsStmts, "$1 = #resizeString($1, $2$3);$n",
[rdLoc(dest), lens, toRope(L)])
app(p.s[cpsStmts], appends)
proc genSeqElemAppend(p: BProc, e: PNode, d: var TLoc) =
# seq &= x -->
# seq = (typeof seq) incrSeq(&seq->Sup, sizeof(x));
# seq->data[seq->len-1] = x;
var a, b, dest: TLoc
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
appcg(p, cpsStmts, "$1 = ($2) #incrSeq(&($1)->Sup, sizeof($3));$n", [
rdLoc(a),
getTypeDesc(p.module, skipTypes(e.sons[1].typ, abstractVar)),
getTypeDesc(p.module, skipTypes(e.sons[2].Typ, abstractVar))])
initLoc(dest, locExpr, b.t, OnHeap)
dest.r = ropef("$1->data[$1->$2-1]", [rdLoc(a), lenField()])
genAssignment(p, dest, b, {needToCopy, afDestIsNil})
proc genReset(p: BProc, n: PNode) =
var a: TLoc
InitLocExpr(p, n.sons[1], a)
appcg(p, cpsStmts, "#genericReset((void*)$1, $2);$n",
[addrLoc(a), genTypeInfo(p.module, skipTypes(a.t, abstractVarRange))])
proc genNew(p: BProc, e: PNode) =
var
a, b: TLoc
reftype, bt: PType
refType = skipTypes(e.sons[1].typ, abstractVarRange)
InitLocExpr(p, e.sons[1], a)
initLoc(b, locExpr, a.t, OnHeap)
b.r = ropecg(p.module,
"($1) #newObj($2, sizeof($3))", [getTypeDesc(p.module, reftype),
genTypeInfo(p.module, refType),
getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))])
genAssignment(p, a, b, {}) # set the object type:
bt = skipTypes(refType.sons[0], abstractRange)
genObjectInit(p, cpsStmts, bt, a, false)
proc genNewSeq(p: BProc, e: PNode) =
var
a, b, c: TLoc
var seqType = skipTypes(e.sons[1].typ, abstractVarRange)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
initLoc(c, locExpr, a.t, OnHeap)
c.r = ropecg(p.module, "($1) #newSeq($2, $3)", [
getTypeDesc(p.module, seqtype),
genTypeInfo(p.module, seqType), rdLoc(b)])
genAssignment(p, a, c, {})
proc genOf(p: BProc, x: PNode, typ: PType, d: var TLoc) =
var a: TLoc
initLocExpr(p, x, a)
var dest = skipTypes(typ, abstractPtrs)
var r = rdLoc(a)
var nilCheck: PRope = nil
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r
r = ropef("(*$1)", [r])
t = skipTypes(t.sons[0], abstractInst)
if gCmd != cmdCompileToCpp:
while (t.kind == tyObject) and (t.sons[0] != nil):
app(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst)
if nilCheck != nil:
r = ropecg(p.module, "(($1) && #isObj($2.m_type, $3))",
[nilCheck, r, genTypeInfo(p.module, dest)])
else:
r = ropecg(p.module, "#isObj($1.m_type, $2)",
[r, genTypeInfo(p.module, dest)])
putIntoDest(p, d, getSysType(tyBool), r)
proc genOf(p: BProc, n: PNode, d: var TLoc) =
genOf(p, n.sons[1], n.sons[2].typ, d)
proc genNewFinalize(p: BProc, e: PNode) =
var
a, b, f: TLoc
refType, bt: PType
ti: PRope
oldModule: BModule
refType = skipTypes(e.sons[1].typ, abstractVarRange)
InitLocExpr(p, e.sons[1], a)
# This is a little hack:
# XXX this is also a bug, if the finalizer expression produces side-effects
oldModule = p.module
p.module = gNimDat
InitLocExpr(p, e.sons[2], f)
p.module = oldModule
initLoc(b, locExpr, a.t, OnHeap)
ti = genTypeInfo(p.module, refType)
appf(gNimDat.s[cfsTypeInit3], "$1->finalizer = (void*)$2;$n", [ti, rdLoc(f)])
b.r = ropecg(p.module, "($1) #newObj($2, sizeof($3))", [
getTypeDesc(p.module, refType),
ti, getTypeDesc(p.module, skipTypes(reftype.sons[0], abstractRange))])
genAssignment(p, a, b, {}) # set the object type:
bt = skipTypes(refType.sons[0], abstractRange)
genObjectInit(p, cpsStmts, bt, a, false)
proc genRepr(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc
InitLocExpr(p, e.sons[1], a)
var t = skipTypes(e.sons[1].typ, abstractVarRange)
case t.kind
of tyInt..tyInt64:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprInt($1)", [rdLoc(a)]))
of tyFloat..tyFloat128:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
of tyBool:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprBool($1)", [rdLoc(a)]))
of tyChar:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprChar($1)", [rdLoc(a)]))
of tyEnum, tyOrdinal:
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprEnum($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]))
of tyString:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprStr($1)", [rdLoc(a)]))
of tySet:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprSet($1, $2)", [
addrLoc(a), genTypeInfo(p.module, t)]))
of tyOpenArray:
var b: TLoc
case a.t.kind
of tyOpenArray:
putIntoDest(p, b, e.typ, ropef("$1, $1Len0", [rdLoc(a)]))
of tyString, tySequence:
putIntoDest(p, b, e.typ,
ropef("$1->data, $1->$2", [rdLoc(a), lenField()]))
of tyArray, tyArrayConstr:
putIntoDest(p, b, e.typ,
ropef("$1, $2", [rdLoc(a), toRope(lengthOrd(a.t))]))
else: InternalError(e.sons[0].info, "genRepr()")
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprOpenArray($1, $2)", [rdLoc(b),
genTypeInfo(p.module, elemType(t))]))
of tyCString, tyArray, tyArrayConstr, tyRef, tyPtr, tyPointer, tyNil,
tySequence:
putIntoDest(p, d, e.typ,
ropecg(p.module, "#reprAny($1, $2)", [
rdLoc(a), genTypeInfo(p.module, t)]))
else:
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprAny($1, $2)",
[addrLoc(a), genTypeInfo(p.module, t)]))
proc genGetTypeInfo(p: BProc, e: PNode, d: var TLoc) =
var t = skipTypes(e.sons[1].typ, abstractVarRange)
putIntoDest(p, d, e.typ, genTypeInfo(p.module, t))
proc genDollar(p: BProc, n: PNode, d: var TLoc, frmt: string) =
var a: TLoc
InitLocExpr(p, n.sons[1], a)
a.r = ropecg(p.module, frmt, [rdLoc(a)])
if d.k == locNone: getTemp(p, n.typ, d)
genAssignment(p, d, a, {})
proc genArrayLen(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var a = e.sons[1]
if a.kind == nkHiddenAddr: a = a.sons[0]
var typ = skipTypes(a.Typ, abstractVar)
case typ.kind
of tyOpenArray:
if op == mHigh: unaryExpr(p, e, d, "($1Len0-1)")
else: unaryExpr(p, e, d, "$1Len0")
of tyCstring:
if op == mHigh: unaryExpr(p, e, d, "(strlen($1)-1)")
else: unaryExpr(p, e, d, "strlen($1)")
of tyString, tySequence:
if gCmd != cmdCompileToCpp:
if op == mHigh: unaryExpr(p, e, d, "($1->Sup.len-1)")
else: unaryExpr(p, e, d, "$1->Sup.len")
else:
if op == mHigh: unaryExpr(p, e, d, "($1->len-1)")
else: unaryExpr(p, e, d, "$1->len")
of tyArray, tyArrayConstr:
# YYY: length(sideeffect) is optimized away incorrectly?
if op == mHigh: putIntoDest(p, d, e.typ, toRope(lastOrd(Typ)))
else: putIntoDest(p, d, e.typ, toRope(lengthOrd(typ)))
else: InternalError(e.info, "genArrayLen()")
proc genSetLengthSeq(p: BProc, e: PNode, d: var TLoc) =
var a, b: TLoc
assert(d.k == locNone)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
var t = skipTypes(e.sons[1].typ, abstractVar)
appcg(p, cpsStmts, "$1 = ($3) #setLengthSeq(&($1)->Sup, sizeof($4), $2);$n", [
rdLoc(a), rdLoc(b), getTypeDesc(p.module, t),
getTypeDesc(p.module, t.sons[0])])
proc genSetLengthStr(p: BProc, e: PNode, d: var TLoc) =
binaryStmt(p, e, d, "$1 = #setLengthStr($1, $2);$n")
proc genSwap(p: BProc, e: PNode, d: var TLoc) =
# swap(a, b) -->
# temp = a
# a = b
# b = temp
var a, b, tmp: TLoc
getTemp(p, skipTypes(e.sons[1].typ, abstractVar), tmp)
InitLocExpr(p, e.sons[1], a) # eval a
InitLocExpr(p, e.sons[2], b) # eval b
genAssignment(p, tmp, a, {})
genAssignment(p, a, b, {})
genAssignment(p, b, tmp, {})
proc rdSetElemLoc(a: TLoc, setType: PType): PRope =
# read a location of an set element; it may need a substraction operation
# before the set operation
result = rdCharLoc(a)
assert(setType.kind == tySet)
if firstOrd(setType) != 0:
result = ropef("($1- $2)", [result, toRope(firstOrd(setType))])
proc fewCmps(s: PNode): bool =
# this function estimates whether it is better to emit code
# for constructing the set or generating a bunch of comparisons directly
if s.kind != nkCurly: InternalError(s.info, "fewCmps")
if (getSize(s.typ) <= platform.intSize) and (nfAllConst in s.flags):
result = false # it is better to emit the set generation code
elif elemType(s.typ).Kind in {tyInt, tyInt16..tyInt64}:
result = true # better not emit the set if int is basetype!
else:
result = sonsLen(s) <= 8 # 8 seems to be a good value
proc binaryExprIn(p: BProc, e: PNode, a, b, d: var TLoc, frmt: string) =
putIntoDest(p, d, e.typ, ropef(frmt, [rdLoc(a), rdSetElemLoc(b, a.t)]))
proc genInExprAux(p: BProc, e: PNode, a, b, d: var TLoc) =
case int(getSize(skipTypes(e.sons[1].typ, abstractVar)))
of 1: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&7)))!=0)")
of 2: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&15)))!=0)")
of 4: binaryExprIn(p, e, a, b, d, "(($1 &(1<<(($2)&31)))!=0)")
of 8: binaryExprIn(p, e, a, b, d, "(($1 &(IL64(1)<<(($2)&IL64(63))))!=0)")
else: binaryExprIn(p, e, a, b, d, "(($1[$2/8] &(1<<($2%8)))!=0)")
proc binaryStmtInExcl(p: BProc, e: PNode, d: var TLoc, frmt: string) =
var a, b: TLoc
assert(d.k == locNone)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
appf(p.s[cpsStmts], frmt, [rdLoc(a), rdSetElemLoc(b, a.t)])
proc genInOp(p: BProc, e: PNode, d: var TLoc) =
var a, b, x, y: TLoc
if (e.sons[1].Kind == nkCurly) and fewCmps(e.sons[1]):
# a set constructor but not a constant set:
# do not emit the set, but generate a bunch of comparisons
initLocExpr(p, e.sons[2], a)
initLoc(b, locExpr, e.typ, OnUnknown)
b.r = toRope("(")
var length = sonsLen(e.sons[1])
for i in countup(0, length - 1):
if e.sons[1].sons[i].Kind == nkRange:
InitLocExpr(p, e.sons[1].sons[i].sons[0], x)
InitLocExpr(p, e.sons[1].sons[i].sons[1], y)
appf(b.r, "$1 >= $2 && $1 <= $3",
[rdCharLoc(a), rdCharLoc(x), rdCharLoc(y)])
else:
InitLocExpr(p, e.sons[1].sons[i], x)
appf(b.r, "$1 == $2", [rdCharLoc(a), rdCharLoc(x)])
if i < length - 1: app(b.r, " || ")
app(b.r, ")")
putIntoDest(p, d, e.typ, b.r)
else:
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
genInExprAux(p, e, a, b, d)
proc genSetOp(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const
lookupOpr: array[mLeSet..mSymDiffSet, string] = [
"for ($1 = 0; $1 < $2; $1++) { $n" &
" $3 = (($4[$1] & ~ $5[$1]) == 0);$n" &
" if (!$3) break;}$n", "for ($1 = 0; $1 < $2; $1++) { $n" &
" $3 = (($4[$1] & ~ $5[$1]) == 0);$n" & " if (!$3) break;}$n" &
"if ($3) $3 = (memcmp($4, $5, $2) != 0);$n",
"&", "|", "& ~", "^"]
var a, b, i: TLoc
var setType = skipTypes(e.sons[1].Typ, abstractVar)
var size = int(getSize(setType))
case size
of 1, 2, 4, 8:
case op
of mIncl:
var ts = "NI" & $(size * 8)
binaryStmtInExcl(p, e, d,
"$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n")
of mExcl:
var ts = "NI" & $(size * 8)
binaryStmtInExcl(p, e, d, "$1 &= ~(1 << ((" & ts & ")($2) % (sizeof(" &
ts & ")*8)));$n")
of mCard:
if size <= 4: unaryExprChar(p, e, d, "#countBits32($1)")
else: unaryExprChar(p, e, d, "#countBits64($1)")
of mLtSet: binaryExprChar(p, e, d, "(($1 & ~ $2 ==0)&&($1 != $2))")
of mLeSet: binaryExprChar(p, e, d, "(($1 & ~ $2)==0)")
of mEqSet: binaryExpr(p, e, d, "($1 == $2)")
of mMulSet: binaryExpr(p, e, d, "($1 & $2)")
of mPlusSet: binaryExpr(p, e, d, "($1 | $2)")
of mMinusSet: binaryExpr(p, e, d, "($1 & ~ $2)")
of mSymDiffSet: binaryExpr(p, e, d, "($1 ^ $2)")
of mInSet:
genInOp(p, e, d)
else: internalError(e.info, "genSetOp()")
else:
case op
of mIncl: binaryStmtInExcl(p, e, d, "$1[$2/8] |=(1<<($2%8));$n")
of mExcl: binaryStmtInExcl(p, e, d, "$1[$2/8] &= ~(1<<($2%8));$n")
of mCard: unaryExprChar(p, e, d, "#cardSet($1, " & $size & ')')
of mLtSet, mLeSet:
getTemp(p, getSysType(tyInt), i) # our counter
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d)
appf(p.s[cpsStmts], lookupOpr[op],
[rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b)])
of mEqSet:
binaryExprChar(p, e, d, "(memcmp($1, $2, " & $(size) & ")==0)")
of mMulSet, mPlusSet, mMinusSet, mSymDiffSet:
# we inline the simple for loop for better code generation:
getTemp(p, getSysType(tyInt), i) # our counter
initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b)
if d.k == locNone: getTemp(p, a.t, d)
appf(p.s[cpsStmts],
"for ($1 = 0; $1 < $2; $1++) $n" &
" $3[$1] = $4[$1] $6 $5[$1];$n", [
rdLoc(i), toRope(size), rdLoc(d), rdLoc(a), rdLoc(b),
toRope(lookupOpr[op])])
of mInSet: genInOp(p, e, d)
else: internalError(e.info, "genSetOp")
proc genOrd(p: BProc, e: PNode, d: var TLoc) =
unaryExprChar(p, e, d, "$1")
proc genCast(p: BProc, e: PNode, d: var TLoc) =
const
ValueTypes = {tyTuple, tyObject, tyArray, tyOpenArray, tyArrayConstr}
# we use whatever C gives us. Except if we have a value-type, we need to go
# through its address:
var a: TLoc
InitLocExpr(p, e.sons[1], a)
if (skipTypes(e.typ, abstractRange).kind in ValueTypes) and
not (lfIndirect in a.flags):
putIntoDest(p, d, e.typ, ropef("(*($1*) ($2))",
[getTypeDesc(p.module, e.typ), addrLoc(a)]))
else:
putIntoDest(p, d, e.typ, ropef("(($1) ($2))",
[getTypeDesc(p.module, e.typ), rdCharLoc(a)]))
proc genRangeChck(p: BProc, n: PNode, d: var TLoc, magic: string) =
var a: TLoc
var dest = skipTypes(n.typ, abstractVar)
if optRangeCheck notin p.options:
InitLocExpr(p, n.sons[0], a)
putIntoDest(p, d, n.typ, ropef("(($1) ($2))",
[getTypeDesc(p.module, dest), rdCharLoc(a)]))
else:
InitLocExpr(p, n.sons[0], a)
putIntoDest(p, d, dest, ropecg(p.module, "(($1)#$5($2, $3, $4))", [
getTypeDesc(p.module, dest), rdCharLoc(a),
genLiteral(p, n.sons[1], dest), genLiteral(p, n.sons[2], dest),
toRope(magic)]))
proc genConv(p: BProc, e: PNode, d: var TLoc) =
genCast(p, e, d)
proc convStrToCStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, skipTypes(n.typ, abstractVar), ropef("$1->data", [rdLoc(a)]))
proc convCStrToStr(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
putIntoDest(p, d, skipTypes(n.typ, abstractVar),
ropecg(p.module, "#cstrToNimstr($1)", [rdLoc(a)]))
proc genStrEquals(p: BProc, e: PNode, d: var TLoc) =
var x: TLoc
var a = e.sons[1]
var b = e.sons[2]
if (a.kind == nkNilLit) or (b.kind == nkNilLit):
binaryExpr(p, e, d, "($1 == $2)")
elif (a.kind in {nkStrLit..nkTripleStrLit}) and (a.strVal == ""):
initLocExpr(p, e.sons[2], x)
putIntoDest(p, d, e.typ,
ropef("(($1) && ($1)->$2 == 0)", [rdLoc(x), lenField()]))
elif (b.kind in {nkStrLit..nkTripleStrLit}) and (b.strVal == ""):
initLocExpr(p, e.sons[1], x)
putIntoDest(p, d, e.typ,
ropef("(($1) && ($1)->$2 == 0)", [rdLoc(x), lenField()]))
else:
binaryExpr(p, e, d, "#eqStrings($1, $2)")
proc genSeqConstr(p: BProc, t: PNode, d: var TLoc) =
var newSeq, arr: TLoc
if d.k == locNone:
getTemp(p, t.typ, d)
# generate call to newSeq before adding the elements per hand:
initLoc(newSeq, locExpr, t.typ, OnHeap)
newSeq.r = ropecg(p.module, "($1) #newSeq($2, $3)",
[getTypeDesc(p.module, t.typ),
genTypeInfo(p.module, t.typ), intLiteral(sonsLen(t))])
genAssignment(p, d, newSeq, {afSrcIsNotNil})
for i in countup(0, sonsLen(t) - 1):
initLoc(arr, locExpr, elemType(skipTypes(t.typ, abstractInst)), OnHeap)
arr.r = ropef("$1->data[$2]", [rdLoc(d), intLiteral(i)])
arr.s = OnHeap # we know that sequences are on the heap
expr(p, t.sons[i], arr)
proc genArrToSeq(p: BProc, t: PNode, d: var TLoc) =
var newSeq, elem, a, arr: TLoc
if t.kind == nkBracket:
t.sons[1].typ = t.typ
genSeqConstr(p, t.sons[1], d)
return
if d.k == locNone:
getTemp(p, t.typ, d)
# generate call to newSeq before adding the elements per hand:
var L = int(lengthOrd(t.sons[1].typ))
initLoc(newSeq, locExpr, t.typ, OnHeap)
newSeq.r = ropecg(p.module, "($1) #newSeq($2, $3)",
[getTypeDesc(p.module, t.typ),
genTypeInfo(p.module, t.typ), intLiteral(L)])
genAssignment(p, d, newSeq, {afSrcIsNotNil})
initLocExpr(p, t.sons[1], a)
for i in countup(0, L - 1):
initLoc(elem, locExpr, elemType(skipTypes(t.typ, abstractInst)), OnHeap)
elem.r = ropef("$1->data[$2]", [rdLoc(d), intLiteral(i)])
elem.s = OnHeap # we know that sequences are on the heap
initLoc(arr, locExpr, elemType(skipTypes(t.sons[1].typ, abstractInst)), a.s)
arr.r = ropef("$1[$2]", [rdLoc(a), intLiteral(i)])
genAssignment(p, elem, arr, {afDestIsNil, needToCopy})
proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
if {optNanCheck, optInfCheck} * p.options != {}:
const opr: array[mAddF64..mDivF64, string] = ["+", "-", "*", "/"]
var a, b: TLoc
assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil)
InitLocExpr(p, e.sons[1], a)
InitLocExpr(p, e.sons[2], b)
putIntoDest(p, d, e.typ, ropef("($2 $1 $3)", [
toRope(opr[m]), rdLoc(a), rdLoc(b)]))
if optNanCheck in p.options:
appcg(p, cpsStmts, "#nanCheck($1);$n", [rdLoc(d)])
if optInfCheck in p.options:
appcg(p, cpsStmts, "#infCheck($1);$n", [rdLoc(d)])
else:
binaryArith(p, e, d, m)
proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
var line, filen: PRope
case op
of mOr, mAnd: genAndOr(p, e, d, op)
of mNot..mToBiggestInt: unaryArith(p, e, d, op)
of mUnaryMinusI..mAbsI64: unaryArithOverflow(p, e, d, op)
of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
of mShrI..mXor: binaryArith(p, e, d, op)
of mAddi..mModi64: binaryArithOverflow(p, e, d, op)
of mRepr: genRepr(p, e, d)
of mGetTypeInfo: genGetTypeInfo(p, e, d)
of mSwap: genSwap(p, e, d)
of mUnaryLt:
if not (optOverflowCheck in p.Options): unaryExpr(p, e, d, "$1 - 1")
else: unaryExpr(p, e, d, "#subInt($1, 1)")
of mPred:
# XXX: range checking?
if not (optOverflowCheck in p.Options): binaryExpr(p, e, d, "$1 - $2")
else: binaryExpr(p, e, d, "#subInt($1, $2)")
of mSucc:
# XXX: range checking?
if not (optOverflowCheck in p.Options): binaryExpr(p, e, d, "$1 + $2")
else: binaryExpr(p, e, d, "#addInt($1, $2)")
of mInc:
if not (optOverflowCheck in p.Options):
binaryStmt(p, e, d, "$1 += $2;$n")
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n")
else:
binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n")
of ast.mDec:
if not (optOverflowCheck in p.Options):
binaryStmt(p, e, d, "$1 -= $2;$n")
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n")
else:
binaryStmt(p, e, d, "$1 = #subInt($1, $2);$n")
of mConStrStr: genStrConcat(p, e, d)
of mAppendStrCh: binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")
of mAppendStrStr: genStrAppend(p, e, d)
of mAppendSeqElem: genSeqElemAppend(p, e, d)
of mEqStr: genStrEquals(p, e, d)
of mLeStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) <= 0)")
of mLtStr: binaryExpr(p, e, d, "(#cmpStrings($1, $2) < 0)")
of mIsNil: unaryExpr(p, e, d, "$1 == 0")
of mIntToStr: genDollar(p, e, d, "#nimIntToStr($1)")
of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)")
of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)")
of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
of mFloatToStr: genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr: expr(p, e.sons[1], d)
of mEnumToStr: genRepr(p, e, d)
of mAssert:
if optAssert in p.Options:
expr(p, e.sons[1], d)
line = toRope(toLinenumber(e.info))
filen = makeCString(ToFilename(e.info))
appcg(p, cpsStmts, "#internalAssert($1, $2, $3);$n",
[filen, line, rdLoc(d)])
of mOf: genOf(p, e, d)
of mNew: genNew(p, e)
of mNewFinalize: genNewFinalize(p, e)
of mNewSeq: genNewSeq(p, e)
of mSizeOf:
putIntoDest(p, d, e.typ, ropef("((NI)sizeof($1))",
[getTypeDesc(p.module, e.sons[1].typ)]))
of mChr: genCast(p, e, d)
of mOrd: genOrd(p, e, d)
of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
genArrayLen(p, e, d, op)
of mGCref: unaryStmt(p, e, d, "#nimGCref($1);$n")
of mGCunref: unaryStmt(p, e, d, "#nimGCunref($1);$n")
of mSetLengthStr: genSetLengthStr(p, e, d)
of mSetLengthSeq: genSetLengthSeq(p, e, d)
of mIncl, mExcl, mCard, mLtSet, mLeSet, mEqSet, mMulSet, mPlusSet, mMinusSet,
mInSet:
genSetOp(p, e, d, op)
of mNewString, mNewStringOfCap, mCopyStr, mCopyStrLast, mExit:
var opr = e.sons[0].sym
if lfNoDecl notin opr.loc.flags:
discard cgsym(p.module, opr.loc.r.ropeToStr)
genCall(p, e, d)
of mReset: genReset(p, e)
of mEcho: genEcho(p, e)
of mArrToSeq: genArrToSeq(p, e, d)
of mNLen..mNError:
localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
else: internalError(e.info, "genMagicExpr: " & $op)
proc genConstExpr(p: BProc, n: PNode): PRope
proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0):
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = NodeTableTestOrSet(p.module.dataCache, n, gid)
fillLoc(d, locData, t, con("TMP", toRope(id)), OnHeap)
if id == gid:
# expression not found in the cache:
inc(gid)
appf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
result = true
else:
result = false
proc genSetConstr(p: BProc, e: PNode, d: var TLoc) =
# example: { a..b, c, d, e, f..g }
# we have to emit an expression of the form:
# memset(tmp, 0, sizeof(tmp)); inclRange(tmp, a, b); incl(tmp, c);
# incl(tmp, d); incl(tmp, e); inclRange(tmp, f, g);
var
a, b, idx: TLoc
if nfAllConst in e.flags:
putIntoDest(p, d, e.typ, genSetNode(p, e))
else:
if d.k == locNone: getTemp(p, e.typ, d)
if getSize(e.typ) > 8:
# big set:
appf(p.s[cpsStmts], "memset($1, 0, sizeof($1));$n", [rdLoc(d)])
for i in countup(0, sonsLen(e) - 1):
if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a)
initLocExpr(p, e.sons[i].sons[1], b)
appf(p.s[cpsStmts], "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2[$1/8] |=(1<<($1%8));$n", [rdLoc(idx), rdLoc(d),
rdSetElemLoc(a, e.typ), rdSetElemLoc(b, e.typ)])
else:
initLocExpr(p, e.sons[i], a)
appf(p.s[cpsStmts], "$1[$2/8] |=(1<<($2%8));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)])
else:
# small set
var ts = "NI" & $(getSize(e.typ) * 8)
appf(p.s[cpsStmts], "$1 = 0;$n", [rdLoc(d)])
for i in countup(0, sonsLen(e) - 1):
if e.sons[i].kind == nkRange:
getTemp(p, getSysType(tyInt), idx) # our counter
initLocExpr(p, e.sons[i].sons[0], a)
initLocExpr(p, e.sons[i].sons[1], b)
appf(p.s[cpsStmts], "for ($1 = $3; $1 <= $4; $1++) $n" &
"$2 |=(1<<((" & ts & ")($1)%(sizeof(" & ts & ")*8)));$n", [
rdLoc(idx), rdLoc(d), rdSetElemLoc(a, e.typ),
rdSetElemLoc(b, e.typ)])
else:
initLocExpr(p, e.sons[i], a)
appf(p.s[cpsStmts],
"$1 |=(1<<((" & ts & ")($2)%(sizeof(" & ts & ")*8)));$n",
[rdLoc(d), rdSetElemLoc(a, e.typ)])
proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) =
var rec: TLoc
if not handleConstExpr(p, n, d):
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
if d.k == locNone: getTemp(p, t, d)
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if it.kind == nkExprColonExpr:
initLoc(rec, locExpr, it.sons[1].typ, d.s)
if (t.n.sons[i].kind != nkSym): InternalError(n.info, "genTupleConstr")
rec.r = ropef("$1.$2",
[rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)])
expr(p, it.sons[1], rec)
elif t.n == nil:
initLoc(rec, locExpr, it.typ, d.s)
rec.r = ropef("$1.Field$2", [rdLoc(d), toRope(i)])
expr(p, it, rec)
else:
initLoc(rec, locExpr, it.typ, d.s)
if (t.n.sons[i].kind != nkSym):
InternalError(n.info, "genTupleConstr: 2")
rec.r = ropef("$1.$2",
[rdLoc(d), mangleRecFieldName(t.n.sons[i].sym, t)])
expr(p, it, rec)
proc genArrayConstr(p: BProc, n: PNode, d: var TLoc) =
var arr: TLoc
if not handleConstExpr(p, n, d):
if d.k == locNone: getTemp(p, n.typ, d)
for i in countup(0, sonsLen(n) - 1):
initLoc(arr, locExpr, elemType(skipTypes(n.typ, abstractInst)), d.s)
arr.r = ropef("$1[$2]", [rdLoc(d), intLiteral(i)])
expr(p, n.sons[i], arr)
proc genComplexConst(p: BProc, sym: PSym, d: var TLoc) =
genConstPrototype(p.module, sym)
assert((sym.loc.r != nil) and (sym.loc.t != nil))
putLocIntoDest(p, d, sym.loc)
proc genStmtListExpr(p: BProc, n: PNode, d: var TLoc) =
var length = sonsLen(n)
for i in countup(0, length - 2): genStmts(p, n.sons[i])
if length > 0: expr(p, n.sons[length - 1], d)
proc upConv(p: BProc, n: PNode, d: var TLoc) =
var a: TLoc
initLocExpr(p, n.sons[0], a)
var dest = skipTypes(n.typ, abstractPtrs)
if optObjCheck in p.options and not isPureObject(dest):
var r = rdLoc(a)
var nilCheck: PRope = nil
var t = skipTypes(a.t, abstractInst)
while t.kind in {tyVar, tyPtr, tyRef}:
if t.kind != tyVar: nilCheck = r
r = ropef("(*$1)", [r])
t = skipTypes(t.sons[0], abstractInst)
if gCmd != cmdCompileToCpp:
while t.kind == tyObject and t.sons[0] != nil:
app(r, ".Sup")
t = skipTypes(t.sons[0], abstractInst)
if nilCheck != nil:
appcg(p, cpsStmts, "if ($1) #chckObj($2.m_type, $3);$n",
[nilCheck, r, genTypeInfo(p.module, dest)])
else:
appcg(p, cpsStmts, "#chckObj($1.m_type, $2);$n",
[r, genTypeInfo(p.module, dest)])
if n.sons[0].typ.kind != tyObject:
putIntoDest(p, d, n.typ,
ropef("(($1) ($2))", [getTypeDesc(p.module, n.typ), rdLoc(a)]))
else:
putIntoDest(p, d, n.typ, ropef("(*($1*) ($2))",
[getTypeDesc(p.module, dest), addrLoc(a)]))
proc downConv(p: BProc, n: PNode, d: var TLoc) =
if gCmd == cmdCompileToCpp:
expr(p, n.sons[0], d) # downcast does C++ for us
else:
var dest = skipTypes(n.typ, abstractPtrs)
var src = skipTypes(n.sons[0].typ, abstractPtrs)
var a: TLoc
initLocExpr(p, n.sons[0], a)
var r = rdLoc(a)
if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
app(r, "->Sup")
for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
r = con("&", r)
else:
for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
putIntoDest(p, d, n.typ, r)
proc genBlock(p: BProc, t: PNode, d: var TLoc)
proc expr(p: BProc, e: PNode, d: var TLoc) =
case e.kind
of nkSym:
var sym = e.sym
case sym.Kind
of skMethod:
if sym.ast.sons[codePos].kind == nkEmpty:
# we cannot produce code for the dispatcher yet:
fillProcLoc(sym)
genProcPrototype(p.module, sym)
else:
genProc(p.module, sym)
putLocIntoDest(p, d, sym.loc)
of skProc, skConverter:
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(e.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of skConst:
if sfFakeConst in sym.flags:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
putLocIntoDest(p, d, sym.loc)
elif isSimpleConst(sym.typ):
putIntoDest(p, d, e.typ, genLiteral(p, sym.ast, sym.typ))
else:
genComplexConst(p, sym, d)
of skEnumField:
putIntoDest(p, d, e.typ, toRope(sym.position))
of skVar, skResult:
if sfGlobal in sym.flags: genVarPrototype(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(e.info, "expr: var not init " & sym.name.s)
if sfThreadVar in sym.flags:
AccessThreadLocalVar(p, sym)
if emulatedThreadVars():
putIntoDest(p, d, sym.loc.t, con("NimTV->", sym.loc.r))
else:
putLocIntoDest(p, d, sym.loc)
else:
putLocIntoDest(p, d, sym.loc)
of skForVar, skTemp:
if ((sym.loc.r == nil) or (sym.loc.t == nil)):
InternalError(e.info, "expr: temp not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
of skParam:
if ((sym.loc.r == nil) or (sym.loc.t == nil)):
InternalError(e.info, "expr: param not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
else: InternalError(e.info, "expr(" & $sym.kind & "); unknown symbol")
of nkStrLit..nkTripleStrLit, nkIntLit..nkInt64Lit, nkFloatLit..nkFloat64Lit,
nkNilLit, nkCharLit:
putIntoDest(p, d, e.typ, genLiteral(p, e))
of nkCall, nkHiddenCallConv, nkInfix, nkPrefix, nkPostfix, nkCommand,
nkCallStrLit:
if e.sons[0].kind == nkSym and e.sons[0].sym.magic != mNone:
genMagicExpr(p, e, d, e.sons[0].sym.magic)
elif e.sons[0].kind == nkSym and sfInfixCall in e.sons[0].sym.flags and
e.len >= 2:
genInfixCall(p, e, d)
elif e.sons[0].kind == nkSym and sfNamedParamCall in e.sons[0].sym.flags:
genNamedParamCall(p, e, d)
else:
genCall(p, e, d)
of nkCurly: genSetConstr(p, e, d)
of nkBracket:
if skipTypes(e.typ, abstractVarRange).kind == tySequence:
genSeqConstr(p, e, d)
else:
genArrayConstr(p, e, d)
of nkPar: genTupleConstr(p, e, d)
of nkCast: genCast(p, e, d)
of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, e, d)
of nkHiddenAddr, nkAddr: genAddr(p, e, d)
of nkBracketExpr:
var ty = skipTypes(e.sons[0].typ, abstractVarRange)
if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.sons[0], abstractVarRange)
case ty.kind
of tyArray, tyArrayConstr: genArrayElem(p, e, d)
of tyOpenArray: genOpenArrayElem(p, e, d)
of tySequence, tyString: genSeqElem(p, e, d)
of tyCString: genCStringElem(p, e, d)
of tyTuple: genTupleElem(p, e, d)
else: InternalError(e.info, "expr(nkBracketExpr, " & $ty.kind & ')')
of nkDerefExpr, nkHiddenDeref: genDeref(p, e, d)
of nkDotExpr: genRecordField(p, e, d)
of nkCheckedFieldExpr: genCheckedRecordField(p, e, d)
of nkBlockExpr: genBlock(p, e, d)
of nkStmtListExpr: genStmtListExpr(p, e, d)
of nkIfExpr: genIfExpr(p, e, d)
of nkObjDownConv: downConv(p, e, d)
of nkObjUpConv: upConv(p, e, d)
of nkChckRangeF: genRangeChck(p, e, d, "chckRangeF")
of nkChckRange64: genRangeChck(p, e, d, "chckRange64")
of nkChckRange: genRangeChck(p, e, d, "chckRange")
of nkStringToCString: convStrToCStr(p, e, d)
of nkCStringToString: convCStrToStr(p, e, d)
of nkLambda:
var sym = e.sons[namePos].sym
genProc(p.module, sym)
if sym.loc.r == nil or sym.loc.t == nil:
InternalError(e.info, "expr: proc not init " & sym.name.s)
putLocIntoDest(p, d, sym.loc)
else: InternalError(e.info, "expr(" & $e.kind & "); unknown node kind")
proc genNamedConstExpr(p: BProc, n: PNode): PRope =
if n.kind == nkExprColonExpr: result = genConstExpr(p, n.sons[1])
else: result = genConstExpr(p, n)
proc genConstSimpleList(p: BProc, n: PNode): PRope =
var length = sonsLen(n)
result = toRope("{")
for i in countup(0, length - 2):
appf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])])
if length > 0: app(result, genNamedConstExpr(p, n.sons[length - 1]))
appf(result, "}$n")
proc genConstExpr(p: BProc, n: PNode): PRope =
case n.Kind
of nkHiddenStdConv, nkHiddenSubConv:
result = genConstExpr(p, n.sons[1])
of nkCurly:
var cs: TBitSet
toBitSet(n, cs)
result = genRawSetData(cs, int(getSize(n.typ)))
of nkBracket, nkPar:
# XXX: tySequence!
result = genConstSimpleList(p, n)
else:
var d: TLoc
initLocExpr(p, n, d)
result = rdLoc(d)