Major bugfix where instructions weren't being shrunk correctly. (Turns out there...
authorDavid Given <dg@cowlark.com>
Sat, 25 May 2013 22:26:10 +0000 (23:26 +0100)
committerDavid Given <dg@cowlark.com>
Sat, 25 May 2013 22:26:10 +0000 (23:26 +0100)
--HG--
branch : dtrg-videocore

mach/vc4/as/mach1.c
mach/vc4/as/mach5.c

index de16461..315468f 100644 (file)
@@ -10,7 +10,7 @@
 #define ALWAYS 14
 
 extern void alu_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
-extern void alu_instr_lit(quad opcode, int cc, int rd, int ra, quad value);
+extern void alu_instr_lit(quad opcode, int cc, int rd, int ra, long value);
 extern void misc_instr_reg(quad opcode, int cc, int rd, int ra, int rb);
 extern void misc_instr_lit(quad opcode, int cc, int rd, int ra, quad value);
 extern void branch_instr(int bl, int cc, struct expr_t* expr);
index 53ec346..a2227fd 100644 (file)
@@ -34,12 +34,12 @@ void alu_instr_reg(quad op, int cc, int rd, int ra, int rb)
 
 /* Assemble an ALU instruction where rb is a literal. */
 
-void alu_instr_lit(quad op, int cc, int rd, int ra, quad value)
+void alu_instr_lit(quad op, int cc, int rd, int ra, long value)
 {
        /* 16 bit short form? */
 
-       if ((cc == ALWAYS) && !(op & 1) && (value <= 0x1f) && (ra == rd) &&
-               (ra < 0x10))
+       if ((cc == ALWAYS) && !(op & 1) && (value >= 0) && (value <= 0x1f) &&
+           (ra == rd) && (ra < 0x10))
        {
                emit2(B16(01100000,00000000) | (op<<8) | (value<<4) | (rd<<0));
                return;
@@ -47,7 +47,7 @@ void alu_instr_lit(quad op, int cc, int rd, int ra, quad value)
 
        /* 32 bit medium form? */
 
-    if (value <= 0x1f)
+    if ((value >= 0) && (value <= 0x1f))
     {
         emit2(B16(11000000,00000000) | (op<<5) | (rd<<0));
         emit2(B16(00000000,01000000) | (ra<<11) | (cc<<7) | (value<<0));
@@ -99,6 +99,7 @@ void branch_instr(int bl, int cc, struct expr_t* expr)
 {
        quad pc = DOTVAL;
        quad type = expr->typ & S_TYP;
+       int d;
 
        /* Sanity checking. */
 
@@ -107,71 +108,52 @@ void branch_instr(int bl, int cc, struct expr_t* expr)
        if (type == S_ABS)
                serror("can't use absolute addresses here");
 
-       switch (pass)
-       {
-               case 0:
-                       /* Calculate size of instructions only. For now we just assume
-                        * that they're going to be the maximum size, 32 bits. */
-
-                       emit4(0);
-                       break;
+       /* The VC4 branch instructions express distance in 2-byte
+        * words. */
 
-               case 1:
-               case 2:
-               {
-                       /* The VC4 branch instructions express distance in 2-byte
-                        * words. */
+       d = (int32_t)expr->val - (int32_t)pc;
+       if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+        d -= DOTGAIN;
+       d /= 2;
 
-                       int d = ((int32_t)expr->val - (int32_t)pc) / 2;
+    /* If this is a reference to code within this section, and it's
+     * close enough to the program counter, we can use a short-
+     * form instruction. */
 
-               /* We now know the worst case for the instruction layout. At
-                * this point we can emit the instructions, which may shrink
-                * the code. */
-
-                       if (!bl && (type == DOTTYP))
-                       {
-                   /* This is a reference to code within this section. If it's
-                    * close enough to the program counter, we can use a short-
-                    * form instruction. */
-
-                   if (fitx(d, 7))
-                   {
-                                       emit2(B16(00011000,00000000) | (cc<<7) | (d&0x7f));
-                                       break;
-                               }
-                       }
+    if (small(!bl && (type == DOTTYP) && fitx(d, 7), 2))
+    {
+               emit2(B16(00011000,00000000) | (cc<<7) | (d&0x7f));
+               return;
+       }
 
-                       /* Absolute addresses and references to other sections
-                        * need the full 32 bits. */
+       /* Absolute addresses and references to other sections
+        * need the full 32 bits. */
 
-                       newrelo(expr->typ, RELOVC4|RELPC);
+       newrelo(expr->typ, RELOVC4|RELPC);
 
-                       if (bl)
-                       {
-                               quad v, hiv, lov;
+       if (bl)
+       {
+               quad v, hiv, lov;
 
-                               if (!fitx(d, 27))
-                                       toobig();
+               if (!fitx(d, 27))
+                       toobig();
 
-                               v = maskx(d, 27);
-                               hiv = v >> 23;
-                               lov = v & 0x007fffff;
-                               emit2(B16(10010000,10000000) | (lov>>16) | (hiv<<8));
-                               emit2(B16(00000000,00000000) | (lov&0xffff));
-                       }
-                       else
-                       {
-                               quad v;
+               v = maskx(d, 27);
+               hiv = v >> 23;
+               lov = v & 0x007fffff;
+               emit2(B16(10010000,10000000) | (lov>>16) | (hiv<<8));
+               emit2(B16(00000000,00000000) | (lov&0xffff));
+       }
+       else
+       {
+               quad v;
 
-                               if (!fitx(d, 23))
-                                       toobig();
+               if (!fitx(d, 23))
+                       toobig();
 
-                               v = maskx(d, 23);
-                               emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
-                               emit2(B16(00000000,00000000) | (v&0xffff));
-                       }
-                       break;
-        }
+               v = maskx(d, 23);
+               emit2(B16(10010000,00000000) | (cc<<8) | (v>>16));
+               emit2(B16(00000000,00000000) | (v&0xffff));
        }
 }
 
@@ -352,66 +334,45 @@ void mem_postincr_instr(quad opcode, int cc, int rd, int rs)
 
 void mem_address_instr(quad opcode, int rd, struct expr_t* expr)
 {
-       static const char sizes[] = {4, 2, 1, 2};
+       static const char sizes[] = {4, 4, 2, 2, 1, 1, 2, 2};
        int size = sizes[opcode];
        quad type = expr->typ & S_TYP;
+       int d, scaledd;
 
        /* Sanity checking. */
 
        if (type == S_ABS)
                serror("can't use absolute addresses here");
 
-       switch (pass)
-       {
-               case 0:
-                       /* Calculate size of instructions only. For now we just assume
-                        * that they're going to be the maximum size, 48 bits. */
-
-                       emit2(0);
-                       emit4(0);
-                       break;
-
-               case 1:
-               case 2:
-               {
-                       int d = expr->val - DOTVAL;
+       d = expr->val - DOTVAL;
+       if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+        d -= DOTGAIN;
+    scaledd = d/size;
 
-               /* We now know the worst case for the instruction layout. At
-                * this point we can emit the instructions, which may shrink
-                * the code. */
+    /* If this is a reference to an address within this section, and
+     * it's close enough to the program counter, we can use a
+     * shorter instruction. */
 
-                       if (type == DOTTYP)
-                       {
-                               int scaledd = d/size;
-
-                   /* This is a reference to an address within this section. If
-                    * it's close enough to the program counter, we can use a
-                    * shorter instruction. */
-
-                               if (fitx(scaledd, 16))
-                               {
-                    emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
-                    emit2(scaledd);
-                    return;
-                }
-                       }
+       if (small((type==DOTTYP) && fitx(scaledd, 16), 2))
+       {
+        emit2(B16(10101010,00000000) | (opcode<<5) | (rd<<0));
+        emit2(scaledd);
+        return;
+    }
 
-                       /* Otherwise we need the full 48 bits. */
+       /* Otherwise we need the full 48 bits. */
 
-                       newrelo(expr->typ, RELOVC4|RELPC);
+       newrelo(expr->typ, RELOVC4|RELPC);
 
-                       /* VC4 relocations store the PC-relative delta into the
-                        * destination section in the instruction data. The linker will
-                        * massage this, and scale it appropriately. */
+       /* VC4 relocations store the PC-relative delta into the
+        * destination section in the instruction data. The linker will
+        * massage this, and scale it appropriately. */
 
-            if (!fitx(d, 27))
-                               toobig();
+    if (!fitx(d, 27))
+               toobig();
 
-            emit2(B16(11100111,00000000) | (opcode<<5) | (rd<<0));
-            emit4((31<<27) | maskx(d, 27));
-                       break;
-        }
-       }
+    emit2(B16(11100111,00000000) | (opcode<<5) | (rd<<0));
+    emit4((31<<27) | maskx(d, 27));
 }
 
 /* Common code for handling addcmp: merge in as much of expr as will fit to
@@ -420,33 +381,23 @@ void mem_address_instr(quad opcode, int rd, struct expr_t* expr)
 static void branch_addcmp_common(quad opcode, int bits, struct expr_t* expr)
 {
        quad type = expr->typ & S_TYP;
+       int d;
 
-       switch (pass)
-       {
-               case 0:
-                       /* Calculate size of instructions only. */
-
-                       emit2(0);
-                       break;
-
-               case 1:
-               case 2:
-               {
-                       if (type != DOTTYP)
-                               serror("can't use this type of branch to jump outside the section");
+       if (type != DOTTYP)
+               serror("can't use this type of branch to jump outside the section");
 
-                       /* The VC4 branch instructions express distance in 2-byte
-                        * words. */
+       /* The VC4 branch instructions express distance in 2-byte
+        * words. */
 
-                       int d = (expr->val - DOTVAL-2 + 4) / 2;
+       d = (expr->val - DOTVAL-2 + 4);
+       if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+        d -= DOTGAIN;
+    d /= 2;
 
-                       if (!fitx(d, bits))
-                               serror("target of branch is too far away");
+       if (!fitx(d, bits))
+               serror("target of branch is too far away");
 
-                       emit2(opcode | maskx(d, bits));
-                       break;
-        }
-       }
+       emit2(opcode | maskx(d, bits));
 }
 
 void branch_addcmp_reg_reg_instr(int cc, int rd, int ra, int rs, struct expr_t* expr)
@@ -518,6 +469,10 @@ void lea_address_instr(int rd, struct expr_t* expr)
 {
        quad pc = DOTVAL;
        quad type = expr->typ & S_TYP;
+       int d = expr->val - pc;
+
+       if ((pass == 2) && (d > 0) && !(expr->typ & S_DOT))
+           d -= DOTGAIN;
 
        if (type == S_ABS)
                serror("can't use absolute addresses here");