C code generation now deterministic; fixes #4364

This commit is contained in:
Andreas Rumpf
2016-06-22 02:50:42 +02:00
parent 6b334770b5
commit 4b0ba5e3f1
8 changed files with 50 additions and 56 deletions

View File

@@ -45,7 +45,7 @@ proc genHexLiteral(v: PNode): Rope =
proc getStrLit(m: BModule, s: string): Rope =
discard cgsym(m, "TGenericSeq")
result = "TMP" & rope(backendId())
result = getTempName(m)
addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
[result, makeCString(s), rope(len(s))])
@@ -67,11 +67,11 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
of nkNilLit:
let t = skipTypes(ty, abstractVarRange)
if t.kind == tyProc and t.callConv == ccClosure:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = "TMP" & rope(id)
if id == gBackendId:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = p.module.tmpBase & rope(id)
if id == p.module.labels:
# not found in cache:
inc(gBackendId)
inc(p.module.labels)
addf(p.module.s[cfsData],
"static NIM_CONST $1 $2 = {NIM_NIL,NIM_NIL};$n",
[getTypeDesc(p.module, t), result])
@@ -81,13 +81,14 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
if n.strVal.isNil:
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
elif skipTypes(ty, abstractVarRange).kind == tyString:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
if id == gBackendId:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
if id == p.module.labels:
# string literal not found in the cache:
result = ropecg(p.module, "((#NimStringDesc*) &$1)",
[getStrLit(p.module, n.strVal)])
else:
result = ropecg(p.module, "((#NimStringDesc*) &TMP$1)", [rope(id)])
result = ropecg(p.module, "((#NimStringDesc*) &$1$2)",
[p.module.tmpBase, rope(id)])
else:
result = makeCString(n.strVal)
of nkFloatLit..nkFloat64Lit:
@@ -134,11 +135,11 @@ proc genSetNode(p: BProc, n: PNode): Rope =
var size = int(getSize(n.typ))
toBitSet(n, cs)
if size > 8:
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
result = "TMP" & rope(id)
if id == gBackendId:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
result = p.module.tmpBase & rope(id)
if id == p.module.labels:
# not found in cache:
inc(gBackendId)
inc(p.module.labels)
addf(p.module.s[cfsData], "static NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, n.typ), result, genRawSetData(cs, size)])
else:
@@ -490,7 +491,7 @@ proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
var size = getSize(t)
let storage = if size < platform.intSize: rope("NI")
else: getTypeDesc(p.module, t)
result = getTempName()
result = getTempName(p.module)
linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
lineCg(p, cpsStmts, frmt, result, rdCharLoc(a), rdCharLoc(b))
if size < platform.intSize or t.kind in {tyRange, tyEnum}:
@@ -801,9 +802,9 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym;
v.r.add(d.loc.r)
genInExprAux(p, it, u, v, test)
let id = nodeTableTestOrSet(p.module.dataCache,
newStrNode(nkStrLit, field.name.s), gBackendId)
let strLit = if id == gBackendId: getStrLit(p.module, field.name.s)
else: "TMP" & rope(id)
newStrNode(nkStrLit, field.name.s), p.module.labels)
let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s)
else: p.module.tmpBase & rope(id)
if op.magic == mNot:
linefmt(p, cpsStmts,
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
@@ -1761,11 +1762,11 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
fillLoc(d, locData, t, "TMP" & rope(id), OnStatic)
if id == gBackendId:
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
fillLoc(d, locData, t, p.module.tmpBase & rope(id), OnStatic)
if id == p.module.labels:
# expression not found in the cache:
inc(gBackendId)
inc(p.module.labels)
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), d.r, genConstExpr(p, n)])
result = true
@@ -1952,12 +1953,12 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
var t = getUniqueType(n.typ)
discard getTypeDesc(p.module, t) # so that any fields are initialized
var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
var tmp = "TMP" & rope(id)
let id = nodeTableTestOrSet(p.module.dataCache, n, p.module.labels)
let tmp = p.module.tmpBase & rope(id)
if id == gBackendId:
if id == p.module.labels:
# expression not found in the cache:
inc(gBackendId)
inc(p.module.labels)
addf(p.module.s[cfsData], "NIM_CONST $1 $2 = $3;$n",
[getTypeDesc(p.module, t), tmp, genConstExpr(p, n)])
@@ -2179,8 +2180,7 @@ proc genConstSeq(p: BProc, n: PNode, t: PType): Rope =
data.add("}")
data.add("}")
inc(gBackendId)
result = "CNSTSEQ" & gBackendId.rope
result = getTempName(p.module)
appcg(p.module, cfsData,
"NIM_CONST struct {$n" &

View File

@@ -793,7 +793,7 @@ proc genTryCpp(p: BProc, t: PNode, d: var TLoc) =
if not isEmptyType(t.typ) and d.k == locNone:
getTemp(p, t.typ, d)
genLineDir(p, t)
let exc = getTempName()
let exc = getTempName(p.module)
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:
@@ -886,7 +886,7 @@ proc genTry(p: BProc, t: PNode, d: var TLoc) =
getTemp(p, t.typ, d)
discard lists.includeStr(p.module.headerFiles, "<setjmp.h>")
genLineDir(p, t)
var safePoint = getTempName()
var safePoint = getTempName(p.module)
if getCompilerProc("Exception") != nil:
discard cgsym(p.module, "Exception")
else:

View File

@@ -100,7 +100,7 @@ proc genTraverseProcSeq(c: var TTraversalClosure, accessor: Rope, typ: PType) =
proc genTraverseProc(m: BModule, typ: PType, reason: TTypeInfoReason): Rope =
var c: TTraversalClosure
var p = newProc(nil, m)
result = getGlobalTempName()
result = getTempName(m)
case reason
of tiNew: c.visitorFrmt = "#nimGCvisit((void*)$1, op);$n"
@@ -135,7 +135,7 @@ proc genTraverseProcForGlobal(m: BModule, s: PSym): Rope =
var c: TTraversalClosure
var p = newProc(nil, m)
var sLoc = s.loc.r
result = getGlobalTempName()
result = getTempName(m)
if sfThread in s.flags and emulatedThreadVars():
accessThreadLocalVar(p, s)

View File

@@ -202,11 +202,9 @@ proc cacheGetType(tab: TIdTable, key: PType): Rope =
# linear search is not necessary anymore:
result = Rope(idTableGet(tab, key))
proc getTempName(): Rope =
result = rfmt(nil, "TMP$1", rope(backendId()))
proc getGlobalTempName(): Rope =
result = rfmt(nil, "TMP$1", rope(backendId()))
proc getTempName(m: BModule): Rope =
result = m.tmpBase & rope(m.labels)
inc m.labels
proc ccgIntroducedPtr(s: PSym): bool =
var pt = skipTypes(s.typ, typedescInst)
@@ -724,7 +722,7 @@ type
proc getClosureType(m: BModule, t: PType, kind: TClosureTypeKind): Rope =
assert t.kind == tyProc
var check = initIntSet()
result = getTempName()
result = getTempName(m)
var rettype, desc: Rope
genProcParams(m, t, rettype, desc, check, declareEnvironment=kind != clHalf)
if not isImportedType(t):
@@ -839,7 +837,7 @@ proc genObjectFields(m: BModule, typ: PType, n: PNode, expr: Rope) =
if L == 1:
genObjectFields(m, typ, n.sons[0], expr)
elif L > 0:
var tmp = getTempName()
var tmp = getTempName(m)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(L)])
for i in countup(0, L-1):
var tmp2 = getNimNode(m)
@@ -911,7 +909,7 @@ proc genTupleInfo(m: BModule, typ: PType, name: Rope) =
var expr = getNimNode(m)
var length = sonsLen(typ)
if length > 0:
var tmp = getTempName()
var tmp = getTempName(m)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n", [tmp, rope(length)])
for i in countup(0, length - 1):
var a = typ.sons[i]
@@ -935,7 +933,7 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
# anyway. We generate a cstring array and a loop over it. Exceptional
# positions will be reset after the loop.
genTypeInfoAux(m, typ, typ, name)
var nodePtrs = getTempName()
var nodePtrs = getTempName(m)
var length = sonsLen(typ.n)
addf(m.s[cfsTypeInit1], "static TNimNode* $1[$2];$n",
[nodePtrs, rope(length)])
@@ -955,8 +953,8 @@ proc genEnumInfo(m: BModule, typ: PType, name: Rope) =
if field.position != i or tfEnumHasHoles in typ.flags:
addf(specialCases, "$1.offset = $2;$n", [elemNode, rope(field.position)])
hasHoles = true
var enumArray = getTempName()
var counter = getTempName()
var enumArray = getTempName(m)
var counter = getTempName(m)
addf(m.s[cfsTypeInit1], "NI $1;$n", [counter])
addf(m.s[cfsTypeInit1], "static char* NIM_CONST $1[$2] = {$n$3};$n",
[enumArray, rope(length), enumNames])

View File

@@ -500,7 +500,7 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
assert(lib != nil)
if not lib.generated:
lib.generated = true
var tmp = getGlobalTempName()
var tmp = getTempName(m)
assert(lib.name == nil)
lib.name = tmp # BUGFIX: cgsym has awful side-effects
addf(m.s[cfsVars], "static void* $1;$n", [tmp])
@@ -1084,6 +1084,7 @@ proc initProcOptions(m: BModule): TOptions =
proc rawNewModule(module: PSym, filename: string): BModule =
new(result)
result.tmpBase = rope("T" & $hashOwner(module) & "_")
initLinkedList(result.headerFiles)
result.declaredThings = initIntSet()
result.declaredProtos = initIntSet()
@@ -1100,8 +1101,8 @@ proc rawNewModule(module: PSym, filename: string): BModule =
initNodeTable(result.dataCache)
result.typeStack = @[]
result.forwardedProcs = @[]
result.typeNodesName = getTempName()
result.nimTypesName = getTempName()
result.typeNodesName = getTempName(result)
result.nimTypesName = getTempName(result)
# no line tracing for the init sections of the system module so that we
# don't generate a TFrame which can confuse the stack botton initialization:
if sfSystemModule in module.flags:
@@ -1126,8 +1127,8 @@ proc resetModule*(m: BModule) =
initNodeTable(m.dataCache)
m.typeStack = @[]
m.forwardedProcs = @[]
m.typeNodesName = getTempName()
m.nimTypesName = getTempName()
m.typeNodesName = getTempName(m)
m.nimTypesName = getTempName(m)
if sfSystemModule in m.module.flags:
incl m.flags, preventStackTrace
else:

View File

@@ -102,12 +102,13 @@ type
includesStringh, # C source file already includes ``<string.h>``
objHasKidsValid # whether we can rely on tfObjHasKids
TCGen = object of TPassContext # represents a C source file
module*: PSym
filename*: string
s*: TCFileSections # sections of the C file
flags*: set[Codegenflag]
module*: PSym
filename*: string
cfilename*: string # filename of the module (including path,
# without extension)
tmpBase*: Rope # base for temp identifier generation
typeCache*: TIdTable # cache the generated types
forwTypeCache*: TIdTable # cache for forward declarations of types
declaredThings*: IntSet # things we have declared in this .c file

View File

@@ -11,7 +11,7 @@
import idents, strutils, os, options
var gFrontEndId, gBackendId*: int
var gFrontEndId*: int
const
debugIds* = false
@@ -30,10 +30,6 @@ proc getID*(): int {.inline.} =
result = gFrontEndId
inc(gFrontEndId)
proc backendId*(): int {.inline.} =
result = gBackendId
inc(gBackendId)
proc setId*(id: int) {.inline.} =
gFrontEndId = max(gFrontEndId, id + 1)
@@ -49,7 +45,6 @@ proc toGid(f: string): string =
proc saveMaxIds*(project: string) =
var f = open(project.toGid, fmWrite)
f.writeLine($gFrontEndId)
f.writeLine($gBackendId)
f.close()
proc loadMaxIds*(project: string) =
@@ -61,5 +56,4 @@ proc loadMaxIds*(project: string) =
if f.readLine(line):
var backEndId = parseInt(line)
gFrontEndId = max(gFrontEndId, frontEndId)
gBackendId = max(gBackendId, backEndId)
f.close()

View File

@@ -24,7 +24,7 @@ proc verboseProcess(context: PPassContext, n: PNode): PNode =
# system.nim deactivates all hints, for verbosity:3 we want the processing
# messages nonetheless, so we activate them again unconditionally:
incl(msgs.gNotes, hintProcessing)
message(n.info, hintProcessing, $idgen.gBackendId)
message(n.info, hintProcessing, $idgen.gFrontendId)
const verbosePass* = makePass(open = verboseOpen, process = verboseProcess)