From 0a04904b75d4a0944aa93327c0b1c5e1ae2c0eae Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 13:22:14 +0100 Subject: [PATCH 01/16] 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; From cc59730c5be4ed9efc164238fb58e15108a5b2ff Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 14:04:14 +0100 Subject: [PATCH 02/16] Cleanup the RPN evaluator somewhat Make the bool field an actual bool Rename `iReloc` to a more exact `isKnown` (as was already pointed out by some comments) Make the value of `BANK(symbol)` consistent when the argument is invalid --- include/asm/rpn.h | 5 ++-- src/asm/asmy.y | 19 ++++++++------- src/asm/output.c | 6 ++--- src/asm/rpn.c | 60 ++++++++++++++++++++++------------------------- 4 files changed, 44 insertions(+), 46 deletions(-) diff --git a/include/asm/rpn.h b/include/asm/rpn.h index 1b0a75b6..6bff26a9 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -10,6 +10,7 @@ #define RGBDS_ASM_RPN_H #include +#include #include "linkdefs.h" @@ -22,13 +23,13 @@ struct Expression { uint32_t nRPNLength; uint32_t nRPNPatchSize; uint32_t nRPNOut; - uint32_t isReloc; + bool isKnown; }; /* FIXME: Should be defined in `asmy.h`, but impossible with POSIX Yacc */ extern int32_t nPCOffset; -uint32_t rpn_isReloc(const struct Expression *expr); +bool rpn_isKnown(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); diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 3f417eab..8d24e441 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -1190,7 +1190,7 @@ constlist_32bit_entry : /* empty */ const_8bit : relocconst { - if( (!rpn_isReloc(&$1)) && (($1.nVal < -128) || ($1.nVal > 255)) ) + if( (rpn_isKnown(&$1)) && (($1.nVal < -128) || ($1.nVal > 255)) ) warning(WARNING_TRUNCATION, "Expression must be 8-bit"); $$ = $1; } @@ -1198,7 +1198,7 @@ const_8bit : relocconst const_16bit : relocconst { - if ((!rpn_isReloc(&$1)) && (($1.nVal < -32768) || ($1.nVal > 65535))) + if ((rpn_isKnown(&$1)) && (($1.nVal < -32768) || ($1.nVal > 65535))) warning(WARNING_TRUNCATION, "Expression must be 16-bit"); $$ = $1; } @@ -1769,7 +1769,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind { rpn_CheckHRAM(&$4, &$4); - if ((!rpn_isReloc(&$4)) && ($4.nVal < 0 || ($4.nVal > 0xFF && $4.nVal < 0xFF00) || $4.nVal > 0xFFFF)) + if ((rpn_isKnown(&$4)) && ($4.nVal < 0 || ($4.nVal > 0xFF && $4.nVal < 0xFF00) || $4.nVal > 0xFFFF)) yyerror("Source address $%x not in $FF00 to $FFFF", $4.nVal); out_AbsByte(0xF0); @@ -1780,7 +1780,7 @@ z80_ldio : T_Z80_LDIO T_MODE_A comma op_mem_ind { rpn_CheckHRAM(&$2, &$2); - if ((!rpn_isReloc(&$2)) && ($2.nVal < 0 || ($2.nVal > 0xFF && $2.nVal < 0xFF00) || $2.nVal > 0xFFFF)) + if ((rpn_isKnown(&$2)) && ($2.nVal < 0 || ($2.nVal > 0xFF && $2.nVal < 0xFF00) || $2.nVal > 0xFFFF)) yyerror("Destination address $%x not in $FF00 to $FFFF", $2.nVal); out_AbsByte(0xE0); @@ -1844,7 +1844,7 @@ z80_ld_mem : T_Z80_LD op_mem_ind comma T_MODE_SP | T_Z80_LD op_mem_ind comma T_MODE_A { if (CurrentOptions.optimizeloads && - (!rpn_isReloc(&$2)) && ($2.nVal >= 0xFF00)) { + (rpn_isKnown(&$2)) && ($2.nVal >= 0xFF00)) { out_AbsByte(0xE0); out_AbsByte($2.nVal & 0xFF); rpn_Free(&$2); @@ -1899,7 +1899,7 @@ z80_ld_a : T_Z80_LD reg_r comma T_MODE_C_IND { if ($2 == REG_A) { if (CurrentOptions.optimizeloads && - (!rpn_isReloc(&$4)) && ($4.nVal >= 0xFF00)) { + (rpn_isKnown(&$4)) && ($4.nVal >= 0xFF00)) { out_AbsByte(0xF0); out_AbsByte($4.nVal & 0xFF); rpn_Free(&$4); @@ -2036,13 +2036,14 @@ z80_rrca : T_Z80_RRCA z80_rst : T_Z80_RST const_8bit { - if (rpn_isReloc(&$2)) { + if (!rpn_isKnown(&$2)) { rpn_CheckRST(&$2, &$2); out_RelByte(&$2); - } else if (($2.nVal & 0x38) != $2.nVal) + } else if (($2.nVal & 0x38) != $2.nVal) { yyerror("Invalid address $%x for RST", $2.nVal); - else + } else { out_AbsByte(0xC7 | $2.nVal); + } rpn_Free(&$2); } ; diff --git a/src/asm/output.c b/src/asm/output.c index e1cfd87d..0b7f71b8 100644 --- a/src/asm/output.c +++ b/src/asm/output.c @@ -766,7 +766,7 @@ void out_RelByte(struct Expression *expr) { checkcodesection(); checksectionoverflow(1); - if (rpn_isReloc(expr)) { + if (!rpn_isKnown(expr)) { pCurrentSection->tData[nPC] = 0; createpatch(PATCHTYPE_BYTE, expr); pCurrentSection->nPC++; @@ -801,7 +801,7 @@ void out_RelWord(struct Expression *expr) { checkcodesection(); checksectionoverflow(2); - if (rpn_isReloc(expr)) { + if (!rpn_isKnown(expr)) { pCurrentSection->tData[nPC] = 0; pCurrentSection->tData[nPC + 1] = 0; createpatch(PATCHTYPE_WORD, expr); @@ -838,7 +838,7 @@ void out_RelLong(struct Expression *expr) { checkcodesection(); checksectionoverflow(4); - if (rpn_isReloc(expr)) { + if (!rpn_isKnown(expr)) { pCurrentSection->tData[nPC] = 0; pCurrentSection->tData[nPC + 1] = 0; pCurrentSection->tData[nPC + 2] = 0; diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 2c93515a..7f1a2644 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -25,7 +25,7 @@ /* * Add a byte to the RPN expression */ -void pushbyte(struct Expression *expr, uint8_t b) +static void pushbyte(struct Expression *expr, uint8_t b) { if (expr->nRPNLength == expr->nRPNCapacity) { if (expr->nRPNCapacity == 0) @@ -55,7 +55,7 @@ void rpn_Init(struct Expression *expr) expr->nRPNLength = 0; expr->nRPNPatchSize = 0; expr->nRPNOut = 0; - expr->isReloc = 0; + expr->isKnown = true; } /* @@ -79,11 +79,11 @@ uint16_t rpn_PopByte(struct Expression *expr) } /* - * Determine if the current expression is relocatable + * Determine if the current expression is known at assembly time */ -uint32_t rpn_isReloc(const struct Expression *expr) +bool rpn_isKnown(const struct Expression *expr) { - return expr->isReloc; + return expr->isKnown; } /* @@ -108,7 +108,7 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) if (!sym || !sym_IsConstant(sym)) { rpn_Init(expr); sym_Ref(tzSym); - expr->isReloc = 1; + expr->isKnown = false; pushbyte(expr, RPN_SYM); while (*tzSym) pushbyte(expr, *tzSym++); @@ -132,11 +132,7 @@ void rpn_BankSelf(struct Expression *expr) rpn_Init(expr); if (pCurrentSection->nBank == -1) - /* - * This is not really relocatable, but this makes the assembler - * write this expression as a RPN patch to the object file. - */ - expr->isReloc = 1; + expr->isKnown = false; else expr->nVal = pCurrentSection->nBank; @@ -154,10 +150,10 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym) return; } + rpn_Init(expr); if (sym && sym_IsConstant(sym)) { yyerror("BANK argument must be a relocatable identifier"); } else { - rpn_Init(expr); sym_Ref(tzSym); pushbyte(expr, RPN_BANK_SYM); for (unsigned int i = 0; tzSym[i]; i++) @@ -172,7 +168,7 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym) /* Symbol's section is known and bank's fixed */ expr->nVal = pSymbol->pSection->nBank; else - expr->isReloc = 1; + expr->isKnown = false; } } @@ -185,11 +181,7 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName) if (pSection && pSection->nBank != -1) expr->nVal = pSection->nBank; else - /* - * This is not really relocatable, but this makes the assembler - * write this expression as a RPN patch to the object file. - */ - expr->isReloc = 1; + expr->isKnown = false; pushbyte(expr, RPN_BANK_SECT); expr->nRPNPatchSize++; @@ -272,11 +264,11 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, { 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; + if (len > MAXRPNLEN) + fatalerror("RPN expression is too large"); + expr->nVal = 0; expr->tRPN = src1->tRPN; @@ -302,7 +294,7 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, expr->nRPNLength = len; expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize; expr->nRPNOut = 0; - expr->isReloc = src1->isReloc || src2->isReloc; + expr->isKnown = src1->isKnown && src2->isKnown; switch (op) { case RPN_LOGOR: @@ -345,24 +337,28 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, 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); + 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); + 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); + 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); + 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 (expr->isKnown) { if (src2->nVal == 0) fatalerror("Division by zero"); @@ -375,7 +371,7 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, } break; case RPN_MOD: - if (!expr->isReloc) { + if (expr->isKnown) { if (src2->nVal == 0) fatalerror("Division by zero"); From 9ce8a9f5f09d126a7885c500df108cf98b157e57 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 15:20:09 +0100 Subject: [PATCH 03/16] Add comments to RPN expr struct --- include/asm/rpn.h | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/include/asm/rpn.h b/include/asm/rpn.h index 6bff26a9..6bd8163e 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -17,13 +17,14 @@ #define MAXRPNLEN 1048576 struct Expression { - int32_t nVal; - uint8_t *tRPN; - uint32_t nRPNCapacity; - uint32_t nRPNLength; - uint32_t nRPNPatchSize; - uint32_t nRPNOut; - bool isKnown; + bool isKnown; // Whether the expression's value is known + int32_t nVal; // If the expression's value is known, it's here + uint8_t *tRPN; // Array of bytes serializing the RPN expression + uint32_t nRPNCapacity; // Size of the `tRPN` buffer + uint32_t nRPNLength; // Used size of the `tRPN` buffer + uint32_t nRPNPatchSize; // Size the expression will take in the obj file + // FIXME: does this need to be part of the struct? + uint32_t nRPNOut; // How many bytes have been written }; /* FIXME: Should be defined in `asmy.h`, but impossible with POSIX Yacc */ From 9fb9e63554aa536c3028f59e349f9663e6c22c15 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 15:26:52 +0100 Subject: [PATCH 04/16] Reserve space for RPN expressions in a single call This should mean less overhead with some commands --- src/asm/rpn.c | 135 +++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 74 deletions(-) diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 7f1a2644..4625b5f3 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -22,27 +23,35 @@ #include "asm/output.h" #include "asm/warning.h" -/* - * Add a byte to the RPN expression - */ -static void pushbyte(struct Expression *expr, uint8_t b) +static uint8_t *reserveSpace(struct Expression *expr, uint32_t size) { - if (expr->nRPNLength == expr->nRPNCapacity) { - if (expr->nRPNCapacity == 0) - expr->nRPNCapacity = 256; - else if (expr->nRPNCapacity == MAXRPNLEN) - fatalerror("RPN expression is too large"); + /* This assumes the RPN length is always less than the capacity */ + if (expr->nRPNCapacity - expr->nRPNLength < size) { + /* If there isn't enough room to reserve the space, realloc */ + if (!expr->tRPN) + expr->nRPNCapacity = 256; /* Initial size */ + else if (expr->nRPNCapacity >= MAXRPNLEN) + /* + * To avoid generating humongous object files, cap the + * size of RPN expressions + */ + fatalerror("RPN expression cannot grow larger than %d bytes", + MAXRPNLEN); else if (expr->nRPNCapacity > MAXRPNLEN / 2) expr->nRPNCapacity = MAXRPNLEN; else expr->nRPNCapacity *= 2; expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity); - if (expr->tRPN == NULL) - fatalerror("No memory for RPN expression"); + if (!expr->tRPN) + fatalerror("Failed to grow RPN expression: %s", + strerror(errno)); } - expr->tRPN[expr->nRPNLength++] = b; + uint8_t *ptr = expr->tRPN + expr->nRPNLength; + + expr->nRPNLength += size; + return ptr; } /* @@ -91,14 +100,12 @@ bool rpn_isKnown(const struct Expression *expr) */ void rpn_Number(struct Expression *expr, uint32_t i) { + uint8_t bytes[] = {RPN_CONST, i, i >> 8, i >> 16, i >> 24}; + rpn_Init(expr); - pushbyte(expr, RPN_CONST); - pushbyte(expr, i); - pushbyte(expr, i >> 8); - pushbyte(expr, i >> 16); - pushbyte(expr, i >> 24); + expr->nRPNPatchSize += sizeof(bytes); + memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes)); expr->nVal = i; - expr->nRPNPatchSize += 5; } void rpn_Symbol(struct Expression *expr, char *tzSym) @@ -109,11 +116,12 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) rpn_Init(expr); sym_Ref(tzSym); expr->isKnown = false; - pushbyte(expr, RPN_SYM); - while (*tzSym) - pushbyte(expr, *tzSym++); - pushbyte(expr, 0); - expr->nRPNPatchSize += 5; + expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */ + + size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); + *ptr++ = RPN_SYM; + memcpy(ptr, tzSym, nameLen); /* RGBLINK assumes PC is at the byte being computed... */ if (sym == pPCSymbol && nPCOffset) { @@ -136,7 +144,7 @@ void rpn_BankSelf(struct Expression *expr) else expr->nVal = pCurrentSection->nBank; - pushbyte(expr, RPN_BANK_SELF); + *reserveSpace(expr, 1) = RPN_BANK_SELF; expr->nRPNPatchSize++; } @@ -155,17 +163,18 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym) yyerror("BANK argument must be a relocatable identifier"); } else { sym_Ref(tzSym); - pushbyte(expr, RPN_BANK_SYM); - for (unsigned int i = 0; tzSym[i]; i++) - pushbyte(expr, tzSym[i]); - pushbyte(expr, 0); - expr->nRPNPatchSize += 5; + expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte sect ID */ + + size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); + *ptr++ = RPN_BANK_SYM; + memcpy(ptr, tzSym, nameLen); /* If the symbol didn't exist, `sym_Ref` created it */ struct sSymbol *pSymbol = sym_FindSymbol(tzSym); if (pSymbol->pSection && pSymbol->pSection->nBank != -1) - /* Symbol's section is known and bank's fixed */ + /* Symbol's section is known and bank is fixed */ expr->nVal = pSymbol->pSection->nBank; else expr->isKnown = false; @@ -183,29 +192,25 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName) else expr->isKnown = false; - pushbyte(expr, RPN_BANK_SECT); - expr->nRPNPatchSize++; + size_t nameLen = strlen(tzSectionName) + 1; /* Don't forget NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); - while (*tzSectionName) { - pushbyte(expr, *tzSectionName++); - expr->nRPNPatchSize++; - } - - pushbyte(expr, 0); - expr->nRPNPatchSize++; + expr->nRPNPatchSize += nameLen + 1; + *ptr++ = RPN_BANK_SECT; + memcpy(ptr, tzSectionName, nameLen); } void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src) { *expr = *src; - pushbyte(expr, RPN_HRAM); expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_HRAM; } void rpn_CheckRST(struct Expression *expr, const struct Expression *src) { *expr = *src; - pushbyte(expr, RPN_RST); + *reserveSpace(expr, 1) = RPN_RST; expr->nRPNPatchSize++; } @@ -213,8 +218,8 @@ void rpn_LOGNOT(struct Expression *expr, const struct Expression *src) { *expr = *src; expr->nVal = !expr->nVal; - pushbyte(expr, RPN_LOGUNNOT); expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_LOGUNNOT; } static int32_t shift(int32_t shiftee, int32_t amount) @@ -291,10 +296,11 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, 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->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; switch (op) { case RPN_LOGOR: @@ -325,6 +331,7 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, 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: @@ -394,9 +401,6 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, case RPN_SYM: fatalerror("%d is no binary operator", op); } - - pushbyte(expr, op); - expr->nRPNPatchSize++; } void rpn_HIGH(struct Expression *expr, const struct Expression *src) @@ -405,23 +409,11 @@ void rpn_HIGH(struct Expression *expr, const struct Expression *src) expr->nVal = (expr->nVal >> 8) & 0xFF; - pushbyte(expr, RPN_CONST); - pushbyte(expr, 8); - pushbyte(expr, 0); - pushbyte(expr, 0); - pushbyte(expr, 0); + uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR, + RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; + expr->nRPNPatchSize += sizeof(bytes); - pushbyte(expr, RPN_SHR); - - pushbyte(expr, RPN_CONST); - pushbyte(expr, 0xFF); - pushbyte(expr, 0); - pushbyte(expr, 0); - pushbyte(expr, 0); - - pushbyte(expr, RPN_AND); - - expr->nRPNPatchSize += 12; + memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes)); } void rpn_LOW(struct Expression *expr, const struct Expression *src) @@ -430,29 +422,24 @@ void rpn_LOW(struct Expression *expr, const struct Expression *src) expr->nVal = expr->nVal & 0xFF; - pushbyte(expr, RPN_CONST); - pushbyte(expr, 0xFF); - pushbyte(expr, 0); - pushbyte(expr, 0); - pushbyte(expr, 0); + uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; - pushbyte(expr, RPN_AND); - - expr->nRPNPatchSize += 6; + 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; - pushbyte(expr, RPN_UNSUB); expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_UNSUB; } void rpn_UNNOT(struct Expression *expr, const struct Expression *src) { *expr = *src; expr->nVal = ~expr->nVal; - pushbyte(expr, RPN_UNNOT); expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_UNNOT; } From f9c25608e90629898373c29fc99007189604854b Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 17:05:49 +0100 Subject: [PATCH 05/16] Ignore RPN strings when their value is known --- src/asm/output.c | 25 +++- src/asm/rpn.c | 351 ++++++++++++++++++++++++++--------------------- 2 files changed, 213 insertions(+), 163 deletions(-) diff --git a/src/asm/output.c b/src/asm/output.c index 0b7f71b8..d8a2234b 100644 --- a/src/asm/output.c +++ b/src/asm/output.c @@ -861,14 +861,25 @@ void out_PCRelByte(struct Expression *expr) { 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); } diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 4625b5f3..67bdf788 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -100,11 +100,7 @@ bool rpn_isKnown(const struct Expression *expr) */ 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_BankSection(struct Expression *expr, char *tzSectionName) 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 @@ static int32_t shift(int32_t shiftee, int32_t amount) void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, const struct Expression *src1, const struct Expression *src2) { - assert(src1->tRPN != NULL && src2->tRPN != NULL); - - 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? + /* First, check if the expression is known */ expr->isKnown = src1->isKnown && src2->isKnown; - expr->nRPNLength = len; - expr->nRPNPatchSize = src1->nRPNPatchSize + src2->nRPNPatchSize + 1; - *reserveSpace(expr, 1) = op; + if (expr->isKnown) { + /* If both expressions are known, just compute the value */ + uint32_t uleft = src1->nVal, uright = src2->nVal; - 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); + 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); - 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; + expr->nVal = shift(src1->nVal, src2->nVal); } - } - break; - case RPN_MOD: - if (expr->isKnown) { - if (src2->nVal == 0) - fatalerror("Division by zero"); + break; + case RPN_SHR: + if (expr->isKnown) { + if (src2->nVal < 0) + warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative value: %d", + src2->nVal); - if (src1->nVal == INT32_MIN && src2->nVal == -1) - expr->nVal = 0; - else - expr->nVal = src1->nVal % src2->nVal; - } - break; + 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"); - 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); + 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 (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->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) { *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; + } } From b4a73f33ce62de139d2c4490a9cc3877c6832cb2 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Sun, 26 Jan 2020 19:42:34 +0100 Subject: [PATCH 06/16] Avoid undefined behavior when shifting in RPN math --- src/asm/rpn.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 67bdf788..8410de99 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -390,9 +390,9 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, /* 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}; + uint32_t lval = src1->nVal; + uint8_t bytes[] = {RPN_CONST, lval, lval >> 8, + lval >> 16, lval >> 24}; expr->nRPNPatchSize = sizeof(bytes); expr->tRPN = NULL; expr->nRPNCapacity = 0; @@ -413,8 +413,9 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, 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}; + uint32_t rval = src2->nVal; + uint8_t bytes[] = {RPN_CONST, rval, rval >> 8, rval >> 16, + rval >> 24}; if (src2->isKnown) { ptr = bytes; len = sizeof(bytes); @@ -436,7 +437,7 @@ void rpn_HIGH(struct Expression *expr, const struct Expression *src) *expr = *src; if (rpn_isKnown(expr)) { - expr->nVal = expr->nVal >> 8 & 0xFF; + expr->nVal = (uint32_t)expr->nVal >> 8 & 0xFF; } else { uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR, RPN_CONST, 0xFF, 0, 0, 0, RPN_AND}; From 52d62c6b215478566c20afd8f8e7e9cc049ac92c Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 23:07:31 +0100 Subject: [PATCH 07/16] Handle subtractions between labels --- src/asm/rpn.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 8410de99..50fb42e3 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -274,6 +274,28 @@ static int32_t shift(int32_t shiftee, int32_t amount) } } +static struct sSymbol const *symbolOf(struct Expression const *expr) +{ + /* If an expression starts with a symbol ref... */ + if (!expr->tRPN || expr->tRPN[0] != RPN_SYM || expr->nRPNPatchSize != 5) + return NULL; + return sym_FindSymbol((char *)expr->tRPN + 1); +} + +static bool isDiffConstant(struct Expression const *src1, + struct Expression const *src2) +{ + /* Check if both expressions only refer to a single symbol */ + struct sSymbol const *symbol1 = symbolOf(src1); + struct sSymbol const *symbol2 = symbolOf(src2); + + if (!symbol1 || !symbol2 + || symbol1->type != SYM_LABEL || symbol2->type != SYM_LABEL) + return false; + + return symbol1->pSection == symbol2->pSection; +} + void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, const struct Expression *src1, const struct Expression *src2) { @@ -383,8 +405,12 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, fatalerror("%d is no binary operator", op); } - /* TODO: under some conditions, the expression will still be known */ + } else if (op == RPN_SUB && isDiffConstant(src1, src2)) { + struct sSymbol const *symbol1 = symbolOf(src1); + struct sSymbol const *symbol2 = symbolOf(src2); + expr->nVal = symbol1->nValue - symbol2->nValue; + expr->isKnown = true; } else { /* If it's not known, start computing the RPN expression */ From 1d78cd0f03e503d6acce6f83e8609d484ca2978f Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 20 Jan 2020 23:12:41 +0100 Subject: [PATCH 08/16] Axe the `constexpr` expression evaluator This avoids redundancy between them (and also having to port fixes and features) The error messages have been preserved through a string reporting mechanism --- Makefile | 1 - include/asm/constexpr.h | 35 ----- include/asm/rpn.h | 1 + src/asm/asmy.y | 145 +++++-------------- src/asm/constexpr.c | 298 ---------------------------------------- src/asm/globlex.c | 1 - src/asm/lexer.c | 1 - src/asm/rpn.c | 91 +++++++----- test/asm/bank.err | 8 +- test/asm/overflow.err | 2 - test/asm/pc-bank.err | 2 +- test/asm/shift.err | 16 +-- 12 files changed, 101 insertions(+), 500 deletions(-) delete mode 100644 include/asm/constexpr.h delete mode 100644 src/asm/constexpr.c diff --git a/Makefile b/Makefile index d9ee6eeb..96b08cd8 100644 --- a/Makefile +++ b/Makefile @@ -54,7 +54,6 @@ all: rgbasm rgblink rgbfix rgbgfx rgbasm_obj := \ src/asm/asmy.o \ src/asm/charmap.o \ - src/asm/constexpr.o \ src/asm/fstack.o \ src/asm/globlex.o \ src/asm/lexer.o \ diff --git a/include/asm/constexpr.h b/include/asm/constexpr.h deleted file mode 100644 index 1e566e53..00000000 --- a/include/asm/constexpr.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * This file is part of RGBDS. - * - * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors. - * - * SPDX-License-Identifier: MIT - */ - -#ifndef RGBDS_ASM_CONSTEXPR_H -#define RGBDS_ASM_CONSTEXPR_H - -#include - -struct ConstExpression { - union { - int32_t nVal; - struct sSymbol *pSym; - } u; - uint32_t isSym; -}; - -void constexpr_Symbol(struct ConstExpression *expr, char *tzSym); -void constexpr_BankSymbol(struct ConstExpression *expr, char *tzSym); -void constexpr_BankSection(struct ConstExpression *expr, char *tzSym); -void constexpr_Number(struct ConstExpression *expr, int32_t i); -void constexpr_UnaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src); -void constexpr_BinaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src1, - const struct ConstExpression *src2); -int32_t constexpr_GetConstantValue(struct ConstExpression *expr); - -#endif /* RGBDS_ASM_CONSTEXPR_H */ diff --git a/include/asm/rpn.h b/include/asm/rpn.h index 6bd8163e..f8bcdc63 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -19,6 +19,7 @@ struct Expression { bool isKnown; // Whether the expression's value is known int32_t nVal; // If the expression's value is known, it's here + char *reason; // Why the expression is not known, if it isn't uint8_t *tRPN; // Array of bytes serializing the RPN expression uint32_t nRPNCapacity; // Size of the `tRPN` buffer uint32_t nRPNLength; // Used size of the `tRPN` buffer diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 8d24e441..4406ead6 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -18,7 +18,6 @@ #include "asm/asm.h" #include "asm/charmap.h" -#include "asm/constexpr.h" #include "asm/fstack.h" #include "asm/lexer.h" #include "asm/main.h" @@ -510,11 +509,10 @@ static void strsubUTF8(char *dest, const char *src, uint32_t pos, uint32_t len) char tzString[MAXSTRLEN + 1]; struct Expression sVal; int32_t nConstValue; - struct ConstExpression sConstExpr; } %type relocconst -%type const +%type const %type uconst %type const_3bit %type const_8bit @@ -966,17 +964,17 @@ global_list_entry : T_ID equ : T_LABEL T_POP_EQU const { - sym_AddEqu($1, constexpr_GetConstantValue(&$3)); + sym_AddEqu($1, $3); } ; set : T_LABEL T_POP_SET const { - sym_AddSet($1, constexpr_GetConstantValue(&$3)); + sym_AddSet($1, $3); } | T_LABEL T_POP_EQUAL const { - sym_AddSet($1, constexpr_GetConstantValue(&$3)); + sym_AddSet($1, $3); } ; @@ -1004,12 +1002,10 @@ incbin : T_POP_INCBIN string charmap : T_POP_CHARMAP string comma const { - int32_t value = constexpr_GetConstantValue(&$4); - - if ((value & 0xFF) != value) + if (($4 & 0xFF) != $4) warning(WARNING_TRUNCATION, "Expression must be 8-bit"); - if (charmap_Add($2, value & 0xFF) == -1) + if (charmap_Add($2, $4 & 0xFF) == -1) yyerror("Error parsing charmap. Either you've added too many (%i), or the input character length is too long (%i)' : %s\n", MAXCHARMAPS, CHARMAPLENGTH, strerror(errno)); } ; @@ -1044,26 +1040,26 @@ printt : T_POP_PRINTT string printv : T_POP_PRINTV const { - printf("$%X", constexpr_GetConstantValue(&$2)); + printf("$%X", $2); } ; printi : T_POP_PRINTI const { - printf("%d", constexpr_GetConstantValue(&$2)); + printf("%d", $2); } ; printf : T_POP_PRINTF const { - math_Print(constexpr_GetConstantValue(&$2)); + math_Print($2); } ; if : T_POP_IF const { nIFDepth++; - if (!constexpr_GetConstantValue(&$2)) { + if (!$2) { /* * Continue parsing after ELSE, or at ELIF or * ENDC keyword. @@ -1095,7 +1091,7 @@ elif : T_POP_ELIF const */ skipElif = true; - if (!constexpr_GetConstantValue(&$2)) { + if (!$2) { /* * Continue parsing after ELSE, or at * ELIF or ENDC keyword. @@ -1127,7 +1123,7 @@ endc : T_POP_ENDC const_3bit : const { - int32_t value = constexpr_GetConstantValue(&$1); + int32_t value = $1; if ((value < 0) || (value > 7)) yyerror("Immediate value must be 3-bit"); else @@ -1268,57 +1264,57 @@ relocconst : T_ID } | T_OP_ROUND '(' const ')' { - rpn_Number(&$$, math_Round(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Round($3)); } | T_OP_CEIL '(' const ')' { - rpn_Number(&$$, math_Ceil(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Ceil($3)); } | T_OP_FLOOR '(' const ')' { - rpn_Number(&$$, math_Floor(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Floor($3)); } | T_OP_FDIV '(' const comma const ')' { rpn_Number(&$$, - math_Div(constexpr_GetConstantValue(&$3), - constexpr_GetConstantValue(&$5))); + math_Div($3, + $5)); } | T_OP_FMUL '(' const comma const ')' { rpn_Number(&$$, - math_Mul(constexpr_GetConstantValue(&$3), - constexpr_GetConstantValue(&$5))); + math_Mul($3, + $5)); } | T_OP_SIN '(' const ')' { - rpn_Number(&$$, math_Sin(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Sin($3)); } | T_OP_COS '(' const ')' { - rpn_Number(&$$, math_Cos(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Cos($3)); } | T_OP_TAN '(' const ')' { - rpn_Number(&$$, math_Tan(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_Tan($3)); } | T_OP_ASIN '(' const ')' { - rpn_Number(&$$, math_ASin(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_ASin($3)); } | T_OP_ACOS '(' const ')' { - rpn_Number(&$$, math_ACos(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_ACos($3)); } | T_OP_ATAN '(' const ')' { - rpn_Number(&$$, math_ATan(constexpr_GetConstantValue(&$3))); + rpn_Number(&$$, math_ATan($3)); } | T_OP_ATAN2 '(' const comma const ')' { rpn_Number(&$$, - math_ATan2(constexpr_GetConstantValue(&$3), - constexpr_GetConstantValue(&$5))); + math_ATan2($3, + $5)); } | T_OP_STRCMP '(' string comma string ')' { @@ -1339,92 +1335,23 @@ relocconst : T_ID uconst : const { - int32_t value = constexpr_GetConstantValue(&$1); + int32_t value = $1; if (value < 0) fatalerror("Constant mustn't be negative: %d", value); $$ = value; } ; -const : T_ID { constexpr_Symbol(&$$, $1); } - | T_NUMBER { constexpr_Number(&$$, $1); } - | T_OP_HIGH '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_LOW '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_BANK '(' T_ID ')' +const : relocconst { - constexpr_BankSymbol(&$$, $3); + if (!rpn_isKnown(&$1)) { + yyerror("Expected constant expression: %s", + $1.reason); + $$ = 0; + } else { + $$ = $1.nVal; + } } - | T_OP_BANK '(' string ')' - { - constexpr_BankSection(&$$, $3); - } - | string - { - char *s = $1; - int32_t length = charmap_Convert(&s); - constexpr_Number(&$$, str2int2(s, length)); - free(s); - } - | T_OP_LOGICNOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | const T_OP_LOGICOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICAND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICEQU const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICGT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICLT const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICGE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICLE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_LOGICNE const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_ADD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_SUB const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_XOR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_OR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_AND const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_SHL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_SHR const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_MUL const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_DIV const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | const T_OP_MOD const { constexpr_BinaryOp(&$$, $2, &$1, &$3); } - | T_OP_ADD const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | T_OP_SUB const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | T_OP_NOT const %prec NEG { constexpr_UnaryOp(&$$, $1, &$2); } - | T_OP_ROUND '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_CEIL '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_FLOOR '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_FDIV '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); } - | T_OP_FMUL '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); } - | T_OP_SIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_COS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_TAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ASIN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ACOS '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ATAN '(' const ')' { constexpr_UnaryOp(&$$, $1, &$3); } - | T_OP_ATAN2 '(' const comma const ')' { constexpr_BinaryOp(&$$, $1, &$3, &$5); } - | T_OP_DEF { - oDontExpandStrings = true; - } '(' T_ID ')' - { - struct sSymbol const *sym = sym_FindSymbol($4); - if (sym && !(sym_IsDefined(sym) && sym->type != SYM_LABEL)) - yyerror("Label \"%s\" is not a valid argument to DEF", - $4); - constexpr_Number(&$$, !!sym); - oDontExpandStrings = false; - } - | T_OP_STRCMP '(' string comma string ')' - { - constexpr_Number(&$$, strcmp($3, $5)); - } - | T_OP_STRIN '(' string comma string ')' - { - char *p = strstr($3, $5); - - if (p != NULL) - constexpr_Number(&$$, p - $3 + 1); - else - constexpr_Number(&$$, 0); - } - | T_OP_STRLEN '(' string ')' { constexpr_Number(&$$, strlenUTF8($3)); } - | '(' const ')' { $$ = $2; } ; string : T_STRING diff --git a/src/asm/constexpr.c b/src/asm/constexpr.c deleted file mode 100644 index d4b323cc..00000000 --- a/src/asm/constexpr.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * This file is part of RGBDS. - * - * Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors. - * - * SPDX-License-Identifier: MIT - */ - -#include -#include -#include - -#include "asm/asm.h" -#include "asm/constexpr.h" -#include "asm/lexer.h" -#include "asm/main.h" -#include "asm/mymath.h" -#include "asm/output.h" -#include "asm/rpn.h" -#include "asm/symbol.h" -#include "asm/warning.h" - -#include "asmy.h" - -void constexpr_Symbol(struct ConstExpression *expr, char *tzSym) -{ - struct sSymbol *sym = sym_FindSymbol(tzSym); - - if (!sym) { - fatalerror("'%s' not defined", tzSym); - } else if (!sym_IsConstant(sym)) { - expr->u.pSym = sym; - expr->isSym = 1; - } else { - constexpr_Number(expr, sym_GetConstantValue(tzSym)); - } -} - -void constexpr_BankSymbol(struct ConstExpression *expr, char *tzSym) -{ - constexpr_Number(expr, 0); - struct sSymbol *sym = sym_FindSymbol(tzSym); - - if (!sym) { - yyerror("BANK argument doesn't exist"); - } else if (sym == pPCSymbol) { - if (pCurrentSection->nBank == -1) - yyerror("Current bank is not known yet"); - else - constexpr_Number(expr, pCurrentSection->nBank); - } else if (sym->type != SYM_LABEL) { - yyerror("BANK argument must be a label"); - } else if (sym->pSection->nBank == -1) { - yyerror("BANK argument's bank is not known yet'"); - } else { - constexpr_Number(expr, sym->pSection->nBank); - } -} - -void constexpr_BankSection(struct ConstExpression *expr, char *tzSectionName) -{ - constexpr_Number(expr, 0); - struct Section *pSection = out_FindSectionByName(tzSectionName); - - if (!pSection) - yyerror("Section \"%s\" doesn't exist", tzSectionName); - else if (pSection->nBank == -1) - yyerror("Section \"%s\"'s bank is not known yet", - tzSectionName); - else - constexpr_Number(expr, pSection->nBank); -} - -void constexpr_Number(struct ConstExpression *expr, int32_t i) -{ - expr->u.nVal = i; - expr->isSym = 0; -} - -void constexpr_UnaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src) -{ - if (src->isSym) - fatalerror("Non-constant operand in constant expression"); - - int32_t value = src->u.nVal; - int32_t result = 0; - - switch (op) { - case T_OP_HIGH: - result = (value >> 8) & 0xFF; - break; - case T_OP_LOW: - result = value & 0xFF; - break; - case T_OP_LOGICNOT: - result = !value; - break; - case T_OP_ADD: - result = value; - break; - case T_OP_SUB: - result = -(uint32_t)value; - break; - case T_OP_NOT: - result = ~value; - break; - case T_OP_ROUND: - result = math_Round(value); - break; - case T_OP_CEIL: - result = math_Ceil(value); - break; - case T_OP_FLOOR: - result = math_Floor(value); - break; - case T_OP_SIN: - result = math_Sin(value); - break; - case T_OP_COS: - result = math_Cos(value); - break; - case T_OP_TAN: - result = math_Tan(value); - break; - case T_OP_ASIN: - result = math_ASin(value); - break; - case T_OP_ACOS: - result = math_ACos(value); - break; - case T_OP_ATAN: - result = math_ATan(value); - break; - default: - fatalerror("Unknown unary op"); - } - - constexpr_Number(expr, result); -} - -void constexpr_BinaryOp(struct ConstExpression *expr, - int32_t op, - const struct ConstExpression *src1, - const struct ConstExpression *src2) -{ - int32_t value1; - int32_t value2; - int32_t result = 0; - - if (op == T_OP_SUB && src1->isSym && src2->isSym) { - char *symName1 = src1->u.pSym->tzName; - char *symName2 = src2->u.pSym->tzName; - - if (!sym_IsRelocDiffDefined(symName1, symName2)) - fatalerror("'%s - %s' not defined", symName1, symName2); - value1 = sym_GetDefinedValue(symName1); - value2 = sym_GetDefinedValue(symName2); - result = value1 - value2; - } else if (src1->isSym || src2->isSym) { - fatalerror("Non-constant operand in constant expression"); - } else { - value1 = src1->u.nVal; - value2 = src2->u.nVal; - - switch (op) { - case T_OP_LOGICOR: - result = value1 || value2; - break; - case T_OP_LOGICAND: - result = value1 && value2; - break; - case T_OP_LOGICEQU: - result = value1 == value2; - break; - case T_OP_LOGICGT: - result = value1 > value2; - break; - case T_OP_LOGICLT: - result = value1 < value2; - break; - case T_OP_LOGICGE: - result = value1 >= value2; - break; - case T_OP_LOGICLE: - result = value1 <= value2; - break; - case T_OP_LOGICNE: - result = value1 != value2; - break; - case T_OP_ADD: - result = (uint32_t)value1 + (uint32_t)value2; - break; - case T_OP_SUB: - result = (uint32_t)value1 - (uint32_t)value2; - break; - case T_OP_XOR: - result = value1 ^ value2; - break; - case T_OP_OR: - result = value1 | value2; - break; - case T_OP_AND: - result = value1 & value2; - break; - case T_OP_SHL: - case T_OP_SHR: - if (value2 < 0) - warning(WARNING_SHIFT_AMOUNT, "Shifting %s by negative amount %d", - op == T_OP_SHL ? "left" : "right", - value2); - if (op == T_OP_SHR) { - value2 = -value2; /* Right shift == neg left */ - - if (value1 < 0) - warning(WARNING_SHIFT, "Shifting negative value %d", - value1); - } - - if (value2 >= 0) { - // Shift left - if (value2 >= 32) { - warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %d", - value2); - result = 0; - } else { - /* - * Use unsigned to force a bitwise shift - * Casting back is OK because the types - * implement two's complement behavior - */ - result = (uint32_t)value1 << value2; - } - } else { - // Shift right - value2 = -value2; - if (value2 >= 32) { - warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %d", - value2); - result = value1 < 0 ? -1 : 0; - } else if (value1 >= 0) { - result = value1 >> value2; - } else { - /* - * The C standard leaves shifting right - * negative values undefined, so use a - * left shift manually sign-extended - */ - result = (uint32_t)value1 >> value2 | - -((uint32_t)1 << (32 - value2)); - } - } - break; - case T_OP_MUL: - result = (uint32_t)value1 * (uint32_t)value2; - break; - case T_OP_DIV: - if (value2 == 0) - fatalerror("Division by zero"); - if (value1 == INT32_MIN && value2 == -1) { - warning(WARNING_DIV, "Division of min value by -1"); - result = INT32_MIN; - } else { - result = value1 / value2; - } - break; - case T_OP_MOD: - if (value2 == 0) - fatalerror("Division by zero"); - if (value1 == INT32_MIN && value2 == -1) - result = 0; - else - result = value1 % value2; - break; - case T_OP_FDIV: - result = math_Div(value1, value2); - break; - case T_OP_FMUL: - result = math_Mul(value1, value2); - break; - case T_OP_ATAN2: - result = math_ATan2(value1, value2); - break; - default: - fatalerror("Unknown binary op"); - } - } - - constexpr_Number(expr, result); -} - -int32_t constexpr_GetConstantValue(struct ConstExpression *expr) -{ - if (expr->isSym) - fatalerror("Non-constant expression"); - return expr->u.nVal; -} diff --git a/src/asm/globlex.c b/src/asm/globlex.c index e591cd1a..44881a96 100644 --- a/src/asm/globlex.c +++ b/src/asm/globlex.c @@ -14,7 +14,6 @@ #include #include "asm/asm.h" -#include "asm/constexpr.h" #include "asm/lexer.h" #include "asm/main.h" #include "asm/rpn.h" diff --git a/src/asm/lexer.c b/src/asm/lexer.c index 6d457901..23e00e0c 100644 --- a/src/asm/lexer.c +++ b/src/asm/lexer.c @@ -15,7 +15,6 @@ #include #include "asm/asm.h" -#include "asm/constexpr.h" #include "asm/fstack.h" #include "asm/lexer.h" #include "asm/main.h" diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 50fb42e3..652b1660 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -23,6 +23,21 @@ #include "asm/output.h" #include "asm/warning.h" +/* Makes an expression "not known", also setting its error message */ +#define makeUnknown(expr_, ...) do { \ + struct Expression *_expr = expr_; \ + _expr->isKnown = false; \ + /* If we had `asprintf` this would be great, but alas. */ \ + _expr->reason = malloc(128); /* Use an initial reasonable size */ \ + if (!_expr->reason) \ + fatalerror("Can't allocate err string: %s", strerror(errno)); \ + int size = snprintf(_expr->reason, 128, __VA_ARGS__); \ + if (size >= 128) { /* If this wasn't enough, try again */ \ + _expr->reason = realloc(_expr->reason, size + 1); \ + sprintf(_expr->reason, __VA_ARGS__); \ + } \ +} while (0) + static uint8_t *reserveSpace(struct Expression *expr, uint32_t size) { /* This assumes the RPN length is always less than the capacity */ @@ -65,6 +80,7 @@ void rpn_Init(struct Expression *expr) expr->nRPNPatchSize = 0; expr->nRPNOut = 0; expr->isKnown = true; + expr->reason = NULL; } /* @@ -73,6 +89,7 @@ void rpn_Init(struct Expression *expr) void rpn_Free(struct Expression *expr) { free(expr->tRPN); + free(expr->reason); rpn_Init(expr); } @@ -111,7 +128,7 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) if (!sym || !sym_IsConstant(sym)) { rpn_Init(expr); sym_Ref(tzSym); - expr->isKnown = false; + makeUnknown(expr, "'%s' is not defined", tzSym); expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */ size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */ @@ -136,7 +153,7 @@ void rpn_BankSelf(struct Expression *expr) rpn_Init(expr); if (pCurrentSection->nBank == -1) - expr->isKnown = false; + makeUnknown(expr, "Current section's bank is not known"); else expr->nVal = pCurrentSection->nBank; @@ -173,7 +190,7 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym) /* Symbol's section is known and bank is fixed */ expr->nVal = pSymbol->pSection->nBank; else - expr->isKnown = false; + makeUnknown(expr, "\"%s\"'s bank is not known", tzSym); } } @@ -186,7 +203,8 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName) if (pSection && pSection->nBank != -1) expr->nVal = pSection->nBank; else - expr->isKnown = false; + makeUnknown(expr, "Section \"%s\"'s bank is not known", + tzSectionName); size_t nameLen = strlen(tzSectionName) + 1; /* Don't forget NUL! */ uint8_t *ptr = reserveSpace(expr, nameLen + 1); @@ -234,9 +252,6 @@ void rpn_LOGNOT(struct Expression *expr, const struct Expression *src) 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) { @@ -346,50 +361,46 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, 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 (src2->nVal < 0) + warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %d", + 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); + if (src1->nVal < 0) + warning(WARNING_SHIFT, "Shifting negative value %d", + src1->nVal); - expr->nVal = shift(src1->nVal, -src2->nVal); - } + if (src2->nVal < 0) + warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %d", + src2->nVal); + + 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 (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; - } + 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 (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; - } + if (src1->nVal == INT32_MIN && src2->nVal == -1) + expr->nVal = 0; + else + expr->nVal = src1->nVal % src2->nVal; break; case RPN_UNSUB: @@ -425,12 +436,18 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, expr->nRPNLength = 0; memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes)); + + /* Use the other expression's un-const reason */ + expr->reason = src2->reason; + free(src1->reason); } else { /* Otherwise just reuse its RPN buffer */ expr->nRPNPatchSize = src1->nRPNPatchSize; expr->tRPN = src1->tRPN; expr->nRPNCapacity = src1->nRPNCapacity; expr->nRPNLength = src1->nRPNLength; + expr->reason = src1->reason; + free(src2->reason); } /* Now, merge the right expression into the left one */ diff --git a/test/asm/bank.err b/test/asm/bank.err index 6623e217..9654dbce 100644 --- a/test/asm/bank.err +++ b/test/asm/bank.err @@ -1,9 +1,9 @@ ERROR: bank.asm(14) -> bank.asm::def_sect(8): - Section "ROMX_bad"'s bank is not known yet + Expected constant expression: Section "ROMX_bad"'s bank is not known ERROR: bank.asm(16) -> bank.asm::def_sect(8): - Section "VRAM_bad"'s bank is not known yet + Expected constant expression: Section "VRAM_bad"'s bank is not known ERROR: bank.asm(18) -> bank.asm::def_sect(8): - Section "SRAM_bad"'s bank is not known yet + Expected constant expression: Section "SRAM_bad"'s bank is not known ERROR: bank.asm(21) -> bank.asm::def_sect(8): - Section "WRAMX_bad"'s bank is not known yet + Expected constant expression: Section "WRAMX_bad"'s bank is not known error: Assembly aborted (4 errors)! diff --git a/test/asm/overflow.err b/test/asm/overflow.err index 03071f3f..8ed2aa85 100644 --- a/test/asm/overflow.err +++ b/test/asm/overflow.err @@ -2,8 +2,6 @@ warning: overflow.asm(24): [-Wdiv] Division of min value by -1 warning: overflow.asm(25): [-Wdiv] Division of min value by -1 -warning: overflow.asm(35): [-Wshift] - Shifting negative value -1 warning: overflow.asm(39): [-Wlarge-constant] Integer constant '4294967296' is too large warning: overflow.asm(42): [-Wlarge-constant] diff --git a/test/asm/pc-bank.err b/test/asm/pc-bank.err index e81e10cf..3c165fb9 100644 --- a/test/asm/pc-bank.err +++ b/test/asm/pc-bank.err @@ -1,5 +1,5 @@ ERROR: pc-bank.asm(2): Source address $2a00 not in $FF00 to $FFFF ERROR: pc-bank.asm(11): - Current bank is not known yet + Expected constant expression: Current section's bank is not known error: Assembly aborted (2 errors)! diff --git a/test/asm/shift.err b/test/asm/shift.err index aea9476e..ba1c7543 100644 --- a/test/asm/shift.err +++ b/test/asm/shift.err @@ -6,18 +6,12 @@ warning: shift.asm(14) -> shift.asm::test(3): [-Wshift-amount] Shifting left by large amount 9001 warning: shift.asm(14) -> shift.asm::test(6): [-Wshift-amount] Shifting left by large amount 9001 -warning: shift.asm(15) -> shift.asm::test(3): [-Wshift] - Shifting negative value -1 -warning: shift.asm(16) -> shift.asm::test(3): [-Wshift] - Shifting negative value -1 warning: shift.asm(16) -> shift.asm::test(3): [-Wshift-amount] Shifting left by large amount 32 warning: shift.asm(16) -> shift.asm::test(6): [-Wshift-amount] Shifting left by large amount 32 warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount] - Shifting left by negative value: -9001 -warning: shift.asm(17) -> shift.asm::test(3): [-Wshift] - Shifting negative value -1 + Shifting left by negative amount -9001 warning: shift.asm(17) -> shift.asm::test(3): [-Wshift-amount] Shifting right by large amount 9001 warning: shift.asm(17) -> shift.asm::test(6): [-Wshift-amount] @@ -52,15 +46,15 @@ warning: shift.asm(23) -> shift.asm::test(3): [-Wshift] Shifting negative value -4 warning: shift.asm(23) -> shift.asm::test(6): [-Wshift] Shifting negative value -4 -warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount] - Shifting right by negative value: -9001 warning: shift.asm(24) -> shift.asm::test(3): [-Wshift] Shifting negative value -1 warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount] - Shifting left by large amount 9001 -warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount] Shifting right by negative amount -9001 +warning: shift.asm(24) -> shift.asm::test(3): [-Wshift-amount] + Shifting left by large amount 9001 warning: shift.asm(24) -> shift.asm::test(6): [-Wshift] Shifting negative value -1 +warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount] + Shifting right by negative amount -9001 warning: shift.asm(24) -> shift.asm::test(6): [-Wshift-amount] Shifting left by large amount 9001 From 5014f55c482c4c45f7bf09cb6a5a4aa37ffdb04f Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 21 Jan 2020 01:05:29 +0100 Subject: [PATCH 09/16] Treat PC as a symbol as well --- include/asm/rpn.h | 4 +++- src/asm/rpn.c | 28 ++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/include/asm/rpn.h b/include/asm/rpn.h index f8bcdc63..38de7fc1 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -17,9 +17,10 @@ #define MAXRPNLEN 1048576 struct Expression { - bool isKnown; // Whether the expression's value is known int32_t nVal; // If the expression's value is known, it's here char *reason; // Why the expression is not known, if it isn't + bool isKnown; // Whether the expression's value is known + bool isSymbol; // Whether the expression represents a symbol uint8_t *tRPN; // Array of bytes serializing the RPN expression uint32_t nRPNCapacity; // Size of the `tRPN` buffer uint32_t nRPNLength; // Used size of the `tRPN` buffer @@ -32,6 +33,7 @@ struct Expression { extern int32_t nPCOffset; bool rpn_isKnown(const struct Expression *expr); +bool rpn_isSymbol(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); diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 652b1660..14b5cf87 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -74,13 +74,14 @@ static uint8_t *reserveSpace(struct Expression *expr, uint32_t size) */ void rpn_Init(struct Expression *expr) { + expr->reason = NULL; + expr->isKnown = true; + expr->isSymbol = false; expr->tRPN = NULL; expr->nRPNCapacity = 0; expr->nRPNLength = 0; expr->nRPNPatchSize = 0; expr->nRPNOut = 0; - expr->isKnown = true; - expr->reason = NULL; } /* @@ -112,6 +113,14 @@ bool rpn_isKnown(const struct Expression *expr) return expr->isKnown; } +/* + * Determine if the current expression is a symbol suitable for const diffing + */ +bool rpn_isSymbol(const struct Expression *expr) +{ + return expr->isSymbol; +} + /* * Add symbols, constants and operators to expression */ @@ -127,6 +136,8 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) if (!sym || !sym_IsConstant(sym)) { rpn_Init(expr); + expr->isSymbol = true; + sym_Ref(tzSym); makeUnknown(expr, "'%s' is not defined", tzSym); expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */ @@ -142,6 +153,8 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) rpn_Number(&offset, nPCOffset); rpn_BinaryOp(RPN_SUB, expr, &pc, &offset); + if (!rpn_isKnown(expr)) + expr->isSymbol = true; } } else { rpn_Number(expr, sym_GetConstantValue(tzSym)); @@ -217,6 +230,7 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName) void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src) { *expr = *src; + expr->isSymbol = false; if (rpn_isKnown(expr)) { /* TODO */ @@ -241,6 +255,7 @@ void rpn_CheckRST(struct Expression *expr, const struct Expression *src) void rpn_LOGNOT(struct Expression *expr, const struct Expression *src) { *expr = *src; + expr->isSymbol = false; if (rpn_isKnown(expr)) { expr->nVal = !expr->nVal; @@ -291,8 +306,7 @@ static int32_t shift(int32_t shiftee, int32_t amount) static struct sSymbol const *symbolOf(struct Expression const *expr) { - /* If an expression starts with a symbol ref... */ - if (!expr->tRPN || expr->tRPN[0] != RPN_SYM || expr->nRPNPatchSize != 5) + if (!rpn_isSymbol(expr)) return NULL; return sym_FindSymbol((char *)expr->tRPN + 1); } @@ -314,6 +328,8 @@ static bool isDiffConstant(struct Expression const *src1, void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, const struct Expression *src1, const struct Expression *src2) { + expr->isSymbol = false; + /* First, check if the expression is known */ expr->isKnown = src1->isKnown && src2->isKnown; if (expr->isKnown) { @@ -478,6 +494,7 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, void rpn_HIGH(struct Expression *expr, const struct Expression *src) { *expr = *src; + expr->isSymbol = false; if (rpn_isKnown(expr)) { expr->nVal = (uint32_t)expr->nVal >> 8 & 0xFF; @@ -492,6 +509,7 @@ void rpn_HIGH(struct Expression *expr, const struct Expression *src) void rpn_LOW(struct Expression *expr, const struct Expression *src) { *expr = *src; + expr->isSymbol = false; if (rpn_isKnown(expr)) { expr->nVal = expr->nVal & 0xFF; @@ -506,6 +524,7 @@ void rpn_LOW(struct Expression *expr, const struct Expression *src) void rpn_UNNEG(struct Expression *expr, const struct Expression *src) { *expr = *src; + expr->isSymbol = false; if (rpn_isKnown(expr)) { expr->nVal = -(uint32_t)expr->nVal; @@ -518,6 +537,7 @@ void rpn_UNNEG(struct Expression *expr, const struct Expression *src) void rpn_UNNOT(struct Expression *expr, const struct Expression *src) { *expr = *src; + expr->isSymbol = false; if (rpn_isKnown(expr)) { expr->nVal = ~expr->nVal; From 4e8b34f42edef9a3ad5de95f3cb79132dad04c46 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 21 Jan 2020 00:19:58 +0100 Subject: [PATCH 10/16] Improve error message when a symbol is not constant --- src/asm/symbol.c | 2 +- test/asm/bracketed-symbols.err | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/asm/symbol.c b/src/asm/symbol.c index af9068f4..83452eb7 100644 --- a/src/asm/symbol.c +++ b/src/asm/symbol.c @@ -269,7 +269,7 @@ uint32_t sym_GetConstantValue(char const *s) if (sym_IsConstant(psym)) return getvaluefield(psym); - fatalerror("Expression must have a constant value"); + fatalerror("\"%s\" does not have a constant value", s); } yyerror("'%s' not defined", s); diff --git a/test/asm/bracketed-symbols.err b/test/asm/bracketed-symbols.err index 14a9a9e6..b6c44e82 100644 --- a/test/asm/bracketed-symbols.err +++ b/test/asm/bracketed-symbols.err @@ -1,4 +1,4 @@ ERROR: bracketed-symbols.asm(16): Print types are only allowed for numbers ERROR: bracketed-symbols.asm(20): - Expression must have a constant value + "Label" does not have a constant value From d466cab1e8aca877e9fd89433f19cec78f894a99 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 21 Jan 2020 00:25:18 +0100 Subject: [PATCH 11/16] Init RPN expressions created by binary operators --- src/asm/rpn.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 14b5cf87..3991becb 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -333,6 +333,8 @@ void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr, /* First, check if the expression is known */ expr->isKnown = src1->isKnown && src2->isKnown; if (expr->isKnown) { + rpn_Init(expr); /* Init the expression to something sane */ + /* If both expressions are known, just compute the value */ uint32_t uleft = src1->nVal, uright = src2->nVal; From 155040240dd49fc92a1986ae963759d715ae1bd2 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 21 Jan 2020 00:25:47 +0100 Subject: [PATCH 12/16] Improve error message when a symbol's value is not constant --- src/asm/rpn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/asm/rpn.c b/src/asm/rpn.c index 3991becb..aa7d1e68 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -139,7 +139,8 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) expr->isSymbol = true; sym_Ref(tzSym); - makeUnknown(expr, "'%s' is not defined", tzSym); + makeUnknown(expr, "'%s' is not constant at assembly time", + tzSym); expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */ size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */ From 63054ae0fd5fa5292f0ebab63efb1f9fe035d378 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 21 Jan 2020 00:36:13 +0100 Subject: [PATCH 13/16] Make more functions ignore the RPN buffer when constant --- src/asm/rpn.c | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/asm/rpn.c b/src/asm/rpn.c index aa7d1e68..abc6fe6a 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -166,13 +166,13 @@ void rpn_BankSelf(struct Expression *expr) { rpn_Init(expr); - if (pCurrentSection->nBank == -1) + if (pCurrentSection->nBank == -1) { makeUnknown(expr, "Current section's bank is not known"); - else + expr->nRPNPatchSize++; + *reserveSpace(expr, 1) = RPN_BANK_SELF; + } else { expr->nVal = pCurrentSection->nBank; - - *reserveSpace(expr, 1) = RPN_BANK_SELF; - expr->nRPNPatchSize++; + } } void rpn_BankSymbol(struct Expression *expr, char *tzSym) @@ -190,21 +190,21 @@ void rpn_BankSymbol(struct Expression *expr, char *tzSym) yyerror("BANK argument must be a relocatable identifier"); } else { sym_Ref(tzSym); - expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte sect ID */ - - size_t nameLen = strlen(tzSym) + 1; /* Don't forget NUL! */ - uint8_t *ptr = reserveSpace(expr, nameLen + 1); - *ptr++ = RPN_BANK_SYM; - memcpy(ptr, tzSym, nameLen); - /* If the symbol didn't exist, `sym_Ref` created it */ struct sSymbol *pSymbol = sym_FindSymbol(tzSym); - if (pSymbol->pSection && pSymbol->pSection->nBank != -1) + if (pSymbol->pSection && pSymbol->pSection->nBank != -1) { /* Symbol's section is known and bank is fixed */ expr->nVal = pSymbol->pSection->nBank; - else + } else { makeUnknown(expr, "\"%s\"'s bank is not known", tzSym); + expr->nRPNPatchSize += 5; /* opcode + 4-byte sect ID */ + + size_t nameLen = strlen(tzSym) + 1; /* Room for NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); + *ptr++ = RPN_BANK_SYM; + memcpy(ptr, tzSym, nameLen); + } } } @@ -214,18 +214,19 @@ void rpn_BankSection(struct Expression *expr, char *tzSectionName) struct Section *pSection = out_FindSectionByName(tzSectionName); - if (pSection && pSection->nBank != -1) + if (pSection && pSection->nBank != -1) { expr->nVal = pSection->nBank; - else + } else { makeUnknown(expr, "Section \"%s\"'s bank is not known", tzSectionName); - size_t nameLen = strlen(tzSectionName) + 1; /* Don't forget NUL! */ - uint8_t *ptr = reserveSpace(expr, nameLen + 1); + size_t nameLen = strlen(tzSectionName) + 1; /* Room for NUL! */ + uint8_t *ptr = reserveSpace(expr, nameLen + 1); - expr->nRPNPatchSize += nameLen + 1; - *ptr++ = RPN_BANK_SECT; - memcpy(ptr, tzSectionName, nameLen); + expr->nRPNPatchSize += nameLen + 1; + *ptr++ = RPN_BANK_SECT; + memcpy(ptr, tzSectionName, nameLen); + } } void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src) From ab1eb146c925498d3aaf31112dd5bd590032b794 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Fri, 7 Feb 2020 14:46:17 +0100 Subject: [PATCH 14/16] Print special message when PC is not constant --- src/asm/rpn.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/asm/rpn.c b/src/asm/rpn.c index abc6fe6a..aceed207 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -139,7 +139,9 @@ void rpn_Symbol(struct Expression *expr, char *tzSym) expr->isSymbol = true; sym_Ref(tzSym); - makeUnknown(expr, "'%s' is not constant at assembly time", + makeUnknown(expr, strcmp(tzSym, "@") + ? "'%s' is not constant at assembly time" + : "PC is not constant at assembly time", tzSym); expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */ From 818a0d029622d7b38228b948c422dffb3a92c552 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Fri, 7 Feb 2020 14:53:28 +0100 Subject: [PATCH 15/16] Test more cases in `label-diff` test --- test/asm/label-diff.asm | 16 ++++++++-------- test/asm/label-diff.err | 33 +++++++++++++++++++++++++++++++++ test/asm/label-diff.out | 16 ++++++++++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/test/asm/label-diff.asm b/test/asm/label-diff.asm index c331d6e0..493def1e 100644 --- a/test/asm/label-diff.asm +++ b/test/asm/label-diff.asm @@ -31,20 +31,20 @@ POPS ; Ensure we are in neither section ; Diffing two labels in the same SECTION as well print_diff Known2, Known ; Diffing a constant and a "floating" label cannot work -; ...And that causes a fatal error print_diff Constant, Known + print_diff Constant, Known ; Diffing a constant and a ref cannot work -; ...And that causes a fatal error print_diff Constant, Unknown + print_diff Constant, Unknown ; Diffing a floating label and a ref cannot work -; ...And that causes a fatal error print_diff Known, Unknown + print_diff Known, Unknown ; Now let's fiddle with PC SECTION "fixed PC", ROM0[420] ; Diffing a constant and PC should work print_diff Constant, @ ; Diffing a floating label and PC cannot work -; ...And that causes a fatal error print_diff Known, @ + print_diff Known, @ ; Diffinf a ref and PC cannot work -; ...And that causes a fatal error print_diff Unknown, @ + print_diff Unknown, @ ; Diffing PC and PC should work print_diff @, @ ; Diffing PC and a label from here should work @@ -53,11 +53,11 @@ LocalFixed: SECTION "Floating PC", ROM0 ; Diffing a constant and PC cannot work -; ...And that causes a fatal error print_diff Constant, @ + print_diff Constant, @ ; Diffing a floating label and PC cannot work -; ...And that causes a fatal error print_diff Known, @ + print_diff Known, @ ; Diffinf a ref and PC cannot work -; ...And that causes a fatal error print_diff Unknown, @ + print_diff Unknown, @ ; Diffing PC and PC should work print_diff @, @ ; Diffing PC and a label from here should work diff --git a/test/asm/label-diff.err b/test/asm/label-diff.err index e69de29b..f6a2d763 100644 --- a/test/asm/label-diff.err +++ b/test/asm/label-diff.err @@ -0,0 +1,33 @@ +ERROR: label-diff.asm(34) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(34) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(36) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(36) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(45) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(45) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(56) -> label-diff.asm::print_diff(20): + Expected constant expression: PC is not constant at assembly time +ERROR: label-diff.asm(56) -> label-diff.asm::print_diff(22): + Expected constant expression: PC is not constant at assembly time +ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(22): + Expected constant expression: PC is not constant at assembly time +ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(22): + Expected constant expression: PC is not constant at assembly time +error: Assembly aborted (16 errors)! diff --git a/test/asm/label-diff.out b/test/asm/label-diff.out index 67533371..2ec5e077 100644 --- a/test/asm/label-diff.out +++ b/test/asm/label-diff.out @@ -2,6 +2,12 @@ $FFFFFFE5 $1B $4 $FFFFFFFC +$0 +$0 +$0 +$0 +$0 +$0 $FFFFFE86 $17A $0 @@ -12,3 +18,13 @@ $0 $0 $0 $0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 +$0 From 1d70c989be64fffab08902c1660b4749c7d16207 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 10 Feb 2020 02:55:51 +0100 Subject: [PATCH 16/16] Test one more label diff case --- test/asm/label-diff.asm | 2 ++ test/asm/label-diff.err | 32 ++++++++++++++++++-------------- test/asm/label-diff.out | 2 ++ 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/test/asm/label-diff.asm b/test/asm/label-diff.asm index 493def1e..fa81e945 100644 --- a/test/asm/label-diff.asm +++ b/test/asm/label-diff.asm @@ -36,6 +36,8 @@ POPS ; Ensure we are in neither section print_diff Constant, Unknown ; Diffing a floating label and a ref cannot work print_diff Known, Unknown + ; Diffing two refs cannot work + print_diff Unknown, Unknown2 ; Now let's fiddle with PC SECTION "fixed PC", ROM0[420] diff --git a/test/asm/label-diff.err b/test/asm/label-diff.err index f6a2d763..f098b2bc 100644 --- a/test/asm/label-diff.err +++ b/test/asm/label-diff.err @@ -10,24 +10,28 @@ ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(20): Expected constant expression: 'Known' is not constant at assembly time ERROR: label-diff.asm(38) -> label-diff.asm::print_diff(22): Expected constant expression: 'Unknown' is not constant at assembly time -ERROR: label-diff.asm(45) -> label-diff.asm::print_diff(20): - Expected constant expression: 'Known' is not constant at assembly time -ERROR: label-diff.asm(45) -> label-diff.asm::print_diff(22): - Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(40) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(40) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown2' is not constant at assembly time ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(20): - Expected constant expression: 'Unknown' is not constant at assembly time -ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(22): - Expected constant expression: 'Unknown' is not constant at assembly time -ERROR: label-diff.asm(56) -> label-diff.asm::print_diff(20): - Expected constant expression: PC is not constant at assembly time -ERROR: label-diff.asm(56) -> label-diff.asm::print_diff(22): - Expected constant expression: PC is not constant at assembly time -ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(20): Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(47) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Known' is not constant at assembly time +ERROR: label-diff.asm(49) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(49) -> label-diff.asm::print_diff(22): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(20): + Expected constant expression: PC is not constant at assembly time ERROR: label-diff.asm(58) -> label-diff.asm::print_diff(22): Expected constant expression: PC is not constant at assembly time ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(20): - Expected constant expression: 'Unknown' is not constant at assembly time + Expected constant expression: 'Known' is not constant at assembly time ERROR: label-diff.asm(60) -> label-diff.asm::print_diff(22): Expected constant expression: PC is not constant at assembly time -error: Assembly aborted (16 errors)! +ERROR: label-diff.asm(62) -> label-diff.asm::print_diff(20): + Expected constant expression: 'Unknown' is not constant at assembly time +ERROR: label-diff.asm(62) -> label-diff.asm::print_diff(22): + Expected constant expression: PC is not constant at assembly time +error: Assembly aborted (18 errors)! diff --git a/test/asm/label-diff.out b/test/asm/label-diff.out index 2ec5e077..bb02119d 100644 --- a/test/asm/label-diff.out +++ b/test/asm/label-diff.out @@ -8,6 +8,8 @@ $0 $0 $0 $0 +$0 +$0 $FFFFFE86 $17A $0