diff --git a/compiler/vm/vmgen.nim b/compiler/vm/vmgen.nim index 01fbe39faef..c530a4a7488 100644 --- a/compiler/vm/vmgen.nim +++ b/compiler/vm/vmgen.nim @@ -3018,8 +3018,21 @@ proc gen(c: var TCtx; n: CgNode; dest: var TDest) = clearDest(c, n, dest) of cnkNeg: prepare(c, dest, n.typ) - let a = c.genx(n[0]) - c.gABC(n, pick(n, opcUnaryMinusInt, opcUnaryMinusFloat), dest, a) + let + a = c.genx(n[0]) + op = pick(n, opcUnaryMinusInt, opcUnaryMinusFloat) + if op == opcUnaryMinusInt: + # the VM has no built-in unchecked integer negation, so it's emulated in + # an overflow-safe manner + # XXX: this is sub-optimal. In the future, all VM integer operations + # should be unchecked + c.gABC(n, opcBitnotInt, dest, a) # invert + let tmp = c.getTemp(slotTempInt) + c.gABx(n, opcLdImmInt, tmp, 1) + c.gABC(n, opcAddu, dest, dest, tmp) # + 1 (two's complement) + c.freeTemp(tmp) + else: + c.gABC(n, op, dest, a) c.freeTemp(a) of cnkAdd: binaryArith(c, n, n[0], n[1], dest, opcAddu, opcAddFloat) of cnkSub: binaryArith(c, n, n[0], n[1], dest, opcSubu, opcSubFloat) diff --git a/tests/overflw/tunchecked_negation_32.nim b/tests/overflw/tunchecked_negation_32.nim new file mode 100644 index 00000000000..e03c0260300 --- /dev/null +++ b/tests/overflw/tunchecked_negation_32.nim @@ -0,0 +1,10 @@ +discard """ + description: ''' + Ensure that disabling overflow checks works for 32-bit integer negations + ''' + targets: "c js vm" + matrix: "--overflowChecks:off" +""" + +var x = low(int32) +discard -x \ No newline at end of file diff --git a/tests/overflw/tunchecked_negation_64.nim b/tests/overflw/tunchecked_negation_64.nim new file mode 100644 index 00000000000..23ed5382a6a --- /dev/null +++ b/tests/overflw/tunchecked_negation_64.nim @@ -0,0 +1,10 @@ +discard """ + description: ''' + Ensure that disabling overflow checks works for 64-bit integer negations + ''' + targets: "c js vm" + matrix: "--overflowChecks:off" +""" + +var x = low(int64) +discard -x