From 0a04904b75d4a0944aa93327c0b1c5e1ae2c0eae Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 13:22:14 +0100 Subject: [PATCH] Refactor RPN binary expressions into a single func This mirrors what the constexpr evaluator is doing, and removes a lot of code shared between all of them --- include/asm/rpn.h | 41 +---- src/asm/asmy.y | 36 ++-- src/asm/rpn.c | 448 ++++++++++++++++++---------------------------- 3 files changed, 195 insertions(+), 330 deletions(-) diff --git a/include/asm/rpn.h b/include/asm/rpn.h index 8ee9e3f1..1b0a75b6 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -11,6 +11,8 @@ #include +#include "linkdefs.h" + #define MAXRPNLEN 1048576 struct Expression { @@ -30,42 +32,9 @@ uint32_t rpn_isReloc(const struct Expression *expr); void rpn_Symbol(struct Expression *expr, char *tzSym); void rpn_Number(struct Expression *expr, uint32_t i); void rpn_LOGNOT(struct Expression *expr, const struct Expression *src); -void rpn_LOGOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGAND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGGT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGLT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGGE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGLE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_LOGNE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_ADD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_SUB(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_XOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_OR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_AND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_SHL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_SHR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_MUL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_DIV(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); -void rpn_MOD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2); +void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, + const struct Expression *src1, + const struct Expression *src2); void rpn_HIGH(struct Expression *expr, const struct Expression *src); void rpn_LOW(struct Expression *expr, const struct Expression *src); void rpn_UNNEG(struct Expression *expr, const struct Expression *src); diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 11169634..3f417eab 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -1223,24 +1223,24 @@ relocconst : T_ID rpn_Number(&$$, r); } | T_OP_LOGICNOT relocconst %prec NEG { rpn_LOGNOT(&$$, &$2); } - | relocconst T_OP_LOGICOR relocconst { rpn_LOGOR(&$$, &$1, &$3); } - | relocconst T_OP_LOGICAND relocconst { rpn_LOGAND(&$$, &$1, &$3); } - | relocconst T_OP_LOGICEQU relocconst { rpn_LOGEQU(&$$, &$1, &$3); } - | relocconst T_OP_LOGICGT relocconst { rpn_LOGGT(&$$, &$1, &$3); } - | relocconst T_OP_LOGICLT relocconst { rpn_LOGLT(&$$, &$1, &$3); } - | relocconst T_OP_LOGICGE relocconst { rpn_LOGGE(&$$, &$1, &$3); } - | relocconst T_OP_LOGICLE relocconst { rpn_LOGLE(&$$, &$1, &$3); } - | relocconst T_OP_LOGICNE relocconst { rpn_LOGNE(&$$, &$1, &$3); } - | relocconst T_OP_ADD relocconst { rpn_ADD(&$$, &$1, &$3); } - | relocconst T_OP_SUB relocconst { rpn_SUB(&$$, &$1, &$3); } - | relocconst T_OP_XOR relocconst { rpn_XOR(&$$, &$1, &$3); } - | relocconst T_OP_OR relocconst { rpn_OR(&$$, &$1, &$3); } - | relocconst T_OP_AND relocconst { rpn_AND(&$$, &$1, &$3); } - | relocconst T_OP_SHL relocconst { rpn_SHL(&$$, &$1, &$3); } - | relocconst T_OP_SHR relocconst { rpn_SHR(&$$, &$1, &$3); } - | relocconst T_OP_MUL relocconst { rpn_MUL(&$$, &$1, &$3); } - | relocconst T_OP_DIV relocconst { rpn_DIV(&$$, &$1, &$3); } - | relocconst T_OP_MOD relocconst { rpn_MOD(&$$, &$1, &$3); } + | relocconst T_OP_LOGICOR relocconst { rpn_BinaryOp(RPN_LOGOR, &$$, &$1, &$3); } + | relocconst T_OP_LOGICAND relocconst { rpn_BinaryOp(RPN_LOGAND, &$$, &$1, &$3); } + | relocconst T_OP_LOGICEQU relocconst { rpn_BinaryOp(RPN_LOGEQ, &$$, &$1, &$3); } + | relocconst T_OP_LOGICGT relocconst { rpn_BinaryOp(RPN_LOGGT, &$$, &$1, &$3); } + | relocconst T_OP_LOGICLT relocconst { rpn_BinaryOp(RPN_LOGLT, &$$, &$1, &$3); } + | relocconst T_OP_LOGICGE relocconst { rpn_BinaryOp(RPN_LOGGE, &$$, &$1, &$3); } + | relocconst T_OP_LOGICLE relocconst { rpn_BinaryOp(RPN_LOGLE, &$$, &$1, &$3); } + | relocconst T_OP_LOGICNE relocconst { rpn_BinaryOp(RPN_LOGNE, &$$, &$1, &$3); } + | relocconst T_OP_ADD relocconst { rpn_BinaryOp(RPN_ADD, &$$, &$1, &$3); } + | relocconst T_OP_SUB relocconst { rpn_BinaryOp(RPN_SUB, &$$, &$1, &$3); } + | relocconst T_OP_XOR relocconst { rpn_BinaryOp(RPN_XOR, &$$, &$1, &$3); } + | relocconst T_OP_OR relocconst { rpn_BinaryOp(RPN_OR, &$$, &$1, &$3); } + | relocconst T_OP_AND relocconst { rpn_BinaryOp(RPN_AND, &$$, &$1, &$3); } + | relocconst T_OP_SHL relocconst { rpn_BinaryOp(RPN_SHL, &$$, &$1, &$3); } + | relocconst T_OP_SHR relocconst { rpn_BinaryOp(RPN_SHR, &$$, &$1, &$3); } + | relocconst T_OP_MUL relocconst { rpn_BinaryOp(RPN_MUL, &$$, &$1, &$3); } + | relocconst T_OP_DIV relocconst { rpn_BinaryOp(RPN_DIV, &$$, &$1, &$3); } + | relocconst T_OP_MOD relocconst { rpn_BinaryOp(RPN_MOD, &$$, &$1, &$3); } | T_OP_ADD relocconst %prec NEG { $$ = $2; } | T_OP_SUB relocconst %prec NEG { rpn_UNNEG(&$$, &$2); } | T_OP_NOT relocconst %prec NEG { rpn_UNNOT(&$$, &$2); } diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 53e31956..2c93515a 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -22,46 +22,6 @@ #include "asm/output.h" #include "asm/warning.h" -#include "linkdefs.h" - -void mergetwoexpressions(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - assert(src1->tRPN != NULL && src2->tRPN != NULL); - - if (src1->nRPNLength + src2->nRPNLength > MAXRPNLEN) - fatalerror("RPN expression is too large"); - - uint32_t len = src1->nRPNLength + src2->nRPNLength; - - 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->nRPNLength = len; - expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize; - expr->nRPNOut = 0; - expr->isReloc = src1->isReloc || src2->isReloc; -} - /* * Add a byte to the RPN expression */ @@ -160,7 +120,7 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) struct Expression pc = *expr, offset; rpn_Number(&offset, nPCOffset); - rpn_SUB(expr, &pc, &offset); + rpn_BinaryOp(RPN_SUB, expr, &pc, &offset); } } else { rpn_Number(expr, sym_GetConstantValue(tzSym)); @@ -265,21 +225,181 @@ void rpn_LOGNOT(struct Expression *expr, const struct Expression *src) expr->nRPNPatchSize++; } -void rpn_LOGOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) +static int32_t shift(int32_t shiftee, int32_t amount) { - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal || src2->nVal); - pushbyte(expr, RPN_LOGOR); - expr->nRPNPatchSize++; + if (shiftee < 0) + warning(WARNING_SHIFT, "Shifting negative value %d", shiftee); + + if (amount >= 0) { + // Left shift + if (amount >= 32) { + warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %d", + amount); + return 0; + + } else { + /* + * Use unsigned to force a bitwise shift + * Casting back is OK because the types implement two's + * complement behavior + */ + return (uint32_t)shiftee << amount; + } + } else { + // Right shift + amount = -amount; + if (amount >= 32) { + warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %d", + amount); + return shiftee < 0 ? -1 : 0; + + } else if (shiftee >= 0) { + return shiftee >> amount; + + } else { + /* + * The C standard leaves shifting right negative values + * undefined, so use a left shift manually sign-extended + */ + return (uint32_t)shiftee >> amount + | -((uint32_t)1 << (32 - amount)); + } + } } -void rpn_LOGAND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) +void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, + const struct Expression *src1, const struct Expression *src2) { - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal && src2->nVal); - pushbyte(expr, RPN_LOGAND); + assert(src1->tRPN != NULL && src2->tRPN != NULL); + + if (src1->nRPNLength + src2->nRPNLength > MAXRPNLEN) + fatalerror("RPN expression is too large"); + + uint32_t len = src1->nRPNLength + src2->nRPNLength; + + 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->nRPNLength = len; + expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize; + expr->nRPNOut = 0; + expr->isReloc = src1->isReloc || src2->isReloc; + + 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: + 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 (src2->nVal < 0) + warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d", + src2->nVal); + + expr->nVal = shift(src1->nVal, src2->nVal); + break; + case RPN_SHR: + 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->isReloc) { + 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; + case RPN_MOD: + if (!expr->isReloc) { + 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); + } + + pushbyte(expr, op); expr->nRPNPatchSize++; } @@ -325,230 +445,6 @@ void rpn_LOW(struct Expression *expr, const struct Expression *src) expr->nRPNPatchSize += 6; } -void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal == src2->nVal); - pushbyte(expr, RPN_LOGEQ); - expr->nRPNPatchSize++; -} - -void rpn_LOGGT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal > src2->nVal); - pushbyte(expr, RPN_LOGGT); - expr->nRPNPatchSize++; -} - -void rpn_LOGLT(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal < src2->nVal); - pushbyte(expr, RPN_LOGLT); - expr->nRPNPatchSize++; -} - -void rpn_LOGGE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal >= src2->nVal); - pushbyte(expr, RPN_LOGGE); - expr->nRPNPatchSize++; -} - -void rpn_LOGLE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal <= src2->nVal); - pushbyte(expr, RPN_LOGLE); - expr->nRPNPatchSize++; -} - -void rpn_LOGNE(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal != src2->nVal); - pushbyte(expr, RPN_LOGNE); - expr->nRPNPatchSize++; -} - -void rpn_ADD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = ((uint32_t)src1->nVal + (uint32_t)src2->nVal); - pushbyte(expr, RPN_ADD); - expr->nRPNPatchSize++; -} - -void rpn_SUB(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = ((uint32_t)src1->nVal - (uint32_t)src2->nVal); - pushbyte(expr, RPN_SUB); - expr->nRPNPatchSize++; -} - -void rpn_XOR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal ^ src2->nVal); - pushbyte(expr, RPN_XOR); - expr->nRPNPatchSize++; -} - -void rpn_OR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal | src2->nVal); - pushbyte(expr, RPN_OR); - expr->nRPNPatchSize++; -} - -void rpn_AND(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = (src1->nVal & src2->nVal); - pushbyte(expr, RPN_AND); - expr->nRPNPatchSize++; -} - -static int32_t shift(int32_t shiftee, int32_t amount) -{ - if (shiftee < 0) - warning(WARNING_SHIFT, "Shifting negative value %d", shiftee); - - if (amount >= 0) { - // Left shift - if (amount >= 32) { - warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %d", - amount); - return 0; - - } else { - /* - * Use unsigned to force a bitwise shift - * Casting back is OK because the types implement two's - * complement behavior - */ - return (uint32_t)shiftee << amount; - } - } else { - // Right shift - amount = -amount; - if (amount >= 32) { - warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %d", - amount); - return shiftee < 0 ? -1 : 0; - - } else if (shiftee >= 0) { - return shiftee >> amount; - - } else { - /* - * The C standard leaves shifting right negative values - * undefined, so use a left shift manually sign-extended - */ - return (uint32_t)shiftee >> amount - | -((uint32_t)1 << (32 - amount)); - } - } -} - -void rpn_SHL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - - if (!expr->isReloc) { - if (src2->nVal < 0) - warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative value: %d", - src2->nVal); - - expr->nVal = shift(src1->nVal, src2->nVal); - } - - pushbyte(expr, RPN_SHL); - expr->nRPNPatchSize++; -} - -void rpn_SHR(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - - if (!expr->isReloc) { - if (src2->nVal < 0) - warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d", - src2->nVal); - - expr->nVal = shift(src1->nVal, -src2->nVal); - } - - pushbyte(expr, RPN_SHR); - expr->nRPNPatchSize++; -} - -void rpn_MUL(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - expr->nVal = ((uint32_t)src1->nVal * (uint32_t)src2->nVal); - pushbyte(expr, RPN_MUL); - expr->nRPNPatchSize++; -} - -void rpn_DIV(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - - if (!expr->isReloc) { - 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); - } - } - - pushbyte(expr, RPN_DIV); - expr->nRPNPatchSize++; -} - -void rpn_MOD(struct Expression *expr, const struct Expression *src1, - const struct Expression *src2) -{ - mergetwoexpressions(expr, src1, src2); - - if (!expr->isReloc) { - 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); - } - - pushbyte(expr, RPN_MOD); - expr->nRPNPatchSize++; -} - void rpn_UNNEG(struct Expression *expr, const struct Expression *src) { *expr = *src;