From 2b47647019408b6642250cc6b542a9045031588b Mon Sep 17 00:00:00 2001 From: mratsim Date: Mon, 26 Mar 2018 17:39:34 +0200 Subject: [PATCH] Force checking sizes at compile-time --- src/private/size_mpuintimpl.nim | 36 ++++++++++++++++++++++++++++++++ src/private/uint_binary_ops.nim | 2 +- src/private/uint_bitwise_ops.nim | 8 +++---- src/private/uint_comparison.nim | 21 ++----------------- 4 files changed, 42 insertions(+), 25 deletions(-) create mode 100644 src/private/size_mpuintimpl.nim diff --git a/src/private/size_mpuintimpl.nim b/src/private/size_mpuintimpl.nim new file mode 100644 index 0000000..68e2b74 --- /dev/null +++ b/src/private/size_mpuintimpl.nim @@ -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` diff --git a/src/private/uint_binary_ops.nim b/src/private/uint_binary_ops.nim index f041280..d1e4152 100644 --- a/src/private/uint_binary_ops.nim +++ b/src/private/uint_binary_ops.nim @@ -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) diff --git a/src/private/uint_bitwise_ops.nim b/src/private/uint_bitwise_ops.nim index f97ff56..61b5c24 100644 --- a/src/private/uint_bitwise_ops.nim +++ b/src/private/uint_bitwise_ops.nim @@ -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 diff --git a/src/private/uint_comparison.nim b/src/private/uint_comparison.nim index bcd9d1b..b472326 100644 --- a/src/private/uint_comparison.nim +++ b/src/private/uint_comparison.nim @@ -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: