From 57781964418caea528f9018cace1acb4a789d71c Mon Sep 17 00:00:00 2001 From: michaelh Date: Mon, 19 Nov 2001 04:56:44 +0000 Subject: [PATCH] * src/z80/ralloc.c (packRegsForHLUse3): Created and optimised. (packRegsForIYUse): Created and optimised. git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@1620 4a8a32a2-be11-0410-ad9d-d568d2c75423 --- ChangeLog | 8 + doc/choices.txt | 89 +++- src/SDCCicode.c | 29 ++ src/SDCCicode.h | 1 + src/z80/gen.c | 442 +++++++++++++---- src/z80/peeph-z80.def | 8 + src/z80/ralloc.c | 449 ++++++++++++------ src/z80/ralloc.h | 11 +- src/z80/z80.h | 3 +- .../{failing => tests}/bug-435214.c | 6 +- support/regression/tests/driverstruct.c | 5 + support/regression/tests/logic.c | 8 +- 12 files changed, 822 insertions(+), 237 deletions(-) rename support/regression/{failing => tests}/bug-435214.c (50%) diff --git a/ChangeLog b/ChangeLog index 4624cb9f..966497fd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2001-11-18 Michael Hope + + * src/z80/ralloc.c (packRegsForHLUse3): Created and optimised. + (packRegsForIYUse): Created and optimised. + +2001-11-07 Michael Hope + + * support/regression/tests/float.c (testFloatAdd): Fixed up warning. 2001-11-18 Bernhard Held * sdcc/support/regression/tests/bug-460010.c: fix seg violation on host diff --git a/doc/choices.txt b/doc/choices.txt index 9fa79244..fd6cbab8 100644 --- a/doc/choices.txt +++ b/doc/choices.txt @@ -105,5 +105,90 @@ Things get better when you access the same set over, as you get rid of the setup. But they get worse when both ops are on the stack/in direct space. Easiest this way for now. iy may benifit... - - +cmpGt: + ld l,#0x80 ; 7 + ld a,-1(ix) ; 19 + xor a,#0x80 ; 7 + ld h,a ; 4 + ld a,#0x02 ; 7 + sub a,-2(ix) ; 19 + ld a,l ; 4 + sbc a,h ; 4 = 71 + +vs + ld hl,0x8002 ; 10 + ld a,-2(ix) ; 19 + xor 0x80 ; 7 + ld d,a ; 4 + ld e,-1(ix) ; 19 + sbc hl,de ; 15 = 74 + +Why is there the whole xor thing going on? + +cmpGt using sub: + left right l-r c expect + 0 0 0 0 false + -1 0 -1 0 false + 1 0 1 0 true + 0 -1 1 1 true + 0 1 -1 1 false + +With top most bits xored + 80h 80h 0 0 false + 7fh 80h FFh 1 false + 81h 80h 01h 0 true + 80h 7fh 01h 0 true + 80h 81h FFh 1 false + +r-l instead - ah. + 80h 80h 0 0 false + 7fh 80h 01h 0 false + 81h 80h FFh 1 true + 80h 7fh FFh 1 true + 80h 81h 01h 0 false + +How about using the sign bit and no XOR on r-l? + 0 0 0 false + FFh 0 01h false + 01h 0 FFh true + 0 FFh FFh true + 0 01h 01h false - works + +cmpEq: + ld hl,#nn ; 10 + ld c,(ix+-5) ; 19 + ld b,(ix+-4) ; 19 + or a ; 4 + sbc hl,bc ; 15 + jp nz,l19 ; 10 = 77 + + ld a,-82(ix) ; 19 + cp a,#0x01 ; 7 + jp nz,00129$ ; 10 + ld a,-81(ix) ; 19 + or a,a ; 7 + jp nz,00129$ ; 10 - 72 + +Add: + ld a,c ; 4 + add a,#0x04 ; 7 + ld -4(ix),a ; 19 + ld a,b ; 4 + adc a,#0x00 ; 7 + ld -3(ix),a ; 19 = 60 +vs + ld hl,#4 ; 10 + add hl,bc ; 11 + ld -4(ix),l ; 19 + ld -3(ix),h ; 19 = 59 + +Same argument as above - not worth the extra cycle. + +Pending optimisations: + iTemp1 = @iTemp2 + iTemp3 = iTemp1 + + iTemp4 = something in direct space + ... + push iTemp4 + diff --git a/src/SDCCicode.c b/src/SDCCicode.c index 59bcf886..460fc5d4 100644 --- a/src/SDCCicode.c +++ b/src/SDCCicode.c @@ -858,6 +858,7 @@ isOperandLiteral (operand * op) return 0; } + /*-----------------------------------------------------------------*/ /* isOperandInFarSpace - will return true if operand is in farSpace */ /*-----------------------------------------------------------------*/ @@ -886,6 +887,34 @@ isOperandInFarSpace (operand * op) return (IN_FARSPACE (SPEC_OCLS (etype)) ? TRUE : FALSE); } +/*------------------------------------------------------------------*/ +/* isOperandInDirSpace - will return true if operand is in dirSpace */ +/*------------------------------------------------------------------*/ +bool +isOperandInDirSpace (operand * op) +{ + sym_link *etype; + + if (!op) + return FALSE; + + if (!IS_SYMOP (op)) + return FALSE; + + if (!IS_TRUE_SYMOP (op)) + { + if (SPIL_LOC (op)) + etype = SPIL_LOC (op)->etype; + else + return FALSE; + } + else + { + etype = getSpec (operandType (op)); + } + return (IN_DIRSPACE (SPEC_OCLS (etype)) ? TRUE : FALSE); +} + /*-----------------------------------------------------------------*/ /* isOperandOnStack - will return true if operand is on stack */ /*-----------------------------------------------------------------*/ diff --git a/src/SDCCicode.h b/src/SDCCicode.h index bd467419..9a44fbc6 100644 --- a/src/SDCCicode.h +++ b/src/SDCCicode.h @@ -310,6 +310,7 @@ int piCode (void *, FILE *); int printOperand (operand *, FILE *); void setOperandType (operand *, sym_link *); bool isOperandInFarSpace (operand *); +bool isOperandInDirSpace (operand *); operand *opFromOpWithDU (operand *, bitVect *, bitVect *); iCode *copyiCode (iCode *); operand *newiTempFromOp (operand *); diff --git a/src/z80/gen.c b/src/z80/gen.c index 7515252e..5652ea6b 100644 --- a/src/z80/gen.c +++ b/src/z80/gen.c @@ -166,8 +166,8 @@ static struct { "bc", "c", "b" }, { "de", "e", "d" }, { "hl", "l", "h" }, - { "iy", "iy.l?", "iy.h?" }, - { "ix", "ix.l?", "ix.h?" } + { "iy", "iyl", "iyh" }, + { "ix", "ixl", "ixh" } }; // PENDING @@ -252,6 +252,23 @@ _getTempPairName(void) return _pairs[_getTempPairId()].name; } +static PAIR_ID +getFreePairId (iCode *ic) +{ + if (!(bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX))) + { + return PAIR_BC; + } + else if (IS_Z80 && !(bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX))) + { + return PAIR_DE; + } + else + { + return PAIR_INVALID; + } +} + static void _tidyUp (char *buf) { @@ -408,18 +425,14 @@ getPairName (asmop * aop) } else if (aop->type == AOP_STR || aop->type == AOP_HLREG) { - switch (*aop->aopu.aop_str[0]) - { - case 'c': - return "bc"; - break; - case 'e': - return "de"; - break; - case 'l': - return "hl"; - break; - } + int i; + for (i = 0; i < NUM_PAIRS; i++) + { + if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0) + { + return _pairs[i].name; + } + } } wassertl (0, "Tried to get the pair name of something that isn't a pair"); return NULL; @@ -445,21 +458,17 @@ getPairId (asmop * aop) return PAIR_HL; } } - if (aop->type == AOP_STR || aop->type == AOP_HLREG) + else if (aop->type == AOP_STR || aop->type == AOP_HLREG) { - if (!strcmp (aop->aopu.aop_str[0], "c") && !strcmp (aop->aopu.aop_str[1], "b")) - { - return PAIR_BC; - } - if (!strcmp (aop->aopu.aop_str[0], "e") && !strcmp (aop->aopu.aop_str[1], "d")) - { - return PAIR_DE; - } - if (!strcmp (aop->aopu.aop_str[0], "l") && !strcmp (aop->aopu.aop_str[1], "h")) - { - return PAIR_HL; - } - } + int i; + for (i = 0; i < NUM_PAIRS; i++) + { + if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h)) + { + return i; + } + } + } } return PAIR_INVALID; } @@ -830,6 +839,16 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) return; } + if (sym->ruonly) + { + int i; + aop = op->aop = sym->aop = newAsmop (AOP_STR); + aop->size = getSize (sym->type); + for (i = 0; i < 4; i++) + aop->aopu.aop_str[i] = _fReturn[i]; + return; + } + if (sym->accuse) { if (sym->accuse == ACCUSE_A) @@ -848,6 +867,14 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) aop->aopu.aop_str[0] = _pairs[PAIR_HL].l; aop->aopu.aop_str[1] = _pairs[PAIR_HL].h; } + else if (sym->accuse == ACCUSE_IY) + { + aop = op->aop = sym->aop = newAsmop (AOP_HLREG); + aop->size = getSize (sym->type); + wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY"); + aop->aopu.aop_str[0] = _pairs[PAIR_IY].l; + aop->aopu.aop_str[1] = _pairs[PAIR_IY].h; + } else { wassertl (0, "Marked as being allocated into A or HL but is actually in neither"); @@ -855,16 +882,6 @@ aopOp (operand * op, iCode * ic, bool result, bool requires_a) return; } - if (sym->ruonly) - { - int i; - aop = op->aop = sym->aop = newAsmop (AOP_STR); - aop->size = getSize (sym->type); - for (i = 0; i < 4; i++) - aop->aopu.aop_str[i] = _fReturn[i]; - return; - } - /* else spill location */ sym->aop = op->aop = aop = aopForSym (ic, sym->usl.spillLoc, result, requires_a); @@ -1123,9 +1140,14 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) if (isLitWord (aop)) { fetchLitPair (pairId, aop, offset); } - else { + else + { + if (getPairId (aop) == pairId) + { + /* Do nothing */ + } /* we need to get it byte by byte */ - if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) { + else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) { aopGet (aop, offset, FALSE); switch (aop->size - offset) { case 1: @@ -1155,6 +1177,24 @@ fetchPairLong (PAIR_ID pairId, asmop * aop, int offset) emit2("ld %s,!zero", _pairs[pairId].h); } } + else if (pairId == PAIR_IY) + { + if (isPair (aop)) + { + emit2 ("push %s", _pairs[getPairId(aop)].name); + emit2 ("pop iy"); + } + else + { + _push (PAIR_HL); + /* Can't load into parts, so load into HL then exchange. */ + emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE)); + emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE)); + emit2 ("push hl"); + emit2 ("pop iy"); + _pop (PAIR_HL); + } + } else { emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE)); emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE)); @@ -1563,7 +1603,9 @@ aopPut (asmop * aop, const char *s, int offset) emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset); } else - emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s); + { + emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s); + } } break; @@ -1719,6 +1761,20 @@ movLeft2ResultLong (operand * left, int offl, emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE)); emit2 ("ld l,a"); } + else if ( getPairId ( AOP (result)) == PAIR_IY) + { + PAIR_ID id = getPairId (AOP (left)); + if (id != PAIR_INVALID) + { + emit2("push %s", _pairs[id].name); + emit2("pop iy"); + } + else + { + /* PENDING */ + emitDebug("Error"); + } + } else { movLeft2Result (left, offl, result, offr, sign); @@ -2925,9 +2981,22 @@ genPlusIncr (iCode * ic) } if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2) { - fetchPair (resultId, AOP (IC_RIGHT (ic))); - emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic)))); - return TRUE; + if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL) + { + PAIR_ID freep = getFreePairId (ic); + if (freep != PAIR_INVALID) + { + fetchPair (freep, AOP (IC_RIGHT (ic))); + emit2 ("add hl,%s", _pairs[freep].name); + return TRUE; + } + } + else + { + fetchPair (resultId, AOP (IC_RIGHT (ic))); + emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic)))); + return TRUE; + } } if (icount > 5) return FALSE; @@ -2945,6 +3014,13 @@ genPlusIncr (iCode * ic) return TRUE; } + if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2) + { + fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount); + commitPair (AOP (IC_RESULT (ic)), PAIR_HL); + return TRUE; + } + /* if the literal value of the right hand side is greater than 4 then it is not worth it */ if (icount > 4) @@ -3178,13 +3254,40 @@ genPlus (iCode * ic) } } - if (isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL) + if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL) { /* Fetch into HL then do the add */ + PAIR_ID left = getPairId (AOP (IC_LEFT (ic))); + PAIR_ID right = getPairId (AOP (IC_RIGHT (ic))); + spillPair (PAIR_HL); - fetchPair (PAIR_HL, AOP (IC_LEFT (ic))); - emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic)))); - goto release; + + if (left == PAIR_HL && right != PAIR_INVALID) + { + emit2 ("add hl,%s", _pairs[right].name); + goto release; + } + else if (right == PAIR_HL && left != PAIR_INVALID) + { + emit2 ("add hl,%s", _pairs[left].name); + goto release; + } + else if (right != PAIR_INVALID) + { + fetchPair (PAIR_HL, AOP (IC_LEFT (ic))); + emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic)))); + goto release; + } + else if (left != PAIR_INVALID) + { + fetchPair (PAIR_HL, AOP (IC_RIGHT (ic))); + emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic)))); + goto release; + } + else + { + /* Can't do it */ + } } if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD) @@ -3643,6 +3746,14 @@ genIfxJump (iCode * ic, char *jval) { inst = "nc"; } + else if (!strcmp (jval, "m")) + { + inst = "m"; + } + else if (!strcmp (jval, "p")) + { + inst = "p"; + } else { /* The buffer contains the bit on A that we should test */ @@ -3665,6 +3776,14 @@ genIfxJump (iCode * ic, char *jval) { inst = "c"; } + else if (!strcmp (jval, "m")) + { + inst = "p"; + } + else if (!strcmp (jval, "p")) + { + inst = "m"; + } else { /* The buffer contains the bit on A that we should test */ @@ -3682,6 +3801,12 @@ genIfxJump (iCode * ic, char *jval) else if (!strcmp (jval, "nc")) { } + else if (!strcmp (jval, "m")) + { + } + else if (!strcmp (jval, "p")) + { + } else { emit2 ("bit %s,a", jval); @@ -3700,30 +3825,7 @@ _getPairIdName (PAIR_ID id) } #endif -/** Generic compare for > or < - */ -static void -genCmp (operand * left, operand * right, - operand * result, iCode * ifx, int sign) -{ - int size, offset = 0; - unsigned long lit = 0L; - bool swap_sense = FALSE; - - /* if left & right are bit variables */ - if (AOP_TYPE (left) == AOP_CRY && - AOP_TYPE (right) == AOP_CRY) - { - /* Cant happen on the Z80 */ - wassertl (0, "Tried to compare two bits"); - } - else - { - /* subtract right from left if at the - end the carry flag is set then we know that - left is greater than right */ - size = max (AOP_SIZE (left), AOP_SIZE (right)); - +#if OLD /* if unsigned char cmp with lit, just compare */ if ((size == 1) && (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR)) @@ -3898,10 +4000,109 @@ genCmp (operand * left, operand * right, } } } +#endif + +/** Generic compare for > or < + */ +static void +genCmp (operand * left, operand * right, + operand * result, iCode * ifx, int sign) +{ + int size, offset = 0; + unsigned long lit = 0L; + bool swap_sense = FALSE; + + /* if left & right are bit variables */ + if (AOP_TYPE (left) == AOP_CRY && + AOP_TYPE (right) == AOP_CRY) + { + /* Cant happen on the Z80 */ + wassertl (0, "Tried to compare two bits"); + } + else + { + /* Do a long subtract of right from left. */ + size = max (AOP_SIZE (left), AOP_SIZE (right)); + + if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left))) + { + // On the Gameboy we can't afford to adjust HL as it may trash the carry. + // Pull left into DE and right into HL + aopGet (AOP(left), LSB, FALSE); + emit2 ("ld d,h"); + emit2 ("ld e,l"); + aopGet (AOP(right), LSB, FALSE); + + while (size--) + { + emit2 ("ld a,(de)"); + emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc"); + + if (size != 0) + { + emit2 ("inc hl"); + emit2 ("inc de"); + } + offset++; + } + spillPair (PAIR_HL); + goto release; + } + + if (AOP_TYPE (right) == AOP_LIT) + { + lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); + /* optimize if(x < 0) or if(x >= 0) */ + if (lit == 0) + { + if (!sign) + { + /* No sign so it's always false */ + _clearCarry(); + } + else + { + /* Just load in the top most bit */ + _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE)); + if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx) + { + genIfxJump (ifx, "7"); + return; + } + else + { + if (!sign) + { + emit2 ("rlc a"); + } + if (ifx) + { + genIfxJump (ifx, swap_sense ? "c" : "nc"); + return; + } + } + } + goto release; + } + } + + while (size--) + { + _moveA (aopGet (AOP (left), offset, FALSE)); + /* Subtract through, propagating the carry */ + emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE)); + offset++; + } + } release: if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) { + if (sign) + { + /* Shift the sign bit up into carry */ + emit2 ("rlca"); + } outBitCLong (result, swap_sense); } else @@ -3910,9 +4111,26 @@ release: ifx conditional branch then generate code a little differently */ if (ifx) - genIfxJump (ifx, swap_sense ? "nc" : "c"); + { + if (IS_GB) + { + emit2 ("rlca"); + genIfxJump (ifx, swap_sense ? "nc" : "c"); + } + else + { + genIfxJump (ifx, swap_sense ? "p" : "m"); + } + } else - outBitCLong (result, swap_sense); + { + if (sign) + { + /* Shift the sign bit up into carry */ + emit2 ("rlca"); + } + outBitCLong (result, swap_sense); + } /* leave the result in acc */ } } @@ -4120,9 +4338,11 @@ genCmpEq (iCode * ic, iCode * ifx) else { tlbl = newiTempLabel (NULL); + emitDebug(";1"); gencjneshort (left, right, tlbl); if (IC_TRUE (ifx)) { + emitDebug(";2"); emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100); emitLabel (tlbl->key + 100); } @@ -4130,6 +4350,7 @@ genCmpEq (iCode * ic, iCode * ifx) { /* PENDING: do this better */ symbol *lbl = newiTempLabel (NULL); + emitDebug(";3"); emit2 ("!shortjp !tlabel", lbl->key + 100); emitLabel (tlbl->key + 100); emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100); @@ -4149,6 +4370,8 @@ genCmpEq (iCode * ic, iCode * ifx) } else { + emitDebug(";4"); + gencjne (left, right, newiTempLabel (NULL)); if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) { @@ -4156,6 +4379,7 @@ genCmpEq (iCode * ic, iCode * ifx) } if (ifx) { + emitDebug(";5"); genIfxJump (ifx, "a"); goto release; } @@ -4163,6 +4387,7 @@ genCmpEq (iCode * ic, iCode * ifx) then put the result in place */ if (AOP_TYPE (result) != AOP_CRY) { + emitDebug(";6"); outAcc (result); } /* leave the result in acc */ @@ -5600,7 +5825,9 @@ genGenPointerGet (operand * left, aopOp (left, ic, FALSE, FALSE); aopOp (result, ic, FALSE, FALSE); - if (isPair (AOP (left)) && AOP_SIZE (result) == 1) + size = AOP_SIZE (result); + + if (isPair (AOP (left)) && size == 1) { /* Just do it */ if (isPtrPair (AOP (left))) @@ -5617,11 +5844,24 @@ genGenPointerGet (operand * left, goto release; } + if ( getPairId( AOP (left)) == PAIR_IY) + { + /* Just do it */ + offset = 0; + while (size--) + { + char at[20]; + tsprintf (at, "!*iyx", offset); + aopPut (AOP (result), at, offset); + offset++; + } + goto release; + } + /* For now we always load into IY */ /* if this is remateriazable */ fetchPair (pair, AOP (left)); - /* so iy now contains the address */ freeAsmop (left, NULL, ic); /* if bit then unpack */ @@ -5629,6 +5869,14 @@ genGenPointerGet (operand * left, { wassert (0); } + else if ( getPairId( AOP (result)) == PAIR_HL) + { + wassertl (size == 2, "HL must be of size 2"); + emit2 ("ld a,!*hl"); + emit2 ("inc hl"); + emit2 ("ld h,!*hl"); + emit2 ("ld l,a"); + } else { size = AOP_SIZE (result); @@ -5681,7 +5929,7 @@ genPointerGet (iCode * ic) bool isRegOrLit (asmop * aop) { - if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD) + if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG) return TRUE; return FALSE; } @@ -5696,15 +5944,17 @@ genGenPointerSet (operand * right, int size, offset; sym_link *retype = getSpec (operandType (right)); PAIR_ID pairId = PAIR_HL; - + aopOp (result, ic, FALSE, FALSE); aopOp (right, ic, FALSE, FALSE); if (IS_GB) pairId = PAIR_DE; + size = AOP_SIZE (right); + /* Handle the exceptions first */ - if (isPair (AOP (result)) && (AOP_SIZE (right) == 1)) + if (isPair (AOP (result)) && size == 1) { /* Just do it */ const char *l = aopGet (AOP (right), 0, FALSE); @@ -5720,6 +5970,28 @@ genGenPointerSet (operand * right, } goto release; } + + if ( getPairId( AOP (result)) == PAIR_IY) + { + /* Just do it */ + const char *l = aopGet (AOP (right), 0, FALSE); + + offset = 0; + while (size--) + { + if (canAssignToPtr (l)) + { + emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE)); + } + else + { + _moveA (aopGet (AOP (right), offset, FALSE)); + emit2 ("ld !*iyx,a", offset); + } + offset++; + } + goto release; + } /* if the operand is already in dptr then we do nothing else we move the value to dptr */ @@ -5737,7 +6009,6 @@ genGenPointerSet (operand * right, } else { - size = AOP_SIZE (right); offset = 0; while (size--) @@ -5915,7 +6186,10 @@ genAssign (iCode * ic) offset = 0; if (AOP_TYPE (right) == AOP_LIT) + { lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit); + } + if (isPair (AOP (result))) { fetchPair (getPairId (AOP (result)), AOP (right)); @@ -5956,6 +6230,12 @@ genAssign (iCode * ic) offset++; } } + else if (size == 2 && AOP_TYPE (right) == AOP_IY) + { + emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir); + aopPut (AOP (result), "l", LSB); + aopPut (AOP (result), "h", MSB16); + } else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB) { /* Special case. Load into a and d, then load out. */ @@ -5991,7 +6271,7 @@ genAssign (iCode * ic) while (size--) { /* PENDING: do this check better */ - if (requiresHL (AOP (right)) && requiresHL (AOP (result))) + if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result))) { _moveA (aopGet (AOP (right), offset, FALSE)); aopPut (AOP (result), "a", offset); diff --git a/src/z80/peeph-z80.def b/src/z80/peeph-z80.def index 76fe8cdd..2bba1260 100644 --- a/src/z80/peeph-z80.def +++ b/src/z80/peeph-z80.def @@ -23,3 +23,11 @@ replace { or a,a jp z,%2 } +replace { + rlca + ld a,#0x00 + rla +} by { + rlca + and a,#0x01 +} diff --git a/src/z80/ralloc.c b/src/z80/ralloc.c index 354d1ee1..320fa781 100644 --- a/src/z80/ralloc.c +++ b/src/z80/ralloc.c @@ -44,6 +44,7 @@ */ #include "z80.h" +#include "SDCCicode.h" /* Flags to turn off optimisations. */ @@ -51,8 +52,7 @@ enum { DISABLE_PACK_ACC = 0, DISABLE_PACK_ASSIGN = 0, - /* Pack for one use is quite broken. */ - DISABLE_PACK_ONE_USE = 1, + DISABLE_PACK_ONE_USE = 0, DISABLE_PACK_HL = 0, }; @@ -64,7 +64,9 @@ enum D_ALLOC2 = 0, D_ACCUSE2 = 0, D_ACCUSE2_VERBOSE = 0, - D_HLUSE = 0 + D_HLUSE = 0, + D_HLUSE2 = 0, + D_HLUSE2_VERBOSE = 0 }; #if 1 @@ -383,6 +385,9 @@ noOverLap (set * itmpStack, symbol * fsym) for (sym = setFirstItem (itmpStack); sym; sym = setNextItem (itmpStack)) { + if (bitVectBitValue(sym->clashes,fsym->key)) + return 0; +#if 0 // if sym starts before (or on) our end point // and ends after (or on) our start point, // it is an overlap. @@ -391,6 +396,7 @@ noOverLap (set * itmpStack, symbol * fsym) { return 0; } +#endif } return 1; } @@ -1017,6 +1023,8 @@ tryAllocatingRegPair (symbol * sym) sym->regs[0] = ®sZ80[i]; regsZ80[i + 1].isFree = 0; sym->regs[1] = ®sZ80[i + 1]; + sym->regType = REG_PAIR; + if (currFunc) { currFunc->regsUsed = @@ -1478,28 +1486,13 @@ packRegsForAssign (iCode * ic, eBBlock * ebp) return 0; } -#if 0 - /* if the true symbol is defined in far space or on stack - then we should not since this will increase register pressure */ - if (isOperandInFarSpace (IC_RESULT (ic))) - { - if ((dic = farSpacePackable (ic))) - goto pack; - else - return 0; - } -#endif - /* find the definition of iTempNN scanning backwards if we find a a use of the true symbol in before we find the definition then we cannot */ for (dic = ic->prev; dic; dic = dic->prev) { - /* if there is a function call and this is - a parameter & not my parameter then don't pack it */ - if ((dic->op == CALL || dic->op == PCALL) && - (OP_SYMBOL (IC_RESULT (ic))->_isparm && - !OP_SYMBOL (IC_RESULT (ic))->ismyparm)) + /* PENDING: Don't pack across function calls. */ + if (dic->op == CALL || dic->op == PCALL) { dic = NULL; break; @@ -1529,14 +1522,6 @@ packRegsForAssign (iCode * ic, eBBlock * ebp) dic = NULL; break; } -#if 0 - if (POINTER_SET (dic) && - IC_RESULT (dic)->key == IC_RESULT (ic)->key) - { - dic = NULL; - break; - } -#endif } if (!dic) @@ -1547,7 +1532,6 @@ packRegsForAssign (iCode * ic, eBBlock * ebp) if (OP_SYMBOL (IC_RESULT (ic))->onStack || OP_SYMBOL (IC_RESULT (ic))->iaccess) { - /* the operation has only one symbol operator then we can pack */ if ((IC_LEFT (dic) && !IS_SYMOP (IC_LEFT (dic))) || @@ -1753,8 +1737,10 @@ packRegsForOneuse (iCode * ic, operand * op, eBBlock * ebp) /* only upto 2 bytes since we cannot predict the usage of b, & acc */ - if (getSize (operandType (op)) > 2 && - ic->op != RETURN && + if (getSize (operandType (op)) > 2) + return NULL; + + if (ic->op != RETURN && ic->op != SEND) return NULL; @@ -2115,8 +2101,267 @@ hluse: OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_SCRATCH; } +static iCode * +packRegsForHLUse3 (iCode * lic, operand * op, eBBlock * ebp) +{ + int i, key; + symbol *sym; + iCode *ic, *dic; + bool isFirst = TRUE; + +#if 0 + printf("Checking:\n"); + piCode(lic, NULL); +#endif + + if ( OP_SYMBOL(op)->accuse) + { + return NULL; + } + + if (OP_SYMBOL(op)->remat) + { + return NULL; + } + + /* Only defined once */ + if (bitVectnBitsOn (OP_DEFS (op)) > 1) + return NULL; + + if (getSize (operandType (op)) != 2) + return NULL; + + /* And this is the definition */ + if (bitVectFirstBit (OP_DEFS (op)) != lic->key) + return NULL; + + /* first check if any overlapping liverange has already been + assigned to DPTR */ + if (OP_SYMBOL(op)->clashes) + { + for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ ) + { + if (bitVectBitValue(OP_SYMBOL(op)->clashes,i)) + { + sym = hTabItemWithKey(liveRanges,i); + if (sym->accuse == ACCUSE_SCRATCH) + { + return NULL; + } + } + } + } + + /* Nothing else that clashes with this is using the scratch + register. Scan through all of the intermediate instructions and + see if any of them could nuke HL. + */ + dic = ic = hTabFirstItemWK(iCodeSeqhTab,OP_SYMBOL(op)->liveFrom); + + for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo; + ic = hTabNextItem(iCodeSeqhTab,&key)) + { +#if 0 + piCode(ic, NULL); + printf("(op: %u)\n", ic->op); +#endif + if (isFirst) + { + isFirst = FALSE; + if (ic->op == ADDRESS_OF) + continue; + if (POINTER_GET (ic)) + continue; + } + + /* Handle the non left/right/result ones first */ + if (ic->op == IFX) + continue; + if (ic->op == JUMPTABLE) + return NULL; + + if (SKIP_IC2(ic)) + continue; + + if (ic->op == IPUSH && isOperandEqual (op, IC_LEFT (ic))) + continue; + + if ((ic->op == '=' && !POINTER_SET(ic)) || + ic->op == UNARYMINUS || + ic->op == '+' || + ic->op == '-' || + 0) + continue; + + if (POINTER_GET (ic) && isOperandEqual (op, IC_LEFT (ic))) + continue; + + if (IS_VALOP (IC_RIGHT (ic)) && + (ic->op == EQ_OP || + 0)) + { + continue; + } + + /* By default give up */ + return NULL; + } + +#if 0 + printf("Succeeded!\n"); +#endif + OP_SYMBOL (op)->accuse = ACCUSE_SCRATCH; + + return dic; +} + +static iCode * +packRegsForIYUse (iCode * lic, operand * op, eBBlock * ebp) +{ + int i, key; + symbol *sym; + iCode *ic, *dic; + bitVect *uses; + +#if 0 + printf("Checking IY on %p lic key %u first def %u:\n", OP_SYMBOL(op), lic->key, bitVectFirstBit(OP_DEFS(op))); + piCode(lic, NULL); +#endif + + if ( OP_SYMBOL(op)->accuse) + { + return NULL; + } + + if (OP_SYMBOL(op)->remat) + { + return NULL; + } + + /* Only defined once */ + if (bitVectnBitsOn (OP_DEFS (op)) > 1) + return NULL; + + /* And this is the definition */ + if (bitVectFirstBit (OP_DEFS (op)) != lic->key) + return NULL; + + /* first check if any overlapping liverange has already been + assigned to DPTR */ + if (OP_SYMBOL(op)->clashes) + { + for (i = 0 ; i < OP_SYMBOL(op)->clashes->size ; i++ ) + { + if (bitVectBitValue(OP_SYMBOL(op)->clashes,i)) + { + sym = hTabItemWithKey(liveRanges,i); + if (sym->accuse == ACCUSE_IY) + { + return NULL; + } + } + } + } + + /* Only a few instructions can load into IY */ + if (lic->op != '=') + { + return NULL; + } + + /* Nothing else that clashes with this is using the scratch + register. Scan through all of the intermediate instructions and + see if any of them could nuke HL. + */ + dic = ic = hTabFirstItemWK(iCodeSeqhTab,OP_SYMBOL(op)->liveFrom); + uses = OP_USES(op); + + for (; ic && ic->seq <= OP_SYMBOL(op)->liveTo; + ic = hTabNextItem(iCodeSeqhTab,&key)) + { +#if 0 + piCode(ic, NULL); + printf("(op: %u uses %u)\n", ic->op, bitVectBitValue(uses, ic->key)); +#endif + + if (ic->op == PCALL || + ic->op == CALL || + ic->op == JUMPTABLE + ) + return NULL; + + if (SKIP_IC2(ic)) + continue; + + /* Only certain rules will work against IY. Check if this iCode uses + this symbol. */ + if (bitVectBitValue(uses, ic->key) != 0) + { + if (ic->op == IFX) + return NULL; + + if (ic->op == '=' && + isOperandEqual(IC_RESULT(ic), op)) + continue; + + if (ic->op == GET_VALUE_AT_ADDRESS && + isOperandEqual(IC_LEFT(ic), op)) + continue; + + if (isOperandEqual(IC_RESULT(ic), IC_LEFT(ic)) == FALSE) + return NULL; + + if (IC_RIGHT (ic) && IS_VALOP (IC_RIGHT (ic))) + { + if (ic->op == '+' || + ic->op == '-') + { + /* Only works if the constant is small */ + if (operandLitValue (IC_RIGHT (ic)) < 4) + continue; + } + } + + return NULL; + } + else + { + if (ic->op == IFX) + continue; + + /* This iCode doesn't use the sym. See if this iCode preserves IY. + */ + if (IC_RESULT(ic) && IS_SYMOP(IC_RESULT(ic)) && + isOperandInDirSpace(IC_RESULT(ic))) + return NULL; + + if (IC_RIGHT(ic) && IS_SYMOP(IC_RIGHT(ic)) && + isOperandInFarSpace(IC_RIGHT(ic))) + return NULL; + + if (IC_LEFT(ic) && IS_SYMOP(IC_LEFT(ic)) && + isOperandInFarSpace(IC_LEFT(ic))) + return NULL; + + continue; + } + + /* By default give up */ + return NULL; + } + +#if 0 + printf("Succeeded IY!\n"); +#endif + OP_SYMBOL (op)->accuse = ACCUSE_IY; + + return dic; +} + +/** Returns TRUE if this operation can use acc and if it preserves the value. + */ static bool -opPreservesA (iCode * ic, iCode * uic) +opPreservesA (iCode * uic) { if (uic->op == IFX) { @@ -2161,6 +2406,8 @@ opPreservesA (iCode * ic, iCode * uic) return FALSE; } +/** Returns true if this operand preserves the value of A. + */ static bool opIgnoresA (iCode * ic, iCode * uic) { @@ -2180,6 +2427,15 @@ opIgnoresA (iCode * ic, iCode * uic) return TRUE; } } + else if (uic->op == '=' && !POINTER_SET (uic)) + { + /* If they are equal and get optimised out then things are OK. */ + if (isOperandEqual (IC_RESULT (uic), IC_RIGHT (uic))) + { + /* Straight assign is OK. */ + return TRUE; + } + } return FALSE; } @@ -2246,7 +2502,7 @@ packRegsForAccUse2 (iCode * ic) { iCode *uic; - D (D_ALLOC, ("packRegsForAccUse2: running on ic %p\n", ic)); + D (D_ACCUSE2, ("packRegsForAccUse2: running on ic %p line %u\n", ic, ic->lineno)); /* Filter out all but those 'good' commands */ if ( @@ -2255,6 +2511,8 @@ packRegsForAccUse2 (iCode * ic) !IS_BITWISE_OP (ic) && ic->op != '=' && ic->op != EQ_OP && + ic->op != '<' && + ic->op != '>' && ic->op != CAST && ic->op != GETHBIT && 1) @@ -2312,7 +2570,7 @@ packRegsForAccUse2 (iCode * ic) bitVectUnSetBit (uses, setBit); /* Still contigous. */ - if (!opPreservesA (ic, next)) + if (!opPreservesA (next)) { D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A\n")); return; @@ -2324,7 +2582,7 @@ packRegsForAccUse2 (iCode * ic) { if (next->prev == NULL) { - if (!opPreservesA (ic, next)) + if (!opPreservesA (next)) { D (D_ACCUSE2, (" + Dropping as operation doesn't preserve A #2\n")); return; @@ -2364,110 +2622,6 @@ packRegsForAccUse2 (iCode * ic) OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A; return; } - - /* OLD CODE FOLLOWS */ - /* if it is a conditional branch then we definitely can - MLH: Depends. - */ -#if 0 - if (uic->op == IFX) - goto accuse; - - /* MLH: Depends. */ - if (uic->op == JUMPTABLE) - return; -#endif - - /* if the usage is not is an assignment or an - arithmetic / bitwise / shift operation then not. - MLH: Pending: Invalid. Our pointer sets are always peechy. - */ -#if 0 - if (POINTER_SET (uic) && - getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE)) > 1) - { - printf ("e5 %u\n", getSize (aggrToPtr (operandType (IC_RESULT (uic)), FALSE))); - return; - } -#endif - - printf ("1\n"); - if (uic->op != '=' && - !IS_ARITHMETIC_OP (uic) && - !IS_BITWISE_OP (uic) && - uic->op != LEFT_OP && - uic->op != RIGHT_OP) - { - printf ("e6\n"); - return; - } - - /* if used in ^ operation then make sure right is not a - literl */ - if (uic->op == '^' && isOperandLiteral (IC_RIGHT (uic))) - return; - - /* if shift operation make sure right side is not a literal */ - if (uic->op == RIGHT_OP && - (isOperandLiteral (IC_RIGHT (uic)) || - getSize (operandType (IC_RESULT (uic))) > 1)) - return; - - if (uic->op == LEFT_OP && - (isOperandLiteral (IC_RIGHT (uic)) || - getSize (operandType (IC_RESULT (uic))) > 1)) - return; - -#if 0 - /* make sure that the result of this icode is not on the - stack, since acc is used to compute stack offset */ - if (IS_TRUE_SYMOP (IC_RESULT (uic)) && - OP_SYMBOL (IC_RESULT (uic))->onStack) - return; -#endif - -#if 0 - /* if either one of them in far space then we cannot */ - if ((IS_TRUE_SYMOP (IC_LEFT (uic)) && - isOperandInFarSpace (IC_LEFT (uic))) || - (IS_TRUE_SYMOP (IC_RIGHT (uic)) && - isOperandInFarSpace (IC_RIGHT (uic)))) - return; -#endif - - /* if the usage has only one operand then we can */ - if (IC_LEFT (uic) == NULL || - IC_RIGHT (uic) == NULL) - goto accuse; - - /* make sure this is on the left side if not - a '+' since '+' is commutative */ - if (ic->op != '+' && - IC_LEFT (uic)->key != IC_RESULT (ic)->key) - return; - - /* if one of them is a literal then we can */ - if ((IC_LEFT (uic) && IS_OP_LITERAL (IC_LEFT (uic))) || - (IC_RIGHT (uic) && IS_OP_LITERAL (IC_RIGHT (uic)))) - { - goto accuse; - return; - } - -/** This is confusing :) Guess for now */ - if (IC_LEFT (uic)->key == IC_RESULT (ic)->key && - (IS_ITEMP (IC_RIGHT (uic)) || - (IS_TRUE_SYMOP (IC_RIGHT (uic))))) - goto accuse; - - if (IC_RIGHT (uic)->key == IC_RESULT (ic)->key && - (IS_ITEMP (IC_LEFT (uic)) || - (IS_TRUE_SYMOP (IC_LEFT (uic))))) - goto accuse; - return; -accuse: - printf ("acc ok!\n"); - OP_SYMBOL (IC_RESULT (ic))->accuse = ACCUSE_A; } /** Does some transformations to reduce register pressure. @@ -2555,6 +2709,13 @@ packRegisters (eBBlock * ebp) packRegsForSupport (ic, ebp); #endif + /* some cases the redundant moves can + can be eliminated for return statements */ + if (ic->op == RETURN || ic->op == SEND) + { + packRegsForOneuse (ic, IC_LEFT (ic), ebp); + } + /* if pointer set & left has a size more than one and right is not in far space */ if (!DISABLE_PACK_ONE_USE && @@ -2591,7 +2752,15 @@ packRegisters (eBBlock * ebp) if (!DISABLE_PACK_HL && IS_ITEMP (IC_RESULT (ic))) { - packRegsForHLUse (ic); + if (IS_GB) + packRegsForHLUse (ic); + else + packRegsForHLUse3 (ic, IC_RESULT (ic), ebp); + } + + if (!DISABLE_PACK_HL && IS_ITEMP (IC_RESULT (ic)) && IS_Z80) + { + packRegsForIYUse (ic, IC_RESULT (ic), ebp); } if (!DISABLE_PACK_ACC && IS_ITEMP (IC_RESULT (ic)) && diff --git a/src/z80/ralloc.h b/src/z80/ralloc.h index 21806142..fb93bdc9 100644 --- a/src/z80/ralloc.h +++ b/src/z80/ralloc.h @@ -50,9 +50,14 @@ enum CND_IDX }; -#define REG_PTR 0x01 -#define REG_GPR 0x02 -#define REG_CND 0x04 +enum + { + REG_PTR = 1, + REG_GPR = 2, + REG_CND = 4, + REG_PAIR = 8 + }; + /* definition for the registers */ typedef struct regs { diff --git a/src/z80/z80.h b/src/z80/z80.h index 66c55676..f34981ec 100644 --- a/src/z80/z80.h +++ b/src/z80/z80.h @@ -26,5 +26,6 @@ extern Z80_OPTS z80_opts; enum { ACCUSE_A = 1, - ACCUSE_SCRATCH + ACCUSE_SCRATCH, + ACCUSE_IY }; diff --git a/support/regression/failing/bug-435214.c b/support/regression/tests/bug-435214.c similarity index 50% rename from support/regression/failing/bug-435214.c rename to support/regression/tests/bug-435214.c index e19adf11..a8887caa 100644 --- a/support/regression/failing/bug-435214.c +++ b/support/regression/tests/bug-435214.c @@ -3,7 +3,7 @@ #include static -unsigned int divide(long a) +unsigned long divide(long a) { return a/512ul; } @@ -11,7 +11,7 @@ unsigned int divide(long a) static void testDivide() { - assert(divide(1300) == 2); - assert(divide(0x12345678) == 0x91A2B); + ASSERT(divide(1300) == 2); + ASSERT(divide(0x12345678) == 0x91A2B); } diff --git a/support/regression/tests/driverstruct.c b/support/regression/tests/driverstruct.c index 0a9c4aa6..9521a28c 100644 --- a/support/regression/tests/driverstruct.c +++ b/support/regression/tests/driverstruct.c @@ -43,3 +43,8 @@ initProxy(devsw_t *pdrv) return (*pdrv->dev_init)(5); } +void +testDriverStruct(void) +{ + initProxy(&_sillyDriver); +} diff --git a/support/regression/tests/logic.c b/support/regression/tests/logic.c index 085cd746..1636d334 100644 --- a/support/regression/tests/logic.c +++ b/support/regression/tests/logic.c @@ -51,19 +51,17 @@ testLogicalAnd(void) ASSERT(true && !false); ASSERT(!false && true); -#if 1 /* PENDING: Doesn't work. */ /* Test that the evaluation is aborted on the first false. */ if (true && false && neverGetHere()) { /* Tested using neverGetHere() */ } -#else + /* Alternate that is similar. */ if (true && false) { neverGetHere(); /* Tested using neverGetHere() */ } -#endif resetGetHere(); /* Test that the evaluation is done left to right. */ @@ -82,15 +80,11 @@ testLogicalOr(void) ASSERT(!true || !false); ASSERT(false || true); -#if 0 /* PENDING: Doesn't work in sdcc. */ /* Test that the evaluation is aborted on the first hit. */ if (false || true || neverGetHere()) { /* Tested using neverGetHere() */ } -#else - /* No equivalent. */ -#endif resetGetHere(); /* Test that the evaluation is done left to right. */ -- 2.30.2