VM: fixes most ran-out-registers problems [backport] (#12485)
This commit is contained in:
parent
9ac062b746
commit
801a794039
1 changed files with 38 additions and 19 deletions
|
|
@ -202,21 +202,19 @@ proc bestEffort(c: PCtx): TLineInfo =
|
||||||
else:
|
else:
|
||||||
c.module.info
|
c.module.info
|
||||||
|
|
||||||
proc getTemp(cc: PCtx; tt: PType): TRegister =
|
proc getFreeRegister(cc: PCtx; k: TSlotKind; start: int): TRegister =
|
||||||
let typ = tt.skipTypesOrNil({tyStatic})
|
|
||||||
let c = cc.prc
|
let c = cc.prc
|
||||||
# we prefer the same slot kind here for efficiency. Unfortunately for
|
# we prefer the same slot kind here for efficiency. Unfortunately for
|
||||||
# discardable return types we may not know the desired type. This can happen
|
# discardable return types we may not know the desired type. This can happen
|
||||||
# for e.g. mNAdd[Multiple]:
|
# for e.g. mNAdd[Multiple]:
|
||||||
let k = if typ.isNil: slotTempComplex else: typ.getSlotKind
|
for i in start .. c.maxSlots-1:
|
||||||
for i in 0 .. c.maxSlots-1:
|
|
||||||
if c.slots[i].kind == k and not c.slots[i].inUse:
|
if c.slots[i].kind == k and not c.slots[i].inUse:
|
||||||
c.slots[i].inUse = true
|
c.slots[i].inUse = true
|
||||||
return TRegister(i)
|
return TRegister(i)
|
||||||
|
|
||||||
# if register pressure is high, we re-use more aggressively:
|
# if register pressure is high, we re-use more aggressively:
|
||||||
if c.maxSlots >= HighRegisterPressure and false:
|
if c.maxSlots >= high(TRegister):
|
||||||
for i in 0 .. c.maxSlots-1:
|
for i in start .. c.maxSlots-1:
|
||||||
if not c.slots[i].inUse:
|
if not c.slots[i].inUse:
|
||||||
c.slots[i] = (inUse: true, kind: k)
|
c.slots[i] = (inUse: true, kind: k)
|
||||||
return TRegister(i)
|
return TRegister(i)
|
||||||
|
|
@ -226,6 +224,14 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
|
||||||
c.slots[c.maxSlots] = (inUse: true, kind: k)
|
c.slots[c.maxSlots] = (inUse: true, kind: k)
|
||||||
inc c.maxSlots
|
inc c.maxSlots
|
||||||
|
|
||||||
|
proc getTemp(cc: PCtx; tt: PType): TRegister =
|
||||||
|
let typ = tt.skipTypesOrNil({tyStatic})
|
||||||
|
# we prefer the same slot kind here for efficiency. Unfortunately for
|
||||||
|
# discardable return types we may not know the desired type. This can happen
|
||||||
|
# for e.g. mNAdd[Multiple]:
|
||||||
|
let k = if typ.isNil: slotTempComplex else: typ.getSlotKind
|
||||||
|
result = getFreeRegister(cc, k, start = 0)
|
||||||
|
|
||||||
proc freeTemp(c: PCtx; r: TRegister) =
|
proc freeTemp(c: PCtx; r: TRegister) =
|
||||||
let c = c.prc
|
let c = c.prc
|
||||||
if c.slots[r].kind in {slotSomeTemp..slotTempComplex}:
|
if c.slots[r].kind in {slotSomeTemp..slotTempComplex}:
|
||||||
|
|
@ -278,7 +284,9 @@ proc gen(c: PCtx; n: PNode; dest: TRegister; flags: TGenFlags = {}) =
|
||||||
proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
|
proc gen(c: PCtx; n: PNode; flags: TGenFlags = {}) =
|
||||||
var tmp: TDest = -1
|
var tmp: TDest = -1
|
||||||
gen(c, n, tmp, flags)
|
gen(c, n, tmp, flags)
|
||||||
#if n.typ.isEmptyType: InternalAssert tmp < 0
|
if tmp >= 0:
|
||||||
|
freeTemp(c, tmp)
|
||||||
|
#if n.typ.isEmptyType: internalAssert tmp < 0
|
||||||
|
|
||||||
proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
|
proc genx(c: PCtx; n: PNode; flags: TGenFlags = {}): TRegister =
|
||||||
var tmp: TDest = -1
|
var tmp: TDest = -1
|
||||||
|
|
@ -335,7 +343,15 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.gen(n.sons[1], dest)
|
c.gen(n.sons[1], dest)
|
||||||
|
|
||||||
for i in oldRegisterCount ..< c.prc.maxSlots:
|
for i in oldRegisterCount ..< c.prc.maxSlots:
|
||||||
if c.prc.slots[i].kind in {slotFixedVar, slotFixedLet}:
|
#if c.prc.slots[i].kind in {slotFixedVar, slotFixedLet}:
|
||||||
|
if i != dest:
|
||||||
|
when not defined(release):
|
||||||
|
if c.prc.slots[i].inUse and c.prc.slots[i].kind in {slotTempUnknown,
|
||||||
|
slotTempInt,
|
||||||
|
slotTempFloat,
|
||||||
|
slotTempStr,
|
||||||
|
slotTempComplex}:
|
||||||
|
doAssert false, "leaking temporary " & $i & " " & $c.prc.slots[i].kind
|
||||||
c.prc.slots[i] = (inUse: false, kind: slotEmpty)
|
c.prc.slots[i] = (inUse: false, kind: slotEmpty)
|
||||||
|
|
||||||
c.clearDest(n, dest)
|
c.clearDest(n, dest)
|
||||||
|
|
@ -752,6 +768,7 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
tmp = c.genx(n.sons[2])
|
tmp = c.genx(n.sons[2])
|
||||||
c.gABC(n, opc, dest, tmp, 0)
|
c.gABC(n, opc, dest, tmp, 0)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(dest)
|
||||||
|
|
||||||
proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
var x = n.sons[1]
|
var x = n.sons[1]
|
||||||
|
|
@ -762,6 +779,7 @@ proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
c.gABC(n, opc, dest, tmp, 0)
|
c.gABC(n, opc, dest, tmp, 0)
|
||||||
#c.genAsgnPatch(n.sons[1], dest)
|
#c.genAsgnPatch(n.sons[1], dest)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(dest)
|
||||||
|
|
||||||
proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
let tmp = c.genx(n.sons[1])
|
let tmp = c.genx(n.sons[1])
|
||||||
|
|
@ -1085,6 +1103,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
|
||||||
c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
|
c.gABC(n, if m == mSetLengthStr: opcSetLenStr else: opcSetLenSeq, d, tmp)
|
||||||
c.genAsgnPatch(n.sons[1], d)
|
c.genAsgnPatch(n.sons[1], d)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(d)
|
||||||
of mSwap:
|
of mSwap:
|
||||||
unused(c, n, dest)
|
unused(c, n, dest)
|
||||||
c.gen(lowerSwap(c.graph, n, if c.prc == nil: c.module else: c.prc.sym))
|
c.gen(lowerSwap(c.graph, n, if c.prc == nil: c.module else: c.prc.sym))
|
||||||
|
|
@ -1434,13 +1453,7 @@ proc genAsgn(c: PCtx; dest: TDest; ri: PNode; requiresCopy: bool) =
|
||||||
proc setSlot(c: PCtx; v: PSym) =
|
proc setSlot(c: PCtx; v: PSym) =
|
||||||
# XXX generate type initialization here?
|
# XXX generate type initialization here?
|
||||||
if v.position == 0:
|
if v.position == 0:
|
||||||
if c.prc.maxSlots == 0: c.prc.maxSlots = 1
|
v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
|
||||||
if c.prc.maxSlots >= high(TRegister):
|
|
||||||
globalError(c.config, v.info, "cannot generate code; too many registers required")
|
|
||||||
v.position = c.prc.maxSlots
|
|
||||||
c.prc.slots[v.position] = (inUse: true,
|
|
||||||
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
|
||||||
inc c.prc.maxSlots
|
|
||||||
|
|
||||||
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
|
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
|
||||||
globalError(c.config, n.info, "cannot evaluate at compile time: " &
|
globalError(c.config, n.info, "cannot evaluate at compile time: " &
|
||||||
|
|
@ -1501,6 +1514,8 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
else:
|
else:
|
||||||
c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
|
c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(idx)
|
||||||
|
c.freeTemp(dest)
|
||||||
of nkCheckedFieldExpr:
|
of nkCheckedFieldExpr:
|
||||||
var objR: TDest = -1
|
var objR: TDest = -1
|
||||||
genCheckedObjAccessAux(c, le, objR, {gfNode})
|
genCheckedObjAccessAux(c, le, objR, {gfNode})
|
||||||
|
|
@ -1508,17 +1523,20 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
let tmp = c.genx(ri)
|
let tmp = c.genx(ri)
|
||||||
c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
|
c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
c.freeTemp(idx)
|
||||||
c.freeTemp(objR)
|
c.freeTemp(objR)
|
||||||
of nkDotExpr:
|
of nkDotExpr:
|
||||||
let dest = c.genx(le.sons[0], {gfNode})
|
let dest = c.genx(le.sons[0], {gfNode})
|
||||||
let idx = genField(c, le.sons[1])
|
let idx = genField(c, le.sons[1])
|
||||||
let tmp = c.genx(ri)
|
let tmp = c.genx(ri)
|
||||||
c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
|
c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
|
||||||
|
c.freeTemp(idx)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
of nkDerefExpr, nkHiddenDeref:
|
of nkDerefExpr, nkHiddenDeref:
|
||||||
let dest = c.genx(le.sons[0], {gfNode})
|
let dest = c.genx(le.sons[0], {gfNode})
|
||||||
let tmp = c.genx(ri)
|
let tmp = c.genx(ri)
|
||||||
c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
|
c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
|
||||||
|
c.freeTemp(dest)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
of nkSym:
|
of nkSym:
|
||||||
let s = le.sym
|
let s = le.sym
|
||||||
|
|
@ -1545,6 +1563,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
else:
|
else:
|
||||||
let dest = c.genx(le, {gfNodeAddr})
|
let dest = c.genx(le, {gfNodeAddr})
|
||||||
genAsgn(c, dest, ri, requiresCopy)
|
genAsgn(c, dest, ri, requiresCopy)
|
||||||
|
c.freeTemp(dest)
|
||||||
|
|
||||||
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
|
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
|
||||||
var n = newNode(nkType)
|
var n = newNode(nkType)
|
||||||
|
|
@ -1628,8 +1647,8 @@ template needsRegLoad(): untyped =
|
||||||
{gfNode, gfNodeAddr} * flags == {} and
|
{gfNode, gfNodeAddr} * flags == {} and
|
||||||
fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic}))
|
fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic}))
|
||||||
|
|
||||||
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
|
||||||
flags: TGenFlags) =
|
flags: TGenFlags) =
|
||||||
let a = c.genx(n.sons[0], flags)
|
let a = c.genx(n.sons[0], flags)
|
||||||
let b = c.genIndex(n.sons[1], n.sons[0].typ)
|
let b = c.genIndex(n.sons[1], n.sons[0].typ)
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
|
@ -1715,11 +1734,11 @@ proc genCheckedObjAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest; flags: TGenFlags) =
|
||||||
let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
|
||||||
if arrayType in {tyString, tyCString}:
|
if arrayType in {tyString, tyCString}:
|
||||||
genArrAccess2(c, n, dest, opcLdStrIdx, {})
|
genArrAccessOpcode(c, n, dest, opcLdStrIdx, {})
|
||||||
elif arrayType == tyTypeDesc:
|
elif arrayType == tyTypeDesc:
|
||||||
c.genTypeLit(n.typ, dest)
|
c.genTypeLit(n.typ, dest)
|
||||||
else:
|
else:
|
||||||
genArrAccess2(c, n, dest, opcLdArr, flags)
|
genArrAccessOpcode(c, n, dest, opcLdArr, flags)
|
||||||
|
|
||||||
proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
|
proc getNullValueAux(t: PType; obj: PNode, result: PNode; conf: ConfigRef; currPosition: var int) =
|
||||||
if t != nil and t.len > 0 and t.sons[0] != nil:
|
if t != nil and t.len > 0 and t.sons[0] != nil:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue