Force checking sizes at compile-time

This commit is contained in:
mratsim 2018-03-26 17:39:34 +02:00
parent 49b3ee1006
commit 2b47647019
4 changed files with 42 additions and 25 deletions

View File

@ -0,0 +1,36 @@
# Copyright 2018 Status Research & Development GmbH
# Licensed under either of
#
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type, macros
proc size_mpuintimpl*(x: NimNode): static[int] =
# Size of doesn't always work at compile-time, pending PR https://github.com/nim-lang/Nim/pull/5664
var multiplier = 1
var node = x.getTypeInst
while node.kind == nnkBracketExpr:
assert eqIdent(node[0], "MpuintImpl")
multiplier *= 2
node = node[1]
# node[1] has the type
# size(node[1]) * multiplier is the size in byte
# For optimization we cast to the biggest possible uint
result = if eqIdent(node, "uint64"): multiplier * 64
elif eqIdent(node, "uint32"): multiplier * 32
elif eqIdent(node, "uint16"): multiplier * 16
else: multiplier * 8
macro size_mpuintimpl*(x: typed): untyped =
let size = size_mpuintimpl(x)
result = quote do:
`size`

View File

@ -78,8 +78,8 @@ proc naiveMulImpl[T: MpUintImpl](x, y: T): MpUintImpl[T] {.noSideEffect, noInit,
# and introduce branching
# - More total operations means more register moves
const halfSize = x.size_mpuintimpl div 2
let
halfSize = T.sizeof * 4
z0 = naiveMul(x.lo, y.lo)
tmp = naiveMul(x.hi, y.lo)

View File

@ -7,7 +7,7 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type
import ./uint_type, size_mpuintimpl
proc `not`*(x: MpUintImpl): MpUintImpl {.noInit, noSideEffect, inline.}=
@ -33,8 +33,7 @@ proc `xor`*(x, y: MpUintImpl): MpUintImpl {.noInit, noSideEffect, inline.}=
proc `shl`*[T: MpUintImpl](x: T, y: SomeInteger): T {.noInit, inline, noSideEffect.}=
## Compute the `shift left` operation of x and y
# Note: inlining this poses codegen/aliasing issue when doing `x = x shl 1`
let
halfSize = T.sizeof * 4
const halfSize = size_mpuintimpl(x) div 2
type SubTy = type x.lo
@ -46,8 +45,7 @@ proc `shl`*[T: MpUintImpl](x: T, y: SomeInteger): T {.noInit, inline, noSideEffe
proc `shr`*[T: MpUintImpl](x: T, y: SomeInteger): T {.noInit, inline, noSideEffect.}=
## Compute the `shift right` operation of x and y
# Note: inlining this poses codegen/aliasing issue when doing `x = x shl 1`
let
halfSize = T.sizeof * 4
const halfSize = size_mpuintimpl(x) div 2
type SubTy = type x.lo

View File

@ -7,27 +7,10 @@
#
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import ./uint_type, macros
import ./uint_type, ./size_mpuintimpl, macros
macro cast_optim(x: typed): untyped =
# Size of doesn't always work at compile-time, pending PR https://github.com/nim-lang/Nim/pull/5664
var multiplier = 1
var node = x.getTypeInst
while node.kind == nnkBracketExpr:
assert eqIdent(node[0], "MpuintImpl")
multiplier *= 2
node = node[1]
# node[1] has the type
# size(node[1]) * multiplier is the size in byte
# For optimization we cast to the biggest possible uint
let size = if eqIdent(node, "uint64"): multiplier * 64
elif eqIdent(node, "uint32"): multiplier * 32
elif eqIdent(node, "uint16"): multiplier * 16
else: multiplier * 8
let size = size_mpuintimpl(x)
if size > 64:
result = quote do: