From aba52f32b01212a7226dfcbeee9b00387591598e Mon Sep 17 00:00:00 2001
From: Mihawk <163614687+mihawk-99@users.noreply.github.com>
Date: Thu, 8 Oct 2026 19:30:16 -0400
Subject: [PATCH] host: preserve IEEE denormal assumptions in compiler wrappers
---
host/bin/prospero-clang | 1 +
host/bin/prospero-clang++ | 1 +
samples/test_denormals/Makefile | 48 +++++++++++++++++++++++++++++++
samples/test_denormals/classify.c | 11 +++++++
samples/test_denormals/main.c | 24 ++++++++++++++++
5 files changed, 85 insertions(+)
create mode 100644 samples/test_denormals/Makefile
create mode 100644 samples/test_denormals/classify.c
create mode 100644 samples/test_denormals/main.c
diff --git a/host/bin/prospero-clang b/host/bin/prospero-clang
index 0f91935a..38d79de9 100755
--- a/host/bin/prospero-clang
+++ b/host/bin/prospero-clang
@@ -75,6 +75,7 @@ exec -a "${SCRIPT_NAME}" "${SCRIPT_DIR}/clang" \
-L "${PS5_PAYLOAD_SDK}/target/lib" \
-L "${PS5_PAYLOAD_HBROOT}/lib" \
-fno-stack-protector -fno-plt -femulated-tls \
+ -fdenormal-fp-math=ieee \
$LIBS_C \
--end-no-unused-arguments \
"$@" \
diff --git a/host/bin/prospero-clang++ b/host/bin/prospero-clang++
index 9b698cf0..0ee8a057 100755
--- a/host/bin/prospero-clang++
+++ b/host/bin/prospero-clang++
@@ -80,6 +80,7 @@ exec -a "${SCRIPT_NAME}" "${SCRIPT_DIR}/clang++" \
-L "${PS5_PAYLOAD_SDK}/target/lib" \
-L "${PS5_PAYLOAD_HBROOT}/lib" \
-fno-stack-protector -fno-plt -femulated-tls \
+ -fdenormal-fp-math=ieee \
-frtti -fexceptions \
$LIBS_CXX $LIBS_C \
--end-no-unused-arguments \
diff --git a/samples/test_denormals/Makefile b/samples/test_denormals/Makefile
new file mode 100644
index 00000000..ab2a2b9e
--- /dev/null
+++ b/samples/test_denormals/Makefile
@@ -0,0 +1,48 @@
+# Copyright (C) 2023 John Törnblom
+#
+# This file 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; see the file COPYING. If not see
+# .
+
+PS5_HOST ?= ps5
+PS5_PORT ?= 9021
+
+ifdef PS5_PAYLOAD_SDK
+ include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk
+else
+ $(error PS5_PAYLOAD_SDK is undefined)
+endif
+
+ELF := test_denormals.elf
+
+CFLAGS := -Wall -Werror -g -O2
+
+all: $(ELF)
+
+$(ELF): main.c classify.c
+ $(CC) $(CFLAGS) -o $@ $^
+
+clean:
+ rm -f $(ELF)
+
+test: $(ELF)
+ $(PS5_DEPLOY) -h $(PS5_HOST) -p $(PS5_PORT) $^
+
+debug: $(ELF)
+ gdb-multiarch \
+ -ex "set architecture i386:x86-64" \
+ -ex "target extended-remote $(PS5_HOST):2159" \
+ -ex "file $(ELF)" \
+ -ex "remote put $(ELF) /data/$(ELF)" \
+ -ex "set remote exec-file /data/$(ELF)" \
+ -ex "start"
diff --git a/samples/test_denormals/classify.c b/samples/test_denormals/classify.c
new file mode 100644
index 00000000..12c6f175
--- /dev/null
+++ b/samples/test_denormals/classify.c
@@ -0,0 +1,11 @@
+/* Copyright (C) 2026 Mihawk
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+#include
+
+/* A separate translation unit prevents constant folding at the call site. */
+int
+classify(float value) {
+ return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL,
+ FP_SUBNORMAL, FP_ZERO, value);
+}
diff --git a/samples/test_denormals/main.c b/samples/test_denormals/main.c
new file mode 100644
index 00000000..fe521cd1
--- /dev/null
+++ b/samples/test_denormals/main.c
@@ -0,0 +1,24 @@
+/* Copyright (C) 2026 Mihawk
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+#include
+#include
+#include
+#include
+
+int classify(float value);
+
+int
+main(void) {
+ unsigned previous, ieee;
+ uint32_t bits = 1; /* Smallest positive IEEE binary32 subnormal. */
+ float value;
+ memcpy(&value, &bits, sizeof(value));
+ __asm__ volatile("stmxcsr %0" : "=m"(previous));
+ ieee = previous & ~0x8040u; /* Disable FTZ and DAZ for this test. */
+ __asm__ volatile("ldmxcsr %0" : : "m"(ieee) : "memory");
+ const int actual = classify(value);
+ __asm__ volatile("ldmxcsr %0" : : "m"(previous) : "memory");
+ printf("classification=%d, expected FP_SUBNORMAL=%d\n", actual, FP_SUBNORMAL);
+ return actual != FP_SUBNORMAL;
+}