# # # The Nimrod Compiler # (c) Copyright 2011 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # # -------------------------- 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 = toRope('{' & tnl) 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;", [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: if sfGlobal in n.sym.flags: result = OnHeap else: result = OnStack 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 not (optRefcGC in 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 then begin # UseMagic(p.module, 'nimGCref'); # appf(p.s[cpsStmts], 'nimGCref($1);$n', [rdLoc(src)]); # end # else if not (afSrcIsNil in flags) then begin # UseMagic(p.module, 'nimGCref'); # appf(p.s[cpsStmts], 'if ($1) nimGCref($1);$n', [rdLoc(src)]); # end; # if afDestIsNotNil in flags then begin # UseMagic(p.module, 'nimGCunref'); # appf(p.s[cpsStmts], 'nimGCunref($1);$n', [rdLoc(dest)]); # end # else if not (afDestIsNil in flags) then begin # UseMagic(p.module, 'nimGCunref'); # appf(p.s[cpsStmts], 'if ($1) nimGCunref($1);$n', [rdLoc(dest)]); # end; # appf(p.s[cpsStmts], '$1 = $2;$n', [rdLoc(dest), rdLoc(src)]
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
const
hasThreadSupport = false # deactivate for now: thread stack walking
# is missing!
maxThreads = 256
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
proc sync_add_and_fetch(p: var int, val: int): int {.
importc: "__sync_add_and_fetch", nodecl.}
proc sync_sub_and_fetch(p: var int, val: int): int {.
importc: "__sync_sub_and_fetch", nodecl.}
elif defined(vcc) and hasThreadSupport:
proc sync_add_and_fetch(p: var int, val: int): int {.
importc: "NimXadd", nodecl.}
else:
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
inc(p, val)
result = p
var
isMultiThreaded: bool # true when prog created at least 1 thread
proc atomicInc(memLoc: var int, x: int): int =
when hasThreadSupport:
result = sync_add_and_fetch(memLoc, x)
else:
inc(memLoc, x)
result = memLoc
proc atomicDec(memLoc: var int, x: int): int =
when hasThreadSupport:
when defined(sync_sub_and_fetch):
result = sync_sub_and_fetch(memLoc, x)
else:
result = sync_add_and_fetch(memLoc, -x)
else:
dec(memLoc, x)
result = memLoc
when defined(Windows):
type
THandle = int
TSysLock {.final, pure.} = object # CRITICAL_SECTION in WinApi
DebugInfo: pointer
LockCount: int32
RecursionCount: int32
OwningThread: int
LockSemaphore: int
Reserved: int32
proc InitLock(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "InitializeCriticalSection".}
proc Lock(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "EnterCriticalSection".}
proc Unlock(L: var TSysLock) {.stdcall,
dynlib: "kernel32", importc: "LeaveCriticalSection".}
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
lpStartAddress: pointer, lpParameter: Pointer,
dwCreationFlags: int32, lpThreadId: var int32): THandle {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
else:
type
TSysLock {.importc: "pthread_mutex_t", header: "<sys/types.h>".} = int
TSysThread {.importc: "pthread_t", header: "<sys/types.h>".} = int
proc InitLock(L: var TSysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>".}
proc Lock(L: var TSysLock) {.
importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc Unlock(L: var TSysLock) {.
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
type
TThread* {.final, pure.} = object
id: int
next: ptr TThread
TThreadFunc* = proc (closure: pointer) {.cdecl.}
proc createThread*(t: var TThread, fn: TThreadFunc) =
nil
proc destroyThread*(t: var TThread) =
nil