diff options
-rw-r--r-- | compiler/vm.nim | 11 | ||||
-rw-r--r-- | compiler/vmdef.nim | 3 | ||||
-rw-r--r-- | compiler/vmgen.nim | 18 | ||||
-rw-r--r-- | tests/vm/tzero_extend.nim | 44 |
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 |