From c3d5ec8eadf3aa887f34231c2d7b5818923818d4 Mon Sep 17 00:00:00 2001 From: andri lim Date: Tue, 7 Aug 2018 14:07:18 +0700 Subject: [PATCH] fixes #8421, fixes #7968, Nim compiler compiles with MSVC C89 version (#8556) --- compiler/rodutils.nim | 21 +++++++++++ lib/pure/math.nim | 80 +++++++++++++++++++++++++++++------------ lib/windows/winlean.nim | 2 +- 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/compiler/rodutils.nim b/compiler/rodutils.nim index 66d7f63c24..a774cdba77 100644 --- a/compiler/rodutils.nim +++ b/compiler/rodutils.nim @@ -10,6 +10,27 @@ ## Serialization utilities for the compiler. import strutils, math +# MSVC prior to 2013 doesn't have C99 functions +when defined(windows) and (defined(vcc) or defined(bcc)): + {.emit: """#if defined(_MSC_VER) && _MSC_VER < 1900 + #include + static int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { + int count = -1; + if (size != 0) count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) count = _vscprintf(format, ap); + return count; + } + int snprintf(char *outBuf, size_t size, const char *format, ...) { + int count; + va_list ap; + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + return count; + } + #endif + """.} + proc c_snprintf(s: cstring; n:uint; frmt: cstring): cint {.importc: "snprintf", header: "", nodecl, varargs.} proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string = diff --git a/lib/pure/math.nim b/lib/pure/math.nim index b921b18417..eb09bf4a7e 100644 --- a/lib/pure/math.nim +++ b/lib/pure/math.nim @@ -162,9 +162,6 @@ when not defined(JS): # C proc log10*(x: float32): float32 {.importc: "log10f", header: "".} proc log10*(x: float64): float64 {.importc: "log10", header: "".} ## Computes the common logarithm (base 10) of `x` - proc log2*(x: float32): float32 {.importc: "log2f", header: "".} - proc log2*(x: float64): float64 {.importc: "log2", header: "".} - ## Computes the binary logarithm (base 2) of `x` proc exp*(x: float32): float32 {.importc: "expf", header: "".} proc exp*(x: float64): float64 {.importc: "exp", header: "".} ## Computes the exponential function of `x` (pow(E, x)) @@ -268,6 +265,8 @@ proc arcsech*[T: float32|float64](x: T): T = arccosh(1.0 / x) proc arccsch*[T: float32|float64](x: T): T = arcsinh(1.0 / x) ## Computes the inverse hyperbolic cosecant of `x` +const windowsCC89 = defined(windows) and (defined(vcc) or defined(bcc)) + when not defined(JS): # C proc hypot*(x, y: float32): float32 {.importc: "hypotf", header: "".} proc hypot*(x, y: float64): float64 {.importc: "hypot", header: "".} @@ -280,25 +279,27 @@ when not defined(JS): # C ## ## To compute power between integers, use `^` e.g. 2 ^ 6 - proc erf*(x: float32): float32 {.importc: "erff", header: "".} - proc erf*(x: float64): float64 {.importc: "erf", header: "".} - ## The error function - proc erfc*(x: float32): float32 {.importc: "erfcf", header: "".} - proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} - ## The complementary error function + # TODO: add C89 version on windows + when not windowsCC89: + proc erf*(x: float32): float32 {.importc: "erff", header: "".} + proc erf*(x: float64): float64 {.importc: "erf", header: "".} + ## The error function + proc erfc*(x: float32): float32 {.importc: "erfcf", header: "".} + proc erfc*(x: float64): float64 {.importc: "erfc", header: "".} + ## The complementary error function - proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} - proc gamma*(x: float64): float64 {.importc: "tgamma", header: "".} - ## The gamma function - proc tgamma*(x: float32): float32 - {.deprecated: "use gamma instead", importc: "tgammaf", header: "".} - proc tgamma*(x: float64): float64 - {.deprecated: "use gamma instead", importc: "tgamma", header: "".} - ## The gamma function - ## **Deprecated since version 0.19.0**: Use ``gamma`` instead. - proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} - proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} - ## Natural log of the gamma function + proc gamma*(x: float32): float32 {.importc: "tgammaf", header: "".} + proc gamma*(x: float64): float64 {.importc: "tgamma", header: "".} + ## The gamma function + proc tgamma*(x: float32): float32 + {.deprecated: "use gamma instead", importc: "tgammaf", header: "".} + proc tgamma*(x: float64): float64 + {.deprecated: "use gamma instead", importc: "tgamma", header: "".} + ## The gamma function + ## **Deprecated since version 0.19.0**: Use ``gamma`` instead. + proc lgamma*(x: float32): float32 {.importc: "lgammaf", header: "".} + proc lgamma*(x: float64): float64 {.importc: "lgamma", header: "".} + ## Natural log of the gamma function proc floor*(x: float32): float32 {.importc: "floorf", header: "".} proc floor*(x: float64): float64 {.importc: "floor", header: "".} @@ -314,7 +315,7 @@ when not defined(JS): # C ## .. code-block:: nim ## echo ceil(-2.1) ## -2.0 - when defined(windows) and (defined(vcc) or defined(bcc)): + when windowsCC89: # MSVC 2010 don't have trunc/truncf # this implementation was inspired by Go-lang Math.Trunc proc truncImpl(f: float64): float64 = @@ -452,6 +453,28 @@ when not defined(JS): var exp: int32 result = c_frexp(x, exp) exponent = exp + + when windowsCC89: + # taken from Go-lang Math.Log2 + const ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 + template log2Impl[T](x: T): T = + var exp: int32 + var frac = frexp(x, exp) + # Make sure exact powers of two give an exact answer. + # Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1. + if frac == 0.5: return T(exp - 1) + log10(frac)*(1/ln2) + T(exp) + + proc log2*(x: float32): float32 = log2Impl(x) + proc log2*(x: float64): float64 = log2Impl(x) + ## Log2 returns the binary logarithm of x. + ## The special cases are the same as for Log. + + else: + proc log2*(x: float32): float32 {.importc: "log2f", header: "".} + proc log2*(x: float64): float64 {.importc: "log2", header: "".} + ## Computes the binary logarithm (base 2) of `x` + else: proc frexp*[T: float32|float64](x: T, exponent: var int): T = if x == 0.0: @@ -564,7 +587,7 @@ proc lcm*[T](x, y: T): T = ## Computes the least common multiple of ``x`` and ``y``. x div gcd(x, y) * y -when isMainModule and not defined(JS): +when isMainModule and not defined(JS) and not windowsCC89: # Check for no side effect annotation proc mySqrt(num: float): float {.noSideEffect.} = return sqrt(num) @@ -692,3 +715,14 @@ when isMainModule: block: # log doAssert log(4.0, 3.0) == ln(4.0) / ln(3.0) + doAssert log2(8.0'f64) == 3.0'f64 + doAssert log2(4.0'f64) == 2.0'f64 + doAssert log2(2.0'f64) == 1.0'f64 + doAssert log2(1.0'f64) == 0.0'f64 + doAssert classify(log2(0.0'f64)) == fcNegInf + + doAssert log2(8.0'f32) == 3.0'f32 + doAssert log2(4.0'f32) == 2.0'f32 + doAssert log2(2.0'f32) == 1.0'f32 + doAssert log2(1.0'f32) == 0.0'f32 + doAssert classify(log2(0.0'f32)) == fcNegInf diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index 3263f1d370..60a6e5d9b3 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -396,7 +396,7 @@ else: proc moveFileA*(lpExistingFileName, lpNewFileName: cstring): WINBOOL {. importc: "MoveFileA", stdcall, dynlib: "kernel32".} - proc moveFileExA*(lpExistingFileName, lpNewFileName: WideCString, + proc moveFileExA*(lpExistingFileName, lpNewFileName: cstring, flags: DWORD): WINBOOL {. importc: "MoveFileExA", stdcall, dynlib: "kernel32".}