fixed and documented computedGoto pragma
This commit is contained in:
parent
50403afb5c
commit
6f1fc1b5ba
8 changed files with 94 additions and 35 deletions
|
|
@ -322,6 +322,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||||
gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
|
gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
|
||||||
line(p, cpsLocals, gotoArray)
|
line(p, cpsLocals, gotoArray)
|
||||||
|
|
||||||
|
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
|
||||||
let caseStmt = n.sons[casePos]
|
let caseStmt = n.sons[casePos]
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, caseStmt.sons[0], a)
|
initLocExpr(p, caseStmt.sons[0], a)
|
||||||
|
|
@ -329,6 +330,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||||
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
||||||
|
|
||||||
for i in 1 .. <caseStmt.len:
|
for i in 1 .. <caseStmt.len:
|
||||||
|
startBlock(p)
|
||||||
let it = caseStmt.sons[i]
|
let it = caseStmt.sons[i]
|
||||||
for j in 0 .. it.len-2:
|
for j in 0 .. it.len-2:
|
||||||
if it.sons[j].kind == nkRange:
|
if it.sons[j].kind == nkRange:
|
||||||
|
|
@ -336,12 +338,13 @@ proc genComputedGoto(p: BProc; n: PNode) =
|
||||||
return
|
return
|
||||||
let val = getOrdValue(it.sons[j])
|
let val = getOrdValue(it.sons[j])
|
||||||
lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
|
lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
|
||||||
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
|
|
||||||
genStmts(p, it.lastSon)
|
genStmts(p, it.lastSon)
|
||||||
for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
|
for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
|
||||||
|
for j in 0 .. casePos-1: genStmts(p, n.sons[j])
|
||||||
var a: TLoc
|
var a: TLoc
|
||||||
initLocExpr(p, caseStmt.sons[0], a)
|
initLocExpr(p, caseStmt.sons[0], a)
|
||||||
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
|
||||||
|
endBlock(p)
|
||||||
|
|
||||||
proc genWhileStmt(p: BProc, t: PNode) =
|
proc genWhileStmt(p: BProc, t: PNode) =
|
||||||
# we don't generate labels here as for example GCC would produce
|
# we don't generate labels here as for example GCC would produce
|
||||||
|
|
|
||||||
|
|
@ -117,32 +117,17 @@ proc ToTreeSet(s: TBitSet, settype: PType, info: TLineInfo): PNode =
|
||||||
e = b
|
e = b
|
||||||
Inc(e)
|
Inc(e)
|
||||||
|
|
||||||
type
|
template nodeSetOp(a, b: PNode, op: expr) {.dirty.} =
|
||||||
TSetOP = enum
|
|
||||||
soUnion, soDiff, soSymDiff, soIntersect
|
|
||||||
|
|
||||||
proc nodeSetOp(a, b: PNode, op: TSetOp): PNode =
|
|
||||||
var x, y: TBitSet
|
var x, y: TBitSet
|
||||||
toBitSet(a, x)
|
toBitSet(a, x)
|
||||||
toBitSet(b, y)
|
toBitSet(b, y)
|
||||||
case op
|
op(x, y)
|
||||||
of soUnion: BitSetUnion(x, y)
|
|
||||||
of soDiff: BitSetDiff(x, y)
|
|
||||||
of soSymDiff: BitSetSymDiff(x, y)
|
|
||||||
of soIntersect: BitSetIntersect(x, y)
|
|
||||||
result = toTreeSet(x, a.typ, a.info)
|
result = toTreeSet(x, a.typ, a.info)
|
||||||
|
|
||||||
proc unionSets(a, b: PNode): PNode =
|
proc unionSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetUnion)
|
||||||
result = nodeSetOp(a, b, soUnion)
|
proc diffSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetDiff)
|
||||||
|
proc intersectSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetIntersect)
|
||||||
proc diffSets(a, b: PNode): PNode =
|
proc symdiffSets(a, b: PNode): PNode = nodeSetOp(a, b, BitSetSymDiff)
|
||||||
result = nodeSetOp(a, b, soDiff)
|
|
||||||
|
|
||||||
proc intersectSets(a, b: PNode): PNode =
|
|
||||||
result = nodeSetOp(a, b, soIntersect)
|
|
||||||
|
|
||||||
proc symdiffSets(a, b: PNode): PNode =
|
|
||||||
result = nodeSetOp(a, b, soSymDiff)
|
|
||||||
|
|
||||||
proc containsSets(a, b: PNode): bool =
|
proc containsSets(a, b: PNode): bool =
|
||||||
var x, y: TBitSet
|
var x, y: TBitSet
|
||||||
|
|
|
||||||
|
|
@ -352,7 +352,6 @@ proc execute(c: PCtx, start: int) =
|
||||||
if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb]))
|
if not inSet(regs[ra], regs[rb]): addSon(regs[ra], copyTree(regs[rb]))
|
||||||
of opcExcl:
|
of opcExcl:
|
||||||
decodeB(nkCurly)
|
decodeB(nkCurly)
|
||||||
# XXX arg we need types here :-(
|
|
||||||
var b = newNodeIT(nkCurly, regs[rb].info, regs[rb].typ)
|
var b = newNodeIT(nkCurly, regs[rb].info, regs[rb].typ)
|
||||||
addSon(b, regs[rb])
|
addSon(b, regs[rb])
|
||||||
var r = diffSets(regs[ra], b)
|
var r = diffSets(regs[ra], b)
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,22 @@ proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
c.freeTemp(tmp2)
|
c.freeTemp(tmp2)
|
||||||
|
|
||||||
|
proc genSetType(c: PCtx; n: PNode; dest: TRegister) =
|
||||||
|
let t = skipTypes(n.typ, abstractInst)
|
||||||
|
if t.kind == tySet:
|
||||||
|
c.gABx(n, opcSetType, dest, c.genType(t))
|
||||||
|
|
||||||
|
proc genBinarySet(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
|
let
|
||||||
|
tmp = c.genx(n.sons[1])
|
||||||
|
tmp2 = c.genx(n.sons[2])
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
c.genSetType(n.sons[1], tmp)
|
||||||
|
c.genSetType(n.sons[2], tmp2)
|
||||||
|
c.gABC(n, opc, dest, tmp, tmp2)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(tmp2)
|
||||||
|
|
||||||
proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
let
|
let
|
||||||
dest = c.genx(n.sons[1])
|
dest = c.genx(n.sons[1])
|
||||||
|
|
@ -488,6 +504,13 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
|
||||||
c.gABx(n, opc, 0, genType(c, n.typ))
|
c.gABx(n, opc, 0, genType(c, n.typ))
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
|
proc genCard(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
let tmp = c.genx(n.sons[1])
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
c.genSetType(n.sons[1], tmp)
|
||||||
|
c.gABC(n, opc, dest, tmp)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
let m = n.sons[0].sym.magic
|
let m = n.sons[0].sym.magic
|
||||||
case m
|
case m
|
||||||
|
|
@ -532,10 +555,11 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
var d = c.genx(n.sons[1])
|
var d = c.genx(n.sons[1])
|
||||||
var tmp = c.genx(n.sons[2])
|
var tmp = c.genx(n.sons[2])
|
||||||
|
c.genSetType(n.sons[1], d)
|
||||||
c.gABC(n, if m == mIncl: opcIncl else: opcExcl, d, tmp)
|
c.gABC(n, if m == mIncl: opcIncl else: opcExcl, d, tmp)
|
||||||
c.freeTemp(d)
|
c.freeTemp(d)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
of mCard: genUnaryABC(c, n, dest, opcCard)
|
of mCard: genCard(c, n, dest)
|
||||||
of mMulI, mMulI64: genBinaryABC(c, n, dest, opcMulInt)
|
of mMulI, mMulI64: genBinaryABC(c, n, dest, opcMulInt)
|
||||||
of mDivI, mDivI64: genBinaryABC(c, n, dest, opcDivInt)
|
of mDivI, mDivI64: genBinaryABC(c, n, dest, opcDivInt)
|
||||||
of mModI, mModI64: genBinaryABC(c, n, dest, opcModInt)
|
of mModI, mModI64: genBinaryABC(c, n, dest, opcModInt)
|
||||||
|
|
@ -580,15 +604,15 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
|
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
|
||||||
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
|
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
|
||||||
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
|
of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
|
||||||
of mEqSet: genBinaryABC(c, n, dest, opcEqSet)
|
of mEqSet: genBinarySet(c, n, dest, opcEqSet)
|
||||||
of mLeSet: genBinaryABC(c, n, dest, opcLeSet)
|
of mLeSet: genBinarySet(c, n, dest, opcLeSet)
|
||||||
of mLtSet: genBinaryABC(c, n, dest, opcLtSet)
|
of mLtSet: genBinarySet(c, n, dest, opcLtSet)
|
||||||
of mMulSet: genBinaryABC(c, n, dest, opcMulSet)
|
of mMulSet: genBinarySet(c, n, dest, opcMulSet)
|
||||||
of mPlusSet: genBinaryABC(c, n, dest, opcPlusSet)
|
of mPlusSet: genBinarySet(c, n, dest, opcPlusSet)
|
||||||
of mMinusSet: genBinaryABC(c, n, dest, opcMinusSet)
|
of mMinusSet: genBinarySet(c, n, dest, opcMinusSet)
|
||||||
of mSymDiffSet: genBinaryABC(c, n, dest, opcSymdiffSet)
|
of mSymDiffSet: genBinarySet(c, n, dest, opcSymdiffSet)
|
||||||
of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr)
|
of mConStrStr: genVarargsABC(c, n, dest, opcConcatStr)
|
||||||
of mInSet: genBinaryABC(c, n, dest, opcContainsSet)
|
of mInSet: genBinarySet(c, n, dest, opcContainsSet)
|
||||||
of mRepr: genUnaryABC(c, n, dest, opcRepr)
|
of mRepr: genUnaryABC(c, n, dest, opcRepr)
|
||||||
of mExit:
|
of mExit:
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
|
|
|
||||||
|
|
@ -4561,6 +4561,51 @@ tested against via linear scanning. If put into the last branch of the
|
||||||
whole ``case`` statement, the whole ``case`` statement uses linear scanning.
|
whole ``case`` statement, the whole ``case`` statement uses linear scanning.
|
||||||
|
|
||||||
|
|
||||||
|
computedGoto pragma
|
||||||
|
-------------------
|
||||||
|
The `computedGoto`:idx: pragma can be used to tell the compiler how to
|
||||||
|
compile a Nimrod `case`:idx: in a ``while true`` statement.
|
||||||
|
Syntactically it has to be used as a statement inside the loop:
|
||||||
|
|
||||||
|
.. code-block:: nimrod
|
||||||
|
|
||||||
|
type
|
||||||
|
MyEnum = enum
|
||||||
|
enumA, enumB, enumC, enumD, enumE
|
||||||
|
|
||||||
|
proc vm() =
|
||||||
|
var instructions: array [0..100, MyEnum]
|
||||||
|
instructions[2] = enumC
|
||||||
|
instructions[3] = enumD
|
||||||
|
instructions[4] = enumA
|
||||||
|
instructions[5] = enumD
|
||||||
|
instructions[6] = enumC
|
||||||
|
instructions[7] = enumA
|
||||||
|
instructions[8] = enumB
|
||||||
|
|
||||||
|
instructions[12] = enumE
|
||||||
|
var pc = 0
|
||||||
|
while true:
|
||||||
|
{.computedGoto.}
|
||||||
|
let instr = instructions[pc]
|
||||||
|
case instr
|
||||||
|
of enumA:
|
||||||
|
echo "yeah A"
|
||||||
|
of enumC, enumD:
|
||||||
|
echo "yeah CD"
|
||||||
|
of enumB:
|
||||||
|
echo "yeah B"
|
||||||
|
of enumE:
|
||||||
|
break
|
||||||
|
inc(pc)
|
||||||
|
|
||||||
|
vm()
|
||||||
|
|
||||||
|
As the example shows ``computedGoto`` is mostly useful for interpreters. If
|
||||||
|
the underlying backend (C compiler) does not support the computed goto
|
||||||
|
extension the pragma is simply ignored.
|
||||||
|
|
||||||
|
|
||||||
unroll pragma
|
unroll pragma
|
||||||
-------------
|
-------------
|
||||||
The `unroll`:idx: pragma can be used to tell the compiler that it should unroll
|
The `unroll`:idx: pragma can be used to tell the compiler that it should unroll
|
||||||
|
|
|
||||||
|
|
@ -488,7 +488,7 @@ in C/C++).
|
||||||
|
|
||||||
|
|
||||||
Nimrod idetools integration
|
Nimrod idetools integration
|
||||||
=======================
|
===========================
|
||||||
|
|
||||||
Nimrod provides language integration with external IDEs through the
|
Nimrod provides language integration with external IDEs through the
|
||||||
idetools command. See the documentation of `idetools <idetools.html>`_
|
idetools command. See the documentation of `idetools <idetools.html>`_
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,8 @@ proc vm() =
|
||||||
var pc = 0
|
var pc = 0
|
||||||
while true:
|
while true:
|
||||||
{.computedGoto.}
|
{.computedGoto.}
|
||||||
case instructions[pc]
|
let instr = instructions[pc]
|
||||||
|
case instr
|
||||||
of enumA:
|
of enumA:
|
||||||
echo "yeah A"
|
echo "yeah A"
|
||||||
of enumC, enumD:
|
of enumC, enumD:
|
||||||
|
|
@ -39,7 +40,7 @@ proc vm() =
|
||||||
of enumB:
|
of enumB:
|
||||||
echo "yeah B"
|
echo "yeah B"
|
||||||
of enumE:
|
of enumE:
|
||||||
return
|
break
|
||||||
inc(pc)
|
inc(pc)
|
||||||
|
|
||||||
vm()
|
vm()
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,8 @@ Compiler Additions
|
||||||
- The compiler now enforces the ``not nil`` constraint.
|
- The compiler now enforces the ``not nil`` constraint.
|
||||||
- The compiler now supports a ``codegenDecl`` pragma for even more control
|
- The compiler now supports a ``codegenDecl`` pragma for even more control
|
||||||
over the generated code.
|
over the generated code.
|
||||||
|
- The compiler now supports a ``computedGoto`` pragma to support very fast
|
||||||
|
dispatching for interpreters and the like.
|
||||||
|
|
||||||
|
|
||||||
Language Additions
|
Language Additions
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue