codegen doesn't produce line tracing commands anymore; fixes #1344

This commit is contained in:
Araq 2015-03-21 15:18:32 +01:00
commit 5641be51c1
9 changed files with 277 additions and 216 deletions

View file

@ -532,12 +532,14 @@ type
mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf, mLow, mHigh, mSizeOf, mTypeTrait, mIs, mOf,
mEcho, mShallowCopy, mSlurp, mStaticExec, mEcho, mShallowCopy, mSlurp, mStaticExec,
mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst, mParseExprToAst, mParseStmtToAst, mExpandToAst, mQuoteAst,
mUnaryLt, mSucc, mUnaryLt, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
mPred, mInc, mDec, mOrd, mNew, mNewFinalize, mNewSeq, mLengthOpenArray,
mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref, mLengthStr, mLengthArray, mLengthSeq, mIncl, mExcl, mCard, mChr, mGCref,
mGCunref, mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64, mGCunref,
mDivI64, mModI64,
mAddI, mSubI, mMulI, mDivI, mModI, mAddI64, mSubI64, mMulI64,
mDivI64, mModI64, mSucc, mPred,
mAddF64, mSubF64, mMulF64, mDivF64, mAddF64, mSubF64, mMulF64, mDivF64,
mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI, mShrI, mShlI, mBitandI, mBitorI, mBitxorI, mMinI, mMaxI,
mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64, mShrI64, mShlI64, mBitandI64, mBitorI64, mBitxorI64, mMinI64, mMaxI64,
mMinF64, mMaxF64, mAddU, mSubU, mMulU, mMinF64, mMaxF64, mAddU, mSubU, mMulU,

View file

@ -485,37 +485,48 @@ proc unaryExprChar(p: BProc, e: PNode, d: var TLoc, frmt: string) =
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)])) putIntoDest(p, d, e.typ, ropecg(p.module, frmt, [rdCharLoc(a)]))
proc binaryArithOverflowRaw(p: BProc, t: PType, a, b: TLoc;
frmt: string): PRope =
var size = getSize(t)
let storage = if size < platform.intSize: toRope("NI")
else: getTypeDesc(p.module, t)
result = getTempName()
linefmt(p, cpsLocals, "$1 $2;$n", storage, result)
lineCg(p, cpsStmts, frmt, result, rdLoc(a), rdLoc(b))
if size < platform.intSize or t.kind in {tyRange, tyEnum}:
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
result, intLiteral(firstOrd(t)), intLiteral(lastOrd(t)))
proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc binaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const const
prc: array[mAddI..mModI64, string] = ["addInt", "subInt", "mulInt", prc: array[mAddI..mPred, string] = [
"divInt", "modInt", "addInt64", "subInt64", "mulInt64", "divInt64", "$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n",
"modInt64"] "$# = #mulInt($#, $#);$n", "$# = #divInt($#, $#);$n",
opr: array[mAddI..mModI64, string] = ["+", "-", "*", "/", "%", "+", "-", "$# = #modInt($#, $#);$n",
"*", "/", "%"] "$# = #addInt64($#, $#);$n", "$# = #subInt64($#, $#);$n",
"$# = #mulInt64($#, $#);$n", "$# = #divInt64($#, $#);$n",
"$# = #modInt64($#, $#);$n",
"$# = #addInt($#, $#);$n", "$# = #subInt($#, $#);$n"]
opr: array[mAddI..mPred, string] = [
"($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
"($#)($# / $#)", "($#)($# % $#)",
"($#)($# + $#)", "($#)($# - $#)", "($#)($# * $#)",
"($#)($# / $#)", "($#)($# % $#)",
"($#)($# + $#)", "($#)($# - $#)"]
var a, b: TLoc var a, b: TLoc
assert(e.sons[1].typ != nil) assert(e.sons[1].typ != nil)
assert(e.sons[2].typ != nil) assert(e.sons[2].typ != nil)
initLocExpr(p, e.sons[1], a) initLocExpr(p, e.sons[1], a)
initLocExpr(p, e.sons[2], b) initLocExpr(p, e.sons[2], b)
var t = skipTypes(e.typ, abstractRange) # skipping 'range' is correct here as we'll generate a proper range check
# later via 'chckRange'
let t = e.typ.skipTypes(abstractRange)
if optOverflowCheck notin p.options: if optOverflowCheck notin p.options:
putIntoDest(p, d, e.typ, ropef("(NI$4)($2 $1 $3)", [toRope(opr[m]), let res = ropef(opr[m], [getTypeDesc(p.module, t), rdLoc(a), rdLoc(b)])
rdLoc(a), rdLoc(b), toRope(getSize(t) * 8)])) putIntoDest(p, d, e.typ, res)
else: else:
var storage: PRope let res = binaryArithOverflowRaw(p, t, a, b, prc[m])
var size = getSize(t) putIntoDest(p, d, e.typ, ropef("($#)($#)", [getTypeDesc(p.module, t), res]))
if size < platform.intSize:
storage = toRope("NI")
else:
storage = getTypeDesc(p.module, t)
var tmp = getTempName()
linefmt(p, cpsLocals, "$1 $2;$n", storage, tmp)
lineCg(p, cpsStmts, "$1 = #$2($3, $4);$n",
tmp, toRope(prc[m]), rdLoc(a), rdLoc(b))
if size < platform.intSize or t.kind in {tyRange, tyEnum, tySet}:
linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseOverflow();$n",
tmp, intLiteral(firstOrd(t)), intLiteral(lastOrd(t)))
putIntoDest(p, d, e.typ, ropef("(NI$1)($2)", [toRope(getSize(t)*8), tmp]))
proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) = proc unaryArithOverflow(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
const const
@ -1648,35 +1659,35 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mAddF64..mDivF64: binaryFloatArith(p, e, d, op) of mAddF64..mDivF64: binaryFloatArith(p, e, d, op)
of mShrI..mXor: binaryArith(p, e, d, op) of mShrI..mXor: binaryArith(p, e, d, op)
of mEqProc: genEqProc(p, e, d) of mEqProc: genEqProc(p, e, d)
of mAddI..mModI64: binaryArithOverflow(p, e, d, op) of mAddI..mPred: binaryArithOverflow(p, e, d, op)
of mRepr: genRepr(p, e, d) of mRepr: genRepr(p, e, d)
of mGetTypeInfo: genGetTypeInfo(p, e, d) of mGetTypeInfo: genGetTypeInfo(p, e, d)
of mSwap: genSwap(p, e, d) of mSwap: genSwap(p, e, d)
of mUnaryLt: of mUnaryLt:
if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)") if optOverflowCheck notin p.options: unaryExpr(p, e, d, "($1 - 1)")
else: unaryExpr(p, e, d, "#subInt($1, 1)") else: unaryExpr(p, e, d, "#subInt($1, 1)")
of mPred: of mInc, mDec:
# XXX: range checking? const opr: array [mInc..mDec, string] = ["$1 += $2;$n", "$1 -= $2;$n"]
if optOverflowCheck notin p.options: binaryExpr(p, e, d, "($1 - $2)") const fun64: array [mInc..mDec, string] = ["$# = #addInt64($#, $#);$n",
else: binaryExpr(p, e, d, "#subInt($1, $2)") "$# = #subInt64($#, $#);$n"]
of mSucc: const fun: array [mInc..mDec, string] = ["$# = #addInt($#, $#);$n",
# XXX: range checking? "$# = #subInt($#, $#);$n"]
if optOverflowCheck notin p.options: binaryExpr(p, e, d, "($1 + $2)")
else: binaryExpr(p, e, d, "#addInt($1, $2)")
of mInc:
if optOverflowCheck notin p.options: if optOverflowCheck notin p.options:
binaryStmt(p, e, d, "$1 += $2;$n") binaryStmt(p, e, d, opr[op])
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64:
binaryStmt(p, e, d, "$1 = #addInt64($1, $2);$n")
else: else:
binaryStmt(p, e, d, "$1 = #addInt($1, $2);$n") var a, b: TLoc
of ast.mDec: assert(e.sons[1].typ != nil)
if optOverflowCheck notin p.options: assert(e.sons[2].typ != nil)
binaryStmt(p, e, d, "$1 -= $2;$n") initLocExpr(p, e.sons[1], a)
elif skipTypes(e.sons[1].typ, abstractVar).kind == tyInt64: initLocExpr(p, e.sons[2], b)
binaryStmt(p, e, d, "$1 = #subInt64($1, $2);$n")
else: let underlying = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar, tyRange})
binaryStmt(p, e, d, "$1 = #subInt($1, $2);$n") let ranged = skipTypes(e.sons[1].typ, {tyGenericInst, tyVar})
let res = binaryArithOverflowRaw(p, ranged, a, b,
if underlying.kind == tyInt64: fun64[op] else: fun[op])
putIntoDest(p, a, ranged, ropef("($#)($#)", [
getTypeDesc(p.module, ranged), res]))
of mConStrStr: genStrConcat(p, e, d) of mConStrStr: genStrConcat(p, e, d)
of mAppendStrCh: of mAppendStrCh:
binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n") binaryStmt(p, e, d, "$1 = #addChar($1, $2);$n")

View file

@ -978,12 +978,13 @@ proc genAsmStmt(p: BProc, t: PNode) =
lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s]) lineF(p, cpsStmts, CC[cCompiler].asmStmtFrmt, [s])
proc genEmit(p: BProc, t: PNode) = proc genEmit(p: BProc, t: PNode) =
genLineDir(p, t)
var s = genAsmOrEmitStmt(p, t.sons[1]) var s = genAsmOrEmitStmt(p, t.sons[1])
if p.prc == nil: if p.prc == nil:
# top level emit pragma? # top level emit pragma?
genCLineDir(p.module.s[cfsProcHeaders], t.info)
app(p.module.s[cfsProcHeaders], s) app(p.module.s[cfsProcHeaders], s)
else: else:
genLineDir(p, t)
line(p, cpsStmts, s) line(p, cpsStmts, s)
var var

View file

@ -13,7 +13,7 @@ import
ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp, ast, astalgo, strutils, hashes, trees, platform, magicsys, extccomp,
options, intsets, options, intsets,
nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os, nversion, nimsets, msgs, crc, bitsets, idents, lists, types, ccgutils, os,
times, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms, ropes, math, passes, rodread, wordrecg, treetab, cgmeth, condsyms,
rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings, rodutils, renderer, idgen, cgendata, ccgmerge, semfold, aliases, lowerings,
semparallel semparallel
@ -183,6 +183,13 @@ proc genCLineDir(r: var PRope, filename: string, line: int) =
proc genCLineDir(r: var PRope, info: TLineInfo) = proc genCLineDir(r: var PRope, info: TLineInfo) =
genCLineDir(r, info.toFullPath, info.safeLineNm) genCLineDir(r, info.toFullPath, info.safeLineNm)
proc freshLineInfo(p: BProc; info: TLineInfo): bool =
if p.lastLineInfo.line != info.line or
p.lastLineInfo.fileIndex != info.fileIndex:
p.lastLineInfo.line = info.line
p.lastLineInfo.fileIndex = info.fileIndex
result = true
proc genLineDir(p: BProc, t: PNode) = proc genLineDir(p: BProc, t: PNode) =
var line = t.info.safeLineNm var line = t.info.safeLineNm
if optEmbedOrigSrc in gGlobalOptions: if optEmbedOrigSrc in gGlobalOptions:
@ -190,13 +197,15 @@ proc genLineDir(p: BProc, t: PNode) =
genCLineDir(p.s(cpsStmts), t.info.toFullPath, line) genCLineDir(p.s(cpsStmts), t.info.toFullPath, line)
if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and if ({optStackTrace, optEndb} * p.options == {optStackTrace, optEndb}) and
(p.prc == nil or sfPure notin p.prc.flags): (p.prc == nil or sfPure notin p.prc.flags):
linefmt(p, cpsStmts, "#endb($1, $2);$n", if freshLineInfo(p, t.info):
line.toRope, makeCString(toFilename(t.info))) linefmt(p, cpsStmts, "#endb($1, $2);$n",
line.toRope, makeCString(toFilename(t.info)))
elif ({optLineTrace, optStackTrace} * p.options == elif ({optLineTrace, optStackTrace} * p.options ==
{optLineTrace, optStackTrace}) and {optLineTrace, optStackTrace}) and
(p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0: (p.prc == nil or sfPure notin p.prc.flags) and t.info.fileIndex >= 0:
linefmt(p, cpsStmts, "nimln($1, $2);$n", if freshLineInfo(p, t.info):
line.toRope, t.info.quotedFilename) linefmt(p, cpsStmts, "nimln($1, $2);$n",
line.toRope, t.info.quotedFilename)
proc postStmtActions(p: BProc) {.inline.} = proc postStmtActions(p: BProc) {.inline.} =
app(p.s(cpsStmts), p.module.injectStmt) app(p.s(cpsStmts), p.module.injectStmt)

View file

@ -12,6 +12,8 @@
import import
ast, astalgo, ropes, passes, options, intsets, lists, platform ast, astalgo, ropes, passes, options, intsets, lists, platform
from msgs import TLineInfo
type type
TLabel* = PRope # for the C generator a label is just a rope TLabel* = PRope # for the C generator a label is just a rope
TCFileSection* = enum # the sections a generated C file consists of TCFileSection* = enum # the sections a generated C file consists of
@ -65,6 +67,7 @@ type
prc*: PSym # the Nim proc that this C proc belongs to prc*: PSym # the Nim proc that this C proc belongs to
beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed beforeRetNeeded*: bool # true iff 'BeforeRet' label for proc is needed
threadVarAccessed*: bool # true if the proc already accessed some threadvar threadVarAccessed*: bool # true if the proc already accessed some threadvar
lastLineInfo*: TLineInfo # to avoid generating excessive 'nimln' statements
nestedTryStmts*: seq[PNode] # in how many nested try statements we are nestedTryStmts*: seq[PNode] # in how many nested try statements we are
# (the vars must be volatile then) # (the vars must be volatile then)
inExceptBlock*: int # are we currently inside an except block? inExceptBlock*: int # are we currently inside an except block?

View file

@ -262,6 +262,8 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64 ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64 ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64 ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
["", "", "($1 + $2)", "($1 + $2)"], # AddF64 ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
["", "", "($1 - $2)", "($1 - $2)"], # SubF64 ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
["", "", "($1 * $2)", "($1 * $2)"], # MulF64 ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
@ -362,6 +364,8 @@ const # magic checked op; magic unchecked op; checked op; unchecked op
["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64 ["mulInt64", "", "mulInt64($1, $2)", "($1 * $2)"], # MulI64
["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64 ["divInt64", "", "divInt64($1, $2)", "Math.floor($1 / $2)"], # DivI64
["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64 ["modInt64", "", "modInt64($1, $2)", "Math.floor($1 % $2)"], # ModI64
["addInt", "", "addInt($1, $2)", "($1 + $2)"], # Succ
["subInt", "", "subInt($1, $2)", "($1 - $2)"], # Pred
["", "", "($1 + $2)", "($1 + $2)"], # AddF64 ["", "", "($1 + $2)", "($1 + $2)"], # AddF64
["", "", "($1 - $2)", "($1 - $2)"], # SubF64 ["", "", "($1 - $2)", "($1 - $2)"], # SubF64
["", "", "($1 * $2)", "($1 * $2)"], # MulF64 ["", "", "($1 * $2)", "($1 * $2)"], # MulF64
@ -1323,14 +1327,6 @@ proc genMagic(p: PProc, n: PNode, r: var TCompRes) =
# XXX: range checking? # XXX: range checking?
if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1") if not (optOverflowCheck in p.options): unaryExpr(p, n, r, "", "$1 - 1")
else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)") else: unaryExpr(p, n, r, "subInt", "subInt($1, 1)")
of mPred:
# XXX: range checking?
if not (optOverflowCheck in p.options): binaryExpr(p, n, r, "", "$1 - $2")
else: binaryExpr(p, n, r, "subInt", "subInt($1, $2)")
of mSucc:
# XXX: range checking?
if not (optOverflowCheck in p.options): binaryExpr(p, n, r, "", "$1 - $2")
else: binaryExpr(p, n, r, "addInt", "addInt($1, $2)")
of mAppendStrCh: binaryExpr(p, n, r, "addChar", "addChar($1, $2)") of mAppendStrCh: binaryExpr(p, n, r, "addChar", "addChar($1, $2)")
of mAppendStrStr: of mAppendStrStr:
if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString: if skipTypes(n.sons[1].typ, abstractVarRange).kind == tyCString:

View file

@ -1557,9 +1557,9 @@ when not defined(nimrodVM) and hostOS != "standalone":
## process. This is only available when threads are enabled. ## process. This is only available when threads are enabled.
when sizeof(int) <= 2: when sizeof(int) <= 2:
type IntLikeForCount = int|int8|int16|char|bool|uint8 type IntLikeForCount = int|int8|int16|char|bool|uint8|enum
else: else:
type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16 type IntLikeForCount = int|int8|int16|int32|char|bool|uint8|uint16|enum
iterator countdown*[T](a, b: T, step = 1): T {.inline.} = iterator countdown*[T](a, b: T, step = 1): T {.inline.} =
## Counts from ordinal value `a` down to `b` with the given ## Counts from ordinal value `a` down to `b` with the given
@ -2900,20 +2900,16 @@ proc `[]`*[Idx, T](a: array[Idx, T], x: Slice[Idx]): seq[T] =
## because the array might have negative bounds. ## because the array might have negative bounds.
var L = ord(x.b) - ord(x.a) + 1 var L = ord(x.b) - ord(x.a) + 1
newSeq(result, L) newSeq(result, L)
var j = x.a
for i in 0.. <L: for i in 0.. <L:
result[i] = a[j] result[i] = a[Idx(ord(x.a) + i)]
inc(j)
proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) = proc `[]=`*[Idx, T](a: var array[Idx, T], x: Slice[Idx], b: openArray[T]) =
## slice assignment for arrays. Negative indexes are **not** supported ## slice assignment for arrays. Negative indexes are **not** supported
## because the array might have negative bounds. ## because the array might have negative bounds.
var L = ord(x.b) - ord(x.a) + 1 var L = ord(x.b) - ord(x.a) + 1
if L == b.len: if L == b.len:
var j = x.a
for i in 0 .. <L: for i in 0 .. <L:
a[j] = b[i] a[Idx(ord(x.a) + i)] = b[i]
inc(j)
else: else:
sysFatal(RangeError, "different lengths for slice assignment") sysFatal(RangeError, "different lengths for slice assignment")

View file

@ -0,0 +1,43 @@
discard """
output: '''10
10
1
1
true'''
"""
# bug #1344
var expected: int
var x: range[1..10] = 10
try:
x += 1
echo x
except OverflowError, RangeError:
expected += 1
echo x
try:
inc x
echo x
except OverflowError, RangeError:
expected += 1
echo x
x = 1
try:
x -= 1
echo x
except OverflowError, RangeError:
expected += 1
echo x
try:
dec x
echo x
except OverflowError, RangeError:
expected += 1
echo x
echo expected == 4