From 50b6f6996ab604931d8ee7ca2a26bfdce5559933 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Mon, 28 Sep 2020 13:51:39 +0200 Subject: [PATCH] .noalias annotation; frontend support (#15419) * .noalias annotation; frontend support * added .noalias support to Nim; implements https://github.com/nim-lang/RFCs/issues/204 --- changelog.md | 5 ++++- compiler/ast.nim | 5 +++-- compiler/ccgtypes.nim | 2 ++ compiler/cgen.nim | 3 +++ compiler/pragmas.nim | 8 ++++++-- compiler/semtypes.nim | 10 ++++++---- compiler/wordrecg.nim | 4 ++-- doc/manual_experimental.rst | 15 +++++++++++++++ lib/impure/nre.nim | 2 +- lib/nimbase.h | 3 +++ tests/ccgbugs/tnoalias.nim | 8 ++++++++ 11 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 tests/ccgbugs/tnoalias.nim diff --git a/changelog.md b/changelog.md index bd5674610..fffcdcb35 100644 --- a/changelog.md +++ b/changelog.md @@ -195,7 +195,7 @@ is cool! """ - ``` + ``` - Add `initUri(isIpv6: bool)` to `uri` module, now `uri` supports parsing ipv6 hostname. @@ -283,6 +283,9 @@ proc mydiv(a, b): int {.raises: [].} = an experimental feature. In other words, you don't have to write pragma `{.experimental: "forLoopMacros".}` if you want to use them. +- Added a ``.noalias`` pragma. It is mapped to C's ``restrict`` keyword for the increased + performance this keyword can enable. + ## Compiler changes diff --git a/compiler/ast.nim b/compiler/ast.nim index 4d37b284c..6bcc6845d 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -229,7 +229,7 @@ type TNodeKinds* = set[TNodeKind] type - TSymFlag* = enum # 43 flags! + TSymFlag* = enum # 46 flags! sfUsed, # read access of sym (for warnings) or simply used sfExported, # symbol is exported from module sfFromGeneric, # symbol is instantiation of a generic; this is needed @@ -293,7 +293,8 @@ type sfNeverRaises # proc can never raise an exception, not even OverflowDefect # or out-of-memory sfUsedInFinallyOrExcept # symbol is used inside an 'except' or 'finally' - sfSingleUsedTemp # For temporaries that we know will only be used once + sfSingleUsedTemp # For temporaries that we know will only be used once + sfNoalias # 'noalias' annotation, means C's 'restrict' TSymFlags* = set[TSymFlag] diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim index 8dee6ee70..ff7b17590 100644 --- a/compiler/ccgtypes.nim +++ b/compiler/ccgtypes.nim @@ -474,6 +474,8 @@ proc genProcParams(m: BModule, t: PType, rettype, params: var Rope, else: params.add(getTypeDescAux(m, param.typ, check, skParam)) params.add(~" ") + if sfNoalias in param.flags: + params.add(~"NIM_NOALIAS ") params.add(param.loc.r) # declare the len field for open arrays: var arr = param.typ diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 242d1f89b..f50676647 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -503,6 +503,7 @@ proc localVarDecl(p: BProc; n: PNode): Rope = #elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds: # decl.add(" GC_GUARD") if sfVolatile in s.flags: result.add(" volatile") + if sfNoalias in s.flags: result.add(" NIM_NOALIAS") result.add(" ") result.add(s.loc.r) else: @@ -563,6 +564,7 @@ proc assignGlobalVar(p: BProc, n: PNode; value: Rope) = if p.hcrOn: decl.add("*") if sfRegister in s.flags: decl.add(" register") if sfVolatile in s.flags: decl.add(" volatile") + if sfNoalias in s.flags: decl.add(" NIM_NOALIAS") if value != nil: decl.addf(" $1 = $2;$n", [s.loc.r, value]) else: @@ -1261,6 +1263,7 @@ proc genVarPrototype(m: BModule, n: PNode) = if lfDynamicLib in sym.loc.flags: m.s[cfsVars].add("*") if sfRegister in sym.flags: m.s[cfsVars].add(" register") if sfVolatile in sym.flags: m.s[cfsVars].add(" volatile") + if sfNoalias in sym.flags: m.s[cfsVars].add(" NIM_NOALIAS") m.s[cfsVars].addf(" $1;$n", [sym.loc.r]) if m.hcrOn: m.initProc.procSec(cpsLocals).addf( "\t$1 = ($2*)hcrGetGlobal($3, \"$1\");$n", [sym.loc.r, diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 71bd6f81f..3b7ae175d 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -65,14 +65,15 @@ const wInheritable, wGensym, wInject, wRequiresInit, wUnchecked, wUnion, wPacked, wBorrow, wGcSafe, wPartial, wExplain, wPackage} fieldPragmas* = declPragmas + { - wGuard, wBitsize, wCursor, wRequiresInit} - {wExportNims, wNodecl} # why exclude these? + wGuard, wBitsize, wCursor, wRequiresInit, wNoalias} - {wExportNims, wNodecl} # why exclude these? varPragmas* = declPragmas + {wVolatile, wRegister, wThreadVar, wMagic, wHeader, wCompilerProc, wCore, wDynlib, wNoInit, wCompileTime, wGlobal, - wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor} + wGensym, wInject, wCodegenDecl, wGuard, wGoto, wCursor, wNoalias} constPragmas* = declPragmas + {wHeader, wMagic, wGensym, wInject, wIntDefine, wStrDefine, wBoolDefine, wCompilerProc, wCore} + paramPragmas* = {wNoalias, wInject, wGensym} letPragmas* = varPragmas procTypePragmas* = {FirstCallConv..LastCallConv, wVarargs, wNoSideEffect, wThread, wRaises, wLocks, wTags, wGcSafe, @@ -864,6 +865,9 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int, of wRegister: noVal(c, it) incl(sym.flags, sfRegister) + of wNoalias: + noVal(c, it) + incl(sym.flags, sfNoalias) of wThreadVar: noVal(c, it) incl(sym.flags, {sfThread, sfGlobal}) diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim index 4d912a46f..9bb7673fa 100644 --- a/compiler/semtypes.nim +++ b/compiler/semtypes.nim @@ -1264,6 +1264,8 @@ proc semProcTypeNode(c: PContext, n, genericParams: PNode, for j in 0..