make distinct conversions addressable in VM (#24124)

fixes #24097

For `nkConv` addresses where the conversion is between 2 types that are
equal between backends, treat assignments the same as assignments to the
argument of the conversion. In the VM this seems to be in `genAsgn` and
`genAsgnPatch`, as evidenced by the special logic for `nkDerefExpr` etc.

This doesn't handle ranges after #24037 because `sameBackendType` is
used and not `sameBackendTypeIgnoreRange`. This is so this is
backportable without #24037 and another PR can be opened that implements
it for ranges and adds tests as well. We can also merge
`sameBackendTypeIgnoreRange` with `sameBackendType` since it doesn't
seem like anything that uses it would be affected (only cycle checks and
the VM), but then we still have to add tests.

(cherry picked from commit 1fbb67ffe9)
This commit is contained in:
metagn
2024-09-17 07:29:49 +03:00
committed by narimiran
parent 6bcb078476
commit 95fa7f0f12
2 changed files with 64 additions and 9 deletions

View File

@@ -698,6 +698,9 @@ proc genAsgnPatch(c: PCtx; le: PNode, value: TRegister) =
let dest = c.genx(le, {gfNodeAddr})
c.gABC(le, opcWrDeref, dest, 0, value)
c.freeTemp(dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgnPatch(c, le[1], value)
else:
discard
@@ -866,7 +869,7 @@ proc genAddSubInt(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
genBinaryABC(c, n, dest, opc)
c.genNarrow(n, dest)
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
proc genConv(c: PCtx; n, arg: PNode; dest: var TDest, flags: TGenFlags = {}; opc=opcConv) =
let t2 = n.typ.skipTypes({tyDistinct})
let targ2 = arg.typ.skipTypes({tyDistinct})
@@ -878,7 +881,7 @@ proc genConv(c: PCtx; n, arg: PNode; dest: var TDest; opc=opcConv) =
return true
if implicitConv():
gen(c, arg, dest)
gen(c, arg, dest, flags)
return
let tmp = c.genx(arg)
@@ -1040,7 +1043,7 @@ proc whichAsgnOpc(n: PNode; requiresCopy = true): TOpcode =
else:
(if requiresCopy: opcAsgnComplex else: opcFastAsgnComplex)
proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
proc genMagic(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}, m: TMagic) =
case m
of mAnd: c.genAndOr(n, opcFJmp, dest)
of mOr: c.genAndOr(n, opcTJmp, dest)
@@ -1179,7 +1182,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(size*8))
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n[1], dest)
genConv(c, n, n[1], dest, flags)
of mEqStr: genBinaryABC(c, n, dest, opcEqStr)
of mEqCString: genBinaryABC(c, n, dest, opcEqCString)
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
@@ -1645,6 +1648,9 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
c.freeTemp(cc)
else:
gen(c, ri, dest)
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
if sameBackendType(le.typ, le[1].typ):
genAsgn(c, le[1], ri, requiresCopy)
else:
let dest = c.genx(le, {gfNodeAddr})
genAsgn(c, dest, ri, requiresCopy)
@@ -2155,7 +2161,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
if n[0].kind == nkSym:
let s = n[0].sym
if s.magic != mNone:
genMagic(c, n, dest, s.magic)
genMagic(c, n, dest, flags, s.magic)
elif s.kind == skMethod:
localError(c.config, n.info, "cannot call method " & s.name.s &
" at compile time")
@@ -2212,11 +2218,11 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
unused(c, n, dest)
gen(c, n[0])
of nkHiddenStdConv, nkHiddenSubConv, nkConv:
genConv(c, n, n[1], dest)
genConv(c, n, n[1], dest, flags)
of nkObjDownConv:
genConv(c, n, n[0], dest)
genConv(c, n, n[0], dest, flags)
of nkObjUpConv:
genConv(c, n, n[0], dest)
genConv(c, n, n[0], dest, flags)
of nkVarSection, nkLetSection:
unused(c, n, dest)
genVarSection(c, n)
@@ -2249,7 +2255,7 @@ proc gen(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags = {}) =
of nkPar, nkClosure, nkTupleConstr: genTupleConstr(c, n, dest)
of nkCast:
if allowCast in c.features:
genConv(c, n, n[1], dest, opcCast)
genConv(c, n, n[1], dest, flags, opcCast)
else:
genCastIntFloat(c, n, dest)
of nkTypeOfExpr:

49
tests/vm/tconvaddr.nim Normal file
View File

@@ -0,0 +1,49 @@
block: # issue #24097
type Foo = distinct int
proc foo(x: var Foo) =
int(x) += 1
proc bar(x: var int) =
x += 1
static:
var x = Foo(1)
int(x) = int(x) + 1
doAssert x.int == 2
int(x) += 1
doAssert x.int == 3
foo(x)
doAssert x.int == 4
bar(int(x)) # need vmgen flags propagated for this
doAssert x.int == 5
type Bar = object
x: Foo
static:
var obj = Bar(x: Foo(1))
int(obj.x) = int(obj.x) + 1
doAssert obj.x.int == 2
int(obj.x) += 1
doAssert obj.x.int == 3
foo(obj.x)
doAssert obj.x.int == 4
bar(int(obj.x)) # need vmgen flags propagated for this
doAssert obj.x.int == 5
static:
var arr = @[Foo(1)]
int(arr[0]) = int(arr[0]) + 1
doAssert arr[0].int == 2
int(arr[0]) += 1
doAssert arr[0].int == 3
foo(arr[0])
doAssert arr[0].int == 4
bar(int(arr[0])) # need vmgen flags propagated for this
doAssert arr[0].int == 5
proc testResult(): Foo =
result = Foo(1)
int(result) = int(result) + 1
doAssert result.int == 2
int(result) += 1
doAssert result.int == 3
foo(result)
doAssert result.int == 4
bar(int(result)) # need vmgen flags propagated for this
doAssert result.int == 5
doAssert testResult().int == 5