Skip to content

Commit

Permalink
codegen: don't use PSym for locals (#914)
Browse files Browse the repository at this point in the history
## Summary

Use a dedicated intermediate representation for local `var`/`let`,
parameters, and the result variable in the code generator IR.

This is the first step towards removing all `PSym` usage from the
backend/code-generators. The goal is to further decouple `sem` from the
code generators, making it possible evolve both (especially their IRs)
more independently from each other.

## Details

### General design

* `cgir.Local` stores all relevant information about a local  
* the information about all locals is owned by and stored as part of
  `Body`
* a local is referenced from the `CgNode` IR via the `cnkLocal` node,
  which stores a `LocalId` value
* the result variable and parameters are also treated as locals.
  In most cases, they don't require any extra handling, so them having
  their own data types and node kinds would only complicate things
* for simplicity, for the `Body` of a procedure, the first local slot is
  always reserved for the result variable, even if the procedure has no
  return type. At least for now, this approach makes it easier to
  ad-hoc compute the IDs for parameters from just their position, which
  is still needed in some cases

In terms of data representation, a `Local` stores the type, alignment,
flags (currently still `TSymFlags`), and the name (which may be unset).
Unlike the MIR, no special distinction is made between temporaries and
user-defined locals.

In addition, `Local` also stores whether the corresponding user-defined
local is immutable (the `isImmutable` field). This additional
information is meant to help the code generators optimize: for example, 
the JavaScript code generator doesn't use indirection for `let` locals,
even if they have their address taken.

For extending the data about locals, each code generator uses an
`OrdinalSeq[LocalId, T]` where `T` is a data type tailored to the needs
of the respective code generator. This data-oriented design allows for
easy extension without having to modify the base IR itself.

### Overview of the changes

All places where `cnkSym` nodes were previously handled are adjusted to
also handle `cnkLocal` nodes. This usually means moving the local/
parameter/result specific handling to a new `cnkLocal` branch.

Merging two bodies (`cgir.merge`) also has to take locals into account:
the list with the locals from the source body is appended to that of the
destination body, and the `cnkLocal` node in the merged source body are
updated.

The code generators (`cgen` and `jsgen`) that support incremental code-
generation for procedures need to synchronize their `OrdinalSeq` with
the body's `Store`, after a partial procedure was updated. For this
purpose, the relevant code generators are extended with the `genPartial`
procedure.

### Changes to `CgNode` rendering

* in order to properly render locals, `cgirutils.render` now requires a
  `Body` instead of only a `CgNode`
* the name disambiguation logic is generalized to support disambiguating
  the names of `PSym`- and `Local`-based symbols (through use of the new
  internal `Symbol` type)

In the output, compiler-inserted locals are now rendered as
`:aux_$LocalId` (auxiliary local) instead of `:tmp_$id`. The
`--expandArc`-using tests are adjusted accordingly.

### Initialization of `Local`s

The setup of the `Local` data for a `Body` happens in `cgirgen`:
* locals reach `cgirgen` as `PSym`s, meaning that they need to be
  translated. When appearing in 'def's, the symbol of a local is
  translated to a `Local`, a `LocalId` is allocated, and a mapping
  between the `PSym` and `LocalId` is established (via the `localsMap`)
* for procedures, `generateIR` is responsible for setting up the
  `Local`s representing the result variable and parameters
* special handling is required for `except T as e`, where `T` is an
  imported exception type: these also act as definitions of new locals

Creating or translating temporaries no longer requires creating new
`PSym`s, which also means that there's one less source of `IdGenerator`
interaction in `cgirgen`. The `IdGenerator`s should ideally be sealed at
the end of semantic analysis, and this is a step towardst this goal.

### C code-generator changes

* instead of in a `SymbolMap`, the `TLoc` for locals is stored in
  an `OrdinalSeq`
* the special handling to account for definitions of locals being
  visited multiple times for `.inline` procedures becomes obsolete and
  is removed
* `cnkLocal` nodes cannot appear in construction expressions, and
  they thus don't need special handling in `hashTree`
* testing whether a local location is uninitialized no longer relies on
  `TSym.locId`; inspect the `TLoc.k` value is enough (`locEmpty`
  signals an empty/uninitialized location)
* for detecting parameters, `reifiedOpenArray` now requires access to
  a `BProc` instance
* for detecting parameters, the `mapTypeChooser` template accepting a
  `CgNode` also requires access to a `BProc` instance
* the dispatching based on the specific symbol kind (`skParam`,
  `skTemp`, `skResult`, etc.) becomes obsolete and is removed
* the parameter and result variable setup in `cgen.startProc` is
  adjusted
* the separate handling of parameters when writing NDI files is
  removed; parameters are part of the locals now
* checking for `skTemp` symbols when writing NDI files is also not
  necessary anymore: it is replaced with checking whether the local has
  both a user-provided *and* mangled name.

Name mangling for locals with user-provided names stays the same, but
for locals without user-defined names, an underscore (`_`) plus the
stringified integer value of the `LocalId` is now used. Within a
single procedure, this simple mangling guarantees unique identifiers.

Because parameters cannot easily be distinguished from other locals,
`compat.isLvalue` now always treats them as l-values. This only affects
the code generated (without impacting observable behaviour) for object
up- and down-conversion.

### JS code-generator changes

* the new `Loc` type represents the code-generator's state for a local.
  It is made up of the mangled name and the location's storage
  description
* in order to free up the name, the `locals` field in `TProc` is renamed
  to `defs`
* `Loc` is intended to be eventually used for globals and constants too
* computing the storage mode once (`StorageFlags`) and then storing the
  result in `Loc` is simpler than storing the symbol flags and kind and
  recomputing the storage mode on each query
* `Loc`s for locals are initialized (via `setupLocalLoc`) when a
  *definition* statement is encountered: these are currently 'def' nodes
  and 'except' branches for imported exceptions
* since `storage` relies on this information, a symbol kind has to be
  passed to `setupLocalLoc`
* `genSymAddr` is restructured into the generic `addrLoc`, which works
  with both `Loc` and `PSym`
* the core part of `genSym` is extracted into the generic `accessLoc`,
  which works with both `Loc` and `PSym`
* the interface of `genVarInit` is adjusted to work for both `Loc` and
  `PSym`

Once `Loc` is used for all location in the JS code generator, the
compatibility and adapter routines can be removed.

### VM code-generator changes

* the new `LocalLoc` type represents the code-generator's state for a
  local. The type replaces the symbol-id-to-register table (`locals`)
  and the `addressTaken` set
* parameter setup (`genParams`) becomes simpler: no special handling
  for the result variable and environment parameter is needed anymore
* `genSymAsgn` is split into `genAsgnToLocal` and `genAsgnToGlobal`
* to reduce the amount of required changes, `genSym` and `genSymAddr`
  still support locals for now. This should be cleaned up separately
  • Loading branch information
zerbina authored Sep 22, 2023
1 parent 37263e3 commit 54d372c
Show file tree
Hide file tree
Showing 20 changed files with 773 additions and 564 deletions.
17 changes: 7 additions & 10 deletions compiler/backend/cbackend.nim
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,12 @@ func hash(x: PSym): int = hash(x.id)

proc writeMangledLocals(p: BProc) =
## Writes the mangled names of `p`'s locals to the module's NDI file.
for it in p.locals.items:
# writing out mangled names for compiler-inserted variables (temporaries)
# is not necessary (lode is guaranteed to be a symbol)
if it.lode.sym.kind != skTemp:
writeMangledName(p.module.ndi, it.lode.sym, it.r, p.config)
for i, it in p.locals.pairs:
# only write a mapping for locals that have both a user-provided
# and mangled name (compile-time-only parameters don't have one)
if p.body[i].name != nil and it.r.len > 0:
writeMangledName(p.module.ndi, it.lode.info, p.body[i].name, it.r,
p.config)

func registerInline(g: var InliningData, prc: PSym): uint32 =
## If not already registered, registers the inline procedure `prc` with
Expand Down Expand Up @@ -228,7 +229,7 @@ proc processEvent(g: BModuleList, inl: var InliningData, discovery: var Discover

let body = generateIR(g.graph, bmod.idgen, evt.sym, evt.body)
# emit into the procedure:
genStmts(p, merge(p.body, body))
genPartial(p, merge(p.body, body))

processLate(bmod, discovery, inl, evt.module, inlineId)
of bekProcedure:
Expand Down Expand Up @@ -416,10 +417,6 @@ proc generateCode*(graph: ModuleGraph, g: BModuleList, mlist: sink ModuleList) =
s = it.sym
m = g.modules[moduleId(s)]
writeMangledName(m.ndi, s, it.name, g.config)
# parameters:
for p in it.params.items:
if p.k != locNone: # not all parameters have locs
writeMangledName(m.ndi, s, p.r, g.config)

template write(loc: TLoc) =
let s = loc.lode.sym
Expand Down
29 changes: 14 additions & 15 deletions compiler/backend/ccgcalls.nim
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ proc reportObservableStore(p: BProc; le, ri: CgNode) =
# do NOT follow ``cnkDerefView`` here!
case n.kind
of cnkSym:
# we don't own the location so it escapes:
if n.sym.owner != p.prc:
return true
elif inTryStmt and sfUsedInFinallyOrExcept in n.sym.flags:
# it is also an observable store if the location is used
# in 'except' or 'finally'
return true
return false
# this must be a global -> the mutation escapes
return true
of cnkLocal:
# if the local is used within an 'except' or 'finally', a mutation of
# it through a procedure that eventually raises is also an observable
# store
return inTryStmt and sfUsedInFinallyOrExcept in p.body[n.local].flags
of cnkFieldAccess, cnkBracketAccess, cnkCheckedFieldAccess:
n = n[0]
of cnkObjUpConv, cnkObjDownConv, cnkHiddenConv, cnkConv:
Expand Down Expand Up @@ -134,11 +133,11 @@ proc fixupCall(p: BProc, le, ri: CgNode, d: var TLoc,

proc genBoundsCheck(p: BProc; arr, a, b: TLoc)

proc reifiedOpenArray(n: CgNode): bool {.inline.} =
proc reifiedOpenArray(p: BProc, n: CgNode): bool {.inline.} =
var x = n
while x.kind in {cnkAddr, cnkHiddenAddr, cnkHiddenConv, cnkDerefView}:
x = x.operand
if x.kind == cnkSym and x.sym.kind == skParam:
if x.kind == cnkLocal and p.locals[x.local].k == locParam:
result = false
else:
result = true
Expand All @@ -165,7 +164,7 @@ proc genOpenArraySlice(p: BProc; q: CgNode; formalType, destType: PType): (Rope,
[rdLoc(a), rdLoc(b), intLiteral(first), dest],
lengthExpr)
of tyOpenArray, tyVarargs:
if reifiedOpenArray(q[1]):
if reifiedOpenArray(p, q[1]):
result = ("($3*)($1.Field0)+($2)" % [rdLoc(a), rdLoc(b), dest],
lengthExpr)
else:
Expand Down Expand Up @@ -208,7 +207,7 @@ proc openArrayLoc(p: BProc, formalType: PType, n: CgNode): Rope =
initLocExpr(p, if n.kind == cnkHiddenConv: n.operand else: n, a)
case skipTypes(a.t, abstractVar+{tyStatic}).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(n):
if reifiedOpenArray(p, n):
result = "$1.Field0, $1.Field1" % [rdLoc(a)]
else:
result = "$1, $1Len_0" % [rdLoc(a)]
Expand Down Expand Up @@ -368,9 +367,9 @@ proc genClosureCall(p: BProc, le, ri: CgNode, d: var TLoc) =
genCallPattern()
exitCall(p, ri[0], canRaise)

proc notYetAlive(n: CgNode): bool {.inline.} =
proc notYetAlive(p: BProc, n: CgNode): bool {.inline.} =
let r = getRoot(n)
result = r != nil and r.locId == 0
result = r != nil and r.kind == cnkLocal and p.locals[r.local].k == locNone

proc isInactiveDestructorCall(p: BProc, e: CgNode): bool =
#[ Consider this example.
Expand All @@ -390,7 +389,7 @@ proc isInactiveDestructorCall(p: BProc, e: CgNode): bool =
the 'let args = ...' statement. We exploit this to generate better
code for 'return'. ]#
result = e.len == 2 and e[0].kind == cnkSym and
e[0].sym.name.s == "=destroy" and notYetAlive(e[1].operand)
e[0].sym.name.s == "=destroy" and notYetAlive(p, e[1].operand)

proc genAsgnCall(p: BProc, le, ri: CgNode, d: var TLoc) =
if p.withinBlockLeaveActions > 0 and isInactiveDestructorCall(p, ri):
Expand Down
43 changes: 14 additions & 29 deletions compiler/backend/ccgexprs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ proc genOpenArrayConv(p: BProc; d: TLoc; a: TLoc) =

case a.t.skipTypes(abstractVar).kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(a.lode):
if reifiedOpenArray(p, a.lode):
linefmt(p, cpsStmts, "$1.Field0 = $2.Field0; $1.Field1 = $2.Field1;$n",
[rdLoc(d), a.rdLoc])
else:
Expand Down Expand Up @@ -177,7 +177,7 @@ proc genAssignment(p: BProc, dest, src: TLoc) =
# HACK: ``cgirgen`` elides to-openArray-conversion operations, so we
# need to reconstruct that information here. Remove this case
# once ``cgirgen`` no longer elides the operations
if reifiedOpenArray(dest.lode):
if reifiedOpenArray(p, dest.lode):
genOpenArrayConv(p, dest, src)
else:
linefmt(p, cpsStmts, "$1 = $2;$n", [rdLoc(dest), rdLoc(src)])
Expand Down Expand Up @@ -486,7 +486,7 @@ proc unaryArith(p: BProc, e: CgNode, d: var TLoc, op: TMagic) =
proc genDeref(p: BProc, e: CgNode, d: var TLoc) =
let
src = e.operand
mt = mapType(p.config, src.typ, mapTypeChooser(src))
mt = mapType(p.config, src.typ, mapTypeChooser(p, src))
if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags:
# XXX the amount of hacks for C's arrays is incredible, maybe we should
# simply wrap them in a struct? --> Losing auto vectorization then?
Expand Down Expand Up @@ -528,7 +528,7 @@ proc genDeref(p: BProc, e: CgNode, d: var TLoc) =
putIntoDest(p, d, e, "(*$1)" % [rdLoc(a)], a.storage)

proc genAddr(p: BProc, e: CgNode, mutate: bool, d: var TLoc) =
if mapType(p.config, e.operand.typ, mapTypeChooser(e.operand)) == ctArray:
if mapType(p.config, e.operand.typ, mapTypeChooser(p, e.operand)) == ctArray:
expr(p, e.operand, d)
else:
var a: TLoc
Expand Down Expand Up @@ -736,7 +736,7 @@ proc genBoundsCheck(p: BProc; arr, a, b: TLoc) =
let ty = skipTypes(arr.t, abstractVarRange)
case ty.kind
of tyOpenArray, tyVarargs:
if reifiedOpenArray(arr.lode):
if reifiedOpenArray(p, arr.lode):
linefmt(p, cpsStmts,
"if ($2-$1 != -1 && " &
"((NU)($1) >= (NU)($3.Field1) || (NU)($2) >= (NU)($3.Field1))){ #raiseIndexError(); $4}$n",
Expand All @@ -763,7 +763,7 @@ proc genOpenArrayElem(p: BProc, n, x, y: CgNode, d: var TLoc) =
var a, b: TLoc
initLocExpr(p, x, a)
initLocExpr(p, y, b)
if not reifiedOpenArray(x):
if not reifiedOpenArray(p, x):
# emit range check:
if optBoundsCheck in p.options:
linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len_0)){ #raiseIndexError2($1,$2Len_0-1); $3}$n",
Expand Down Expand Up @@ -1326,7 +1326,7 @@ proc genArrayLen(p: BProc, e: CgNode, d: var TLoc, op: TMagic) =
else:
putIntoDest(p, d, e, ropecg(p.module, "($2)-($1)+1", [rdLoc(b), rdLoc(c)]))
else:
if not reifiedOpenArray(a):
if not reifiedOpenArray(p, a):
if op == mHigh: unaryExpr(p, e, d, "($1Len_0-1)")
else: unaryExpr(p, e, d, "$1Len_0")
else:
Expand Down Expand Up @@ -1687,7 +1687,7 @@ proc skipAddr(n: CgNode): CgNode =
proc genWasMoved(p: BProc; n: CgNode) =
var a: TLoc
let n1 = n[1].skipAddr
if p.withinBlockLeaveActions > 0 and notYetAlive(n1):
if p.withinBlockLeaveActions > 0 and notYetAlive(p, n1):
discard
else:
initLocExpr(p, n1, a)
Expand Down Expand Up @@ -2107,8 +2107,8 @@ proc expr(p: BProc, n: CgNode, d: var TLoc) =
useConst(p.module, sym)
putLocIntoDest(p, d, p.module.consts[sym])
of skVar, skForVar, skLet:
if {sfGlobal, sfThread} * sym.flags != {}:
genVarPrototype(p.module, n)
assert sfGlobal in sym.flags
genVarPrototype(p.module, n)

if sfThread in sym.flags:
accessThreadLocalVar(p, sym)
Expand All @@ -2117,26 +2117,11 @@ proc expr(p: BProc, n: CgNode, d: var TLoc) =
putIntoDest(p, d, loc.lode, "NimTV_->" & loc.r)
else:
putLocIntoDest(p, d, p.module.globals[sym])
elif sfGlobal in sym.flags:
putLocIntoDest(p, d, p.module.globals[sym])
else: # must be a local then
putLocIntoDest(p, d, p.locals[sym])
of skResult:
# the 'result' location is either a parameter or local
if p.params[0].k != locNone:
putLocIntoDest(p, d, p.params[0])
else:
putLocIntoDest(p, d, p.locals[sym])
of skTemp:
putLocIntoDest(p, d, p.locals[sym])
of skParam:
if sym.position + 1 < p.params.len:
putLocIntoDest(p, d, p.params[sym.position + 1])
else:
# must be the hidden environment parameter (which is treated as a
# local)
putLocIntoDest(p, d, p.locals[sym])
putLocIntoDest(p, d, p.module.globals[sym])
else: internalError(p.config, n.info, "expr(" & $sym.kind & "); unknown symbol")
of cnkLocal:
putLocIntoDest(p, d, p.locals[n.local])
of cnkStrLit:
putDataIntoDest(p, d, n, genLiteral(p, n))
of cnkIntLit, cnkUIntLit, cnkFloatLit, cnkNilLit:
Expand Down Expand Up @@ -2202,7 +2187,7 @@ proc expr(p: BProc, n: CgNode, d: var TLoc) =
of cnkClosureConstr: genClosure(p, n, d)
of cnkEmpty: discard
of cnkRepeatStmt: genRepeatStmt(p, n)
of cnkDef: genDef(p, n)
of cnkDef: genSingleVar(p, n[0], n[1])
of cnkCaseStmt: genCase(p, n)
of cnkReturnStmt: genReturnStmt(p, n)
of cnkBreakStmt: genBreakStmt(p, n)
Expand Down
31 changes: 13 additions & 18 deletions compiler/backend/ccgstmts.nim
Original file line number Diff line number Diff line change
Expand Up @@ -155,31 +155,22 @@ proc genGotoVar(p: BProc; value: CgNode) =

proc genBracedInit(p: BProc, n: CgNode; isConst: bool; optionalType: PType): Rope

proc genSingleVar(p: BProc, v: PSym; vn, value: CgNode) =
if sfGoto in v.flags:
proc genSingleVar(p: BProc, vn, value: CgNode) =
## Generates and emits the C code for the definition statement of a local.
let v = vn.local

if sfGoto in p.body[v].flags:
# translate 'var state {.goto.} = X' into 'goto LX':
genGotoVar(p, value)
return

assert {sfGlobal, sfThread} * v.flags == {}
let imm = isAssignedImmediately(p.config, value)
assignLocalVar(p, vn)
initLocalVar(p, v, imm)

if value.kind != cnkEmpty:
genLineDir(p, vn)
# we have a parameter aliasing issue here: passing `p.locals[v]`
# as the parameter directly would be an aliasing rule violation.
# Since the initializer expression cannot reference `v` itself,
# it's safe to temporarily move the loc out of ``p.locals``
var loc = move p.locals[v]
loadInto(p, vn, value, loc)
p.locals.assign(v, loc) # put it back

proc genDef(p: BProc, a: CgNode) =
assert a.kind == cnkDef
let v = a[0].sym
genSingleVar(p, v, a[0], a[1])
loadInto(p, vn, value, p.locals[v])

proc genIf(p: BProc, n: CgNode) =
# if (expr1)
Expand Down Expand Up @@ -595,7 +586,7 @@ proc genCase(p: BProc, t: CgNode) =
genCaseGeneric(p, t, "if ($1 >= $2 && $1 <= $3) goto $4;$n",
"if ($1 == $2) goto $3;$n")
else:
if t[0].kind == cnkSym and sfGoto in t[0].sym.flags:
if t[0].kind == cnkLocal and sfGoto in p.body[t[0].local].flags:
genGotoForCase(p, t)
else:
genOrdinalCase(p, t)
Expand Down Expand Up @@ -725,7 +716,7 @@ proc genAsmOrEmitStmt(p: BProc, t: CgNode, isAsmStmt=false): Rope =
var a: TLoc
initLocExpr(p, it, a)
res.add(rdLoc(a))
of skVar, skLet, skForVar, skParam, skResult, skTemp:
of skVar, skLet, skForVar:
# make sure the C type description is available:
discard getTypeDesc(p.module, skipTypes(sym.typ, abstractPtrs))
var a: TLoc
Expand All @@ -741,6 +732,10 @@ proc genAsmOrEmitStmt(p: BProc, t: CgNode, isAsmStmt=false): Rope =
res.add(p.fieldName(sym))
else:
unreachable(sym.kind)
of cnkLocal:
# make sure the C type description is available:
discard getTypeDesc(p.module, skipTypes(it.typ, abstractPtrs))
res.add(rdLoc(p.locals[it.local]))
of cnkType:
res.add(getTypeDesc(p.module, it.typ))
else:
Expand Down Expand Up @@ -825,7 +820,7 @@ proc asgnFieldDiscriminant(p: BProc, e: CgNode) =
genAssignment(p, a, tmp)

proc genAsgn(p: BProc, e: CgNode) =
if e[0].kind == cnkSym and sfGoto in e[0].sym.flags:
if e[0].kind == cnkLocal and sfGoto in p.body[e[0].local].flags:
genLineDir(p, e)
genGotoVar(p, e[1])
elif optFieldCheck in p.options and isDiscriminantField(e[0]):
Expand Down
29 changes: 14 additions & 15 deletions compiler/backend/ccgtypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -53,27 +53,26 @@ proc mangleParamName(c: ConfigRef; s: PSym): Rope =

result = res.rope

proc mangleLocalName(p: BProc; s: PSym): Rope =
assert s.kind in skLocalVars+{skTemp}
#assert sfGlobal notin s.flags
if true:
var key: string
shallowCopy(key, s.name.s.mangle)
proc mangleLocalName(p: BProc; name: PIdent, id: LocalId): Rope =
if name.isNil:
# use the ID prefixed by an underscore, which is guaranteed to be a unique
# name within the procedure
result = "_" & $id.int
else:
# mangle the user-defiend name, also accounting for shadowed names
var key = name.s.mangle
let counter = p.sigConflicts.getOrDefault(key)
result = key.rope
if s.kind == skTemp:
# speed up conflict search for temps (these are quite common):
if counter != 0: result.add "_" & rope(counter+1)
elif counter != 0 or isKeyword(s.name) or p.module.g.config.cppDefines.contains(key):
result = key
if counter != 0 or isKeyword(name) or p.module.g.config.cppDefines.contains(key):
result.add "_" & rope(counter+1)
p.sigConflicts.inc(key)

proc scopeMangledParam(p: BProc; param: PSym) =
proc scopeMangledParam(p: BProc; name: PIdent) =
## parameter generation doesn't have access to a ``BProc``, so we have to
## remember these parameter names are already in scope to be able to
## generate unique identifiers reliably (consider that ``var a = a`` is
## even an idiom in Nim).
var key = param.name.s.mangle
var key = name.s.mangle
p.sigConflicts.inc(key)

const
Expand Down Expand Up @@ -205,7 +204,7 @@ proc addAbiCheck(m: BModule, t: PType, name: Rope) =

proc initResultParamLoc(conf: ConfigRef; param: CgNode): TLoc =
result = initLoc(locParam, param, "Result", OnStack)
let t = param.sym.typ
let t = param.typ
if mapReturnType(conf, t) != ctArray and isInvalidReturnType(conf, t):
incl(result.flags, lfIndirect)
result.storage = OnUnknown
Expand Down Expand Up @@ -369,7 +368,7 @@ proc prepareParameters(m: BModule, t: PType): seq[TLoc] =
else:
OnStack

result[i] = initLoc(locParam, toSymNode(params[i]),
result[i] = initLoc(locParam, newLocalRef(LocalId(i), param.info, param.typ),
mangleParamName(m.config, param), storage)

if ccgIntroducedPtr(m.config, param, t[0]):
Expand Down
Loading

0 comments on commit 54d372c

Please sign in to comment.