mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Ignore RPN strings when their value is known
This commit is contained in:
@@ -861,14 +861,25 @@ void out_PCRelByte(struct Expression *expr)
|
|||||||
{
|
{
|
||||||
checkcodesection();
|
checkcodesection();
|
||||||
checksectionoverflow(1);
|
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. */
|
if (offset < -128 || offset > 127) {
|
||||||
pCurrentSection->tData[nPC] = 0;
|
yyerror("jr target out of reach (expected -129 < %d < 128)", offset);
|
||||||
createpatch(PATCHTYPE_JR, expr);
|
out_AbsByte(0);
|
||||||
pCurrentSection->nPC++;
|
} else {
|
||||||
nPC++;
|
out_AbsByte(offset);
|
||||||
pPCSymbol->nValue++;
|
}
|
||||||
|
}
|
||||||
rpn_Free(expr);
|
rpn_Free(expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
351
src/asm/rpn.c
351
src/asm/rpn.c
@@ -100,11 +100,7 @@ bool rpn_isKnown(const struct Expression *expr)
|
|||||||
*/
|
*/
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i)
|
void rpn_Number(struct Expression *expr, uint32_t i)
|
||||||
{
|
{
|
||||||
uint8_t bytes[] = {RPN_CONST, i, i >> 8, i >> 16, i >> 24};
|
|
||||||
|
|
||||||
rpn_Init(expr);
|
rpn_Init(expr);
|
||||||
expr->nRPNPatchSize += sizeof(bytes);
|
|
||||||
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
|
|
||||||
expr->nVal = i;
|
expr->nVal = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,23 +199,37 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName)
|
|||||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *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)
|
void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *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)
|
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->nVal = !expr->nVal;
|
|
||||||
expr->nRPNPatchSize++;
|
if (rpn_isKnown(expr)) {
|
||||||
*reserveSpace(expr, 1) = RPN_LOGUNNOT;
|
expr->nVal = !expr->nVal;
|
||||||
|
} else {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_LOGUNNOT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t shift(int32_t shiftee, int32_t amount)
|
static int32_t shift(int32_t shiftee, int32_t amount)
|
||||||
@@ -267,139 +277,157 @@ static int32_t shift(int32_t shiftee, int32_t amount)
|
|||||||
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||||
const struct Expression *src1, const struct Expression *src2)
|
const struct Expression *src1, const struct Expression *src2)
|
||||||
{
|
{
|
||||||
assert(src1->tRPN != NULL && src2->tRPN != NULL);
|
/* First, check if the expression is known */
|
||||||
|
|
||||||
uint32_t len = src1->nRPNLength + src2->nRPNLength;
|
|
||||||
|
|
||||||
if (len > MAXRPNLEN)
|
|
||||||
fatalerror("RPN expression is too large");
|
|
||||||
|
|
||||||
expr->nVal = 0;
|
|
||||||
expr->tRPN = src1->tRPN;
|
|
||||||
|
|
||||||
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 (len > cap)
|
|
||||||
cap = (cap <= MAXRPNLEN / 2) ? cap * 2 : MAXRPNLEN;
|
|
||||||
|
|
||||||
expr->nRPNCapacity = cap;
|
|
||||||
expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
|
|
||||||
if (expr->tRPN == NULL)
|
|
||||||
fatalerror("No memory for RPN expression");
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(expr->tRPN + src1->nRPNLength, src2->tRPN, src2->nRPNLength);
|
|
||||||
free(src2->tRPN);
|
|
||||||
|
|
||||||
expr->nRPNOut = 0; // FIXME: is this necessary?
|
|
||||||
expr->isKnown = src1->isKnown && src2->isKnown;
|
expr->isKnown = src1->isKnown && src2->isKnown;
|
||||||
expr->nRPNLength = len;
|
if (expr->isKnown) {
|
||||||
expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize + 1;
|
/* If both expressions are known, just compute the value */
|
||||||
*reserveSpace(expr, 1) = op;
|
uint32_t uleft = src1->nVal, uright = src2->nVal;
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case RPN_LOGOR:
|
case RPN_LOGOR:
|
||||||
expr->nVal = src1->nVal || src2->nVal;
|
expr->nVal = src1->nVal || src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_LOGAND:
|
case RPN_LOGAND:
|
||||||
expr->nVal = src1->nVal && src2->nVal;
|
expr->nVal = src1->nVal && src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_LOGEQ:
|
case RPN_LOGEQ:
|
||||||
expr->nVal = src1->nVal == src2->nVal;
|
expr->nVal = src1->nVal == src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_LOGGT:
|
case RPN_LOGGT:
|
||||||
expr->nVal = src1->nVal > src2->nVal;
|
expr->nVal = src1->nVal > src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_LOGLT:
|
case RPN_LOGLT:
|
||||||
expr->nVal = src1->nVal < src2->nVal;
|
expr->nVal = src1->nVal < src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_LOGGE:
|
case RPN_LOGGE:
|
||||||
expr->nVal = src1->nVal >= src2->nVal;
|
expr->nVal = src1->nVal >= src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_LOGLE:
|
case RPN_LOGLE:
|
||||||
expr->nVal = src1->nVal <= src2->nVal;
|
expr->nVal = src1->nVal <= src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_LOGNE:
|
case RPN_LOGNE:
|
||||||
expr->nVal = src1->nVal != src2->nVal;
|
expr->nVal = src1->nVal != src2->nVal;
|
||||||
break;
|
break;
|
||||||
case RPN_ADD:
|
case RPN_ADD:
|
||||||
expr->nVal = (uint32_t)src1->nVal + (uint32_t)src2->nVal;
|
expr->nVal = uleft + uright;
|
||||||
break;
|
break;
|
||||||
case RPN_SUB:
|
case RPN_SUB:
|
||||||
// FIXME: under certain conditions, this might be actually known
|
expr->nVal = uleft - uright;
|
||||||
expr->nVal = (uint32_t)src1->nVal - (uint32_t)src2->nVal;
|
break;
|
||||||
break;
|
case RPN_XOR:
|
||||||
case RPN_XOR:
|
expr->nVal = src1->nVal ^ src2->nVal;
|
||||||
expr->nVal = src1->nVal ^ src2->nVal;
|
break;
|
||||||
break;
|
case RPN_OR:
|
||||||
case RPN_OR:
|
expr->nVal = src1->nVal | src2->nVal;
|
||||||
expr->nVal = src1->nVal | src2->nVal;
|
break;
|
||||||
break;
|
case RPN_AND:
|
||||||
case RPN_AND:
|
expr->nVal = src1->nVal & src2->nVal;
|
||||||
expr->nVal = src1->nVal & src2->nVal;
|
break;
|
||||||
break;
|
case RPN_SHL:
|
||||||
case RPN_SHL:
|
if (expr->isKnown) {
|
||||||
if (expr->isKnown) {
|
if (src2->nVal < 0)
|
||||||
if (src2->nVal < 0)
|
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d",
|
||||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d",
|
src2->nVal);
|
||||||
src2->nVal);
|
|
||||||
|
|
||||||
expr->nVal = shift(src1->nVal, src2->nVal);
|
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 = 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");
|
|
||||||
|
|
||||||
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;
|
||||||
break;
|
case RPN_SHR:
|
||||||
case RPN_MOD:
|
if (expr->isKnown) {
|
||||||
if (expr->isKnown) {
|
if (src2->nVal < 0)
|
||||||
if (src2->nVal == 0)
|
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d",
|
||||||
fatalerror("Division by zero");
|
src2->nVal);
|
||||||
|
|
||||||
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
expr->nVal = shift(src1->nVal, -src2->nVal);
|
||||||
expr->nVal = 0;
|
}
|
||||||
else
|
break;
|
||||||
expr->nVal = src1->nVal % src2->nVal;
|
case RPN_MUL:
|
||||||
}
|
expr->nVal = uleft * uright;
|
||||||
break;
|
break;
|
||||||
|
case RPN_DIV:
|
||||||
|
if (expr->isKnown) {
|
||||||
|
if (src2->nVal == 0)
|
||||||
|
fatalerror("Division by zero");
|
||||||
|
|
||||||
case RPN_UNSUB:
|
if (src1->nVal == INT32_MIN
|
||||||
case RPN_UNNOT:
|
&& src2->nVal == -1) {
|
||||||
case RPN_LOGUNNOT:
|
warning(WARNING_DIV, "Division of min value by -1");
|
||||||
case RPN_BANK_SYM:
|
expr->nVal = INT32_MIN;
|
||||||
case RPN_BANK_SECT:
|
} else {
|
||||||
case RPN_BANK_SELF:
|
expr->nVal = src1->nVal / src2->nVal;
|
||||||
case RPN_HRAM:
|
}
|
||||||
case RPN_RST:
|
}
|
||||||
case RPN_CONST:
|
break;
|
||||||
case RPN_SYM:
|
case RPN_MOD:
|
||||||
fatalerror("%d is no binary operator", op);
|
if (expr->isKnown) {
|
||||||
|
if (src2->nVal == 0)
|
||||||
|
fatalerror("Division by zero");
|
||||||
|
|
||||||
|
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
||||||
|
expr->nVal = 0;
|
||||||
|
else
|
||||||
|
expr->nVal = src1->nVal % src2->nVal;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: under some conditions, the expression will still be known */
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* If it's not known, start computing the RPN expression */
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 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);
|
||||||
|
}
|
||||||
|
/* Copy the right RPN and append the operator */
|
||||||
|
uint8_t *buf = reserveSpace(expr, len + 1);
|
||||||
|
|
||||||
|
memcpy(buf, ptr, len);
|
||||||
|
buf[len] = op;
|
||||||
|
|
||||||
|
free(src2->tRPN); /* If there was none, this is `free(NULL)` */
|
||||||
|
expr->nRPNPatchSize += patchSize + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,39 +435,50 @@ void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
|||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
|
|
||||||
expr->nVal = (expr->nVal >> 8) & 0xFF;
|
if (rpn_isKnown(expr)) {
|
||||||
|
expr->nVal = expr->nVal >> 8 & 0xFF;
|
||||||
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
|
} else {
|
||||||
RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
|
||||||
expr->nRPNPatchSize += sizeof(bytes);
|
RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
||||||
|
expr->nRPNPatchSize += sizeof(bytes);
|
||||||
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
|
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*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)
|
void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->nVal = -(uint32_t)expr->nVal;
|
|
||||||
expr->nRPNPatchSize++;
|
if (rpn_isKnown(expr)) {
|
||||||
*reserveSpace(expr, 1) = RPN_UNSUB;
|
expr->nVal = -(uint32_t)expr->nVal;
|
||||||
|
} else {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_UNSUB;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->nVal = ~expr->nVal;
|
|
||||||
expr->nRPNPatchSize++;
|
if (rpn_isKnown(expr)) {
|
||||||
*reserveSpace(expr, 1) = RPN_UNNOT;
|
expr->nVal = ~expr->nVal;
|
||||||
|
} else {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_UNNOT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user