Add assembler support for fixing up arbitrary oris/addi pairs of instructions;
authorDavid Given <dg@cowlark.com>
Sat, 14 Jan 2017 23:15:01 +0000 (00:15 +0100)
committerDavid Given <dg@cowlark.com>
Sat, 14 Jan 2017 23:15:01 +0000 (00:15 +0100)
this should allow oris/lwz constant value loads, which will save an opcode.

mach/powerpc/as/mach2.c
mach/powerpc/as/mach3.c
mach/powerpc/as/mach4.c
mach/powerpc/as/mach5.c
mach/powerpc/ncg/table
util/led/relocate.c

index 480c5fa..a07f21b 100644 (file)
@@ -84,6 +84,9 @@
 %token <y_word> OP_LA
 %token <y_word> OP_LI32
 
+%token <y_word> OP_POWERPC_FIXUP
+%token <y_word> OP_HI OP_LO
+
 /* Other token types */
 
 %type <y_word> c
index 0f0bfda..62ed204 100644 (file)
 0,     OP_LA,                 0,                                       "la",
 0,     OP_LA,                 0,                                       "li",
 0,     OP_RS_RA_RA_C,         31<<26 | 444<<1,                         "mr",
+0,     OP_POWERPC_FIXUP,      0,                                       ".powerpcfixup",
+0,     OP_HI,                 0,                                       "hi",
+0,     OP_LO,                 0,                                       "lo",
 
 /* Branch processor instructions (page 20) */
 
 0,     OP_RS_RA_SH_ME6_SH_C,  30<<26 | 1<<2,                           "rldicr",
 0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 2<<2,                           "rldic",
 0,     OP_RS_RA_SH_MB5_ME5_C, 21<<26,                                  "rlwinm",
-0,     OP_RS_RA_RB_MB6_C,     30<<26 | 8<<1,                           "rldcl", 
+0,     OP_RS_RA_RB_MB6_C,     30<<26 | 8<<1,                           "rldcl",
 0,     OP_RS_RA_RB_ME6_C,     30<<26 | 9<<1,                           "rldcr",
 0,     OP_RS_RA_RB_MB5_ME5_C, 23<<26,                                  "rlwnm",
 0,     OP_RS_RA_SH_MB6_SH_C,  30<<26 | 3<<2,                           "rldimi",
index e1fb3fd..d9e4b03 100644 (file)
@@ -19,9 +19,9 @@ operation
        | OP_FRS_RA_D          FPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
        | OP_FRS_RA_RB         FPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
        | OP_FRT_FRA_FRB_C     c FPR ',' FPR ',' FPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<11)); }
-       | OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); } 
+       | OP_FRT_FRA_FRC_FRB_C c FPR ',' FPR ',' FPR ',' FPR { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($9<<11) | ($7<<6)); }
        | OP_FRT_FRA_FRC_C     c FPR ',' FPR ',' FPR      { emit4($1 | $2 | ($3<<21) | ($5<<16) | ($7<<6)); }
-       | OP_FRT_FRB_C         c FPR ',' FPR              { emit4($1 | $2 | ($3<<21) | ($5<<11)); } 
+       | OP_FRT_FRB_C         c FPR ',' FPR              { emit4($1 | $2 | ($3<<21) | ($5<<11)); }
        | OP_FRT_RA_D          FPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
        | OP_FRT_RA_RB         FPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
        | OP_FRT_C             c FPR                      { emit4($1 | $2 | ($3<<21)); }
@@ -40,15 +40,15 @@ operation
        | OP_RS_RA_D           GPR ',' e16 '(' GPR ')'    { emit4($1 | ($2<<21) | ($6<<16) | $4); }
        | OP_RS_RA_DS          GPR ',' ds '(' GPR ')'     { emit4($1 | ($2<<21) | ($6<<16) | $4); }
        | OP_RS_RA_NB          GPR ',' GPR ',' nb         { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
-       | OP_RS_RA_UI          GPR ',' GPR ',' e16        { emit4($1 | ($4<<21) | ($2<<16) | $6); } 
-       | OP_RS_RA_UI_CC       C GPR ',' GPR ',' e16      { emit4($1 | ($5<<21) | ($3<<16) | $7); } 
+       | OP_RS_RA_UI          GPR ',' GPR ',' e16        { emit4($1 | ($4<<21) | ($2<<16) | $6); }
+       | OP_RS_RA_UI_CC       C GPR ',' GPR ',' e16      { emit4($1 | ($5<<21) | ($3<<16) | $7); }
        | OP_RS_RA_RB          GPR ',' GPR ',' GPR        { emit4($1 | ($2<<21) | ($4<<16) | ($6<<11)); }
        | OP_RS_RA_RB_C        c GPR ',' GPR ',' GPR      { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
        | OP_RS_RA_RA_C        c GPR ',' GPR              { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($5<<11)); }
-       | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }  
+       | OP_RS_RA_RB_MB5_ME5_C c GPR ',' GPR ',' GPR ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }
        | OP_RS_RA_RB_MB6_C    c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
        | OP_RS_RA_RB_ME6_C    c GPR ',' GPR ',' GPR ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | (($9&0x1F)<<6) | (($9&0x20)>>0)); }
-       | OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }  
+       | OP_RS_RA_SH_MB5_ME5_C c GPR ',' GPR ',' u5 ',' u5 ',' u5 { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11) | ($9<<6) | ($11<<1)); }
        | OP_RS_RA_SH_MB6_SH_C  c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
        | OP_RS_RA_SH_ME6_SH_C  c GPR ',' GPR ',' u6 ',' u6 { emit4($1 | $2 | ($5<<21) | ($3<<16) | (($7&0x1F)<<11) | ($9<<6) | (($7&0x20)>>4)); }
        | OP_RS_RA_SH5_C       c GPR ',' GPR ',' u5       { emit4($1 | $2 | ($5<<21) | ($3<<16) | ($7<<11)); }
@@ -60,13 +60,14 @@ operation
        | OP_LIA               lia                        { emit4($1 | $2); }
        | OP_LIL               lil                        { emit4($1 | $2); }
        | OP_LI32              li32                       /* emitted in subrule */
+       | OP_POWERPC_FIXUP     powerpcfixup               /* emitted in subrule */
        ;
 
 c
        : /* nothing */                          { $$ = 0; }
        | C                                      { $$ = 1; }
        ;
-       
+
 e16
        : absexp
        {
@@ -75,8 +76,34 @@ e16
                        serror("16-bit value out of range");
                $$ = (uint16_t) $1;
        }
+       | OP_HI expr
+       {
+               /* If this is a symbol reference, discard the symbol and keep only the
+                * offset part. */
+               quad type = $2.typ & S_TYP;
+               quad val = $2.val;
+
+               /* If the assembler stored a symbol for relocation later, we need to
+                * abandon it (because we're not going to generate a relocation). */
+               if (type != S_ABS)
+                       relonami = 0;
+
+               $$ = ((quad)val) >> 16;
+       }
+       | OP_LO expr
+       {
+               quad type = $2.typ & S_TYP;
+               quad val = $2.val;
+
+               /* If the assembler stored a symbol for relocation later, we need to
+                * abandon it (because we're not going to generate a relocation). */
+               if (type != S_ABS)
+                       relonami = 0;
+
+               $$ = val & 0xffff;
+       }
        ;
-               
+
 u8
        : absexp
        {
@@ -85,7 +112,7 @@ u8
                $$ = $1;
        }
        ;
-       
+
 u7
        : absexp
        {
@@ -94,7 +121,7 @@ u7
                $$ = $1;
        }
        ;
-       
+
 u6
        : absexp
        {
@@ -103,7 +130,7 @@ u6
                $$ = $1;
        }
        ;
-       
+
 u5
        : absexp
        {
@@ -112,7 +139,7 @@ u5
                $$ = $1;
        }
        ;
-       
+
 u4
        : absexp
        {
@@ -121,7 +148,7 @@ u4
                $$ = $1;
        }
        ;
-       
+
 u1
        : absexp
        {
@@ -130,7 +157,7 @@ u1
                $$ = $1;
        }
        ;
-       
+
 u2
        : absexp
        {
@@ -139,7 +166,7 @@ u2
                $$ = $1;
        }
        ;
-       
+
 ds
        : e16
        {
@@ -148,26 +175,26 @@ ds
                $$ = $1;
        }
        ;
-       
+
 nb
        : absexp
        {
                if (($1 < 1) || ($1 > 32))
                        serror("register count must be in the range 1..32");
-       
+
                if ($1 == 32)
                        $$ = 0;
                else
-                       $$ = $1;        
+                       $$ = $1;
        }
        ;
-       
+
 bdl
        : expr
        {
                int dist = $1.val - DOTVAL;
                fit(fitx(dist, 25));
-               
+
                if (dist & 0x3)
                        serror("jump targets must be 4-aligned");
 
@@ -183,7 +210,7 @@ bda
        {
                int target = $1.val;
                fit(fitx(target, 16));
-               
+
                if (target & 0x3)
                        serror("jump targets must be 4-aligned");
 
@@ -193,7 +220,7 @@ bda
                $$ = target & 0xFFFD;
        }
        ;
-       
+
 li32
        : GPR ',' expr
        {
@@ -215,7 +242,7 @@ lil
        {
                int dist = $1.val - DOTVAL;
                fit(fitx(dist, 26));
-               
+
                if (dist & 0x3)
                        serror("jump targets must be 4-aligned");
 
@@ -223,13 +250,13 @@ lil
                $$ = dist & 0x03FFFFFD;
        }
        ;
-       
+
 lia
        : expr
        {
                int target = $1.val;
                fit(fitx(target, 26));
-               
+
                if (target & 0x3)
                        serror("jump targets must be 4-aligned");
 
@@ -248,3 +275,14 @@ spr_num
                $$ = ($1 >> 5) | (($1 & 0x1f) << 5);
        }
        ;
+
+powerpcfixup
+       : expr
+       {
+               quad type = $1.typ & S_TYP;
+               quad val = $1.val;
+               if (type == S_ABS)
+                       serror(".powerpcfixup is useless on absolute values");
+               newrelo($1.typ, RELOPPC | FIXUPFLAGS);
+       }
+       ;
index 998cd8d..5b8eb91 100644 (file)
@@ -2,4 +2,3 @@
  * $Source$
  * $State$
  */
-
index 52f335c..29353a2 100644 (file)
@@ -169,11 +169,14 @@ TOKENS
 /* Used only in instruction descriptions (to generate the correct syntax). */
 
        GPRINDIRECT        = { GPR reg; INT off; }    4    off "(" reg ")".
+       GPRINDIRECT_OFFSET_LO = { GPR reg; ADDR adr; } 4   "lo [" adr "](" reg ")".
        CONST              = { INT val; }             4    val.
 
 /* Primitives */
 
        LABEL              = { ADDR adr; }            4    adr.
+       LABEL_OFFSET_HI    = { ADDR adr; }            4    "hi " adr.
+       LABEL_OFFSET_LO    = { ADDR adr; }            4    "lo " adr.
        LOCAL              = { INT off; }             4.
 
 /* Allows us to use regvar() to refer to registers */
@@ -282,7 +285,7 @@ INSTRUCTIONS
   add             GPR:wo, GPR:ro, GPR:ro.
   addX "add."     GPR:wo, GPR:ro, GPR:ro.
   addi            GPR:wo, GPR:ro, CONST:ro.
-  addis           GPR:wo, GPR:ro, CONST:ro.
+  addis           GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HI:ro.
   and             GPR:wo, GPR:ro, GPR:ro.
   andc            GPR:wo, GPR:ro, GPR:ro.
   andiX  "andi."  GPR:wo:cc, GPR:ro, CONST:ro.
@@ -329,10 +332,9 @@ INSTRUCTIONS
   lhz             GPR:wo, GPRINDIRECT:ro cost(4, 3).
   lhzx            GPR:wo, GPR:ro, GPR:ro cost(4, 3).
   li32            GPR:wo, CONST:ro cost(8, 2).
-  li32            GPR:wo, LABEL:ro cost(8, 2).
   lwzu            GPR:wo, GPRINDIRECT:ro cost(4, 3).
   lwzx            GPR:wo, GPR:ro, GPR:ro cost(4, 3).
-  lwz             GPR:wo, GPRINDIRECT:ro cost(4, 3).
+  lwz             GPR:wo, GPRINDIRECT+GPRINDIRECT_OFFSET_LO:ro cost(4, 3).
   nand            GPR:wo, GPR:ro, GPR:ro.
   neg             GPR:wo, GPR:ro.
   nor             GPR:wo, GPR:ro, GPR:ro.
@@ -342,7 +344,7 @@ INSTRUCTIONS
   mtspr           SPR:wo, GPR:ro cost(4, 2).
   or              GPR:wo, GPR:ro, GPR:ro.
   orc             GPR:wo, GPR:ro, GPR:ro.
-  ori             GPR:wo, GPR:ro, CONST:ro.
+  ori             GPR:wo, GPR:ro, CONST+LABEL_OFFSET_LO:ro.
   oris            GPR:wo, GPR:ro, CONST:ro.
   orX "or."       GPR:wo:cc, GPR:ro, GPR:ro.
   rlwinm          GPR:wo, GPR:ro, CONST:ro, CONST:ro, CONST:ro.
@@ -368,7 +370,8 @@ INSTRUCTIONS
   xori            GPR:wo, GPR:ro, CONST:ro.
   xoris           GPR:wo, GPR:ro, CONST:ro.
 
-  comment "!" LABEL:ro cost(0, 0).
+  fixup   ".powerpcfixup" LABEL:ro.
+  comment "!"             LABEL:ro cost(0, 0).
 
 
 
@@ -405,7 +408,9 @@ MOVES
        from LABEL to GPR
                gen
                        COMMENT("move LABEL->GPR")
-                       li32 %2, {LABEL, %1.adr}
+                       fixup {LABEL, %1.adr}
+                       addis %2, R0, {LABEL_OFFSET_HI, %1.adr}
+                       ori %2, %2, {LABEL_OFFSET_LO, %1.adr}
 
 /* Sign extension */
 
@@ -1142,6 +1147,13 @@ PATTERNS
                        yields {IND_RC_H, %1.reg, %1.off}
 
        pat loi $1==INT32                  /* Load word indirect */
+               with LABEL
+                       uses REG
+                       gen
+                               fixup {LABEL, %1.adr}
+                               addis %a, R0, {LABEL_OFFSET_HI, %1.adr}
+                               lwz %a, {GPRINDIRECT_OFFSET_LO, %a, %1.adr}
+                       yields %a
                with GPR
                        yields {IND_RC_W, %1, 0}
                with SUM_RC
index c72965e..02b0be3 100644 (file)
@@ -119,14 +119,13 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type)
                /* branch instruction */
                return opcode1 & 0x03fffffd;
        }
-       else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
-                ((opcode2 & 0xfc000000) == 0x60000000))
+       else
        {
-               /* addis / ori instruction pair */
+               /* If it's not a branch, we're just going to assume that the user
+                * knows what they're doing and this is a addis/ori pair (or
+                * compatible). */
                return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff);
        }
-
-       assert(0 && "unrecognised PowerPC instruction");
 }
 
 /*
@@ -260,17 +259,17 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
                i |= value & 0x03fffffd;
                write4(i, addr, type);
        }
-       else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
-                ((opcode2 & 0xfc000000) == 0x60000000))
+       else
        {
+               /* If it's not a branch, we're just going to assume that the user
+                * knows what they're doing and this is a addis/ori pair (or
+                * compatible). */
                uint16_t hi = value >> 16;
                uint16_t lo = value & 0xffff;
 
                write4((opcode1 & 0xffff0000) | hi, addr+0, type);
                write4((opcode2 & 0xffff0000) | lo, addr+4, type);
        }
-       else
-               assert(0 && "unrecognised PowerPC instruction");
 }
 
 /*
@@ -339,7 +338,7 @@ addrelo(relo, names, valu_out)
                extern int              hash();
                extern struct outname   *searchname();
                extern unsigned         indexof();
-               extern struct outhead   outhead; 
+               extern struct outhead   outhead;
 
                name = searchname(local->on_mptr, hash(local->on_mptr));
                if (name == (struct outname *)0)