This commit is contained in:
Araq 2012-07-28 14:16:08 +02:00
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) genCLineDir(result, prc.info)
# using static is needed for inline procs # using static is needed for inline procs
if gCmd != cmdCompileToLLVM and lfExportLib in prc.loc.flags: 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: elif prc.typ.callConv == ccInline:
result.app "static " result.app "static "
var check = initIntSet() var check = initIntSet()

View file

@ -22,6 +22,9 @@ when options.hasTinyCBackend:
proc cgenPass*(): TPass proc cgenPass*(): TPass
# implementation # implementation
var
generatedHeader: BModule
proc ropeff(cformat, llvmformat: string, args: openarray[PRope]): PRope = proc ropeff(cformat, llvmformat: string, args: openarray[PRope]): PRope =
if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args) if gCmd == cmdCompileToLLVM: result = ropef(llvmformat, args)
else: result = ropef(cformat, args) else: result = ropef(cformat, args)
@ -754,16 +757,26 @@ proc requestConstImpl(p: BProc, sym: PSym) =
# declare header: # declare header:
if q != m and not ContainsOrIncl(m.declaredThings, sym.id): if q != m and not ContainsOrIncl(m.declaredThings, sym.id):
assert(sym.loc.r != nil) 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]) [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) = proc genProc(m: BModule, prc: PSym) =
if sfBorrow in prc.flags: return if sfBorrow in prc.flags: return
fillProcLoc(prc) fillProcLoc(prc)
if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc) if {sfForward, sfFromGeneric} * prc.flags != {}: addForwardedProc(m, prc)
else: genProcNoForward(m, prc) 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 genVarPrototype(m: BModule, sym: PSym) = proc genVarPrototypeAux(m: BModule, sym: PSym) =
assert(sfGlobal in sym.flags) assert(sfGlobal in sym.flags)
useHeader(m, sym) useHeader(m, sym)
fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap) fillLoc(sym.loc, locGlobalVar, sym.typ, mangleName(sym), OnHeap)
@ -782,25 +795,12 @@ proc genVarPrototype(m: BModule, sym: PSym) =
if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile") if sfVolatile in sym.flags: app(m.s[cfsVars], " volatile")
appf(m.s[cfsVars], " $1;$n", [sym.loc.r]) appf(m.s[cfsVars], " $1;$n", [sym.loc.r])
proc getFileHeader(cfilenoext: string): PRope = proc genVarPrototype(m: BModule, sym: PSym) =
if optCompileOnly in gGlobalOptions: genVarPrototypeAux(m, sym)
result = ropeff("/* Generated by Nimrod Compiler v$1 */$n" & if sfExportc in sym.flags and generatedHeader != nil:
"/* (c) 2012 Andreas Rumpf */$n", genVarPrototypeAux(generatedHeader, sym)
"; Generated by Nimrod Compiler v$1$n" &
"; (c) 2012 Andreas Rumpf$n", [toRope(versionAsString)]) proc addIntTypes(result: var PRope) =
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))])
case platform.CPU[targetCPU].intSize case platform.CPU[targetCPU].intSize
of 16: of 16:
appff(result, appff(result,
@ -813,8 +813,33 @@ proc getFileHeader(cfilenoext: string): PRope =
of 64: of 64:
appff(result, "$ntypedef long long int NI;$n" & appff(result, "$ntypedef long long int NI;$n" &
"typedef unsigned long long int NU;$n", "$n%NI = type i64$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: 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) = proc genMainProc(m: BModule) =
const const
@ -1008,6 +1033,31 @@ proc newModule(module: PSym, filename: string): BModule =
proc myOpen(module: PSym, filename: string): PPassContext = proc myOpen(module: PSym, filename: string): PPassContext =
result = newModule(module, filename) 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 = proc getCFile(m: BModule): string =
result = changeFileExt(completeCFilePath(m.cfilename), cExt) 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 # we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong # deps are allowed (and the system module is processed in the wrong
# order anyway) # order anyway)
if generatedHeader != nil: finishModule(generatedHeader)
while gForwardedProcsCounter > 0: while gForwardedProcsCounter > 0:
for i in countup(0, high(gModules)): for i in countup(0, high(gModules)):
finishModule(gModules[i]) finishModule(gModules[i])
for i in countup(0, high(gModules)): for i in countup(0, high(gModules)):
writeModule(gModules[i], pending=true) writeModule(gModules[i], pending=true)
writeMapping(gMapping) writeMapping(gMapping)
if generatedHeader != nil: writeHeader(generatedHeader)
proc cgenPass(): TPass = proc cgenPass(): TPass =
initPass(result) initPass(result)

View file

@ -91,6 +91,7 @@ type
usesThreadVars*: bool # true if the module uses a thread var usesThreadVars*: bool # true if the module uses a thread var
FrameDeclared*: bool # hack for ROD support so that we don't declare FrameDeclared*: bool # hack for ROD support so that we don't declare
# a frame var twice in an init proc # 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, cfilename*: string # filename of the module (including path,
# without extension) # without extension)
typeCache*: TIdTable # cache the generated types typeCache*: TIdTable # cache the generated types

View file

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

View file

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

View file

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

View file

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

View file

@ -238,7 +238,6 @@ proc semSizeof(c: PContext, n: PNode): PNode =
else: else:
n.sons[1] = semExprWithType(c, n.sons[1]) n.sons[1] = semExprWithType(c, n.sons[1])
restoreOldStyleType(n.sons[1]) restoreOldStyleType(n.sons[1])
n.typ = getSysType(tyInt) n.typ = getSysType(tyInt)
result = n result = n
@ -252,8 +251,19 @@ proc semOf(c: PContext, n: PNode): PNode =
var b = skipTypes(n.sons[2].typ, abstractPtrs) var b = skipTypes(n.sons[2].typ, abstractPtrs)
if b.kind != tyObject or a.kind != tyObject: if b.kind != tyObject or a.kind != tyObject:
GlobalError(n.info, errXExpectsObjectTypes, "of") GlobalError(n.info, errXExpectsObjectTypes, "of")
while b != nil and b.id != a.id: b = b.sons[0] let diff = inheritanceDiff(a, b)
if b == nil: # | 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)) GlobalError(n.info, errXcanNeverBeOfThisSubtype, typeToString(a))
n.typ = getSysType(tyBool) n.typ = getSysType(tyBool)
else: else:

View file

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

View file

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

View file

@ -29,6 +29,8 @@ Advanced options:
--import:PATH add an automatically imported module --import:PATH add an automatically imported module
--include:PATH add an automatically included module --include:PATH add an automatically included module
--nimcache:PATH set the path used for generated files --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 -c, --compileOnly compile only; do not assemble or link
--noLinking compile but do not link --noLinking compile but do not link
--noMain do not generate a main procedure --noMain do not generate a main procedure