From 6aade97fe82e0308693587aa0d920aeac5a075e1 Mon Sep 17 00:00:00 2001 From: Ico Doornekamp Date: Sat, 30 Nov 2019 13:38:36 +0100 Subject: [PATCH] Refactored VM registerlayout. The size and location of the registers in (#12775) the instructions are now all derived from a single definition, allowing the register layout to be changed. --- compiler/vmdef.nim | 43 ++++++++++++++++++++++++++++++++++--------- compiler/vmgen.nim | 40 ++++++++++++++++++++-------------------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim index 81de277df3..0c3c54d0e2 100644 --- a/compiler/vmdef.nim +++ b/compiler/vmdef.nim @@ -12,17 +12,42 @@ import ast, idents, options, modulegraphs, lineinfos +type TInstrType* = uint32 + const + regOBits = 8 # Opcode + regABits = 8 + regBBits = 8 + regCBits = 8 + regBxBits = 16 + byteExcess* = 128 # we use excess-K for immediates - wordExcess* = 32768 MaxLoopIterations* = 10_000_000 # max iterations of all loops +# Calculate register shifts, masks and ranges + +const + regOShift* = 0.TInstrType + regAShift* = (regOShift + regOBits) + regBShift* = (regAShift + regABits) + regCShift* = (regBShift + regBBits) + regBxShift* = (regAShift + regABits) + + regOMask* = ((1.TInstrType shl regOBits) - 1) + regAMask* = ((1.TInstrType shl regABits) - 1) + regBMask* = ((1.TInstrType shl regBBits) - 1) + regCMask* = ((1.TInstrType shl regCBits) - 1) + regBxMask* = ((1.TInstrType shl regBxBits) - 1) + + wordExcess* = 1 shl (regBxBits-1) + regBxMin* = -wordExcess+1 + regBxMax* = wordExcess-1 type - TRegister* = range[0..255] - TDest* = range[-1..255] - TInstr* = distinct uint32 + TRegister* = range[0..regAMask.int] + TDest* = range[-1..regAMask.int] + TInstr* = distinct TInstrType TOpcode* = enum opcEof, # end of code @@ -254,10 +279,10 @@ const # flag is used to signal opcSeqLen if node is NimNode. const nimNodeFlag* = 16 -template opcode*(x: TInstr): TOpcode = TOpcode(x.uint32 and 0xff'u32) -template regA*(x: TInstr): TRegister = TRegister(x.uint32 shr 8'u32 and 0xff'u32) -template regB*(x: TInstr): TRegister = TRegister(x.uint32 shr 16'u32 and 0xff'u32) -template regC*(x: TInstr): TRegister = TRegister(x.uint32 shr 24'u32) -template regBx*(x: TInstr): int = (x.uint32 shr 16'u32).int +template opcode*(x: TInstr): TOpcode = TOpcode(x.TInstrType shr regOShift and regOMask) +template regA*(x: TInstr): TRegister = TRegister(x.TInstrType shr regAShift and regAMask) +template regB*(x: TInstr): TRegister = TRegister(x.TInstrType shr regBShift and regBMask) +template regC*(x: TInstr): TRegister = TRegister(x.TInstrType shr regCShift and regCMask) +template regBx*(x: TInstr): int = (x.TInstrType shr regBxShift and regBxMask).int template jmpDiff*(x: TInstr): int = regBx(x) - wordExcess diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim index f8f4b81dd7..987fc7864a 100644 --- a/compiler/vmgen.nim +++ b/compiler/vmgen.nim @@ -116,9 +116,9 @@ proc gABC(ctx: PCtx; n: PNode; opc: TOpcode; a, b, c: TRegister = 0) = ## stores the result into register `a` ## The node is needed for debug information assert opc.ord < 255 - let ins = (opc.uint32 or (a.uint32 shl 8'u32) or - (b.uint32 shl 16'u32) or - (c.uint32 shl 24'u32)).TInstr + let ins = (opc.TInstrType or (a.TInstrType shl regAShift) or + (b.TInstrType shl regBShift) or + (c.TInstrType shl regCShift)).TInstr when false: if ctx.code.len == 43: writeStackTrace() @@ -131,9 +131,9 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) = # and stores the output value into `a`. # `imm` is signed and must be within [-128, 127] if imm >= -128 and imm <= 127: - let ins = (opc.uint32 or (a.uint32 shl 8'u32) or - (b.uint32 shl 16'u32) or - (imm+byteExcess).uint32 shl 24'u32).TInstr + let ins = (opc.TInstrType or (a.TInstrType shl regAShift) or + (b.TInstrType shl regBShift) or + (imm+byteExcess).TInstrType shl regCShift).TInstr c.code.add(ins) c.debug.add(n.info) else: @@ -142,20 +142,20 @@ proc gABI(c: PCtx; n: PNode; opc: TOpcode; a, b: TRegister; imm: BiggestInt) = proc gABx(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0; bx: int) = # Applies `opc` to `bx` and stores it into register `a` - # `bx` must be signed and in the range [-32768, 32767] + # `bx` must be signed and in the range [regBxMin, regBxMax] when false: if c.code.len == 43: writeStackTrace() echo "generating ", opc - if bx >= -32768 and bx <= 32767: - let ins = (opc.uint32 or a.uint32 shl 8'u32 or - (bx+wordExcess).uint32 shl 16'u32).TInstr + if bx >= regBxMin-1 and bx <= regBxMax: + let ins = (opc.TInstrType or a.TInstrType shl regAShift or + (bx+wordExcess).TInstrType shl regBxShift).TInstr c.code.add(ins) c.debug.add(n.info) else: localError(c.config, n.info, - "VM: immediate value does not fit into an int16") + "VM: immediate value does not fit into regBx") proc xjmp(c: PCtx; n: PNode; opc: TOpcode; a: TRegister = 0): TPosition = #assert opc in {opcJmp, opcFJmp, opcTJmp} @@ -168,7 +168,7 @@ proc genLabel(c: PCtx): TPosition = proc jmpBack(c: PCtx, n: PNode, p = TPosition(0)) = let dist = p.int - c.code.len - internalAssert(c.config, -0x7fff < dist and dist < 0x7fff) + internalAssert(c.config, regBxMin < dist and dist < regBxMax) gABx(c, n, opcJmpBack, 0, dist) proc patch(c: PCtx, p: TPosition) = @@ -176,11 +176,11 @@ proc patch(c: PCtx, p: TPosition) = let p = p.int let diff = c.code.len - p #c.jumpTargets.incl(c.code.len) - internalAssert(c.config, -0x7fff < diff and diff < 0x7fff) + internalAssert(c.config, regBxMin < diff and diff < regBxMax) let oldInstr = c.code[p] # opcode and regA stay the same: - c.code[p] = ((oldInstr.uint32 and 0xffff'u32).uint32 or - uint32(diff+wordExcess) shl 16'u32).TInstr + c.code[p] = ((oldInstr.TInstrType and regBxMask).TInstrType or + TInstrType(diff+wordExcess) shl regBxShift).TInstr proc getSlotKind(t: PType): TSlotKind = case t.skipTypes(abstractRange-{tyTypeDesc}).kind @@ -440,7 +440,7 @@ proc rawGenLiteral(c: PCtx; n: PNode): int = #assert(n.kind != nkCall) n.flags.incl nfAllConst c.constants.add n.canonValue - internalAssert c.config, result < 0x7fff + internalAssert c.config, result < regBxMax proc sameConstant*(a, b: PNode): bool = result = false @@ -513,7 +513,7 @@ proc genType(c: PCtx; typ: PType): int = if sameType(t, typ): return i result = c.types.len c.types.add(typ) - internalAssert(c.config, result <= 0x7fff) + internalAssert(c.config, result <= regBxMax) proc genTry(c: PCtx; n: PNode; dest: var TDest) = if dest < 0 and not isEmptyType(n.typ): dest = getTemp(c, n.typ) @@ -2179,11 +2179,11 @@ proc genParams(c: PCtx; params: PNode) = c.prc.maxSlots = max(params.len, 1) proc finalJumpTarget(c: PCtx; pc, diff: int) = - internalAssert(c.config, -0x7fff < diff and diff < 0x7fff) + internalAssert(c.config, regBxMin < diff and diff < regBxMax) let oldInstr = c.code[pc] # opcode and regA stay the same: - c.code[pc] = ((oldInstr.uint32 and 0xffff'u32).uint32 or - uint32(diff+wordExcess) shl 16'u32).TInstr + c.code[pc] = ((oldInstr.TInstrType and ((regOMask shl regOShift) or (regAMask shl regAShift))).TInstrType or + TInstrType(diff+wordExcess) shl regBxShift).TInstr proc genGenericParams(c: PCtx; gp: PNode) = var base = c.prc.maxSlots