mirror of
https://github.com/cc65/cc65.git
synced 2024-12-27 00:29:31 +00:00
CS_MergeLabels: Keep labels referenced by data
Partial fix for ICE in #1211. This may fix enough to allow #1049 to be fixed. When merging labels, keep the first label with a ref that has no JumpTo; this is a data segment label, used by computed gotos. The real fix is to track and rewrite labels in data, but this is more involved.
This commit is contained in:
parent
037a806036
commit
81550ca1ee
@ -180,6 +180,16 @@ INLINE CodeLabel* CE_GetLabel (CodeEntry* E, unsigned Index)
|
||||
# define CE_GetLabel(E, Index) CollAt (&(E)->Labels, (Index))
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void CE_ReplaceLabel (CodeEntry* E, CodeLabel* L, unsigned Index)
|
||||
/* Replace the code label at the specified index with L */
|
||||
{
|
||||
return CollReplace (&E->Labels, L, Index);
|
||||
}
|
||||
#else
|
||||
# define CE_ReplaceLabel(E, L, Index) CollReplace (&(E)->Labels, (L), (Index))
|
||||
#endif
|
||||
|
||||
void CE_MoveLabel (CodeLabel* L, CodeEntry* E);
|
||||
/* Move the code label L from it's former owner to the code entry E. */
|
||||
|
||||
|
@ -183,6 +183,37 @@ static void CS_RemoveLabelFromHash (CodeSeg* S, CodeLabel* L)
|
||||
|
||||
|
||||
|
||||
static CodeLabel* PickRefLab (CodeEntry* E)
|
||||
/* Pick a reference label and move it to index 0 in E. */
|
||||
{
|
||||
unsigned I;
|
||||
unsigned LabelCount = CE_GetLabelCount (E);
|
||||
CHECK (LabelCount > 0);
|
||||
/* Use either the first one as reference label, or a label with a Ref that has no JumpTo.
|
||||
** This is a hack to partially work around #1211. Refs with no JumpTo are labels used
|
||||
** in data segments. (They are not tracked.) If a data segment is the only reference,
|
||||
** the label will be pruned away, but the data reference will remain, causing linking to fail.
|
||||
*/
|
||||
CodeLabel* L0 = CE_GetLabel (E, 0);
|
||||
for (I = 1; I < LabelCount; ++I) {
|
||||
unsigned J;
|
||||
CodeLabel* L = CE_GetLabel (E, I);
|
||||
unsigned RefCount = CL_GetRefCount (L);
|
||||
for (J = 0; J < RefCount; ++J) {
|
||||
CodeEntry* EJ = CL_GetRef (L, J);
|
||||
if (EJ->JumpTo == NULL) {
|
||||
/* Move it to the beginning since it's simpler to handle the removal this way. */
|
||||
CE_ReplaceLabel (E, L, 0);
|
||||
CE_ReplaceLabel (E, L0, I);
|
||||
return L;
|
||||
}
|
||||
}
|
||||
}
|
||||
return L0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Functions for parsing instructions */
|
||||
/*****************************************************************************/
|
||||
@ -935,8 +966,10 @@ void CS_MergeLabels (CodeSeg* S)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have at least one label. Use the first one as reference label. */
|
||||
RefLab = CE_GetLabel (E, 0);
|
||||
/* Pick a label to keep, all references will be moved to this one, and the other labels
|
||||
** will be deleted. PickRefLab moves this to index 0.
|
||||
*/
|
||||
RefLab = PickRefLab (E);
|
||||
|
||||
/* Walk through the remaining labels and change references to these
|
||||
** labels to a reference to the one and only label. Delete the labels
|
||||
|
@ -21,7 +21,8 @@
|
||||
/*
|
||||
Test of indirect goto with label merge ICE.
|
||||
https://github.com/cc65/cc65/issues/1211
|
||||
This should compile and should be moved to tests/val/ when the bug is fixed.
|
||||
This test case works because CS_MergeLabels has a hack to keep the "unreferenced" label
|
||||
(i.e. the one referenced in a data segment).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
Loading…
Reference in New Issue
Block a user