[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