parent
8926095fe7
commit
e0bfcea5c9
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")])
|
||||
|
||||
|
||||
;;
|
||||
;; ....................
|
||||
|
|
Loading…
Reference in New Issue