X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fcodeseg.c;h=325eee20f67558d14d682df3d9a156fce59d73ab;hb=0529c2044a7006eb9092d419a59916acc8522c23;hp=89029350bac47e9a757b8d7f03651592c61b67d9;hpb=f42300ef62779856c7c5c88a9d84c9eb63da31ba;p=cc65 diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index 89029350b..325eee20f 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -62,12 +62,35 @@ +static void CS_MoveLabelsToEntry (CodeSeg* S, CodeEntry* E) +/* Move all labels from the label pool to the given entry and remove them + * from the pool. + */ +{ + /* Transfer the labels if we have any */ + unsigned I; + unsigned LabelCount = CollCount (&S->Labels); + for (I = 0; I < LabelCount; ++I) { + + /* Get the label */ + CodeLabel* L = CollAt (&S->Labels, I); + + /* Attach it to the entry */ + CE_AttachLabel (E, L); + } + + /* Delete the transfered labels */ + CollDeleteAll (&S->Labels); +} + + + static void CS_MoveLabelsToPool (CodeSeg* S, CodeEntry* E) /* Move the labels of the code entry E to the label pool of the code segment */ { unsigned LabelCount = CE_GetLabelCount (E); while (LabelCount--) { - CodeLabel* L = CE_GetLabel (E, LabelCount); + CodeLabel* L = CE_GetLabel (E, LabelCount); L->Owner = 0; CollAppend (&S->Labels, L); } @@ -235,7 +258,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L) L = ReadToken (L+1, ",)", Arg, sizeof (Arg)); /* Check for errors */ - if (*L == '\0') { + if (*L == '\0') { Error ("ASM code error: syntax error"); return 0; } @@ -278,7 +301,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L) AM = AM65_ZP_IND; } else { Error ("ASM code error: syntax error"); - return 0; + return 0; } } break; @@ -321,7 +344,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L) AM = AM65_ABSX; } } else if (Reg == 'Y') { - AM = AM65_ABSY; + AM = AM65_ABSY; } else { Error ("ASM code error: syntax error"); return 0; @@ -402,23 +425,11 @@ CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func) -void CS_AddEntry (CodeSeg* S, struct CodeEntry* E, LineInfo* LI) +void CS_AddEntry (CodeSeg* S, struct CodeEntry* E) /* Add an entry to the given code segment */ { /* Transfer the labels if we have any */ - unsigned I; - unsigned LabelCount = CollCount (&S->Labels); - for (I = 0; I < LabelCount; ++I) { - - /* Get the label */ - CodeLabel* L = CollAt (&S->Labels, I); - - /* Attach it to the entry */ - CE_AttachLabel (E, L); - } - - /* Delete the transfered labels */ - CollDeleteAll (&S->Labels); + CS_MoveLabelsToEntry (S, E); /* Add the entry to the list of code entries in this segment */ CollAppend (&S->Entries, E); @@ -426,7 +437,7 @@ void CS_AddEntry (CodeSeg* S, struct CodeEntry* E, LineInfo* LI) -void CS_AddEntryLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap) +void CS_AddLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap) /* Add a line to the given code segment */ { const char* L; @@ -465,7 +476,7 @@ void CS_AddEntryLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap) /* If we have a code entry, transfer the labels and insert it */ if (E) { - CS_AddEntry (S, E, LI); + CS_AddEntry (S, E); } } @@ -545,29 +556,48 @@ void CS_DelEntries (CodeSeg* S, unsigned Start, unsigned Count) * memory moving. */ while (Count--) { - CS_DelEntry (S, Start + Count); + CS_DelEntry (S, Start + Count); } } -void CS_MoveEntry (CodeSeg* S, unsigned OldPos, unsigned NewPos) -/* Move an entry from one position to another. OldPos is the current position - * of the entry, NewPos is the new position of the entry. +void CS_MoveEntries (CodeSeg* S, unsigned Start, unsigned Count, unsigned NewPos) +/* Move a range of entries from one position to another. Start is the index + * of the first entry to move, Count is the number of entries and NewPos is + * the index of the target entry. The entry with the index Start will later + * have the index NewPos. All entries with indices NewPos and above are + * moved to higher indices. If the code block is moved to the end of the + * current code, and if pending labels exist, these labels will get attached + * to the first instruction of the moved block (the first one after the + * current code end) */ { - /* Get the code entry and remove it from the collection */ - CodeEntry* E = CS_GetEntry (S, OldPos); - CollDelete (&S->Entries, OldPos); - - /* Correct NewPos if needed */ - if (NewPos >= OldPos) { - /* Position has changed with removal */ - --NewPos; + /* If NewPos is at the end of the code segment, move any labels from the + * label pool to the first instruction of the moved range. + */ + if (NewPos == CS_GetEntryCount (S)) { + CS_MoveLabelsToEntry (S, CS_GetEntry (S, Start)); } - /* Now insert it at the new position */ - CollInsert (&S->Entries, E, NewPos); + /* Move the code block to the destination */ + CollMoveMultiple (&S->Entries, Start, Count, NewPos); +} + + + +struct CodeEntry* CS_GetPrevEntry (CodeSeg* S, unsigned Index) +/* Get the code entry preceeding the one with the index Index. If there is no + * preceeding code entry, return NULL. + */ +{ + if (Index == 0) { + /* This is the first entry */ + return 0; + } else { + /* Previous entry available */ + return CollAtUnchecked (&S->Entries, Index-1); + } } @@ -578,10 +608,10 @@ struct CodeEntry* CS_GetNextEntry (CodeSeg* S, unsigned Index) */ { if (Index >= CollCount (&S->Entries)-1) { - /* This is the last entry */ - return 0; + /* This is the last entry */ + return 0; } else { - /* Code entries left */ + /* Code entries left */ return CollAtUnchecked (&S->Entries, Index+1); } } @@ -986,4 +1016,230 @@ void CS_Output (const CodeSeg* S, FILE* F) +void CS_FreeRegInfo (CodeSeg* S) +/* Free register infos for all instructions */ +{ + unsigned I; + for (I = 0; I < CS_GetEntryCount (S); ++I) { + CE_FreeRegInfo (CS_GetEntry(S, I)); + } +} + + + +void CS_GenRegInfo (CodeSeg* S) +/* Generate register infos for all instructions */ +{ + unsigned I; + RegContents Regs; + RegContents* CurrentRegs; + int WasJump; + + /* Be sure to delete all register infos */ + CS_FreeRegInfo (S); + + /* On entry, the register contents are unknown */ + RC_Invalidate (&Regs); + CurrentRegs = &Regs; + + /* First pass. Walk over all insns an note just the changes from one + * insn to the next one. + */ + WasJump = 0; + for (I = 0; I < CS_GetEntryCount (S); ++I) { + + CodeEntry* P; + + /* Get the next instruction */ + CodeEntry* E = CollAtUnchecked (&S->Entries, I); + + /* If the instruction has a label, we need some special handling */ + unsigned LabelCount = CE_GetLabelCount (E); + if (LabelCount > 0) { + + /* Loop over all entry points that jump here. If these entry + * points already have register info, check if all values are + * known and identical. If all values are identical, and the + * preceeding instruction was not an unconditional branch, check + * if the register value on exit of the preceeding instruction + * is also identical. If all these values are identical, the + * value of a register is known, otherwise it is unknown. + */ + CodeLabel* Label = CE_GetLabel (E, 0); + unsigned Entry; + if (WasJump) { + /* Preceeding insn was an unconditional branch */ + CodeEntry* J = CL_GetRef(Label, 0); + if (J->RI) { + Regs = J->RI->Out2; + } else { + RC_Invalidate (&Regs); + } + Entry = 1; + } else { + Regs = *CurrentRegs; + Entry = 0; + } + + while (Entry < CL_GetRefCount (Label)) { + /* Get this entry */ + CodeEntry* J = CL_GetRef (Label, Entry); + if (J->RI == 0) { + /* No register info for this entry, bail out */ + RC_Invalidate (&Regs); + break; + } + if (J->RI->Out2.RegA != Regs.RegA) { + Regs.RegA = -1; + } + if (J->RI->Out2.RegX != Regs.RegX) { + Regs.RegX = -1; + } + if (J->RI->Out2.RegY != Regs.RegY) { + Regs.RegY = -1; + } + ++Entry; + } + + /* Use this register info */ + CurrentRegs = &Regs; + + } + + /* Generate register info for this instruction */ + CE_GenRegInfo (E, CurrentRegs); + + /* Remember for the next insn if this insn was an uncondition branch */ + WasJump = (E->Info & OF_UBRA) != 0; + + /* Output registers for this insn are input for the next */ + CurrentRegs = &E->RI->Out; + + /* If this insn is a branch on zero flag, we may have more info on + * register contents for one of both flow directions, but only if + * there is a previous instruction. + */ + if ((E->Info & OF_ZBRA) != 0 && (P = CS_GetPrevEntry (S, I)) != 0) { + + /* Get the branch condition */ + bc_t BC = GetBranchCond (E->OPC); + + /* Check the previous instruction */ + switch (P->OPC) { + + case OP65_ADC: + case OP65_AND: + case OP65_DEA: + case OP65_EOR: + case OP65_INA: + case OP65_LDA: + case OP65_ORA: + case OP65_PLA: + case OP65_SBC: + /* A is zero in one execution flow direction */ + if (BC == BC_EQ) { + E->RI->Out2.RegA = 0; + } else { + E->RI->Out.RegA = 0; + } + break; + + case OP65_CMP: + /* If this is an immidiate compare, the A register has + * the value of the compare later. + */ + if (CE_KnownImm (P)) { + if (BC == BC_EQ) { + E->RI->Out2.RegA = (unsigned char)P->Num; + } else { + E->RI->Out.RegA = (unsigned char)P->Num; + } + } + break; + + case OP65_CPX: + /* If this is an immidiate compare, the X register has + * the value of the compare later. + */ + if (CE_KnownImm (P)) { + if (BC == BC_EQ) { + E->RI->Out2.RegX = (unsigned char)P->Num; + } else { + E->RI->Out.RegX = (unsigned char)P->Num; + } + } + break; + + case OP65_CPY: + /* If this is an immidiate compare, the Y register has + * the value of the compare later. + */ + if (CE_KnownImm (P)) { + if (BC == BC_EQ) { + E->RI->Out2.RegY = (unsigned char)P->Num; + } else { + E->RI->Out.RegY = (unsigned char)P->Num; + } + } + break; + + case OP65_DEX: + case OP65_INX: + case OP65_LDX: + case OP65_PLX: + /* X is zero in one execution flow direction */ + if (BC == BC_EQ) { + E->RI->Out2.RegX = 0; + } else { + E->RI->Out.RegX = 0; + } + break; + + case OP65_DEY: + case OP65_INY: + case OP65_LDY: + case OP65_PLY: + /* X is zero in one execution flow direction */ + if (BC == BC_EQ) { + E->RI->Out2.RegY = 0; + } else { + E->RI->Out.RegY = 0; + } + break; + + case OP65_TAX: + case OP65_TXA: + /* If the branch is a beq, both A and X are zero at the + * branch target, otherwise they are zero at the next + * insn. + */ + if (BC == BC_EQ) { + E->RI->Out2.RegA = E->RI->Out2.RegX = 0; + } else { + E->RI->Out.RegA = E->RI->Out.RegX = 0; + } + break; + + case OP65_TAY: + case OP65_TYA: + /* If the branch is a beq, both A and Y are zero at the + * branch target, otherwise they are zero at the next + * insn. + */ + if (BC == BC_EQ) { + E->RI->Out2.RegA = E->RI->Out2.RegY = 0; + } else { + E->RI->Out.RegA = E->RI->Out.RegY = 0; + } + break; + + default: + break; + + } + } + } +} + +