summary refs log tree commit diff stats
path: root/compiler/nir
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2023-10-12 23:33:38 +0200
committerGitHub <noreply@github.com>2023-10-12 23:33:38 +0200
commit8990626ca9715a3687b28331aee4ccf242997aa2 (patch)
tree792a4d375eb3ad77cb9764001029b56c62c2416b /compiler/nir
parentd790112ea4600c847fed830171333fde308421a3 (diff)
downloadNim-8990626ca9715a3687b28331aee4ccf242997aa2.tar.gz
NIR: progress (#22817)
Done:

- [x] Implement conversions to openArray/varargs.
- [x] Implement index/range checking.
Diffstat (limited to 'compiler/nir')
-rw-r--r--compiler/nir/ast2ir.nim277
-rw-r--r--compiler/nir/nirinsts.nim3
-rw-r--r--compiler/nir/nirtypes.nim5
-rw-r--r--compiler/nir/types2ir.nim6
4 files changed, 234 insertions, 57 deletions
diff --git a/compiler/nir/ast2ir.nim b/compiler/nir/ast2ir.nim
index bc7348be3..fcda145ea 100644
--- a/compiler/nir/ast2ir.nim
+++ b/compiler/nir/ast2ir.nim
@@ -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:
diff --git a/compiler/nir/nirinsts.nim b/compiler/nir/nirinsts.nim
index f037b4f0e..2c0dc3d11 100644
--- a/compiler/nir/nirinsts.nim
+++ b/compiler/nir/nirinsts.nim
@@ -66,6 +66,9 @@ type
     SetExc,
     TestExc,
 
+    CheckedRange,
+    CheckedIndex,
+
     Call,
     IndirectCall,
     CheckedCall, # call that can raise
diff --git a/compiler/nir/nirtypes.nim b/compiler/nir/nirtypes.nim
index d989397a6..a42feab00 100644
--- a/compiler/nir/nirtypes.nim
+++ b/compiler/nir/nirtypes.nim
@@ -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"
diff --git a/compiler/nir/types2ir.nim b/compiler/nir/types2ir.nim
index 6d163c6c7..835bef03c 100644
--- a/compiler/nir/types2ir.nim
+++ b/compiler/nir/types2ir.nim
@@ -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: