mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Refactor structs to use methods instead of functions (#1322)
This commit is contained in:
136
src/asm/rpn.cpp
136
src/asm/rpn.cpp
@@ -21,6 +21,16 @@
|
||||
|
||||
#include "opmath.hpp"
|
||||
|
||||
// Init a RPN expression
|
||||
static void initExpression(Expression *expr)
|
||||
{
|
||||
expr->reason = nullptr;
|
||||
expr->isKnown = true;
|
||||
expr->isSymbol = false;
|
||||
expr->rpn = nullptr;
|
||||
expr->rpnPatchSize = 0;
|
||||
}
|
||||
|
||||
// Makes an expression "not known", also setting its error message
|
||||
template<typename... Ts>
|
||||
static void makeUnknown(Expression *expr, Ts ...parts)
|
||||
@@ -46,28 +56,18 @@ static uint8_t *reserveSpace(Expression *expr, uint32_t size)
|
||||
return &(*expr->rpn)[curSize];
|
||||
}
|
||||
|
||||
// Init a RPN expression
|
||||
static void rpn_Init(Expression *expr)
|
||||
{
|
||||
expr->reason = nullptr;
|
||||
expr->isKnown = true;
|
||||
expr->isSymbol = false;
|
||||
expr->rpn = nullptr;
|
||||
expr->rpnPatchSize = 0;
|
||||
}
|
||||
|
||||
// Free the RPN expression
|
||||
void rpn_Free(Expression *expr)
|
||||
{
|
||||
delete expr->rpn;
|
||||
delete expr->reason;
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
}
|
||||
|
||||
// Add symbols, constants and operators to expression
|
||||
void rpn_Number(Expression *expr, uint32_t i)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
expr->val = i;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ void rpn_Symbol(Expression *expr, char const *symName)
|
||||
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
|
||||
error("PC has no value outside a section\n");
|
||||
rpn_Number(expr, 0);
|
||||
} else if (!sym || !sym_IsConstant(sym)) {
|
||||
rpn_Init(expr);
|
||||
} else if (!sym || !sym->isConstant()) {
|
||||
initExpression(expr);
|
||||
expr->isSymbol = true;
|
||||
|
||||
if (sym_IsPC(sym))
|
||||
@@ -100,7 +100,7 @@ void rpn_Symbol(Expression *expr, char const *symName)
|
||||
|
||||
void rpn_BankSelf(Expression *expr)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
if (!currentSection) {
|
||||
error("PC has no bank outside a section\n");
|
||||
@@ -124,22 +124,23 @@ void rpn_BankSymbol(Expression *expr, char const *symName)
|
||||
return;
|
||||
}
|
||||
|
||||
rpn_Init(expr);
|
||||
if (sym && !sym_IsLabel(sym)) {
|
||||
initExpression(expr);
|
||||
if (sym && !sym->isLabel()) {
|
||||
error("BANK argument must be a label\n");
|
||||
} else {
|
||||
sym = sym_Ref(symName);
|
||||
assert(sym); // If the symbol didn't exist, it should have been created
|
||||
|
||||
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != (uint32_t)-1) {
|
||||
if (sym->getSection() && sym->getSection()->bank != (uint32_t)-1) {
|
||||
// Symbol's section is known and bank is fixed
|
||||
expr->val = sym_GetSection(sym)->bank;
|
||||
expr->val = sym->getSection()->bank;
|
||||
} else {
|
||||
makeUnknown(expr, "\"", symName, "\"'s bank is not known");
|
||||
expr->rpnPatchSize += 5; // opcode + 4-byte sect ID
|
||||
|
||||
size_t nameLen = strlen(sym->name) + 1; // Room for NUL!
|
||||
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||
|
||||
*ptr++ = RPN_BANK_SYM;
|
||||
memcpy(ptr, sym->name, nameLen);
|
||||
}
|
||||
@@ -148,7 +149,7 @@ void rpn_BankSymbol(Expression *expr, char const *symName)
|
||||
|
||||
void rpn_BankSection(Expression *expr, char const *sectionName)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
Section *section = sect_FindSectionByName(sectionName);
|
||||
|
||||
@@ -168,11 +169,11 @@ void rpn_BankSection(Expression *expr, char const *sectionName)
|
||||
|
||||
void rpn_SizeOfSection(Expression *expr, char const *sectionName)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
Section *section = sect_FindSectionByName(sectionName);
|
||||
|
||||
if (section && sect_IsSizeKnown(section)) {
|
||||
if (section && section->isSizeKnown()) {
|
||||
expr->val = section->size;
|
||||
} else {
|
||||
makeUnknown(expr, "Section \"", sectionName, "\"'s size is not known");
|
||||
@@ -188,7 +189,7 @@ void rpn_SizeOfSection(Expression *expr, char const *sectionName)
|
||||
|
||||
void rpn_StartOfSection(Expression *expr, char const *sectionName)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
|
||||
Section *section = sect_FindSectionByName(sectionName);
|
||||
|
||||
@@ -208,7 +209,7 @@ void rpn_StartOfSection(Expression *expr, char const *sectionName)
|
||||
|
||||
void rpn_SizeOfSectionType(Expression *expr, enum SectionType type)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
makeUnknown(expr, "Section type's size is not known");
|
||||
|
||||
uint8_t *ptr = reserveSpace(expr, 2);
|
||||
@@ -220,7 +221,7 @@ void rpn_SizeOfSectionType(Expression *expr, enum SectionType type)
|
||||
|
||||
void rpn_StartOfSectionType(Expression *expr, enum SectionType type)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
initExpression(expr);
|
||||
makeUnknown(expr, "Section type's start is not known");
|
||||
|
||||
uint8_t *ptr = reserveSpace(expr, 2);
|
||||
@@ -235,7 +236,7 @@ void rpn_CheckHRAM(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (!rpn_isKnown(expr)) {
|
||||
if (!expr->isKnown) {
|
||||
expr->rpnPatchSize++;
|
||||
*reserveSpace(expr, 1) = RPN_HRAM;
|
||||
} else if (expr->val >= 0xFF00 && expr->val <= 0xFFFF) {
|
||||
@@ -250,7 +251,7 @@ void rpn_CheckRST(Expression *expr, const Expression *src)
|
||||
{
|
||||
*expr = *src;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
// A valid RST address must be masked with 0x38
|
||||
if (expr->val & ~0x38)
|
||||
error("Invalid address $%" PRIx32 " for RST\n", expr->val);
|
||||
@@ -268,7 +269,7 @@ void rpn_CheckNBit(Expression const *expr, uint8_t n)
|
||||
assert(n != 0); // That doesn't make sense
|
||||
assert(n < CHAR_BIT * sizeof(int)); // Otherwise `1 << n` is UB
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
int32_t val = expr->val;
|
||||
|
||||
if (val < -(1 << n) || val >= 1 << n)
|
||||
@@ -278,13 +279,13 @@ void rpn_CheckNBit(Expression const *expr, uint8_t n)
|
||||
}
|
||||
}
|
||||
|
||||
int32_t rpn_GetConstVal(Expression const *expr)
|
||||
int32_t Expression::getConstVal() const
|
||||
{
|
||||
if (!rpn_isKnown(expr)) {
|
||||
error("Expected constant expression: %s\n", expr->reason->c_str());
|
||||
if (!isKnown) {
|
||||
error("Expected constant expression: %s\n", reason->c_str());
|
||||
return 0;
|
||||
}
|
||||
return expr->val;
|
||||
return val;
|
||||
}
|
||||
|
||||
void rpn_LOGNOT(Expression *expr, const Expression *src)
|
||||
@@ -292,7 +293,7 @@ void rpn_LOGNOT(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = !expr->val;
|
||||
} else {
|
||||
expr->rpnPatchSize++;
|
||||
@@ -300,31 +301,26 @@ void rpn_LOGNOT(Expression *expr, const Expression *src)
|
||||
}
|
||||
}
|
||||
|
||||
Symbol const *rpn_SymbolOf(Expression const *expr)
|
||||
Symbol const *Expression::symbolOf() const
|
||||
{
|
||||
if (!rpn_isSymbol(expr))
|
||||
if (!isSymbol)
|
||||
return nullptr;
|
||||
return sym_FindScopedSymbol((char const *)&(*expr->rpn)[1]);
|
||||
return sym_FindScopedSymbol((char const *)&(*rpn)[1]);
|
||||
}
|
||||
|
||||
bool rpn_IsDiffConstant(Expression const *src, Symbol const *sym)
|
||||
bool Expression::isDiffConstant(Symbol const *sym) const
|
||||
{
|
||||
// Check if both expressions only refer to a single symbol
|
||||
Symbol const *sym1 = rpn_SymbolOf(src);
|
||||
Symbol const *sym1 = symbolOf();
|
||||
|
||||
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
|
||||
return false;
|
||||
|
||||
Section const *section1 = sym_GetSection(sym1);
|
||||
Section const *section2 = sym_GetSection(sym);
|
||||
Section const *section1 = sym1->getSection();
|
||||
Section const *section2 = sym->getSection();
|
||||
return section1 && (section1 == section2);
|
||||
}
|
||||
|
||||
static bool isDiffConstant(Expression const *src1, Expression const *src2)
|
||||
{
|
||||
return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempts to compute a constant binary AND from non-constant operands
|
||||
* This is possible if one operand is a symbol belonging to an `ALIGN[N]` section, and the other is
|
||||
@@ -334,33 +330,33 @@ static bool isDiffConstant(Expression const *src1, Expression const *src2)
|
||||
*/
|
||||
static int32_t tryConstMask(Expression const *lhs, Expression const *rhs)
|
||||
{
|
||||
Symbol const *sym = rpn_SymbolOf(lhs);
|
||||
Symbol const *sym = lhs->symbolOf();
|
||||
Expression const *expr = rhs;
|
||||
|
||||
if (!sym || !sym_GetSection(sym)) {
|
||||
if (!sym || !sym->getSection()) {
|
||||
// If the lhs isn't a symbol, try again the other way around
|
||||
sym = rpn_SymbolOf(rhs);
|
||||
sym = rhs->symbolOf();
|
||||
expr = lhs;
|
||||
|
||||
if (!sym || !sym_GetSection(sym))
|
||||
if (!sym || !sym->getSection())
|
||||
return -1;
|
||||
}
|
||||
assert(sym_IsNumeric(sym));
|
||||
assert(sym->isNumeric());
|
||||
|
||||
if (!rpn_isKnown(expr))
|
||||
if (!expr->isKnown)
|
||||
return -1;
|
||||
// We can now safely use `expr->val`
|
||||
Section const *sect = sym_GetSection(sym);
|
||||
Section const *sect = sym->getSection();
|
||||
int32_t unknownBits = (1 << 16) - (1 << sect->align); // The max alignment is 16
|
||||
|
||||
// The mask must ignore all unknown bits
|
||||
if ((expr->val & unknownBits) != 0)
|
||||
return -1;
|
||||
|
||||
// `sym_GetValue()` attempts to add the section's address,
|
||||
// but that's "-1" because the section is floating (otherwise we wouldn't be here)
|
||||
// `sym->getValue()` attempts to add the section's address, but that's "-1"
|
||||
// because the section is floating (otherwise we wouldn't be here)
|
||||
assert(sect->org == (uint32_t)-1);
|
||||
int32_t symbolOfs = sym_GetValue(sym) + 1;
|
||||
int32_t symbolOfs = sym->getValue() + 1;
|
||||
|
||||
return (symbolOfs + sect->alignOfs) & ~unknownBits;
|
||||
}
|
||||
@@ -371,9 +367,9 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
||||
int32_t constMaskVal;
|
||||
|
||||
// First, check if the expression is known
|
||||
expr->isKnown = rpn_isKnown(src1) && rpn_isKnown(src2);
|
||||
if (rpn_isKnown(expr)) {
|
||||
rpn_Init(expr); // Init the expression to something sane
|
||||
expr->isKnown = src1->isKnown && src2->isKnown;
|
||||
if (expr->isKnown) {
|
||||
initExpression(expr); // Init the expression to something sane
|
||||
|
||||
// If both expressions are known, just compute the value
|
||||
uint32_t uleft = src1->val, uright = src2->val;
|
||||
@@ -509,11 +505,11 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
||||
fatalerror("%d is not a binary operator\n", op);
|
||||
}
|
||||
|
||||
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
||||
Symbol const *symbol1 = rpn_SymbolOf(src1);
|
||||
Symbol const *symbol2 = rpn_SymbolOf(src2);
|
||||
} else if (op == RPN_SUB && src1->isDiffConstant(src2->symbolOf())) {
|
||||
Symbol const *symbol1 = src1->symbolOf();
|
||||
Symbol const *symbol2 = src2->symbolOf();
|
||||
|
||||
expr->val = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
||||
expr->val = symbol1->getValue() - symbol2->getValue();
|
||||
expr->isKnown = true;
|
||||
} else if (op == RPN_AND && (constMaskVal = tryConstMask(src1, src2)) != -1) {
|
||||
expr->val = constMaskVal;
|
||||
@@ -522,7 +518,7 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
||||
// If it's not known, start computing the RPN expression
|
||||
|
||||
// Convert the left-hand expression if it's constant
|
||||
if (rpn_isKnown(src1)) {
|
||||
if (src1->isKnown) {
|
||||
uint32_t lval = src1->val;
|
||||
uint8_t bytes[] = {RPN_CONST, (uint8_t)lval, (uint8_t)(lval >> 8),
|
||||
(uint8_t)(lval >> 16), (uint8_t)(lval >> 24)};
|
||||
@@ -550,7 +546,7 @@ void rpn_BinaryOp(enum RPNCommand op, Expression *expr, const Expression *src1,
|
||||
uint32_t rval = src2->val;
|
||||
uint8_t bytes[] = {RPN_CONST, (uint8_t)rval, (uint8_t)(rval >> 8),
|
||||
(uint8_t)(rval >> 16), (uint8_t)(rval >> 24)};
|
||||
if (rpn_isKnown(src2)) {
|
||||
if (src2->isKnown) {
|
||||
ptr = bytes;
|
||||
len = sizeof(bytes);
|
||||
patchSize = sizeof(bytes);
|
||||
@@ -577,7 +573,7 @@ void rpn_HIGH(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = (uint32_t)expr->val >> 8 & 0xFF;
|
||||
} else {
|
||||
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
|
||||
@@ -592,7 +588,7 @@ void rpn_LOW(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = expr->val & 0xFF;
|
||||
} else {
|
||||
uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
||||
@@ -604,8 +600,8 @@ void rpn_LOW(Expression *expr, const Expression *src)
|
||||
|
||||
void rpn_ISCONST(Expression *expr, const Expression *src)
|
||||
{
|
||||
rpn_Init(expr);
|
||||
expr->val = rpn_isKnown(src);
|
||||
initExpression(expr);
|
||||
expr->val = src->isKnown;
|
||||
expr->isKnown = true;
|
||||
expr->isSymbol = false;
|
||||
}
|
||||
@@ -615,7 +611,7 @@ void rpn_NEG(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = -(uint32_t)expr->val;
|
||||
} else {
|
||||
expr->rpnPatchSize++;
|
||||
@@ -628,7 +624,7 @@ void rpn_NOT(Expression *expr, const Expression *src)
|
||||
*expr = *src;
|
||||
expr->isSymbol = false;
|
||||
|
||||
if (rpn_isKnown(expr)) {
|
||||
if (expr->isKnown) {
|
||||
expr->val = ~expr->val;
|
||||
} else {
|
||||
expr->rpnPatchSize++;
|
||||
|
||||
Reference in New Issue
Block a user