diff options
author | aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-10 03:25:32 +0000 |
---|---|---|
committer | aoliva <aoliva@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-07-10 03:25:32 +0000 |
commit | b87a151a2a5914ee6dea4559cb1ca33d7c754231 (patch) | |
tree | 2431eaa1b2838fc78a056c559e1d707256745663 /gcc/config/mn10300 | |
parent | 0bd69b3e01bb60df15a91b1df9d5527e553b11b6 (diff) | |
download | gcc-b87a151a2a5914ee6dea4559cb1ca33d7c754231.tar.gz |
2003-06-16 Alexandre Oliva <aoliva@redhat.com>
* config/mn10300/mn10300.c (mn10300_unspec_int_label_counter):
Moved from...
* config/mn10300/mn10300.md (GOTaddr2picreg): ... here.
* config/mn10300/mn10300.h: GTY-declare it.
2003-06-11 Alexandre Oliva <aoliva@redhat.com>
* config/mn10300/mn10300.c (mn10300_encode_section_info): Fix
prototype. Use incoming RTL argument.
2002-12-12 Alexandre Oliva <aoliva@redhat.com>
* config/mn10300/mn10300.md (int_label): Move C statements...
(GOTaddr2picreg): ... here.
2002-08-15 Alexandre Oliva <aoliva@redhat.com>
* config/mn10300/mn10300.h (ENCODE_SECTION_INFO): Move...
* config/mn10300/mn10300.c (mn10300_encode_section_info):
... here. New function.
(TARGET_ENCODE_SECTION_INFO): Define to it.
2001-11-04 Alexandre Oliva <aoliva@redhat.com>
* config/mn10300/mn10300.md (builtin_setjmp_receiver): Fix typo in
pattern name.
(mn10300_loadPC): Define as insn splittable after reload.
2001-05-13 Alexandre Oliva <aoliva@redhat.com>
* config/sh/mn10300.h (JUMP_TABLES_IN_TEXT_SECTION): Let them
be defined in .rodata even in PIC, now that the assembler
supports that.
2001-05-09 Alexandre Oliva <aoliva@redhat.com>
* config/mn10300/mn10300.h (GOT_SYMBOL_NAME): Don't let the
symbol take an underscore prefix.
2001-04-14 Alexandre Oliva <aoliva@redhat.com>
* config/mn10300/mn10300-protos.h (legitimate_pic_operand_p,
legitimize_pic_address): Declare.
* config/mn10300/mn10300.h (CONDITIONAL_REGISTER_USAGE): Mark
the PIC register as fixed.
(EXTRA_CONSTRAINT): Match UNSPEC_PLT and UNSPEC_PIC for 'S'.
(GO_IF_LEGITIMATE_ADDRESS): Require legitimate_pic_operand for
PIC.
(LEGITIMATE_PIC_OPERAND_P): Define.
(PIC_OFFSET_TABLE_REGNUM): Define.
(GOT_SYMBOL_NAME): Define.
(SYMBOLIC_CONST_P): Define.
(ENCODE_SECTION_INFO): Use SYMBOL_REF_FLAG to mark local
symbols.
(MN10300_GLOBAL_P): Test it.
(OUTPUT_ADDR_CONST_EXTRA): Handle PIC-related unspecs.
(JUMP_TABLES_IN_TEXT_SECTION): Enable for PIC.
* config/mn10300/mn10300.c (print_operand): Handle unspec.
(expand_prologue): Set PIC register.
(call_address_operand): Don't match SYMBOL_REFs in PIC.
(legitimize_address): Call legitimize_pic_address.
(legitimize_pic_address): New fn.
(legitimate_pic_operand_p): New fn.
* config/mn10300/mn10300.md (PIC_REG, SP_REG): New constants.
(UNSPEC_INT_LABEL, UNSPEC_PIC, UNSPEC_GOT, UNSPEC_GOTOFF,
UNSPEC_PLT): New constants.
(pop_pic_reg): New insn.
(movsi): Adjust non-PIC addresses.
(builtin_setjmp_receiver): Restore the PIC register.
(casesi): New insn.
(call): Adjust non-PIC addresses.
(int_label, GOTaddr2picreg): New expands.
(am33_loadPC): New insn.
(mn10300_loadPC): New expand.
(call_next_insn): New insn.
(add_GOT_to_pic_reg): New expand.
(symGOT2reg, symGOT2reg_i): New expands.
(symGOTOFF2reg, symGOTOFF2reg_i): New expands.
(sym2PIC, sym2PLT): New expands.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69169 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/mn10300')
-rw-r--r-- | gcc/config/mn10300/mn10300-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.c | 122 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.h | 66 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.md | 240 |
4 files changed, 429 insertions, 1 deletions
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h index 209a7e6c891..74154d92494 100644 --- a/gcc/config/mn10300/mn10300-protos.h +++ b/gcc/config/mn10300/mn10300-protos.h @@ -26,6 +26,8 @@ extern void mn10300_va_start PARAMS ((tree, rtx)); #endif /* TREE_CODE */ extern struct rtx_def *legitimize_address PARAMS ((rtx, rtx, enum machine_mode)); +extern rtx legitimize_pic_address (rtx, rtx); +extern int legitimate_pic_operand_p (rtx); extern void print_operand PARAMS ((FILE *, rtx, int)); extern void print_operand_address PARAMS ((FILE *, rtx)); extern void mn10300_print_reg_list PARAMS ((FILE *, int)); diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index bb14b4c9023..e4ef4bffe8b 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -44,6 +44,10 @@ Boston, MA 02111-1307, USA. */ #include "target.h" #include "target-def.h" +/* This is used by GOTaddr2picreg to uniquely identify + UNSPEC_INT_LABELs. */ +int mn10300_unspec_int_label_counter; + /* The size of the callee register save area. Right now we save everything on entry since it costs us nothing in code size. It does cost us from a speed standpoint, so we want to optimize this sooner or later. */ @@ -75,6 +79,10 @@ static void mn10300_file_start PARAMS ((void)); #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true +#undef TARGET_ENCODE_SECTION_INFO +#define TARGET_ENCODE_SECTION_INFO mn10300_encode_section_info + +static void mn10300_encode_section_info (tree, rtx, int); struct gcc_target targetm = TARGET_INITIALIZER; static void @@ -410,6 +418,7 @@ print_operand (file, x, code) case CONST: case LABEL_REF: case CODE_LABEL: + case UNSPEC: print_operand_address (file, x); break; default: @@ -881,6 +890,24 @@ expand_prologue () emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, GEN_INT (-size))); + if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) + { + rtx insn = get_last_insn (); + rtx last = emit_insn (gen_GOTaddr2picreg ()); + + /* Mark these insns as possibly dead. Sometimes, flow2 may + delete all uses of the PIC register. In this case, let it + delete the initialization too. */ + do + { + insn = NEXT_INSN (insn); + + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD, + const0_rtx, + REG_NOTES (insn)); + } + while (insn != last); + } } void @@ -1269,6 +1296,9 @@ call_address_operand (op, mode) rtx op; enum machine_mode mode ATTRIBUTE_UNUSED; { + if (flag_pic) + return (EXTRA_CONSTRAINT (op, 'S') || GET_CODE (op) == REG); + return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG); } @@ -1756,6 +1786,9 @@ legitimize_address (x, oldx, mode) rtx oldx ATTRIBUTE_UNUSED; enum machine_mode mode ATTRIBUTE_UNUSED; { + if (flag_pic && ! legitimate_pic_operand_p (x)) + x = legitimize_pic_address (oldx, NULL_RTX); + /* Uh-oh. We might have an address for x[n-100000]. This needs special handling to avoid creating an indexed memory address with x-100000 as the base. */ @@ -1786,6 +1819,75 @@ legitimize_address (x, oldx, mode) return x; } +/* Convert a non-PIC address in `orig' to a PIC address using @GOT or + @GOTOFF in `reg'. */ +rtx +legitimize_pic_address (orig, reg) + rtx orig; + rtx reg; +{ + if (GET_CODE (orig) == LABEL_REF + || (GET_CODE (orig) == SYMBOL_REF + && (CONSTANT_POOL_ADDRESS_P (orig) + || ! MN10300_GLOBAL_P (orig)))) + { + if (reg == 0) + reg = gen_reg_rtx (Pmode); + + emit_insn (gen_symGOTOFF2reg (reg, orig)); + return reg; + } + else if (GET_CODE (orig) == SYMBOL_REF) + { + if (reg == 0) + reg = gen_reg_rtx (Pmode); + + emit_insn (gen_symGOT2reg (reg, orig)); + return reg; + } + return orig; +} + +/* Return zero if X references a SYMBOL_REF or LABEL_REF whose symbol + isn't protected by a PIC unspec; non-zero otherwise. */ +int +legitimate_pic_operand_p (x) + rtx x; +{ + register const char *fmt; + register int i; + + if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF) + return 0; + + if (GET_CODE (x) == UNSPEC + && (XINT (x, 1) == UNSPEC_PIC + || XINT (x, 1) == UNSPEC_GOT + || XINT (x, 1) == UNSPEC_GOTOFF + || XINT (x, 1) == UNSPEC_PLT)) + return 1; + + if (GET_CODE (x) == QUEUED) + return legitimate_pic_operand_p (QUEUED_VAR (x)); + + fmt = GET_RTX_FORMAT (GET_CODE (x)); + for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--) + { + if (fmt[i] == 'E') + { + register int j; + + for (j = XVECLEN (x, i) - 1; j >= 0; j--) + if (! legitimate_pic_operand_p (XVECEXP (x, i, j))) + return 0; + } + else if (fmt[i] == 'e' && ! legitimate_pic_operand_p (XEXP (x, i))) + return 0; + } + + return 1; +} + static int mn10300_address_cost_1 (x, unsig) rtx x; @@ -1973,3 +2075,23 @@ mn10300_wide_const_load_uses_clr (operands) return val[0] == 0 || val[1] == 0; } +/* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we + may access it using GOTOFF instead of GOT. */ + +static void +mn10300_encode_section_info (decl, rtl, first) + tree decl; + rtx rtl; + int first; +{ + rtx symbol; + + if (GET_CODE (rtl) != MEM) + return; + symbol = XEXP (rtl, 0); + if (GET_CODE (symbol) != SYMBOL_REF) + return; + + if (flag_pic) + SYMBOL_REF_FLAG (symbol) = (*targetm.binds_local_p) (decl); +} diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h index 75d4183af74..2432a38a1ce 100644 --- a/gcc/config/mn10300/mn10300.h +++ b/gcc/config/mn10300/mn10300.h @@ -46,6 +46,8 @@ Boston, MA 02111-1307, USA. */ extern int target_flags; +extern GTY(()) int mn10300_unspec_int_label_counter; + /* Macros used in the machine description to test the flags. */ /* Macro to define tables used to set the flags. @@ -212,6 +214,8 @@ extern int target_flags; i++) \ fixed_regs[i] = call_used_regs[i] = 1; \ } \ + if (flag_pic) \ + fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ } /* Return number of consecutive hard regs needed starting at reg REGNO @@ -735,6 +739,9 @@ struct cum_arg {int nbytes; }; #define EXTRA_CONSTRAINT(OP, C) \ ((C) == 'R' ? OK_FOR_R (OP) \ : (C) == 'Q' ? OK_FOR_Q (OP) \ + : (C) == 'S' && flag_pic \ + ? GET_CODE (OP) == UNSPEC && (XINT (OP, 1) == UNSPEC_PLT \ + || XINT (OP, 1) == UNSPEC_PIC) \ : (C) == 'S' ? GET_CODE (OP) == SYMBOL_REF \ : (C) == 'T' ? OK_FOR_T (OP) \ : 0) @@ -775,7 +782,8 @@ struct cum_arg {int nbytes; }; #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ { \ - if (CONSTANT_ADDRESS_P (X)) \ + if (CONSTANT_ADDRESS_P (X) \ + && (! flag_pic || legitimate_pic_operand_p (X))) \ goto ADDR; \ if (RTX_OK_FOR_BASE_P (X)) \ goto ADDR; \ @@ -797,6 +805,8 @@ struct cum_arg {int nbytes; }; { \ if (GET_CODE (index) == CONST_INT) \ goto ADDR; \ + if (GET_CODE (index) == CONST) \ + goto ADDR; \ } \ } \ } @@ -833,6 +843,60 @@ struct cum_arg {int nbytes; }; #define LEGITIMATE_CONSTANT_P(X) 1 +/* Zero if this needs fixing up to become PIC. */ + +#define LEGITIMATE_PIC_OPERAND_P(X) (legitimate_pic_operand_p (X)) + +/* Register to hold the addressing base for + position independent code access to data items. */ +#define PIC_OFFSET_TABLE_REGNUM PIC_REG + +/* The name of the pseudo-symbol representing the Global Offset Table. */ +#define GOT_SYMBOL_NAME "*_GLOBAL_OFFSET_TABLE_" + +#define SYMBOLIC_CONST_P(X) \ +((GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF) \ + && ! LEGITIMATE_PIC_OPERAND_P (X)) + +/* Non-global SYMBOL_REFs have SYMBOL_REF_FLAG enabled. */ +#define MN10300_GLOBAL_P(X) (! SYMBOL_REF_FLAG (X)) + +/* Recognize machine-specific patterns that may appear within + constants. Used for PIC-specific UNSPECs. */ +#define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL) \ + do \ + if (GET_CODE (X) == UNSPEC && XVECLEN ((X), 0) == 1) \ + { \ + switch (XINT ((X), 1)) \ + { \ + case UNSPEC_INT_LABEL: \ + asm_fprintf ((STREAM), ".%LLIL%d", \ + INTVAL (XVECEXP ((X), 0, 0))); \ + break; \ + case UNSPEC_PIC: \ + /* GLOBAL_OFFSET_TABLE or local symbols, no suffix. */ \ + output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \ + break; \ + case UNSPEC_GOT: \ + output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \ + fputs ("@GOT", (STREAM)); \ + break; \ + case UNSPEC_GOTOFF: \ + output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \ + fputs ("@GOTOFF", (STREAM)); \ + break; \ + case UNSPEC_PLT: \ + output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \ + fputs ("@PLT", (STREAM)); \ + break; \ + default: \ + goto FAIL; \ + } \ + break; \ + } \ + else \ + goto FAIL; \ + while (0) /* Tell final.c how to eliminate redundant test instructions. */ diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md index a615f6b97ea..27a40ef3720 100644 --- a/gcc/config/mn10300/mn10300.md +++ b/gcc/config/mn10300/mn10300.md @@ -37,6 +37,17 @@ ;; clobber - value of cc is unknown (define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber,invert" (const_string "clobber")) + +(define_constants [ + (PIC_REG 6) + (SP_REG 9) + + (UNSPEC_INT_LABEL 0) + (UNSPEC_PIC 1) + (UNSPEC_GOT 2) + (UNSPEC_GOTOFF 3) + (UNSPEC_PLT 4) +]) ;; ---------------------------------------------------------------------- ;; MOVE INSTRUCTIONS @@ -269,6 +280,12 @@ DONE; }") +(define_insn "pop_pic_reg" + [(set (reg:SI PIC_REG) + (mem:SI (post_inc:SI (reg:SI SP_REG))))] + "reload_completed" + "movm (sp),[a2]") + (define_expand "movsi" [(set (match_operand:SI 0 "general_operand" "") (match_operand:SI 1 "general_operand" ""))] @@ -279,6 +296,33 @@ if (!register_operand (operand1, SImode) && !register_operand (operand0, SImode)) operands[1] = copy_to_mode_reg (SImode, operand1); + if (flag_pic) + { + rtx temp; + if (SYMBOLIC_CONST_P (operands[1])) + { + if (GET_CODE (operands[0]) == MEM) + operands[1] = force_reg (Pmode, operands[1]); + else + { + temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); + operands[1] = legitimize_pic_address (operands[1], temp); + } + } + else if (GET_CODE (operands[1]) == CONST + && GET_CODE (XEXP (operands[1], 0)) == PLUS + && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0))) + { + temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode); + temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0), + temp); + operands[1] = expand_binop (SImode, add_optab, temp, + XEXP (XEXP (operands[1], 0), 1), + no_new_pseudos ? temp + : gen_reg_rtx (Pmode), + 0, OPTAB_LIB_WIDEN); + } + } }") (define_insn "" @@ -1666,6 +1710,43 @@ "jmp (%0)" [(set_attr "cc" "none")]) +(define_expand "builtin_setjmp_receiver" + [(match_operand 0 "" "")] + "flag_pic" + " +{ + if (flag_pic) + emit_insn (gen_GOTaddr2picreg ()); + + DONE; +}") + +(define_expand "casesi" + [(match_operand:SI 0 "register_operand" "") + (match_operand:SI 1 "immediate_operand" "") + (match_operand:SI 2 "immediate_operand" "") + (match_operand 3 "" "") (match_operand 4 "" "")] + "" + " +{ + rtx table = gen_reg_rtx (SImode); + rtx index = gen_reg_rtx (SImode); + rtx addr = gen_reg_rtx (Pmode); + + emit_move_insn (table, gen_rtx_LABEL_REF (VOIDmode, operands[3])); + emit_move_insn (index, plus_constant (operands[0], - INTVAL (operands[1]))); + emit_insn (gen_cmpsi (index, operands[2])); + emit_jump_insn (gen_bgtu (operands[4])); + emit_move_insn (index, gen_rtx_ASHIFT (SImode, index, GEN_INT (2))); + emit_move_insn (addr, gen_rtx_MEM (SImode, + gen_rtx_PLUS (SImode, table, index))); + if (flag_pic) + emit_move_insn (addr, gen_rtx_PLUS (SImode, addr, table)); + + emit_jump_insn (gen_tablejump (addr, operands[3])); + DONE; +}") + (define_insn "tablejump" [(set (pc) (match_operand:SI 0 "register_operand" "a")) (use (label_ref (match_operand 1 "" "")))] @@ -1681,6 +1762,20 @@ "" " { + if (flag_pic && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF) + { + if (MN10300_GLOBAL_P (XEXP (operands[0], 0))) + { + /* The PLT code won't run on AM30, but then, there's no + shared library support for AM30 either, so we just assume + the linker is going to adjust all @PLT relocs to the + actual symbols. */ + emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); + XEXP (operands[0], 0) = gen_sym2PLT (XEXP (operands[0], 0)); + } + else + XEXP (operands[0], 0) = gen_sym2PIC (XEXP (operands[0], 0)); + } if (! call_address_operand (XEXP (operands[0], 0), VOIDmode)) XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0)); emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1])); @@ -1710,6 +1805,20 @@ "" " { + if (flag_pic && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF) + { + if (MN10300_GLOBAL_P (XEXP (operands[1], 0))) + { + /* The PLT code won't run on AM30, but then, there's no + shared library support for AM30 either, so we just assume + the linker is going to adjust all @PLT relocs to the + actual symbols. */ + emit_insn (gen_rtx_USE (VOIDmode, pic_offset_table_rtx)); + XEXP (operands[1], 0) = gen_sym2PLT (XEXP (operands[1], 0)); + } + else + XEXP (operands[1], 0) = gen_sym2PIC (XEXP (operands[1], 0)); + } if (! call_address_operand (XEXP (operands[1], 0), VOIDmode)) XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0)); emit_call_insn (gen_call_value_internal (operands[0], @@ -2402,3 +2511,134 @@ "add %0,%0\;bcc %1" [(set_attr "cc" "clobber")]) +(define_expand "int_label" + [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)] + "" "") + +(define_expand "GOTaddr2picreg" + [(match_dup 0)] + "" " +{ + /* It would be nice to be able to have int_label keep track of the + counter and all, but if we add C code to it, we'll get an insn + back, and we just want the pattern. */ + operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++)); + if (TARGET_AM33) + emit_insn (gen_am33_loadPC (operands[0])); + else + emit_insn (gen_mn10300_loadPC (operands[0])); + emit_insn (gen_add_GOT_to_pic_reg (operands[0])); + DONE; +} +") + +(define_insn "am33_loadPC" + [(parallel + [(set (reg:SI PIC_REG) (pc)) + (use (match_operand 0 "" ""))])] + "TARGET_AM33" + "%0:\;mov pc,a2") + + +(define_insn_and_split "mn10300_loadPC" + [(parallel + [(set (reg:SI PIC_REG) (pc)) + (use (match_operand 0 "" ""))])] + "" + "#" + "reload_completed" + [(match_operand 0 "" "")] + " +{ + rtx sp_reg = gen_rtx_REG (SImode, SP_REG); + int need_stack_space = (get_frame_size () == 0 + && current_function_outgoing_args_size == 0); + + if (need_stack_space) + emit_move_insn (sp_reg, plus_constant (sp_reg, -4)); + + emit_insn (gen_call_next_insn (operands[0])); + + if (need_stack_space) + emit_insn (gen_pop_pic_reg ()); + else + emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg)); + + DONE; +}") + +(define_insn "call_next_insn" + [(parallel + [(set (mem:SI (reg:SI SP_REG)) (pc)) + (use (match_operand 0 "" ""))])] + "reload_completed" + "calls %0\;%0:") + +(define_expand "add_GOT_to_pic_reg" + [(set (reg:SI PIC_REG) + (plus:SI + (reg:SI PIC_REG) + (const + (unspec [(minus:SI + (match_dup 1) + (const (minus:SI + (const (match_operand:SI 0 "" "")) + (pc)))) + ] UNSPEC_PIC))))] + "" + " +{ + operands[1] = gen_rtx_SYMBOL_REF (VOIDmode, GOT_SYMBOL_NAME); +}") + +(define_expand "symGOT2reg" + [(match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")] + "" + " +{ + rtx insn = emit_insn (gen_symGOT2reg_i (operands[0], operands[1])); + + RTX_UNCHANGING_P (SET_SRC (PATTERN (insn))) = 1; + + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], + REG_NOTES (insn)); + + DONE; +}") + +(define_expand "symGOT2reg_i" + [(set (match_operand:SI 0 "" "") + (mem:SI (plus:SI (reg:SI PIC_REG) + (const (unspec [(match_operand:SI 1 "" "")] + UNSPEC_GOT)))))] + "" + "") + +(define_expand "symGOTOFF2reg" + [(match_operand:SI 0 "" "") (match_operand:SI 1 "" "")] + "" + " +{ + rtx insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1])); + + REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1], + REG_NOTES (insn)); + + DONE; +}") + +(define_expand "symGOTOFF2reg_i" + [(set (match_operand:SI 0 "" "") + (const (unspec [(match_operand:SI 1 "" "")] UNSPEC_GOTOFF))) + (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI PIC_REG)))] + "" + "") + +(define_expand "sym2PIC" + [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PIC)] + "" "") + +(define_expand "sym2PLT" + [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PLT)] + "" "") |