bugfix: wrong assertions for C++ code generation; some solaris support; first steps to an effect system

This commit is contained in:
Araq
2012-10-30 22:29:03 +01:00
parent 86ed918157
commit 2133fbfcce
11 changed files with 193 additions and 22 deletions

View File

@@ -277,6 +277,13 @@ const
# getting ready for the future expr/stmt merge
nkWhen* = nkWhenStmt
nkWhenExpr* = nkWhenStmt
nkEffectList* = nkArgList
# hacks ahead: an nkEffectList is a node with 4 children:
exceptionEffects* = 0 # exceptions at position 0
readEffects* = 1 # read effects at position 1
writeEffects* = 2 # write effects at position 2
tagEffects* = 3 # user defined tag ('gc', 'time' etc.)
effectListLen* = 4 # list of effects list
type
TTypeKind* = enum # order is important!

View File

@@ -1131,11 +1131,6 @@ proc writeModule(m: BModule, pending: bool) =
addFileToCompile(cfilenoext)
addFileToLink(cfilenoext)
proc genPlatformAsserts(m: BModule) =
appf(m.s[cfsForwardTypes],
"typedef assert_numbits[sizeof(NI) == sizeof(void*) &&" &
"NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];$N")
proc myClose(b: PPassContext, n: PNode): PNode =
result = n
if b == nil or passes.skipCodegen(n): return
@@ -1149,7 +1144,6 @@ proc myClose(b: PPassContext, n: PNode): PNode =
if sfMainModule in m.module.flags:
var disp = generateMethodDispatchers()
for i in 0..sonsLen(disp)-1: genProcAux(m, disp.sons[i].sym)
genPlatformAsserts(m)
genMainProc(m)
# we need to process the transitive closure because recursive module
# deps are allowed (and the system module is processed in the wrong

View File

@@ -41,7 +41,7 @@ const
wFatal, wDefine, wUndef, wCompile, wLink, wLinkSys, wPure, wPush, wPop,
wBreakpoint, wWatchpoint, wPassL, wPassC, wDeadCodeElim, wDeprecated,
wFloatChecks, wInfChecks, wNanChecks, wPragma, wEmit, wUnroll,
wLinearScanEnd, wPatterns}
wLinearScanEnd, wPatterns, wEffects}
lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl,
wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame}
@@ -292,14 +292,14 @@ proc processOption(c: PContext, n: PNode) =
if n.sons[1].kind != nkIdent:
invalidPragma(n)
else:
case whichKeyword(n.sons[1].ident)
of wSpeed:
case n.sons[1].ident.s.normalize
of "speed":
incl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
of wSize:
of "size":
excl(gOptions, optOptimizeSpeed)
incl(gOptions, optOptimizeSize)
of wNone:
of "none":
excl(gOptions, optOptimizeSpeed)
excl(gOptions, optOptimizeSize)
else: LocalError(n.info, errNoneSpeedOrSizeExpected)
@@ -656,6 +656,9 @@ proc pragma(c: PContext, sym: PSym, n: PNode, validPragmas: TSpecialWords) =
of wEmit: PragmaEmit(c, it)
of wUnroll: PragmaUnroll(c, it)
of wLinearScanEnd: PragmaLinearScanEnd(c, it)
of wEffects:
# is later processed in effect analysis:
noVal(it)
of wIncompleteStruct:
noVal(it)
if sym.typ == nil: invalidPragma(it)

View File

@@ -14,7 +14,7 @@ import
# way had some inherent problems. Performs:
#
# * procvar checks
# * effect tracking
# * effect+exception tracking
# * closure analysis
# * checks for invalid usages of compiletime magics (not implemented)
# * checks for invalid usages of PNimNode (not implemented)
@@ -29,6 +29,21 @@ import
# --> a TR macro can annotate the proc with user defined annotations
# --> the effect system can access these
# Load&Store analysis is performed on *paths*. A path is an access like
# obj.x.y[i].z; splitting paths up causes some problems:
#
# var x = obj.x
# var z = x.y[i].z
#
# Alias analysis is affected by this too! A good solution is *type splitting*:
# T becomes T1 and T2 if it's known that T1 and T2 can't alias.
#
# An aliasing problem and a race condition are effectively the same problem.
# Type based alias analysis is nice but not sufficient; especially splitting
# an array and filling it in parallel should be supported but is not easily
# done: It essentially requires a built-in 'indexSplit' operation and dependent
# typing.
proc sem2call(c: PContext, n: PNode): PNode =
assert n.kind in nkCallKinds
@@ -37,4 +52,145 @@ proc sem2call(c: PContext, n: PNode): PNode =
proc sem2sym(c: PContext, n: PNode): PNode =
assert n.kind == nkSym
# ------------------------ exception tracking -------------------------------
discard """
exception tracking:
a() # raises 'x', 'e'
try:
b() # raises 'e'
except e:
# must not undo 'e' here; hrm
c()
--> we need a stack of scopes for this analysis
Effect tracking:
We track the effects per proc; forward declarations and indirect calls cause
problems: Forward declarations are computed lazily (we do this pass after
a whole module) and indirect calls are assumed the worst, unless they have
an effect annotation.
"""
type
TEffects = object
exc: PNode # stack of exceptions
bottom: int
PEffects = var TEffects
proc throws(tracked: PEffects, n: PNode) =
# since a 'raise' statement occurs rarely and we need distinct reasons;
# we simply do not merge anything here, this would be problematic for the
# stack of exceptions anyway:
tracked.exc.add n
proc excType(n: PNode): PType =
assert n.kind == nkRaiseStmt
# reraise is like raising E_Base:
let t = if n.sons[0].kind == nkEmpty: sysTypeFromName"E_Base"
else: n.sons[0].typ
result = skipTypes(t, skipPtrs)
proc mergeEffects(a: PEffects, b: PNode) =
var aa = a.exc
for effect in items(b):
block search
for i in a.bottom .. <aa.len:
if sameType(aa[i].excType, b.excType): break search
throws(a, effect)
proc listEffects(a: PEffects) =
var aa = a.exc
for e in items(aa):
Message(e.info, hintUser, renderTree(e))
proc catches(tracked: PEffects, e: PType) =
let e = skipTypes(e, skipPtrs)
let L = tracked.exc.len
var i = tracked.bottom
while i < L:
# e supertype of r?
if inheritanceDiff(e, tracked.exc[i].excType) <= 0:
tracked.exc.sons[i] = tracked.exc.sons[L-1]
dec L
else:
inc i
proc catchesAll(tracked: PEffects) =
setLen(tracked.exc.sons, tracked.bottom)
proc track(tracked: PEffects, n: PNode)
proc trackTryStmt(tracked: PEffects, n: PNode) =
let oldBottom = tracked.bottom
tracked.bottom = tracked.exc.len
track(tracked, n.sons[0])
for i in 1 .. < n.len:
let b = n.sons[i]
let blen = sonsLen(b)
if b.kind == nkExceptBranch:
if blen == 1:
catchesAll(tracked)
else:
for j in countup(0, blen - 2):
assert(b.sons[j].kind == nkType)
catches(tracked, b.sons[j].typ)
else:
assert b.kind == nkFinally
track(tracked, b.sons[blen-1])
tracked.bottom = oldBottom
proc isIndirectCall(n: PNode): bool =
result = n.kind != nkSym or n.sym.kind notin routineKinds
proc isForwardedProc(n: PNode): bool =
result = n.kind == nkSym and sfForward in n.sym.flags
proc trackPragmaStmt(tracked: PEffects, n: PNode) =
for i in countup(0, sonsLen(n) - 1):
var it = n.sons[i]
if whichPragma(it) == wEffects:
# list the computed effects up to here:
listEffects(tracked)
proc track(tracked: PEffects, n: PNode) =
case n.kind
of nkRaiseStmt: throws(tracked, n)
of nkCallNode:
# p's effects are ours too:
let op = n.sons[0].typ
InternalAssert op.kind == tyProc and op.n.sons[0].kind == nkEffectList
var effectList = op.n.sons[0]
if effectList.len == 0:
if isIndirectCall(n.sons[0]) or isForwardedProc(n.sons[0]):
# assume the worst: raise of exception 'E_Base':
var rs = newNodeI(nkRaiseStmt, n.info)
var re = newNodeIT(nkType, n.info, sysTypeFromName"E_Base")
rs.add(re)
effectList.add(rs)
mergeEffects(tracked, effectList)
of nkTryStmt:
trackTryStmt(tracked, n)
return
of nkPragma:
trackPragmaStmt(tracked, n)
return
else: nil
for i in 0 .. <safeLen(n):
track(tracked, n.sons[i])
proc trackProc*(s: PSym, body: PNode) =
var effects = s.typ.n.sons[0]
InternalAssert effects.kind == nkEffectList
# effects already computed?
if effects.len == effectListLen: return
newSeq(effects.sons, effectListLen)
var t: TEffects
t.exc = effects.sons[exceptionEffects]
track(t, body)

View File

@@ -647,7 +647,10 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode,
if genericParams != nil and sonsLen(genericParams) == 0:
cl = initIntSet()
rawAddSon(result, nil) # return type
res = newNodeI(nkType, n.info)
# result.n[0] used to be `nkType`, but now it's `nkEffectList` because
# the effects are now stored in there too ... this is a bit hacky, but as
# usual we desperately try to save memory:
res = newNodeI(nkEffectList, n.info)
addSon(result.n, res)
var check = initIntSet()
var counter = 0

View File

@@ -59,6 +59,8 @@ proc setupEnvironment =
#addFile(nimrodDir / r"tinyc\lib\libtcc1.c")
else:
addSysincludePath(gTinyC, "/usr/include")
when defined(amd64):
addSysincludePath(gTinyC, "/usr/include/x86_64-linux-gnu")
proc compileCCode*(ccode: string) =
if not libIncluded:
@@ -66,11 +68,11 @@ proc compileCCode*(ccode: string) =
setupEnvironment()
discard compileString(gTinyC, ccode)
proc run*() =
proc run*() =
var a: array[0..1, cstring]
a[0] = ""
a[1] = ""
var err = tinyc.run(gTinyC, 0'i32, addr(a)) != 0'i32
var err = tinyc.run(gTinyC, 0'i32, cast[cstringArray](addr(a))) != 0'i32
closeCCState(gTinyC)
if err: rawMessage(errExecutionOfProgramFailed, "")
if err: rawMessage(errExecutionOfProgramFailed, "")

View File

@@ -18,7 +18,7 @@ import
# Keywords must be kept sorted and within a range
type
type
TSpecialWord* = enum
wInvalid,
@@ -52,7 +52,7 @@ type
wBoundchecks, wOverflowchecks, wNilchecks,
wFloatchecks, wNanChecks, wInfChecks,
wAssertions, wPatterns, wWarnings,
wHints, wOptimization, wSpeed, wSize, wNone,
wHints, wOptimization, wRaises, wWrites, wReads, wSize, wEffects,
wDeadCodeElim, wSafecode,
wPragma,
wCompileTime, wNoInit,
@@ -62,7 +62,7 @@ type
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wNoStackFrame,
wImplicitStatic, wGlobal, wHoist
wImplicitStatic, wGlobal, wHoist,
wAuto, wBool, wCatch, wChar, wClass,
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
@@ -133,7 +133,7 @@ const
"floatchecks", "nanchecks", "infchecks",
"assertions", "patterns", "warnings", "hints",
"optimization", "speed", "size", "none",
"optimization", "raises", "writes", "reads", "size", "effects",
"deadcodeelim", "safecode",
"pragma",
"compiletime", "noinit",

View File

@@ -470,4 +470,6 @@ static inline void GCGuard (void *ptr) { asm volatile ("" :: "X" (ptr)); }
# define GC_GUARD
#endif
typedef int assert_numbits[sizeof(NI) == sizeof(void*) &&
NIM_INTBITS == sizeof(NI)*8 ? 1 : -1];
#endif

View File

@@ -24,6 +24,9 @@ when defined(Windows):
import winlean
else:
import posix
when defined(solaris):
{.passl: "-lsocket -lnsl".}
# Note: The enumerations are mapped to Window's constants.

View File

@@ -4,5 +4,5 @@ type
var a: TArray
echo a[0] #OUT 0
echo a[0x0012] #OUT 0

View File

@@ -37,7 +37,8 @@ version 0.9.XX
echo a
echo b)
- implement the "snoopResult" pragma
- implement the "snoopResult" pragma; no, make a strutils with string append
semantics instead ...
- implement "closure tuple consists of a single 'ref'" optimization
- JS gen:
- fix exception handling