add native nim mode (#142)
* add native nim mode * don't try to link wasm-c code
This commit is contained in:
parent
54e24cae41
commit
711cda4456
44
stint.nimble
44
stint.nimble
|
@ -10,24 +10,42 @@ skipDirs = @["tests", "benchmarks"]
|
||||||
requires "nim >= 1.6.12",
|
requires "nim >= 1.6.12",
|
||||||
"stew"
|
"stew"
|
||||||
|
|
||||||
proc test(args, path: string) =
|
let nimc = getEnv("NIMC", "nim") # Which nim compiler to use
|
||||||
if not dirExists "build":
|
let lang = getEnv("NIMLANG", "c") # Which backend (c/cpp/js)
|
||||||
mkDir "build"
|
let flags = getEnv("NIMFLAGS", "") # Extra flags for the compiler
|
||||||
|
let verbose = getEnv("V", "") notin ["", "0"]
|
||||||
|
|
||||||
exec "nim " & getEnv("TEST_LANG", "c") & " " & getEnv("NIMFLAGS") & " " & args &
|
from os import quoteShell
|
||||||
" --outdir:build -r --hints:off --warnings:off --skipParentCfg" &
|
|
||||||
" --styleCheck:usages --styleCheck:error " & path
|
let cfg =
|
||||||
|
" --styleCheck:usages --styleCheck:error" &
|
||||||
|
(if verbose: "" else: " --verbosity:0 --hints:off") &
|
||||||
|
" --skipParentCfg --skipUserCfg --outdir:build " &
|
||||||
|
quoteShell("--nimcache:build/nimcache/$projectName")
|
||||||
|
|
||||||
|
|
||||||
|
proc build(args, path: string) =
|
||||||
|
exec nimc & " " & lang & " " & cfg & " " & flags & " " & args & " " & path
|
||||||
|
|
||||||
|
proc run(args, path: string) =
|
||||||
|
build args & " -r", path
|
||||||
if (NimMajor, NimMinor) > (1, 6):
|
if (NimMajor, NimMinor) > (1, 6):
|
||||||
exec "nim " & getEnv("TEST_LANG", "c") & " " & getEnv("NIMFLAGS") & " " & args &
|
build args & " --mm:refc -r", path
|
||||||
" --outdir:build -r --mm:refc --hints:off --warnings:off --skipParentCfg" &
|
|
||||||
" --styleCheck:usages --styleCheck:error " & path
|
proc test(path: string) =
|
||||||
|
for config in ["", "-d:stintNoIntrinsics"]:
|
||||||
|
for mode in ["-d:debug", "-d:release"]:
|
||||||
|
run(config & " " & mode, path)
|
||||||
|
|
||||||
task test_internal, "Run tests for internal procs":
|
task test_internal, "Run tests for internal procs":
|
||||||
test "", "tests/internal"
|
test "tests/internal"
|
||||||
|
|
||||||
task test_public_api, "Run all tests - prod implementation (StUint[64] = uint64":
|
task test_public_api, "Run all tests - prod implementation (StUint[64] = uint64":
|
||||||
test "", "tests/all_tests"
|
test "tests/all_tests"
|
||||||
|
|
||||||
task test, "Run all tests":
|
task test, "Run all tests":
|
||||||
exec "nimble test_internal"
|
test "tests/internal"
|
||||||
exec "nimble test_public_api"
|
test "tests/all_tests"
|
||||||
|
|
||||||
|
# Smoke-test wasm32 compiles
|
||||||
|
build "--cpu:wasm32 -c", "tests/all_tests"
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Stint
|
||||||
|
# Copyright 2023 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.
|
||||||
|
|
||||||
|
const
|
||||||
|
stintNoIntrinsics* {.booldefine.} = false
|
||||||
|
## Use only native Nim code without intrinsics, emit or asm - useful for
|
||||||
|
## targets such as wasm and compilers with no native int128 support (and the
|
||||||
|
## vm!)
|
|
@ -53,6 +53,7 @@ const X86* = defined(amd64) or defined(i386)
|
||||||
when sizeof(int) == 8 and GCC_Compatible:
|
when sizeof(int) == 8 and GCC_Compatible:
|
||||||
type
|
type
|
||||||
uint128*{.importc: "unsigned __int128".} = object
|
uint128*{.importc: "unsigned __int128".} = object
|
||||||
|
hi, lo: uint64
|
||||||
|
|
||||||
# Accessors
|
# Accessors
|
||||||
# --------------------------------------------------------
|
# --------------------------------------------------------
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#
|
#
|
||||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||||
|
|
||||||
import ../datatypes, ./compiletime_fallback
|
import ../../config, ../datatypes, ./compiletime_fallback
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
|
@ -84,7 +84,11 @@ import ../datatypes, ./compiletime_fallback
|
||||||
# Note: GCC before 2017 had incorrect codegen in some cases:
|
# Note: GCC before 2017 had incorrect codegen in some cases:
|
||||||
# - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81300
|
# - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81300
|
||||||
|
|
||||||
when X86:
|
const
|
||||||
|
useIntrinsics = X86 and not stintNoIntrinsics
|
||||||
|
useInt128 = GCC_Compatible and sizeof(int) == 8 and not stintNoIntrinsics
|
||||||
|
|
||||||
|
when useIntrinsics:
|
||||||
when defined(windows):
|
when defined(windows):
|
||||||
{.pragma: intrinsics, header:"<intrin.h>", nodecl.}
|
{.pragma: intrinsics, header:"<intrin.h>", nodecl.}
|
||||||
else:
|
else:
|
||||||
|
@ -105,37 +109,35 @@ when X86:
|
||||||
func addC*(cOut: var Carry, sum: var uint32, a, b: uint32, cIn: Carry) {.inline.} =
|
func addC*(cOut: var Carry, sum: var uint32, a, b: uint32, cIn: Carry) {.inline.} =
|
||||||
## Addition with carry
|
## Addition with carry
|
||||||
## (CarryOut, Sum) <- a + b + CarryIn
|
## (CarryOut, Sum) <- a + b + CarryIn
|
||||||
when nimvm:
|
template native =
|
||||||
let dblPrec = uint64(cIn) + uint64(a) + uint64(b)
|
let dblPrec = uint64(cIn) + uint64(a) + uint64(b)
|
||||||
sum = uint32(dblPrec and uint32.high)
|
sum = uint32(dblPrec and uint32.high)
|
||||||
cOut = Carry(dblPrec shr 32)
|
cOut = Carry(dblPrec shr 32)
|
||||||
|
|
||||||
|
when nimvm:
|
||||||
|
native
|
||||||
else:
|
else:
|
||||||
when X86:
|
when useIntrinsics:
|
||||||
cOut = addcarry_u32(cIn, a, b, sum)
|
cOut = addcarry_u32(cIn, a, b, sum)
|
||||||
else:
|
else:
|
||||||
# on arch e.g. arm: nim will complaints "Error: redefinition of 'dblPrec'"
|
native
|
||||||
# so we use dlbPrec2 here
|
|
||||||
let dblPrec2 = uint64(cIn) + uint64(a) + uint64(b)
|
|
||||||
sum = uint32(dblPrec2)
|
|
||||||
cOut = Carry(dblPrec2 shr 32)
|
|
||||||
|
|
||||||
func subB*(bOut: var Borrow, diff: var uint32, a, b: uint32, bIn: Borrow) {.inline.} =
|
func subB*(bOut: var Borrow, diff: var uint32, a, b: uint32, bIn: Borrow) {.inline.} =
|
||||||
## Substraction with borrow
|
## Substraction with borrow
|
||||||
## (BorrowOut, Diff) <- a - b - borrowIn
|
## (BorrowOut, Diff) <- a - b - borrowIn
|
||||||
when nimvm:
|
template native =
|
||||||
let dblPrec = uint64(a) - uint64(b) - uint64(bIn)
|
let dblPrec = uint64(a) - uint64(b) - uint64(bIn)
|
||||||
diff = uint32(dblPrec and uint32.high)
|
diff = uint32(dblPrec and uint32.high)
|
||||||
# On borrow the high word will be 0b1111...1111 and needs to be masked
|
# On borrow the high word will be 0b1111...1111 and needs to be masked
|
||||||
bOut = Borrow((dblPrec shr 32) and 1)
|
bOut = Borrow((dblPrec shr 32) and 1)
|
||||||
|
|
||||||
|
when nimvm:
|
||||||
|
native
|
||||||
else:
|
else:
|
||||||
when X86:
|
when useIntrinsics:
|
||||||
bOut = subborrow_u32(bIn, a, b, diff)
|
bOut = subborrow_u32(bIn, a, b, diff)
|
||||||
else:
|
else:
|
||||||
# ditto
|
native
|
||||||
let dblPrec2 = uint64(a) - uint64(b) - uint64(bIn)
|
|
||||||
diff = uint32(dblPrec2)
|
|
||||||
# On borrow the high word will be 0b1111...1111 and needs to be masked
|
|
||||||
bOut = Borrow((dblPrec2 shr 32) and 1)
|
|
||||||
|
|
||||||
func addC*(cOut: var Carry, sum: var uint64, a, b: uint64, cIn: Carry) {.inline.} =
|
func addC*(cOut: var Carry, sum: var uint64, a, b: uint64, cIn: Carry) {.inline.} =
|
||||||
## Addition with carry
|
## Addition with carry
|
||||||
|
@ -143,24 +145,21 @@ func addC*(cOut: var Carry, sum: var uint64, a, b: uint64, cIn: Carry) {.inline.
|
||||||
when nimvm:
|
when nimvm:
|
||||||
addC_nim(cOut, sum, a, b, cIn)
|
addC_nim(cOut, sum, a, b, cIn)
|
||||||
else:
|
else:
|
||||||
when X86:
|
when useIntrinsics:
|
||||||
cOut = addcarry_u64(cIn, a, b, sum)
|
cOut = addcarry_u64(cIn, a, b, sum)
|
||||||
|
elif useInt128:
|
||||||
|
var dblPrec {.noInit.}: uint128
|
||||||
|
{.emit:[dblPrec, " = (unsigned __int128)", a," + (unsigned __int128)", b, " + (unsigned __int128)",cIn,";"].}
|
||||||
|
|
||||||
|
# Don't forget to dereference the var param in C mode
|
||||||
|
when defined(cpp):
|
||||||
|
{.emit:[cOut, " = (NU64)(", dblPrec," >> ", 64'u64, ");"].}
|
||||||
|
{.emit:[sum, " = (NU64)", dblPrec,";"].}
|
||||||
|
else:
|
||||||
|
{.emit:["*",cOut, " = (NU64)(", dblPrec," >> ", 64'u64, ");"].}
|
||||||
|
{.emit:["*",sum, " = (NU64)", dblPrec,";"].}
|
||||||
else:
|
else:
|
||||||
block:
|
addC_nim(cOut, sum, a, b, cIn)
|
||||||
static:
|
|
||||||
doAssert GCC_Compatible
|
|
||||||
doAssert sizeof(int) == 8
|
|
||||||
|
|
||||||
var dblPrec {.noInit.}: uint128
|
|
||||||
{.emit:[dblPrec, " = (unsigned __int128)", a," + (unsigned __int128)", b, " + (unsigned __int128)",cIn,";"].}
|
|
||||||
|
|
||||||
# Don't forget to dereference the var param in C mode
|
|
||||||
when defined(cpp):
|
|
||||||
{.emit:[cOut, " = (NU64)(", dblPrec," >> ", 64'u64, ");"].}
|
|
||||||
{.emit:[sum, " = (NU64)", dblPrec,";"].}
|
|
||||||
else:
|
|
||||||
{.emit:["*",cOut, " = (NU64)(", dblPrec," >> ", 64'u64, ");"].}
|
|
||||||
{.emit:["*",sum, " = (NU64)", dblPrec,";"].}
|
|
||||||
|
|
||||||
func subB*(bOut: var Borrow, diff: var uint64, a, b: uint64, bIn: Borrow) {.inline.} =
|
func subB*(bOut: var Borrow, diff: var uint64, a, b: uint64, bIn: Borrow) {.inline.} =
|
||||||
## Substraction with borrow
|
## Substraction with borrow
|
||||||
|
@ -168,22 +167,19 @@ func subB*(bOut: var Borrow, diff: var uint64, a, b: uint64, bIn: Borrow) {.inli
|
||||||
when nimvm:
|
when nimvm:
|
||||||
subB_nim(bOut, diff, a, b, bIn)
|
subB_nim(bOut, diff, a, b, bIn)
|
||||||
else:
|
else:
|
||||||
when X86:
|
when useIntrinsics:
|
||||||
bOut = subborrow_u64(bIn, a, b, diff)
|
bOut = subborrow_u64(bIn, a, b, diff)
|
||||||
|
elif useInt128:
|
||||||
|
var dblPrec {.noInit.}: uint128
|
||||||
|
{.emit:[dblPrec, " = (unsigned __int128)", a," - (unsigned __int128)", b, " - (unsigned __int128)",bIn,";"].}
|
||||||
|
|
||||||
|
# Don't forget to dereference the var param in C mode
|
||||||
|
# On borrow the high word will be 0b1111...1111 and needs to be masked
|
||||||
|
when defined(cpp):
|
||||||
|
{.emit:[bOut, " = (NU64)(", dblPrec," >> ", 64'u64, ") & 1;"].}
|
||||||
|
{.emit:[diff, " = (NU64)", dblPrec,";"].}
|
||||||
|
else:
|
||||||
|
{.emit:["*",bOut, " = (NU64)(", dblPrec," >> ", 64'u64, ") & 1;"].}
|
||||||
|
{.emit:["*",diff, " = (NU64)", dblPrec,";"].}
|
||||||
else:
|
else:
|
||||||
block:
|
subB_nim(bOut, diff, a, b, bIn)
|
||||||
static:
|
|
||||||
doAssert GCC_Compatible
|
|
||||||
doAssert sizeof(int) == 8
|
|
||||||
|
|
||||||
var dblPrec {.noInit.}: uint128
|
|
||||||
{.emit:[dblPrec, " = (unsigned __int128)", a," - (unsigned __int128)", b, " - (unsigned __int128)",bIn,";"].}
|
|
||||||
|
|
||||||
# Don't forget to dereference the var param in C mode
|
|
||||||
# On borrow the high word will be 0b1111...1111 and needs to be masked
|
|
||||||
when defined(cpp):
|
|
||||||
{.emit:[bOut, " = (NU64)(", dblPrec," >> ", 64'u64, ") & 1;"].}
|
|
||||||
{.emit:[diff, " = (NU64)", dblPrec,";"].}
|
|
||||||
else:
|
|
||||||
{.emit:["*",bOut, " = (NU64)(", dblPrec," >> ", 64'u64, ") & 1;"].}
|
|
||||||
{.emit:["*",diff, " = (NU64)", dblPrec,";"].}
|
|
||||||
|
|
|
@ -82,16 +82,19 @@ func muladd2*(hi, lo: var uint32, a, b, c1, c2: uint32) {.inline.}=
|
||||||
# ############################################################
|
# ############################################################
|
||||||
|
|
||||||
when sizeof(int) == 8 and not defined(Stint32):
|
when sizeof(int) == 8 and not defined(Stint32):
|
||||||
|
import ../../config
|
||||||
|
|
||||||
from ./compiletime_fallback import div2n1n_nim, mul_nim, muladd1_nim, muladd2_nim
|
from ./compiletime_fallback import div2n1n_nim, mul_nim, muladd1_nim, muladd2_nim
|
||||||
|
|
||||||
when defined(vcc):
|
when not stintNoIntrinsics:
|
||||||
from ./extended_precision_x86_64_msvc import div2n1n_128, mul_128, muladd1_128, muladd2_128
|
when defined(vcc):
|
||||||
elif GCC_Compatible:
|
from ./extended_precision_x86_64_msvc import div2n1n_128, mul_128, muladd1_128, muladd2_128
|
||||||
when X86:
|
|
||||||
from ./extended_precision_x86_64_gcc import div2n1n_128
|
|
||||||
from ./extended_precision_64bit_uint128 import mul_128, muladd1_128, muladd2_128
|
|
||||||
else:
|
else:
|
||||||
from ./extended_precision_64bit_uint128 import div2n1n_128, mul_128, muladd1_128, muladd2_128
|
when defined(amd64):
|
||||||
|
from ./extended_precision_x86_64_gcc import div2n1n_128
|
||||||
|
from ./extended_precision_64bit_uint128 import mul_128, muladd1_128, muladd2_128
|
||||||
|
else:
|
||||||
|
from ./extended_precision_64bit_uint128 import div2n1n_128, mul_128, muladd1_128, muladd2_128
|
||||||
|
|
||||||
func mul*(hi, lo: var uint64, u, v: uint64) {.inline.}=
|
func mul*(hi, lo: var uint64, u, v: uint64) {.inline.}=
|
||||||
## Extended precision multiplication
|
## Extended precision multiplication
|
||||||
|
@ -99,7 +102,10 @@ when sizeof(int) == 8 and not defined(Stint32):
|
||||||
when nimvm:
|
when nimvm:
|
||||||
mul_nim(hi, lo, u, v)
|
mul_nim(hi, lo, u, v)
|
||||||
else:
|
else:
|
||||||
mul_128(hi, lo, u, v)
|
when stintNoIntrinsics:
|
||||||
|
mul_nim(hi, lo, u, v)
|
||||||
|
else:
|
||||||
|
mul_128(hi, lo, u, v)
|
||||||
|
|
||||||
func muladd1*(hi, lo: var uint64, a, b, c: uint64) {.inline.}=
|
func muladd1*(hi, lo: var uint64, a, b, c: uint64) {.inline.}=
|
||||||
## Extended precision multiplication + addition
|
## Extended precision multiplication + addition
|
||||||
|
@ -110,7 +116,10 @@ when sizeof(int) == 8 and not defined(Stint32):
|
||||||
when nimvm:
|
when nimvm:
|
||||||
muladd1_nim(hi, lo, a, b, c)
|
muladd1_nim(hi, lo, a, b, c)
|
||||||
else:
|
else:
|
||||||
muladd1_128(hi, lo, a, b, c)
|
when stintNoIntrinsics:
|
||||||
|
muladd1_nim(hi, lo, a, b, c)
|
||||||
|
else:
|
||||||
|
muladd1_128(hi, lo, a, b, c)
|
||||||
|
|
||||||
func muladd2*(hi, lo: var uint64, a, b, c1, c2: uint64) {.inline.}=
|
func muladd2*(hi, lo: var uint64, a, b, c1, c2: uint64) {.inline.}=
|
||||||
## Extended precision multiplication + addition + addition
|
## Extended precision multiplication + addition + addition
|
||||||
|
@ -122,7 +131,10 @@ when sizeof(int) == 8 and not defined(Stint32):
|
||||||
when nimvm:
|
when nimvm:
|
||||||
muladd2_nim(hi, lo, a, b, c1, c2)
|
muladd2_nim(hi, lo, a, b, c1, c2)
|
||||||
else:
|
else:
|
||||||
muladd2_128(hi, lo, a, b, c1, c2)
|
when stintNoIntrinsics:
|
||||||
|
muladd2_nim(hi, lo, a, b, c1, c2)
|
||||||
|
else:
|
||||||
|
muladd2_128(hi, lo, a, b, c1, c2)
|
||||||
|
|
||||||
func div2n1n*(q, r: var uint64, n_hi, n_lo, d: uint64) {.inline.}=
|
func div2n1n*(q, r: var uint64, n_hi, n_lo, d: uint64) {.inline.}=
|
||||||
## Division uint128 by uint64
|
## Division uint128 by uint64
|
||||||
|
@ -132,7 +144,10 @@ when sizeof(int) == 8 and not defined(Stint32):
|
||||||
when nimvm:
|
when nimvm:
|
||||||
div2n1n_nim(q, r, n_hi, n_lo, d)
|
div2n1n_nim(q, r, n_hi, n_lo, d)
|
||||||
else:
|
else:
|
||||||
div2n1n_128(q, r, n_hi, n_lo, d)
|
when stintNoIntrinsics:
|
||||||
|
div2n1n_nim(q, r, n_hi, n_lo, d)
|
||||||
|
else:
|
||||||
|
div2n1n_128(q, r, n_hi, n_lo, d)
|
||||||
|
|
||||||
# ############################################################
|
# ############################################################
|
||||||
#
|
#
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
# Test implementation of internal proc:
|
# Test implementation of internal proc:
|
||||||
|
|
||||||
|
{.used.}
|
||||||
|
|
||||||
include ../stint/private/uint_div
|
include ../stint/private/uint_div
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue