summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ccgstmts.nim61
-rw-r--r--compiler/condsyms.nim2
-rw-r--r--compiler/msgs.nim3
-rw-r--r--compiler/pragmas.nim7
-rw-r--r--compiler/vm.nim6
-rw-r--r--compiler/wordrecg.nim4
6 files changed, 71 insertions, 12 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 1f21b275a..4d52e3aab 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -292,6 +292,57 @@ proc genReturnStmt(p: BProc, t: PNode) =
   blockLeaveActions(p, min(1, p.nestedTryStmts.len))
   lineFF(p, cpsStmts, "goto BeforeRet;$n", "br label %BeforeRet$n", [])
 
+proc genComputedGoto(p: BProc; n: PNode) =
+  # first pass: Generate array of computed labels:
+  var casePos = -1
+  var arraySize: Int
+  for i in 0 .. <n.len:
+    let it = n.sons[i]
+    if it.kind == nkCaseStmt:
+      if lastSon(it).kind != nkOfBranch:
+        localError(it.info,
+            "case statement must be exhaustive for computed goto"); return
+      casePos = i
+      let aSize = lengthOrd(it.sons[0].typ)
+      if aSize > 10_000:
+        localError(it.info,
+            "case statement has too many cases for computed goto"); return
+      arraySize = aSize.int
+      if firstOrd(it.sons[0].typ) != 0:
+        localError(it.info,
+            "case statement has to start at 0 for computed goto"); return
+  if casePos < 0:
+    localError(n.info, "no case statement found for computed goto"); return
+  var id = p.labels+1
+  inc p.labels, arraySize+1
+  let tmp = ropef("TMP$1", id.toRope)
+  var gotoArray = ropef("static void* $#[$#] = {", tmp, arraySize.toRope)
+  for i in 1..arraySize-1:
+    gotoArray.appf("&&TMP$#, ", (id+i).toRope)
+  gotoArray.appf("&&TMP$#};$n", (id+arraySize).toRope)
+  line(p, cpsLocals, gotoArray)
+  
+  let caseStmt = n.sons[casePos]
+  var a: TLoc
+  initLocExpr(p, caseStmt.sons[0], a)
+  # first goto:
+  lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
+  
+  for i in 1 .. <caseStmt.len:
+    let it = caseStmt.sons[i]
+    for j in 0 .. it.len-2:
+      if it.sons[j].kind == nkRange:
+        localError(it.info, "range notation not available for computed goto")
+        return
+      let val = getOrdValue(it.sons[j])
+      lineF(p, cpsStmts, "TMP$#:$n", intLiteral(val+id+1))
+    for j in 0 .. casePos-1: genStmts(p, n.sons[j])
+    genStmts(p, it.lastSon)
+    for j in casePos+1 .. <n.len: genStmts(p, n.sons[j])
+    var a: TLoc
+    initLocExpr(p, caseStmt.sons[0], a)
+    lineF(p, cpsStmts, "goto *$#[$#];$n", tmp, a.rdLoc)
+
 proc genWhileStmt(p: BProc, t: PNode) =
   # we don't generate labels here as for example GCC would produce
   # significantly worse code
@@ -309,7 +360,15 @@ proc genWhileStmt(p: BProc, t: PNode) =
     if (t.sons[0].kind != nkIntLit) or (t.sons[0].intVal == 0): 
       let label = assignLabel(p.blocks[p.breakIdx])
       lineF(p, cpsStmts, "if (!$1) goto $2;$n", [rdLoc(a), label])
-    genStmts(p, t.sons[1])
+    var loopBody = t.sons[1]
+    if loopBody.stmtsContainPragma(wComputedGoto) and
+        hasComputedGoto in CC[ccompiler].props:
+      # for closure support weird loop bodies are generated:
+      if loopBody.len == 2 and loopBody.sons[0].kind == nkEmpty:
+        loopBody = loopBody.sons[1]
+      genComputedGoto(p, loopBody)
+    else:
+      genStmts(p, loopBody)
 
     if optProfiler in p.options:
       # invoke at loop body exit:
diff --git a/compiler/condsyms.nim b/compiler/condsyms.nim
index b8d6a5ce7..21095072b 100644
--- a/compiler/condsyms.nim
+++ b/compiler/condsyms.nim
@@ -46,7 +46,7 @@ proc InitDefines*() =
   DefineSymbol("nimmixin")
   DefineSymbol("nimeffects")
   DefineSymbol("nimbabel")
-  DefineSymbol("nimsuperops")
+  DefineSymbol("nimcomputedgoto")
   
   # add platform specific symbols:
   case targetCPU
diff --git a/compiler/msgs.nim b/compiler/msgs.nim
index 73481940c..3e5304358 100644
--- a/compiler/msgs.nim
+++ b/compiler/msgs.nim
@@ -774,6 +774,9 @@ proc GlobalError*(info: TLineInfo, arg: string) =
 proc LocalError*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doNothing)
 
+proc LocalError*(info: TLineInfo, arg: string) =
+  liMessage(info, errGenerated, arg, doNothing)
+
 proc Message*(info: TLineInfo, msg: TMsgKind, arg = "") =
   liMessage(info, msg, arg, doNothing)
 
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index a11739f95..f185d0f80 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -42,7 +42,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, wEffects, wNoForward}
+    wLinearScanEnd, wPatterns, wEffects, wNoForward, wComputedGoto}
   lambdaPragmas* = {FirstCallConv..LastCallConv, wImportc, wExportc, wNodecl, 
     wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader, 
     wDeprecated, wExtern, wThread, wImportcpp, wImportobjc, wNoStackFrame,
@@ -446,9 +446,6 @@ proc PragmaUnroll(c: PContext, n: PNode) =
     else: 
       invalidPragma(n)
 
-proc PragmaLinearScanEnd(c: PContext, n: PNode) =
-  noVal(n)
-
 proc PragmaLine(c: PContext, n: PNode) =
   if n.kind == nkExprColonExpr:
     n.sons[1] = c.semConstExpr(c, n.sons[1])
@@ -691,7 +688,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
           else: sym.typ.callConv = wordToCallConv(k)
         of wEmit: PragmaEmit(c, it)
         of wUnroll: PragmaUnroll(c, it)
-        of wLinearScanEnd: PragmaLinearScanEnd(c, it)
+        of wLinearScanEnd, wComputedGoto: noVal(it)
         of wEffects:
           # is later processed in effect analysis:
           noVal(it)
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 37f13990f..b02de405e 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -54,8 +54,8 @@ proc bailOut(c: PCtx; tos: PStackFrame) =
   stackTrace(c, tos, c.exceptionInstr, errUnhandledExceptionX,
              c.currentExceptionA.sons[2].strVal)
 
-when not defined(nimHasInterpreterLoop):
-  {.pragma: interpreterLoop.}
+when not defined(nimComputedGoto):
+  {.pragma: computedGoto.}
 
 template inc(pc: ptr TInstr, diff = 1) =
   inc cast[TAddress](pc), TInstr.sizeof * diff
@@ -237,7 +237,7 @@ proc execute(c: PCtx, start: int) =
   var tos: PStackFrame
   newSeq(regs, c.prc.maxSlots)
   while true:
-    {.interpreterLoop.}
+    {.computedGoto.}
     let instr = c.code[pc]
     let ra = instr.regA
     #echo "PC ", pc, " ", c.code[pc].opcode, " ra ", ra
diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim
index 06607d2a6..a9540269c 100644
--- a/compiler/wordrecg.nim
+++ b/compiler/wordrecg.nim
@@ -59,7 +59,7 @@ type
     wPassc, wPassl, wBorrow, wDiscardable,
     wFieldChecks, 
     wWatchPoint, wSubsChar, 
-    wAcyclic, wShallow, wUnroll, wLinearScanEnd,
+    wAcyclic, wShallow, wUnroll, wLinearScanEnd, wComputedGoto,
     wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit, 
     wNoStackFrame,
     wImplicitStatic, wGlobal, wCodegenDecl,
@@ -140,7 +140,7 @@ const
     "compiletime", "noinit",
     "passc", "passl", "borrow", "discardable", "fieldchecks",
     "watchpoint",
-    "subschar", "acyclic", "shallow", "unroll", "linearscanend",
+    "subschar", "acyclic", "shallow", "unroll", "linearscanend", "computedgoto",
     "write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
     "nostackframe", "implicitstatic", "global", "codegendecl",