mirror of
https://github.com/cc65/cc65.git
synced 2024-11-19 06:31:31 +00:00
New functions CS_ResetMarks, CS_ResetAllMarks and CS_IsBasicBlock.
git-svn-id: svn://svn.cc65.org/cc65/trunk@1448 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
62b3576f5f
commit
1647c6783f
@ -1096,6 +1096,126 @@ void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
|
||||
|
||||
|
||||
|
||||
void CS_ResetMarks (CodeSeg* S, unsigned First, unsigned Last)
|
||||
/* Remove all user marks from the entries in the given range */
|
||||
{
|
||||
while (First <= Last) {
|
||||
CE_ResetMark (CS_GetEntry (S, First++));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last)
|
||||
/* Check if the given code segment range is a basic block. That is, check if
|
||||
* First is the only entrance and Last is the only exit. This means that no
|
||||
* jump/branch inside the block may jump to an insn below First or after(!)
|
||||
* Last, and that no insn may jump into this block from the outside.
|
||||
*/
|
||||
{
|
||||
unsigned I;
|
||||
|
||||
/* Don't accept invalid ranges */
|
||||
CHECK (First <= Last);
|
||||
|
||||
/* First pass: Walk over the range and remove all marks from the entries */
|
||||
CS_ResetMarks (S, First, Last);
|
||||
|
||||
/* Second pass: Walk over the range checking all labels. Note: There may be
|
||||
* label on the first insn which is ok.
|
||||
*/
|
||||
I = First + 1;
|
||||
while (I <= Last) {
|
||||
|
||||
/* Get the next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if this entry has one or more labels, if so, check which
|
||||
* entries jump to this label.
|
||||
*/
|
||||
unsigned LabelCount = CE_GetLabelCount (E);
|
||||
unsigned LabelIndex;
|
||||
for (LabelIndex = 0; LabelIndex < LabelCount; ++LabelIndex) {
|
||||
|
||||
/* Get this label */
|
||||
CodeLabel* L = CE_GetLabel (E, LabelIndex);
|
||||
|
||||
/* Walk over all entries that jump to this label. Check for each
|
||||
* of the entries if it is out of the range.
|
||||
*/
|
||||
unsigned RefCount = CL_GetRefCount (L);
|
||||
unsigned RefIndex;
|
||||
for (RefIndex = 0; RefIndex < RefCount; ++RefIndex) {
|
||||
|
||||
/* Get the code entry that jumps here */
|
||||
CodeEntry* Ref = CL_GetRef (L, RefIndex);
|
||||
|
||||
/* Walk over out complete range and check if we find the
|
||||
* refering entry. This is cheaper than using CS_GetEntryIndex,
|
||||
* because CS_GetEntryIndex will search the complete code
|
||||
* segment and not just our range.
|
||||
*/
|
||||
unsigned J;
|
||||
for (J = First; J <= Last; ++J) {
|
||||
if (Ref == CS_GetEntry (S, J)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (J > Last) {
|
||||
/* We did not find the entry. This means that the jump to
|
||||
* out code segment entry E came from outside the range,
|
||||
* which in turn means that the given range is not a basic
|
||||
* block.
|
||||
*/
|
||||
CS_ResetMarks (S, First, Last);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If we come here, we found the entry. Mark it, so we know
|
||||
* that the branch to the label is in range.
|
||||
*/
|
||||
CE_SetMark (Ref);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Third pass: Walk again over the range and check all branches. If we
|
||||
* find a branch that is not marked, its target is not inside the range
|
||||
* (since we checked all the labels in the range before).
|
||||
*/
|
||||
I = First;
|
||||
while (I <= Last) {
|
||||
|
||||
/* Get the next entry */
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check if this is a branch and if so, if it has a mark */
|
||||
if (E->Info & (OF_UBRA | OF_CBRA)) {
|
||||
if (!CE_HasMark (E)) {
|
||||
/* No mark means not a basic block. Before bailing out, be sure
|
||||
* to remove the marks from the remaining entries.
|
||||
*/
|
||||
CS_ResetMarks (S, I+1, Last);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove the mark */
|
||||
CE_ResetMark (E);
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
}
|
||||
|
||||
/* Done - this is a basic block */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CS_OutputPrologue (const CodeSeg* S, FILE* F)
|
||||
/* If the given code segment is a code segment for a function, output the
|
||||
* assembler prologue into the file. That is: Output a comment header, switch
|
||||
|
@ -103,6 +103,16 @@ void CS_AddVLine (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap) attr
|
||||
void CS_AddLine (CodeSeg* S, LineInfo* LI, const char* Format, ...) attribute ((format(printf,3,4)));
|
||||
/* Add a line to the given code segment */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned CS_GetEntryCount (const CodeSeg* S)
|
||||
/* Return the number of entries for the given code segment */
|
||||
{
|
||||
return CollCount (&S->Entries);
|
||||
}
|
||||
#else
|
||||
# define CS_GetEntryCount(S) CollCount (&(S)->Entries)
|
||||
#endif
|
||||
|
||||
void CS_InsertEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index);
|
||||
/* Insert the code entry at the index given. Following code entries will be
|
||||
* moved to slots with higher indices.
|
||||
@ -218,6 +228,29 @@ void CS_MoveLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L);
|
||||
void CS_DelCodeAfter (CodeSeg* S, unsigned Last);
|
||||
/* Delete all entries including the given one */
|
||||
|
||||
void CS_ResetMarks (CodeSeg* S, unsigned First, unsigned Last);
|
||||
/* Remove all user marks from the entries in the given range */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE void CS_ResetAllMarks (CodeSeg* S)
|
||||
/* Remove all user marks from the code segment */
|
||||
{
|
||||
if (CS_GetEntryCount (S) > 0) {
|
||||
CS_ResetMarks (S, 0, CS_GetEntryCount (S));
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define CS_ResetAllMarks(S) \
|
||||
((CS_GetEntryCount (S) > 0)? CS_ResetMarks (S, 0, CS_GetEntryCount (S)) : (void) 0)
|
||||
#endif
|
||||
|
||||
int CS_IsBasicBlock (CodeSeg* S, unsigned First, unsigned Last);
|
||||
/* Check if the given code segment range is a basic block. That is, check if
|
||||
* First is the only entrance and Last is the only exit. This means that no
|
||||
* jump/branch inside the block may jump to an insn below First or after(!)
|
||||
* Last, and that no insn may jump into this block from the outside.
|
||||
*/
|
||||
|
||||
void CS_OutputPrologue (const CodeSeg* S, FILE* F);
|
||||
/* If the given code segment is a code segment for a function, output the
|
||||
* assembler prologue into the file. That is: Output a comment header, switch
|
||||
@ -233,16 +266,6 @@ void CS_OutputEpilogue (const CodeSeg* S, FILE* F);
|
||||
void CS_Output (const CodeSeg* S, FILE* F);
|
||||
/* Output the code segment data to a file */
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE unsigned CS_GetEntryCount (const CodeSeg* S)
|
||||
/* Return the number of entries for the given code segment */
|
||||
{
|
||||
return CollCount (&S->Entries);
|
||||
}
|
||||
#else
|
||||
# define CS_GetEntryCount(S) CollCount (&(S)->Entries)
|
||||
#endif
|
||||
|
||||
void CS_FreeRegInfo (CodeSeg* S);
|
||||
/* Free register infos for all instructions */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user