mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
NIR: progress (#22817)
Done: - [x] Implement conversions to openArray/varargs. - [x] Implement index/range checking.
This commit is contained in:
@@ -2157,7 +2157,7 @@ proc toHumanStr*(kind: TTypeKind): string =
|
||||
## strips leading `tk`
|
||||
result = toHumanStrImpl(kind, 2)
|
||||
|
||||
proc skipAddr*(n: PNode): PNode {.inline.} =
|
||||
proc skipHiddenAddr*(n: PNode): PNode {.inline.} =
|
||||
(if n.kind == nkHiddenAddr: n[0] else: n)
|
||||
|
||||
proc isNewStyleConcept*(n: PNode): bool {.inline.} =
|
||||
|
||||
@@ -2279,9 +2279,6 @@ proc binaryFloatArith(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
|
||||
else:
|
||||
binaryArith(p, e, d, m)
|
||||
|
||||
proc skipAddr(n: PNode): PNode =
|
||||
result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n
|
||||
|
||||
proc genWasMoved(p: BProc; n: PNode) =
|
||||
var a: TLoc
|
||||
let n1 = n[1].skipAddr
|
||||
|
||||
@@ -1162,7 +1162,7 @@ proc genProcAux*(m: BModule, prc: PSym) =
|
||||
var returnStmt: Rope = ""
|
||||
assert(prc.ast != nil)
|
||||
|
||||
var procBody = transformBody(m.g.graph, m.idgen, prc, dontUseCache)
|
||||
var procBody = transformBody(m.g.graph, m.idgen, prc, {})
|
||||
if sfInjectDestructors in prc.flags:
|
||||
procBody = injectDestructorCalls(m.g.graph, m.idgen, prc, procBody)
|
||||
|
||||
|
||||
@@ -2718,7 +2718,7 @@ proc genProc(oldProc: PProc, prc: PSym): Rope =
|
||||
else:
|
||||
returnStmt = "return $#;$n" % [a.res]
|
||||
|
||||
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, dontUseCache)
|
||||
var transformedBody = transformBody(p.module.graph, p.module.idgen, prc, {})
|
||||
if sfInjectDestructors in prc.flags:
|
||||
transformedBody = injectDestructorCalls(p.module.graph, p.module.idgen, prc, transformedBody)
|
||||
|
||||
|
||||
@@ -449,7 +449,7 @@ proc detectCapturedVars(n: PNode; owner: PSym; c: var DetectionPass) =
|
||||
if innerProc:
|
||||
if s.isIterator: c.somethingToDo = true
|
||||
if not c.processed.containsOrIncl(s.id):
|
||||
let body = transformBody(c.graph, c.idgen, s, useCache)
|
||||
let body = transformBody(c.graph, c.idgen, s, {useCache})
|
||||
detectCapturedVars(body, s, c)
|
||||
let ow = s.skipGenericOwner
|
||||
let innerClosure = innerProc and s.typ.callConv == ccClosure and not s.isIterator
|
||||
@@ -755,7 +755,7 @@ proc liftCapturedVars(n: PNode; owner: PSym; d: var DetectionPass;
|
||||
# echo renderTree(s.getBody, {renderIds})
|
||||
let oldInContainer = c.inContainer
|
||||
c.inContainer = 0
|
||||
var body = transformBody(d.graph, d.idgen, s, dontUseCache)
|
||||
var body = transformBody(d.graph, d.idgen, s, {})
|
||||
body = liftCapturedVars(body, s, d, c)
|
||||
if c.envVars.getOrDefault(s.id).isNil:
|
||||
s.transformedBody = body
|
||||
@@ -879,7 +879,7 @@ proc liftIterToProc*(g: ModuleGraph; fn: PSym; body: PNode; ptrType: PType;
|
||||
fn.typ.callConv = oldCC
|
||||
|
||||
proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
idgen: IdGenerator, force: bool): PNode =
|
||||
idgen: IdGenerator; flags: TransformFlags): PNode =
|
||||
# XXX backend == backendJs does not suffice! The compiletime stuff needs
|
||||
# the transformation even when compiling to JS ...
|
||||
|
||||
@@ -888,7 +888,7 @@ proc liftLambdas*(g: ModuleGraph; fn: PSym, body: PNode; tooEarly: var bool;
|
||||
|
||||
if body.kind == nkEmpty or (
|
||||
g.config.backend == backendJs and not isCompileTime) or
|
||||
(fn.skipGenericOwner.kind != skModule and not force):
|
||||
(fn.skipGenericOwner.kind != skModule and force notin flags):
|
||||
|
||||
# ignore forward declaration:
|
||||
result = body
|
||||
|
||||
@@ -45,6 +45,7 @@ type
|
||||
locGen: int
|
||||
m: ModuleCon
|
||||
prc: PSym
|
||||
options: TOptions
|
||||
|
||||
proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; module: PSym): ModuleCon =
|
||||
result = ModuleCon(graph: graph, types: initTypesCon(config), slotGenerator: new(int),
|
||||
@@ -61,7 +62,9 @@ proc initModuleCon*(graph: ModuleGraph; config: ConfigRef; idgen: IdGenerator; m
|
||||
result.nativeUIntId = UInt16Id
|
||||
|
||||
proc initProcCon*(m: ModuleCon; prc: PSym; config: ConfigRef): ProcCon =
|
||||
ProcCon(m: m, sm: initSlotManager({}, m.slotGenerator), prc: prc, config: config)
|
||||
ProcCon(m: m, sm: initSlotManager({}, m.slotGenerator), prc: prc, config: config,
|
||||
options: if prc != nil: prc.options
|
||||
else: config.options)
|
||||
|
||||
proc toLineInfo(c: var ProcCon; i: TLineInfo): PackedLineInfo =
|
||||
var val: LitId
|
||||
@@ -476,14 +479,21 @@ proc genField(c: var ProcCon; n: PNode; d: var Value) =
|
||||
d.addImmediateVal toLineInfo(c, n.info), pos
|
||||
|
||||
proc genIndex(c: var ProcCon; n: PNode; arr: PType; d: var Value) =
|
||||
let info = toLineInfo(c, n.info)
|
||||
if arr.skipTypes(abstractInst).kind == tyArray and
|
||||
(let x = firstOrd(c.config, arr); x != Zero):
|
||||
let info = toLineInfo(c, n.info)
|
||||
buildTyped d, info, Sub, c.m.nativeIntId:
|
||||
c.gen(n, d)
|
||||
d.addImmediateVal toLineInfo(c, n.info), toInt(x)
|
||||
else:
|
||||
c.gen(n, d)
|
||||
if optBoundsCheck in c.options:
|
||||
let idx = move d
|
||||
build d, info, CheckedIndex:
|
||||
copyTree d.Tree, idx
|
||||
let x = toInt64 lengthOrd(c.config, arr)
|
||||
d.Tree.addIntVal c.m.integers, info, c.m.nativeIntId, x
|
||||
d.Tree.addLabel info, CheckedGoto, c.exitLabel
|
||||
|
||||
proc genNew(c: var ProcCon; n: PNode; needsInit: bool) =
|
||||
# If in doubt, always follow the blueprint of the C code generator for `mm:orc`.
|
||||
@@ -586,6 +596,8 @@ proc genBinaryOp(c: var ProcCon; n: PNode; d: var Value; opc: Opcode) =
|
||||
let t = typeToIr(c.m.types, n.typ)
|
||||
template body(target) =
|
||||
buildTyped target, info, opc, t:
|
||||
if optOverflowCheck in c.options and opc in {CheckedAdd, CheckedSub, CheckedMul, CheckedDiv, CheckedMod}:
|
||||
c.code.addLabel info, CheckedGoto, c.exitLabel
|
||||
copyTree target, tmp
|
||||
copyTree target, tmp2
|
||||
intoDest d, info, t, body
|
||||
@@ -688,10 +700,16 @@ proc genUnaryMinus(c: var ProcCon; n: PNode; d: var Value) =
|
||||
c.freeTemp(tmp)
|
||||
|
||||
proc genHigh(c: var ProcCon; n: PNode; d: var Value) =
|
||||
let subOpr = createMagic(c.m.graph, c.m.idgen, "-", mSubI)
|
||||
let lenOpr = createMagic(c.m.graph, c.m.idgen, "len", mLengthOpenArray)
|
||||
let asLenExpr = subOpr.buildCall(lenOpr.buildCall(n[1]), nkIntLit.newIntNode(1))
|
||||
c.gen asLenExpr, d
|
||||
let info = toLineInfo(c, n.info)
|
||||
let t = typeToIr(c.m.types, n.typ)
|
||||
var x = default(Value)
|
||||
genArrayLen(c, n, x)
|
||||
template body(target) =
|
||||
buildTyped target, info, Sub, t:
|
||||
copyTree target, x
|
||||
target.addIntVal(c.m.integers, info, t, 1)
|
||||
intoDest d, info, t, body
|
||||
c.freeTemp x
|
||||
|
||||
proc genBinaryCp(c: var ProcCon; n: PNode; d: var Value; compilerProc: string) =
|
||||
let info = toLineInfo(c, n.info)
|
||||
@@ -1365,6 +1383,81 @@ proc genDefault(c: var ProcCon; n: PNode; d: var Value) =
|
||||
let m = expandDefault(n.typ, n.info)
|
||||
gen c, m, d
|
||||
|
||||
proc genWasMoved(c: var ProcCon; n: PNode) =
|
||||
let n1 = n[1].skipAddr
|
||||
# XXX We need a way to replicate this logic or better yet a better
|
||||
# solution for injectdestructors.nim:
|
||||
#if c.withinBlockLeaveActions > 0 and notYetAlive(n1):
|
||||
var d = c.genx(n1)
|
||||
assert not isEmpty(d)
|
||||
let m = expandDefault(n1.typ, n1.info)
|
||||
gen c, m, d
|
||||
|
||||
proc genMove(c: var ProcCon; n: PNode; d: var Value) =
|
||||
let info = toLineInfo(c, n.info)
|
||||
let n1 = n[1].skipAddr
|
||||
var a = c.genx(n1)
|
||||
if n.len == 4:
|
||||
# generated by liftdestructors:
|
||||
let src = c.genx(n[2])
|
||||
# if ($1.p == $2.p) goto lab1
|
||||
let lab1 = newLabel(c.labelGen)
|
||||
|
||||
let payloadType = seqPayloadPtrType(c.m.types, n1.typ)
|
||||
buildTyped c.code, info, Select, Bool8Id:
|
||||
buildTyped c.code, info, Eq, payloadType:
|
||||
buildTyped c.code, info, FieldAt, payloadType:
|
||||
copyTree c.code, a
|
||||
c.code.addImmediateVal info, 1 # (len, p)-pair
|
||||
buildTyped c.code, info, FieldAt, payloadType:
|
||||
copyTree c.code, src
|
||||
c.code.addImmediateVal info, 1 # (len, p)-pair
|
||||
|
||||
build c.code, info, SelectPair:
|
||||
build c.code, info, SelectValue:
|
||||
c.code.boolVal(info, true)
|
||||
c.code.gotoLabel info, Goto, lab1
|
||||
|
||||
gen(c, n[3])
|
||||
c.patch n, lab1
|
||||
|
||||
buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ):
|
||||
copyTree c.code, a
|
||||
copyTree c.code, src
|
||||
|
||||
else:
|
||||
if isEmpty(d): d = getTemp(c, n)
|
||||
buildTyped c.code, info, Asgn, typeToIr(c.m.types, n1.typ):
|
||||
copyTree c.code, d
|
||||
copyTree c.code, a
|
||||
var op = getAttachedOp(c.m.graph, n.typ, attachedWasMoved)
|
||||
if op == nil or skipTypes(n1.typ, abstractVar+{tyStatic}).kind in {tyOpenArray, tyVarargs}:
|
||||
let m = expandDefault(n1.typ, n1.info)
|
||||
gen c, m, a
|
||||
else:
|
||||
var opB = c.genx(newSymNode(op))
|
||||
buildTyped c.code, info, Call, typeToIr(c.m.types, n.typ):
|
||||
copyTree c.code, opB
|
||||
buildTyped c.code, info, AddrOf, ptrTypeOf(c.m.types.g, typeToIr(c.m.types, n1.typ)):
|
||||
copyTree c.code, a
|
||||
|
||||
proc genDestroy(c: var ProcCon; n: PNode) =
|
||||
let t = n[1].typ.skipTypes(abstractInst)
|
||||
case t.kind
|
||||
of tyString:
|
||||
var unused = default(Value)
|
||||
genUnaryCp(c, n, unused, "nimDestroyStrV1")
|
||||
of tySequence:
|
||||
#[
|
||||
var a = initLocExpr(c, arg)
|
||||
linefmt(c, cpsStmts, "if ($1.p && ($1.p->cap & NIM_STRLIT_FLAG) == 0) {$n" &
|
||||
" #alignedDealloc($1.p, NIM_ALIGNOF($2));$n" &
|
||||
"}$n",
|
||||
[rdLoc(a), getTypeDesc(c.module, t.lastSon)])
|
||||
]#
|
||||
globalError(c.config, n.info, "not implemented: =destroy for seqs")
|
||||
else: discard "nothing to do"
|
||||
|
||||
proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
|
||||
case m
|
||||
of mAnd: c.genAndOr(n, opcFJmp, d)
|
||||
@@ -1391,9 +1484,9 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
|
||||
of mNewString, mNewStringOfCap, mExit: c.genCall(n, d)
|
||||
of mLengthOpenArray, mLengthArray, mLengthSeq, mLengthStr:
|
||||
genArrayLen(c, n, d)
|
||||
of mMulI: genBinaryOp(c, n, d, Mul)
|
||||
of mDivI: genBinaryOp(c, n, d, Div)
|
||||
of mModI: genBinaryOp(c, n, d, Mod)
|
||||
of mMulI: genBinaryOp(c, n, d, CheckedMul)
|
||||
of mDivI: genBinaryOp(c, n, d, CheckedDiv)
|
||||
of mModI: genBinaryOp(c, n, d, CheckedMod)
|
||||
of mAddF64: genBinaryOp(c, n, d, Add)
|
||||
of mSubF64: genBinaryOp(c, n, d, Sub)
|
||||
of mMulF64: genBinaryOp(c, n, d, Mul)
|
||||
@@ -1495,7 +1588,6 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
|
||||
localError(c.config, n.info, sizeOfLikeMsg("offsetof"))
|
||||
of mRunnableExamples:
|
||||
discard "just ignore any call to runnableExamples"
|
||||
of mDestroy, mTrace: discard "ignore calls to the default destructor"
|
||||
of mOf: genOf(c, n, d)
|
||||
of mAppendStrStr:
|
||||
unused(c, n, d)
|
||||
@@ -1522,49 +1614,23 @@ proc genMagic(c: var ProcCon; n: PNode; d: var Value; m: TMagic) =
|
||||
of mConStrStr: genStrConcat(c, n, d)
|
||||
of mDefault, mZeroDefault:
|
||||
genDefault c, n, d
|
||||
of mMove: genMove(c, n, d)
|
||||
of mWasMoved, mReset:
|
||||
unused(c, n, d)
|
||||
genWasMoved(c, n)
|
||||
of mDestroy: genDestroy(c, n)
|
||||
#of mAccessEnv: unaryExpr(d, n, d, "$1.ClE_0")
|
||||
#of mAccessTypeField: genAccessTypeField(c, n, d)
|
||||
#of mSlice: genSlice(c, n, d)
|
||||
of mTrace: discard "no code to generate"
|
||||
else:
|
||||
# mGCref, mGCunref,
|
||||
# mGCref, mGCunref: unused by ORC
|
||||
globalError(c.config, n.info, "cannot generate code for: " & $m)
|
||||
|
||||
#[
|
||||
|
||||
of mReset:
|
||||
unused(c, n, d)
|
||||
var d = c.genx(n[1])
|
||||
# XXX use ldNullOpcode() here?
|
||||
c.gABx(n, opcLdNull, d, c.genType(n[1].typ))
|
||||
c.gABC(n, opcNodeToReg, d, d)
|
||||
c.gABx(n, ldNullOpcode(n.typ), d, c.genType(n.typ))
|
||||
|
||||
of mConStrStr: genVarargsABC(c, n, d, opcConcatStr)
|
||||
|
||||
of mRepr: genUnaryABC(c, n, d, opcRepr)
|
||||
|
||||
of mSlice:
|
||||
var
|
||||
d = c.genx(n[1])
|
||||
left = c.genIndex(n[2], n[1].typ)
|
||||
right = c.genIndex(n[3], n[1].typ)
|
||||
if isEmpty(d): d = c.getTemp(n)
|
||||
c.gABC(n, opcNodeToReg, d, d)
|
||||
c.gABC(n, opcSlice, d, left, right)
|
||||
c.freeTemp(left)
|
||||
c.freeTemp(right)
|
||||
c.freeTemp(d)
|
||||
|
||||
of mMove:
|
||||
let arg = n[1]
|
||||
let a = c.genx(arg)
|
||||
if isEmpty(d): d = c.getTemp(arg)
|
||||
gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), d, a)
|
||||
c.freeTemp(a)
|
||||
of mDup:
|
||||
let arg = n[1]
|
||||
let a = c.genx(arg)
|
||||
if isEmpty(d): d = c.getTemp(arg)
|
||||
gABC(c, arg, whichAsgnOpc(arg, requiresCopy=false), d, a)
|
||||
c.freeTemp(a)
|
||||
|
||||
of mNodeId:
|
||||
c.genUnaryABC(n, d, opcNodeId)
|
||||
|
||||
@@ -1764,6 +1830,63 @@ proc genDeref(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
|
||||
valueIntoDest c, info, d, n.typ, body
|
||||
freeTemp c, tmp
|
||||
|
||||
proc addAddrOfFirstElem(c: var ProcCon; target: var Tree; info: PackedLineInfo; tmp: Value; typ: PType) =
|
||||
let arrType = typ.skipTypes(abstractVar)
|
||||
let elemType = arrayPtrTypeOf(c.m.types.g, typeToIr(c.m.types, arrType.lastSon))
|
||||
case arrType.kind
|
||||
of tyString:
|
||||
let t = typeToIr(c.m.types, typ.lastSon)
|
||||
target.addImmediateVal info, 0
|
||||
buildTyped target, info, AddrOf, elemType:
|
||||
buildTyped target, info, ArrayAt, t:
|
||||
buildTyped target, info, FieldAt, strPayloadPtrType(c.m.types):
|
||||
copyTree target, tmp
|
||||
target.addImmediateVal info, 1 # (len, p)-pair
|
||||
target.addIntVal c.m.integers, info, c.m.nativeIntId, 0
|
||||
# len:
|
||||
target.addImmediateVal info, 1
|
||||
buildTyped target, info, FieldAt, c.m.nativeIntId:
|
||||
copyTree target, tmp
|
||||
target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
|
||||
|
||||
of tySequence:
|
||||
let t = typeToIr(c.m.types, typ.lastSon)
|
||||
target.addImmediateVal info, 0
|
||||
buildTyped target, info, AddrOf, elemType:
|
||||
buildTyped target, info, ArrayAt, t:
|
||||
buildTyped target, info, FieldAt, seqPayloadPtrType(c.m.types, typ):
|
||||
copyTree target, tmp
|
||||
target.addImmediateVal info, 1 # (len, p)-pair
|
||||
target.addIntVal c.m.integers, info, c.m.nativeIntId, 0
|
||||
# len:
|
||||
target.addImmediateVal info, 1
|
||||
buildTyped target, info, FieldAt, c.m.nativeIntId:
|
||||
copyTree target, tmp
|
||||
target.addImmediateVal info, 0 # (len, p)-pair so len is at index 0
|
||||
|
||||
of tyArray:
|
||||
let t = typeToIr(c.m.types, typ.lastSon)
|
||||
target.addImmediateVal info, 0
|
||||
buildTyped target, info, AddrOf, elemType:
|
||||
buildTyped target, info, ArrayAt, t:
|
||||
copyTree target, tmp
|
||||
target.addIntVal c.m.integers, info, c.m.nativeIntId, 0
|
||||
target.addImmediateVal info, 1
|
||||
target.addIntVal(c.m.integers, info, c.m.nativeIntId, toInt lengthOrd(c.config, typ))
|
||||
else:
|
||||
raiseAssert "addAddrOfFirstElem: " & typeToString(typ)
|
||||
|
||||
proc genToOpenArrayConv(c: var ProcCon; arg: PNode; d: var Value; flags: GenFlags; destType: PType) =
|
||||
let info = toLineInfo(c, arg.info)
|
||||
let tmp = c.genx(arg, flags)
|
||||
let arrType = destType.skipTypes(abstractVar)
|
||||
template body(target) =
|
||||
buildTyped target, info, ObjConstr, typeToIr(c.m.types, arrType):
|
||||
c.addAddrOfFirstElem target, info, tmp, arg.typ
|
||||
|
||||
valueIntoDest c, info, d, arrType, body
|
||||
freeTemp c, tmp
|
||||
|
||||
proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc: Opcode) =
|
||||
let targetType = n.typ.skipTypes({tyDistinct})
|
||||
let argType = arg.typ.skipTypes({tyDistinct})
|
||||
@@ -1774,6 +1897,11 @@ proc genConv(c: var ProcCon; n, arg: PNode; d: var Value; flags: GenFlags; opc:
|
||||
gen c, arg, d
|
||||
return
|
||||
|
||||
if opc != Cast and targetType.skipTypes({tyVar, tyLent}).kind in {tyOpenArray, tyVarargs} and
|
||||
argType.skipTypes({tyVar, tyLent}).kind notin {tyOpenArray, tyVarargs}:
|
||||
genToOpenArrayConv c, arg, d, flags, n.typ
|
||||
return
|
||||
|
||||
let info = toLineInfo(c, n.info)
|
||||
let tmp = c.genx(arg, flags)
|
||||
template body(target) =
|
||||
@@ -1850,7 +1978,7 @@ proc genVarSection(c: var ProcCon; n: PNode) =
|
||||
genAsgn2(c, vn, a[2])
|
||||
else:
|
||||
if a[2].kind == nkEmpty:
|
||||
discard "XXX assign default value to location here"
|
||||
genAsgn2(c, vn, expandDefault(vn.typ, vn.info))
|
||||
else:
|
||||
genAsgn2(c, vn, a[2])
|
||||
|
||||
@@ -1922,17 +2050,56 @@ proc genNilLit(c: var ProcCon; n: PNode; d: var Value) =
|
||||
valueIntoDest c, info, d, n.typ, body
|
||||
|
||||
proc genRangeCheck(c: var ProcCon; n: PNode; d: var Value) =
|
||||
# XXX to implement properly
|
||||
gen c, n[0], d
|
||||
if optRangeCheck in c.options:
|
||||
let info = toLineInfo(c, n.info)
|
||||
let tmp = c.genx n[0]
|
||||
let a = c.genx n[1]
|
||||
let b = c.genx n[2]
|
||||
template body(target) =
|
||||
buildTyped target, info, CheckedRange, typeToIr(c.m.types, n.typ):
|
||||
copyTree target, tmp
|
||||
copyTree target, a
|
||||
copyTree target, b
|
||||
target.addLabel info, CheckedGoto, c.exitLabel
|
||||
valueIntoDest c, info, d, n.typ, body
|
||||
freeTemp c, tmp
|
||||
freeTemp c, a
|
||||
freeTemp c, b
|
||||
else:
|
||||
gen c, n[0], d
|
||||
|
||||
type
|
||||
IndexFor = enum
|
||||
ForSeq, ForStr, ForOpenArray
|
||||
|
||||
proc genIndexCheck(c: var ProcCon; n: PNode; a: Value; kind: IndexFor): Value =
|
||||
if optBoundsCheck in c.options:
|
||||
let info = toLineInfo(c, n.info)
|
||||
result = default(Value)
|
||||
let idx = genx(c, n)
|
||||
build result, info, CheckedIndex:
|
||||
copyTree result.Tree, idx
|
||||
case kind
|
||||
of ForSeq, ForStr:
|
||||
buildTyped result, info, FieldAt, c.m.nativeIntId:
|
||||
copyTree result.Tree, a
|
||||
result.addImmediateVal info, 0 # (len, p)-pair
|
||||
of ForOpenArray:
|
||||
buildTyped result, info, FieldAt, c.m.nativeIntId:
|
||||
copyTree result.Tree, a
|
||||
result.addImmediateVal info, 1 # (p, len)-pair
|
||||
result.Tree.addLabel info, CheckedGoto, c.exitLabel
|
||||
freeTemp c, idx
|
||||
else:
|
||||
result = genx(c, n)
|
||||
|
||||
proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
|
||||
let arrayKind = n[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
||||
let info = toLineInfo(c, n.info)
|
||||
case arrayKind
|
||||
of tyString:
|
||||
# XXX implement range check
|
||||
let a = genx(c, n[0], flags)
|
||||
let b = genx(c, n[1])
|
||||
let b = genIndexCheck(c, n[1], a, ForStr)
|
||||
let t = typeToIr(c.m.types, n.typ)
|
||||
template body(target) =
|
||||
buildTyped target, info, ArrayAt, t:
|
||||
@@ -1966,9 +2133,8 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
|
||||
|
||||
freeTemp c, a
|
||||
of tyOpenArray, tyVarargs:
|
||||
# XXX implement range check
|
||||
let a = genx(c, n[0], flags)
|
||||
let b = genx(c, n[1])
|
||||
let b = genIndexCheck(c, n[1], a, ForOpenArray)
|
||||
let t = typeToIr(c.m.types, n.typ)
|
||||
template body(target) =
|
||||
buildTyped target, info, ArrayAt, t:
|
||||
@@ -1981,7 +2147,6 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
|
||||
freeTemp c, b
|
||||
freeTemp c, a
|
||||
of tyArray:
|
||||
# XXX implement range check
|
||||
let a = genx(c, n[0], flags)
|
||||
var b = default(Value)
|
||||
genIndex(c, n[1], n[0].typ, b)
|
||||
@@ -1995,7 +2160,7 @@ proc genArrAccess(c: var ProcCon; n: PNode; d: var Value; flags: GenFlags) =
|
||||
freeTemp c, a
|
||||
of tySequence:
|
||||
let a = genx(c, n[0], flags)
|
||||
let b = genx(c, n[1])
|
||||
let b = genIndexCheck(c, n[1], a, ForSeq)
|
||||
let t = typeToIr(c.m.types, n.typ)
|
||||
template body(target) =
|
||||
buildTyped target, info, ArrayAt, t:
|
||||
@@ -2047,7 +2212,7 @@ proc genProc(cOuter: var ProcCon; n: PNode) =
|
||||
var c = initProcCon(cOuter.m, prc, cOuter.m.graph.config)
|
||||
genParams(c, prc.typ.n)
|
||||
|
||||
let body = transformBody(c.m.graph, c.m.idgen, prc, useCache)
|
||||
let body = transformBody(c.m.graph, c.m.idgen, prc, {useCache, keepOpenArrayConversions})
|
||||
|
||||
let info = toLineInfo(c, body.info)
|
||||
build c.code, info, ProcDecl:
|
||||
|
||||
@@ -66,6 +66,9 @@ type
|
||||
SetExc,
|
||||
TestExc,
|
||||
|
||||
CheckedRange,
|
||||
CheckedIndex,
|
||||
|
||||
Call,
|
||||
IndirectCall,
|
||||
CheckedCall, # call that can raise
|
||||
|
||||
@@ -239,6 +239,11 @@ proc ptrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
|
||||
g.addType t
|
||||
result = sealType(g, f)
|
||||
|
||||
proc arrayPtrTypeOf*(g: var TypeGraph; t: TypeId): TypeId =
|
||||
let f = g.openType AArrayPtrTy
|
||||
g.addType t
|
||||
result = sealType(g, f)
|
||||
|
||||
proc toString*(dest: var string; g: TypeGraph; i: TypeId) =
|
||||
case g[i].kind
|
||||
of VoidTy: dest.add "void"
|
||||
|
||||
@@ -459,7 +459,11 @@ proc typeToIr*(c: var TypesCon; t: PType): TypeId =
|
||||
let a = openType(c.g, LastArrayTy)
|
||||
c.g.addType(elemType)
|
||||
result = sealType(c.g, a)
|
||||
of tyNone, tyEmpty, tyUntyped, tyTyped, tyTypeDesc,
|
||||
of tyUntyped, tyTyped:
|
||||
# this avoids a special case for system.echo which is not a generic but
|
||||
# uses `varargs[typed]`:
|
||||
result = VoidId
|
||||
of tyNone, tyEmpty, tyTypeDesc,
|
||||
tyNil, tyGenericInvocation, tyProxy, tyBuiltInTypeClass,
|
||||
tyUserTypeClass, tyUserTypeClassInst, tyCompositeTypeClass,
|
||||
tyAnd, tyOr, tyNot, tyAnything, tyConcept, tyIterable, tyForward:
|
||||
|
||||
@@ -66,7 +66,7 @@ proc mergeBasicBlockInfo(parent: var BasicBlock; this: BasicBlock) {.inline.} =
|
||||
proc wasMovedTarget(matches: var IntSet; branch: seq[PNode]; moveTarget: PNode): bool =
|
||||
result = false
|
||||
for i in 0..<branch.len:
|
||||
if exprStructuralEquivalent(branch[i][1].skipAddr, moveTarget,
|
||||
if exprStructuralEquivalent(branch[i][1].skipHiddenAddr, moveTarget,
|
||||
strictSymEquality = true):
|
||||
result = true
|
||||
matches.incl i
|
||||
@@ -76,7 +76,7 @@ proc intersect(summary: var seq[PNode]; branch: seq[PNode]) =
|
||||
var i = 0
|
||||
var matches = initIntSet()
|
||||
while i < summary.len:
|
||||
if wasMovedTarget(matches, branch, summary[i][1].skipAddr):
|
||||
if wasMovedTarget(matches, branch, summary[i][1].skipHiddenAddr):
|
||||
inc i
|
||||
else:
|
||||
summary.del i
|
||||
@@ -87,7 +87,7 @@ proc intersect(summary: var seq[PNode]; branch: seq[PNode]) =
|
||||
proc invalidateWasMoved(c: var BasicBlock; x: PNode) =
|
||||
var i = 0
|
||||
while i < c.wasMovedLocs.len:
|
||||
if exprStructuralEquivalent(c.wasMovedLocs[i][1].skipAddr, x,
|
||||
if exprStructuralEquivalent(c.wasMovedLocs[i][1].skipHiddenAddr, x,
|
||||
strictSymEquality = true):
|
||||
c.wasMovedLocs.del i
|
||||
else:
|
||||
@@ -96,7 +96,7 @@ proc invalidateWasMoved(c: var BasicBlock; x: PNode) =
|
||||
proc wasMovedDestroyPair(c: var Con; b: var BasicBlock; d: PNode) =
|
||||
var i = 0
|
||||
while i < b.wasMovedLocs.len:
|
||||
if exprStructuralEquivalent(b.wasMovedLocs[i][1].skipAddr, d[1].skipAddr,
|
||||
if exprStructuralEquivalent(b.wasMovedLocs[i][1].skipHiddenAddr, d[1].skipHiddenAddr,
|
||||
strictSymEquality = true):
|
||||
b.wasMovedLocs[i].flags.incl nfMarkForDeletion
|
||||
c.somethingTodo = true
|
||||
|
||||
@@ -993,9 +993,9 @@ proc trackCall(tracked: PEffects; n: PNode) =
|
||||
# consider this case: p(out x, x); we want to remark that 'x' is not
|
||||
# initialized until after the call. Since we do this after we analysed the
|
||||
# call, this is fine.
|
||||
initVar(tracked, n[i].skipAddr, false)
|
||||
initVar(tracked, n[i].skipHiddenAddr, false)
|
||||
if strictFuncs in tracked.c.features and not tracked.inEnforcedNoSideEffects and
|
||||
isDangerousLocation(n[i].skipAddr, tracked.owner):
|
||||
isDangerousLocation(n[i].skipHiddenAddr, tracked.owner):
|
||||
if sfNoSideEffect in tracked.owner.flags:
|
||||
localError(tracked.config, n[i].info,
|
||||
"cannot pass $1 to `var T` parameter within a strict func" % renderTree(n[i]))
|
||||
|
||||
@@ -28,10 +28,11 @@ when defined(nimPreviewSlimSystem):
|
||||
import std/assertions
|
||||
|
||||
type
|
||||
TransformBodyFlag* = enum
|
||||
dontUseCache, useCache
|
||||
TransformFlag* = enum
|
||||
useCache, keepOpenArrayConversions, force
|
||||
TransformFlags* = set[TransformFlag]
|
||||
|
||||
proc transformBody*(g: ModuleGraph; idgen: IdGenerator, prc: PSym, flag: TransformBodyFlag, force = false): PNode
|
||||
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flags: TransformFlags): PNode
|
||||
|
||||
import closureiters, lambdalifting
|
||||
|
||||
@@ -50,9 +51,10 @@ type
|
||||
module: PSym
|
||||
transCon: PTransCon # top of a TransCon stack
|
||||
inlining: int # > 0 if we are in inlining context (copy vars)
|
||||
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
|
||||
contSyms, breakSyms: seq[PSym] # to transform 'continue' and 'break'
|
||||
deferDetected, tooEarly: bool
|
||||
isIntroducingNewLocalVars: bool # true if we are in `introducingNewLocalVars` (don't transform yields)
|
||||
flags: TransformFlags
|
||||
graph: ModuleGraph
|
||||
idgen: IdGenerator
|
||||
|
||||
@@ -116,7 +118,7 @@ proc transformSymAux(c: PTransf, n: PNode): PNode =
|
||||
let s = n.sym
|
||||
if s.typ != nil and s.typ.callConv == ccClosure:
|
||||
if s.kind in routineKinds:
|
||||
discard transformBody(c.graph, c.idgen, s, useCache)
|
||||
discard transformBody(c.graph, c.idgen, s, {useCache}+c.flags)
|
||||
if s.kind == skIterator:
|
||||
if c.tooEarly: return n
|
||||
else: return liftIterSym(c.graph, n, c.idgen, getCurrOwner(c))
|
||||
@@ -552,11 +554,14 @@ proc transformConv(c: PTransf, n: PNode): PNode =
|
||||
else:
|
||||
result = transformSons(c, n)
|
||||
of tyOpenArray, tyVarargs:
|
||||
result = transform(c, n[1])
|
||||
#result = transformSons(c, n)
|
||||
result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen)
|
||||
#echo n.info, " came here and produced ", typeToString(result.typ),
|
||||
# " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
|
||||
if keepOpenArrayConversions in c.flags:
|
||||
result = transformSons(c, n)
|
||||
else:
|
||||
result = transform(c, n[1])
|
||||
#result = transformSons(c, n)
|
||||
result.typ = takeType(n.typ, n[1].typ, c.graph, c.idgen)
|
||||
#echo n.info, " came here and produced ", typeToString(result.typ),
|
||||
# " from ", typeToString(n.typ), " and ", typeToString(n[1].typ)
|
||||
of tyCstring:
|
||||
if source.kind == tyString:
|
||||
result = newTransNode(nkStringToCString, n, 1)
|
||||
@@ -774,7 +779,7 @@ proc transformFor(c: PTransf, n: PNode): PNode =
|
||||
stmtList.add(newAsgnStmt(c, nkFastAsgn, temp, arg, true))
|
||||
idNodeTablePut(newC.mapping, formal, temp)
|
||||
|
||||
let body = transformBody(c.graph, c.idgen, iter, useCache)
|
||||
let body = transformBody(c.graph, c.idgen, iter, {useCache}+c.flags)
|
||||
pushInfoContext(c.graph.config, n.info)
|
||||
inc(c.inlining)
|
||||
stmtList.add(transform(c, body))
|
||||
@@ -1137,13 +1142,8 @@ proc processTransf(c: PTransf, n: PNode, owner: PSym): PNode =
|
||||
popTransCon(c)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc openTransf(g: ModuleGraph; module: PSym, filename: string; idgen: IdGenerator): PTransf =
|
||||
new(result)
|
||||
result.contSyms = @[]
|
||||
result.breakSyms = @[]
|
||||
result.module = module
|
||||
result.graph = g
|
||||
result.idgen = idgen
|
||||
proc openTransf(g: ModuleGraph; module: PSym, filename: string; idgen: IdGenerator; flags: TransformFlags): PTransf =
|
||||
result = PTransf(module: module, graph: g, idgen: idgen, flags: flags)
|
||||
|
||||
proc flattenStmts(n: PNode) =
|
||||
var goOn = true
|
||||
@@ -1186,7 +1186,7 @@ template liftDefer(c, root) =
|
||||
if c.deferDetected:
|
||||
liftDeferAux(root)
|
||||
|
||||
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: TransformBodyFlag, force = false): PNode =
|
||||
proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flags: TransformFlags): PNode =
|
||||
assert prc.kind in routineKinds
|
||||
|
||||
if prc.transformedBody != nil:
|
||||
@@ -1195,8 +1195,8 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: Transfo
|
||||
result = getBody(g, prc)
|
||||
else:
|
||||
prc.transformedBody = newNode(nkEmpty) # protects from recursion
|
||||
var c = openTransf(g, prc.getModule, "", idgen)
|
||||
result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen, force)
|
||||
var c = openTransf(g, prc.getModule, "", idgen, flags)
|
||||
result = liftLambdas(g, prc, getBody(g, prc), c.tooEarly, c.idgen, flags)
|
||||
result = processTransf(c, result, prc)
|
||||
liftDefer(c, result)
|
||||
result = liftLocalsIfRequested(prc, result, g.cache, g.config, c.idgen)
|
||||
@@ -1206,7 +1206,7 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: Transfo
|
||||
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
if flag == useCache or prc.typ.callConv == ccInline:
|
||||
if useCache in flags or prc.typ.callConv == ccInline:
|
||||
# genProc for inline procs will be called multiple times from different modules,
|
||||
# it is important to transform exactly once to get sym ids and locations right
|
||||
prc.transformedBody = result
|
||||
@@ -1217,21 +1217,21 @@ proc transformBody*(g: ModuleGraph; idgen: IdGenerator; prc: PSym; flag: Transfo
|
||||
#if prc.name.s == "main":
|
||||
# echo "transformed into ", renderTree(result, {renderIds})
|
||||
|
||||
proc transformStmt*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode =
|
||||
proc transformStmt*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode; flags: TransformFlags = {}): PNode =
|
||||
if nfTransf in n.flags:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(g, module, "", idgen)
|
||||
var c = openTransf(g, module, "", idgen, flags)
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
#result = liftLambdasForTopLevel(module, result)
|
||||
incl(result.flags, nfTransf)
|
||||
|
||||
proc transformExpr*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode): PNode =
|
||||
proc transformExpr*(g: ModuleGraph; idgen: IdGenerator; module: PSym, n: PNode; flags: TransformFlags = {}): PNode =
|
||||
if nfTransf in n.flags:
|
||||
result = n
|
||||
else:
|
||||
var c = openTransf(g, module, "", idgen)
|
||||
var c = openTransf(g, module, "", idgen, flags)
|
||||
result = processTransf(c, n, module)
|
||||
liftDefer(c, result)
|
||||
# expressions are not to be injected with destructor calls as that
|
||||
|
||||
@@ -234,3 +234,6 @@ proc isRunnableExamples*(n: PNode): bool =
|
||||
# Templates and generics don't perform symbol lookups.
|
||||
result = n.kind == nkSym and n.sym.magic == mRunnableExamples or
|
||||
n.kind == nkIdent and n.ident.id == ord(wRunnableExamples)
|
||||
|
||||
proc skipAddr*(n: PNode): PNode {.inline.} =
|
||||
result = if n.kind in {nkAddr, nkHiddenAddr}: n[0] else: n
|
||||
|
||||
@@ -1295,7 +1295,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
|
||||
let ast = a.sym.ast.shallowCopy
|
||||
for i in 0..<a.sym.ast.len:
|
||||
ast[i] = a.sym.ast[i]
|
||||
ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, useCache, force=true)
|
||||
ast[bodyPos] = transformBody(c.graph, c.idgen, a.sym, {useCache, force})
|
||||
ast.copyTree()
|
||||
of opcSymOwner:
|
||||
decodeB(rkNode)
|
||||
|
||||
@@ -2388,7 +2388,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||
c.procToCodePos[s.id] = result
|
||||
# thanks to the jmp we can add top level statements easily and also nest
|
||||
# procs easily:
|
||||
let body = transformBody(c.graph, c.idgen, s, if isCompileTimeProc(s): dontUseCache else: useCache)
|
||||
let body = transformBody(c.graph, c.idgen, s, if isCompileTimeProc(s): {} else: {useCache})
|
||||
let procStart = c.xjmp(body, opcJmp, 0)
|
||||
var p = PProc(blocks: @[], sym: s)
|
||||
let oldPrc = c.prc
|
||||
|
||||
@@ -206,6 +206,9 @@ proc nimAddStrV1(s: var NimStringV2; src: NimStringV2) {.compilerRtl, inl.} =
|
||||
prepareAdd(s, src.len)
|
||||
appendString s, src
|
||||
|
||||
proc nimDestroyStrV1(s: NimStringV2) {.compilerRtl, inl.} =
|
||||
frees(s)
|
||||
|
||||
func capacity*(self: string): int {.inline.} =
|
||||
## Returns the current capacity of the string.
|
||||
# See https://github.com/nim-lang/RFCs/issues/460
|
||||
|
||||
Reference in New Issue
Block a user