+void RemoveCodeRange (const CodeMark* Start, const CodeMark* End)
+/* Remove all code between two code markers */
+{
+ /* Nothing to do if the range is empty */
+ if (Start->Pos == End->Pos) {
+ return;
+ }
+
+ /* We can only delete the range if End is the end of the code segment or
+ * if both SP values are identical.
+ */
+ CHECK (Start->SP == End->SP || End->Pos == CS_GetEntryCount (CS->Code));
+
+ /* Delete the range */
+ CS_DelCodeRange (CS->Code, Start->Pos, End->Pos-1);
+}
+
+
+
void RemoveCode (const CodeMark* M)
/* Remove all code after the given code marker */
{
void GetCodePos (CodeMark* M);
/* Get a marker pointing to the current output position */
+void RemoveCodeRange (const CodeMark* Start, const CodeMark* End);
+/* Remove all code between two code markers */
+
void RemoveCode (const CodeMark* M);
/* Remove all code after the given code marker */
/* cc65 */
+#include "asmcode.h"
#include "assignment.h"
#include "codegen.h"
#include "datatype.h"
} else if (ED_IsBitField (Expr)) {
+ CodeMark AndPos;
+ CodeMark PushPos;
+
unsigned Mask;
unsigned Flags;
/* Mask unwanted bits */
Mask = (0x0001U << Expr->BitWidth) - 1U;
+ GetCodePos (&AndPos);
g_and (Flags | CF_CONST, ~(Mask << Expr->BitOffs));
/* Push it on stack */
+ GetCodePos (&PushPos);
g_push (Flags, 0);
/* Read the expression on the right side of the '=' */
hie1 (&Expr2);
- /* Do type conversion if necessary. Beware: Do not use char type
+ /* Do type conversion if necessary. Beware: Do not use char type
* here!
*/
TypeConversion (&Expr2, ltype);
- /* If necessary, load the value into the primary register */
- LoadExpr (CF_NONE, &Expr2);
+ /* Special treatment if the value is constant */
+ if (ED_IsConstAbsInt (&Expr2)) {
+
+ /* Get the value and apply the mask */
+ unsigned Val = (unsigned) (Expr2.IVal & Mask);
- /* Apply the mask */
- g_and (Flags | CF_CONST, Mask);
+ /* Since we will do the OR with a constant, we can remove the push */
+ RemoveCode (&PushPos);
+
+ /* If the value is equal to the mask now, all bits are one, and we
+ * can remove the mask operation from above.
+ */
+ if (Val == Mask) {
+ RemoveCode (&AndPos);
+ }
- /* Shift it into the right position */
- g_asl (Flags | CF_CONST, Expr->BitOffs);
+ /* Generate the or operation */
+ g_or (Flags | CF_CONST, Val << Expr->BitOffs);
- /* Or both values */
- g_or (Flags, 0);
+ } else {
+
+ /* If necessary, load the value into the primary register */
+ LoadExpr (CF_NONE, &Expr2);
+
+ /* Apply the mask */
+ g_and (Flags | CF_CONST, Mask);
+
+ /* Shift it into the right position */
+ g_asl (Flags | CF_CONST, Expr->BitOffs);
+
+ /* Or both values */
+ g_or (Flags, 0);
+ }
/* Generate a store instruction */
Store (Expr, 0);
+void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last)
+/* Delete all entries between first and last, both inclusive. The function
+ * can only handle basic blocks (First is the only entry, Last the only exit)
+ * and no open labels. It will call FAIL if any of these preconditions are
+ * violated.
+ */
+{
+ unsigned I;
+ CodeEntry* FirstEntry;
+
+ /* Do some sanity checks */
+ CHECK (First <= Last && Last < CS_GetEntryCount (S));
+
+ /* If Last is actually the last insn, call CS_DelCodeAfter instead, which
+ * is more flexible in this case.
+ */
+ if (Last == CS_GetEntryCount (S) - 1) {
+ CS_DelCodeAfter (S, First);
+ return;
+ }
+
+ /* Get the first entry and check if it has any labels. If it has, move
+ * them to the insn following Last. If Last is the last insn of the code
+ * segment, make them ownerless and move them to the label pool.
+ */
+ FirstEntry = CS_GetEntry (S, First);
+ if (CE_HasLabel (FirstEntry)) {
+ /* Get the entry following last */
+ CodeEntry* FollowingEntry = CS_GetNextEntry (S, Last);
+ if (FollowingEntry) {
+ /* There is an entry after Last - move the labels */
+ CS_MoveLabels (S, FirstEntry, FollowingEntry);
+ } else {
+ /* Move the labels to the pool and clear the owner pointer */
+ CS_MoveLabelsToPool (S, FirstEntry);
+ }
+ }
+
+ /* First pass: Delete all references to labels. If the reference count
+ * for a label drops to zero, delete it.
+ */
+ for (I = Last; I >= First; --I) {
+
+ /* Get the next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if this entry has a label reference */
+ if (E->JumpTo) {
+
+ /* If the label is a label in the label pool, this is an error */
+ CodeLabel* L = E->JumpTo;
+ CHECK (CollIndex (&S->Labels, L) < 0);
+
+ /* Remove the reference to the label */
+ CS_RemoveLabelRef (S, E);
+ }
+ }
+
+ /* Second pass: Delete the instructions. If a label attached to an
+ * instruction still has references, it must be references from outside
+ * the deleted area, which is an error.
+ */
+ for (I = Last; I >= First; --I) {
+
+ /* Get the next entry */
+ CodeEntry* E = CS_GetEntry (S, I);
+
+ /* Check if this entry has a label attached */
+ CHECK (!CE_HasLabel (E));
+
+ /* Delete the pointer to the entry */
+ CollDelete (&S->Entries, I);
+
+ /* Delete the entry itself */
+ FreeCodeEntry (E);
+ }
+}
+
+
+
void CS_DelCodeAfter (CodeSeg* S, unsigned Last)
/* Delete all entries including the given one */
{
* deleted.
*/
+void CS_DelCodeRange (CodeSeg* S, unsigned First, unsigned Last);
+/* Delete all entries between first and last, both inclusive. The function
+ * can only handle basic blocks (First is the only entry, Last the only exit)
+ * and no open labels. It will call FAIL if any of these preconditions are
+ * violated.
+ */
+
void CS_DelCodeAfter (CodeSeg* S, unsigned Last);
/* Delete all entries including the given one */