shithub: rgbds

Download patch

ref: f9c25608e90629898373c29fc99007189604854b
parent: 9fb9e63554aa536c3028f59e349f9663e6c22c15
author: ISSOtm <[email protected]>
date: Mon Jan 20 12:05:49 EST 2020

Ignore RPN strings when their value is known

--- a/src/asm/output.c
+++ b/src/asm/output.c
@@ -861,14 +861,25 @@
 {
 	checkcodesection();
 	checksectionoverflow(1);
+	if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) {
+		pCurrentSection->tData[nPC] = 0;
+		createpatch(PATCHTYPE_JR, expr);
+		pCurrentSection->nPC++;
+		nPC++;
+		pPCSymbol->nValue++;
+	} else {
+		/* Target is relative to the byte *after* the operand */
+		uint16_t address = pCurrentSection->nOrg + nPC + 1;
+		/* The offset wraps (jump from ROM to HRAM, for loopexample) */
+		int16_t offset = expr->nVal - address;
 
-	/* Always let the linker calculate the offset. */
-	pCurrentSection->tData[nPC] = 0;
-	createpatch(PATCHTYPE_JR, expr);
-	pCurrentSection->nPC++;
-	nPC++;
-	pPCSymbol->nValue++;
-
+		if (offset < -128 || offset > 127) {
+			yyerror("jr target out of reach (expected -129 < %d < 128)", offset);
+			out_AbsByte(0);
+		} else {
+			out_AbsByte(offset);
+		}
+	}
 	rpn_Free(expr);
 }
 
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -100,11 +100,7 @@
  */
 void rpn_Number(struct Expression *expr, uint32_t i)
 {
-	uint8_t bytes[] = {RPN_CONST, i, i >> 8, i >> 16, i >> 24};
-
 	rpn_Init(expr);
-	expr->nRPNPatchSize += sizeof(bytes);
-	memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
 	expr->nVal = i;
 }
 
@@ -203,23 +199,37 @@
 void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
 {
 	*expr = *src;
-	expr->nRPNPatchSize++;
-	*reserveSpace(expr, 1) = RPN_HRAM;
+
+	if (rpn_isKnown(expr)) {
+		/* TODO */
+	} else {
+		expr->nRPNPatchSize++;
+		*reserveSpace(expr, 1) = RPN_HRAM;
+	}
 }
 
 void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
 {
 	*expr = *src;
-	*reserveSpace(expr, 1) = RPN_RST;
-	expr->nRPNPatchSize++;
+
+	if (rpn_isKnown(expr)) {
+		/* TODO */
+	} else {
+		expr->nRPNPatchSize++;
+		*reserveSpace(expr, 1) = RPN_RST;
+	}
 }
 
 void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
 {
 	*expr = *src;
-	expr->nVal = !expr->nVal;
-	expr->nRPNPatchSize++;
-	*reserveSpace(expr, 1) = RPN_LOGUNNOT;
+
+	if (rpn_isKnown(expr)) {
+		expr->nVal = !expr->nVal;
+	} else {
+		expr->nRPNPatchSize++;
+		*reserveSpace(expr, 1) = RPN_LOGUNNOT;
+	}
 }
 
 static int32_t shift(int32_t shiftee, int32_t amount)
@@ -267,139 +277,157 @@
 void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
 		  const struct Expression *src1, const struct Expression *src2)
 {
-	assert(src1->tRPN != NULL && src2->tRPN != NULL);
+	/* First, check if the expression is known */
+	expr->isKnown = src1->isKnown && src2->isKnown;
+	if (expr->isKnown) {
+		/* If both expressions are known, just compute the value */
+		uint32_t uleft = src1->nVal, uright = src2->nVal;
 
-	uint32_t len = src1->nRPNLength + src2->nRPNLength;
+		switch (op) {
+		case RPN_LOGOR:
+			expr->nVal = src1->nVal || src2->nVal;
+			break;
+		case RPN_LOGAND:
+			expr->nVal = src1->nVal && src2->nVal;
+			break;
+		case RPN_LOGEQ:
+			expr->nVal = src1->nVal == src2->nVal;
+			break;
+		case RPN_LOGGT:
+			expr->nVal = src1->nVal > src2->nVal;
+			break;
+		case RPN_LOGLT:
+			expr->nVal = src1->nVal < src2->nVal;
+			break;
+		case RPN_LOGGE:
+			expr->nVal = src1->nVal >= src2->nVal;
+			break;
+		case RPN_LOGLE:
+			expr->nVal = src1->nVal <= src2->nVal;
+			break;
+		case RPN_LOGNE:
+			expr->nVal = src1->nVal != src2->nVal;
+			break;
+		case RPN_ADD:
+			expr->nVal = uleft + uright;
+			break;
+		case RPN_SUB:
+			expr->nVal = uleft - uright;
+			break;
+		case RPN_XOR:
+			expr->nVal = src1->nVal ^ src2->nVal;
+			break;
+		case RPN_OR:
+			expr->nVal = src1->nVal | src2->nVal;
+			break;
+		case RPN_AND:
+			expr->nVal = src1->nVal & src2->nVal;
+			break;
+		case RPN_SHL:
+			if (expr->isKnown) {
+				if (src2->nVal < 0)
+					warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d",
+						src2->nVal);
 
-	if (len > MAXRPNLEN)
-		fatalerror("RPN expression is too large");
+				expr->nVal = shift(src1->nVal, src2->nVal);
+			}
+			break;
+		case RPN_SHR:
+			if (expr->isKnown) {
+				if (src2->nVal < 0)
+					warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d",
+						src2->nVal);
 
-	expr->nVal = 0;
-	expr->tRPN = src1->tRPN;
+				expr->nVal = shift(src1->nVal, -src2->nVal);
+			}
+			break;
+		case RPN_MUL:
+			expr->nVal = uleft * uright;
+			break;
+		case RPN_DIV:
+			if (expr->isKnown) {
+				if (src2->nVal == 0)
+					fatalerror("Division by zero");
 
-	if (src1->nRPNCapacity >= len) {
-		expr->nRPNCapacity = src1->nRPNCapacity;
-	} else {
-		uint32_t cap1 = src1->nRPNCapacity;
-		uint32_t cap2 = src2->nRPNCapacity;
-		uint32_t cap = (cap1 > cap2) ? cap1 : cap2;
+				if (src1->nVal == INT32_MIN
+				 && src2->nVal == -1) {
+					warning(WARNING_DIV, "Division of min value by -1");
+					expr->nVal = INT32_MIN;
+				} else {
+					expr->nVal = src1->nVal / src2->nVal;
+				}
+			}
+			break;
+		case RPN_MOD:
+			if (expr->isKnown) {
+				if (src2->nVal == 0)
+					fatalerror("Division by zero");
 
-		if (len > cap)
-			cap = (cap <= MAXRPNLEN / 2) ? cap * 2 : MAXRPNLEN;
+				if (src1->nVal == INT32_MIN && src2->nVal == -1)
+					expr->nVal = 0;
+				else
+					expr->nVal = src1->nVal % src2->nVal;
+			}
+			break;
 
-		expr->nRPNCapacity = cap;
-		expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
-		if (expr->tRPN == NULL)
-			fatalerror("No memory for RPN expression");
-	}
+		case RPN_UNSUB:
+		case RPN_UNNOT:
+		case RPN_LOGUNNOT:
+		case RPN_BANK_SYM:
+		case RPN_BANK_SECT:
+		case RPN_BANK_SELF:
+		case RPN_HRAM:
+		case RPN_RST:
+		case RPN_CONST:
+		case RPN_SYM:
+			fatalerror("%d is no binary operator", op);
+		}
 
-	memcpy(expr->tRPN + src1->nRPNLength, src2->tRPN, src2->nRPNLength);
-	free(src2->tRPN);
+	/* TODO: under some conditions, the expression will still be known */
 
-	expr->nRPNOut = 0; // FIXME: is this necessary?
-	expr->isKnown = src1->isKnown && src2->isKnown;
-	expr->nRPNLength = len;
-	expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize + 1;
-	*reserveSpace(expr, 1) = op;
+	} else {
+		/* If it's not known, start computing the RPN expression */
 
-	switch (op) {
-	case RPN_LOGOR:
-		expr->nVal = src1->nVal || src2->nVal;
-		break;
-	case RPN_LOGAND:
-		expr->nVal = src1->nVal && src2->nVal;
-		break;
-	case RPN_LOGEQ:
-		expr->nVal = src1->nVal == src2->nVal;
-		break;
-	case RPN_LOGGT:
-		expr->nVal = src1->nVal > src2->nVal;
-		break;
-	case RPN_LOGLT:
-		expr->nVal = src1->nVal < src2->nVal;
-		break;
-	case RPN_LOGGE:
-		expr->nVal = src1->nVal >= src2->nVal;
-		break;
-	case RPN_LOGLE:
-		expr->nVal = src1->nVal <= src2->nVal;
-		break;
-	case RPN_LOGNE:
-		expr->nVal = src1->nVal != src2->nVal;
-		break;
-	case RPN_ADD:
-		expr->nVal = (uint32_t)src1->nVal + (uint32_t)src2->nVal;
-		break;
-	case RPN_SUB:
-		// FIXME: under certain conditions, this might be actually known
-		expr->nVal = (uint32_t)src1->nVal - (uint32_t)src2->nVal;
-		break;
-	case RPN_XOR:
-		expr->nVal = src1->nVal ^ src2->nVal;
-		break;
-	case RPN_OR:
-		expr->nVal = src1->nVal | src2->nVal;
-		break;
-	case RPN_AND:
-		expr->nVal = src1->nVal & src2->nVal;
-		break;
-	case RPN_SHL:
-		if (expr->isKnown) {
-			if (src2->nVal < 0)
-				warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d",
-					src2->nVal);
-
-			expr->nVal = shift(src1->nVal, src2->nVal);
+		/* Convert the left-hand expression if it's constant */
+		if (src1->isKnown) {
+			uint8_t bytes[] = {RPN_CONST, src1->nVal,
+					   src1->nVal >> 8, src1->nVal >> 16,
+					   src1->nVal >> 24};
+			expr->nRPNPatchSize = sizeof(bytes);
+			expr->tRPN = NULL;
+			expr->nRPNCapacity = 0;
+			expr->nRPNLength = 0;
+			memcpy(reserveSpace(expr, sizeof(bytes)), bytes,
+			       sizeof(bytes));
+		} else {
+			/* Otherwise just reuse its RPN buffer */
+			expr->nRPNPatchSize = src1->nRPNPatchSize;
+			expr->tRPN = src1->tRPN;
+			expr->nRPNCapacity = src1->nRPNCapacity;
+			expr->nRPNLength = src1->nRPNLength;
 		}
-		break;
-	case RPN_SHR:
-		if (expr->isKnown) {
-			if (src2->nVal < 0)
-				warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d",
-					src2->nVal);
 
-			expr->nVal = shift(src1->nVal, -src2->nVal);
-		}
-		break;
-	case RPN_MUL:
-		expr->nVal = (uint32_t)src1->nVal * (uint32_t)src2->nVal;
-		break;
-	case RPN_DIV:
-		if (expr->isKnown) {
-			if (src2->nVal == 0)
-				fatalerror("Division by zero");
+		/* Now, merge the right expression into the left one */
+		uint8_t *ptr = src2->tRPN; /* Pointer to the right RPN */
+		uint32_t len = src2->nRPNLength; /* Size of the right RPN */
+		uint32_t patchSize = src2->nRPNPatchSize;
 
-			if (src1->nVal == INT32_MIN && src2->nVal == -1) {
-				warning(WARNING_DIV, "Division of min value by -1");
-				expr->nVal = INT32_MIN;
-			} else {
-				expr->nVal = src1->nVal / src2->nVal;
-			}
+		/* If the right expression is constant, merge a shim instead */
+		uint8_t bytes[] = {RPN_CONST, src2->nVal, src2->nVal >> 8,
+				   src2->nVal >> 16, src2->nVal >> 24};
+		if (src2->isKnown) {
+			ptr = bytes;
+			len = sizeof(bytes);
+			patchSize = sizeof(bytes);
 		}
-		break;
-	case RPN_MOD:
-		if (expr->isKnown) {
-			if (src2->nVal == 0)
-				fatalerror("Division by zero");
+		/* Copy the right RPN and append the operator */
+		uint8_t *buf = reserveSpace(expr, len + 1);
 
-			if (src1->nVal == INT32_MIN && src2->nVal == -1)
-				expr->nVal = 0;
-			else
-				expr->nVal = src1->nVal % src2->nVal;
-		}
-		break;
+		memcpy(buf, ptr, len);
+		buf[len] = op;
 
-	case RPN_UNSUB:
-	case RPN_UNNOT:
-	case RPN_LOGUNNOT:
-	case RPN_BANK_SYM:
-	case RPN_BANK_SECT:
-	case RPN_BANK_SELF:
-	case RPN_HRAM:
-	case RPN_RST:
-	case RPN_CONST:
-	case RPN_SYM:
-		fatalerror("%d is no binary operator", op);
+		free(src2->tRPN); /* If there was none, this is `free(NULL)` */
+		expr->nRPNPatchSize += patchSize + 1;
 	}
 }
 
@@ -407,13 +435,14 @@
 {
 	*expr = *src;
 
-	expr->nVal = (expr->nVal >> 8) & 0xFF;
-
-	uint8_t bytes[] = {RPN_CONST,    8, 0, 0, 0, RPN_SHR,
-			   RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
-	expr->nRPNPatchSize += sizeof(bytes);
-
-	memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
+	if (rpn_isKnown(expr)) {
+		expr->nVal = expr->nVal >> 8 & 0xFF;
+	} else {
+		uint8_t bytes[] = {RPN_CONST,    8, 0, 0, 0, RPN_SHR,
+				   RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
+		expr->nRPNPatchSize += sizeof(bytes);
+		memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
+	}
 }
 
 void rpn_LOW(struct Expression *expr, const struct Expression *src)
@@ -420,26 +449,36 @@
 {
 	*expr = *src;
 
-	expr->nVal = expr->nVal & 0xFF;
+	if (rpn_isKnown(expr)) {
+		expr->nVal = expr->nVal & 0xFF;
+	} else {
+		uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
 
-	uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
-
-	expr->nRPNPatchSize += sizeof(bytes);
-	memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
+		expr->nRPNPatchSize += sizeof(bytes);
+		memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
+	}
 }
 
 void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
 {
 	*expr = *src;
-	expr->nVal = -(uint32_t)expr->nVal;
-	expr->nRPNPatchSize++;
-	*reserveSpace(expr, 1) = RPN_UNSUB;
+
+	if (rpn_isKnown(expr)) {
+		expr->nVal = -(uint32_t)expr->nVal;
+	} else {
+		expr->nRPNPatchSize++;
+		*reserveSpace(expr, 1) = RPN_UNSUB;
+	}
 }
 
 void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
 {
 	*expr = *src;
-	expr->nVal = ~expr->nVal;
-	expr->nRPNPatchSize++;
-	*reserveSpace(expr, 1) = RPN_UNNOT;
+
+	if (rpn_isKnown(expr)) {
+		expr->nVal = ~expr->nVal;
+	} else {
+		expr->nRPNPatchSize++;
+		*reserveSpace(expr, 1) = RPN_UNNOT;
+	}
 }