Compare commits

..

2 Commits

Author SHA1 Message Date
Rangi42
df5162edca Use loops instead of tail calls and musttail
gcc 15.2.1 20250813 complains "address of automatic variable can
escape to `musttail` call" from `-Wmaybe-musttail-local-addr`,
and guaranteeing tail-call optimization cross-platform is more
trouble than it's worth.
2025-10-27 12:05:27 -04:00
Rangi42
2519d1e698 Mention REDEF and FOR regarding EQUS expansion
Fixes #1851
2025-10-27 10:54:16 -04:00
4 changed files with 116 additions and 124 deletions

View File

@@ -60,13 +60,4 @@
#define _POSIX_C_SOURCE 200809L
#endif
// gcc and clang have their own `musttail` attributes for tail recursion
#if defined(__clang__) && __has_cpp_attribute(clang::musttail)
#define MUSTTAIL [[clang::musttail]]
#elif defined(__GNUC__) && __has_cpp_attribute(gnu::musttail)
#define MUSTTAIL [[gnu::musttail]]
#else
#define MUSTTAIL
#endif
#endif // RGBDS_PLATFORM_HPP

View File

@@ -154,6 +154,8 @@ of string constants:
will be expanded in all of
.Ql DEF({name}) ,
.Ql DEF {name} EQU/=/EQUS/etc ... ,
.Ql REDEF {name} EQU/=/EQUS/etc ... ,
.Ql FOR {name}, ... ,
.Ql PURGE {name} ,
and
.Ql MACRO {name} ,
@@ -1556,6 +1558,8 @@ in the C programming language.
This expansion is disabled in a few contexts:
.Ql DEF(name) ,
.Ql DEF name EQU/=/EQUS/etc ... ,
.Ql REDEF name EQU/=/EQUS/etc ... ,
.Ql FOR name, ... ,
.Ql PURGE name ,
and
.Ql MACRO name

View File

@@ -716,6 +716,7 @@ int LexerState::peekCharAhead() {
static std::pair<Symbol const *, std::shared_ptr<std::string>> readInterpolation(size_t depth);
static int peek() {
for (;;) {
int c = lexerState->peekChar();
if (lexerState->expansionScanDistance > 0) {
@@ -732,7 +733,6 @@ static int peek() {
if (!isMacroChar(lexerState->peekCharAhead())) {
return c;
}
// If character is a macro arg char, do macro arg expansion
shiftChar();
if (std::shared_ptr<std::string> str = readMacroArg(); str) {
@@ -743,20 +743,19 @@ static int peek() {
// https://en.wikipedia.org/wiki/Painted_blue
lexerState->expansionScanDistance += str->length();
}
MUSTTAIL return peek();
// Continue in the next iteration
} else if (c == '{') {
// If character is an open brace, do symbol interpolation
shiftChar();
if (auto interp = readInterpolation(0); interp.first && interp.second) {
beginExpansion(interp.second, interp.first->name);
}
MUSTTAIL return peek();
// Continue in the next iteration
} else {
return c;
}
}
}
static void shiftChar() {
if (lexerState->capturing) {
@@ -1943,8 +1942,6 @@ static Token yylex_NORMAL() {
if (Symbol const *sym = sym_FindExactSymbol(std::get<std::string>(token.value));
sym && sym->type == SYM_EQUS) {
beginExpansion(sym->getEqus(), sym->name);
// We cannot do `MUSTTAIL return yylex_NORMAL();` because tail call optimization
// requires the return value to be "trivially destructible", and `Token` is not.
continue; // Restart, reading from the new buffer
}
}

View File

@@ -15,7 +15,6 @@
#include "helpers.hpp"
#include "itertools.hpp"
#include "linkdefs.hpp"
#include "platform.hpp" // MUSTTAIL
#include "verbosity.hpp"
#include "link/main.hpp"
@@ -119,6 +118,7 @@ static MemoryLocation getStartLocation(Section const &section) {
static std::optional<size_t> getPlacement(Section const &section, MemoryLocation &location) {
SectionTypeInfo const &typeInfo = sectionTypeInfo[section.type];
for (;;) {
// Switch to the beginning of the next bank
std::deque<FreeSpace> &bankMem = memory[section.type][location.bank - typeInfo.firstBank];
size_t spaceIdx = 0;
@@ -137,12 +137,11 @@ static std::optional<size_t> getPlacement(Section const &section, MemoryLocation
// Go to the next *possible* location
if (section.isAddressFixed) {
// If the address is fixed, there can be only one candidate block per bank;
// if we already reached it, give up.
if (location.address < section.org) {
location.address = section.org;
} else {
break; // Try again in next bank
// if we already reached it, give up and try again in the next bank.
if (location.address >= section.org) {
break;
}
location.address = section.org;
} else if (section.isAlignFixed) {
// Move to next aligned location
// Move back to alignment boundary
@@ -204,7 +203,8 @@ static std::optional<size_t> getPlacement(Section const &section, MemoryLocation
return std::nullopt;
}
MUSTTAIL return getPlacement(section, location);
// Try again in the next iteration.
}
}
static std::string getSectionDescription(Section const &section) {