This commit is contained in:
Araq
2012-07-28 14:16:08 +02:00
parent 2ff8d17369
commit 538b06a123
11 changed files with 114 additions and 39 deletions

View File

@@ -653,7 +653,10 @@ proc genProcHeader(m: BModule, prc: PSym): PRope =
genCLineDir(result, prc.info)
# using static is needed for inline procs
if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags:
result.app "N_LIB_EXPORT "
if m.isHeaderFile:
result.app "N_LIB_IMPORT "
else:
result.app "N_LIB_EXPORT "
elif prc.typ.callConv == ccInline:
result.app "static "
var check = initIntSet()

View File

@@ -22,6 +22,9 @@ when options.hasTinyCBackend:
proc cgenPass*(): TPass
# implementation
var
generatedHeader: BModule
proc ropeff(cformat, llvmformat: string, args: openarray[PRope]): PRope =
if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args)
else: result = ropef(cformat, args)
@@ -721,7 +724,7 @@ proc genProcNoForward(m: BModule, prc: PSym) =
# dependency to a compilerproc:
discard cgsym(m, prc.name.s)
return
genProcPrototype(m, prc)
genProcPrototype(m, prc)
if lfNoDecl in prc.loc.Flags: nil
elif prc.typ.callConv == ccInline:
# We add inline procs to the calling module to enable C based inlining.
@@ -754,16 +757,26 @@ proc requestConstImpl(p: BProc, sym: PSym) =
# declare header:
if q != m and not ContainsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil)
appf(m.s[cfsData], "extern NIM_CONST $1 $2;$n",
let headerDecl = ropef("extern NIM_CONST $1 $2;$n",
[getTypeDesc(m, sym.loc.t), sym.loc.r])
app(m.s[cfsData], headerDecl)
if sfExportc in sym.flags and generatedHeader != nil:
app(generatedHeader.s[cfsData], headerDecl)
proc genProc(m: BModule, prc: PSym) =
if sfBorrow in prc.flags: return
fillProcLoc(prc)
if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
else: genProcNoForward(m, prc)
proc genVarPrototype(m: BModule, sym: PSym) =
else:
genProcNoForward(m, prc)
if {sfExportc, sfCompilerProc} * prc.flags == {sfExportc} and
generatedHeader != nil and lfNoDecl notin prc.loc.Flags:
genProcPrototype(generatedHeader, prc)
if prc.typ.callConv == ccInline:
if not ContainsOrIncl(generatedHeader.declaredThings, prc.id):
genProcAux(generatedHeader, prc)
proc genVarPrototypeAux(m: BModule, sym: PSym) =
assert(sfGlobal in sym.flags)
useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
@@ -782,27 +795,14 @@ proc genVarPrototype(m: BModule, sym: PSym) =
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc getFileHeader(cfilenoext: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)])
else:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n" &
"/* Compiled for: $2, $3, $4 */$n" &
"/* Command for C compiler:$n $5 */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n" &
"; Compiled for: $2, $3, $4$n" &
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.ccompiler].name),
toRope(getCompileCFileCmd(cfilenoext))])
proc genVarPrototype(m: BModule, sym: PSym) =
genVarPrototypeAux(m, sym)
if sfExportc in sym.flags and generatedHeader != nil:
genVarPrototypeAux(generatedHeader, sym)
proc addIntTypes(result: var PRope) =
case platform.CPU[targetCPU].intSize
of 16:
of 16:
appff(result,
"$ntypedef short int NI;$n" & "typedef unsigned short int NU;$n",
"$n%NI = type i16$n", [])
@@ -813,8 +813,33 @@ proc getFileHeader(cfilenoext: string): PRope =
of 64:
appff(result, "$ntypedef long long int NI;$n" &
"typedef unsigned long long int NU;$n", "$n%NI = type i64$n", [])
else: nil
proc getCopyright(cfilenoext: string): PRope =
if optCompileOnly in gGlobalOptions:
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n" &
"/* The generated code is subject to the original license. */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)])
else:
nil
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" &
"/* (c) 2012 Andreas Rumpf */$n" &
"/* The generated code is subject to the original license. */$n" &
"/* Compiled for: $2, $3, $4 */$n" &
"/* Command for C compiler:$n $5 */$n",
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n" &
"; Compiled for: $2, $3, $4$n" &
"; Command for LLVM compiler:$n $5$n", [toRope(versionAsString),
toRope(platform.OS[targetOS].name),
toRope(platform.CPU[targetCPU].name),
toRope(extccomp.CC[extccomp.ccompiler].name),
toRope(getCompileCFileCmd(cfilenoext))])
proc getFileHeader(cfilenoext: string): PRope =
result = getCopyright(cfilenoext)
addIntTypes(result)
proc genMainProc(m: BModule) =
const
@@ -1008,6 +1033,31 @@ proc newModule(module: PSym, filename: string): BModule =
proc myOpen(module: PSym, filename: string): PPassContext =
result = newModule(module, filename)
if optGenIndex in gGlobalOptions and generatedHeader == nil:
let f = if headerFile.len > 0: headerFile else: gProjectFull
generatedHeader = rawNewModule(module,
changeFileExt(completeCFilePath(f), hExt))
generatedHeader.isHeaderFile = true
proc writeHeader(m: BModule) =
var result = getCopyright(m.filename)
var guard = ropef("__$1__", m.filename.splitFile.name.toRope)
result.appf("#ifndef $1$n#define $1$n", guard)
addIntTypes(result)
generateHeaders(m)
generateThreadLocalStorage(m)
for i in countup(cfsHeaders, cfsProcs):
app(result, genSectionStart(i))
app(result, m.s[i])
app(result, genSectionEnd(i))
app(result, m.s[cfsInitProc])
if optGenDynLib in gGlobalOptions:
result.app("N_LIB_IMPORT ")
result.appf("N_CDECL(void, NimMain)(void);$n")
result.appf("#endif /* $1 */$n", guard)
writeRope(result, m.filename)
proc getCFile(m: BModule): string =
result = changeFileExt(completeCFilePath(m.cfilename), cExt)
@@ -1106,12 +1156,14 @@ proc myClose(b: PPassContext, n: PNode): PNode =
# we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong
# order anyway)
if generatedHeader != nil: finishModule(generatedHeader)
while gForwardedProcsCounter > 0:
for i in countup(0, high(gModules)):
finishModule(gModules[i])
for i in countup(0, high(gModules)):
writeModule(gModules[i], pending=true)
writeMapping(gMapping)
if generatedHeader != nil: writeHeader(generatedHeader)
proc cgenPass(): TPass =
initPass(result)

View File

@@ -91,6 +91,7 @@ type
usesThreadVars*: bool # true if the module uses a thread var
FrameDeclared*: bool # hack for ROD support so that we don't declare
# a frame var twice in an init proc
isHeaderFile*: bool # C source file is the header file
cfilename*: string # filename of the module (including path,
# without extension)
typeCache*: TIdTable # cache the generated types
@@ -119,7 +120,7 @@ var
# finished with code generation
gModules*: seq[BModule] = @[] # list of all compiled modules
gForwardedProcsCounter*: int = 0
proc s*(p: BProc, s: TCProcSection): var PRope {.inline.} =
# section in the current block
result = p.blocks[p.blocks.len - 1].sections[s]

View File

@@ -365,7 +365,10 @@ proc processSwitch(switch, arg: string, pass: TCmdlinePass, info: TLineInfo) =
of "clib":
expectArg(switch, arg, pass, info)
if pass in {passCmd2, passPP}: cLinkedLibs.add arg
of "index":
of "header":
headerFile = arg
incl(gGlobalOptions, optGenIndex)
of "index":
ProcessOnOffSwitchG({optGenIndex}, arg, pass, info)
of "import":
expectArg(switch, arg, pass, info)

View File

@@ -107,7 +107,9 @@ type
hintSuccess, hintSuccessX,
hintLineTooLong, hintXDeclaredButNotUsed, hintConvToBaseNotNeeded,
hintConvFromXtoItselfNotNeeded, hintExprAlwaysX, hintQuitCalled,
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath, hintUser
hintProcessing, hintCodeBegin, hintCodeEnd, hintConf, hintPath,
hintConditionAlwaysTrue,
hintUser
const
MsgKindToStr*: array[TMsgKind, string] = [
@@ -361,6 +363,7 @@ const
hintCodeEnd: "end of listing [CodeEnd]",
hintConf: "used config file \'$1\' [Conf]",
hintPath: "added path: '$1' [Path]",
hintConditionAlwaysTrue: "condition is always true: '$1' [CondTrue]",
hintUser: "$1 [User]"]
const
@@ -373,10 +376,10 @@ const
"AnalysisLoophole", "DifferentHeaps", "WriteToForeignHeap",
"ImplicitClosure", "EachIdentIsTuple", "User"]
HintsToStr*: array[0..13, string] = ["Success", "SuccessX", "LineTooLong",
HintsToStr*: array[0..14, string] = ["Success", "SuccessX", "LineTooLong",
"XDeclaredButNotUsed", "ConvToBaseNotNeeded", "ConvFromXtoItselfNotNeeded",
"ExprAlwaysX", "QuitCalled", "Processing", "CodeBegin", "CodeEnd", "Conf",
"Path",
"Path", "CondTrue",
"User"]
const

View File

@@ -54,7 +54,8 @@ type # please make sure we have under 32 options
optThreadAnalysis, # thread analysis pass
optTaintMode, # taint mode turned on
optTlsEmulation, # thread var emulation turned on
optGenIndex # generate index file for documentation
optGenIndex # generate index file for documentation;
# also: generate header file
TGlobalOptions* = set[TGlobalOption]
TCommands* = enum # Nimrod's commands
@@ -85,6 +86,7 @@ var
gExitcode*: int8
searchPaths*: TLinkedList
outFile*: string = ""
headerFile*: string = ""
gCmd*: TCommands = cmdNone # the command
gVerbosity*: int # how verbose the compiler is
gNumberOfProcessors*: int # number of processors

View File

@@ -112,7 +112,7 @@ proc freezeMutableRope*(r: PRope) {.inline.} =
r.length = r.data.len
var
cache: array[0..2048 -1, PRope]
cache: array[0..2048*2 -1, PRope]
proc RopeInvariant(r: PRope): bool =
if r == nil:

View File

@@ -238,7 +238,6 @@ proc semSizeof(c: PContext, n: PNode): PNode =
else:
n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1])
n.typ = getSysType(tyInt)
result = n
@@ -252,8 +251,19 @@ proc semOf(c: PContext, n: PNode): PNode =
var b = skipTypes(n.sons[2].typ, abstractPtrs)
if b.kind != tyObject or a.kind != tyObject:
GlobalError(n.info, errXExpectsObjectTypes, "of")
while b != nil and b.id != a.id: b = b.sons[0]
if b == nil:
let diff = inheritanceDiff(a, b)
# | returns: 0 iff `a` == `b`
# | returns: -x iff `a` is the x'th direct superclass of `b`
# | returns: +x iff `a` is the x'th direct subclass of `b`
# | returns: `maxint` iff `a` and `b` are not compatible at all
if diff <= 0:
# optimize to true:
Message(n.info, hintConditionAlwaysTrue, renderTree(n))
result = newIntNode(nkIntLit, 1)
result.info = n.info
result.typ = getSysType(tyBool)
return result
elif diff == high(int):
GlobalError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
n.typ = getSysType(tyBool)
else:

View File

@@ -49,7 +49,6 @@ type
nestedProcs: int # > 0 if we are in a nested proc
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
inLoop: int # > 0 if we are in a loop
transformedInnerProcs: TIntSet
PTransf = ref TTransfContext
proc newTransNode(a: PNode): PTransNode {.inline.} =
@@ -753,7 +752,6 @@ proc openTransf(module: PSym, filename: string): PPassContext =
n.contSyms = @[]
n.breakSyms = @[]
n.module = module
n.transformedInnerProcs = initIntSet()
result = n
proc openTransfCached(module: PSym, filename: string,

View File

@@ -59,6 +59,7 @@ const
abstractInst* = {tyGenericInst, tyDistinct, tyConst, tyMutable, tyOrdinal}
skipPtrs* = {tyVar, tyPtr, tyRef, tyGenericInst, tyConst, tyMutable}
typeclassPtrs* = abstractPtrs + {tyTypeClass}
proc skipTypes*(t: PType, kinds: TTypeKinds): PType
proc containsObject*(t: PType): bool

View File

@@ -29,6 +29,8 @@ Advanced options:
--import:PATH add an automatically imported module
--include:PATH add an automatically included module
--nimcache:PATH set the path used for generated files
--header:FILE the compiler should produce a .h file (FILE
is optional)
-c, --compileOnly compile only; do not assemble or link
--noLinking compile but do not link
--noMain do not generate a main procedure