C codegen: preparations for different seq and string implementations
This commit is contained in:
parent
b25044286b
commit
d837362216
8 changed files with 116 additions and 43 deletions
|
|
@ -30,12 +30,6 @@ proc intLiteral(i: BiggestInt): Rope =
|
||||||
else:
|
else:
|
||||||
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
result = ~"(IL64(-9223372036854775807) - IL64(1))"
|
||||||
|
|
||||||
proc getStrLit(m: BModule, s: string): Rope =
|
|
||||||
discard cgsym(m, "TGenericSeq")
|
|
||||||
result = getTempName(m)
|
|
||||||
addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
|
|
||||||
[result, makeCString(s), rope(len(s))])
|
|
||||||
|
|
||||||
proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||||
if ty == nil: internalError(n.info, "genLiteral: ty is nil")
|
if ty == nil: internalError(n.info, "genLiteral: ty is nil")
|
||||||
case n.kind
|
case n.kind
|
||||||
|
|
@ -67,19 +61,9 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
|
||||||
of nkStrLit..nkTripleStrLit:
|
of nkStrLit..nkTripleStrLit:
|
||||||
case skipTypes(ty, abstractVarRange).kind
|
case skipTypes(ty, abstractVarRange).kind
|
||||||
of tyNil:
|
of tyNil:
|
||||||
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
|
result = genNilStringLiteral(p.module, n.info)
|
||||||
of tyString:
|
of tyString:
|
||||||
if n.strVal.isNil:
|
result = genStringLiteral(p.module, n)
|
||||||
result = ropecg(p.module, "((#NimStringDesc*) NIM_NIL)", [])
|
|
||||||
else:
|
|
||||||
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*) &$1$2)",
|
|
||||||
[p.module.tmpBase, rope(id)])
|
|
||||||
else:
|
else:
|
||||||
if n.strVal.isNil: result = rope("NIM_NIL")
|
if n.strVal.isNil: result = rope("NIM_NIL")
|
||||||
else: result = makeCString(n.strVal)
|
else: result = makeCString(n.strVal)
|
||||||
|
|
@ -823,16 +807,16 @@ proc genFieldCheck(p: BProc, e: PNode, obj: Rope, field: PSym) =
|
||||||
genInExprAux(p, it, u, v, test)
|
genInExprAux(p, it, u, v, test)
|
||||||
let id = nodeTableTestOrSet(p.module.dataCache,
|
let id = nodeTableTestOrSet(p.module.dataCache,
|
||||||
newStrNode(nkStrLit, field.name.s), p.module.labels)
|
newStrNode(nkStrLit, field.name.s), p.module.labels)
|
||||||
let strLit = if id == p.module.labels: getStrLit(p.module, field.name.s)
|
let strLit = if id == p.module.labels: genStringLiteralDataOnly(p.module, field.name.s, e.info)
|
||||||
else: p.module.tmpBase & rope(id)
|
else: p.module.tmpBase & rope(id)
|
||||||
if op.magic == mNot:
|
if op.magic == mNot:
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"if ($1) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
"if ($1) #raiseFieldError($2);$n",
|
||||||
rdLoc(test), strLit)
|
rdLoc(test), genStringLiteralFromData(p.module, strLit, e.info))
|
||||||
else:
|
else:
|
||||||
linefmt(p, cpsStmts,
|
linefmt(p, cpsStmts,
|
||||||
"if (!($1)) #raiseFieldError(((#NimStringDesc*) &$2));$n",
|
"if (!($1)) #raiseFieldError($2);$n",
|
||||||
rdLoc(test), strLit)
|
rdLoc(test), genStringLiteralFromData(p.module, strLit, e.info))
|
||||||
|
|
||||||
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
|
||||||
if optFieldCheck in p.options:
|
if optFieldCheck in p.options:
|
||||||
|
|
|
||||||
81
compiler/ccgliterals.nim
Normal file
81
compiler/ccgliterals.nim
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# The Nim Compiler
|
||||||
|
# (c) Copyright 2018 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## This include file contains the logic to produce constant string
|
||||||
|
## and seq literals. The code here is responsible that
|
||||||
|
## ``const x = ["a", "b"]`` works without hidden runtime creation code.
|
||||||
|
## The price is that seqs and strings are not purely a library
|
||||||
|
## implementation.
|
||||||
|
|
||||||
|
template detectVersion(field, corename) =
|
||||||
|
if m.g.field == 0:
|
||||||
|
let core = getCompilerProc(corename)
|
||||||
|
if core == nil or core.kind != skConst:
|
||||||
|
m.g.field = 1
|
||||||
|
else:
|
||||||
|
m.g.field = int ast.getInt(core.ast)
|
||||||
|
result = m.g.field
|
||||||
|
|
||||||
|
proc detectStrVersion(m: BModule): int =
|
||||||
|
detectVersion(strVersion, "nimStrVersion")
|
||||||
|
|
||||||
|
proc detectSeqVersion(m: BModule): int =
|
||||||
|
detectVersion(seqVersion, "nimSeqVersion")
|
||||||
|
|
||||||
|
# ----- Version 1: GC'ed strings and seqs --------------------------------
|
||||||
|
|
||||||
|
proc genStringLiteralDataOnlyV1(m: BModule, s: string): Rope =
|
||||||
|
discard cgsym(m, "TGenericSeq")
|
||||||
|
result = getTempName(m)
|
||||||
|
addf(m.s[cfsData], "STRING_LITERAL($1, $2, $3);$n",
|
||||||
|
[result, makeCString(s), rope(len(s))])
|
||||||
|
|
||||||
|
proc genStringLiteralV1(m: BModule; n: PNode): Rope =
|
||||||
|
if s.isNil:
|
||||||
|
result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", [])
|
||||||
|
else:
|
||||||
|
let id = nodeTableTestOrSet(m.dataCache, n, m.labels)
|
||||||
|
if id == m.labels:
|
||||||
|
# string literal not found in the cache:
|
||||||
|
result = ropecg(m, "((#NimStringDesc*) &$1)",
|
||||||
|
[genStringLiteralDataOnlyV1(m, n.strVal)])
|
||||||
|
else:
|
||||||
|
result = ropecg(m, "((#NimStringDesc*) &$1$2)",
|
||||||
|
[m.tmpBase, rope(id)])
|
||||||
|
|
||||||
|
# ------ Version 2: destructor based strings and seqs -----------------------
|
||||||
|
|
||||||
|
proc genStringLiteralDataOnlyV2(m: BModule, s: string): Rope =
|
||||||
|
discard "to implement"
|
||||||
|
|
||||||
|
proc genStringLiteralV2(m: BModule; n: PNode): Rope =
|
||||||
|
discard "to implement"
|
||||||
|
|
||||||
|
# ------ Version selector ---------------------------------------------------
|
||||||
|
|
||||||
|
proc genStringLiteralDataOnly(m: BModule; s: string; info: TLineInfo): Rope =
|
||||||
|
case detectStrVersion(m)
|
||||||
|
of 0, 1: result = genStringLiteralDataOnlyV1(m, s)
|
||||||
|
of 2: result = genStringLiteralDataOnlyV2(m, s)
|
||||||
|
else:
|
||||||
|
localError(info, "cannot determine how to produce code for string literal")
|
||||||
|
|
||||||
|
proc genStringLiteralFromData(m: BModule; data: Rope; info: TLineInfo): Rope =
|
||||||
|
result = ropecg(m, "((#NimStringDesc*) &$1)",
|
||||||
|
[data])
|
||||||
|
|
||||||
|
proc genNilStringLiteral(m: BModule; info: TLineInfo): Rope =
|
||||||
|
result = ropecg(m, "((#NimStringDesc*) NIM_NIL)", [])
|
||||||
|
|
||||||
|
proc genStringLiteral(m: BModule; n: PNode): Rope =
|
||||||
|
case detectStrVersion(m)
|
||||||
|
of 0, 1: result = genStringLiteralV1(m, n)
|
||||||
|
of 2: result = genStringLiteralV2(m, n)
|
||||||
|
else:
|
||||||
|
localError(n.info, "cannot determine how to produce code for string literal")
|
||||||
|
|
@ -267,10 +267,6 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =
|
||||||
if isDefined("checkabi"):
|
if isDefined("checkabi"):
|
||||||
addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))])
|
addf(m.s[cfsTypeInfo], "NIM_CHECK_SIZE($1, $2);$n", [name, rope(getSize(t))])
|
||||||
|
|
||||||
proc getTempName(m: BModule): Rope =
|
|
||||||
result = m.tmpBase & rope(m.labels)
|
|
||||||
inc m.labels
|
|
||||||
|
|
||||||
proc ccgIntroducedPtr(s: PSym): bool =
|
proc ccgIntroducedPtr(s: PSym): bool =
|
||||||
var pt = skipTypes(s.typ, typedescInst)
|
var pt = skipTypes(s.typ, typedescInst)
|
||||||
assert skResult != s.kind
|
assert skResult != s.kind
|
||||||
|
|
@ -316,6 +312,11 @@ proc getSimpleTypeDesc(m: BModule, typ: PType): Rope =
|
||||||
of tyPointer:
|
of tyPointer:
|
||||||
result = typeNameOrLiteral(m, typ, "void*")
|
result = typeNameOrLiteral(m, typ, "void*")
|
||||||
of tyString:
|
of tyString:
|
||||||
|
case detectStrVersion(m)
|
||||||
|
of 2:
|
||||||
|
discard cgsym(m, "string")
|
||||||
|
result = typeNameOrLiteral(m, typ, "NimStringV2")
|
||||||
|
else:
|
||||||
discard cgsym(m, "NimStringDesc")
|
discard cgsym(m, "NimStringDesc")
|
||||||
result = typeNameOrLiteral(m, typ, "NimStringDesc*")
|
result = typeNameOrLiteral(m, typ, "NimStringDesc*")
|
||||||
of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING")
|
of tyCString: result = typeNameOrLiteral(m, typ, "NCSTRING")
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,12 @@ proc genProc(m: BModule, prc: PSym)
|
||||||
template compileToCpp(m: BModule): untyped =
|
template compileToCpp(m: BModule): untyped =
|
||||||
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
|
gCmd == cmdCompileToCpp or sfCompileToCpp in m.module.flags
|
||||||
|
|
||||||
include "ccgtypes.nim"
|
proc getTempName(m: BModule): Rope =
|
||||||
|
result = m.tmpBase & rope(m.labels)
|
||||||
|
inc m.labels
|
||||||
|
|
||||||
|
include ccgliterals
|
||||||
|
include ccgtypes
|
||||||
|
|
||||||
# ------------------------------ Manager of temporaries ------------------
|
# ------------------------------ Manager of temporaries ------------------
|
||||||
|
|
||||||
|
|
@ -551,11 +556,13 @@ proc loadDynamicLib(m: BModule, lib: PLib) =
|
||||||
for i in countup(0, high(s)):
|
for i in countup(0, high(s)):
|
||||||
inc(m.labels)
|
inc(m.labels)
|
||||||
if i > 0: add(loadlib, "||")
|
if i > 0: add(loadlib, "||")
|
||||||
appcg(m, loadlib, "($1 = #nimLoadLibrary((#NimStringDesc*) &$2))$n",
|
let n = newStrNode(nkStrLit, s[i])
|
||||||
[tmp, getStrLit(m, s[i])])
|
n.info = lib.path.info
|
||||||
|
appcg(m, loadlib, "($1 = #nimLoadLibrary($2))$n",
|
||||||
|
[tmp, genStringLiteral(m, n)])
|
||||||
appcg(m, m.s[cfsDynLibInit],
|
appcg(m, m.s[cfsDynLibInit],
|
||||||
"if (!($1)) #nimLoadLibraryError((#NimStringDesc*) &$2);$n",
|
"if (!($1)) #nimLoadLibraryError($2);$n",
|
||||||
[loadlib, getStrLit(m, lib.path.strVal)])
|
[loadlib, genStringLiteral(m, lib.path)])
|
||||||
else:
|
else:
|
||||||
var p = newProc(nil, m)
|
var p = newProc(nil, m)
|
||||||
p.options = p.options - {optStackTrace, optEndb}
|
p.options = p.options - {optStackTrace, optEndb}
|
||||||
|
|
|
||||||
|
|
@ -116,6 +116,7 @@ type
|
||||||
breakpoints*: Rope # later the breakpoints are inserted into the main proc
|
breakpoints*: Rope # later the breakpoints are inserted into the main proc
|
||||||
typeInfoMarker*: TypeCache
|
typeInfoMarker*: TypeCache
|
||||||
config*: ConfigRef
|
config*: ConfigRef
|
||||||
|
strVersion*, seqVersion*: int # version of the string/seq implementation to use
|
||||||
|
|
||||||
TCGen = object of TPassContext # represents a C source file
|
TCGen = object of TPassContext # represents a C source file
|
||||||
s*: TCFileSections # sections of the C file
|
s*: TCFileSections # sections of the C file
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ const
|
||||||
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed}
|
wGensym, wInject, wCodegenDecl, wGuard, wGoto, wExportNims, wUsed}
|
||||||
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
|
||||||
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
|
wExtern, wImportCpp, wImportObjC, wError, wGensym, wInject, wExportNims,
|
||||||
wIntDefine, wStrDefine, wUsed}
|
wIntDefine, wStrDefine, wUsed, wCompilerProc, wCore}
|
||||||
letPragmas* = varPragmas
|
letPragmas* = varPragmas
|
||||||
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNosideeffect,
|
||||||
wThread, wRaises, wLocks, wTags, wGcSafe}
|
wThread, wRaises, wLocks, wTags, wGcSafe}
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,11 @@ type
|
||||||
len, cap: int
|
len, cap: int
|
||||||
data: ptr UncheckedArray[T]
|
data: ptr UncheckedArray[T]
|
||||||
|
|
||||||
|
const nimSeqVersion {.core.} = 2
|
||||||
|
|
||||||
template frees(s) = dealloc(s.data, s.cap * sizeof(T))
|
template frees(s) = dealloc(s.data, s.cap * sizeof(T))
|
||||||
|
|
||||||
# XXX make code memory safe for overflows in '*'
|
# XXX make code memory safe for overflows in '*'
|
||||||
proc nimSeqLiteral[T](x: openArray[T]): seq[T] {.core.} =
|
|
||||||
seq[T](len: x.len, cap: x.len, data: x)
|
|
||||||
|
|
||||||
when defined(nimHasTrace):
|
when defined(nimHasTrace):
|
||||||
proc `=trace`[T](s: seq[T]; a: Allocator) =
|
proc `=trace`[T](s: seq[T]; a: Allocator) =
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,11 @@
|
||||||
import allocators
|
import allocators
|
||||||
|
|
||||||
type
|
type
|
||||||
string {.core.} = object
|
string {.core, exportc: "NimStringV2".} = object
|
||||||
len, cap: int
|
len, cap: int
|
||||||
data: ptr UncheckedArray[char]
|
data: ptr UncheckedArray[char]
|
||||||
|
|
||||||
proc nimStringLiteral(x: cstring; len: int): string {.core.} =
|
const nimStrVersion {.core.} = 2
|
||||||
string(len: len, cap: len, data: x)
|
|
||||||
|
|
||||||
template frees(s) = dealloc(s.data, s.cap + 1)
|
template frees(s) = dealloc(s.data, s.cap + 1)
|
||||||
|
|
||||||
|
|
@ -80,7 +79,7 @@ proc newString*(len: int): string =
|
||||||
if len > 0:
|
if len > 0:
|
||||||
result.data = alloc0(len+1)
|
result.data = alloc0(len+1)
|
||||||
|
|
||||||
converter toCString(x: string): cstring {.core.} =
|
converter toCString(x: string): cstring {.core, inline.} =
|
||||||
if x.len == 0: cstring"" else: cast[cstring](x.data)
|
if x.len == 0: cstring"" else: cast[cstring](x.data)
|
||||||
|
|
||||||
proc newStringOfCap*(cap: int): string =
|
proc newStringOfCap*(cap: int): string =
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue