Implement more math: non-rigogous translation for now, more precise operation correctness later

This commit is contained in:
Alexander Ivanov 2018-01-16 20:42:38 +02:00
parent 706f3982a7
commit 69475a98f5
9 changed files with 132 additions and 40 deletions

View File

@ -7,6 +7,9 @@ type
Int256* = distinct int # TODO
# TODO
# We'll have a fast fixed Int256, for now this
proc `==`*(a: Int256, b: Int256): bool =
a.int == b.int
@ -82,12 +85,24 @@ proc `and`*(a: Int256, b: Int256): Int256 =
proc `or`*(a: Int256, b: Int256): Int256 =
(a.int or b.int).Int256
proc `xor`*(a: Int256, b: Int256): Int256 =
(a.int xor b.int).Int256
proc max*(a: Int256, b: Int256): Int256 =
max(a.int, b.int).Int256
proc min*(a: Int256, b: Int256): Int256 =
min(a.int, b.int).Int256
proc `-`*(a: Int256): Int256 =
(-(a.int)).Int256
proc `shl`*(a: Int256, b: Int256): Int256 =
(a.int shl b.int).Int256
proc `shr`*(a: Int256, b: Int256): Int256 =
(a.int shr b.int).Int256
proc repeat(b: cstring, count: int): cstring =
# TODO: faster
var s = $b

Binary file not shown.

1
src/lightchain_shell.nim Normal file
View File

@ -0,0 +1 @@
# not implemented

View File

@ -1 +0,0 @@

View File

@ -1,24 +1,23 @@
import
../constants, ../utils_numeric, ../stack
../constants, ../utils_numeric, ../computation,
.. / vm / [gas_meter, stack],
helpers
template pushRes =
computation.stack.push(res)
proc add*(computation: var Computation) =
proc add*(computation: var BaseComputation) =
# Addition
var (left, right = computation.stack.popInt(2)
var (left, right) = computation.stack.popInt(2)
var res = (left + right) and constants.UINT_256_MAX
pushRes()
proc addmod*(computation: var Computation) =
proc addmod*(computation: var BaseComputation) =
# Modulo Addition
var (left, right, arg) = computation.stack.popInt(3)
var res = if arg == 0: 0.Int256 else: (left + right) mod arg
pushRes()
proc sub*(computation: var Computation) =
proc sub*(computation: var BaseComputation) =
# Subtraction
var (left, right) = computation.stack.popInt(2)
@ -26,62 +25,62 @@ proc sub*(computation: var Computation) =
pushRes()
proc modulo*(computation: var Computation) =
proc modulo*(computation: var BaseComputation) =
# Modulo
var (value, arg) = computation.stack.popInt(2)
var res = if arg == 0: 0.Int256 else: value mod arg
pushRes()
proc smod*(computation: var Computation) =
proc smod*(computation: var BaseComputation) =
# Signed Modulo
var (value, arg) = computation.stack.popInt(2)
value = unsignedToSigned(value)
arg = unsignedToSigned(value)
var posOrNeg = if value < 0: -1.Int256 else 1.Int256
var res = if mod == 0: 0.Int256 else: ((value.abs mod arg.abs) * posOrNeg) and constants.UINT_256_MAX
var posOrNeg = if value < 0: -1.Int256 else: 1.Int256
var res = if arg == 0: 0.Int256 else: ((value.abs mod arg.abs) * posOrNeg) and constants.UINT_256_MAX
res = signedToUnsigned(res)
pushRes()
proc mul*(computation: var Computation) =
proc mul*(computation: var BaseComputation) =
# Multiplication
var (left, right) = computation.stack.popInt(2)
var res = (left * right) and constants.UINT_256_MAX
pushRes()
proc mulmod*(computation: var Computation) =
proc mulmod*(computation: var BaseComputation) =
# Modulo Multiplication
var (left, right, arg) = computation.stack.popInt(3)
var res = if mod == 0: 0.Int256 else: (left * right) mod arg
var res = if arg == 0: 0.Int256 else: (left * right) mod arg
pushRes()
proc divide*(computation: var Computation) =
proc divide*(computation: var BaseComputation) =
# Division
var (numerator, denominator) = computation.stack.popInt(2)
var res = if denominator == 0: 0.Int256 else: (numerator div denominator) and constants.UINT_256_MAX
pushRes()
proc sdiv*(computation: var Computation) =
proc sdiv*(computation: var BaseComputation) =
# Signed Division
var (numerator, denominator) = computation.stack.popInt(2)
numerator = unsignedToSigned(numerator)
denominator = unsignedToSigned(denominator)
var posOrNeg = if numerator * denominator < 0: -1.Int256 else 1.Int256
var posOrNeg = if numerator * denominator < 0: -1.Int256 else: 1.Int256
var res = if denominator == 0: 0.Int256 else: (posOrNeg * (numerator.abs div denominator.abs))
res = unsignedToSigned(res)
pushRes()
# no curry
proc exp*(computation: var Computation, gasPerByte: Int256) =
proc exp*(computation: var BaseComputation, gasPerByte: Int256) =
# Exponentiation
var (base, exponent) = computation.stack.popInt(2)
var bitSize = exponent.bitLength()
var bitSize = 0.Int256 # TODO exponent.bitLength()
var byteSize = ceil8(bitSize) div 8
var res = if base == 0: 0.Int256 else: (base ^ exponent) mod constants.UINT_256_CEILING
computation.gasMeter.consumeGas(
@ -90,7 +89,7 @@ proc exp*(computation: var Computation, gasPerByte: Int256) =
)
pushRes()
proc signextend(computation: var Computation) =
proc signextend(computation: var BaseComputation) =
# Signed Extend
var (bits, value) = computation.stack.popInt(2)
@ -98,7 +97,7 @@ proc signextend(computation: var Computation) =
if bits <= 31.Int256:
var testBit = bits * 8.Int256 + 7.Int256
var signBit = (1.Int256 shl testBit)
res = if value and signBit != 0: value or (constants.UINT_256_CEILING - signBit) else: value and (signBit - 1)
res = if value != 0 and signBit != 0: value or (constants.UINT_256_CEILING - signBit) else: value and (signBit - 1.Int256)
else:
res = value
pushRes()

39
src/logic/comparison.nim Normal file
View File

@ -0,0 +1,39 @@
import
../constants, ../utils_numeric, ../computation, ../vm/stack,
helpers
quasiBoolean(lt, `<`) # Lesser Comparison
quasiBoolean(gt, `>`) # Greater Comparison
quasiBoolean(slt, `<`, signed=true) # Signed Lesser Comparison
quasiBoolean(sgt, `>`, signed=true) # Signed Greater Comparison
quasiBoolean(eq, `==`) # Equality
quasiBoolean(andOp, `and`, nonzero=true) # Bitwise And
quasiBoolean(orOp, `or`, nonzero=true) # Bitwise Or
quasiBoolean(xorOp, `xor`, nonzero=true) # Bitwise XOr
# proc iszero*(computation: var BaseComputation) =
# var value = computation.stack.popInt()
# var res = if value == 0: 1.Int256 else: 0.Int256
# pushRes()
# proc notOp*(computation: var BaseComputation) =
# var value = computation.stack.popInt()
# var res = constants.UINT_256_MAX - value
# pushRes()
# proc byteOp*(computation: var BaseComputation) =
# # Bitwise And
# var (position, value) = computation.stack.popInt(2)
# var res = if position >= 32.Int256: 0.Int256 else: (value div (256.Int256 ^ (31.Int256 - position))) mod 256
# pushRes()

33
src/logic/helpers.nim Normal file
View File

@ -0,0 +1,33 @@
import macros
template pushRes* =
let resNode = ident("res")
computation.stack.push(`resNode`)
macro quasiBoolean*(name: untyped, op: untyped, signed: untyped = nil, nonzero: untyped = nil): untyped =
var signedNode = newEmptyNode()
var finishSignedNode = newEmptyNode()
let resNode = ident("res")
let leftNode = ident("left")
let rightNode = ident("right")
if not signed.isNil:
signedNode = quote:
`leftNode` = unsignedToSigned(`leftNode`)
`rightNode` = unsignedToSigned(`rightNode`)
finishSignedNode = quote:
`resNode` = signedToUnsigned(`resNode`)
var test = if nonzero.isNil:
quote:
`op`(`leftNode`, `rightNode`)
else:
quote:
`op`(`leftNode`, `rightNode`) != 0
result = quote:
proc `name`*(computation: var BaseComputation) =
var (`leftNode`, `rightNode`) = computation.stack.popInt(2)
`signedNode`
var `resNode` = if `test`: 1.Int256 else: 0.Int256
`finishSignedNode`
computation.stack.push(`resNode`)

View File

@ -6,13 +6,13 @@ proc intToBigEndian*(value: Int256): cstring =
proc bigEndianToInt*(value: cstring): Int256 =
result = 0.Int256
proc unsignedToSigned(value: Int256): Int256 =
proc unsignedToSigned*(value: Int256): Int256 =
if value <= UINT_255_MAX:
return value
else:
return value - UINT_256_CEILING
proc signedToUnsigned(value: Int256): Int256 =
proc signedToUnsigned*(value: Int256): Int256 =
if value < 0:
return value + UINT_256_CEILING
else:
@ -27,7 +27,7 @@ macro ceilXX(ceiling: static[int]): untyped =
return value
else:
return value + `ceiling`.Int256 - remainder
echo result.repr
ceilXX(32)
ceilXX(8)

View File

@ -87,26 +87,32 @@ proc pop*(stack: var Stack; numItems: int): seq[Value] =
result = stack.internalPop(numItems)
ensurePop(result, numItems)
# proc popInt*(stack: var Stack): Int256 =
# var elements = stack.internalPop(1, Int256)
# ensurePop(elements, 1)
# result = elements[0]
proc popInt*(stack: var Stack): Int256 =
var elements = stack.internalPop(1, Int256)
ensurePop(elements, 1)
result = elements[0]
macro internalPopTuple(numItems: static[int]): untyped =
var name = ident(%"internalPopTuple{numItems}")
var typ = nnkPar.newTree()
var t = ident("T")
var resultNode = ident("result")
var stackNode = ident("stack")
for z in 0 ..< numItems:
typ.add(t)
result = quote:
proc `name`(stack: var Stack, `t`: typedesc): `typ` =
for z in 0 ..< `numItems`:
var value = stack.values.pop()
case value.kind:
of VInt:
result[z] = toType(value.i, `t`)
of VBinary:
result[z] = toType(value.b, `t`)
proc `name`*(`stackNode`: var Stack, `t`: typedesc): `typ`
result[^1] = nnkStmtList.newTree()
for z in 0 ..< numItems:
var zNode = newLit(z)
var element = quote:
var value = `stackNode`.values.pop()
case value.kind:
of VInt:
`resultNode`[`zNode`] = toType(value.i, `t`)
of VBinary:
`resultNode`[`zNode`] = toType(value.b, `t`)
result[^1].add(element)
# define pop<T> for tuples
internalPopTuple(2)
@ -120,11 +126,11 @@ macro popInt*(stack: typed; numItems: static[int]): untyped =
var resultNode = ident("result")
if numItems >= 8:
result = quote:
`resultNode` = `stack`.internalPop(`numItems`, Int256)
`stack`.internalPop(`numItems`, Int256)
else:
var name = ident(%"internalPopTuple{numItems}")
result = quote:
`resultNode` = `name`(`stack`, Int256)
`name`(`stack`, Int256)
# proc popInt*(stack: var Stack, numItems: int): seq[Int256] =
# result = stack.internalPop(numItems, Int256)