tests: exercise wide 32-bit products and unsigned umul16
Add runtime markers for a full-width 32x32 multiply (0x12345678 * 0x9abcdef0 = 0x242d2080) and for a wide-dividend remainder, so a 16-bit-truncated MPYS or a wrong FS1 cannot still produce the expected small results. Compute the 16x16 unsigned product in unsigned arithmetic to remove the signed-overflow annotation, and reject a regressed nuw nsw multiply in the optimized IR.
This commit is contained in:
1 parent
7cd9a48ee3
commit
00522b56fc
3 files changed
+29
-10
No files matched your search
@@ -14,6 +14,8 @@
|
||||
-- 018A80E0 srem(-100,7) == -2
|
||||
-- 018A8100 sumto(10) == 55
|
||||
-- 018A8120 squares(5) == 30
|
||||
-- 018A8140 mul(0x12345678,0x9abcdef0) == 0x242d2080
|
||||
-- 018A8160 urem(0xfffffffe,7) == 2
|
||||
|
||||
dofile(os.getenv("M4_LOADER_LUA"))
|
||||
|
||||
@@ -28,16 +30,17 @@ emu.register_frame_done(function()
|
||||
checked = true
|
||||
local prog = manager.machine.devices[':maincpu'].spaces['program']
|
||||
local m = {}
|
||||
for i = 0, 9 do
|
||||
for i = 0, 11 do
|
||||
m[i] = prog:read_u32(0x018A8000 + i * 0x20)
|
||||
end
|
||||
print(string.format(
|
||||
"M4: mul=%d umul16=%d sdiv=%d udiv=%d srem=%d urem=%d sdivneg=%d sremneg=%d sumto=%d squares=%d",
|
||||
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9]))
|
||||
"M4: mul=%d umul16=%d sdiv=%d udiv=%d srem=%d urem=%d sdivneg=%d sremneg=%d sumto=%d squares=%d widemul=%d widerem=%d",
|
||||
m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9],
|
||||
m[10], m[11]))
|
||||
local want = {42, 0xfffe0001, 14, 613566756, 2, 2,
|
||||
0xfffffff2, 0xfffffffe, 55, 30}
|
||||
0xfffffff2, 0xfffffffe, 55, 30, 0x242d2080, 2}
|
||||
local ok = true
|
||||
for i = 0, 9 do
|
||||
for i = 0, 11 do
|
||||
if m[i] ~= want[i + 1] then
|
||||
ok = false
|
||||
end
|
||||
@@ -45,7 +48,7 @@ emu.register_frame_done(function()
|
||||
if ok then
|
||||
print("M4 MAME: PASS")
|
||||
else
|
||||
print("M4 MAME: FAIL (want mul=42 umul16=4294836225 sdiv=14 udiv=613566756 srem=2 urem=2 sdivneg=-14 sremneg=-2 sumto=55 squares=30)")
|
||||
print("M4 MAME: FAIL (want mul=42 umul16=4294836225 sdiv=14 udiv=613566756 srem=2 urem=2 sdivneg=-14 sremneg=-2 sumto=55 squares=30 widemul=606937216 widerem=2)")
|
||||
end
|
||||
end
|
||||
end, "mul-check")
|
||||
+10
-3
@@ -9,15 +9,20 @@
|
||||
* 018A80A0 urem(100,7) == 2
|
||||
* 018A80C0 sdiv(-100,7) == -14
|
||||
* 018A80E0 srem(-100,7) == -2
|
||||
* 018A8140 mul(0x12345678,0x9ABCDEF0) == 0x242D2080 (wide 32x32 product)
|
||||
* 018A8160 urem(0xfffffffe,7) == 2 (wide quotient in the remainder)
|
||||
*/
|
||||
#define MARK(n) (*(volatile unsigned int *)(0x018A8000u + (n)*0x20u))
|
||||
|
||||
int mul(int a, int b) { return a * b; }
|
||||
|
||||
/* A 16x16 unsigned product: both operands are masked to 16 bits, which is the
|
||||
* form the target selects to MPYU. A plain unsigned short multiply promotes
|
||||
* to a signed int multiply and would use MPYS. */
|
||||
int umul16(int a, int b) { return (a & 0xffff) * (b & 0xffff); }
|
||||
* form the target selects to MPYU. The product must be computed in unsigned
|
||||
* arithmetic: 0xffff * 0xffff does not fit in signed int, so `int * int` would
|
||||
* be signed overflow and the optimizer could narrow or rename the result. */
|
||||
int umul16(int a, int b) {
|
||||
return (int)((unsigned)(a & 0xffff) * (unsigned)(b & 0xffff));
|
||||
}
|
||||
|
||||
int sdiv(int a, int b) { return a / b; }
|
||||
unsigned udiv(unsigned a, unsigned b) { return a / b; }
|
||||
@@ -33,5 +38,7 @@ int mul_test(void) {
|
||||
MARK(5) = urem(100u, 7u);
|
||||
MARK(6) = (unsigned)sdiv(-100, 7);
|
||||
MARK(7) = (unsigned)srem(-100, 7);
|
||||
MARK(10) = (unsigned)mul(0x12345678, 0x9ABCDEF0);
|
||||
MARK(11) = urem(0xfffffffeu, 7u);
|
||||
return 0;
|
||||
}
|
||||
+10
-1
@@ -34,6 +34,15 @@ if grep -Eq '\bmul i(33|64)\b' "$WORK/asm/loop.ll"; then
|
||||
fi
|
||||
echo " ok driver -O2 loop IR has no i33/i64 multiply"
|
||||
|
||||
# The 16x16 unsigned product must not carry the old signed-overflow
|
||||
# annotation. With the multiply done in unsigned arithmetic the IR is
|
||||
# `mul nuw`, not `mul nuw nsw`; the latter contradicts the 0xfffe0001 result.
|
||||
if awk '/^define .*@umul16\(/{infn=1} infn{print} infn && /^}/{exit}' \
|
||||
"$WORK/asm/mul.ll" | grep -q 'mul nuw nsw'; then
|
||||
fail "umul16 still has a signed no-wrap multiply (the product is unsigned)"
|
||||
fi
|
||||
echo " ok umul16 multiplies without signed no-wrap"
|
||||
|
||||
# Stop at the next function label (a column-0 label that is not an LBB block
|
||||
# label), so a following local function cannot leak into this slice.
|
||||
body() { # body FILE FUNC
|
||||
@@ -49,7 +58,7 @@ body() { # body FILE FUNC
|
||||
TMP=$(mktemp -d "${TMPDIR:-/tmp}/m4-mul.XXXXXX")
|
||||
trap 'rm -rf "$TMP"' EXIT HUP INT TERM
|
||||
|
||||
EXPECTED="M4: mul=42 umul16=4294836225 sdiv=14 udiv=613566756 srem=2 urem=2 sdivneg=4294967282 sremneg=4294967294 sumto=55 squares=30"
|
||||
EXPECTED="M4: mul=42 umul16=4294836225 sdiv=14 udiv=613566756 srem=2 urem=2 sdivneg=4294967282 sremneg=4294967294 sumto=55 squares=30 widemul=606937216 widerem=2"
|
||||
grep -Fqx "$EXPECTED" "$WORK/mame.log" \
|
||||
|| { grep -E '^M4: ' "$WORK/mame.log" >&2 || true; fail "runtime markers did not match: $EXPECTED"; }
|
||||
echo " ok runtime markers: $EXPECTED"
|
||||
|
||||
Reference in new issue
Block a user