shithub: rgbds

Download patch

ref: eb5af70d79cd35d4383d7746a0190ce423119344
parent: cf19879281a953cbf754673be9a212c874971857
author: ISSOtm <eldredhabert0@gmail.com>
date: Sat Feb 5 06:27:41 EST 2022

Add unsigned right shift operator

--- a/include/linkdefs.h
+++ b/include/linkdefs.h
@@ -14,7 +14,7 @@
 
 #define RGBDS_OBJECT_VERSION_STRING "RGB%1u"
 #define RGBDS_OBJECT_VERSION_NUMBER 9U
-#define RGBDS_OBJECT_REV 8U
+#define RGBDS_OBJECT_REV 9U
 
 enum AssertionType {
 	ASSERT_WARN,
@@ -49,6 +49,7 @@
 
 	RPN_SHL			= 0x40,
 	RPN_SHR			= 0x41,
+	RPN_USHR		= 0x42,
 
 	RPN_BANK_SYM		= 0x50,
 	RPN_BANK_SECT		= 0x51,
--- a/include/opmath.h
+++ b/include/opmath.h
@@ -16,5 +16,6 @@
 int32_t op_exponent(int32_t base, uint32_t power);
 int32_t op_shift_left(int32_t value, int32_t amount);
 int32_t op_shift_right(int32_t value, int32_t amount);
+int32_t op_shift_right_unsigned(int32_t value, int32_t amount);
 
 #endif /* RGBDS_OP_MATH_H */
--- a/src/asm/lexer.c
+++ b/src/asm/lexer.c
@@ -1890,7 +1890,7 @@
 				return T_OP_LOGICLT;
 			}
 
-		case '>': /* Either >>=, GT, GTE, or right shift */
+		case '>': /* Either >>=, GT, GTE, or either kind of right shift */
 			switch (peek()) {
 			case '=':
 				shiftChar();
@@ -1897,11 +1897,16 @@
 				return T_OP_LOGICGE;
 			case '>':
 				shiftChar();
-				if (peek() == '=') {
+				switch (peek()) {
+				case '=':
 					shiftChar();
 					return T_POP_SHREQ;
+				case '>':
+					shiftChar();
+					return T_OP_USHR;
+				default:
+					return T_OP_SHR;
 				}
-				return T_OP_SHR;
 			default:
 				return T_OP_LOGICGT;
 			}
--- a/src/asm/parser.y
+++ b/src/asm/parser.y
@@ -534,7 +534,7 @@
 %token	T_OP_LOGICNE "!=" T_OP_LOGICEQU "=="
 %token	T_OP_ADD "+" T_OP_SUB "-"
 %token	T_OP_OR "|" T_OP_XOR "^" T_OP_AND "&"
-%token	T_OP_SHL "<<" T_OP_SHR ">>"
+%token	T_OP_SHL "<<" T_OP_SHR ">>" T_OP_USHR ">>>"
 %token	T_OP_MUL "*" T_OP_DIV "/" T_OP_MOD "%"
 %token	T_OP_NOT "~"
 %left	T_OP_LOGICOR
@@ -542,7 +542,7 @@
 %left	T_OP_LOGICGT T_OP_LOGICLT T_OP_LOGICGE T_OP_LOGICLE T_OP_LOGICNE T_OP_LOGICEQU
 %left	T_OP_ADD T_OP_SUB
 %left	T_OP_OR T_OP_XOR T_OP_AND
-%left	T_OP_SHL T_OP_SHR
+%left	T_OP_SHL T_OP_SHR T_OP_USHR
 %left	T_OP_MUL T_OP_DIV T_OP_MOD
 
 %precedence	NEG /* negation -- unary minus */
@@ -1476,6 +1476,9 @@
 		}
 		| relocexpr T_OP_SHR relocexpr {
 			rpn_BinaryOp(RPN_SHR, &$$, &$1, &$3);
+		}
+		| relocexpr T_OP_USHR relocexpr {
+			rpn_BinaryOp(RPN_USHR, &$$, &$1, &$3);
 		}
 		| relocexpr T_OP_MUL relocexpr {
 			rpn_BinaryOp(RPN_MUL, &$$, &$1, &$3);
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -251,7 +251,9 @@
 .It Li ** Ta Exponent
 .It Li ~ + - Ta Unary complement/plus/minus
 .It Li * / % Ta Multiply/divide/modulo
-.It Li << >> Ta Shift left/right
+.It Li << Ta Shift left
+.It Li >> Ta Signed shift right (sign-extension)
+.It Li >>> Ta Unsigned shift right (zero-extension)
 .It Li & \&| ^ Ta Binary and/or/xor
 .It Li + - Ta Add/subtract
 .It Li != == <= >= < > Ta Comparison
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -421,6 +421,19 @@
 
 			expr->val = op_shift_right(src1->val, src2->val);
 			break;
+		case RPN_USHR:
+			if (src2->val < 0)
+				warning(WARNING_SHIFT_AMOUNT,
+					"Shifting right by negative amount %" PRId32 "\n",
+					src2->val);
+
+			if (src2->val >= 32)
+				warning(WARNING_SHIFT_AMOUNT,
+					"Shifting right by large amount %" PRId32 "\n",
+					src2->val);
+
+			expr->val = op_shift_right_unsigned(src1->val, src2->val);
+			break;
 		case RPN_MUL:
 			expr->val = uleft * uright;
 			break;
--- a/src/link/patch.c
+++ b/src/link/patch.c
@@ -265,6 +265,10 @@
 			value = popRPN();
 			value = op_shift_right(popRPN(), value);
 			break;
+		case RPN_USHR:
+			value = popRPN();
+			value = op_shift_right_unsigned(popRPN(), value);
+			break;
 
 		case RPN_BANK_SYM:
 			value = 0;
--- a/src/opmath.c
+++ b/src/opmath.c
@@ -86,3 +86,18 @@
 	// undefined, so use a left shift manually sign-extended
 	return ((uint32_t)value >> amount) | amount_high_bits;
 }
+
+int32_t op_shift_right_unsigned(int32_t value, int32_t amount)
+{
+	// Repeat the easy cases here to avoid INT_MIN funny business
+	if (amount == 0)
+		return value;
+	if (value == 0 || amount <= -32)
+		return 0;
+	if (amount > 31)
+		return (value < 0) ? -1 : 0;
+	if (amount < 0)
+		return op_shift_left(value, -amount);
+
+	return (uint32_t)value >> amount;
+}
--- a/src/rgbds.5
+++ b/src/rgbds.5
@@ -241,6 +241,7 @@
 .It Li $35 Ta Li <= comparison
 .It Li $40 Ta Li << operator
 .It Li $41 Ta Li >> operator
+.It Li $42 Ta Li >>> operator
 .It Li $50 Ta Li BANK(symbol) ,
 a
 .Ar LONG
--- a/test/asm/shift.asm
+++ b/test/asm/shift.asm
@@ -1,6 +1,6 @@
 macro test
 	; Test the rpn system, as well as the linker...
-	DEF expr EQUS STRRPL(STRRPL("\1 + zero)", "<<", "<< ("), ">>", ">> (")
+	DEF expr EQUS STRRPL(STRRPL("\1 + zero)", "<< ", "<< ("), ">> ", ">> (")
 	dl expr
 	PURGE expr
 
@@ -23,6 +23,9 @@
 	test -4 >> 1
 	test -4 >> 2
 	test -1 >> -9001
+
+	test $DEADBEEF >> 1
+	test $DEADBEEF >>> 1
 
 SECTION "Zero", ROM0[0]
 zero:
--- a/test/asm/shift.err
+++ b/test/asm/shift.err
@@ -24,3 +24,5 @@
     Shifting right negative value -1
 warning: shift.asm(25) -> shift.asm::test(8): [-Wshift-amount]
     Shifting right by negative amount -9001
+warning: shift.asm(27) -> shift.asm::test(8): [-Wshift]
+    Shifting right negative value -559038737
--- a/test/asm/shift.out
+++ b/test/asm/shift.out
@@ -10,3 +10,5 @@
 -4 >> 1 = $FFFFFFFE
 -4 >> 2 = $FFFFFFFF
 -1 >> -9001 = $0
+$DEADBEEF >> 1 = $EF56DF77
+$DEADBEEF >>> 1 = $6F56DF77
binary files a/test/asm/shift.out.bin b/test/asm/shift.out.bin differ