VM: fixes most ran-out-registers problems [backport] (#12485)

This commit is contained in:
Andreas Rumpf
2019-10-24 17:29:32 +02:00
committed by GitHub
parent 9ac062b746
commit 801a794039

View File

@@ -202,21 +202,19 @@ proc bestEffort(c: PCtx): TLineInfo =
else:
c.module.info
proc getTemp(cc: PCtx; tt: PType): TRegister =
let typ = tt.skipTypesOrNil({tyStatic})
proc getFreeRegister(cc: PCtx; k: TSlotKind; start: int): TRegister =
let c = cc.prc
# 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
for i in 0 .. c.maxSlots-1:
for i in start .. c.maxSlots-1:
if c.slots[i].kind == k and not c.slots[i].inUse:
c.slots[i].inUse = true
return TRegister(i)
# if register pressure is high, we re-use more aggressively:
if c.maxSlots >= HighRegisterPressure and false:
for i in 0 .. c.maxSlots-1:
if c.maxSlots >= high(TRegister):
for i in start .. c.maxSlots-1:
if not c.slots[i].inUse:
c.slots[i] = (inUse: true, kind: k)
return TRegister(i)
@@ -226,6 +224,14 @@ proc getTemp(cc: PCtx; tt: PType): TRegister =
c.slots[c.maxSlots] = (inUse: true, kind: k)
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) =
let c = c.prc
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 = {}) =
var tmp: TDest = -1
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 =
var tmp: TDest = -1
@@ -335,7 +343,15 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
c.gen(n.sons[1], dest)
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.clearDest(n, dest)
@@ -752,6 +768,7 @@ proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
tmp = c.genx(n.sons[2])
c.gABC(n, opc, dest, tmp, 0)
c.freeTemp(tmp)
c.freeTemp(dest)
proc genBinaryStmtVar(c: PCtx; n: PNode; opc: TOpcode) =
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.genAsgnPatch(n.sons[1], dest)
c.freeTemp(tmp)
c.freeTemp(dest)
proc genUnaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
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.genAsgnPatch(n.sons[1], d)
c.freeTemp(tmp)
c.freeTemp(d)
of mSwap:
unused(c, n, dest)
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) =
# XXX generate type initialization here?
if v.position == 0:
if c.prc.maxSlots == 0: c.prc.maxSlots = 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
v.position = getFreeRegister(c, if v.kind == skLet: slotFixedLet else: slotFixedVar, start = 1)
proc cannotEval(c: PCtx; n: PNode) {.noinline.} =
globalError(c.config, n.info, "cannot evaluate at compile time: " &
@@ -1501,6 +1514,8 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
else:
c.preventFalseAlias(le, opcWrArr, dest, idx, tmp)
c.freeTemp(tmp)
c.freeTemp(idx)
c.freeTemp(dest)
of nkCheckedFieldExpr:
var objR: TDest = -1
genCheckedObjAccessAux(c, le, objR, {gfNode})
@@ -1508,17 +1523,20 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
let tmp = c.genx(ri)
c.preventFalseAlias(le[0], opcWrObj, objR, idx, tmp)
c.freeTemp(tmp)
c.freeTemp(idx)
c.freeTemp(objR)
of nkDotExpr:
let dest = c.genx(le.sons[0], {gfNode})
let idx = genField(c, le.sons[1])
let tmp = c.genx(ri)
c.preventFalseAlias(le, opcWrObj, dest, idx, tmp)
c.freeTemp(idx)
c.freeTemp(tmp)
of nkDerefExpr, nkHiddenDeref:
let dest = c.genx(le.sons[0], {gfNode})
let tmp = c.genx(ri)
c.preventFalseAlias(le, opcWrDeref, dest, 0, tmp)
c.freeTemp(dest)
c.freeTemp(tmp)
of nkSym:
let s = le.sym
@@ -1545,6 +1563,7 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
else:
let dest = c.genx(le, {gfNodeAddr})
genAsgn(c, dest, ri, requiresCopy)
c.freeTemp(dest)
proc genTypeLit(c: PCtx; t: PType; dest: var TDest) =
var n = newNode(nkType)
@@ -1628,8 +1647,8 @@ template needsRegLoad(): untyped =
{gfNode, gfNodeAddr} * flags == {} and
fitsRegister(n.typ.skipTypes({tyVar, tyLent, tyStatic}))
proc genArrAccess2(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
flags: TGenFlags) =
proc genArrAccessOpcode(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode;
flags: TGenFlags) =
let a = c.genx(n.sons[0], flags)
let b = c.genIndex(n.sons[1], n.sons[0].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) =
let arrayType = n.sons[0].typ.skipTypes(abstractVarRange-{tyTypeDesc}).kind
if arrayType in {tyString, tyCString}:
genArrAccess2(c, n, dest, opcLdStrIdx, {})
genArrAccessOpcode(c, n, dest, opcLdStrIdx, {})
elif arrayType == tyTypeDesc:
c.genTypeLit(n.typ, dest)
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) =
if t != nil and t.len > 0 and t.sons[0] != nil: