diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 1994-04-08 15:23:06 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 1994-04-08 15:23:06 +0000 |
commit | e0bfcea5c918f2a20437d58cdb22ad83e4851eb5 (patch) | |
tree | ee8ea3867eb51777f4b5396bd9367b9a0619dce9 /gcc | |
parent | 8926095fe7324b246adcf31dc78297d8963ed38a (diff) | |
download | gcc-e0bfcea5c918f2a20437d58cdb22ad83e4851eb5.zip gcc-e0bfcea5c918f2a20437d58cdb22ad83e4851eb5.tar.gz gcc-e0bfcea5c918f2a20437d58cdb22ad83e4851eb5.tar.bz2 |
Add support for -membedded-pic
From-SVN: r6997
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/config/mips/mips.c | 31 | ||||
-rw-r--r-- | gcc/config/mips/mips.h | 53 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 84 |
3 files changed, 156 insertions, 12 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 16315b4..19a00cc 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -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); diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index e7a954e..175649b 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -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 diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 618fddb..be9e151 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -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")]) + ;; ;; .................... |