new vm: lots of fixes
This commit is contained in:
parent
fca23d1675
commit
27b7ecbbff
3 changed files with 146 additions and 53 deletions
|
|
@ -10,7 +10,10 @@
|
||||||
## This file implements the new evaluation engine for Nimrod code.
|
## This file implements the new evaluation engine for Nimrod code.
|
||||||
## An instruction is 1-2 int32s in memory, it is a register based VM.
|
## An instruction is 1-2 int32s in memory, it is a register based VM.
|
||||||
|
|
||||||
import ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned
|
import
|
||||||
|
strutils, ast, astalgo, msgs, vmdef, vmgen, nimsets, types, passes, unsigned
|
||||||
|
|
||||||
|
from semfold import leValueConv
|
||||||
|
|
||||||
type
|
type
|
||||||
PStackFrame* = ref TStackFrame
|
PStackFrame* = ref TStackFrame
|
||||||
|
|
@ -79,10 +82,6 @@ template decodeBx(k: expr) {.immediate, dirty.} =
|
||||||
let rbx = instr.regBx - wordExcess
|
let rbx = instr.regBx - wordExcess
|
||||||
ensureKind(k)
|
ensureKind(k)
|
||||||
|
|
||||||
proc compile(c: PCtx, s: PSym): int =
|
|
||||||
result = vmgen.genProc(c, s)
|
|
||||||
#c.echoCode
|
|
||||||
|
|
||||||
proc myreset(n: PNode) =
|
proc myreset(n: PNode) =
|
||||||
when defined(system.reset):
|
when defined(system.reset):
|
||||||
var oldInfo = n.info
|
var oldInfo = n.info
|
||||||
|
|
@ -130,18 +129,14 @@ proc pushSafePoint(f: PStackFrame; pc: int) =
|
||||||
|
|
||||||
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
|
proc popSafePoint(f: PStackFrame) = discard f.safePoints.pop()
|
||||||
|
|
||||||
proc nextSafePoint(f: PStackFrame): int =
|
|
||||||
var f = f
|
|
||||||
while f.safePoints.isNil or f.safePoints.len == 0:
|
|
||||||
f = f.next
|
|
||||||
if f.isNil: return -1
|
|
||||||
result = f.safePoints.pop
|
|
||||||
|
|
||||||
proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int =
|
proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int =
|
||||||
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
let raisedType = c.currentExceptionA.typ.skipTypes(abstractPtrs)
|
||||||
|
var f = tos
|
||||||
while true:
|
while true:
|
||||||
var pc2 = tos.nextSafePoint
|
while f.safePoints.isNil or f.safePoints.len == 0:
|
||||||
if pc2 == -1: return -1
|
f = f.next
|
||||||
|
if f.isNil: return -1
|
||||||
|
var pc2 = f.safePoints[f.safePoints.high]
|
||||||
|
|
||||||
var nextExceptOrFinally = -1
|
var nextExceptOrFinally = -1
|
||||||
if c.code[pc2].opcode == opcExcept:
|
if c.code[pc2].opcode == opcExcept:
|
||||||
|
|
@ -163,6 +158,8 @@ proc cleanUpOnException(c: PCtx; tos: PStackFrame; regs: TNodeSeq): int =
|
||||||
if c.code[pc2].opcode == opcFinally:
|
if c.code[pc2].opcode == opcFinally:
|
||||||
# execute the corresponding handler, but don't quit walking the stack:
|
# execute the corresponding handler, but don't quit walking the stack:
|
||||||
return pc2
|
return pc2
|
||||||
|
# not the right one:
|
||||||
|
discard f.safePoints.pop
|
||||||
|
|
||||||
proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
||||||
if f.safePoints.isNil: return -1
|
if f.safePoints.isNil: return -1
|
||||||
|
|
@ -174,6 +171,10 @@ proc cleanUpOnReturn(c: PCtx; f: PStackFrame): int =
|
||||||
return pc
|
return pc
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
|
proc compile(c: PCtx, s: PSym): int =
|
||||||
|
result = vmgen.genProc(c, s)
|
||||||
|
#c.echoCode
|
||||||
|
|
||||||
proc execute(c: PCtx, start: int) =
|
proc execute(c: PCtx, start: int) =
|
||||||
var pc = start
|
var pc = start
|
||||||
var regs: TNodeSeq # alias to tos.slots for performance
|
var regs: TNodeSeq # alias to tos.slots for performance
|
||||||
|
|
@ -188,11 +189,12 @@ proc execute(c: PCtx, start: int) =
|
||||||
of opcEof: break
|
of opcEof: break
|
||||||
of opcRet:
|
of opcRet:
|
||||||
# XXX perform any cleanup actions
|
# XXX perform any cleanup actions
|
||||||
|
pc = tos.comesFrom
|
||||||
tos = tos.next
|
tos = tos.next
|
||||||
if tos.isNil: return
|
if tos.isNil: return
|
||||||
|
|
||||||
let retVal = regs[0]
|
let retVal = regs[0]
|
||||||
move(regs, tos.slots)
|
move(regs, tos.slots)
|
||||||
pc = tos.comesFrom
|
|
||||||
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
assert c.code[pc].opcode in {opcIndCall, opcIndCallAsgn}
|
||||||
if c.code[pc].opcode == opcIndCallAsgn:
|
if c.code[pc].opcode == opcIndCallAsgn:
|
||||||
regs[c.code[pc].regA] = retVal
|
regs[c.code[pc].regA] = retVal
|
||||||
|
|
@ -222,6 +224,10 @@ proc execute(c: PCtx, start: int) =
|
||||||
let idx = regs[rc].intVal
|
let idx = regs[rc].intVal
|
||||||
# XXX what if the array is not 0-based? -> codegen should insert a sub
|
# XXX what if the array is not 0-based? -> codegen should insert a sub
|
||||||
regs[ra] = regs[rb].sons[idx.int]
|
regs[ra] = regs[rb].sons[idx.int]
|
||||||
|
of opcLdStrIdx:
|
||||||
|
decodeBC(nkIntLit)
|
||||||
|
let idx = regs[rc].intVal
|
||||||
|
regs[ra].intVal = regs[rb].strVal[idx.int].ord
|
||||||
of opcWrArr:
|
of opcWrArr:
|
||||||
# a[b] = c
|
# a[b] = c
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
|
|
@ -432,6 +438,15 @@ proc execute(c: PCtx, start: int) =
|
||||||
regs[ra].strVal = getstr(regs[rb])
|
regs[ra].strVal = getstr(regs[rb])
|
||||||
for i in rb+1..rb+rc-1:
|
for i in rb+1..rb+rc-1:
|
||||||
regs[ra].strVal.add getstr(regs[i])
|
regs[ra].strVal.add getstr(regs[i])
|
||||||
|
of opcAddStrCh:
|
||||||
|
decodeB(nkStrLit)
|
||||||
|
regs[ra].strVal.add(regs[rb].intVal.chr)
|
||||||
|
of opcAddStrStr:
|
||||||
|
decodeB(nkStrLit)
|
||||||
|
regs[ra].strVal.add(regs[rb].strVal)
|
||||||
|
of opcAddSeqElem:
|
||||||
|
decodeB(nkBracket)
|
||||||
|
regs[ra].add(copyTree(regs[rb]))
|
||||||
of opcEcho:
|
of opcEcho:
|
||||||
echo regs[ra].strVal
|
echo regs[ra].strVal
|
||||||
of opcContainsSet:
|
of opcContainsSet:
|
||||||
|
|
@ -444,6 +459,14 @@ proc execute(c: PCtx, start: int) =
|
||||||
let rd = c.code[pc].regA
|
let rd = c.code[pc].regA
|
||||||
regs[ra].strVal = substr(regs[rb].strVal, regs[rc].intVal.int,
|
regs[ra].strVal = substr(regs[rb].strVal, regs[rc].intVal.int,
|
||||||
regs[rd].intVal.int)
|
regs[rd].intVal.int)
|
||||||
|
of opcRangeChck:
|
||||||
|
let rb = instr.regB
|
||||||
|
let rc = instr.regC
|
||||||
|
if not (leValueConv(regs[rb], regs[ra]) and
|
||||||
|
leValueConv(regs[ra], regs[rc])):
|
||||||
|
stackTrace(c, tos, pc, errGenerated,
|
||||||
|
msgKindToString(errIllegalConvFromXtoY) % [
|
||||||
|
"unknown type" , "unknown type"])
|
||||||
of opcIndCall, opcIndCallAsgn:
|
of opcIndCall, opcIndCallAsgn:
|
||||||
# dest = call regStart, n; where regStart = fn, arg1, ...
|
# dest = call regStart, n; where regStart = fn, arg1, ...
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
|
|
@ -545,6 +568,12 @@ proc execute(c: PCtx, start: int) =
|
||||||
regs[ra] = getNullValue(typ, c.debug[pc])
|
regs[ra] = getNullValue(typ, c.debug[pc])
|
||||||
of opcLdConst:
|
of opcLdConst:
|
||||||
regs[ra] = c.constants.sons[instr.regBx - wordExcess]
|
regs[ra] = c.constants.sons[instr.regBx - wordExcess]
|
||||||
|
of opcAsgnConst:
|
||||||
|
let rb = instr.regBx - wordExcess
|
||||||
|
if regs[ra].isNil:
|
||||||
|
regs[ra] = copyTree(c.constants.sons[rb])
|
||||||
|
else:
|
||||||
|
asgnComplex(regs[ra], c.constants.sons[rb])
|
||||||
of opcNBindSym:
|
of opcNBindSym:
|
||||||
# trivial implementation:
|
# trivial implementation:
|
||||||
let rb = instr.regB
|
let rb = instr.regB
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,6 @@ type
|
||||||
TDest* = range[-1 .. 255]
|
TDest* = range[-1 .. 255]
|
||||||
TInstr* = distinct uint32
|
TInstr* = distinct uint32
|
||||||
|
|
||||||
TInstrFormat = enum
|
|
||||||
ifABC, # three registers
|
|
||||||
ifABx, # A + extended B
|
|
||||||
|
|
||||||
TOpcode* = enum
|
TOpcode* = enum
|
||||||
opcEof, # end of code
|
opcEof, # end of code
|
||||||
opcRet, # return
|
opcRet, # return
|
||||||
|
|
@ -46,6 +42,7 @@ type
|
||||||
opcAddr,
|
opcAddr,
|
||||||
opcDeref,
|
opcDeref,
|
||||||
opcWrStrIdx,
|
opcWrStrIdx,
|
||||||
|
opcLdStrIdx, # a = b[c]
|
||||||
|
|
||||||
opcAddInt,
|
opcAddInt,
|
||||||
opcAddImmInt,
|
opcAddImmInt,
|
||||||
|
|
@ -66,12 +63,18 @@ type
|
||||||
opcSwap, opcIsNil, opcOf,
|
opcSwap, opcIsNil, opcOf,
|
||||||
opcSubStr, opcConv, opcCast, opcQuit, opcReset,
|
opcSubStr, opcConv, opcCast, opcQuit, opcReset,
|
||||||
|
|
||||||
|
opcAddStrCh,
|
||||||
|
opcAddStrStr,
|
||||||
|
opcAddSeqElem,
|
||||||
|
opcRangeChck,
|
||||||
|
|
||||||
opcEcho,
|
opcEcho,
|
||||||
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||||
opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
|
opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
|
||||||
|
|
||||||
opcRaise,
|
opcRaise,
|
||||||
opcNBindSym, # opcodes for the AST manipulation following
|
opcNBindSym, # opcodes for the AST manipulation following
|
||||||
|
opcNewStr,
|
||||||
|
|
||||||
opcTJmp, # jump Bx if A != 0
|
opcTJmp, # jump Bx if A != 0
|
||||||
opcFJmp, # jump Bx if A == 0
|
opcFJmp, # jump Bx if A == 0
|
||||||
|
|
@ -83,9 +86,9 @@ type
|
||||||
opcFinallyEnd,
|
opcFinallyEnd,
|
||||||
opcNew,
|
opcNew,
|
||||||
opcNewSeq,
|
opcNewSeq,
|
||||||
opcNewStr,
|
|
||||||
opcLdNull, # dest = nullvalue(types[Bx])
|
opcLdNull, # dest = nullvalue(types[Bx])
|
||||||
opcLdConst, # dest = constants[Bx]
|
opcLdConst, # dest = constants[Bx]
|
||||||
|
opcAsgnConst, # dest = copy(constants[Bx])
|
||||||
opcLdGlobal, # dest = globals[Bx]
|
opcLdGlobal, # dest = globals[Bx]
|
||||||
opcLdImmInt, # dest = immediate value
|
opcLdImmInt, # dest = immediate value
|
||||||
opcWrGlobal,
|
opcWrGlobal,
|
||||||
|
|
@ -100,7 +103,8 @@ type
|
||||||
# temporary slot usage. This is required for the parameter
|
# temporary slot usage. This is required for the parameter
|
||||||
# passing implementation.
|
# passing implementation.
|
||||||
slotEmpty, # slot is unused
|
slotEmpty, # slot is unused
|
||||||
slotFixed, # slot is used for a fixed var/param/result
|
slotFixedVar, # slot is used for a fixed var/result (requires copy then)
|
||||||
|
slotFixedLet, # slot is used for a fixed param/let
|
||||||
slotTempUnknown, # slot but type unknown (argument of proc call)
|
slotTempUnknown, # slot but type unknown (argument of proc call)
|
||||||
slotTempInt, # some temporary int
|
slotTempInt, # some temporary int
|
||||||
slotTempFloat, # some temporary float
|
slotTempFloat, # some temporary float
|
||||||
|
|
@ -117,11 +121,6 @@ type
|
||||||
code*: seq[TInstr]
|
code*: seq[TInstr]
|
||||||
debug*: seq[TLineInfo] # line info for every instruction; kept separate
|
debug*: seq[TLineInfo] # line info for every instruction; kept separate
|
||||||
# to not slow down interpretation
|
# to not slow down interpretation
|
||||||
jumpTargets*: TIntSet # we need to mark instructions that are
|
|
||||||
# jump targets;
|
|
||||||
# we must not optimize over a jump target and we
|
|
||||||
# need to generate a label for a jump target when
|
|
||||||
# producing a VM listing
|
|
||||||
globals*: PNode #
|
globals*: PNode #
|
||||||
constants*: PNode # constant data
|
constants*: PNode # constant data
|
||||||
types*: seq[PType] # some instructions reference types (e.g. 'except')
|
types*: seq[PType] # some instructions reference types (e.g. 'except')
|
||||||
|
|
@ -132,7 +131,7 @@ type
|
||||||
TPosition* = distinct int
|
TPosition* = distinct int
|
||||||
|
|
||||||
proc newCtx*(): PCtx =
|
proc newCtx*(): PCtx =
|
||||||
PCtx(code: @[], debug: @[], jumpTargets: initIntSet(),
|
PCtx(code: @[], debug: @[],
|
||||||
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
|
globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
|
||||||
prc: PProc(blocks: @[]))
|
prc: PProc(blocks: @[]))
|
||||||
|
|
||||||
|
|
@ -141,6 +140,7 @@ const
|
||||||
largeInstrs* = { # instructions which use 2 int32s instead of 1:
|
largeInstrs* = { # instructions which use 2 int32s instead of 1:
|
||||||
opcSubstr, opcConv, opcCast, opcNewSeq, opcOf}
|
opcSubstr, opcConv, opcCast, opcNewSeq, opcOf}
|
||||||
slotSomeTemp* = slotTempUnknown
|
slotSomeTemp* = slotTempUnknown
|
||||||
|
relativeJumps* = {opcTJmp, opcFJmp, opcJmp}
|
||||||
|
|
||||||
template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32)
|
template opcode*(x: TInstr): TOpcode {.immediate.} = TOpcode(x.uint32 and 0xff'u32)
|
||||||
template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
|
template regA*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 8'u32 and 0xff'u32)
|
||||||
|
|
|
||||||
|
|
@ -14,16 +14,30 @@ import
|
||||||
trees, intsets, rodread
|
trees, intsets, rodread
|
||||||
|
|
||||||
proc codeListing(c: PCtx, result: var string) =
|
proc codeListing(c: PCtx, result: var string) =
|
||||||
|
# first iteration: compute all necessary labels:
|
||||||
|
var jumpTargets = initIntSet()
|
||||||
|
|
||||||
|
for i in 0.. < c.code.len:
|
||||||
|
let x = c.code[i]
|
||||||
|
if x.opcode in relativeJumps:
|
||||||
|
jumpTargets.incl(i+x.regBx-wordExcess)
|
||||||
|
|
||||||
# for debugging purposes
|
# for debugging purposes
|
||||||
var i = 0
|
var i = 0
|
||||||
while i < c.code.len:
|
while i < c.code.len:
|
||||||
if i in c.jumpTargets: result.addf("L$1:\n", i)
|
if i in jumpTargets: result.addf("L$1:\n", i)
|
||||||
let x = c.code[i]
|
let x = c.code[i]
|
||||||
|
|
||||||
let opc = opcode(x)
|
let opc = opcode(x)
|
||||||
if opc < firstABxInstr:
|
if opc < firstABxInstr:
|
||||||
result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA,
|
result.addf("\t$#\tr$#, r$#, r$#", ($opc).substr(3), x.regA,
|
||||||
x.regB, x.regC)
|
x.regB, x.regC)
|
||||||
|
elif opc in relativeJumps:
|
||||||
|
result.addf("\t$#\tr$#, L$#", ($opc).substr(3), x.regA,
|
||||||
|
i+x.regBx-wordExcess)
|
||||||
|
elif opc in {opcLdConst, opcAsgnConst}:
|
||||||
|
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA,
|
||||||
|
c.constants[x.regBx-wordExcess].renderTree)
|
||||||
else:
|
else:
|
||||||
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
|
result.addf("\t$#\tr$#, $#", ($opc).substr(3), x.regA, x.regBx-wordExcess)
|
||||||
result.add("\t#")
|
result.add("\t#")
|
||||||
|
|
@ -64,7 +78,7 @@ proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition =
|
||||||
|
|
||||||
proc genLabel(c: PCtx): TPosition =
|
proc genLabel(c: PCtx): TPosition =
|
||||||
result = TPosition(c.code.len)
|
result = TPosition(c.code.len)
|
||||||
c.jumpTargets.incl(c.code.len)
|
#c.jumpTargets.incl(c.code.len)
|
||||||
|
|
||||||
proc jmpBack(c: PCtx, n: PNode, opc: TOpcode, p = TPosition(0)) =
|
proc jmpBack(c: PCtx, n: PNode, opc: TOpcode, p = TPosition(0)) =
|
||||||
let dist = p.int - c.code.len
|
let dist = p.int - c.code.len
|
||||||
|
|
@ -75,7 +89,7 @@ proc patch(c: PCtx, p: TPosition) =
|
||||||
# patch with current index
|
# patch with current index
|
||||||
let p = p.int
|
let p = p.int
|
||||||
let diff = c.code.len - p
|
let diff = c.code.len - p
|
||||||
c.jumpTargets.incl(c.code.len)
|
#c.jumpTargets.incl(c.code.len)
|
||||||
InternalAssert(-0x7fff < diff and diff < 0x7fff)
|
InternalAssert(-0x7fff < diff and diff < 0x7fff)
|
||||||
let oldInstr = c.code[p]
|
let oldInstr = c.code[p]
|
||||||
# opcode and regA stay the same:
|
# opcode and regA stay the same:
|
||||||
|
|
@ -195,10 +209,11 @@ proc genBlock(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
proc genBreak(c: PCtx; n: PNode) =
|
proc genBreak(c: PCtx; n: PNode) =
|
||||||
let L1 = c.xjmp(n, opcJmp)
|
let L1 = c.xjmp(n, opcJmp)
|
||||||
if n.sons[0].kind == nkSym:
|
if n.sons[0].kind == nkSym:
|
||||||
|
echo cast[int](n.sons[0].sym)
|
||||||
for i in countdown(c.prc.blocks.len-1, 0):
|
for i in countdown(c.prc.blocks.len-1, 0):
|
||||||
if c.prc.blocks[i].label == n.sons[0].sym:
|
if c.prc.blocks[i].label == n.sons[0].sym:
|
||||||
c.prc.blocks[i].fixups.add L1
|
c.prc.blocks[i].fixups.add L1
|
||||||
break
|
return
|
||||||
InternalError(n.info, "cannot find 'break' target")
|
InternalError(n.info, "cannot find 'break' target")
|
||||||
else:
|
else:
|
||||||
c.prc.blocks[c.prc.blocks.high].fixups.add L1
|
c.prc.blocks[c.prc.blocks.high].fixups.add L1
|
||||||
|
|
@ -365,7 +380,10 @@ proc genCall(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
|
||||||
proc genNew(c: PCtx; n: PNode) =
|
proc genNew(c: PCtx; n: PNode) =
|
||||||
let dest = c.genx(n.sons[1])
|
let dest = c.genx(n.sons[1])
|
||||||
c.gABx(n, opcNew, dest, c.genType(n.sons[1].typ.skipTypes(abstractVar)))
|
# we use the ref's base type here as the VM conflates 'ref object'
|
||||||
|
# and 'object' since internally we already have a pointer.
|
||||||
|
c.gABx(n, opcNew, dest,
|
||||||
|
c.genType(n.sons[1].typ.skipTypes(abstractVar).sons[0]))
|
||||||
c.freeTemp(dest)
|
c.freeTemp(dest)
|
||||||
|
|
||||||
proc genNewSeq(c: PCtx; n: PNode) =
|
proc genNewSeq(c: PCtx; n: PNode) =
|
||||||
|
|
@ -382,6 +400,12 @@ proc genUnaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
c.gABC(n, opc, dest, tmp)
|
c.gABC(n, opc, dest, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
|
proc genUnaryABI(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
|
let tmp = c.genx(n.sons[1])
|
||||||
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
c.gABI(n, opc, dest, tmp, 0)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
let
|
let
|
||||||
tmp = c.genx(n.sons[1])
|
tmp = c.genx(n.sons[1])
|
||||||
|
|
@ -391,6 +415,13 @@ proc genBinaryABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
c.freeTemp(tmp2)
|
c.freeTemp(tmp2)
|
||||||
|
|
||||||
|
proc genBinaryStmt(c: PCtx; n: PNode; opc: TOpcode) =
|
||||||
|
let
|
||||||
|
dest = c.genx(n.sons[1])
|
||||||
|
tmp = c.genx(n.sons[2])
|
||||||
|
c.gABC(n, opc, dest, tmp, 0)
|
||||||
|
c.freeTemp(tmp)
|
||||||
|
|
||||||
proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
proc genVarargsABC(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
if dest < 0: dest = getTemp(c, n.typ)
|
if dest < 0: dest = getTemp(c, n.typ)
|
||||||
var x = c.getTempRange(n.len-1, slotTempStr)
|
var x = c.getTempRange(n.len-1, slotTempStr)
|
||||||
|
|
@ -465,9 +496,9 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
c.gABC(n, opcNewStr, dest, tmp)
|
c.gABC(n, opcNewStr, dest, tmp)
|
||||||
c.freeTemp(tmp)
|
c.freeTemp(tmp)
|
||||||
of mLengthOpenArray, mLengthArray, mLengthSeq:
|
of mLengthOpenArray, mLengthArray, mLengthSeq:
|
||||||
genUnaryABC(c, n, dest, opcLenSeq)
|
genUnaryABI(c, n, dest, opcLenSeq)
|
||||||
of mLengthStr:
|
of mLengthStr:
|
||||||
genUnaryABC(c, n, dest, opcLenStr)
|
genUnaryABI(c, n, dest, opcLenStr)
|
||||||
of mIncl, mExcl:
|
of mIncl, mExcl:
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
var d = c.genx(n.sons[1])
|
var d = c.genx(n.sons[1])
|
||||||
|
|
@ -596,9 +627,15 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
var d = c.genx(n.sons[i])
|
var d = c.genx(n.sons[i])
|
||||||
c.gABC(n, opcEcho, d)
|
c.gABC(n, opcEcho, d)
|
||||||
c.freeTemp(d)
|
c.freeTemp(d)
|
||||||
of mAppendStrCh: InternalError(n.info, "cannot generate code for: " & $m)
|
of mAppendStrCh:
|
||||||
of mAppendStrStr: InternalError(n.info, "cannot generate code for: " & $m)
|
unused(n, dest)
|
||||||
of mAppendSeqElem: InternalError(n.info, "cannot generate code for: " & $m)
|
genBinaryStmt(c, n, opcAddStrCh)
|
||||||
|
of mAppendStrStr:
|
||||||
|
unused(n, dest)
|
||||||
|
genBinaryStmt(c, n, opcAddStrStr)
|
||||||
|
of mAppendSeqElem:
|
||||||
|
unused(n, dest)
|
||||||
|
genBinaryStmt(c, n, opcAddSeqElem)
|
||||||
of mParseExprToAst: InternalError(n.info, "cannot generate code for: " & $m)
|
of mParseExprToAst: InternalError(n.info, "cannot generate code for: " & $m)
|
||||||
of mParseStmtToAst: InternalError(n.info, "cannot generate code for: " & $m)
|
of mParseStmtToAst: InternalError(n.info, "cannot generate code for: " & $m)
|
||||||
of mExpandToAst: InternalError(n.info, "cannot generate code for: " & $m)
|
of mExpandToAst: InternalError(n.info, "cannot generate code for: " & $m)
|
||||||
|
|
@ -664,18 +701,18 @@ proc requiresCopy(n: PNode): bool =
|
||||||
else:
|
else:
|
||||||
result = true
|
result = true
|
||||||
|
|
||||||
proc unnecessaryIndirection(n: PNode): bool =
|
proc unneededIndirection(n: PNode): bool =
|
||||||
n.typ.skipTypes(abstractInst).kind == tyRef
|
n.typ.skipTypes(abstractInst).kind == tyRef
|
||||||
|
|
||||||
proc skipDeref(n: PNode): PNode =
|
proc skipDeref(n: PNode): PNode =
|
||||||
if n.kind in {nkDerefExpr, nkHiddenDeref} and unnecessaryIndirection(n):
|
if n.kind in {nkDerefExpr, nkHiddenDeref} and unneededIndirection(n.sons[0]):
|
||||||
result = n.sons[0]
|
result = n.sons[0]
|
||||||
else:
|
else:
|
||||||
result = n
|
result = n
|
||||||
|
|
||||||
proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
proc genAddrDeref(c: PCtx; n: PNode; dest: var TDest; opc: TOpcode) =
|
||||||
# a nop for certain types
|
# a nop for certain types
|
||||||
if unnecessaryIndirection(n):
|
if unneededIndirection(n.sons[0]):
|
||||||
gen(c, n.sons[0], dest)
|
gen(c, n.sons[0], dest)
|
||||||
else:
|
else:
|
||||||
let tmp = c.genx(n.sons[0])
|
let tmp = c.genx(n.sons[0])
|
||||||
|
|
@ -740,9 +777,11 @@ proc genAsgn(c: PCtx; le, ri: PNode; requiresCopy: bool) =
|
||||||
genAsgn(c, dest, ri, requiresCopy)
|
genAsgn(c, dest, ri, requiresCopy)
|
||||||
|
|
||||||
proc genLit(c: PCtx; n: PNode; dest: var TDest) =
|
proc genLit(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
|
var opc = opcLdConst
|
||||||
if dest < 0: dest = c.getTemp(n.typ)
|
if dest < 0: dest = c.getTemp(n.typ)
|
||||||
|
elif c.prc.slots[dest].kind == slotFixedVar: opc = opcAsgnConst
|
||||||
let lit = genLiteral(c, n)
|
let lit = genLiteral(c, n)
|
||||||
c.gABx(n, opcLdConst, dest, lit)
|
c.gABx(n, opc, dest, lit)
|
||||||
|
|
||||||
proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
|
proc genRdVar(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
let s = n.sym
|
let s = n.sym
|
||||||
|
|
@ -775,7 +814,10 @@ proc genObjAccess(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
genAccess(c, n, dest, opcLdObj)
|
genAccess(c, n, dest, opcLdObj)
|
||||||
|
|
||||||
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest) =
|
proc genArrAccess(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
genAccess(c, n, dest, opcLdArr)
|
if n.sons[0].typ.skipTypes(abstractVarRange).kind in {tyString, tyCString}:
|
||||||
|
genAccess(c, n, dest, opcLdStrIdx)
|
||||||
|
else:
|
||||||
|
genAccess(c, n, dest, opcLdArr)
|
||||||
|
|
||||||
proc getNullValue*(typ: PType, info: TLineInfo): PNode
|
proc getNullValue*(typ: PType, info: TLineInfo): PNode
|
||||||
proc getNullValueAux(obj: PNode, result: PNode) =
|
proc getNullValueAux(obj: PNode, result: PNode) =
|
||||||
|
|
@ -827,7 +869,8 @@ proc setSlot(c: PCtx; v: PSym) =
|
||||||
# XXX generate type initialization here?
|
# XXX generate type initialization here?
|
||||||
if v.position == 0:
|
if v.position == 0:
|
||||||
v.position = c.prc.maxSlots
|
v.position = c.prc.maxSlots
|
||||||
c.prc.slots[v.position] = (inUse: true, kind: slotFixed)
|
c.prc.slots[v.position] = (inUse: true,
|
||||||
|
kind: if v.kind == skLet: slotFixedLet else: slotFixedVar)
|
||||||
inc c.prc.maxSlots
|
inc c.prc.maxSlots
|
||||||
|
|
||||||
proc genVarSection(c: PCtx; n: PNode) =
|
proc genVarSection(c: PCtx; n: PNode) =
|
||||||
|
|
@ -959,36 +1002,56 @@ proc gen(c: PCtx; n: PNode; dest: var TDest) =
|
||||||
let s = n.sons[namePos].sym
|
let s = n.sons[namePos].sym
|
||||||
discard genProc(c, s)
|
discard genProc(c, s)
|
||||||
genLit(c, n.sons[namePos], dest)
|
genLit(c, n.sons[namePos], dest)
|
||||||
|
of nkChckRangeF, nkChckRange64, nkChckRange:
|
||||||
|
let
|
||||||
|
tmp0 = c.genx(n.sons[0])
|
||||||
|
tmp1 = c.genx(n.sons[1])
|
||||||
|
tmp2 = c.genx(n.sons[2])
|
||||||
|
c.gABC(n, opcRangeChck, tmp0, tmp1, tmp2)
|
||||||
|
c.freeTemp(tmp1)
|
||||||
|
c.freeTemp(tmp2)
|
||||||
|
if dest >= 0:
|
||||||
|
gABC(c, n, whichAsgnOpc(n), dest, tmp0)
|
||||||
|
c.freeTemp(tmp0)
|
||||||
|
else:
|
||||||
|
dest = tmp0
|
||||||
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
|
of nkEmpty, nkCommentStmt, nkTypeSection, nkConstSection, nkPragma,
|
||||||
nkTemplateDef, nkIncludeStmt, nkImportStmt:
|
nkTemplateDef, nkIncludeStmt, nkImportStmt:
|
||||||
unused(n, dest)
|
unused(n, dest)
|
||||||
|
of nkStringToCString, nkCStringToString:
|
||||||
|
gen(c, n.sons[0], dest)
|
||||||
else:
|
else:
|
||||||
#of nkCurly, nkBracket, nkPar:
|
#of nkCurly, nkBracket, nkPar:
|
||||||
InternalError n.info, "too implement " & $n.kind
|
InternalError n.info, "too implement " & $n.kind
|
||||||
|
|
||||||
proc genStmt*(c: PCtx; n: PNode): int =
|
proc removeLastEof(c: PCtx) =
|
||||||
result = c.code.len
|
|
||||||
var d: TDest = -1
|
|
||||||
gen(c, n, d)
|
|
||||||
let last = c.code.len-1
|
let last = c.code.len-1
|
||||||
if last >= 0 and c.code[last].opcode == opcEof:
|
if last >= 0 and c.code[last].opcode == opcEof:
|
||||||
# since we can re-use the EOF nothing happened:
|
# overwrite last EOF:
|
||||||
result = last
|
assert c.code.len == c.debug.len
|
||||||
else:
|
c.code.setLen(last)
|
||||||
gABC(c, n, opcEof)
|
c.debug.setLen(last)
|
||||||
|
|
||||||
|
proc genStmt*(c: PCtx; n: PNode): int =
|
||||||
|
c.removeLastEof
|
||||||
|
result = c.code.len
|
||||||
|
var d: TDest = -1
|
||||||
|
c.gen(n, d)
|
||||||
|
c.gABC(n, opcEof)
|
||||||
InternalAssert d < 0
|
InternalAssert d < 0
|
||||||
|
|
||||||
proc genParams(c: PCtx; params: PNode) =
|
proc genParams(c: PCtx; params: PNode) =
|
||||||
# res.sym.position is already 0
|
# res.sym.position is already 0
|
||||||
c.prc.slots[0] = (inUse: true, kind: slotFixed)
|
c.prc.slots[0] = (inUse: true, kind: slotFixedVar)
|
||||||
for i in 1.. <params.len:
|
for i in 1.. <params.len:
|
||||||
let param = params.sons[i].sym
|
let param = params.sons[i].sym
|
||||||
c.prc.slots[i] = (inUse: true, kind: slotFixed)
|
c.prc.slots[i] = (inUse: true, kind: slotFixedLet)
|
||||||
c.prc.maxSlots = max(params.len, 1)
|
c.prc.maxSlots = max(params.len, 1)
|
||||||
|
|
||||||
proc genProc(c: PCtx; s: PSym): int =
|
proc genProc(c: PCtx; s: PSym): int =
|
||||||
let x = s.ast.sons[optimizedCodePos]
|
let x = s.ast.sons[optimizedCodePos]
|
||||||
if x.kind == nkEmpty:
|
if x.kind == nkEmpty:
|
||||||
|
c.removeLastEof
|
||||||
result = c.code.len+1 # skip the jump instruction
|
result = c.code.len+1 # skip the jump instruction
|
||||||
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
|
s.ast.sons[optimizedCodePos] = newIntNode(nkIntLit, result)
|
||||||
# thanks to the jmp we can add top level statements easily and also nest
|
# thanks to the jmp we can add top level statements easily and also nest
|
||||||
|
|
@ -1004,6 +1067,7 @@ proc genProc(c: PCtx; s: PSym): int =
|
||||||
# generate final 'return' statement:
|
# generate final 'return' statement:
|
||||||
c.gABC(body, opcRet)
|
c.gABC(body, opcRet)
|
||||||
c.patch(procStart)
|
c.patch(procStart)
|
||||||
|
c.gABC(body, opcEof)
|
||||||
s.position = c.prc.maxSlots
|
s.position = c.prc.maxSlots
|
||||||
c.prc = oldPrc
|
c.prc = oldPrc
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue