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;
+ }
}