Use std::deque<std::vector> for free space (#1323)

This commit is contained in:
Sylvie
2024-03-01 16:21:29 -05:00
committed by GitHub
parent 1ac3c0262f
commit 446fb07fd5
2 changed files with 62 additions and 101 deletions

View File

@@ -6,6 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <vector>
#include "link/assign.hpp" #include "link/assign.hpp"
#include "link/section.hpp" #include "link/section.hpp"
@@ -27,11 +28,10 @@ struct MemoryLocation {
struct FreeSpace { struct FreeSpace {
uint16_t address; uint16_t address;
uint16_t size; uint16_t size;
FreeSpace *next, *prev;
}; };
// Table of free space for each bank // Table of free space for each bank
FreeSpace *memory[SECTTYPE_INVALID]; std::vector<std::deque<FreeSpace>> memory[SECTTYPE_INVALID];
uint64_t nbSectionsToAssign; uint64_t nbSectionsToAssign;
@@ -39,20 +39,12 @@ uint64_t nbSectionsToAssign;
static void initFreeSpace() static void initFreeSpace()
{ {
for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) { for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) {
memory[type] = (FreeSpace *)malloc(sizeof(*memory[type]) * nbbanks(type)); memory[type].resize(nbbanks(type));
if (!memory[type]) for (std::deque<FreeSpace> &bankMem : memory[type]) {
err("Failed to init free space for region %d", type); bankMem.push_back({
.address = sectionTypeInfo[type].startAddr,
for (uint32_t bank = 0; bank < nbbanks(type); bank++) { .size = sectionTypeInfo[type].size
memory[type][bank].next = });
(FreeSpace *)malloc(sizeof(*memory[type][0].next));
if (!memory[type][bank].next)
err("Failed to init free space for region %d bank %" PRIu32,
type, bank);
memory[type][bank].next->address = sectionTypeInfo[type].startAddr;
memory[type][bank].next->size = sectionTypeInfo[type].size;
memory[type][bank].next->next = nullptr;
memory[type][bank].next->prev = &memory[type][bank];
} }
} }
} }
@@ -88,7 +80,7 @@ static void assignSection(Section *section, MemoryLocation const *location)
* @param location The location to attempt placing the section at * @param location The location to attempt placing the section at
* @return True if the location is suitable, false otherwise. * @return True if the location is suitable, false otherwise.
*/ */
static bool isLocationSuitable(Section const *section, FreeSpace const *freeSpace, static bool isLocationSuitable(Section const *section, FreeSpace const &freeSpace,
MemoryLocation const *location) MemoryLocation const *location)
{ {
if (section->isAddressFixed && section->org != location->address) if (section->isAddressFixed && section->org != location->address)
@@ -97,20 +89,23 @@ static bool isLocationSuitable(Section const *section, FreeSpace const *freeSpac
if (section->isAlignFixed && ((location->address - section->alignOfs) & section->alignMask)) if (section->isAlignFixed && ((location->address - section->alignOfs) & section->alignMask))
return false; return false;
if (location->address < freeSpace->address) if (location->address < freeSpace.address)
return false; return false;
return location->address + section->size <= freeSpace->address + freeSpace->size; return location->address + section->size <= freeSpace.address + freeSpace.size;
} }
/* /*
* Finds a suitable location to place a section at. * Finds a suitable location to place a section at.
* @param section The section to be placed * @param section The section to be placed
* @param location A pointer to a memory location that will be filled * @param location A pointer to a memory location that will be filled
* @return A pointer to the free space encompassing the location, or `nullptr` if none was found * @return The index into `memory[section->type]` of the free space encompassing the location,
* or -1 if none was found
*/ */
static FreeSpace *getPlacement(Section const *section, MemoryLocation *location) static ssize_t getPlacement(Section const *section, MemoryLocation *location)
{ {
SectionTypeInfo const &typeInfo = sectionTypeInfo[section->type];
static uint16_t curScrambleROM = 0; static uint16_t curScrambleROM = 0;
static uint8_t curScrambleWRAM = 0; static uint8_t curScrambleWRAM = 0;
static int8_t curScrambleSRAM = 0; static int8_t curScrambleSRAM = 0;
@@ -131,22 +126,22 @@ static FreeSpace *getPlacement(Section const *section, MemoryLocation *location)
curScrambleSRAM = scrambleSRAM; curScrambleSRAM = scrambleSRAM;
location->bank = curScrambleSRAM--; location->bank = curScrambleSRAM--;
} else { } else {
location->bank = sectionTypeInfo[section->type].firstBank; location->bank = typeInfo.firstBank;
} }
FreeSpace *space;
for (;;) { for (;;) {
// Switch to the beginning of the next bank // Switch to the beginning of the next bank
#define BANK_INDEX (location->bank - sectionTypeInfo[section->type].firstBank) std::deque<FreeSpace> &bankMem = memory[section->type][location->bank - typeInfo.firstBank];
space = memory[section->type][BANK_INDEX].next; size_t spaceIdx = 0;
if (space)
location->address = space->address; if (spaceIdx < bankMem.size())
location->address = bankMem[spaceIdx].address;
// Process locations in that bank // Process locations in that bank
while (space) { while (spaceIdx < bankMem.size()) {
// If that location is OK, return it // If that location is OK, return it
if (isLocationSuitable(section, space, location)) if (isLocationSuitable(section, bankMem[spaceIdx], location))
return space; return spaceIdx;
// Go to the next *possible* location // Go to the next *possible* location
if (section->isAddressFixed) { if (section->isAddressFixed) {
@@ -156,8 +151,7 @@ static FreeSpace *getPlacement(Section const *section, MemoryLocation *location)
if (location->address < section->org) if (location->address < section->org)
location->address = section->org; location->address = section->org;
else else
// Try again in next bank break; // Try again in next bank
space = nullptr;
} else if (section->isAlignFixed) { } else if (section->isAlignFixed) {
// Move to next aligned location // Move to next aligned location
// Move back to alignment boundary // Move back to alignment boundary
@@ -168,15 +162,16 @@ static FreeSpace *getPlacement(Section const *section, MemoryLocation *location)
location->address += section->alignMask + 1 + section->alignOfs; location->address += section->alignMask + 1 + section->alignOfs;
} else { } else {
// Any location is fine, so, next free block // Any location is fine, so, next free block
space = space->next; spaceIdx++;
if (space) if (spaceIdx < bankMem.size())
location->address = space->address; location->address = bankMem[spaceIdx].address;
} }
// If that location is past the current block's end, // If that location is past the current block's end,
// go forwards until that is no longer the case. // go forwards until that is no longer the case.
while (space && location->address >= space->address + space->size) while (spaceIdx < bankMem.size() && location->address >=
space = space->next; bankMem[spaceIdx].address + bankMem[spaceIdx].size)
spaceIdx++;
// Try again with the new location/free space combo // Try again with the new location/free space combo
} }
@@ -185,34 +180,33 @@ static FreeSpace *getPlacement(Section const *section, MemoryLocation *location)
// Try scrambled banks in descending order until no bank in the scrambled range is available. // Try scrambled banks in descending order until no bank in the scrambled range is available.
// Otherwise, try in ascending order. // Otherwise, try in ascending order.
if (section->isBankFixed) { if (section->isBankFixed) {
return nullptr; return -1;
} else if (scrambleROMX && section->type == SECTTYPE_ROMX && location->bank <= scrambleROMX) { } else if (scrambleROMX && section->type == SECTTYPE_ROMX && location->bank <= scrambleROMX) {
if (location->bank > sectionTypeInfo[section->type].firstBank) if (location->bank > typeInfo.firstBank)
location->bank--; location->bank--;
else if (scrambleROMX < sectionTypeInfo[section->type].lastBank) else if (scrambleROMX < typeInfo.lastBank)
location->bank = scrambleROMX + 1; location->bank = scrambleROMX + 1;
else else
return nullptr; return -1;
} else if (scrambleWRAMX && section->type == SECTTYPE_WRAMX && location->bank <= scrambleWRAMX) { } else if (scrambleWRAMX && section->type == SECTTYPE_WRAMX && location->bank <= scrambleWRAMX) {
if (location->bank > sectionTypeInfo[section->type].firstBank) if (location->bank > typeInfo.firstBank)
location->bank--; location->bank--;
else if (scrambleWRAMX < sectionTypeInfo[section->type].lastBank) else if (scrambleWRAMX < typeInfo.lastBank)
location->bank = scrambleWRAMX + 1; location->bank = scrambleWRAMX + 1;
else else
return nullptr; return -1;
} else if (scrambleSRAM && section->type == SECTTYPE_SRAM && location->bank <= scrambleSRAM) { } else if (scrambleSRAM && section->type == SECTTYPE_SRAM && location->bank <= scrambleSRAM) {
if (location->bank > sectionTypeInfo[section->type].firstBank) if (location->bank > typeInfo.firstBank)
location->bank--; location->bank--;
else if (scrambleSRAM < sectionTypeInfo[section->type].lastBank) else if (scrambleSRAM < typeInfo.lastBank)
location->bank = scrambleSRAM + 1; location->bank = scrambleSRAM + 1;
else else
return nullptr; return -1;
} else if (location->bank < sectionTypeInfo[section->type].lastBank) { } else if (location->bank < typeInfo.lastBank) {
location->bank++; location->bank++;
} else { } else {
return nullptr; return -1;
} }
#undef BANK_INDEX
} }
} }
@@ -242,49 +236,35 @@ static void placeSection(Section *section)
// Place section using first-fit decreasing algorithm // Place section using first-fit decreasing algorithm
// https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm // https://en.wikipedia.org/wiki/Bin_packing_problem#First-fit_algorithm
FreeSpace *freeSpace = getPlacement(section, &location); if (ssize_t spaceIdx = getPlacement(section, &location); spaceIdx != -1) {
std::deque<FreeSpace> &bankMem = memory[section->type][location.bank -
sectionTypeInfo[section->type].firstBank];
FreeSpace &freeSpace = bankMem[spaceIdx];
if (freeSpace) {
assignSection(section, &location); assignSection(section, &location);
// Split the free space // Update the free space
bool noLeftSpace = freeSpace->address == section->org; bool noLeftSpace = freeSpace.address == section->org;
bool noRightSpace = freeSpace->address + freeSpace->size bool noRightSpace = freeSpace.address + freeSpace.size == section->org + section->size;
== section->org + section->size;
if (noLeftSpace && noRightSpace) { if (noLeftSpace && noRightSpace) {
// The free space is entirely deleted // The free space is entirely deleted
freeSpace->prev->next = freeSpace->next; bankMem.erase(bankMem.begin() + spaceIdx);
if (freeSpace->next)
freeSpace->next->prev = freeSpace->prev;
// If the space is the last one on the list, set its
// size to 0 so it doesn't get picked, but don't free()
// it as it will be freed when cleaning up
free(freeSpace);
} else if (!noLeftSpace && !noRightSpace) { } else if (!noLeftSpace && !noRightSpace) {
// The free space is split in two // The free space is split in two
FreeSpace *newSpace = (FreeSpace *)malloc(sizeof(*newSpace)); // Append the new space after the original one
bankMem.insert(bankMem.begin() + spaceIdx + 1, {
if (!newSpace) .address = (uint16_t)(section->org + section->size),
err("Failed to split new free space"); .size = (uint16_t)(freeSpace.address + freeSpace.size -
// Append the new space after the chosen one section->org - section->size)
newSpace->prev = freeSpace; });
newSpace->next = freeSpace->next; // Resize the original space (address is unmodified)
if (freeSpace->next) freeSpace.size = section->org - freeSpace.address;
freeSpace->next->prev = newSpace;
freeSpace->next = newSpace;
// Set its parameters
newSpace->address = section->org + section->size;
newSpace->size = freeSpace->address + freeSpace->size -
newSpace->address;
// Set the original space's new parameters
freeSpace->size = section->org - freeSpace->address;
// address is unmodified
} else { } else {
// The amount of free spaces doesn't change: resize! // The amount of free spaces doesn't change: resize!
freeSpace->size -= section->size; freeSpace.size -= section->size;
if (noLeftSpace) if (noLeftSpace)
// The free space is moved *and* resized // The free space is moved *and* resized
freeSpace->address += section->size; freeSpace.address += section->size;
} }
return; return;
} }
@@ -417,21 +397,3 @@ max_out:
unreachable_(); unreachable_();
} }
void assign_Cleanup()
{
for (enum SectionType type : EnumSeq(SECTTYPE_INVALID)) {
for (uint32_t bank = 0; bank < nbbanks(type); bank++) {
FreeSpace *ptr = memory[type][bank].next;
while (ptr) {
FreeSpace *next = ptr->next;
free(ptr);
ptr = next;
}
}
free(memory[type]);
}
}

View File

@@ -470,7 +470,6 @@ int main(int argc, char *argv[])
reportErrors(); reportErrors();
assign_AssignSections(); assign_AssignSections();
obj_CheckAssertions(); obj_CheckAssertions();
assign_Cleanup();
// and finally output the result. // and finally output the result.
patch_ApplyPatches(); patch_ApplyPatches();