- operand *right, *left, *result;
- int size, offset;
- char *l;
- symbol *tlbl, *tlbl1 ;
-
- /* we do it the hard way put the shift count in b
- and loop thru preserving the sign */
-
- right = IC_RIGHT(ic);
- left = IC_LEFT(ic);
- result = IC_RESULT(ic);
-
- aopOp(right,ic,FALSE);
-
-
- if ( AOP_TYPE(right) == AOP_LIT) {
- genRightShiftLiteral (left,right,result,ic,1);
- return ;
- }
- /* shift count is unknown then we have to form
- a loop get the loop count in B : Note: we take
- only the lower order byte since shifting
- more that 32 bits make no sense anyway, ( the
- largest size of an object can be only 32 bits ) */
-
- emitcode("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE));
- emitcode("inc","b");
- freeAsmop (right,NULL,ic,TRUE);
- aopOp(left,ic,FALSE);
- aopOp(result,ic,FALSE);
-
- /* now move the left to the result if they are not the
- same */
- if (!sameRegs(AOP(left),AOP(result)) &&
- AOP_SIZE(result) > 1) {
-
- size = AOP_SIZE(result);
- offset=0;
- while (size--) {
- l = aopGet(AOP(left),offset,FALSE,TRUE);
- if (*l == '@' && IS_AOP_PREG(result)) {
-
- emitcode("mov","a,%s",l);
- aopPut(AOP(result),"a",offset);
- } else
- aopPut(AOP(result),l,offset);
- offset++;
- }
- }
-
- /* mov the highest order bit to OVR */
- tlbl = newiTempLabel(NULL);
- tlbl1= newiTempLabel(NULL);
-
- size = AOP_SIZE(result);
- offset = size - 1;
- emitcode("mov","a,%s",aopGet(AOP(left),offset,FALSE,FALSE));
- emitcode("rlc","a");
- emitcode("mov","ov,c");
- /* if it is only one byte then */
- if (size == 1) {
- l = aopGet(AOP(left),0,FALSE,FALSE);
- MOVA(l);
- emitcode("sjmp","%05d$",tlbl1->key+100);
- emitcode("","%05d$:",tlbl->key+100);
- emitcode("mov","c,ov");
- emitcode("rrc","a");
- emitcode("","%05d$:",tlbl1->key+100);
- emitcode("djnz","b,%05d$",tlbl->key+100);
- aopPut(AOP(result),"a",0);
- goto release ;
- }
-
- reAdjustPreg(AOP(result));
- emitcode("sjmp","%05d$",tlbl1->key+100);
- emitcode("","%05d$:",tlbl->key+100);
- emitcode("mov","c,ov");
- while (size--) {
- l = aopGet(AOP(result),offset,FALSE,FALSE);
- MOVA(l);
- emitcode("rrc","a");
- aopPut(AOP(result),"a",offset--);
- }
- reAdjustPreg(AOP(result));
- emitcode("","%05d$:",tlbl1->key+100);
- emitcode("djnz","b,%05d$",tlbl->key+100);
-
-release:
- freeAsmop(left,NULL,ic,TRUE);
- freeAsmop(result,NULL,ic,TRUE);
+ operand *left, *right, *result;
+ int size, offset;
+ symbol *tlbl;
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (right, ic, FALSE);
+
+ if (AOP_TYPE (right) == AOP_LIT) {
+ genShiftLeftLit (ic);
+ return;
+ }
+
+ /* unknown count */
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+ size = AOP_SIZE (result);
+ offset = 0;
+ if (AOP_SIZE (right) > 1) {
+ if (isRegPair (AOP (right))) {
+ emitcode ("movw", "r24,%s", aopGet (AOP (right), 0));
+ }
+ else {
+ emitcode ("mov", "r24,%s", aopGet (AOP (right), 0));
+ emitcode ("mov", "r25,%s", aopGet (AOP (right), 1));
+ }
+ }
+ else {
+ emitcode ("mov", "r24,%s", aopGet (AOP (right), 0));
+ }
+ if (!sameRegs (AOP (left), AOP (result))) {
+ while (size--) {
+ aopPut (AOP (result), aopGet (AOP (left), offset),
+ offset);
+ offset++;
+ }
+ size = AOP_SIZE (result);
+ }
+ tlbl = newiTempLabel (NULL);
+ emitcode ("", "L%05d:", tlbl->key);
+ offset = 0;
+ while (size--) {
+ if (offset)
+ emitcode ("rol", "%s", aopGet (AOP (result), offset));
+ else
+ emitcode ("lsl", "%s", aopGet (AOP (result), 0));
+ offset++;
+ }
+ if (AOP_SIZE (right) > 1)
+ emitcode ("sbiw", "r24,1");
+ else
+ emitcode ("dec", "r24");
+ emitcode ("brne", "L%05d", tlbl->key);
+
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);
+}
+
+/*-----------------------------------------------------------------*/
+/* genShiftRightLit - generate for right shift with known count */
+/*-----------------------------------------------------------------*/
+static void
+genShiftRightLit (iCode * ic)
+{
+ operand *left = IC_LEFT (ic)
+ , *right = IC_RIGHT (ic)
+ , *result = IC_RESULT (ic);
+ int size, shCount, offset = 0;
+ int hByteZ = 0;
+ sym_link *letype = getSpec (operandType (left));
+ int sign = !SPEC_USIGN (letype);
+
+ right = IC_RIGHT (ic);
+ left = IC_LEFT (ic);
+ result = IC_RESULT (ic);
+
+ aopOp (left, ic, FALSE);
+ aopOp (result, ic, FALSE);
+ size = AOP_SIZE (result);
+ shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
+
+ /* if signed then give up and use a loop to shift */
+ if (sign) {
+ symbol *tlbl;
+ if (!sameRegs (AOP (left), AOP (result))) {
+ while (size--) {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset), offset);
+ offset++;
+ }
+ size = AOP_SIZE (result);
+ offset = 0;
+ }
+ /* be as economical as possible */
+ if (shCount <= 4) {
+ while (shCount--) {
+ size = AOP_SIZE (result);
+ offset = size - 1;
+ while (size--) {
+ /* highest order byte */
+ if (offset == (AOP_SIZE(result)-1))
+ emitcode ("asr", "%s", aopGet (AOP (result), offset));
+ else
+ emitcode ("ror", "%s", aopGet (AOP (result), offset));
+ offset--;
+ }
+ }
+ }
+ else {
+ emitcode ("ldi", "r24,<(%d)", shCount);
+ tlbl = newiTempLabel (NULL);
+ emitcode ("", "L%05d:", tlbl->key);
+ offset = size - 1;
+ while (size--) {
+ if (offset == (AOP_SIZE(result) - 1))
+ emitcode ("asr", "%s", aopGet (AOP (result), offset));
+ else
+ emitcode ("ror", "%s", aopGet (AOP (result), offset));
+ offset--;
+ }
+ emitcode ("dec", "r24");
+ emitcode ("brne", "L%05d", tlbl->key);
+ }
+ goto release;
+ }
+ if (shCount > (size * 8 - 1)) {
+ while (size--)
+ aopPut (AOP (result), zero, offset++);
+ goto release;
+ }
+ /* for unsigned we can much more efficient */
+ switch (size) {
+ case 1:
+ if (!sameRegs (AOP (left), AOP (result)))
+ aopPut (AOP (result), aopGet (AOP (left), 0), 0);
+ if (shCount >= 4) {
+ emitcode ("swap", "%s", aopGet (AOP (result), 0));
+ if (AOP_ISHIGHREG(AOP(result),0)) {
+ emitcode ("andi", "%s,0x0f",aopGet(AOP(result),0));
+ } else {
+ emitcode ("ldi","r24,0x0f");
+ emitcode ("and", "%s,r24",aopGet(AOP(result),0));
+ }
+ shCount -= 4;
+ }
+ while (shCount--)
+ emitcode ("lsr", "%s", aopGet (AOP (result), 0));
+ break;
+ case 2:
+ if (shCount >= 12) {
+ aopPut (AOP (result), aopGet (AOP (left), 1), 0);
+ aopPut (AOP (result), zero, 1);
+ emitcode ("swap", "%s", aopGet (AOP (result), 0));
+ if (AOP_ISHIGHREG(AOP(result),0)) {
+ emitcode ("andi", "%s,0x0f", aopGet (AOP (result), 0));
+ } else {
+ emitcode ("ldi","r24,0x0f");
+ emitcode ("and", "%s,r24",aopGet(AOP(result),0));
+ }
+ shCount -= 12;
+ hByteZ = 1;
+ }
+ if (shCount >= 8) {
+ aopPut (AOP (result), aopGet (AOP (left), 1), 0);
+ aopPut (AOP (result), zero, 1);
+ shCount -= 8;
+ hByteZ = 1;
+ }
+ if (shCount >= 4) {
+ shCount -= 4;
+ if (!sameRegs (AOP (left), AOP (result))) {
+ aopPut (AOP (result), aopGet (AOP (left), 0), 0);
+ aopPut (AOP (result), aopGet (AOP (left), 1), 1);
+ }
+ if (!(AOP_ISHIGHREG(AOP(result),0) && AOP_ISHIGHREG(AOP(result),1))) {
+ emitcode("ldi","r25,0x0f");
+ }
+ emitcode ("mov", "r24,%s", aopGet (AOP (result), 1));
+ emitcode ("andi", "r24,0xf0");
+ emitcode ("swap", "%s", aopGet (AOP (result), 0));
+ if (AOP_ISHIGHREG(AOP(result),0)) {
+ emitcode ("andi", "%s,0x0f", aopGet (AOP (result), 0));
+ } else {
+ emitcode ("and", "%s,r25", aopGet (AOP (result), 0));
+ }
+ emitcode ("or", "%s,r24", aopGet (AOP (result), 0));
+ emitcode ("swap", "%s", aopGet (AOP (result), 1));
+ if (AOP_ISHIGHREG(AOP(result),1)) {
+ emitcode ("andi", "%s,0x0f", aopGet (AOP (result), 1));
+ } else {
+ emitcode ("and", "%s,r24", aopGet (AOP (result), 1));
+ }
+ while (shCount--) {
+ emitcode ("lsr", "%s", aopGet (AOP (result), 1));
+ emitcode ("ror", "%s", aopGet (AOP (result), 0));
+ }
+
+ }
+ if (!hByteZ && !sameRegs (AOP (result), AOP (left))
+ && shCount) {
+ offset = 0;
+ while (size--) {
+ aopPut (AOP (result), aopGet (AOP (left), offset), offset);
+ offset++;
+ }
+ }
+ while (shCount--) {
+ if (hByteZ) {
+ emitcode ("lsr", "%s", aopGet (AOP (result), 0));
+ }
+ else {
+ emitcode ("lsr", "%s", aopGet (AOP (result), 1));
+ emitcode ("ror", "%s", aopGet (AOP (result), 0));
+ }
+ }
+ break;
+
+ case 3:
+ assert ("shifting generic pointer ?\n");
+ break;
+ case 4:
+ /* 32 bits we do only byte boundaries */
+ if (shCount >= 24) {
+ aopPut (AOP (result), aopGet (AOP (left), 3), 0);
+ aopPut (AOP (result), zero, 1);
+ aopPut (AOP (result), zero, 2);
+ aopPut (AOP (result), zero, 3);
+ hByteZ = 3;
+ shCount -= 24;
+ }
+ if (shCount >= 16) {
+ aopPut (AOP (result), aopGet (AOP (left), 3), 1);
+ aopPut (AOP (result), aopGet (AOP (left), 2), 0);
+ aopPut (AOP (result), zero, 2);
+ aopPut (AOP (result), zero, 3);
+ hByteZ = 2;
+ shCount -= 16;
+ }
+ if (shCount >= 8) {
+ aopPut (AOP (result), aopGet (AOP (left), 1), 0);
+ aopPut (AOP (result), aopGet (AOP (left), 2), 1);
+ aopPut (AOP (result), aopGet (AOP (left), 3), 2);
+ aopPut (AOP (result), zero, 3);
+ shCount -= 8;
+ hByteZ = 1;
+ }
+ if (!hByteZ && !sameRegs (AOP (left), AOP (right))) {
+ offset = 0;
+ while (size--) {
+ aopPut (AOP (result),
+ aopGet (AOP (left), offset), offset);
+ offset++;
+ }
+ offset = 0;
+ size = AOP_SIZE (result);
+ }
+ if (shCount) {
+ switch (hByteZ) {
+ case 0:
+ while (shCount--) {
+ emitcode ("lsr", "%s", aopGet (AOP (result), 3));
+ emitcode ("ror", "%s", aopGet (AOP (result), 2));
+ emitcode ("ror", "%s", aopGet (AOP (result), 1));
+ emitcode ("ror", "%s", aopGet (AOP (result), 0));
+ }
+ break;
+ case 1:
+ while (shCount--) {
+ emitcode ("lsr", "%s", aopGet (AOP (result), 2));
+ emitcode ("ror", "%s", aopGet (AOP (result), 1));
+ emitcode ("ror", "%s", aopGet (AOP (result), 0));
+ }
+ break;
+ case 2:
+ while (shCount--) {
+ emitcode ("lsr", "%s", aopGet (AOP (result), 1));
+ emitcode ("ror", "%s", aopGet (AOP (result), 0));
+ }
+ break;
+ case 3:
+ while (shCount--) {
+ emitcode ("lsr", "%s", aopGet (AOP (result), 0));
+ }
+ break;
+ }
+ }
+ }
+ release:
+ freeAsmop (left, NULL, ic, TRUE);
+ freeAsmop (right, NULL, ic, TRUE);
+ freeAsmop (result, NULL, ic, TRUE);