NIR: progress (#22817)

Done:

- [x] Implement conversions to openArray/varargs.
- [x] Implement index/range checking.
This commit is contained in:
Andreas Rumpf
2023-10-12 23:33:38 +02:00
committed by GitHub
parent d790112ea4
commit 8990626ca9
16 changed files with 281 additions and 101 deletions

View File

@@ -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:

View File

@@ -66,6 +66,9 @@ type
SetExc,
TestExc,
CheckedRange,
CheckedIndex,
Call,
IndirectCall,
CheckedCall, # call that can raise

View File

@@ -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"

View File

@@ -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: