[Scummvm-git-logs] scummvm master -> a90a1a0aed9c52b96366a5f4546c1354d558a684
sev-
noreply at scummvm.org
Fri Jun 3 19:28:20 UTC 2022
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
a90a1a0aed COMMON: Move 80-bit float parsing from Director to Common (#3953)
Commit: a90a1a0aed9c52b96366a5f4546c1354d558a684
https://github.com/scummvm/scummvm/commit/a90a1a0aed9c52b96366a5f4546c1354d558a684
Author: Eric Lasota (ejlasota at gmail.com)
Date: 2022-06-03T21:28:17+02:00
Commit Message:
COMMON: Move 80-bit float parsing from Director to Common (#3953)
Changed paths:
A common/xpfloat.cpp
A common/xpfloat.h
common/module.mk
engines/director/lingo/lingo-bytecode.cpp
diff --git a/common/module.mk b/common/module.mk
index 85c7a3bf676..0d27c0d145b 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -55,6 +55,7 @@ MODULE_OBJS := \
winexe_ne.o \
winexe_pe.o \
xmlparser.o \
+ xpfloat.o \
zlib.o
MODULE_OBJS += \
diff --git a/common/xpfloat.cpp b/common/xpfloat.cpp
new file mode 100644
index 00000000000..15eb0b624eb
--- /dev/null
+++ b/common/xpfloat.cpp
@@ -0,0 +1,161 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/xpfloat.h"
+#include "common/textconsole.h"
+
+/*
+Format:
+s eeeeeeeeeeeeeee i fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+^ ^ ^ ^
+| | | |
+| Exponent (15) | Fraction (63)
+Sign (1) Integer i (1)
+
+MC68881 semantics:
+e i f meaning
+0 <= e <= 32766 1 any (-1)^s x 2^(e-16383) x (1.f) Normalized
+0 <= e <= 32766 0 non-0 (-1)^s x 2^(e-16383) x (0.f) Denormalized
+0 <= e <= 32766 0 0 (-1)^s x 0 Zero
+32767 any 0 (-1)^s x Infinity Infinity
+32767 any non-0 NaN NaN
+*/
+
+namespace Common {
+
+XPFloat XPFloat::fromDouble(double value, Semantics semantics) {
+ uint64 bits;
+ memcpy(&bits, &value, 8);
+ return fromDoubleBits(bits, semantics);
+}
+
+XPFloat XPFloat::fromDoubleBits(uint64 inBits, Semantics semantics) {
+ uint64 inMantissa = inBits & 0xfffffffffffffu;
+ int16 inExponent = (inBits >> 52) & 0x7ff;
+ uint8 inSign = (inBits >> 63) & 1;
+
+ // Convert to 1.63 fraction and absolute exponent
+ uint64 workMantissa = 0;
+ int16 workExponent = 0;
+ if (inExponent == 0) {
+ if (inMantissa == 0) {
+ // +/- 0
+ return XPFloat(inSign << 15, 0);
+ } else {
+ // Subnormal
+ workMantissa = inMantissa << 11;
+ workExponent = -1022;
+
+ // Move implicit 1 to the high bit
+ while ((workMantissa & 0x8000000000000000u) == 0) {
+ workMantissa <<= 1;
+ workExponent--;
+ }
+ }
+ } else if (inExponent == 0x7ff) {
+ if (inMantissa == 0) {
+ // Infinity
+ return XPFloat((inSign << 15) | 0x7fffu, static_cast<uint64>(1) << 63);
+ } else {
+ // NaN
+ return XPFloat(0xFFFFu, 0xffffffffffffffffu);
+ }
+ } else {
+ // Normal number
+ workExponent = inExponent - 1023;
+ workMantissa = (inMantissa | 0x10000000000000) << 11;
+ }
+
+ return XPFloat((inSign << 15) | (workExponent + 16383), workMantissa);
+}
+
+void XPFloat::toDoubleSafe(double &result, bool &outOverflowed, Semantics semantics) const {
+ uint64 temp;
+ toDoubleBitsSafe(temp, outOverflowed, semantics);
+ memcpy(&result, &temp, 8);
+}
+
+void XPFloat::toDoubleBitsSafe(uint64 &result, bool &outOverflowed, Semantics semantics) const {
+ bool overflowed = false;
+ uint64 doubleBits = 0;
+ if ((signAndExponent & 0x7fff) == 0x7fff) {
+ if ((mantissa & 0x7fffffffffffffffu) == 0) {
+ // Infinity
+ doubleBits = (static_cast<uint64>(signAndExponent & 0x8000) << 63) | 0x7ff0000000000000u;
+ } else {
+ // NaN
+ doubleBits = 0xffffffffffffffff;
+ }
+ } else {
+ // For MC68881 semantics, denormal and normal numbers are handled the same way because the
+ // i bit is effectively an explicit 1.
+ uint8 signBit = ((signAndExponent >> 15) & 1);
+ if (mantissa == 0) {
+ // +/- 0
+ doubleBits = static_cast<uint64>(signBit) << 63;
+ } else {
+ // Convert to 1.63
+ int32 workExponent = static_cast<int32>(signAndExponent & 0x7fff) - 16383;
+ uint64 workMantissa = mantissa;
+
+ while ((workMantissa & 0x8000000000000000u) == 0) {
+ workMantissa <<= 1;
+ workExponent--;
+ }
+
+ int32 adjustedExponent = workExponent + 1023;
+ if (adjustedExponent < 0) {
+ // Subnormal
+ int subnormalBits = -adjustedExponent;
+ if (subnormalBits > 52)
+ workMantissa = 0;
+ else
+ workMantissa >>= subnormalBits;
+ adjustedExponent = 0;
+ } else {
+ // Normal
+ if (adjustedExponent >= 0x7ff) {
+ // Overflow to +/- infinity
+ overflowed = true;
+ adjustedExponent = 0x7ff;
+ workMantissa = 0;
+ }
+ }
+
+ doubleBits = (static_cast<uint64>(signBit) << 63) | (static_cast<uint64>(adjustedExponent) << 52) | ((workMantissa >> 11) & 0xfffffffffffffu);
+ }
+ }
+
+ memcpy(&result, &doubleBits, 8);
+ outOverflowed = overflowed;
+}
+
+double XPFloat::toDouble(Semantics semantics) const {
+ double result;
+ bool overflowed;
+ toDoubleSafe(result, overflowed, semantics);
+ if (overflowed)
+ warning("Extended-precision floating point value was too large to represent as a double");
+
+ return result;
+}
+
+}
diff --git a/common/xpfloat.h b/common/xpfloat.h
new file mode 100644
index 00000000000..e7eb715335c
--- /dev/null
+++ b/common/xpfloat.h
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef COMMON_XPFLOAT_H
+#define COMMON_XPFLOAT_H
+
+// 80-bit extended precision floating point
+// Mostly encountered stored as data on Apple systems
+
+#include "common/scummsys.h"
+
+namespace Common {
+
+struct XPFloat {
+ uint16 signAndExponent;
+ uint64 mantissa;
+
+ enum Semantics {
+ kSemanticsMC68881,
+ kSemanticsSANE = kSemanticsMC68881,
+
+ // Could add Intel 8087 and derivatives here since they're mostly compatible,
+ // but have different NaN/INF flag cases.
+ };
+
+ XPFloat();
+ XPFloat(uint16 signAndExponent, uint64 mantissa);
+ XPFloat(const XPFloat &other);
+
+ static XPFloat fromDouble(double value, Semantics semantics = kSemanticsMC68881);
+ static XPFloat fromDoubleBits(uint64 value, Semantics semantics = kSemanticsMC68881);
+
+ void toDoubleSafe(double &result, bool &outOverflowed, Semantics semantics = kSemanticsMC68881) const;
+ void toDoubleBitsSafe(uint64 &result, bool &outOverflowed, Semantics semantics = kSemanticsMC68881) const;
+
+ // Simple version that clamps to infinity and warns on overflow
+ double toDouble(Semantics semantics = kSemanticsMC68881) const;
+};
+
+inline XPFloat::XPFloat() : signAndExponent(0), mantissa(0) {}
+inline XPFloat::XPFloat(uint16 fSignAndExponent, uint64 fMantissa) : signAndExponent(fSignAndExponent), mantissa(fMantissa) {}
+inline XPFloat::XPFloat(const XPFloat &other) : signAndExponent(other.signAndExponent), mantissa(other.mantissa) {}
+
+}
+
+#endif
diff --git a/engines/director/lingo/lingo-bytecode.cpp b/engines/director/lingo/lingo-bytecode.cpp
index 11b0fa5d9d2..7ed7d520ccc 100644
--- a/engines/director/lingo/lingo-bytecode.cpp
+++ b/engines/director/lingo/lingo-bytecode.cpp
@@ -22,6 +22,7 @@
#include "common/config-manager.h"
#include "common/file.h"
#include "common/substream.h"
+#include "common/xpfloat.h"
#include "director/director.h"
#include "director/cast.h"
@@ -1140,29 +1141,10 @@ ScriptContext *LingoCompiler::compileLingoV4(Common::SeekableReadStreamEndian &s
error("Constant float expected to be 10 bytes");
break;
}
- uint16 exponent = READ_BE_UINT16(&constsStore[pointer]);
- uint64 f64sign = (uint64)(exponent & 0x8000) << 48;
- exponent &= 0x7fff;
- uint64 fraction = READ_BE_UINT64(&constsStore[pointer+2]);
- fraction &= 0x7fffffffffffffffULL;
- uint64 f64exp = 0;
- if (exponent == 0) {
- f64exp = 0;
- } else if (exponent == 0x7fff) {
- f64exp = 0x7ff;
- } else {
- int32 normexp = (int32)exponent - 0x3fff;
- if ((-0x3fe > normexp) || (normexp >= 0x3ff)) {
- error("Constant float exponent too big for a double");
- break;
- }
- f64exp = (uint64)(normexp + 0x3ff);
- }
- f64exp <<= 52;
- uint64 f64fract = fraction >> 11;
- uint64 f64bin = f64sign | f64exp | f64fract;
+ uint16 signAndExponent = READ_BE_UINT16(&constsStore[pointer]);
+ uint64 mantissa = READ_BE_UINT64(&constsStore[pointer+2]);
- constant.u.f = *(double *)(&f64bin);
+ constant.u.f = Common::XPFloat(signAndExponent, mantissa).toDouble(Common::XPFloat::kSemanticsSANE);
}
break;
default:
More information about the Scummvm-git-logs
mailing list