mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
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:
@@ -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
49
tests/vm/tconvaddr.nim
Normal 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
|
||||
Reference in New Issue
Block a user