implements the 'codegenDecl' pragma

This commit is contained in:
Araq
2013-06-27 18:13:11 +02:00
parent 6d7ad66982
commit 139562cc64
7 changed files with 58 additions and 25 deletions

View File

@@ -278,8 +278,6 @@ const
# the compiler will avoid printing such names
# in user messages.
sfHoist* = sfVolatile ## proc return value can be hoisted
sfNoForward* = sfRegister
# forward declarations are not required (per module)
@@ -673,7 +671,9 @@ type
loc*: TLoc
annex*: PLib # additional fields (seldom used, so we use a
# reference to another object to safe space)
constraint*: PNode # additional constraints like 'lit|result'
constraint*: PNode # additional constraints like 'lit|result'; also
# misused for the codegenDecl pragma in the hope
# it won't cause problems
TTypeSeq* = seq[PType]
TType* {.acyclic.} = object of TIdObj # \

View File

@@ -651,7 +651,9 @@ proc finishTypeDescriptions(m: BModule) =
while i < len(m.typeStack):
discard getTypeDesc(m, m.typeStack[i])
inc(i)
template cgDeclFrmt*(s: PSym): string = s.constraint.strVal
proc genProcHeader(m: BModule, prc: PSym): PRope =
var
rettype, params: PRope
@@ -669,8 +671,12 @@ proc genProcHeader(m: BModule, prc: PSym): PRope =
genProcParams(m, prc.typ, rettype, params, check)
# careful here! don't access ``prc.ast`` as that could reload large parts of
# the object graph!
appf(result, "$1($2, $3)$4",
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r, params])
if prc.constraint.isNil:
appf(result, "$1($2, $3)$4",
[toRope(CallingConvToStr[prc.typ.callConv]), rettype, prc.loc.r,
params])
else:
result = ropef(prc.cgDeclFrmt, [rettype, prc.loc.r, params])
# ------------------ type info generation -------------------------------------

View File

@@ -488,12 +488,15 @@ proc assignLocalVar(p: BProc, s: PSym) =
fillLoc(s.loc, locLocalVar, s.typ, mangleName(s), OnStack)
if s.kind == skLet: incl(s.loc.flags, lfNoDeepCopy)
var decl = getTypeDesc(p.module, s.loc.t)
if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
if s.constraint.isNil:
if sfRegister in s.flags: app(decl, " register")
#elif skipTypes(s.typ, abstractInst).kind in GcTypeKinds:
# app(decl, " GC_GUARD")
if sfVolatile in s.flags or p.nestedTryStmts.len > 0:
app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
else:
decl = ropef(s.cgDeclFrmt & ";$n", decl, s.loc.r)
line(p, cpsLocals, decl)
localDebugInfo(p, s)
@@ -518,11 +521,17 @@ proc assignGlobalVar(p: BProc, s: PSym) =
if sfThread in s.flags:
declareThreadVar(p.module, s, sfImportc in s.flags)
else:
if sfImportc in s.flags: app(p.module.s[cfsVars], "extern ")
app(p.module.s[cfsVars], getTypeDesc(p.module, s.loc.t))
if sfRegister in s.flags: app(p.module.s[cfsVars], " register")
if sfVolatile in s.flags: app(p.module.s[cfsVars], " volatile")
appf(p.module.s[cfsVars], " $1;$n", [s.loc.r])
var decl: PRope = nil
var td = getTypeDesc(p.module, s.loc.t)
if s.constraint.isNil:
if sfImportc in s.flags: app(decl, "extern ")
app(decl, td)
if sfRegister in s.flags: app(decl, " register")
if sfVolatile in s.flags: app(decl, " volatile")
appf(decl, " $1;$n", [s.loc.r])
else:
decl = ropef(s.cgDeclFrmt & ";$n", td, s.loc.r)
app(p.module.s[cfsVars], decl)
if p.withinLoop > 0:
# fixes tests/run/tzeroarray:
resetLoc(p, s.loc)

View File

@@ -23,7 +23,7 @@ const
wMagic, wNosideEffect, wSideEffect, wNoreturn, wDynLib, wHeader,
wCompilerProc, wProcVar, wDeprecated, wVarargs, wCompileTime, wMerge,
wBorrow, wExtern, wImportCompilerProc, wThread, wImportCpp, wImportObjC,
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wHoist,
wNoStackFrame, wError, wDiscardable, wNoInit, wDestructor, wCodegenDecl,
wGenSym, wInject, wRaises, wTags}
converterPragmas* = procPragmas
methodPragmas* = procPragmas
@@ -56,7 +56,7 @@ const
varPragmas* = {wImportc, wExportc, wVolatile, wRegister, wThreadVar, wNodecl,
wMagic, wHeader, wDeprecated, wCompilerProc, wDynLib, wExtern,
wImportcpp, wImportobjc, wError, wNoInit, wCompileTime, wGlobal,
wGenSym, wInject}
wGenSym, wInject, wCodegenDecl}
constPragmas* = {wImportc, wExportc, wHeader, wDeprecated, wMagic, wNodecl,
wExtern, wImportcpp, wImportobjc, wError, wGenSym, wInject}
letPragmas* = varPragmas
@@ -147,7 +147,10 @@ proc expectIntLit(c: PContext, n: PNode): int =
proc getOptionalStr(c: PContext, n: PNode, defaultStr: string): string =
if n.kind == nkExprColonExpr: result = expectStrLit(c, n)
else: result = defaultStr
proc processCodegenDecl(c: PContext, n: PNode, sym: PSym) =
sym.constraint = getStrLitNode(c, n)
proc processMagic(c: PContext, n: PNode, s: PSym) =
#if sfSystemModule notin c.module.flags:
# liMessage(n.info, errMagicOnlyInSystem)
@@ -669,9 +672,7 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: int,
of wNoInit:
noVal(it)
if sym != nil: incl(sym.flags, sfNoInit)
of wHoist:
noVal(it)
if sym != nil: incl(sym.flags, sfHoist)
of wCodegenDecl: processCodegenDecl(c, it, sym)
of wChecks, wObjChecks, wFieldChecks, wRangechecks, wBoundchecks,
wOverflowchecks, wNilchecks, wAssertions, wWarnings, wHints,
wLinedir, wStacktrace, wLinetrace, wOptimization,

View File

@@ -62,7 +62,7 @@ type
wAcyclic, wShallow, wUnroll, wLinearScanEnd,
wWrite, wGensym, wInject, wDirty, wInheritable, wThreadVar, wEmit,
wNoStackFrame,
wImplicitStatic, wGlobal, wHoist,
wImplicitStatic, wGlobal, wCodegenDecl,
wAuto, wBool, wCatch, wChar, wClass,
wConst_cast, wDefault, wDelete, wDouble, wDynamic_cast,
@@ -142,7 +142,7 @@ const
"watchpoint",
"subschar", "acyclic", "shallow", "unroll", "linearscanend",
"write", "gensym", "inject", "dirty", "inheritable", "threadvar", "emit",
"nostackframe", "implicitstatic", "global", "hoist",
"nostackframe", "implicitstatic", "global", "codegendecl",
"auto", "bool", "catch", "char", "class",
"const_cast", "default", "delete", "double",

View File

@@ -399,6 +399,21 @@ interfacing with libraries written in Objective C:
The compiler needs to be told to generate Objective C (command ``objc``) for
this to work. The conditional symbol ``objc`` is defined when the compiler
emits Objective C code.
CodegenDecl pragma
------------------
The `codegenDecl`:idx: pragma can be used to directly influence Nimrod's code
generator. It receives a format string that determines how the variable or
proc is declared in the generated code:
.. code-block:: nimrod
var
a {.codegenDecl: "$# progmem $#".}: int
proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
echo "realistic interrupt handler"
LineDir option

View File

@@ -33,6 +33,8 @@ Compiler Additions
real uninitialized variables in Nimrod as they are initialized to binary
zero). Activate via ``{.warning[Uninit]:on.}``.
- The compiler now enforces the ``not nil`` constraint.
- The compiler now supports a ``codegenDecl`` pragma for even more control
over the generated code.
Language Additions