make -d:nimFpRoundtrips work consistently in vm vs rt, fix #18400, etc (#18531)

* compiler/vmhooks: add getVar to allow vmops with var params
* addFloat vmops with var param
* cgen now renders float32 literals in c backend using roundtrip float to string
This commit is contained in:
Timothee Cour 2021-07-20 13:13:52 -07:00 • committed by GitHub
commit cf0cf32d27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 286 additions and 199 deletions

View file

@ -652,7 +652,7 @@ type
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot,
mUnaryPlusI, mBitnotI,
mUnaryPlusF64, mUnaryMinusF64,
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr,
mStrToStr, mEnumToStr,
mAnd, mOr,
mImplies, mIff, mExists, mForall, mOld,
@ -720,7 +720,7 @@ const
mEqRef, mEqProc, mLePtr, mLtPtr, mEqCString, mXor,
mUnaryMinusI, mUnaryMinusI64, mAbsI, mNot, mUnaryPlusI, mBitnotI,
mUnaryPlusF64, mUnaryMinusF64,
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr, mCStrToStr,
mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr,
mStrToStr, mEnumToStr,
mAnd, mOr,
mEqStr, mLeStr, mLtStr,

View file

@ -94,9 +94,12 @@ proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
else:
result = makeCString(n.strVal)
of nkFloatLit, nkFloat64Lit:
result = rope(n.floatVal.toStrMaxPrecision)
if ty.kind == tyFloat32:
result = rope(n.floatVal.float32.toStrMaxPrecision)
else:
result = rope(n.floatVal.toStrMaxPrecision)
of nkFloat32Lit:
result = rope(n.floatVal.toStrMaxPrecision("f"))
result = rope(n.floatVal.float32.toStrMaxPrecision)
else:
internalError(p.config, n.info, "genLiteral(" & $n.kind & ')')
result = nil
@ -2300,11 +2303,6 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
of mInt64ToStr: genDollar(p, e, d, "#nimInt64ToStr($1)")
of mBoolToStr: genDollar(p, e, d, "#nimBoolToStr($1)")
of mCharToStr: genDollar(p, e, d, "#nimCharToStr($1)")
of mFloatToStr:
if e[1].typ.skipTypes(abstractInst).kind == tyFloat32:
genDollar(p, e, d, "#nimFloat32ToStr($1)")
else:
genDollar(p, e, d, "#nimFloatToStr($1)")
of mCStrToStr: genDollar(p, e, d, "#cstrToNimstr($1)")
of mStrToStr, mUnown: expr(p, e[1], d)
of mIsolate: genCall(p, e, d)

View file

@ -434,7 +434,6 @@ const # magic checked op; magic unchecked op;
mBoolToStr: ["nimBoolToStr", "nimBoolToStr"],
mIntToStr: ["cstrToNimstr", "cstrToNimstr"],
mInt64ToStr: ["cstrToNimstr", "cstrToNimstr"],
mFloatToStr: ["cstrToNimstr", "cstrToNimstr"],
mCStrToStr: ["cstrToNimstr", "cstrToNimstr"],
mStrToStr: ["", ""]]
@ -656,9 +655,6 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
of mBoolToStr: applyFormat("nimBoolToStr($1)", "nimBoolToStr($1)")
of mIntToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")")
of mInt64ToStr: applyFormat("cstrToNimstr(($1) + \"\")", "cstrToNimstr(($1) + \"\")")
of mFloatToStr:
useMagic(p, "nimFloatToString")
applyFormat "cstrToNimstr(nimFloatToString($1))"
of mCStrToStr: applyFormat("cstrToNimstr($1)", "cstrToNimstr($1)")
of mStrToStr, mUnown, mIsolate: applyFormat("$1", "$1")
else:
@ -682,8 +678,7 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
gen(p, n[1], x)
gen(p, n[2], y)
r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc]
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mFloatToStr,
mCStrToStr, mStrToStr, mEnumToStr:
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr:
arithAux(p, n, r, op)
of mEqRef:
if mapType(n[1].typ) != etyBaseIndex:

View file

@ -4,6 +4,7 @@ hint:XDeclaredButNotUsed:off
define:booting
define:nimcore
define:nimFpRoundtrips
#import:"$projectpath/testability"

View file

@ -39,7 +39,10 @@ when not declared(signbit):
proc signbit*(x: SomeFloat): bool {.inline.} =
result = c_signbit(x) != 0
proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
import system/formatfloat
proc toStrMaxPrecision*(f: BiggestFloat | float32): string =
const literalPostfix = when f is float32: "f" else: ""
case classify(f)
of fcNan:
if signbit(f):
@ -55,9 +58,8 @@ proc toStrMaxPrecision*(f: BiggestFloat, literalPostfix = ""): string =
of fcNegInf:
result = "-INF"
else:
result = newString(81)
let n = c_snprintf(result.cstring, result.len.uint, "%#.16e%s", f, literalPostfix.cstring)
setLen(result, n)
result.addFloatRoundtrip(f)
result.add literalPostfix
proc encodeStr*(s: string, result: var string) =
for i in 0..<s.len:

View file

@ -290,7 +290,6 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; idgen: IdGenerator; g: ModuleGraph): P
of mBoolToStr:
if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
else: result = newStrNodeT("true", n, g)
of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
of mCStrToStr, mCharToStr:
if a.kind == nkBracket:
var s = ""

View file

@ -1127,8 +1127,7 @@ proc genMagic(c: PCtx; n: PNode; dest: var TDest; m: TMagic) =
let t = skipTypes(n.typ, abstractVar-{tyTypeDesc})
if t.kind in {tyUInt8..tyUInt32} or (t.kind == tyUInt and t.size < 8):
c.gABC(n, opcNarrowU, dest, TRegister(t.size*8))
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr,
mFloatToStr, mCStrToStr, mStrToStr, mEnumToStr:
of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr:
genConv(c, n, n[1], dest)
of mEqStr, mEqCString: genBinaryABC(c, n, dest, opcEqStr)
of mLeStr: genBinaryABC(c, n, dest, opcLeStr)

View file

@ -36,10 +36,14 @@ proc setResult*(a: VmArgs; v: seq[string]) =
for x in v: n.add newStrNode(nkStrLit, x)
a.slots[a.ra].node = n
template getX(k, field) {.dirty.} =
template getReg(a, i): untyped =
doAssert i < a.rc-1
doAssert a.slots[i+a.rb+1].kind == k
result = a.slots[i+a.rb+1].field
a.slots[i+a.rb+1].unsafeAddr
template getX(k, field): untyped {.dirty.} =
let p = getReg(a, i)
doAssert p.kind == k, $p.kind
p.field
proc numArgs*(a: VmArgs): int =
result = a.rc-1
@ -47,19 +51,17 @@ proc numArgs*(a: VmArgs): int =
proc getInt*(a: VmArgs; i: Natural): BiggestInt = getX(rkInt, intVal)
proc getBool*(a: VmArgs; i: Natural): bool = getInt(a, i) != 0
proc getFloat*(a: VmArgs; i: Natural): BiggestFloat = getX(rkFloat, floatVal)
proc getString*(a: VmArgs; i: Natural): string =
doAssert i < a.rc-1
doAssert a.slots[i+a.rb+1].kind == rkNode
result = a.slots[i+a.rb+1].node.strVal
proc getNode*(a: VmArgs; i: Natural): PNode =
doAssert i < a.rc-1
doAssert a.slots[i+a.rb+1].kind == rkNode
result = a.slots[i+a.rb+1].node
proc getNode*(a: VmArgs; i: Natural): PNode = getX(rkNode, node)
proc getString*(a: VmArgs; i: Natural): string = getX(rkNode, node).strVal
proc getVar*(a: VmArgs; i: Natural): PNode =
let p = getReg(a, i)
# depending on whether we come from top-level or proc scope, we need to consider 2 cases
case p.kind
of rkRegisterAddr: result = p.regAddr.node
of rkNodeAddr: result = p.nodeAddr[]
else: doAssert false, $p.kind
proc getNodeAddr*(a: VmArgs; i: Natural): PNode =
doAssert i < a.rc-1
doAssert a.slots[i+a.rb+1].kind == rkNodeAddr
let nodeAddr = a.slots[i+a.rb+1].nodeAddr
let nodeAddr = getX(rkNodeAddr, nodeAddr)
doAssert nodeAddr != nil
result = nodeAddr[]

View file

@ -27,6 +27,7 @@ from std/md5 import getMD5
from std/times import cpuTime
from std/hashes import hash
from std/osproc import nil
from system/formatfloat import addFloatRoundtrip, addFloatSprintf
from sighashes import symBodyDigest
@ -325,3 +326,13 @@ proc registerAdditionalOps*(c: PCtx) =
registerCallback c, "stdlib.typetraits.hasClosureImpl", proc (a: VmArgs) =
let fn = getNode(a, 0)
setResult(a, fn.kind == nkClosure or (fn.typ != nil and fn.typ.callConv == ccClosure))
registerCallback c, "stdlib.formatfloat.addFloatRoundtrip", proc(a: VmArgs) =
let p = a.getVar(0)
let x = a.getFloat(1)
addFloatRoundtrip(p.strVal, x)
registerCallback c, "stdlib.formatfloat.addFloatSprintf", proc(a: VmArgs) =
let p = a.getVar(0)
let x = a.getFloat(1)
addFloatSprintf(p.strVal, x)