fixed and documented computedGoto pragma

This commit is contained in:
Araq 2013-08-22 08:38:47 +02:00
commit 6f1fc1b5ba
8 changed files with 94 additions and 35 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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>`_

View file

@ -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()

View file

@ -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