1 /* Simplify the code to load global variable's address from GOT.
3 Free Software Foundation, Inc.
4 Contributed by Wei Guozhi <carrot@google.com>.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 /* This file contains optimization for global variable's address loading
25 When generating PIC code, we need to load global variable's address from
26 GOT. Many targets do this as following:
28 (set pic_reg ...) # load the base address of GOT into pic_reg.
30 (set off_set ...) # load the offset from the base of GOT to
31 # a global variable's GOT entry.
32 (set address # load the address from GOT.
33 (mem (plus pic_reg off_set)))
36 If the target has an alternative method (usually uses a different
37 relocation) to load the global address and in some cases it has less
38 cost and avoid the pic_reg, we can use this pass to improve it.
40 In order to employ this optimization the target must satisfy the
41 following constraints:
43 1. There should be at least 2 methods to load a global variable's
46 2. By default all global variables accesses use the method described
49 3. There is a target dependent situation that the alternative method is
50 better when considering the number of global variable accesses and
51 the number of accessed variables.
53 4. The alternative method doesn't use the base of GOT (pic_reg).
58 #include "coretypes.h"
63 #include "tree-pass.h"
67 #define VAR_TABLE_SIZE 10
69 /* Information needed when rewrite the GOT access insns. */
70 struct got_access_info
72 rtx symbol
; /* The global variable. */
73 rtx offset_reg
; /* Register contains the GOT entry offset. */
74 rtx address_reg
; /* Register contains the final global address. */
75 rtx offset_insn
; /* The insn loads the offset. */
76 rtx load_insn
; /* The insn which loads the address from GOT. */
79 /* This optimization is enabled only when the pic_reg is actually used. */
81 gate_handle_simplify_got (void)
83 return optimize
&& targetm
.got_access
.get_pic_reg ();
87 rest_of_handle_simplify_got (void)
91 int i
, n_symbol
, n_access
= 0;
92 struct got_access_info
* got_accesses
;
93 htab_t var_table
= htab_create (VAR_TABLE_SIZE
,
97 rtx pic_reg
= targetm
.got_access
.get_pic_reg ();
100 ref
= DF_REG_USE_CHAIN (REGNO (pic_reg
));
101 got_accesses
= XNEWVEC(struct got_access_info
,
102 DF_REG_USE_COUNT (REGNO (pic_reg
)));
104 /* Check if all uses of pic_reg are loading global address through the
108 rtx insn
= DF_REF_INSN (ref
);
110 /* Check for the special USE insn, it is not a real usage of pic_reg. */
111 if (GET_CODE (PATTERN (insn
)) == USE
)
115 /* If an insn both set and use pic_reg, it is in the process of
116 constructing the value of pic_reg. We should also ignore it. */
117 rtx set
= single_set (insn
);
118 if (!(set
&& SET_DEST (set
) == pic_reg
))
122 rtx symbol
= targetm
.got_access
.loaded_global_var (insn
,
127 rtx
* slot
= (rtx
*) htab_find_slot (var_table
, symbol
, INSERT
);
128 if (*slot
== HTAB_EMPTY_ENTRY
)
132 got_accesses
[n_access
].symbol
= symbol
;
133 got_accesses
[n_access
].offset_reg
= offset_reg
;
134 got_accesses
[n_access
].address_reg
= SET_DEST (set
);
135 got_accesses
[n_access
].load_insn
= insn
;
136 got_accesses
[n_access
].offset_insn
= offset_insn
;
141 /* This insn doesn't load a global address, but it has
142 other unexpected usage of pic_reg, give up. */
144 htab_delete (var_table
);
149 ref
= DF_REF_NEXT_REG(ref
);
152 /* Check if we can simplify it. */
153 n_symbol
= htab_elements (var_table
);
154 gcc_assert (n_symbol
<= n_access
);
155 if (!targetm
.got_access
.can_simplify_got_access (n_symbol
, n_access
))
158 htab_delete (var_table
);
162 /* Rewrite the global address loading insns. */
163 for (i
=0; i
<n_access
; i
++)
164 targetm
.got_access
.load_global_address (got_accesses
[i
].symbol
,
165 got_accesses
[i
].offset_reg
,
166 got_accesses
[i
].address_reg
,
167 got_accesses
[i
].load_insn
,
168 got_accesses
[i
].offset_insn
);
170 /* Since there is no usage of pic_reg now, we can remove it. */
173 targetm
.got_access
.clear_pic_reg ();
175 htab_delete (var_table
);
179 struct rtl_opt_pass pass_simplify_got
=
183 "simplify_got", /* name */
184 gate_handle_simplify_got
, /* gate */
185 rest_of_handle_simplify_got
, /* execute */
188 0, /* static_pass_number */
189 TV_SIMPLIFY_GOT
, /* tv_id */
190 0, /* properties_required */
191 0, /* properties_provided */
192 0, /* properties_destroyed */
193 0, /* todo_flags_start */
194 TODO_dump_func
/* todo_flags_finish */