shithub: rgbds

Download patch

ref: 748e7dd4c79f0fef101a30b91252388f945254b9
parent: d049ffc0f0a508f9d48d27e850692f54b6c062f8
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Wed Feb 17 04:25:02 EST 2021

Fix calculation of 2**30

In exponent(), 'base *= base;' should not run
when base is 65536, since it overflows an int32_t.

This also optimizes exponent() based on
gcc and clang -O3 test cases in godbolt.org.

--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -283,14 +283,16 @@
 	}
 }
 
-static int32_t exponent(int32_t base, int32_t power)
+static int32_t exponent(int32_t base, uint32_t power)
 {
 	int32_t result = 1;
 
-	while (power) {
+	for (;;) {
 		if (power % 2)
 			result *= base;
 		power /= 2;
+		if (!power)
+			break;
 		base *= base;
 	}
 
--- a/src/link/patch.c
+++ b/src/link/patch.c
@@ -21,14 +21,16 @@
 
 #include "extern/err.h"
 
-static int32_t exponent(int32_t base, int32_t power)
+static int32_t exponent(int32_t base, uint32_t power)
 {
 	int32_t result = 1;
 
-	while (power) {
+	for (;;) {
 		if (power % 2)
 			result *= base;
 		power /= 2;
+		if (!power)
+			break;
 		base *= base;
 	}
 
--- a/test/asm/math.asm
+++ b/test/asm/math.asm
@@ -12,7 +12,9 @@
 ENDM
 
 	test (v 2)*(v 10)**(v 2)*(v 2) == (v 400)
-	test -(v 3)**(v 4) == v -81
+	test -(v 3)**(v 4) == (v -81)
+	test (v 1) << (v 30) == (v $4000_0000)
+	test (v 2)**(v 30) == (v $4000_0000)
 
 	assert DIV(5.0, 2.0) == 2.5
 	assert DIV(-5.0, 2.0) == -2.5