Skip to content

Commit 8f4982b

Browse files
committed
lower mChckBounds magic with MIR pass
Summary ======= Lower the bound checks for `toOpenArray` with a MIR pass when using the C target. Details ======= * implement a bound check lowering pass * the lowering is integrated into the existing `lowerChecks` * bound checks are turned into calls to the `chckBounds` runtime procedure * remove the `mChckBounds` translation and associated logic from `cgen`
1 parent 5a14e3e commit 8f4982b

File tree

4 files changed

+39
-40
lines changed

4 files changed

+39
-40
lines changed

compiler/backend/ccgexprs.nim

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -515,32 +515,6 @@ proc genCStringElem(p: BProc, n, x, y: CgNode, d: var TLoc) =
515515
putIntoDest(p, d, n,
516516
ropecg(p.module, "$1[$2]", [rdLoc(a), rdCharLoc(b)]), a.storage)
517517

518-
proc genBoundsCheck(p: BProc; arr, a, b: TLoc, exit: CgNode) =
519-
# types that map to C pointers need to be skipped here too, since no
520-
# dereference is generated for ``ptr array`` and the like
521-
let ty = skipTypes(arr.t, abstractVarRange + {tyPtr, tyRef, tyLent})
522-
case ty.kind
523-
of tyOpenArray, tyVarargs:
524-
if reifiedOpenArray(p, arr.lode):
525-
linefmt(p, cpsStmts,
526-
"if ($2-$1 != -1 && " &
527-
"((NU)($1) >= (NU)($3.Field1) || (NU)($2) >= (NU)($3.Field1))){ #raiseIndexError(); $4}$n",
528-
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p, exit)])
529-
else:
530-
linefmt(p, cpsStmts,
531-
"if ($2-$1 != -1 && " &
532-
"((NU)($1) >= (NU)($3Len_0) || (NU)($2) >= (NU)($3Len_0))){ #raiseIndexError(); $4}$n",
533-
[rdLoc(a), rdLoc(b), rdLoc(arr), raiseInstr(p, exit)])
534-
of tySequence, tyString:
535-
linefmt(p, cpsStmts,
536-
"if ($2-$1 != -1 && " &
537-
"((NU)($1) >= (NU)$3 || (NU)($2) >= (NU)$3)){ #raiseIndexError(); $4}$n",
538-
[rdLoc(a), rdLoc(b), lenExpr(p, arr), raiseInstr(p, exit)])
539-
of tyUncheckedArray, tyCstring:
540-
discard "no checks are used"
541-
else:
542-
unreachable(ty.kind)
543-
544518
proc genOpenArrayElem(p: BProc, n, x, y: CgNode, d: var TLoc) =
545519
var a, b: TLoc
546520
initLocExpr(p, x, a)
@@ -1416,12 +1390,6 @@ proc genMagicExpr(p: BProc, e: CgNode, d: var TLoc, op: TMagic) =
14161390
typ.add "*"
14171391

14181392
linefmt(p, cpsStmts, "$1 = ($2)($3);$n", [a.r, typ, rdLoc(b)])
1419-
of mChckBounds:
1420-
var arr, a, b: TLoc
1421-
initLocExpr(p, e[1], arr)
1422-
initLocExpr(p, e[2], a)
1423-
initLocExpr(p, e[3], b)
1424-
genBoundsCheck(p, arr, a, b, e.exit)
14251393
of mSamePayload:
14261394
var a, b: TLoc
14271395
initLocExpr(p, e[1], a)

compiler/backend/ccgstmts.nim

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,6 @@ proc genIf(p: BProc, n: CgNode) =
9595
lineF(p, cpsStmts, "if ($1)$n", [rdLoc(a)])
9696
startBlock(p)
9797

98-
proc exit(n: CgNode): CgNode =
99-
# XXX: exists as a convenience for overflow check, index check, etc.
100-
# code gen. Should be removed once those are fully lowered prior
101-
# to code generation
102-
case n.kind
103-
of cnkCheckedCall: n[^1]
104-
else: nil
105-
10698
proc raiseInstr(p: BProc, n: CgNode): Rope =
10799
if n != nil:
108100
case n.kind

compiler/mir/rtchecks.nim

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,35 @@ proc emitCheckedFloatOp(tree; call; graph; env; bu): Value =
564564
bu.emitCall(tree, call, env.addCompilerProc(graph, "raiseFloatOverflow")):
565565
bu.emitByVal result
566566

567+
proc emitBoundCheck(tree; call; graph; env; bu) =
568+
## Emits the lowered version of a bound check.
569+
case env.types.headerFor(tree[tree.argument(call, 0)].typ, Canonical).kind
570+
of tkSeq, tkString, tkOpenArray:
571+
let len = bu.wrapTemp env.types.sizeType:
572+
# note: lengthOpenArray works for all containers
573+
bu.buildMagicCall mLengthOpenArray, env.types.sizeType:
574+
bu.subTree mnkArg:
575+
bu.emitFrom(tree, NodePosition tree.argument(call, 0))
576+
577+
bu.emitCall(tree, call, env.addCompilerProc(graph, "chckBounds")):
578+
bu.emitByVal len
579+
bu.subTree mnkArg:
580+
bu.emitFrom(tree, NodePosition tree.argument(call, 1))
581+
bu.subTree mnkArg:
582+
bu.emitFrom(tree, NodePosition tree.argument(call, 2))
583+
of tkCstring:
584+
# TODO: don't emit a ``mChckBounds`` call for cstrings in the first place
585+
if tree[call].kind == mnkCheckedCall and
586+
tree[tree.last(call)].kind != mnkUnwind:
587+
# emit ``if false: raise``, so that the target label isn't unused
588+
bu.buildIf (bu.use env.makeLiteral(mnkUIntLit, Zero, BoolType)):
589+
bu.subTree mnkRaise:
590+
bu.emitFrom(tree, tree.last(call))
591+
else:
592+
discard "no local handler -> nothing to do"
593+
else:
594+
unreachable()
595+
567596
proc lowerChecks*(body; graph; env; changes: var Changeset) =
568597
## Lowers all magic calls implementing the run-time checks.
569598
template tree: MirTree = body.code
@@ -599,6 +628,10 @@ proc lowerChecks*(body; graph; env; changes: var Changeset) =
599628
let call = tree.parent(i)
600629
changes.replaceMulti(tree, tree.parent(call), bu):
601630
emitObjectCheck(tree, call, graph, env, bu)
631+
of mChckBounds:
632+
let call = tree.parent(i)
633+
changes.replaceMulti(tree, tree.parent(call), bu):
634+
emitBoundCheck(tree, call, graph, env, bu)
602635

603636
of mAddI, mSubI, mMulI, mModI, mDivI:
604637
let call = tree.parent(i)

lib/system/chcks.nim

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,9 @@ proc chckNil(p: pointer) =
122122
when defined(nimV2):
123123
proc raiseObjectCaseTransition() {.compilerproc.} =
124124
sysFatal(FieldDefect, "assignment to discriminant changes object branch")
125+
126+
proc chckBounds(len: int, lo, hi: int) {.compilerproc, inline.} =
127+
## Bounds check for integer-sized containers.
128+
let ulen = cast[uint](len)
129+
if hi-lo != -1 and (cast[uint](lo) >= ulen or cast[uint](hi) >= ulen):
130+
raiseIndexError()

0 commit comments

Comments
 (0)