add native nim mode (#142)

* add native nim mode

* don't try to link wasm-c code
This commit is contained in:
Jacek Sieka 2023-09-25 16:49:04 +02:00 committed by GitHub
parent 54e24cae41
commit 711cda4456
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 120 additions and 73 deletions

1
nim.cfg Normal file
View File

@ -0,0 +1 @@
nimcache = "build/nimcache/$projectName"

View File

@ -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"

14
stint/config.nim Normal file
View File

@ -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!)

View File

@ -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
# -------------------------------------------------------- # --------------------------------------------------------

View File

@ -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,14 +145,9 @@ 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)
else: elif useInt128:
block:
static:
doAssert GCC_Compatible
doAssert sizeof(int) == 8
var dblPrec {.noInit.}: uint128 var dblPrec {.noInit.}: uint128
{.emit:[dblPrec, " = (unsigned __int128)", a," + (unsigned __int128)", b, " + (unsigned __int128)",cIn,";"].} {.emit:[dblPrec, " = (unsigned __int128)", a," + (unsigned __int128)", b, " + (unsigned __int128)",cIn,";"].}
@ -161,6 +158,8 @@ func addC*(cOut: var Carry, sum: var uint64, a, b: uint64, cIn: Carry) {.inline.
else: else:
{.emit:["*",cOut, " = (NU64)(", dblPrec," >> ", 64'u64, ");"].} {.emit:["*",cOut, " = (NU64)(", dblPrec," >> ", 64'u64, ");"].}
{.emit:["*",sum, " = (NU64)", dblPrec,";"].} {.emit:["*",sum, " = (NU64)", dblPrec,";"].}
else:
addC_nim(cOut, sum, a, b, cIn)
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,14 +167,9 @@ 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)
else: elif useInt128:
block:
static:
doAssert GCC_Compatible
doAssert sizeof(int) == 8
var dblPrec {.noInit.}: uint128 var dblPrec {.noInit.}: uint128
{.emit:[dblPrec, " = (unsigned __int128)", a," - (unsigned __int128)", b, " - (unsigned __int128)",bIn,";"].} {.emit:[dblPrec, " = (unsigned __int128)", a," - (unsigned __int128)", b, " - (unsigned __int128)",bIn,";"].}
@ -187,3 +181,5 @@ func subB*(bOut: var Borrow, diff: var uint64, a, b: uint64, bIn: Borrow) {.inli
else: else:
{.emit:["*",bOut, " = (NU64)(", dblPrec," >> ", 64'u64, ") & 1;"].} {.emit:["*",bOut, " = (NU64)(", dblPrec," >> ", 64'u64, ") & 1;"].}
{.emit:["*",diff, " = (NU64)", dblPrec,";"].} {.emit:["*",diff, " = (NU64)", dblPrec,";"].}
else:
subB_nim(bOut, diff, a, b, bIn)

View File

@ -82,12 +82,15 @@ 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 not stintNoIntrinsics:
when defined(vcc): when defined(vcc):
from ./extended_precision_x86_64_msvc import div2n1n_128, mul_128, muladd1_128, muladd2_128 from ./extended_precision_x86_64_msvc import div2n1n_128, mul_128, muladd1_128, muladd2_128
elif GCC_Compatible: else:
when X86: when defined(amd64):
from ./extended_precision_x86_64_gcc import div2n1n_128 from ./extended_precision_x86_64_gcc import div2n1n_128
from ./extended_precision_64bit_uint128 import mul_128, muladd1_128, muladd2_128 from ./extended_precision_64bit_uint128 import mul_128, muladd1_128, muladd2_128
else: else:
@ -98,6 +101,9 @@ when sizeof(int) == 8 and not defined(Stint32):
## (hi, lo) <- u * v ## (hi, lo) <- u * v
when nimvm: when nimvm:
mul_nim(hi, lo, u, v) mul_nim(hi, lo, u, v)
else:
when stintNoIntrinsics:
mul_nim(hi, lo, u, v)
else: else:
mul_128(hi, lo, u, v) mul_128(hi, lo, u, v)
@ -109,6 +115,9 @@ when sizeof(int) == 8 and not defined(Stint32):
## so adding any c cannot overflow ## so adding any c cannot overflow
when nimvm: when nimvm:
muladd1_nim(hi, lo, a, b, c) muladd1_nim(hi, lo, a, b, c)
else:
when stintNoIntrinsics:
muladd1_nim(hi, lo, a, b, c)
else: else:
muladd1_128(hi, lo, a, b, c) muladd1_128(hi, lo, a, b, c)
@ -121,6 +130,9 @@ when sizeof(int) == 8 and not defined(Stint32):
## and we have enough space to add again 0xFFFFFFFFFFFFFFFF without overflowing ## and we have enough space to add again 0xFFFFFFFFFFFFFFFF without overflowing
when nimvm: when nimvm:
muladd2_nim(hi, lo, a, b, c1, c2) muladd2_nim(hi, lo, a, b, c1, c2)
else:
when stintNoIntrinsics:
muladd2_nim(hi, lo, a, b, c1, c2)
else: else:
muladd2_128(hi, lo, a, b, c1, c2) muladd2_128(hi, lo, a, b, c1, c2)
@ -131,6 +143,9 @@ when sizeof(int) == 8 and not defined(Stint32):
## - if n_hi > d result is undefined ## - if n_hi > d result is undefined
when nimvm: when nimvm:
div2n1n_nim(q, r, n_hi, n_lo, d) div2n1n_nim(q, r, n_hi, n_lo, d)
else:
when stintNoIntrinsics:
div2n1n_nim(q, r, n_hi, n_lo, d)
else: else:
div2n1n_128(q, r, n_hi, n_lo, d) div2n1n_128(q, r, n_hi, n_lo, d)

View File

@ -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