Signed vs unsigned lower halves of powerpc fixups are now handled by having two
authorDavid Given <dg@cowlark.com>
Sun, 15 Jan 2017 10:51:37 +0000 (11:51 +0100)
committerDavid Given <dg@cowlark.com>
Sun, 15 Jan 2017 10:51:37 +0000 (11:51 +0100)
assembler directives, ha16() and has16(), for the upper half; has16() applies
the sign adjustment. .powerpcfixup is now gone, as we generate the relocation
in ha*() instead. Add special logic to the linker for undoing and redoing the
sign adjustment when reading/writing fixups. Tests still pass.

mach/powerpc/as/mach1.c
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/const.h
util/led/debug.h
util/led/relocate.c

index 998cd8d..8cf9ca2 100644 (file)
@@ -3,3 +3,7 @@
  * $State$
  */
 
+#include <stdbool.h>
+
+extern quad emit_ha(struct expr_t* expr, bool is_signed);
+extern quad emit_lo(struct expr_t* expr);
index a07f21b..f64d148 100644 (file)
@@ -85,7 +85,7 @@
 %token <y_word> OP_LI32
 
 %token <y_word> OP_POWERPC_FIXUP
-%token <y_word> OP_HI OP_LO
+%token <y_word> OP_HA OP_HAS OP_LO
 
 /* Other token types */
 
index a40e249..74415aa 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,                                       "ha16",
+0,     OP_HA,                 0,                                       "ha16",
+0,     OP_HAS,                0,                                       "has16",
 0,     OP_LO,                 0,                                       "lo16",
 
 /* Branch processor instructions (page 20) */
index 0168775..bb6f516 100644 (file)
@@ -60,7 +60,6 @@ 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
@@ -76,32 +75,9 @@ e16
                        serror("16-bit value out of range");
                $$ = (uint16_t) $1;
        }
-       | OP_HI ASC_LPAR expr ASC_RPAR
-       {
-               /* If this is a symbol reference, discard the symbol and keep only the
-                * offset part. */
-               quad type = $3.typ & S_TYP;
-               quad val = $3.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 ASC_LPAR expr ASC_RPAR
-       {
-               quad type = $3.typ & S_TYP;
-               quad val = $3.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;
-       }
+       | OP_HA ASC_LPAR expr ASC_RPAR           { $$ = emit_ha(&$3, false); }
+       | OP_HAS ASC_LPAR expr ASC_RPAR          { $$ = emit_ha(&$3, true); }
+       | OP_LO ASC_LPAR expr ASC_RPAR           { $$ = emit_lo(&$3); }
        ;
 
 u8
index 5b8eb91..a8e4cd0 100644 (file)
@@ -1,4 +1,38 @@
-/*
- * $Source$
- * $State$
- */
+
+quad emit_ha(struct expr_t* expr, bool is_signed)
+{
+    /* If this is a symbol reference, discard the symbol and keep only the
+        * offset part. */
+    quad type = expr->typ & S_TYP;
+    quad val = expr->val;
+    uint16_t hi = val >> 16;
+    uint16_t lo = val & 0xffff;
+
+    if (type != S_ABS)
+               newrelo(expr->typ, RELOPPC | FIXUPFLAGS);
+
+    /* If the low half of this relocation is going to be a memory operation,
+     * then it'll be treated as a signed value. That means that values greater
+     * than 0x7fff will cause the high word to have 1 subtracted from it; so
+     * we apply an adjustment here.
+     */
+
+    if (is_signed && (lo > 0x7fff))
+        hi++;
+
+    return hi;
+}
+
+quad emit_lo(struct expr_t* expr)
+{
+    quad type = expr->typ & S_TYP;
+    quad val = expr->val;
+
+    /* If the assembler stored a symbol for relocation later, we need to
+     * abandon it (because the relocation was generated by emit_ha). */
+
+    if (type != S_ABS)
+        relonami = 0;
+
+    return val & 0xffff;
+}
index a907e42..d37bed8 100644 (file)
@@ -175,7 +175,8 @@ TOKENS
 /* Primitives */
 
        LABEL              = { ADDR adr; }            4    adr.
-       LABEL_OFFSET_HI    = { ADDR adr; }            4    "ha16[" adr "]".
+       LABEL_OFFSET_HA    = { ADDR adr; }            4    "ha16[" adr "]".
+       LABEL_OFFSET_HAS   = { ADDR adr; }            4    "has16[" adr "]".
        LABEL_OFFSET_LO    = { ADDR adr; }            4    "lo16[" adr "]".
        LOCAL              = { INT off; }             4.
 
@@ -285,7 +286,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+LABEL_OFFSET_HI:ro.
+  addis           GPR:wo, GPR:ro, CONST+LABEL_OFFSET_HA+LABEL_OFFSET_HAS:ro.
   and             GPR:wo, GPR:ro, GPR:ro.
   andc            GPR:wo, GPR:ro, GPR:ro.
   andiX  "andi."  GPR:wo:cc, GPR:ro, CONST:ro.
@@ -370,7 +371,6 @@ INSTRUCTIONS
   xori            GPR:wo, GPR:ro, CONST:ro.
   xoris           GPR:wo, GPR:ro, CONST:ro.
 
-  fixup   ".powerpcfixup" LABEL:ro.
   comment "!"             LABEL:ro cost(0, 0).
 
 
@@ -408,8 +408,7 @@ MOVES
        from LABEL to GPR
                gen
                        COMMENT("move LABEL->GPR")
-                       fixup {LABEL, %1.adr}
-                       addis %2, R0, {LABEL_OFFSET_HI, %1.adr}
+                       addis %2, R0, {LABEL_OFFSET_HA, %1.adr}
                        ori %2, %2, {LABEL_OFFSET_LO, %1.adr}
 
 /* Sign extension */
@@ -1150,8 +1149,7 @@ PATTERNS
                with LABEL
                        uses REG
                        gen
-                               fixup {LABEL, %1.adr}
-                               addis %a, R0, {LABEL_OFFSET_HI, %1.adr}
+                               addis %a, R0, {LABEL_OFFSET_HAS, %1.adr}
                                lwz %a, {GPRINDIRECT_OFFSET_LO, %a, %1.adr}
                        yields %a
                with GPR
index 40ad395..d2d27f5 100644 (file)
@@ -4,8 +4,6 @@
  */
 /* $Id$ */
 
-typedef int            bool;
-
 #define FALSE          0
 #define TRUE           1
 
index 0e49318..715409d 100644 (file)
@@ -17,3 +17,5 @@ extern int DEB;
 
 extern int Verbose;
 #define verbose(s, a1, a2, a3, a4)     (Verbose && do_verbose(s, a1, a2, a3, a4))
+
+extern void fatal(char* format, ...);
index 9e5c92b..613a0af 100644 (file)
@@ -9,6 +9,7 @@ static char rcsid[] = "$Id$";
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <assert.h>
 #include "out.h"
 #include "const.h"
@@ -104,6 +105,24 @@ static uint32_t get_vc4_valu(char* addr)
        assert(0 && "unrecognised VC4 instruction");
 }
 
+static bool is_powerpc_memory_op(uint32_t opcode)
+{
+       /* Tests for any PowerPC memory indirection instruction where the payload
+        * is a *signed* 16-bit value. */
+       switch ((opcode & 0xfc000000) >> 26)
+       {
+               case 34: /* lbz */
+               case 40: /* lhz */
+               case 32: /* lwz */
+               case 38: /* stb */
+               case 44: /* sth */
+               case 36: /* stw */
+                       return true;
+       }
+
+       return false;
+}
+
 /* PowerPC fixups are complex as we need to patch up to the next two
  * instructions in one of several different ways, depending on what the
  * instructions area.
@@ -125,8 +144,23 @@ static uint32_t get_powerpc_valu(char* addr, uint16_t type)
                /* addis / ori instruction pair */
                return ((opcode1 & 0xffff) << 16) | (opcode2 & 0xffff);
        }
+       else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
+                is_powerpc_memory_op(opcode2))
+       {
+               /* addis / memoryop instruction pair */
+               uint16_t hi = opcode1 & 0xffff;
+               uint16_t lo = opcode2 & 0xffff;
+
+               /* Undo the sign adjustment (see mach/powerpc/as/mach5.c). */
+
+               if (lo > 0x7fff)
+                       hi--;
+
+               return ((hi << 16) | lo);
+       }
 
-       assert(0 && "unrecognised PowerPC instruction");
+       fatal("Don't know how to read from PowerPC fixup on instructions 0x%08x+0x%08x",
+               opcode1, opcode2);
 }
 
 /*
@@ -269,8 +303,25 @@ static void put_powerpc_valu(char* addr, uint32_t value, uint16_t type)
                write4((opcode1 & 0xffff0000) | hi, addr+0, type);
                write4((opcode2 & 0xffff0000) | lo, addr+4, type);
        }
+       else if (((opcode1 & 0xfc1f0000) == 0x3c000000) &&
+                is_powerpc_memory_op(opcode2))
+       {
+               /* addis / memoryop instruction pair */
+               uint16_t hi = value >> 16;
+               uint16_t lo = value & 0xffff;
+
+               /* Apply the sign adjustment (see mach/powerpc/as/mach5.c). */
+
+               if (lo > 0x7fff)
+                       hi++;
+
+               write4((opcode1 & 0xffff0000) | hi, addr+0, type);
+               write4((opcode2 & 0xffff0000) | lo, addr+4, type);
+       }
+
        else
-               assert(0 && "unrecognised PowerPC instruction");
+               fatal("Don't know how to write a PowerPC fixup to instructions 0x%08x+0x%08x",
+                       opcode1, opcode2);
 }
 
 /*