diff --git a/compiler/ast.nim b/compiler/ast.nim index 10a3d8039..978b43b5e 100755 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -145,6 +145,7 @@ type nkIfStmt, # an if statement nkWhenStmt, # a when expression or statement nkForStmt, # a for statement + nkParForStmt, # a parallel for statement nkWhileStmt, # a while statement nkCaseStmt, # a case statement nkTypeSection, # a type section (consists of type definitions) @@ -396,7 +397,7 @@ type mAnd, mOr, mEqStr, mLeStr, mLtStr, mEqSet, mLeSet, mLtSet, mMulSet, mPlusSet, mMinusSet, mSymDiffSet, mConStrStr, mConArrArr, mConArrT, mConTArr, mConTT, mSlice, - mFields, mFieldPairs, + mFields, mFieldPairs, mOmpParFor, mAppendStrCh, mAppendStrStr, mAppendSeqElem, mInRange, mInSet, mRepr, mExit, mSetLengthStr, mSetLengthSeq, mIsPartOf, mAstToStr, mRand, diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index db6d5bd67..891731533 100755 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -258,6 +258,34 @@ proc genBlock(p: BProc, t: PNode, d: var TLoc) = else: genStmts(p, t.sons[1]) endBlock(p) +proc genParForStmt(p: BProc, t: PNode) = + assert(sonsLen(t) == 3) + inc(p.withinLoop) + genLineDir(p, t) + + preserveBreakIdx: + let forLoopVar = t.sons[0].sym + var rangeA, rangeB: TLoc + assignLocalVar(P, forLoopVar) + #initLoc(forLoopVar.loc, locLocalVar, forLoopVar.typ, onStack) + #discard mangleName(forLoopVar) + let call = t.sons[1] + initLocExpr(p, call.sons[1], rangeA) + initLocExpr(p, call.sons[2], rangeB) + + appf(p.s(cpsStmts), "#pragma omp parallel for $4$n" & + "for ($1 = $2; $1 <= $3; ++$1)", + forLoopVar.loc.rdLoc, + rangeA.rdLoc, rangeB.rdLoc, + call.sons[3].getStr.toRope) + + p.breakIdx = startBlock(p) + p.blocks[p.breakIdx].isLoop = true + genStmts(p, t.sons[2]) + endBlock(p) + + dec(p.withinLoop) + proc genBreakStmt(p: BProc, t: PNode) = var idx = p.breakIdx if t.sons[0].kind != nkEmpty: @@ -815,5 +843,6 @@ proc genStmts(p: BProc, t: PNode) = # we have not only the header: if prc.getBody.kind != nkEmpty or lfDynamicLib in prc.loc.flags: genProc(p.module, prc) + of nkParForStmt: genParForStmt(p, t) else: internalError(t.info, "genStmts(" & $t.kind & ')') diff --git a/compiler/ecmasgen.nim b/compiler/ecmasgen.nim index 3ab4303c2..ecdbb022e 100755 --- a/compiler/ecmasgen.nim +++ b/compiler/ecmasgen.nim @@ -1341,7 +1341,8 @@ proc genStmt(p: var TProc, n: PNode, r: var TCompRes) = of nkWhileStmt: genWhileStmt(p, n, r) of nkVarSection, nkLetSection: genVarStmt(p, n, r) of nkConstSection: genConstStmt(p, n, r) - of nkForStmt: internalError(n.info, "for statement not eliminated") + of nkForStmt, nkParForStmt: + internalError(n.info, "for statement not eliminated") of nkCaseStmt: genCaseStmt(p, n, r) of nkReturnStmt: genReturnStmt(p, n, r) of nkBreakStmt: genBreakStmt(p, n, r) diff --git a/compiler/evals.nim b/compiler/evals.nim index a4d4cdd9e..b2fded071 100755 --- a/compiler/evals.nim +++ b/compiler/evals.nim @@ -1289,7 +1289,7 @@ proc evalAux(c: PEvalContext, n: PNode, flags: TEvalFlags): PNode = of nkPragmaBlock: result = evalAux(c, n.sons[1], flags) of nkIdentDefs, nkCast, nkYieldStmt, nkAsmStmt, nkForStmt, nkPragmaExpr, - nkLambdaKinds, nkContinueStmt, nkIdent: + nkLambdaKinds, nkContinueStmt, nkIdent, nkParForStmt: result = raiseCannotEval(c, n.info) of nkRefTy: result = evalAux(c, n.sons[0], flags) diff --git a/compiler/renderer.nim b/compiler/renderer.nim index 67b657657..a5e79762c 100755 --- a/compiler/renderer.nim +++ b/compiler/renderer.nim @@ -984,7 +984,7 @@ proc gsub(g: var TSrcGen, n: PNode, c: TContext) = of nkCaseStmt, nkRecCase: gcase(g, n) of nkMacroStmt: gmacro(g, n) of nkTryStmt: gtry(g, n) - of nkForStmt: gfor(g, n) + of nkForStmt, nkParForStmt: gfor(g, n) of nkBlockStmt, nkBlockExpr: gblock(g, n) of nkStaticStmt: gstaticStmt(g, n) of nkAsmStmt: gasm(g, n) diff --git a/compiler/semgnrc.nim b/compiler/semgnrc.nim index d8f017c4c..f7e64bdee 100755 --- a/compiler/semgnrc.nim +++ b/compiler/semgnrc.nim @@ -142,7 +142,7 @@ proc semGenericStmt(c: PContext, n: PNode, a.sons[j] = semGenericStmt(c, a.sons[j], flags, toBind) a.sons[L - 1] = semGenericStmtScope(c, a.sons[L-1], flags, toBind) closeScope(c.tab) - of nkForStmt: + of nkForStmt, nkParForStmt: var L = sonsLen(n) openScope(c.tab) n.sons[L - 2] = semGenericStmt(c, n.sons[L-2], flags, toBind) diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim index 6b79326fe..202b7416a 100755 --- a/compiler/semstmts.nim +++ b/compiler/semstmts.nim @@ -465,7 +465,11 @@ proc semFor(c: PContext, n: PNode): PNode = else: GlobalError(n.sons[length - 2].info, errIteratorExpected) elif call.sons[0].sym.magic != mNone: - result = semForFields(c, n, call.sons[0].sym.magic) + if call.sons[0].sym.magic == mOmpParFor: + result = semForVars(c, n) + result.kind = nkParForStmt + else: + result = semForFields(c, n, call.sons[0].sym.magic) else: result = semForVars(c, n) closeScope(c.tab) @@ -889,7 +893,7 @@ proc SemStmt(c: PContext, n: PNode): PNode = of nkWhileStmt: result = semWhile(c, n) of nkTryStmt: result = semTry(c, n) of nkBreakStmt, nkContinueStmt: result = semBreakOrContinue(c, n) - of nkForStmt: result = semFor(c, n) + of nkForStmt, nkParForStmt: result = semFor(c, n) of nkCaseStmt: result = semCase(c, n) of nkReturnStmt: result = semReturn(c, n) of nkAsmStmt: result = semAsm(c, n) diff --git a/compiler/transf.nim b/compiler/transf.nim index 9e0d4051f..0ab8bc8d3 100755 --- a/compiler/transf.nim +++ b/compiler/transf.nim @@ -247,7 +247,7 @@ proc transformConstSection(c: PTransf, v: PNode): PTransNode = proc hasContinue(n: PNode): bool = case n.kind - of nkEmpty..nkNilLit, nkForStmt, nkWhileStmt: nil + of nkEmpty..nkNilLit, nkForStmt, nkParForStmt, nkWhileStmt: nil of nkContinueStmt: result = true else: for i in countup(0, sonsLen(n) - 1): @@ -659,6 +659,10 @@ proc transform(c: PTransf, n: PNode): PTransNode = inc c.inLoop result = transformFor(c, n) dec c.inLoop + of nkParForStmt: + inc c.inLoop + result = transformSons(c, n) + dec c.inLoop of nkCaseStmt: result = transformCase(c, n) of nkContinueStmt: result = PTransNode(newNode(nkBreakStmt)) diff --git a/config/nimrod.cfg b/config/nimrod.cfg index 21cf55ec9..c98f30f02 100755 --- a/config/nimrod.cfg +++ b/config/nimrod.cfg @@ -60,6 +60,7 @@ hint[LineTooLong]=off @if unix: @if not bsd: + # -fopenmp gcc.options.linker = "-ldl" clang.options.linker = "-ldl" tcc.options.linker = "-ldl" diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 8b08952f0..21f5134e2 100755 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -36,7 +36,7 @@ type nnkMacroDef, nnkTemplateDef, nnkIteratorDef, nnkOfBranch, nnkElifBranch, nnkExceptBranch, nnkElse, nnkMacroStmt, nnkAsmStmt, nnkPragma, nnkPragmaBlock, nnkIfStmt, nnkWhenStmt, - nnkForStmt, nnkWhileStmt, nnkCaseStmt, + nnkForStmt, nnkParForStmt, nnkWhileStmt, nnkCaseStmt, nnkTypeSection, nnkVarSection, nnkLetSection, nnkConstSection, nnkConstDef, nnkTypeDef, nnkYieldStmt, nnkTryStmt, nnkFinally, nnkRaiseStmt, diff --git a/lib/system.nim b/lib/system.nim index f78ca9738..148df7e34 100755 --- a/lib/system.nim +++ b/lib/system.nim @@ -1200,6 +1200,15 @@ iterator `..`*[S, T](a: S, b: T): T {.inline.} = yield res inc res +iterator `||`*[S, T](a: S, b: T, annotation=""): T {. + inline, magic: "OmpParFor", sideEffect.} = + ## parallel loop iterator. Same as `..` but the loop may run in parallel. + ## `annotation` is an additional annotation for the code generator to use. + ## Note that the compiler maps that to + ## the ``#pragma omp parallel for`` construct of `OpenMP`:idx: and as + ## such isn't aware of the parallelism in your code. Be careful. + nil + proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} proc min*(x, y: int8): int8 {.magic: "MinI", noSideEffect.} proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} diff --git a/web/news.txt b/web/news.txt index e047cf1fc..f83c86a25 100755 --- a/web/news.txt +++ b/web/news.txt @@ -46,6 +46,7 @@ Library Additions - Added ``system.clamp`` to limit a value within an interval ``[a, b]``. - Added ``strutils.continuesWith``. - Added ``system.getStackTrace``. +- Added ``system.||`` for parallel for loop support. - The GC supports (soft) realtime systems via ``GC_setMaxPause`` and ``GC_step`` procs. @@ -84,6 +85,7 @@ Compiler Additions option or pragma. - The compiler now generates marker procs that the GC can use instead of RTTI. This speeds up the GC quite a bit. +- The compiler now supports OpenMP's parallel for loop. Language Additions