summary refs log tree commit diff stats
path: root/compiler/vmdef.nim
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2013-07-24 21:39:39 +0200
committerAraq <rumpf_a@web.de>2013-07-24 21:39:39 +0200
commitb30e237a3746b4c4c421a87277a6458642c9f13a (patch)
treeaa695bb65169ed47c0e1f30e46a83b38b98c7e94 /compiler/vmdef.nim
parent84534ce4b8d2717f672e870921cab46dc2397c28 (diff)
downloadNim-b30e237a3746b4c4c421a87277a6458642c9f13a.tar.gz
first steps to a new evaluation engine
Diffstat (limited to 'compiler/vmdef.nim')
-rw-r--r--compiler/vmdef.nim149
1 files changed, 149 insertions, 0 deletions
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
new file mode 100644
index 000000000..cbad16516
--- /dev/null
+++ b/compiler/vmdef.nim
@@ -0,0 +1,149 @@
+#
+#
+#           The Nimrod Compiler
+#        (c) Copyright 2013 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## This module contains the type definitions for the new evaluation engine.
+## An instruction is 1-2 int32s in memory, it is a register based VM.
+
+import ast, passes, msgs, intsets
+
+const
+  byteExcess* = 128 # we use excess-K for immediates
+  wordExcess* = 32768
+
+type
+  TRegister* = range[0..255]
+  TDest* = range[-1 .. 255]
+  TInstr* = distinct uint32
+
+  TInstrFormat = enum
+    ifABC,  # three registers
+    ifABx,  # A + extended B
+
+  TOpcode* = enum
+    opcEof,         # end of code
+    opcRet,         # return
+    opcYldYoid,     # yield with no value
+    opcYldVal,      # yield with a value
+    
+    opcAsgnInt,
+    opcAsgnStr,
+    opcAsgnFloat,
+    opcAsgnRef,
+    opcAsgnComplex,
+
+    opcLdArr,  # a = b[c]
+    opcWrArr,  # a[b] = c
+    opcWrArrRef,
+    opcLdObj,  # a = b.c
+    opcWrObj,  # a.b = c
+    opcWrObjRef,
+    opcAddr,
+    opcDeref,
+    opcWrStrIdx,
+    
+    opcAddInt, 
+    opcAddImmInt,
+    opcSubInt,
+    opcSubImmInt,
+    opcLenSeq,
+    opcLenStr,
+
+    opcIncl, opcExcl, opcCard, opcMulInt, opcDivInt, opcModInt,
+    opcAddFloat, opcSubFloat, opcMulFloat, opcDivFloat, opcShrInt, opcShlInt,
+    opcBitandInt, opcBitorInt, opcBitxorInt, opcAddu, opcSubu, opcMulu, 
+    opcDivu, opcModu, opcEqInt, opcLeInt, opcLtInt, opcEqFloat, 
+    opcLeFloat, opcLtFloat, opcLeu, opcLtu, opcEqRef, opcXor, 
+    opcNot, opcUnaryMinusInt, opcUnaryMinusFloat, opcBitnotInt, 
+    opcEqStr, opcLeStr, opcLtStr, opcEqSet, opcLeSet, opcLtSet,
+    opcMulSet, opcPlusSet, opcMinusSet, opcSymdiffSet, opcConcatStr,
+    opcContainsSet, opcRepr, opcSetLenStr, opcSetLenSeq,
+    opcSwap, opcIsNil, opcOf,
+    opcSubStr, opcConv, opcCast, opcQuit, opcReset,
+    
+    opcEcho,
+    opcIndCall, # dest = call regStart, n; where regStart = fn, arg1, ...
+    opcIndCallAsgn, # dest = call regStart, n; where regStart = fn, arg1, ...
+
+    opcRaise,
+    opcNBindSym, # opcodes for the AST manipulation following
+  
+    opcTJmp,  # jump Bx if A != 0
+    opcFJmp,  # jump Bx if A == 0
+    opcJmp,   # jump Bx
+    opcBranch,  # branch for 'case'
+    opcTry,
+    opcExcept,
+    opcFinally,
+    opcFinallyEnd,
+    opcNew,
+    opcNewSeq,
+    opcNewStr,
+    opcLdNull,    # dest = nullvalue(types[Bx])
+    opcLdConst,   # dest = constants[Bx]
+    opcLdGlobal,  # dest = globals[Bx]
+    opcLdImmInt,  # dest = immediate value
+    opcWrGlobal,
+    opcWrGlobalRef
+
+  TBlock* = object
+    label*: PSym
+    fixups*: seq[TPosition]
+
+  TSlotKind* = enum   # We try to re-use slots in a smart way to
+                      # minimize allocations; however the VM supports arbitrary
+                      # temporary slot usage. This is required for the parameter
+                      # passing implementation.
+    slotEmpty,        # slot is unused
+    slotFixed,        # slot is used for a fixed var/param/result
+    slotTempUnknown,  # slot but type unknown (argument of proc call)
+    slotTempInt,      # some temporary int
+    slotTempFloat,    # some temporary float
+    slotTempStr,      # some temporary string
+    slotTempComplex   # some complex temporary (n.sons field is used)
+
+  PProc* = ref object
+    blocks*: seq[TBlock]    # blocks; temp data structure
+    slots*: array[TRegister, tuple[inUse: bool, kind: TSlotKind]]
+    maxSlots*: int
+    
+  PCtx* = ref TCtx
+  TCtx* = object of passes.TPassContext # code gen context
+    code*: seq[TInstr]
+    debug*: seq[TLineInfo]  # line info for every instruction; kept separate
+                            # 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         # 
+    constants*: PNode       # constant data
+    types*: seq[PType]      # some instructions reference types (e.g. 'except')
+    currentExceptionA*, currentExceptionB*: PNode
+    exceptionInstr*: int # index of instruction that raised the exception
+    prc*: PProc
+
+  TPosition* = distinct int
+  
+proc newCtx*(): PCtx =
+  PCtx(code: @[], debug: @[], jumpTargets: initIntSet(),
+    globals: newNode(nkStmtList), constants: newNode(nkStmtList), types: @[],
+    prc: PProc(blocks: @[]))
+
+const
+  firstABxInstr* = opcTJmp
+  largeInstrs* = { # instructions which use 2 int32s instead of 1:
+    opcSubstr, opcConv, opcCast, opcNewSeq, opcOf}
+  slotSomeTemp* = slotTempUnknown
+
+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 regB*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 16'u32 and 0xff'u32)
+template regC*(x: TInstr): TRegister {.immediate.} = TRegister(x.uint32 shr 24'u32)
+template regBx*(x: TInstr): int {.immediate.} = (x.uint32 shr 16'u32).int