summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/vm.nim11
-rw-r--r--compiler/vmdef.nim3
-rw-r--r--compiler/vmgen.nim18
-rw-r--r--tests/vm/tzero_extend.nim44
4 files changed, 73 insertions, 3 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 908bbeb69..2dd6d6a9c 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -1483,6 +1483,17 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       createStrKeepNode(regs[ra])
       if regs[ra].node.strVal.isNil: regs[ra].node.strVal = newStringOfCap(1000)
       storeAny(regs[ra].node.strVal, typ, regs[rb].regToNode)
+    of opcToNarrowInt:
+      decodeBC(rkInt)
+      let mask = (1'i64 shl rc) - 1 # 0xFF
+      let signbit = 1'i64 shl (rc - 1) # 0x80
+      let toggle = mask - signbit # 0x7F
+      # algorithm: -((i8 and 0xFF) xor 0x7F) + 0x7F
+      # mask off higher bits.
+      # uses two's complement to sign-extend integer.
+      # reajust integer into desired range.
+      regs[ra].intVal = -((regs[rb].intVal and mask) xor toggle) + toggle
+
     inc pc
 
 proc execute(c: PCtx, start: int): PNode =
diff --git a/compiler/vmdef.nim b/compiler/vmdef.nim
index 5045f3f07..7e1309e0a 100644
--- a/compiler/vmdef.nim
+++ b/compiler/vmdef.nim
@@ -136,7 +136,8 @@ type
     opcNBindSym,
     opcSetType,   # dest.typ = types[Bx]
     opcTypeTrait,
-    opcMarshalLoad, opcMarshalStore
+    opcMarshalLoad, opcMarshalStore,
+    opcToNarrowInt
 
   TBlock* = object
     label*: PSym
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index d65fe22e9..ab969a42f 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -875,11 +875,25 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
   of mBitnotI:
     genUnaryABC(c, n, dest, opcBitnotInt)
     genNarrowU(c, n, dest)
-  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64,
-     mToU8, mToU16, mToU32, mToFloat, mToBiggestFloat, mToInt,
+  of mToFloat, mToBiggestFloat, mToInt,
      mToBiggestInt, mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
      mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
     genConv(c, n, n.sons[1], dest)
+  of mZe8ToI, mZe8ToI64, mZe16ToI, mZe16ToI64, mZe32ToI64, mZeIToI64:
+    #genNarrowU modified
+    let t = skipTypes(n.sons[1].typ, abstractVar-{tyTypeDesc})
+    let tmp = c.genx(n.sons[1])
+    c.gABC(n, opcNarrowU, tmp, TRegister(t.size*8))
+    # assign result to dest register
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcAsgnInt, dest, tmp)
+    c.freeTemp(tmp)
+  of mToU8, mToU16, mToU32:
+    let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
+    var tmp = c.genx(n.sons[1])
+    if dest < 0: dest = c.getTemp(n.typ)
+    c.gABC(n, opcToNarrowInt, dest, tmp, TRegister(t.size*8))
+    c.freeTemp(tmp)
   of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
   of mLeStr: genBinaryABC(c, n, dest, opcLeStr)
   of mLtStr: genBinaryABC(c, n, dest, opcLtStr)
diff --git a/tests/vm/tzero_extend.nim b/tests/vm/tzero_extend.nim
new file mode 100644
index 000000000..a79105531
--- /dev/null
+++ b/tests/vm/tzero_extend.nim
@@ -0,0 +1,44 @@
+
+const RANGE = -384.. -127
+
+proc get_values(): (seq[int8], seq[int16], seq[int32]) =
+  let i8 = -3'i8
+  let i16 = -3'i16
+  let i32 = -3'i32
+  doAssert i8.ze == 0xFD
+  doAssert i8.ze64 == 0xFD
+  doAssert i16.ze == 0xFFFD
+  doAssert i16.ze64 == 0xFFFD
+
+  result[0] = @[]; result[1] = @[]; result[2] = @[]
+
+  for offset in RANGE:
+    let i8 = -(1 shl 9) + offset
+    let i16 = -(1 shl 17) + offset
+    let i32 = -(1 shl 33) + offset
+
+    # higher bits are masked. these should be exactly equal to offset.
+    result[0].add i8.toU8
+    result[1].add i16.toU16
+    result[2].add i32.toU32
+
+
+# these values this computed by VM
+const COMPILETIME_VALUES = get_values()
+
+# these values this computed by compiler
+let RUNTIME_VALUES = get_values()
+
+template check_values(int_type: static[int]) =
+  var index = 0
+  let cvalues = COMPILETIME_VALUES[int_type]
+  let rvalues = RUNTIME_VALUES[int_type]
+  for offset in RANGE:
+    let moffset = cast[type(rvalues[0])](offset)
+    doAssert(moffset == rvalues[index] and moffset == cvalues[index],
+      "expected: " & $moffset & " got runtime: " & $rvalues[index] & " && compiletime: " & $cvalues[index] )
+    inc(index)
+
+check_values(0) # uint8
+check_values(1) # uint16
+check_values(2) # uint32