]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Add support for -membedded-pic
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 8 Apr 1994 15:23:06 +0000 (15:23 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 8 Apr 1994 15:23:06 +0000 (15:23 +0000)
From-SVN: r6997

gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md

index 16315b4566b62f43436addd7ee468207101da46b..19a00cc3ed3140e780cd4cf88b168083ca9e8a77 100644 (file)
@@ -3191,6 +3191,28 @@ override_options ()
   else
     mips_abicalls = MIPS_ABICALLS_NO;
 
+  /* -membedded-pic is a form of PIC code suitable for embedded
+     systems.  All calls are made using PC relative addressing, and
+     all data is addressed using the $gp register.  This requires gas,
+     which does most of the work, and GNU ld, which automatically
+     expands PC relative calls which are out of range into a longer
+     instruction sequence.  All gcc really does differently is
+     generate a different sequence for a switch.  */
+  if (TARGET_EMBEDDED_PIC)
+    {
+      flag_pic = 1;
+      if (TARGET_ABICALLS)
+       warning ("-membedded-pic and -mabicalls are incompatible");
+      if (g_switch_set)
+       warning ("-G and -membedded-pic are incompatible");
+      /* Setting mips_section_threshold is not required, because gas
+        will force everything to be GP addressable anyhow, but
+        setting it will cause gcc to make better estimates of the
+        number of instructions required to access a particular data
+        item.  */
+      mips_section_threshold = 0x7fffffff;
+    }
+
   /* -mrnames says to use the MIPS software convention for register
      names instead of the hardware names (ie, $a0 instead of $4).
      We do this by switching the names in mips_reg_names, which the
@@ -3387,6 +3409,7 @@ mips_debugger_offset (addr, offset)
    'M'  print high-order register of double-word register operand.
    'C'  print part of opcode for a branch condition.
    'N'  print part of opcode for a branch condition, inverted.
+   'S'  X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
    '(' Turn on .set noreorder
    ')' Turn on .set reorder
    '[' Turn on .set noat
@@ -3569,6 +3592,14 @@ print_operand (file, op, letter)
        abort_with_insn (op, "PRINT_OPERAND, illegal insn for %%N");
       }
 
+  else if (letter == 'S')
+    {
+      char buffer[100];
+
+      ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
+      assemble_name (file, buffer);
+    }
+
   else if (code == REG)
     {
       register int regnum = REGNO (op);
index e7a954e1ee4e9e4b217e60b197a1ca76a57f9e2c..175649b6d39bc520bea7fc5080fd2561deebbe4b 100644 (file)
@@ -254,12 +254,12 @@ extern char              *mktemp ();
 #define MASK_HALF_PIC  0x00000800      /* Emit OSF-style pic refs to externs*/
 #define MASK_LONG_CALLS        0x00001000      /* Always call through a register */
 #define MASK_64BIT     0x00002000      /* Use 64 bit GP registers and insns */
-#define MASK_UNUSED1   0x00004000
-#define MASK_UNUSED2   0x00008000
-#define MASK_UNUSED3   0x00010000
-#define MASK_UNUSED4   0x00020000
-#define MASK_UNUSED5   0x00040000
-#define MASK_UNUSED6   0x00080000
+#define MASK_EMBEDDED_PIC 0x00004000   /* Generate embedded PIC code */
+#define MASK_UNUSED1   0x00008000
+#define MASK_UNUSED2   0x00010000
+#define MASK_UNUSED3   0x00020000
+#define MASK_UNUSED4   0x00040000
+#define MASK_UNUSED5   0x00080000
 
                                        /* Dummy switches used only in spec's*/
 #define MASK_MIPS_TFILE        0x00000000      /* flag for mips-tfile usage */
@@ -327,6 +327,10 @@ extern char               *mktemp ();
                                        /* always call through a register */
 #define TARGET_LONG_CALLS      (target_flags & MASK_LONG_CALLS)
 
+                                       /* generate embedded PIC code;
+                                          requires gas.  */
+#define TARGET_EMBEDDED_PIC    (target_flags & MASK_EMBEDDED_PIC)
+
 /* Macro to define tables used to set the flags.
    This is a list in braces of pairs in braces,
    each pair being { "NAME", VALUE }
@@ -364,6 +368,8 @@ extern char        *mktemp ();
   {"no-half-pic",       -MASK_HALF_PIC},                               \
   {"long-calls",         MASK_LONG_CALLS},                             \
   {"no-long-calls",     -MASK_LONG_CALLS},                             \
+  {"embedded-pic",       MASK_EMBEDDED_PIC},                           \
+  {"no-embedded-pic",   -MASK_EMBEDDED_PIC},                           \
   {"debug",              MASK_DEBUG},                                  \
   {"debuga",             MASK_DEBUG_A},                                \
   {"debugb",             MASK_DEBUG_B},                                \
@@ -552,7 +558,8 @@ while (0)
 %{ggdb:-g} %{ggdb0:-g0} %{ggdb1:-g1} %{ggdb2:-g2} %{ggdb3:-g3} \
 %{gstabs:-g} %{gstabs0:-g0} %{gstabs1:-g1} %{gstabs2:-g2} %{gstabs3:-g3} \
 %{gstabs+:-g} %{gstabs+0:-g0} %{gstabs+1:-g1} %{gstabs+2:-g2} %{gstabs+3:-g3} \
-%{gcoff:-g} %{gcoff0:-g0} %{gcoff1:-g1} %{gcoff2:-g2} %{gcoff3:-g3}"
+%{gcoff:-g} %{gcoff0:-g0} %{gcoff1:-g1} %{gcoff2:-g2} %{gcoff3:-g3} \
+%{membedded-pic}"
 
 #else
 /* not GAS */
@@ -568,7 +575,8 @@ while (0)
 %{ggdb:-g} %{ggdb0:-g0} %{ggdb1:-g1} %{ggdb2:-g2} %{ggdb3:-g3} \
 %{gstabs:-g} %{gstabs0:-g0} %{gstabs1:-g1} %{gstabs2:-g2} %{gstabs3:-g3} \
 %{gstabs+:-g} %{gstabs+0:-g0} %{gstabs+1:-g1} %{gstabs+2:-g2} %{gstabs+3:-g3} \
-%{gcoff:-g} %{gcoff0:-g0} %{gcoff1:-g1} %{gcoff2:-g2} %{gcoff3:-g3}"
+%{gcoff:-g} %{gcoff0:-g0} %{gcoff1:-g1} %{gcoff2:-g2} %{gcoff3:-g3} \
+%{membedded-pic}"
 
 #endif
 #endif /* ASM_SPEC */
@@ -3375,12 +3383,33 @@ do {                                                                    \
           VALUE)
 
 /* This is how to output an element of a case-vector that is relative.
-   This is used for pc-relative code (e.g. when TARGET_ABICALLS).  */
+   This is used for pc-relative code (e.g. when TARGET_ABICALLS or
+   TARGET_EMBEDDED_PIC).  */
 
 #define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, VALUE, REL)                   \
-  fprintf (STREAM, "\t%s\t$L%d\n",                                     \
-          TARGET_LONG64 ? ".gpdword" : ".gpword",                      \
-          VALUE)
+do {                                                                   \
+  if (TARGET_EMBEDDED_PIC)                                             \
+    fprintf (STREAM, "\t%s\t$L%d-$LS%d\n",                             \
+            TARGET_LONG64 ? ".dword" : ".word",                        \
+            VALUE, REL);                                               \
+  else                                                                 \
+    fprintf (STREAM, "\t%s\t$L%d\n",                                   \
+            TARGET_LONG64 ? ".gpdword" : ".gpword",                    \
+            VALUE);                                                    \
+} while (0)
+
+/* When generating embedded PIC code we want to put the jump table in
+   the .text section.  In all other cases, we want to put the jump
+   table in the .rdata section.  Unfortunately, we can't use
+   JUMP_TABLES_IN_TEXT_SECTION, because it is not conditional.
+   Instead, we use ASM_OUTPUT_CASE_LABEL to switch back to the .text
+   section if appropriate.  */
+#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, INSN)                 \
+do {                                                                   \
+  if (TARGET_EMBEDDED_PIC)                                             \
+    text_section ();                                                   \
+  ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM);                       \
+} while (0)
 
 /* This is how to output an assembler line
    that says to advance the location counter
index 618fddb6b72af1953e1b91d99437f28a5a924d3e..be9e1512a06b6d7f2b078d68748dfd35908a7e42 100644 (file)
@@ -5410,6 +5410,90 @@ move\\t%0,%z4\\n\\
    (set_attr "mode"    "none")
    (set_attr "length"  "1")])
 
+;; Implement a switch statement when generating embedded PIC code.
+;; Switches are implemented by `tablejump' when not using -membedded-pic.
+
+(define_expand "casesi"
+  [(set (match_dup 5)
+       (minus:SI (match_operand:SI 0 "register_operand" "d")
+                 (match_operand:SI 1 "arith_operand" "dI")))
+   (set (cc0)
+       (compare:CC (match_dup 5)
+                   (match_operand:SI 2 "arith_operand" "")))
+   (set (pc)
+       (if_then_else (gtu (cc0)
+                          (const_int 0))
+                     (label_ref (match_operand 4 "" ""))
+                     (pc)))
+   (parallel
+    [(set (pc)
+         (mem:SI (plus:SI (mult:SI (match_dup 5)
+                                   (const_int 4))
+                          (label_ref (match_operand 3 "" "")))))
+     (clobber (match_scratch:SI 6 ""))
+     (clobber (reg:SI 31))])]
+  "TARGET_EMBEDDED_PIC"
+  "
+{
+  /* We need slightly different code for eight byte table entries.  */
+  if (TARGET_LONG64)
+    abort ();
+
+  if (operands[0])
+    {
+      rtx reg = gen_reg_rtx (SImode);
+
+      /* The constraints should handle this, but they don't.  */
+      operands[0] = force_reg (SImode, operands[0]);
+      if (! arith_operand (operands[1]))
+       operands[1] = force_reg (SImode, operands[1]);
+      if (! arith_operand (operands[2]))
+       operands[2] = force_reg (SImode, operands[2]);
+
+      /* If the index is too large, go to the default label.  */
+      emit_insn (gen_subsi3 (reg, operands[0], operands[1]));
+      emit_insn (gen_cmpsi (reg, operands[2]));
+      emit_insn (gen_bgtu (operands[4]));
+
+      /* Do the PIC jump.  */
+      emit_insn (gen_casesi_internal (reg, operands[3], gen_reg_rtx (SImode)));
+
+      DONE;
+    }
+}")
+
+;; An embedded PIC switch statement looks like this:
+;;     bal     $LS1
+;;     sll     $reg,$index,2
+;; $LS1:
+;;     addu    $reg,$reg,$31
+;;     lw      $reg,$L1-$LS1($reg)
+;;     addu    $reg,$reg,$31
+;;     j       $reg
+;; $L1:
+;;     .word   case1-$LS1
+;;     .word   case2-$LS1
+;;     ...
+
+(define_insn "casesi_internal"
+  [(set (pc)
+       (mem:SI (plus:SI (mult:SI (match_operand:SI 0 "register_operand" "d")
+                                 (const_int 4))
+                        (label_ref (match_operand 1 "" "")))))
+   (clobber (match_operand:SI 2 "register_operand" "d"))
+   (clobber (reg:SI 31))]
+  "TARGET_EMBEDDED_PIC"
+  "*
+{
+  output_asm_insn (\"%(bal\\t%S1\;sll\\t%0,2\\n%S1:\", operands);
+  output_asm_insn (\"addu\\t%0,%0,$31%)\", operands);
+  output_asm_insn (\"lw\\t%0,%1-%S1(%0)\;addu\\t%0,%0,$31\", operands);
+  return \"j\\t%0\";
+}"
+  [(set_attr "type"    "jump")
+   (set_attr "mode"    "none")
+   (set_attr "length"  "6")])
+
 \f
 ;;
 ;;  ....................