annotate gcc/dwarf2cfi.c @ 16:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
16
kono
parents:
diff changeset
1 /* Dwarf2 Call Frame Information helper routines.
kono
parents:
diff changeset
2 Copyright (C) 1992-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3
kono
parents:
diff changeset
4 This file is part of GCC.
kono
parents:
diff changeset
5
kono
parents:
diff changeset
6 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
7 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
8 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
9 version.
kono
parents:
diff changeset
10
kono
parents:
diff changeset
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
14 for more details.
kono
parents:
diff changeset
15
kono
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
17 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
18 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
19
kono
parents:
diff changeset
20 #include "config.h"
kono
parents:
diff changeset
21 #include "system.h"
kono
parents:
diff changeset
22 #include "coretypes.h"
kono
parents:
diff changeset
23 #include "target.h"
kono
parents:
diff changeset
24 #include "function.h"
kono
parents:
diff changeset
25 #include "rtl.h"
kono
parents:
diff changeset
26 #include "tree.h"
kono
parents:
diff changeset
27 #include "tree-pass.h"
kono
parents:
diff changeset
28 #include "memmodel.h"
kono
parents:
diff changeset
29 #include "tm_p.h"
kono
parents:
diff changeset
30 #include "emit-rtl.h"
kono
parents:
diff changeset
31 #include "stor-layout.h"
kono
parents:
diff changeset
32 #include "cfgbuild.h"
kono
parents:
diff changeset
33 #include "dwarf2out.h"
kono
parents:
diff changeset
34 #include "dwarf2asm.h"
kono
parents:
diff changeset
35 #include "common/common-target.h"
kono
parents:
diff changeset
36
kono
parents:
diff changeset
37 #include "except.h" /* expand_builtin_dwarf_sp_column */
kono
parents:
diff changeset
38 #include "profile-count.h" /* For expr.h */
kono
parents:
diff changeset
39 #include "expr.h" /* init_return_column_size */
kono
parents:
diff changeset
40 #include "output.h" /* asm_out_file */
kono
parents:
diff changeset
41 #include "debug.h" /* dwarf2out_do_frame, dwarf2out_do_cfi_asm */
kono
parents:
diff changeset
42
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 /* ??? Poison these here until it can be done generically. They've been
kono
parents:
diff changeset
45 totally replaced in this file; make sure it stays that way. */
kono
parents:
diff changeset
46 #undef DWARF2_UNWIND_INFO
kono
parents:
diff changeset
47 #undef DWARF2_FRAME_INFO
kono
parents:
diff changeset
48 #if (GCC_VERSION >= 3000)
kono
parents:
diff changeset
49 #pragma GCC poison DWARF2_UNWIND_INFO DWARF2_FRAME_INFO
kono
parents:
diff changeset
50 #endif
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 #ifndef INCOMING_RETURN_ADDR_RTX
kono
parents:
diff changeset
53 #define INCOMING_RETURN_ADDR_RTX (gcc_unreachable (), NULL_RTX)
kono
parents:
diff changeset
54 #endif
kono
parents:
diff changeset
55
kono
parents:
diff changeset
56 /* A collected description of an entire row of the abstract CFI table. */
kono
parents:
diff changeset
57 struct GTY(()) dw_cfi_row
kono
parents:
diff changeset
58 {
kono
parents:
diff changeset
59 /* The expression that computes the CFA, expressed in two different ways.
kono
parents:
diff changeset
60 The CFA member for the simple cases, and the full CFI expression for
kono
parents:
diff changeset
61 the complex cases. The later will be a DW_CFA_cfa_expression. */
kono
parents:
diff changeset
62 dw_cfa_location cfa;
kono
parents:
diff changeset
63 dw_cfi_ref cfa_cfi;
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 /* The expressions for any register column that is saved. */
kono
parents:
diff changeset
66 cfi_vec reg_save;
kono
parents:
diff changeset
67 };
kono
parents:
diff changeset
68
kono
parents:
diff changeset
69 /* The caller's ORIG_REG is saved in SAVED_IN_REG. */
kono
parents:
diff changeset
70 struct GTY(()) reg_saved_in_data {
kono
parents:
diff changeset
71 rtx orig_reg;
kono
parents:
diff changeset
72 rtx saved_in_reg;
kono
parents:
diff changeset
73 };
kono
parents:
diff changeset
74
kono
parents:
diff changeset
75
kono
parents:
diff changeset
76 /* Since we no longer have a proper CFG, we're going to create a facsimile
kono
parents:
diff changeset
77 of one on the fly while processing the frame-related insns.
kono
parents:
diff changeset
78
kono
parents:
diff changeset
79 We create dw_trace_info structures for each extended basic block beginning
kono
parents:
diff changeset
80 and ending at a "save point". Save points are labels, barriers, certain
kono
parents:
diff changeset
81 notes, and of course the beginning and end of the function.
kono
parents:
diff changeset
82
kono
parents:
diff changeset
83 As we encounter control transfer insns, we propagate the "current"
kono
parents:
diff changeset
84 row state across the edges to the starts of traces. When checking is
kono
parents:
diff changeset
85 enabled, we validate that we propagate the same data from all sources.
kono
parents:
diff changeset
86
kono
parents:
diff changeset
87 All traces are members of the TRACE_INFO array, in the order in which
kono
parents:
diff changeset
88 they appear in the instruction stream.
kono
parents:
diff changeset
89
kono
parents:
diff changeset
90 All save points are present in the TRACE_INDEX hash, mapping the insn
kono
parents:
diff changeset
91 starting a trace to the dw_trace_info describing the trace. */
kono
parents:
diff changeset
92
kono
parents:
diff changeset
93 struct dw_trace_info
kono
parents:
diff changeset
94 {
kono
parents:
diff changeset
95 /* The insn that begins the trace. */
kono
parents:
diff changeset
96 rtx_insn *head;
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 /* The row state at the beginning and end of the trace. */
kono
parents:
diff changeset
99 dw_cfi_row *beg_row, *end_row;
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 /* Tracking for DW_CFA_GNU_args_size. The "true" sizes are those we find
kono
parents:
diff changeset
102 while scanning insns. However, the args_size value is irrelevant at
kono
parents:
diff changeset
103 any point except can_throw_internal_p insns. Therefore the "delay"
kono
parents:
diff changeset
104 sizes the values that must actually be emitted for this trace. */
kono
parents:
diff changeset
105 HOST_WIDE_INT beg_true_args_size, end_true_args_size;
kono
parents:
diff changeset
106 HOST_WIDE_INT beg_delay_args_size, end_delay_args_size;
kono
parents:
diff changeset
107
kono
parents:
diff changeset
108 /* The first EH insn in the trace, where beg_delay_args_size must be set. */
kono
parents:
diff changeset
109 rtx_insn *eh_head;
kono
parents:
diff changeset
110
kono
parents:
diff changeset
111 /* The following variables contain data used in interpreting frame related
kono
parents:
diff changeset
112 expressions. These are not part of the "real" row state as defined by
kono
parents:
diff changeset
113 Dwarf, but it seems like they need to be propagated into a trace in case
kono
parents:
diff changeset
114 frame related expressions have been sunk. */
kono
parents:
diff changeset
115 /* ??? This seems fragile. These variables are fragments of a larger
kono
parents:
diff changeset
116 expression. If we do not keep the entire expression together, we risk
kono
parents:
diff changeset
117 not being able to put it together properly. Consider forcing targets
kono
parents:
diff changeset
118 to generate self-contained expressions and dropping all of the magic
kono
parents:
diff changeset
119 interpretation code in this file. Or at least refusing to shrink wrap
kono
parents:
diff changeset
120 any frame related insn that doesn't contain a complete expression. */
kono
parents:
diff changeset
121
kono
parents:
diff changeset
122 /* The register used for saving registers to the stack, and its offset
kono
parents:
diff changeset
123 from the CFA. */
kono
parents:
diff changeset
124 dw_cfa_location cfa_store;
kono
parents:
diff changeset
125
kono
parents:
diff changeset
126 /* A temporary register holding an integral value used in adjusting SP
kono
parents:
diff changeset
127 or setting up the store_reg. The "offset" field holds the integer
kono
parents:
diff changeset
128 value, not an offset. */
kono
parents:
diff changeset
129 dw_cfa_location cfa_temp;
kono
parents:
diff changeset
130
kono
parents:
diff changeset
131 /* A set of registers saved in other registers. This is the inverse of
kono
parents:
diff changeset
132 the row->reg_save info, if the entry is a DW_CFA_register. This is
kono
parents:
diff changeset
133 implemented as a flat array because it normally contains zero or 1
kono
parents:
diff changeset
134 entry, depending on the target. IA-64 is the big spender here, using
kono
parents:
diff changeset
135 a maximum of 5 entries. */
kono
parents:
diff changeset
136 vec<reg_saved_in_data> regs_saved_in_regs;
kono
parents:
diff changeset
137
kono
parents:
diff changeset
138 /* An identifier for this trace. Used only for debugging dumps. */
kono
parents:
diff changeset
139 unsigned id;
kono
parents:
diff changeset
140
kono
parents:
diff changeset
141 /* True if this trace immediately follows NOTE_INSN_SWITCH_TEXT_SECTIONS. */
kono
parents:
diff changeset
142 bool switch_sections;
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 /* True if we've seen different values incoming to beg_true_args_size. */
kono
parents:
diff changeset
145 bool args_size_undefined;
kono
parents:
diff changeset
146 };
kono
parents:
diff changeset
147
kono
parents:
diff changeset
148
kono
parents:
diff changeset
149 /* Hashtable helpers. */
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 struct trace_info_hasher : nofree_ptr_hash <dw_trace_info>
kono
parents:
diff changeset
152 {
kono
parents:
diff changeset
153 static inline hashval_t hash (const dw_trace_info *);
kono
parents:
diff changeset
154 static inline bool equal (const dw_trace_info *, const dw_trace_info *);
kono
parents:
diff changeset
155 };
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 inline hashval_t
kono
parents:
diff changeset
158 trace_info_hasher::hash (const dw_trace_info *ti)
kono
parents:
diff changeset
159 {
kono
parents:
diff changeset
160 return INSN_UID (ti->head);
kono
parents:
diff changeset
161 }
kono
parents:
diff changeset
162
kono
parents:
diff changeset
163 inline bool
kono
parents:
diff changeset
164 trace_info_hasher::equal (const dw_trace_info *a, const dw_trace_info *b)
kono
parents:
diff changeset
165 {
kono
parents:
diff changeset
166 return a->head == b->head;
kono
parents:
diff changeset
167 }
kono
parents:
diff changeset
168
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 /* The variables making up the pseudo-cfg, as described above. */
kono
parents:
diff changeset
171 static vec<dw_trace_info> trace_info;
kono
parents:
diff changeset
172 static vec<dw_trace_info *> trace_work_list;
kono
parents:
diff changeset
173 static hash_table<trace_info_hasher> *trace_index;
kono
parents:
diff changeset
174
kono
parents:
diff changeset
175 /* A vector of call frame insns for the CIE. */
kono
parents:
diff changeset
176 cfi_vec cie_cfi_vec;
kono
parents:
diff changeset
177
kono
parents:
diff changeset
178 /* The state of the first row of the FDE table, which includes the
kono
parents:
diff changeset
179 state provided by the CIE. */
kono
parents:
diff changeset
180 static GTY(()) dw_cfi_row *cie_cfi_row;
kono
parents:
diff changeset
181
kono
parents:
diff changeset
182 static GTY(()) reg_saved_in_data *cie_return_save;
kono
parents:
diff changeset
183
kono
parents:
diff changeset
184 static GTY(()) unsigned long dwarf2out_cfi_label_num;
kono
parents:
diff changeset
185
kono
parents:
diff changeset
186 /* The insn after which a new CFI note should be emitted. */
kono
parents:
diff changeset
187 static rtx_insn *add_cfi_insn;
kono
parents:
diff changeset
188
kono
parents:
diff changeset
189 /* When non-null, add_cfi will add the CFI to this vector. */
kono
parents:
diff changeset
190 static cfi_vec *add_cfi_vec;
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 /* The current instruction trace. */
kono
parents:
diff changeset
193 static dw_trace_info *cur_trace;
kono
parents:
diff changeset
194
kono
parents:
diff changeset
195 /* The current, i.e. most recently generated, row of the CFI table. */
kono
parents:
diff changeset
196 static dw_cfi_row *cur_row;
kono
parents:
diff changeset
197
kono
parents:
diff changeset
198 /* A copy of the current CFA, for use during the processing of a
kono
parents:
diff changeset
199 single insn. */
kono
parents:
diff changeset
200 static dw_cfa_location *cur_cfa;
kono
parents:
diff changeset
201
kono
parents:
diff changeset
202 /* We delay emitting a register save until either (a) we reach the end
kono
parents:
diff changeset
203 of the prologue or (b) the register is clobbered. This clusters
kono
parents:
diff changeset
204 register saves so that there are fewer pc advances. */
kono
parents:
diff changeset
205
kono
parents:
diff changeset
206 struct queued_reg_save {
kono
parents:
diff changeset
207 rtx reg;
kono
parents:
diff changeset
208 rtx saved_reg;
kono
parents:
diff changeset
209 HOST_WIDE_INT cfa_offset;
kono
parents:
diff changeset
210 };
kono
parents:
diff changeset
211
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 static vec<queued_reg_save> queued_reg_saves;
kono
parents:
diff changeset
214
kono
parents:
diff changeset
215 /* True if any CFI directives were emitted at the current insn. */
kono
parents:
diff changeset
216 static bool any_cfis_emitted;
kono
parents:
diff changeset
217
kono
parents:
diff changeset
218 /* Short-hand for commonly used register numbers. */
kono
parents:
diff changeset
219 static unsigned dw_stack_pointer_regnum;
kono
parents:
diff changeset
220 static unsigned dw_frame_pointer_regnum;
kono
parents:
diff changeset
221
kono
parents:
diff changeset
222 /* Hook used by __throw. */
kono
parents:
diff changeset
223
kono
parents:
diff changeset
224 rtx
kono
parents:
diff changeset
225 expand_builtin_dwarf_sp_column (void)
kono
parents:
diff changeset
226 {
kono
parents:
diff changeset
227 unsigned int dwarf_regnum = DWARF_FRAME_REGNUM (STACK_POINTER_REGNUM);
kono
parents:
diff changeset
228 return GEN_INT (DWARF2_FRAME_REG_OUT (dwarf_regnum, 1));
kono
parents:
diff changeset
229 }
kono
parents:
diff changeset
230
kono
parents:
diff changeset
231 /* MEM is a memory reference for the register size table, each element of
kono
parents:
diff changeset
232 which has mode MODE. Initialize column C as a return address column. */
kono
parents:
diff changeset
233
kono
parents:
diff changeset
234 static void
kono
parents:
diff changeset
235 init_return_column_size (scalar_int_mode mode, rtx mem, unsigned int c)
kono
parents:
diff changeset
236 {
kono
parents:
diff changeset
237 HOST_WIDE_INT offset = c * GET_MODE_SIZE (mode);
kono
parents:
diff changeset
238 HOST_WIDE_INT size = GET_MODE_SIZE (Pmode);
kono
parents:
diff changeset
239 emit_move_insn (adjust_address (mem, mode, offset),
kono
parents:
diff changeset
240 gen_int_mode (size, mode));
kono
parents:
diff changeset
241 }
kono
parents:
diff changeset
242
kono
parents:
diff changeset
243 /* Datastructure used by expand_builtin_init_dwarf_reg_sizes and
kono
parents:
diff changeset
244 init_one_dwarf_reg_size to communicate on what has been done by the
kono
parents:
diff changeset
245 latter. */
kono
parents:
diff changeset
246
kono
parents:
diff changeset
247 struct init_one_dwarf_reg_state
kono
parents:
diff changeset
248 {
kono
parents:
diff changeset
249 /* Whether the dwarf return column was initialized. */
kono
parents:
diff changeset
250 bool wrote_return_column;
kono
parents:
diff changeset
251
kono
parents:
diff changeset
252 /* For each hard register REGNO, whether init_one_dwarf_reg_size
kono
parents:
diff changeset
253 was given REGNO to process already. */
kono
parents:
diff changeset
254 bool processed_regno [FIRST_PSEUDO_REGISTER];
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 };
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 /* Helper for expand_builtin_init_dwarf_reg_sizes. Generate code to
kono
parents:
diff changeset
259 initialize the dwarf register size table entry corresponding to register
kono
parents:
diff changeset
260 REGNO in REGMODE. TABLE is the table base address, SLOTMODE is the mode to
kono
parents:
diff changeset
261 use for the size entry to initialize, and INIT_STATE is the communication
kono
parents:
diff changeset
262 datastructure conveying what we're doing to our caller. */
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264 static
kono
parents:
diff changeset
265 void init_one_dwarf_reg_size (int regno, machine_mode regmode,
kono
parents:
diff changeset
266 rtx table, machine_mode slotmode,
kono
parents:
diff changeset
267 init_one_dwarf_reg_state *init_state)
kono
parents:
diff changeset
268 {
kono
parents:
diff changeset
269 const unsigned int dnum = DWARF_FRAME_REGNUM (regno);
kono
parents:
diff changeset
270 const unsigned int rnum = DWARF2_FRAME_REG_OUT (dnum, 1);
kono
parents:
diff changeset
271 const unsigned int dcol = DWARF_REG_TO_UNWIND_COLUMN (rnum);
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 const HOST_WIDE_INT slotoffset = dcol * GET_MODE_SIZE (slotmode);
kono
parents:
diff changeset
274 const HOST_WIDE_INT regsize = GET_MODE_SIZE (regmode);
kono
parents:
diff changeset
275
kono
parents:
diff changeset
276 init_state->processed_regno[regno] = true;
kono
parents:
diff changeset
277
kono
parents:
diff changeset
278 if (rnum >= DWARF_FRAME_REGISTERS)
kono
parents:
diff changeset
279 return;
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 if (dnum == DWARF_FRAME_RETURN_COLUMN)
kono
parents:
diff changeset
282 {
kono
parents:
diff changeset
283 if (regmode == VOIDmode)
kono
parents:
diff changeset
284 return;
kono
parents:
diff changeset
285 init_state->wrote_return_column = true;
kono
parents:
diff changeset
286 }
kono
parents:
diff changeset
287
kono
parents:
diff changeset
288 if (slotoffset < 0)
kono
parents:
diff changeset
289 return;
kono
parents:
diff changeset
290
kono
parents:
diff changeset
291 emit_move_insn (adjust_address (table, slotmode, slotoffset),
kono
parents:
diff changeset
292 gen_int_mode (regsize, slotmode));
kono
parents:
diff changeset
293 }
kono
parents:
diff changeset
294
kono
parents:
diff changeset
295 /* Generate code to initialize the dwarf register size table located
kono
parents:
diff changeset
296 at the provided ADDRESS. */
kono
parents:
diff changeset
297
kono
parents:
diff changeset
298 void
kono
parents:
diff changeset
299 expand_builtin_init_dwarf_reg_sizes (tree address)
kono
parents:
diff changeset
300 {
kono
parents:
diff changeset
301 unsigned int i;
kono
parents:
diff changeset
302 scalar_int_mode mode = SCALAR_INT_TYPE_MODE (char_type_node);
kono
parents:
diff changeset
303 rtx addr = expand_normal (address);
kono
parents:
diff changeset
304 rtx mem = gen_rtx_MEM (BLKmode, addr);
kono
parents:
diff changeset
305
kono
parents:
diff changeset
306 init_one_dwarf_reg_state init_state;
kono
parents:
diff changeset
307
kono
parents:
diff changeset
308 memset ((char *)&init_state, 0, sizeof (init_state));
kono
parents:
diff changeset
309
kono
parents:
diff changeset
310 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
kono
parents:
diff changeset
311 {
kono
parents:
diff changeset
312 machine_mode save_mode;
kono
parents:
diff changeset
313 rtx span;
kono
parents:
diff changeset
314
kono
parents:
diff changeset
315 /* No point in processing a register multiple times. This could happen
kono
parents:
diff changeset
316 with register spans, e.g. when a reg is first processed as a piece of
kono
parents:
diff changeset
317 a span, then as a register on its own later on. */
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 if (init_state.processed_regno[i])
kono
parents:
diff changeset
320 continue;
kono
parents:
diff changeset
321
kono
parents:
diff changeset
322 save_mode = targetm.dwarf_frame_reg_mode (i);
kono
parents:
diff changeset
323 span = targetm.dwarf_register_span (gen_rtx_REG (save_mode, i));
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 if (!span)
kono
parents:
diff changeset
326 init_one_dwarf_reg_size (i, save_mode, mem, mode, &init_state);
kono
parents:
diff changeset
327 else
kono
parents:
diff changeset
328 {
kono
parents:
diff changeset
329 for (int si = 0; si < XVECLEN (span, 0); si++)
kono
parents:
diff changeset
330 {
kono
parents:
diff changeset
331 rtx reg = XVECEXP (span, 0, si);
kono
parents:
diff changeset
332
kono
parents:
diff changeset
333 init_one_dwarf_reg_size
kono
parents:
diff changeset
334 (REGNO (reg), GET_MODE (reg), mem, mode, &init_state);
kono
parents:
diff changeset
335 }
kono
parents:
diff changeset
336 }
kono
parents:
diff changeset
337 }
kono
parents:
diff changeset
338
kono
parents:
diff changeset
339 if (!init_state.wrote_return_column)
kono
parents:
diff changeset
340 init_return_column_size (mode, mem, DWARF_FRAME_RETURN_COLUMN);
kono
parents:
diff changeset
341
kono
parents:
diff changeset
342 #ifdef DWARF_ALT_FRAME_RETURN_COLUMN
kono
parents:
diff changeset
343 init_return_column_size (mode, mem, DWARF_ALT_FRAME_RETURN_COLUMN);
kono
parents:
diff changeset
344 #endif
kono
parents:
diff changeset
345
kono
parents:
diff changeset
346 targetm.init_dwarf_reg_sizes_extra (address);
kono
parents:
diff changeset
347 }
kono
parents:
diff changeset
348
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 static dw_trace_info *
kono
parents:
diff changeset
351 get_trace_info (rtx_insn *insn)
kono
parents:
diff changeset
352 {
kono
parents:
diff changeset
353 dw_trace_info dummy;
kono
parents:
diff changeset
354 dummy.head = insn;
kono
parents:
diff changeset
355 return trace_index->find_with_hash (&dummy, INSN_UID (insn));
kono
parents:
diff changeset
356 }
kono
parents:
diff changeset
357
kono
parents:
diff changeset
358 static bool
kono
parents:
diff changeset
359 save_point_p (rtx_insn *insn)
kono
parents:
diff changeset
360 {
kono
parents:
diff changeset
361 /* Labels, except those that are really jump tables. */
kono
parents:
diff changeset
362 if (LABEL_P (insn))
kono
parents:
diff changeset
363 return inside_basic_block_p (insn);
kono
parents:
diff changeset
364
kono
parents:
diff changeset
365 /* We split traces at the prologue/epilogue notes because those
kono
parents:
diff changeset
366 are points at which the unwind info is usually stable. This
kono
parents:
diff changeset
367 makes it easier to find spots with identical unwind info so
kono
parents:
diff changeset
368 that we can use remember/restore_state opcodes. */
kono
parents:
diff changeset
369 if (NOTE_P (insn))
kono
parents:
diff changeset
370 switch (NOTE_KIND (insn))
kono
parents:
diff changeset
371 {
kono
parents:
diff changeset
372 case NOTE_INSN_PROLOGUE_END:
kono
parents:
diff changeset
373 case NOTE_INSN_EPILOGUE_BEG:
kono
parents:
diff changeset
374 return true;
kono
parents:
diff changeset
375 }
kono
parents:
diff changeset
376
kono
parents:
diff changeset
377 return false;
kono
parents:
diff changeset
378 }
kono
parents:
diff changeset
379
kono
parents:
diff changeset
380 /* Divide OFF by DWARF_CIE_DATA_ALIGNMENT, asserting no remainder. */
kono
parents:
diff changeset
381
kono
parents:
diff changeset
382 static inline HOST_WIDE_INT
kono
parents:
diff changeset
383 div_data_align (HOST_WIDE_INT off)
kono
parents:
diff changeset
384 {
kono
parents:
diff changeset
385 HOST_WIDE_INT r = off / DWARF_CIE_DATA_ALIGNMENT;
kono
parents:
diff changeset
386 gcc_assert (r * DWARF_CIE_DATA_ALIGNMENT == off);
kono
parents:
diff changeset
387 return r;
kono
parents:
diff changeset
388 }
kono
parents:
diff changeset
389
kono
parents:
diff changeset
390 /* Return true if we need a signed version of a given opcode
kono
parents:
diff changeset
391 (e.g. DW_CFA_offset_extended_sf vs DW_CFA_offset_extended). */
kono
parents:
diff changeset
392
kono
parents:
diff changeset
393 static inline bool
kono
parents:
diff changeset
394 need_data_align_sf_opcode (HOST_WIDE_INT off)
kono
parents:
diff changeset
395 {
kono
parents:
diff changeset
396 return DWARF_CIE_DATA_ALIGNMENT < 0 ? off > 0 : off < 0;
kono
parents:
diff changeset
397 }
kono
parents:
diff changeset
398
kono
parents:
diff changeset
399 /* Return a pointer to a newly allocated Call Frame Instruction. */
kono
parents:
diff changeset
400
kono
parents:
diff changeset
401 static inline dw_cfi_ref
kono
parents:
diff changeset
402 new_cfi (void)
kono
parents:
diff changeset
403 {
kono
parents:
diff changeset
404 dw_cfi_ref cfi = ggc_alloc<dw_cfi_node> ();
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = 0;
kono
parents:
diff changeset
407 cfi->dw_cfi_oprnd2.dw_cfi_reg_num = 0;
kono
parents:
diff changeset
408
kono
parents:
diff changeset
409 return cfi;
kono
parents:
diff changeset
410 }
kono
parents:
diff changeset
411
kono
parents:
diff changeset
412 /* Return a newly allocated CFI row, with no defined data. */
kono
parents:
diff changeset
413
kono
parents:
diff changeset
414 static dw_cfi_row *
kono
parents:
diff changeset
415 new_cfi_row (void)
kono
parents:
diff changeset
416 {
kono
parents:
diff changeset
417 dw_cfi_row *row = ggc_cleared_alloc<dw_cfi_row> ();
kono
parents:
diff changeset
418
kono
parents:
diff changeset
419 row->cfa.reg = INVALID_REGNUM;
kono
parents:
diff changeset
420
kono
parents:
diff changeset
421 return row;
kono
parents:
diff changeset
422 }
kono
parents:
diff changeset
423
kono
parents:
diff changeset
424 /* Return a copy of an existing CFI row. */
kono
parents:
diff changeset
425
kono
parents:
diff changeset
426 static dw_cfi_row *
kono
parents:
diff changeset
427 copy_cfi_row (dw_cfi_row *src)
kono
parents:
diff changeset
428 {
kono
parents:
diff changeset
429 dw_cfi_row *dst = ggc_alloc<dw_cfi_row> ();
kono
parents:
diff changeset
430
kono
parents:
diff changeset
431 *dst = *src;
kono
parents:
diff changeset
432 dst->reg_save = vec_safe_copy (src->reg_save);
kono
parents:
diff changeset
433
kono
parents:
diff changeset
434 return dst;
kono
parents:
diff changeset
435 }
kono
parents:
diff changeset
436
kono
parents:
diff changeset
437 /* Generate a new label for the CFI info to refer to. */
kono
parents:
diff changeset
438
kono
parents:
diff changeset
439 static char *
kono
parents:
diff changeset
440 dwarf2out_cfi_label (void)
kono
parents:
diff changeset
441 {
kono
parents:
diff changeset
442 int num = dwarf2out_cfi_label_num++;
kono
parents:
diff changeset
443 char label[20];
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 ASM_GENERATE_INTERNAL_LABEL (label, "LCFI", num);
kono
parents:
diff changeset
446
kono
parents:
diff changeset
447 return xstrdup (label);
kono
parents:
diff changeset
448 }
kono
parents:
diff changeset
449
kono
parents:
diff changeset
450 /* Add CFI either to the current insn stream or to a vector, or both. */
kono
parents:
diff changeset
451
kono
parents:
diff changeset
452 static void
kono
parents:
diff changeset
453 add_cfi (dw_cfi_ref cfi)
kono
parents:
diff changeset
454 {
kono
parents:
diff changeset
455 any_cfis_emitted = true;
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 if (add_cfi_insn != NULL)
kono
parents:
diff changeset
458 {
kono
parents:
diff changeset
459 add_cfi_insn = emit_note_after (NOTE_INSN_CFI, add_cfi_insn);
kono
parents:
diff changeset
460 NOTE_CFI (add_cfi_insn) = cfi;
kono
parents:
diff changeset
461 }
kono
parents:
diff changeset
462
kono
parents:
diff changeset
463 if (add_cfi_vec != NULL)
kono
parents:
diff changeset
464 vec_safe_push (*add_cfi_vec, cfi);
kono
parents:
diff changeset
465 }
kono
parents:
diff changeset
466
kono
parents:
diff changeset
467 static void
kono
parents:
diff changeset
468 add_cfi_args_size (HOST_WIDE_INT size)
kono
parents:
diff changeset
469 {
kono
parents:
diff changeset
470 dw_cfi_ref cfi = new_cfi ();
kono
parents:
diff changeset
471
kono
parents:
diff changeset
472 /* While we can occasionally have args_size < 0 internally, this state
kono
parents:
diff changeset
473 should not persist at a point we actually need an opcode. */
kono
parents:
diff changeset
474 gcc_assert (size >= 0);
kono
parents:
diff changeset
475
kono
parents:
diff changeset
476 cfi->dw_cfi_opc = DW_CFA_GNU_args_size;
kono
parents:
diff changeset
477 cfi->dw_cfi_oprnd1.dw_cfi_offset = size;
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 add_cfi (cfi);
kono
parents:
diff changeset
480 }
kono
parents:
diff changeset
481
kono
parents:
diff changeset
482 static void
kono
parents:
diff changeset
483 add_cfi_restore (unsigned reg)
kono
parents:
diff changeset
484 {
kono
parents:
diff changeset
485 dw_cfi_ref cfi = new_cfi ();
kono
parents:
diff changeset
486
kono
parents:
diff changeset
487 cfi->dw_cfi_opc = (reg & ~0x3f ? DW_CFA_restore_extended : DW_CFA_restore);
kono
parents:
diff changeset
488 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
kono
parents:
diff changeset
489
kono
parents:
diff changeset
490 add_cfi (cfi);
kono
parents:
diff changeset
491 }
kono
parents:
diff changeset
492
kono
parents:
diff changeset
493 /* Perform ROW->REG_SAVE[COLUMN] = CFI. CFI may be null, indicating
kono
parents:
diff changeset
494 that the register column is no longer saved. */
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 static void
kono
parents:
diff changeset
497 update_row_reg_save (dw_cfi_row *row, unsigned column, dw_cfi_ref cfi)
kono
parents:
diff changeset
498 {
kono
parents:
diff changeset
499 if (vec_safe_length (row->reg_save) <= column)
kono
parents:
diff changeset
500 vec_safe_grow_cleared (row->reg_save, column + 1);
kono
parents:
diff changeset
501 (*row->reg_save)[column] = cfi;
kono
parents:
diff changeset
502 }
kono
parents:
diff changeset
503
kono
parents:
diff changeset
504 /* This function fills in aa dw_cfa_location structure from a dwarf location
kono
parents:
diff changeset
505 descriptor sequence. */
kono
parents:
diff changeset
506
kono
parents:
diff changeset
507 static void
kono
parents:
diff changeset
508 get_cfa_from_loc_descr (dw_cfa_location *cfa, struct dw_loc_descr_node *loc)
kono
parents:
diff changeset
509 {
kono
parents:
diff changeset
510 struct dw_loc_descr_node *ptr;
kono
parents:
diff changeset
511 cfa->offset = 0;
kono
parents:
diff changeset
512 cfa->base_offset = 0;
kono
parents:
diff changeset
513 cfa->indirect = 0;
kono
parents:
diff changeset
514 cfa->reg = -1;
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 for (ptr = loc; ptr != NULL; ptr = ptr->dw_loc_next)
kono
parents:
diff changeset
517 {
kono
parents:
diff changeset
518 enum dwarf_location_atom op = ptr->dw_loc_opc;
kono
parents:
diff changeset
519
kono
parents:
diff changeset
520 switch (op)
kono
parents:
diff changeset
521 {
kono
parents:
diff changeset
522 case DW_OP_reg0:
kono
parents:
diff changeset
523 case DW_OP_reg1:
kono
parents:
diff changeset
524 case DW_OP_reg2:
kono
parents:
diff changeset
525 case DW_OP_reg3:
kono
parents:
diff changeset
526 case DW_OP_reg4:
kono
parents:
diff changeset
527 case DW_OP_reg5:
kono
parents:
diff changeset
528 case DW_OP_reg6:
kono
parents:
diff changeset
529 case DW_OP_reg7:
kono
parents:
diff changeset
530 case DW_OP_reg8:
kono
parents:
diff changeset
531 case DW_OP_reg9:
kono
parents:
diff changeset
532 case DW_OP_reg10:
kono
parents:
diff changeset
533 case DW_OP_reg11:
kono
parents:
diff changeset
534 case DW_OP_reg12:
kono
parents:
diff changeset
535 case DW_OP_reg13:
kono
parents:
diff changeset
536 case DW_OP_reg14:
kono
parents:
diff changeset
537 case DW_OP_reg15:
kono
parents:
diff changeset
538 case DW_OP_reg16:
kono
parents:
diff changeset
539 case DW_OP_reg17:
kono
parents:
diff changeset
540 case DW_OP_reg18:
kono
parents:
diff changeset
541 case DW_OP_reg19:
kono
parents:
diff changeset
542 case DW_OP_reg20:
kono
parents:
diff changeset
543 case DW_OP_reg21:
kono
parents:
diff changeset
544 case DW_OP_reg22:
kono
parents:
diff changeset
545 case DW_OP_reg23:
kono
parents:
diff changeset
546 case DW_OP_reg24:
kono
parents:
diff changeset
547 case DW_OP_reg25:
kono
parents:
diff changeset
548 case DW_OP_reg26:
kono
parents:
diff changeset
549 case DW_OP_reg27:
kono
parents:
diff changeset
550 case DW_OP_reg28:
kono
parents:
diff changeset
551 case DW_OP_reg29:
kono
parents:
diff changeset
552 case DW_OP_reg30:
kono
parents:
diff changeset
553 case DW_OP_reg31:
kono
parents:
diff changeset
554 cfa->reg = op - DW_OP_reg0;
kono
parents:
diff changeset
555 break;
kono
parents:
diff changeset
556 case DW_OP_regx:
kono
parents:
diff changeset
557 cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
kono
parents:
diff changeset
558 break;
kono
parents:
diff changeset
559 case DW_OP_breg0:
kono
parents:
diff changeset
560 case DW_OP_breg1:
kono
parents:
diff changeset
561 case DW_OP_breg2:
kono
parents:
diff changeset
562 case DW_OP_breg3:
kono
parents:
diff changeset
563 case DW_OP_breg4:
kono
parents:
diff changeset
564 case DW_OP_breg5:
kono
parents:
diff changeset
565 case DW_OP_breg6:
kono
parents:
diff changeset
566 case DW_OP_breg7:
kono
parents:
diff changeset
567 case DW_OP_breg8:
kono
parents:
diff changeset
568 case DW_OP_breg9:
kono
parents:
diff changeset
569 case DW_OP_breg10:
kono
parents:
diff changeset
570 case DW_OP_breg11:
kono
parents:
diff changeset
571 case DW_OP_breg12:
kono
parents:
diff changeset
572 case DW_OP_breg13:
kono
parents:
diff changeset
573 case DW_OP_breg14:
kono
parents:
diff changeset
574 case DW_OP_breg15:
kono
parents:
diff changeset
575 case DW_OP_breg16:
kono
parents:
diff changeset
576 case DW_OP_breg17:
kono
parents:
diff changeset
577 case DW_OP_breg18:
kono
parents:
diff changeset
578 case DW_OP_breg19:
kono
parents:
diff changeset
579 case DW_OP_breg20:
kono
parents:
diff changeset
580 case DW_OP_breg21:
kono
parents:
diff changeset
581 case DW_OP_breg22:
kono
parents:
diff changeset
582 case DW_OP_breg23:
kono
parents:
diff changeset
583 case DW_OP_breg24:
kono
parents:
diff changeset
584 case DW_OP_breg25:
kono
parents:
diff changeset
585 case DW_OP_breg26:
kono
parents:
diff changeset
586 case DW_OP_breg27:
kono
parents:
diff changeset
587 case DW_OP_breg28:
kono
parents:
diff changeset
588 case DW_OP_breg29:
kono
parents:
diff changeset
589 case DW_OP_breg30:
kono
parents:
diff changeset
590 case DW_OP_breg31:
kono
parents:
diff changeset
591 cfa->reg = op - DW_OP_breg0;
kono
parents:
diff changeset
592 cfa->base_offset = ptr->dw_loc_oprnd1.v.val_int;
kono
parents:
diff changeset
593 break;
kono
parents:
diff changeset
594 case DW_OP_bregx:
kono
parents:
diff changeset
595 cfa->reg = ptr->dw_loc_oprnd1.v.val_int;
kono
parents:
diff changeset
596 cfa->base_offset = ptr->dw_loc_oprnd2.v.val_int;
kono
parents:
diff changeset
597 break;
kono
parents:
diff changeset
598 case DW_OP_deref:
kono
parents:
diff changeset
599 cfa->indirect = 1;
kono
parents:
diff changeset
600 break;
kono
parents:
diff changeset
601 case DW_OP_plus_uconst:
kono
parents:
diff changeset
602 cfa->offset = ptr->dw_loc_oprnd1.v.val_unsigned;
kono
parents:
diff changeset
603 break;
kono
parents:
diff changeset
604 default:
kono
parents:
diff changeset
605 gcc_unreachable ();
kono
parents:
diff changeset
606 }
kono
parents:
diff changeset
607 }
kono
parents:
diff changeset
608 }
kono
parents:
diff changeset
609
kono
parents:
diff changeset
610 /* Find the previous value for the CFA, iteratively. CFI is the opcode
kono
parents:
diff changeset
611 to interpret, *LOC will be updated as necessary, *REMEMBER is used for
kono
parents:
diff changeset
612 one level of remember/restore state processing. */
kono
parents:
diff changeset
613
kono
parents:
diff changeset
614 void
kono
parents:
diff changeset
615 lookup_cfa_1 (dw_cfi_ref cfi, dw_cfa_location *loc, dw_cfa_location *remember)
kono
parents:
diff changeset
616 {
kono
parents:
diff changeset
617 switch (cfi->dw_cfi_opc)
kono
parents:
diff changeset
618 {
kono
parents:
diff changeset
619 case DW_CFA_def_cfa_offset:
kono
parents:
diff changeset
620 case DW_CFA_def_cfa_offset_sf:
kono
parents:
diff changeset
621 loc->offset = cfi->dw_cfi_oprnd1.dw_cfi_offset;
kono
parents:
diff changeset
622 break;
kono
parents:
diff changeset
623 case DW_CFA_def_cfa_register:
kono
parents:
diff changeset
624 loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
kono
parents:
diff changeset
625 break;
kono
parents:
diff changeset
626 case DW_CFA_def_cfa:
kono
parents:
diff changeset
627 case DW_CFA_def_cfa_sf:
kono
parents:
diff changeset
628 loc->reg = cfi->dw_cfi_oprnd1.dw_cfi_reg_num;
kono
parents:
diff changeset
629 loc->offset = cfi->dw_cfi_oprnd2.dw_cfi_offset;
kono
parents:
diff changeset
630 break;
kono
parents:
diff changeset
631 case DW_CFA_def_cfa_expression:
kono
parents:
diff changeset
632 get_cfa_from_loc_descr (loc, cfi->dw_cfi_oprnd1.dw_cfi_loc);
kono
parents:
diff changeset
633 break;
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 case DW_CFA_remember_state:
kono
parents:
diff changeset
636 gcc_assert (!remember->in_use);
kono
parents:
diff changeset
637 *remember = *loc;
kono
parents:
diff changeset
638 remember->in_use = 1;
kono
parents:
diff changeset
639 break;
kono
parents:
diff changeset
640 case DW_CFA_restore_state:
kono
parents:
diff changeset
641 gcc_assert (remember->in_use);
kono
parents:
diff changeset
642 *loc = *remember;
kono
parents:
diff changeset
643 remember->in_use = 0;
kono
parents:
diff changeset
644 break;
kono
parents:
diff changeset
645
kono
parents:
diff changeset
646 default:
kono
parents:
diff changeset
647 break;
kono
parents:
diff changeset
648 }
kono
parents:
diff changeset
649 }
kono
parents:
diff changeset
650
kono
parents:
diff changeset
651 /* Determine if two dw_cfa_location structures define the same data. */
kono
parents:
diff changeset
652
kono
parents:
diff changeset
653 bool
kono
parents:
diff changeset
654 cfa_equal_p (const dw_cfa_location *loc1, const dw_cfa_location *loc2)
kono
parents:
diff changeset
655 {
kono
parents:
diff changeset
656 return (loc1->reg == loc2->reg
kono
parents:
diff changeset
657 && loc1->offset == loc2->offset
kono
parents:
diff changeset
658 && loc1->indirect == loc2->indirect
kono
parents:
diff changeset
659 && (loc1->indirect == 0
kono
parents:
diff changeset
660 || loc1->base_offset == loc2->base_offset));
kono
parents:
diff changeset
661 }
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 /* Determine if two CFI operands are identical. */
kono
parents:
diff changeset
664
kono
parents:
diff changeset
665 static bool
kono
parents:
diff changeset
666 cfi_oprnd_equal_p (enum dw_cfi_oprnd_type t, dw_cfi_oprnd *a, dw_cfi_oprnd *b)
kono
parents:
diff changeset
667 {
kono
parents:
diff changeset
668 switch (t)
kono
parents:
diff changeset
669 {
kono
parents:
diff changeset
670 case dw_cfi_oprnd_unused:
kono
parents:
diff changeset
671 return true;
kono
parents:
diff changeset
672 case dw_cfi_oprnd_reg_num:
kono
parents:
diff changeset
673 return a->dw_cfi_reg_num == b->dw_cfi_reg_num;
kono
parents:
diff changeset
674 case dw_cfi_oprnd_offset:
kono
parents:
diff changeset
675 return a->dw_cfi_offset == b->dw_cfi_offset;
kono
parents:
diff changeset
676 case dw_cfi_oprnd_addr:
kono
parents:
diff changeset
677 return (a->dw_cfi_addr == b->dw_cfi_addr
kono
parents:
diff changeset
678 || strcmp (a->dw_cfi_addr, b->dw_cfi_addr) == 0);
kono
parents:
diff changeset
679 case dw_cfi_oprnd_loc:
kono
parents:
diff changeset
680 return loc_descr_equal_p (a->dw_cfi_loc, b->dw_cfi_loc);
kono
parents:
diff changeset
681 }
kono
parents:
diff changeset
682 gcc_unreachable ();
kono
parents:
diff changeset
683 }
kono
parents:
diff changeset
684
kono
parents:
diff changeset
685 /* Determine if two CFI entries are identical. */
kono
parents:
diff changeset
686
kono
parents:
diff changeset
687 static bool
kono
parents:
diff changeset
688 cfi_equal_p (dw_cfi_ref a, dw_cfi_ref b)
kono
parents:
diff changeset
689 {
kono
parents:
diff changeset
690 enum dwarf_call_frame_info opc;
kono
parents:
diff changeset
691
kono
parents:
diff changeset
692 /* Make things easier for our callers, including missing operands. */
kono
parents:
diff changeset
693 if (a == b)
kono
parents:
diff changeset
694 return true;
kono
parents:
diff changeset
695 if (a == NULL || b == NULL)
kono
parents:
diff changeset
696 return false;
kono
parents:
diff changeset
697
kono
parents:
diff changeset
698 /* Obviously, the opcodes must match. */
kono
parents:
diff changeset
699 opc = a->dw_cfi_opc;
kono
parents:
diff changeset
700 if (opc != b->dw_cfi_opc)
kono
parents:
diff changeset
701 return false;
kono
parents:
diff changeset
702
kono
parents:
diff changeset
703 /* Compare the two operands, re-using the type of the operands as
kono
parents:
diff changeset
704 already exposed elsewhere. */
kono
parents:
diff changeset
705 return (cfi_oprnd_equal_p (dw_cfi_oprnd1_desc (opc),
kono
parents:
diff changeset
706 &a->dw_cfi_oprnd1, &b->dw_cfi_oprnd1)
kono
parents:
diff changeset
707 && cfi_oprnd_equal_p (dw_cfi_oprnd2_desc (opc),
kono
parents:
diff changeset
708 &a->dw_cfi_oprnd2, &b->dw_cfi_oprnd2));
kono
parents:
diff changeset
709 }
kono
parents:
diff changeset
710
kono
parents:
diff changeset
711 /* Determine if two CFI_ROW structures are identical. */
kono
parents:
diff changeset
712
kono
parents:
diff changeset
713 static bool
kono
parents:
diff changeset
714 cfi_row_equal_p (dw_cfi_row *a, dw_cfi_row *b)
kono
parents:
diff changeset
715 {
kono
parents:
diff changeset
716 size_t i, n_a, n_b, n_max;
kono
parents:
diff changeset
717
kono
parents:
diff changeset
718 if (a->cfa_cfi)
kono
parents:
diff changeset
719 {
kono
parents:
diff changeset
720 if (!cfi_equal_p (a->cfa_cfi, b->cfa_cfi))
kono
parents:
diff changeset
721 return false;
kono
parents:
diff changeset
722 }
kono
parents:
diff changeset
723 else if (!cfa_equal_p (&a->cfa, &b->cfa))
kono
parents:
diff changeset
724 return false;
kono
parents:
diff changeset
725
kono
parents:
diff changeset
726 n_a = vec_safe_length (a->reg_save);
kono
parents:
diff changeset
727 n_b = vec_safe_length (b->reg_save);
kono
parents:
diff changeset
728 n_max = MAX (n_a, n_b);
kono
parents:
diff changeset
729
kono
parents:
diff changeset
730 for (i = 0; i < n_max; ++i)
kono
parents:
diff changeset
731 {
kono
parents:
diff changeset
732 dw_cfi_ref r_a = NULL, r_b = NULL;
kono
parents:
diff changeset
733
kono
parents:
diff changeset
734 if (i < n_a)
kono
parents:
diff changeset
735 r_a = (*a->reg_save)[i];
kono
parents:
diff changeset
736 if (i < n_b)
kono
parents:
diff changeset
737 r_b = (*b->reg_save)[i];
kono
parents:
diff changeset
738
kono
parents:
diff changeset
739 if (!cfi_equal_p (r_a, r_b))
kono
parents:
diff changeset
740 return false;
kono
parents:
diff changeset
741 }
kono
parents:
diff changeset
742
kono
parents:
diff changeset
743 return true;
kono
parents:
diff changeset
744 }
kono
parents:
diff changeset
745
kono
parents:
diff changeset
746 /* The CFA is now calculated from NEW_CFA. Consider OLD_CFA in determining
kono
parents:
diff changeset
747 what opcode to emit. Returns the CFI opcode to effect the change, or
kono
parents:
diff changeset
748 NULL if NEW_CFA == OLD_CFA. */
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 static dw_cfi_ref
kono
parents:
diff changeset
751 def_cfa_0 (dw_cfa_location *old_cfa, dw_cfa_location *new_cfa)
kono
parents:
diff changeset
752 {
kono
parents:
diff changeset
753 dw_cfi_ref cfi;
kono
parents:
diff changeset
754
kono
parents:
diff changeset
755 /* If nothing changed, no need to issue any call frame instructions. */
kono
parents:
diff changeset
756 if (cfa_equal_p (old_cfa, new_cfa))
kono
parents:
diff changeset
757 return NULL;
kono
parents:
diff changeset
758
kono
parents:
diff changeset
759 cfi = new_cfi ();
kono
parents:
diff changeset
760
kono
parents:
diff changeset
761 if (new_cfa->reg == old_cfa->reg && !new_cfa->indirect && !old_cfa->indirect)
kono
parents:
diff changeset
762 {
kono
parents:
diff changeset
763 /* Construct a "DW_CFA_def_cfa_offset <offset>" instruction, indicating
kono
parents:
diff changeset
764 the CFA register did not change but the offset did. The data
kono
parents:
diff changeset
765 factoring for DW_CFA_def_cfa_offset_sf happens in output_cfi, or
kono
parents:
diff changeset
766 in the assembler via the .cfi_def_cfa_offset directive. */
kono
parents:
diff changeset
767 if (new_cfa->offset < 0)
kono
parents:
diff changeset
768 cfi->dw_cfi_opc = DW_CFA_def_cfa_offset_sf;
kono
parents:
diff changeset
769 else
kono
parents:
diff changeset
770 cfi->dw_cfi_opc = DW_CFA_def_cfa_offset;
kono
parents:
diff changeset
771 cfi->dw_cfi_oprnd1.dw_cfi_offset = new_cfa->offset;
kono
parents:
diff changeset
772 }
kono
parents:
diff changeset
773 else if (new_cfa->offset == old_cfa->offset
kono
parents:
diff changeset
774 && old_cfa->reg != INVALID_REGNUM
kono
parents:
diff changeset
775 && !new_cfa->indirect
kono
parents:
diff changeset
776 && !old_cfa->indirect)
kono
parents:
diff changeset
777 {
kono
parents:
diff changeset
778 /* Construct a "DW_CFA_def_cfa_register <register>" instruction,
kono
parents:
diff changeset
779 indicating the CFA register has changed to <register> but the
kono
parents:
diff changeset
780 offset has not changed. */
kono
parents:
diff changeset
781 cfi->dw_cfi_opc = DW_CFA_def_cfa_register;
kono
parents:
diff changeset
782 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
kono
parents:
diff changeset
783 }
kono
parents:
diff changeset
784 else if (new_cfa->indirect == 0)
kono
parents:
diff changeset
785 {
kono
parents:
diff changeset
786 /* Construct a "DW_CFA_def_cfa <register> <offset>" instruction,
kono
parents:
diff changeset
787 indicating the CFA register has changed to <register> with
kono
parents:
diff changeset
788 the specified offset. The data factoring for DW_CFA_def_cfa_sf
kono
parents:
diff changeset
789 happens in output_cfi, or in the assembler via the .cfi_def_cfa
kono
parents:
diff changeset
790 directive. */
kono
parents:
diff changeset
791 if (new_cfa->offset < 0)
kono
parents:
diff changeset
792 cfi->dw_cfi_opc = DW_CFA_def_cfa_sf;
kono
parents:
diff changeset
793 else
kono
parents:
diff changeset
794 cfi->dw_cfi_opc = DW_CFA_def_cfa;
kono
parents:
diff changeset
795 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = new_cfa->reg;
kono
parents:
diff changeset
796 cfi->dw_cfi_oprnd2.dw_cfi_offset = new_cfa->offset;
kono
parents:
diff changeset
797 }
kono
parents:
diff changeset
798 else
kono
parents:
diff changeset
799 {
kono
parents:
diff changeset
800 /* Construct a DW_CFA_def_cfa_expression instruction to
kono
parents:
diff changeset
801 calculate the CFA using a full location expression since no
kono
parents:
diff changeset
802 register-offset pair is available. */
kono
parents:
diff changeset
803 struct dw_loc_descr_node *loc_list;
kono
parents:
diff changeset
804
kono
parents:
diff changeset
805 cfi->dw_cfi_opc = DW_CFA_def_cfa_expression;
kono
parents:
diff changeset
806 loc_list = build_cfa_loc (new_cfa, 0);
kono
parents:
diff changeset
807 cfi->dw_cfi_oprnd1.dw_cfi_loc = loc_list;
kono
parents:
diff changeset
808 }
kono
parents:
diff changeset
809
kono
parents:
diff changeset
810 return cfi;
kono
parents:
diff changeset
811 }
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 /* Similarly, but take OLD_CFA from CUR_ROW, and update it after the fact. */
kono
parents:
diff changeset
814
kono
parents:
diff changeset
815 static void
kono
parents:
diff changeset
816 def_cfa_1 (dw_cfa_location *new_cfa)
kono
parents:
diff changeset
817 {
kono
parents:
diff changeset
818 dw_cfi_ref cfi;
kono
parents:
diff changeset
819
kono
parents:
diff changeset
820 if (cur_trace->cfa_store.reg == new_cfa->reg && new_cfa->indirect == 0)
kono
parents:
diff changeset
821 cur_trace->cfa_store.offset = new_cfa->offset;
kono
parents:
diff changeset
822
kono
parents:
diff changeset
823 cfi = def_cfa_0 (&cur_row->cfa, new_cfa);
kono
parents:
diff changeset
824 if (cfi)
kono
parents:
diff changeset
825 {
kono
parents:
diff changeset
826 cur_row->cfa = *new_cfa;
kono
parents:
diff changeset
827 cur_row->cfa_cfi = (cfi->dw_cfi_opc == DW_CFA_def_cfa_expression
kono
parents:
diff changeset
828 ? cfi : NULL);
kono
parents:
diff changeset
829
kono
parents:
diff changeset
830 add_cfi (cfi);
kono
parents:
diff changeset
831 }
kono
parents:
diff changeset
832 }
kono
parents:
diff changeset
833
kono
parents:
diff changeset
834 /* Add the CFI for saving a register. REG is the CFA column number.
kono
parents:
diff changeset
835 If SREG is -1, the register is saved at OFFSET from the CFA;
kono
parents:
diff changeset
836 otherwise it is saved in SREG. */
kono
parents:
diff changeset
837
kono
parents:
diff changeset
838 static void
kono
parents:
diff changeset
839 reg_save (unsigned int reg, unsigned int sreg, HOST_WIDE_INT offset)
kono
parents:
diff changeset
840 {
kono
parents:
diff changeset
841 dw_fde_ref fde = cfun ? cfun->fde : NULL;
kono
parents:
diff changeset
842 dw_cfi_ref cfi = new_cfi ();
kono
parents:
diff changeset
843
kono
parents:
diff changeset
844 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
kono
parents:
diff changeset
845
kono
parents:
diff changeset
846 /* When stack is aligned, store REG using DW_CFA_expression with FP. */
kono
parents:
diff changeset
847 if (fde
kono
parents:
diff changeset
848 && fde->stack_realign
kono
parents:
diff changeset
849 && sreg == INVALID_REGNUM)
kono
parents:
diff changeset
850 {
kono
parents:
diff changeset
851 cfi->dw_cfi_opc = DW_CFA_expression;
kono
parents:
diff changeset
852 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = reg;
kono
parents:
diff changeset
853 cfi->dw_cfi_oprnd2.dw_cfi_loc
kono
parents:
diff changeset
854 = build_cfa_aligned_loc (&cur_row->cfa, offset,
kono
parents:
diff changeset
855 fde->stack_realignment);
kono
parents:
diff changeset
856 }
kono
parents:
diff changeset
857 else if (sreg == INVALID_REGNUM)
kono
parents:
diff changeset
858 {
kono
parents:
diff changeset
859 if (need_data_align_sf_opcode (offset))
kono
parents:
diff changeset
860 cfi->dw_cfi_opc = DW_CFA_offset_extended_sf;
kono
parents:
diff changeset
861 else if (reg & ~0x3f)
kono
parents:
diff changeset
862 cfi->dw_cfi_opc = DW_CFA_offset_extended;
kono
parents:
diff changeset
863 else
kono
parents:
diff changeset
864 cfi->dw_cfi_opc = DW_CFA_offset;
kono
parents:
diff changeset
865 cfi->dw_cfi_oprnd2.dw_cfi_offset = offset;
kono
parents:
diff changeset
866 }
kono
parents:
diff changeset
867 else if (sreg == reg)
kono
parents:
diff changeset
868 {
kono
parents:
diff changeset
869 /* While we could emit something like DW_CFA_same_value or
kono
parents:
diff changeset
870 DW_CFA_restore, we never expect to see something like that
kono
parents:
diff changeset
871 in a prologue. This is more likely to be a bug. A backend
kono
parents:
diff changeset
872 can always bypass this by using REG_CFA_RESTORE directly. */
kono
parents:
diff changeset
873 gcc_unreachable ();
kono
parents:
diff changeset
874 }
kono
parents:
diff changeset
875 else
kono
parents:
diff changeset
876 {
kono
parents:
diff changeset
877 cfi->dw_cfi_opc = DW_CFA_register;
kono
parents:
diff changeset
878 cfi->dw_cfi_oprnd2.dw_cfi_reg_num = sreg;
kono
parents:
diff changeset
879 }
kono
parents:
diff changeset
880
kono
parents:
diff changeset
881 add_cfi (cfi);
kono
parents:
diff changeset
882 update_row_reg_save (cur_row, reg, cfi);
kono
parents:
diff changeset
883 }
kono
parents:
diff changeset
884
kono
parents:
diff changeset
885 /* A subroutine of scan_trace. Check INSN for a REG_ARGS_SIZE note
kono
parents:
diff changeset
886 and adjust data structures to match. */
kono
parents:
diff changeset
887
kono
parents:
diff changeset
888 static void
kono
parents:
diff changeset
889 notice_args_size (rtx_insn *insn)
kono
parents:
diff changeset
890 {
kono
parents:
diff changeset
891 HOST_WIDE_INT args_size, delta;
kono
parents:
diff changeset
892 rtx note;
kono
parents:
diff changeset
893
kono
parents:
diff changeset
894 note = find_reg_note (insn, REG_ARGS_SIZE, NULL);
kono
parents:
diff changeset
895 if (note == NULL)
kono
parents:
diff changeset
896 return;
kono
parents:
diff changeset
897
kono
parents:
diff changeset
898 args_size = INTVAL (XEXP (note, 0));
kono
parents:
diff changeset
899 delta = args_size - cur_trace->end_true_args_size;
kono
parents:
diff changeset
900 if (delta == 0)
kono
parents:
diff changeset
901 return;
kono
parents:
diff changeset
902
kono
parents:
diff changeset
903 cur_trace->end_true_args_size = args_size;
kono
parents:
diff changeset
904
kono
parents:
diff changeset
905 /* If the CFA is computed off the stack pointer, then we must adjust
kono
parents:
diff changeset
906 the computation of the CFA as well. */
kono
parents:
diff changeset
907 if (cur_cfa->reg == dw_stack_pointer_regnum)
kono
parents:
diff changeset
908 {
kono
parents:
diff changeset
909 gcc_assert (!cur_cfa->indirect);
kono
parents:
diff changeset
910
kono
parents:
diff changeset
911 /* Convert a change in args_size (always a positive in the
kono
parents:
diff changeset
912 direction of stack growth) to a change in stack pointer. */
kono
parents:
diff changeset
913 if (!STACK_GROWS_DOWNWARD)
kono
parents:
diff changeset
914 delta = -delta;
kono
parents:
diff changeset
915
kono
parents:
diff changeset
916 cur_cfa->offset += delta;
kono
parents:
diff changeset
917 }
kono
parents:
diff changeset
918 }
kono
parents:
diff changeset
919
kono
parents:
diff changeset
920 /* A subroutine of scan_trace. INSN is can_throw_internal. Update the
kono
parents:
diff changeset
921 data within the trace related to EH insns and args_size. */
kono
parents:
diff changeset
922
kono
parents:
diff changeset
923 static void
kono
parents:
diff changeset
924 notice_eh_throw (rtx_insn *insn)
kono
parents:
diff changeset
925 {
kono
parents:
diff changeset
926 HOST_WIDE_INT args_size;
kono
parents:
diff changeset
927
kono
parents:
diff changeset
928 args_size = cur_trace->end_true_args_size;
kono
parents:
diff changeset
929 if (cur_trace->eh_head == NULL)
kono
parents:
diff changeset
930 {
kono
parents:
diff changeset
931 cur_trace->eh_head = insn;
kono
parents:
diff changeset
932 cur_trace->beg_delay_args_size = args_size;
kono
parents:
diff changeset
933 cur_trace->end_delay_args_size = args_size;
kono
parents:
diff changeset
934 }
kono
parents:
diff changeset
935 else if (cur_trace->end_delay_args_size != args_size)
kono
parents:
diff changeset
936 {
kono
parents:
diff changeset
937 cur_trace->end_delay_args_size = args_size;
kono
parents:
diff changeset
938
kono
parents:
diff changeset
939 /* ??? If the CFA is the stack pointer, search backward for the last
kono
parents:
diff changeset
940 CFI note and insert there. Given that the stack changed for the
kono
parents:
diff changeset
941 args_size change, there *must* be such a note in between here and
kono
parents:
diff changeset
942 the last eh insn. */
kono
parents:
diff changeset
943 add_cfi_args_size (args_size);
kono
parents:
diff changeset
944 }
kono
parents:
diff changeset
945 }
kono
parents:
diff changeset
946
kono
parents:
diff changeset
947 /* Short-hand inline for the very common D_F_R (REGNO (x)) operation. */
kono
parents:
diff changeset
948 /* ??? This ought to go into dwarf2out.h, except that dwarf2out.h is
kono
parents:
diff changeset
949 used in places where rtl is prohibited. */
kono
parents:
diff changeset
950
kono
parents:
diff changeset
951 static inline unsigned
kono
parents:
diff changeset
952 dwf_regno (const_rtx reg)
kono
parents:
diff changeset
953 {
kono
parents:
diff changeset
954 gcc_assert (REGNO (reg) < FIRST_PSEUDO_REGISTER);
kono
parents:
diff changeset
955 return DWARF_FRAME_REGNUM (REGNO (reg));
kono
parents:
diff changeset
956 }
kono
parents:
diff changeset
957
kono
parents:
diff changeset
958 /* Compare X and Y for equivalence. The inputs may be REGs or PC_RTX. */
kono
parents:
diff changeset
959
kono
parents:
diff changeset
960 static bool
kono
parents:
diff changeset
961 compare_reg_or_pc (rtx x, rtx y)
kono
parents:
diff changeset
962 {
kono
parents:
diff changeset
963 if (REG_P (x) && REG_P (y))
kono
parents:
diff changeset
964 return REGNO (x) == REGNO (y);
kono
parents:
diff changeset
965 return x == y;
kono
parents:
diff changeset
966 }
kono
parents:
diff changeset
967
kono
parents:
diff changeset
968 /* Record SRC as being saved in DEST. DEST may be null to delete an
kono
parents:
diff changeset
969 existing entry. SRC may be a register or PC_RTX. */
kono
parents:
diff changeset
970
kono
parents:
diff changeset
971 static void
kono
parents:
diff changeset
972 record_reg_saved_in_reg (rtx dest, rtx src)
kono
parents:
diff changeset
973 {
kono
parents:
diff changeset
974 reg_saved_in_data *elt;
kono
parents:
diff changeset
975 size_t i;
kono
parents:
diff changeset
976
kono
parents:
diff changeset
977 FOR_EACH_VEC_ELT (cur_trace->regs_saved_in_regs, i, elt)
kono
parents:
diff changeset
978 if (compare_reg_or_pc (elt->orig_reg, src))
kono
parents:
diff changeset
979 {
kono
parents:
diff changeset
980 if (dest == NULL)
kono
parents:
diff changeset
981 cur_trace->regs_saved_in_regs.unordered_remove (i);
kono
parents:
diff changeset
982 else
kono
parents:
diff changeset
983 elt->saved_in_reg = dest;
kono
parents:
diff changeset
984 return;
kono
parents:
diff changeset
985 }
kono
parents:
diff changeset
986
kono
parents:
diff changeset
987 if (dest == NULL)
kono
parents:
diff changeset
988 return;
kono
parents:
diff changeset
989
kono
parents:
diff changeset
990 reg_saved_in_data e = {src, dest};
kono
parents:
diff changeset
991 cur_trace->regs_saved_in_regs.safe_push (e);
kono
parents:
diff changeset
992 }
kono
parents:
diff changeset
993
kono
parents:
diff changeset
994 /* Add an entry to QUEUED_REG_SAVES saying that REG is now saved at
kono
parents:
diff changeset
995 SREG, or if SREG is NULL then it is saved at OFFSET to the CFA. */
kono
parents:
diff changeset
996
kono
parents:
diff changeset
997 static void
kono
parents:
diff changeset
998 queue_reg_save (rtx reg, rtx sreg, HOST_WIDE_INT offset)
kono
parents:
diff changeset
999 {
kono
parents:
diff changeset
1000 queued_reg_save *q;
kono
parents:
diff changeset
1001 queued_reg_save e = {reg, sreg, offset};
kono
parents:
diff changeset
1002 size_t i;
kono
parents:
diff changeset
1003
kono
parents:
diff changeset
1004 /* Duplicates waste space, but it's also necessary to remove them
kono
parents:
diff changeset
1005 for correctness, since the queue gets output in reverse order. */
kono
parents:
diff changeset
1006 FOR_EACH_VEC_ELT (queued_reg_saves, i, q)
kono
parents:
diff changeset
1007 if (compare_reg_or_pc (q->reg, reg))
kono
parents:
diff changeset
1008 {
kono
parents:
diff changeset
1009 *q = e;
kono
parents:
diff changeset
1010 return;
kono
parents:
diff changeset
1011 }
kono
parents:
diff changeset
1012
kono
parents:
diff changeset
1013 queued_reg_saves.safe_push (e);
kono
parents:
diff changeset
1014 }
kono
parents:
diff changeset
1015
kono
parents:
diff changeset
1016 /* Output all the entries in QUEUED_REG_SAVES. */
kono
parents:
diff changeset
1017
kono
parents:
diff changeset
1018 static void
kono
parents:
diff changeset
1019 dwarf2out_flush_queued_reg_saves (void)
kono
parents:
diff changeset
1020 {
kono
parents:
diff changeset
1021 queued_reg_save *q;
kono
parents:
diff changeset
1022 size_t i;
kono
parents:
diff changeset
1023
kono
parents:
diff changeset
1024 FOR_EACH_VEC_ELT (queued_reg_saves, i, q)
kono
parents:
diff changeset
1025 {
kono
parents:
diff changeset
1026 unsigned int reg, sreg;
kono
parents:
diff changeset
1027
kono
parents:
diff changeset
1028 record_reg_saved_in_reg (q->saved_reg, q->reg);
kono
parents:
diff changeset
1029
kono
parents:
diff changeset
1030 if (q->reg == pc_rtx)
kono
parents:
diff changeset
1031 reg = DWARF_FRAME_RETURN_COLUMN;
kono
parents:
diff changeset
1032 else
kono
parents:
diff changeset
1033 reg = dwf_regno (q->reg);
kono
parents:
diff changeset
1034 if (q->saved_reg)
kono
parents:
diff changeset
1035 sreg = dwf_regno (q->saved_reg);
kono
parents:
diff changeset
1036 else
kono
parents:
diff changeset
1037 sreg = INVALID_REGNUM;
kono
parents:
diff changeset
1038 reg_save (reg, sreg, q->cfa_offset);
kono
parents:
diff changeset
1039 }
kono
parents:
diff changeset
1040
kono
parents:
diff changeset
1041 queued_reg_saves.truncate (0);
kono
parents:
diff changeset
1042 }
kono
parents:
diff changeset
1043
kono
parents:
diff changeset
1044 /* Does INSN clobber any register which QUEUED_REG_SAVES lists a saved
kono
parents:
diff changeset
1045 location for? Or, does it clobber a register which we've previously
kono
parents:
diff changeset
1046 said that some other register is saved in, and for which we now
kono
parents:
diff changeset
1047 have a new location for? */
kono
parents:
diff changeset
1048
kono
parents:
diff changeset
1049 static bool
kono
parents:
diff changeset
1050 clobbers_queued_reg_save (const_rtx insn)
kono
parents:
diff changeset
1051 {
kono
parents:
diff changeset
1052 queued_reg_save *q;
kono
parents:
diff changeset
1053 size_t iq;
kono
parents:
diff changeset
1054
kono
parents:
diff changeset
1055 FOR_EACH_VEC_ELT (queued_reg_saves, iq, q)
kono
parents:
diff changeset
1056 {
kono
parents:
diff changeset
1057 size_t ir;
kono
parents:
diff changeset
1058 reg_saved_in_data *rir;
kono
parents:
diff changeset
1059
kono
parents:
diff changeset
1060 if (modified_in_p (q->reg, insn))
kono
parents:
diff changeset
1061 return true;
kono
parents:
diff changeset
1062
kono
parents:
diff changeset
1063 FOR_EACH_VEC_ELT (cur_trace->regs_saved_in_regs, ir, rir)
kono
parents:
diff changeset
1064 if (compare_reg_or_pc (q->reg, rir->orig_reg)
kono
parents:
diff changeset
1065 && modified_in_p (rir->saved_in_reg, insn))
kono
parents:
diff changeset
1066 return true;
kono
parents:
diff changeset
1067 }
kono
parents:
diff changeset
1068
kono
parents:
diff changeset
1069 return false;
kono
parents:
diff changeset
1070 }
kono
parents:
diff changeset
1071
kono
parents:
diff changeset
1072 /* What register, if any, is currently saved in REG? */
kono
parents:
diff changeset
1073
kono
parents:
diff changeset
1074 static rtx
kono
parents:
diff changeset
1075 reg_saved_in (rtx reg)
kono
parents:
diff changeset
1076 {
kono
parents:
diff changeset
1077 unsigned int regn = REGNO (reg);
kono
parents:
diff changeset
1078 queued_reg_save *q;
kono
parents:
diff changeset
1079 reg_saved_in_data *rir;
kono
parents:
diff changeset
1080 size_t i;
kono
parents:
diff changeset
1081
kono
parents:
diff changeset
1082 FOR_EACH_VEC_ELT (queued_reg_saves, i, q)
kono
parents:
diff changeset
1083 if (q->saved_reg && regn == REGNO (q->saved_reg))
kono
parents:
diff changeset
1084 return q->reg;
kono
parents:
diff changeset
1085
kono
parents:
diff changeset
1086 FOR_EACH_VEC_ELT (cur_trace->regs_saved_in_regs, i, rir)
kono
parents:
diff changeset
1087 if (regn == REGNO (rir->saved_in_reg))
kono
parents:
diff changeset
1088 return rir->orig_reg;
kono
parents:
diff changeset
1089
kono
parents:
diff changeset
1090 return NULL_RTX;
kono
parents:
diff changeset
1091 }
kono
parents:
diff changeset
1092
kono
parents:
diff changeset
1093 /* A subroutine of dwarf2out_frame_debug, process a REG_DEF_CFA note. */
kono
parents:
diff changeset
1094
kono
parents:
diff changeset
1095 static void
kono
parents:
diff changeset
1096 dwarf2out_frame_debug_def_cfa (rtx pat)
kono
parents:
diff changeset
1097 {
kono
parents:
diff changeset
1098 memset (cur_cfa, 0, sizeof (*cur_cfa));
kono
parents:
diff changeset
1099
kono
parents:
diff changeset
1100 if (GET_CODE (pat) == PLUS)
kono
parents:
diff changeset
1101 {
kono
parents:
diff changeset
1102 cur_cfa->offset = INTVAL (XEXP (pat, 1));
kono
parents:
diff changeset
1103 pat = XEXP (pat, 0);
kono
parents:
diff changeset
1104 }
kono
parents:
diff changeset
1105 if (MEM_P (pat))
kono
parents:
diff changeset
1106 {
kono
parents:
diff changeset
1107 cur_cfa->indirect = 1;
kono
parents:
diff changeset
1108 pat = XEXP (pat, 0);
kono
parents:
diff changeset
1109 if (GET_CODE (pat) == PLUS)
kono
parents:
diff changeset
1110 {
kono
parents:
diff changeset
1111 cur_cfa->base_offset = INTVAL (XEXP (pat, 1));
kono
parents:
diff changeset
1112 pat = XEXP (pat, 0);
kono
parents:
diff changeset
1113 }
kono
parents:
diff changeset
1114 }
kono
parents:
diff changeset
1115 /* ??? If this fails, we could be calling into the _loc functions to
kono
parents:
diff changeset
1116 define a full expression. So far no port does that. */
kono
parents:
diff changeset
1117 gcc_assert (REG_P (pat));
kono
parents:
diff changeset
1118 cur_cfa->reg = dwf_regno (pat);
kono
parents:
diff changeset
1119 }
kono
parents:
diff changeset
1120
kono
parents:
diff changeset
1121 /* A subroutine of dwarf2out_frame_debug, process a REG_ADJUST_CFA note. */
kono
parents:
diff changeset
1122
kono
parents:
diff changeset
1123 static void
kono
parents:
diff changeset
1124 dwarf2out_frame_debug_adjust_cfa (rtx pat)
kono
parents:
diff changeset
1125 {
kono
parents:
diff changeset
1126 rtx src, dest;
kono
parents:
diff changeset
1127
kono
parents:
diff changeset
1128 gcc_assert (GET_CODE (pat) == SET);
kono
parents:
diff changeset
1129 dest = XEXP (pat, 0);
kono
parents:
diff changeset
1130 src = XEXP (pat, 1);
kono
parents:
diff changeset
1131
kono
parents:
diff changeset
1132 switch (GET_CODE (src))
kono
parents:
diff changeset
1133 {
kono
parents:
diff changeset
1134 case PLUS:
kono
parents:
diff changeset
1135 gcc_assert (dwf_regno (XEXP (src, 0)) == cur_cfa->reg);
kono
parents:
diff changeset
1136 cur_cfa->offset -= INTVAL (XEXP (src, 1));
kono
parents:
diff changeset
1137 break;
kono
parents:
diff changeset
1138
kono
parents:
diff changeset
1139 case REG:
kono
parents:
diff changeset
1140 break;
kono
parents:
diff changeset
1141
kono
parents:
diff changeset
1142 default:
kono
parents:
diff changeset
1143 gcc_unreachable ();
kono
parents:
diff changeset
1144 }
kono
parents:
diff changeset
1145
kono
parents:
diff changeset
1146 cur_cfa->reg = dwf_regno (dest);
kono
parents:
diff changeset
1147 gcc_assert (cur_cfa->indirect == 0);
kono
parents:
diff changeset
1148 }
kono
parents:
diff changeset
1149
kono
parents:
diff changeset
1150 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_OFFSET note. */
kono
parents:
diff changeset
1151
kono
parents:
diff changeset
1152 static void
kono
parents:
diff changeset
1153 dwarf2out_frame_debug_cfa_offset (rtx set)
kono
parents:
diff changeset
1154 {
kono
parents:
diff changeset
1155 HOST_WIDE_INT offset;
kono
parents:
diff changeset
1156 rtx src, addr, span;
kono
parents:
diff changeset
1157 unsigned int sregno;
kono
parents:
diff changeset
1158
kono
parents:
diff changeset
1159 src = XEXP (set, 1);
kono
parents:
diff changeset
1160 addr = XEXP (set, 0);
kono
parents:
diff changeset
1161 gcc_assert (MEM_P (addr));
kono
parents:
diff changeset
1162 addr = XEXP (addr, 0);
kono
parents:
diff changeset
1163
kono
parents:
diff changeset
1164 /* As documented, only consider extremely simple addresses. */
kono
parents:
diff changeset
1165 switch (GET_CODE (addr))
kono
parents:
diff changeset
1166 {
kono
parents:
diff changeset
1167 case REG:
kono
parents:
diff changeset
1168 gcc_assert (dwf_regno (addr) == cur_cfa->reg);
kono
parents:
diff changeset
1169 offset = -cur_cfa->offset;
kono
parents:
diff changeset
1170 break;
kono
parents:
diff changeset
1171 case PLUS:
kono
parents:
diff changeset
1172 gcc_assert (dwf_regno (XEXP (addr, 0)) == cur_cfa->reg);
kono
parents:
diff changeset
1173 offset = INTVAL (XEXP (addr, 1)) - cur_cfa->offset;
kono
parents:
diff changeset
1174 break;
kono
parents:
diff changeset
1175 default:
kono
parents:
diff changeset
1176 gcc_unreachable ();
kono
parents:
diff changeset
1177 }
kono
parents:
diff changeset
1178
kono
parents:
diff changeset
1179 if (src == pc_rtx)
kono
parents:
diff changeset
1180 {
kono
parents:
diff changeset
1181 span = NULL;
kono
parents:
diff changeset
1182 sregno = DWARF_FRAME_RETURN_COLUMN;
kono
parents:
diff changeset
1183 }
kono
parents:
diff changeset
1184 else
kono
parents:
diff changeset
1185 {
kono
parents:
diff changeset
1186 span = targetm.dwarf_register_span (src);
kono
parents:
diff changeset
1187 sregno = dwf_regno (src);
kono
parents:
diff changeset
1188 }
kono
parents:
diff changeset
1189
kono
parents:
diff changeset
1190 /* ??? We'd like to use queue_reg_save, but we need to come up with
kono
parents:
diff changeset
1191 a different flushing heuristic for epilogues. */
kono
parents:
diff changeset
1192 if (!span)
kono
parents:
diff changeset
1193 reg_save (sregno, INVALID_REGNUM, offset);
kono
parents:
diff changeset
1194 else
kono
parents:
diff changeset
1195 {
kono
parents:
diff changeset
1196 /* We have a PARALLEL describing where the contents of SRC live.
kono
parents:
diff changeset
1197 Adjust the offset for each piece of the PARALLEL. */
kono
parents:
diff changeset
1198 HOST_WIDE_INT span_offset = offset;
kono
parents:
diff changeset
1199
kono
parents:
diff changeset
1200 gcc_assert (GET_CODE (span) == PARALLEL);
kono
parents:
diff changeset
1201
kono
parents:
diff changeset
1202 const int par_len = XVECLEN (span, 0);
kono
parents:
diff changeset
1203 for (int par_index = 0; par_index < par_len; par_index++)
kono
parents:
diff changeset
1204 {
kono
parents:
diff changeset
1205 rtx elem = XVECEXP (span, 0, par_index);
kono
parents:
diff changeset
1206 sregno = dwf_regno (src);
kono
parents:
diff changeset
1207 reg_save (sregno, INVALID_REGNUM, span_offset);
kono
parents:
diff changeset
1208 span_offset += GET_MODE_SIZE (GET_MODE (elem));
kono
parents:
diff changeset
1209 }
kono
parents:
diff changeset
1210 }
kono
parents:
diff changeset
1211 }
kono
parents:
diff changeset
1212
kono
parents:
diff changeset
1213 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_REGISTER note. */
kono
parents:
diff changeset
1214
kono
parents:
diff changeset
1215 static void
kono
parents:
diff changeset
1216 dwarf2out_frame_debug_cfa_register (rtx set)
kono
parents:
diff changeset
1217 {
kono
parents:
diff changeset
1218 rtx src, dest;
kono
parents:
diff changeset
1219 unsigned sregno, dregno;
kono
parents:
diff changeset
1220
kono
parents:
diff changeset
1221 src = XEXP (set, 1);
kono
parents:
diff changeset
1222 dest = XEXP (set, 0);
kono
parents:
diff changeset
1223
kono
parents:
diff changeset
1224 record_reg_saved_in_reg (dest, src);
kono
parents:
diff changeset
1225 if (src == pc_rtx)
kono
parents:
diff changeset
1226 sregno = DWARF_FRAME_RETURN_COLUMN;
kono
parents:
diff changeset
1227 else
kono
parents:
diff changeset
1228 sregno = dwf_regno (src);
kono
parents:
diff changeset
1229
kono
parents:
diff changeset
1230 dregno = dwf_regno (dest);
kono
parents:
diff changeset
1231
kono
parents:
diff changeset
1232 /* ??? We'd like to use queue_reg_save, but we need to come up with
kono
parents:
diff changeset
1233 a different flushing heuristic for epilogues. */
kono
parents:
diff changeset
1234 reg_save (sregno, dregno, 0);
kono
parents:
diff changeset
1235 }
kono
parents:
diff changeset
1236
kono
parents:
diff changeset
1237 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_EXPRESSION note. */
kono
parents:
diff changeset
1238
kono
parents:
diff changeset
1239 static void
kono
parents:
diff changeset
1240 dwarf2out_frame_debug_cfa_expression (rtx set)
kono
parents:
diff changeset
1241 {
kono
parents:
diff changeset
1242 rtx src, dest, span;
kono
parents:
diff changeset
1243 dw_cfi_ref cfi = new_cfi ();
kono
parents:
diff changeset
1244 unsigned regno;
kono
parents:
diff changeset
1245
kono
parents:
diff changeset
1246 dest = SET_DEST (set);
kono
parents:
diff changeset
1247 src = SET_SRC (set);
kono
parents:
diff changeset
1248
kono
parents:
diff changeset
1249 gcc_assert (REG_P (src));
kono
parents:
diff changeset
1250 gcc_assert (MEM_P (dest));
kono
parents:
diff changeset
1251
kono
parents:
diff changeset
1252 span = targetm.dwarf_register_span (src);
kono
parents:
diff changeset
1253 gcc_assert (!span);
kono
parents:
diff changeset
1254
kono
parents:
diff changeset
1255 regno = dwf_regno (src);
kono
parents:
diff changeset
1256
kono
parents:
diff changeset
1257 cfi->dw_cfi_opc = DW_CFA_expression;
kono
parents:
diff changeset
1258 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = regno;
kono
parents:
diff changeset
1259 cfi->dw_cfi_oprnd2.dw_cfi_loc
kono
parents:
diff changeset
1260 = mem_loc_descriptor (XEXP (dest, 0), get_address_mode (dest),
kono
parents:
diff changeset
1261 GET_MODE (dest), VAR_INIT_STATUS_INITIALIZED);
kono
parents:
diff changeset
1262
kono
parents:
diff changeset
1263 /* ??? We'd like to use queue_reg_save, were the interface different,
kono
parents:
diff changeset
1264 and, as above, we could manage flushing for epilogues. */
kono
parents:
diff changeset
1265 add_cfi (cfi);
kono
parents:
diff changeset
1266 update_row_reg_save (cur_row, regno, cfi);
kono
parents:
diff changeset
1267 }
kono
parents:
diff changeset
1268
kono
parents:
diff changeset
1269 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_VAL_EXPRESSION
kono
parents:
diff changeset
1270 note. */
kono
parents:
diff changeset
1271
kono
parents:
diff changeset
1272 static void
kono
parents:
diff changeset
1273 dwarf2out_frame_debug_cfa_val_expression (rtx set)
kono
parents:
diff changeset
1274 {
kono
parents:
diff changeset
1275 rtx dest = SET_DEST (set);
kono
parents:
diff changeset
1276 gcc_assert (REG_P (dest));
kono
parents:
diff changeset
1277
kono
parents:
diff changeset
1278 rtx span = targetm.dwarf_register_span (dest);
kono
parents:
diff changeset
1279 gcc_assert (!span);
kono
parents:
diff changeset
1280
kono
parents:
diff changeset
1281 rtx src = SET_SRC (set);
kono
parents:
diff changeset
1282 dw_cfi_ref cfi = new_cfi ();
kono
parents:
diff changeset
1283 cfi->dw_cfi_opc = DW_CFA_val_expression;
kono
parents:
diff changeset
1284 cfi->dw_cfi_oprnd1.dw_cfi_reg_num = dwf_regno (dest);
kono
parents:
diff changeset
1285 cfi->dw_cfi_oprnd2.dw_cfi_loc
kono
parents:
diff changeset
1286 = mem_loc_descriptor (src, GET_MODE (src),
kono
parents:
diff changeset
1287 GET_MODE (dest), VAR_INIT_STATUS_INITIALIZED);
kono
parents:
diff changeset
1288 add_cfi (cfi);
kono
parents:
diff changeset
1289 update_row_reg_save (cur_row, dwf_regno (dest), cfi);
kono
parents:
diff changeset
1290 }
kono
parents:
diff changeset
1291
kono
parents:
diff changeset
1292 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_RESTORE note. */
kono
parents:
diff changeset
1293
kono
parents:
diff changeset
1294 static void
kono
parents:
diff changeset
1295 dwarf2out_frame_debug_cfa_restore (rtx reg)
kono
parents:
diff changeset
1296 {
kono
parents:
diff changeset
1297 gcc_assert (REG_P (reg));
kono
parents:
diff changeset
1298
kono
parents:
diff changeset
1299 rtx span = targetm.dwarf_register_span (reg);
kono
parents:
diff changeset
1300 if (!span)
kono
parents:
diff changeset
1301 {
kono
parents:
diff changeset
1302 unsigned int regno = dwf_regno (reg);
kono
parents:
diff changeset
1303 add_cfi_restore (regno);
kono
parents:
diff changeset
1304 update_row_reg_save (cur_row, regno, NULL);
kono
parents:
diff changeset
1305 }
kono
parents:
diff changeset
1306 else
kono
parents:
diff changeset
1307 {
kono
parents:
diff changeset
1308 /* We have a PARALLEL describing where the contents of REG live.
kono
parents:
diff changeset
1309 Restore the register for each piece of the PARALLEL. */
kono
parents:
diff changeset
1310 gcc_assert (GET_CODE (span) == PARALLEL);
kono
parents:
diff changeset
1311
kono
parents:
diff changeset
1312 const int par_len = XVECLEN (span, 0);
kono
parents:
diff changeset
1313 for (int par_index = 0; par_index < par_len; par_index++)
kono
parents:
diff changeset
1314 {
kono
parents:
diff changeset
1315 reg = XVECEXP (span, 0, par_index);
kono
parents:
diff changeset
1316 gcc_assert (REG_P (reg));
kono
parents:
diff changeset
1317 unsigned int regno = dwf_regno (reg);
kono
parents:
diff changeset
1318 add_cfi_restore (regno);
kono
parents:
diff changeset
1319 update_row_reg_save (cur_row, regno, NULL);
kono
parents:
diff changeset
1320 }
kono
parents:
diff changeset
1321 }
kono
parents:
diff changeset
1322 }
kono
parents:
diff changeset
1323
kono
parents:
diff changeset
1324 /* A subroutine of dwarf2out_frame_debug, process a REG_CFA_WINDOW_SAVE.
kono
parents:
diff changeset
1325 ??? Perhaps we should note in the CIE where windows are saved (instead of
kono
parents:
diff changeset
1326 assuming 0(cfa)) and what registers are in the window. */
kono
parents:
diff changeset
1327
kono
parents:
diff changeset
1328 static void
kono
parents:
diff changeset
1329 dwarf2out_frame_debug_cfa_window_save (void)
kono
parents:
diff changeset
1330 {
kono
parents:
diff changeset
1331 dw_cfi_ref cfi = new_cfi ();
kono
parents:
diff changeset
1332
kono
parents:
diff changeset
1333 cfi->dw_cfi_opc = DW_CFA_GNU_window_save;
kono
parents:
diff changeset
1334 add_cfi (cfi);
kono
parents:
diff changeset
1335 }
kono
parents:
diff changeset
1336
kono
parents:
diff changeset
1337 /* Record call frame debugging information for an expression EXPR,
kono
parents:
diff changeset
1338 which either sets SP or FP (adjusting how we calculate the frame
kono
parents:
diff changeset
1339 address) or saves a register to the stack or another register.
kono
parents:
diff changeset
1340 LABEL indicates the address of EXPR.
kono
parents:
diff changeset
1341
kono
parents:
diff changeset
1342 This function encodes a state machine mapping rtxes to actions on
kono
parents:
diff changeset
1343 cfa, cfa_store, and cfa_temp.reg. We describe these rules so
kono
parents:
diff changeset
1344 users need not read the source code.
kono
parents:
diff changeset
1345
kono
parents:
diff changeset
1346 The High-Level Picture
kono
parents:
diff changeset
1347
kono
parents:
diff changeset
1348 Changes in the register we use to calculate the CFA: Currently we
kono
parents:
diff changeset
1349 assume that if you copy the CFA register into another register, we
kono
parents:
diff changeset
1350 should take the other one as the new CFA register; this seems to
kono
parents:
diff changeset
1351 work pretty well. If it's wrong for some target, it's simple
kono
parents:
diff changeset
1352 enough not to set RTX_FRAME_RELATED_P on the insn in question.
kono
parents:
diff changeset
1353
kono
parents:
diff changeset
1354 Changes in the register we use for saving registers to the stack:
kono
parents:
diff changeset
1355 This is usually SP, but not always. Again, we deduce that if you
kono
parents:
diff changeset
1356 copy SP into another register (and SP is not the CFA register),
kono
parents:
diff changeset
1357 then the new register is the one we will be using for register
kono
parents:
diff changeset
1358 saves. This also seems to work.
kono
parents:
diff changeset
1359
kono
parents:
diff changeset
1360 Register saves: There's not much guesswork about this one; if
kono
parents:
diff changeset
1361 RTX_FRAME_RELATED_P is set on an insn which modifies memory, it's a
kono
parents:
diff changeset
1362 register save, and the register used to calculate the destination
kono
parents:
diff changeset
1363 had better be the one we think we're using for this purpose.
kono
parents:
diff changeset
1364 It's also assumed that a copy from a call-saved register to another
kono
parents:
diff changeset
1365 register is saving that register if RTX_FRAME_RELATED_P is set on
kono
parents:
diff changeset
1366 that instruction. If the copy is from a call-saved register to
kono
parents:
diff changeset
1367 the *same* register, that means that the register is now the same
kono
parents:
diff changeset
1368 value as in the caller.
kono
parents:
diff changeset
1369
kono
parents:
diff changeset
1370 Except: If the register being saved is the CFA register, and the
kono
parents:
diff changeset
1371 offset is nonzero, we are saving the CFA, so we assume we have to
kono
parents:
diff changeset
1372 use DW_CFA_def_cfa_expression. If the offset is 0, we assume that
kono
parents:
diff changeset
1373 the intent is to save the value of SP from the previous frame.
kono
parents:
diff changeset
1374
kono
parents:
diff changeset
1375 In addition, if a register has previously been saved to a different
kono
parents:
diff changeset
1376 register,
kono
parents:
diff changeset
1377
kono
parents:
diff changeset
1378 Invariants / Summaries of Rules
kono
parents:
diff changeset
1379
kono
parents:
diff changeset
1380 cfa current rule for calculating the CFA. It usually
kono
parents:
diff changeset
1381 consists of a register and an offset. This is
kono
parents:
diff changeset
1382 actually stored in *cur_cfa, but abbreviated
kono
parents:
diff changeset
1383 for the purposes of this documentation.
kono
parents:
diff changeset
1384 cfa_store register used by prologue code to save things to the stack
kono
parents:
diff changeset
1385 cfa_store.offset is the offset from the value of
kono
parents:
diff changeset
1386 cfa_store.reg to the actual CFA
kono
parents:
diff changeset
1387 cfa_temp register holding an integral value. cfa_temp.offset
kono
parents:
diff changeset
1388 stores the value, which will be used to adjust the
kono
parents:
diff changeset
1389 stack pointer. cfa_temp is also used like cfa_store,
kono
parents:
diff changeset
1390 to track stores to the stack via fp or a temp reg.
kono
parents:
diff changeset
1391
kono
parents:
diff changeset
1392 Rules 1- 4: Setting a register's value to cfa.reg or an expression
kono
parents:
diff changeset
1393 with cfa.reg as the first operand changes the cfa.reg and its
kono
parents:
diff changeset
1394 cfa.offset. Rule 1 and 4 also set cfa_temp.reg and
kono
parents:
diff changeset
1395 cfa_temp.offset.
kono
parents:
diff changeset
1396
kono
parents:
diff changeset
1397 Rules 6- 9: Set a non-cfa.reg register value to a constant or an
kono
parents:
diff changeset
1398 expression yielding a constant. This sets cfa_temp.reg
kono
parents:
diff changeset
1399 and cfa_temp.offset.
kono
parents:
diff changeset
1400
kono
parents:
diff changeset
1401 Rule 5: Create a new register cfa_store used to save items to the
kono
parents:
diff changeset
1402 stack.
kono
parents:
diff changeset
1403
kono
parents:
diff changeset
1404 Rules 10-14: Save a register to the stack. Define offset as the
kono
parents:
diff changeset
1405 difference of the original location and cfa_store's
kono
parents:
diff changeset
1406 location (or cfa_temp's location if cfa_temp is used).
kono
parents:
diff changeset
1407
kono
parents:
diff changeset
1408 Rules 16-20: If AND operation happens on sp in prologue, we assume
kono
parents:
diff changeset
1409 stack is realigned. We will use a group of DW_OP_XXX
kono
parents:
diff changeset
1410 expressions to represent the location of the stored
kono
parents:
diff changeset
1411 register instead of CFA+offset.
kono
parents:
diff changeset
1412
kono
parents:
diff changeset
1413 The Rules
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 "{a,b}" indicates a choice of a xor b.
kono
parents:
diff changeset
1416 "<reg>:cfa.reg" indicates that <reg> must equal cfa.reg.
kono
parents:
diff changeset
1417
kono
parents:
diff changeset
1418 Rule 1:
kono
parents:
diff changeset
1419 (set <reg1> <reg2>:cfa.reg)
kono
parents:
diff changeset
1420 effects: cfa.reg = <reg1>
kono
parents:
diff changeset
1421 cfa.offset unchanged
kono
parents:
diff changeset
1422 cfa_temp.reg = <reg1>
kono
parents:
diff changeset
1423 cfa_temp.offset = cfa.offset
kono
parents:
diff changeset
1424
kono
parents:
diff changeset
1425 Rule 2:
kono
parents:
diff changeset
1426 (set sp ({minus,plus,losum} {sp,fp}:cfa.reg
kono
parents:
diff changeset
1427 {<const_int>,<reg>:cfa_temp.reg}))
kono
parents:
diff changeset
1428 effects: cfa.reg = sp if fp used
kono
parents:
diff changeset
1429 cfa.offset += {+/- <const_int>, cfa_temp.offset} if cfa.reg==sp
kono
parents:
diff changeset
1430 cfa_store.offset += {+/- <const_int>, cfa_temp.offset}
kono
parents:
diff changeset
1431 if cfa_store.reg==sp
kono
parents:
diff changeset
1432
kono
parents:
diff changeset
1433 Rule 3:
kono
parents:
diff changeset
1434 (set fp ({minus,plus,losum} <reg>:cfa.reg <const_int>))
kono
parents:
diff changeset
1435 effects: cfa.reg = fp
kono
parents:
diff changeset
1436 cfa_offset += +/- <const_int>
kono
parents:
diff changeset
1437
kono
parents:
diff changeset
1438 Rule 4:
kono
parents:
diff changeset
1439 (set <reg1> ({plus,losum} <reg2>:cfa.reg <const_int>))
kono
parents:
diff changeset
1440 constraints: <reg1> != fp
kono
parents:
diff changeset
1441 <reg1> != sp
kono
parents:
diff changeset
1442 effects: cfa.reg = <reg1>
kono
parents:
diff changeset
1443 cfa_temp.reg = <reg1>
kono
parents:
diff changeset
1444 cfa_temp.offset = cfa.offset
kono
parents:
diff changeset
1445
kono
parents:
diff changeset
1446 Rule 5:
kono
parents:
diff changeset
1447 (set <reg1> (plus <reg2>:cfa_temp.reg sp:cfa.reg))
kono
parents:
diff changeset
1448 constraints: <reg1> != fp
kono
parents:
diff changeset
1449 <reg1> != sp
kono
parents:
diff changeset
1450 effects: cfa_store.reg = <reg1>
kono
parents:
diff changeset
1451 cfa_store.offset = cfa.offset - cfa_temp.offset
kono
parents:
diff changeset
1452
kono
parents:
diff changeset
1453 Rule 6:
kono
parents:
diff changeset
1454 (set <reg> <const_int>)
kono
parents:
diff changeset
1455 effects: cfa_temp.reg = <reg>
kono
parents:
diff changeset
1456 cfa_temp.offset = <const_int>
kono
parents:
diff changeset
1457
kono
parents:
diff changeset
1458 Rule 7:
kono
parents:
diff changeset
1459 (set <reg1>:cfa_temp.reg (ior <reg2>:cfa_temp.reg <const_int>))
kono
parents:
diff changeset
1460 effects: cfa_temp.reg = <reg1>
kono
parents:
diff changeset
1461 cfa_temp.offset |= <const_int>
kono
parents:
diff changeset
1462
kono
parents:
diff changeset
1463 Rule 8:
kono
parents:
diff changeset
1464 (set <reg> (high <exp>))
kono
parents:
diff changeset
1465 effects: none
kono
parents:
diff changeset
1466
kono
parents:
diff changeset
1467 Rule 9:
kono
parents:
diff changeset
1468 (set <reg> (lo_sum <exp> <const_int>))
kono
parents:
diff changeset
1469 effects: cfa_temp.reg = <reg>
kono
parents:
diff changeset
1470 cfa_temp.offset = <const_int>
kono
parents:
diff changeset
1471
kono
parents:
diff changeset
1472 Rule 10:
kono
parents:
diff changeset
1473 (set (mem ({pre,post}_modify sp:cfa_store (???? <reg1> <const_int>))) <reg2>)
kono
parents:
diff changeset
1474 effects: cfa_store.offset -= <const_int>
kono
parents:
diff changeset
1475 cfa.offset = cfa_store.offset if cfa.reg == sp
kono
parents:
diff changeset
1476 cfa.reg = sp
kono
parents:
diff changeset
1477 cfa.base_offset = -cfa_store.offset
kono
parents:
diff changeset
1478
kono
parents:
diff changeset
1479 Rule 11:
kono
parents:
diff changeset
1480 (set (mem ({pre_inc,pre_dec,post_dec} sp:cfa_store.reg)) <reg>)
kono
parents:
diff changeset
1481 effects: cfa_store.offset += -/+ mode_size(mem)
kono
parents:
diff changeset
1482 cfa.offset = cfa_store.offset if cfa.reg == sp
kono
parents:
diff changeset
1483 cfa.reg = sp
kono
parents:
diff changeset
1484 cfa.base_offset = -cfa_store.offset
kono
parents:
diff changeset
1485
kono
parents:
diff changeset
1486 Rule 12:
kono
parents:
diff changeset
1487 (set (mem ({minus,plus,losum} <reg1>:{cfa_store,cfa_temp} <const_int>))
kono
parents:
diff changeset
1488
kono
parents:
diff changeset
1489 <reg2>)
kono
parents:
diff changeset
1490 effects: cfa.reg = <reg1>
kono
parents:
diff changeset
1491 cfa.base_offset = -/+ <const_int> - {cfa_store,cfa_temp}.offset
kono
parents:
diff changeset
1492
kono
parents:
diff changeset
1493 Rule 13:
kono
parents:
diff changeset
1494 (set (mem <reg1>:{cfa_store,cfa_temp}) <reg2>)
kono
parents:
diff changeset
1495 effects: cfa.reg = <reg1>
kono
parents:
diff changeset
1496 cfa.base_offset = -{cfa_store,cfa_temp}.offset
kono
parents:
diff changeset
1497
kono
parents:
diff changeset
1498 Rule 14:
kono
parents:
diff changeset
1499 (set (mem (post_inc <reg1>:cfa_temp <const_int>)) <reg2>)
kono
parents:
diff changeset
1500 effects: cfa.reg = <reg1>
kono
parents:
diff changeset
1501 cfa.base_offset = -cfa_temp.offset
kono
parents:
diff changeset
1502 cfa_temp.offset -= mode_size(mem)
kono
parents:
diff changeset
1503
kono
parents:
diff changeset
1504 Rule 15:
kono
parents:
diff changeset
1505 (set <reg> {unspec, unspec_volatile})
kono
parents:
diff changeset
1506 effects: target-dependent
kono
parents:
diff changeset
1507
kono
parents:
diff changeset
1508 Rule 16:
kono
parents:
diff changeset
1509 (set sp (and: sp <const_int>))
kono
parents:
diff changeset
1510 constraints: cfa_store.reg == sp
kono
parents:
diff changeset
1511 effects: cfun->fde.stack_realign = 1
kono
parents:
diff changeset
1512 cfa_store.offset = 0
kono
parents:
diff changeset
1513 fde->drap_reg = cfa.reg if cfa.reg != sp and cfa.reg != fp
kono
parents:
diff changeset
1514
kono
parents:
diff changeset
1515 Rule 17:
kono
parents:
diff changeset
1516 (set (mem ({pre_inc, pre_dec} sp)) (mem (plus (cfa.reg) (const_int))))
kono
parents:
diff changeset
1517 effects: cfa_store.offset += -/+ mode_size(mem)
kono
parents:
diff changeset
1518
kono
parents:
diff changeset
1519 Rule 18:
kono
parents:
diff changeset
1520 (set (mem ({pre_inc, pre_dec} sp)) fp)
kono
parents:
diff changeset
1521 constraints: fde->stack_realign == 1
kono
parents:
diff changeset
1522 effects: cfa_store.offset = 0
kono
parents:
diff changeset
1523 cfa.reg != HARD_FRAME_POINTER_REGNUM
kono
parents:
diff changeset
1524
kono
parents:
diff changeset
1525 Rule 19:
kono
parents:
diff changeset
1526 (set (mem ({pre_inc, pre_dec} sp)) cfa.reg)
kono
parents:
diff changeset
1527 constraints: fde->stack_realign == 1
kono
parents:
diff changeset
1528 && cfa.offset == 0
kono
parents:
diff changeset
1529 && cfa.indirect == 0
kono
parents:
diff changeset
1530 && cfa.reg != HARD_FRAME_POINTER_REGNUM
kono
parents:
diff changeset
1531 effects: Use DW_CFA_def_cfa_expression to define cfa
kono
parents:
diff changeset
1532 cfa.reg == fde->drap_reg */
kono
parents:
diff changeset
1533
kono
parents:
diff changeset
1534 static void
kono
parents:
diff changeset
1535 dwarf2out_frame_debug_expr (rtx expr)
kono
parents:
diff changeset
1536 {
kono
parents:
diff changeset
1537 rtx src, dest, span;
kono
parents:
diff changeset
1538 HOST_WIDE_INT offset;
kono
parents:
diff changeset
1539 dw_fde_ref fde;
kono
parents:
diff changeset
1540
kono
parents:
diff changeset
1541 /* If RTX_FRAME_RELATED_P is set on a PARALLEL, process each member of
kono
parents:
diff changeset
1542 the PARALLEL independently. The first element is always processed if
kono
parents:
diff changeset
1543 it is a SET. This is for backward compatibility. Other elements
kono
parents:
diff changeset
1544 are processed only if they are SETs and the RTX_FRAME_RELATED_P
kono
parents:
diff changeset
1545 flag is set in them. */
kono
parents:
diff changeset
1546 if (GET_CODE (expr) == PARALLEL || GET_CODE (expr) == SEQUENCE)
kono
parents:
diff changeset
1547 {
kono
parents:
diff changeset
1548 int par_index;
kono
parents:
diff changeset
1549 int limit = XVECLEN (expr, 0);
kono
parents:
diff changeset
1550 rtx elem;
kono
parents:
diff changeset
1551
kono
parents:
diff changeset
1552 /* PARALLELs have strict read-modify-write semantics, so we
kono
parents:
diff changeset
1553 ought to evaluate every rvalue before changing any lvalue.
kono
parents:
diff changeset
1554 It's cumbersome to do that in general, but there's an
kono
parents:
diff changeset
1555 easy approximation that is enough for all current users:
kono
parents:
diff changeset
1556 handle register saves before register assignments. */
kono
parents:
diff changeset
1557 if (GET_CODE (expr) == PARALLEL)
kono
parents:
diff changeset
1558 for (par_index = 0; par_index < limit; par_index++)
kono
parents:
diff changeset
1559 {
kono
parents:
diff changeset
1560 elem = XVECEXP (expr, 0, par_index);
kono
parents:
diff changeset
1561 if (GET_CODE (elem) == SET
kono
parents:
diff changeset
1562 && MEM_P (SET_DEST (elem))
kono
parents:
diff changeset
1563 && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
kono
parents:
diff changeset
1564 dwarf2out_frame_debug_expr (elem);
kono
parents:
diff changeset
1565 }
kono
parents:
diff changeset
1566
kono
parents:
diff changeset
1567 for (par_index = 0; par_index < limit; par_index++)
kono
parents:
diff changeset
1568 {
kono
parents:
diff changeset
1569 elem = XVECEXP (expr, 0, par_index);
kono
parents:
diff changeset
1570 if (GET_CODE (elem) == SET
kono
parents:
diff changeset
1571 && (!MEM_P (SET_DEST (elem)) || GET_CODE (expr) == SEQUENCE)
kono
parents:
diff changeset
1572 && (RTX_FRAME_RELATED_P (elem) || par_index == 0))
kono
parents:
diff changeset
1573 dwarf2out_frame_debug_expr (elem);
kono
parents:
diff changeset
1574 }
kono
parents:
diff changeset
1575 return;
kono
parents:
diff changeset
1576 }
kono
parents:
diff changeset
1577
kono
parents:
diff changeset
1578 gcc_assert (GET_CODE (expr) == SET);
kono
parents:
diff changeset
1579
kono
parents:
diff changeset
1580 src = SET_SRC (expr);
kono
parents:
diff changeset
1581 dest = SET_DEST (expr);
kono
parents:
diff changeset
1582
kono
parents:
diff changeset
1583 if (REG_P (src))
kono
parents:
diff changeset
1584 {
kono
parents:
diff changeset
1585 rtx rsi = reg_saved_in (src);
kono
parents:
diff changeset
1586 if (rsi)
kono
parents:
diff changeset
1587 src = rsi;
kono
parents:
diff changeset
1588 }
kono
parents:
diff changeset
1589
kono
parents:
diff changeset
1590 fde = cfun->fde;
kono
parents:
diff changeset
1591
kono
parents:
diff changeset
1592 switch (GET_CODE (dest))
kono
parents:
diff changeset
1593 {
kono
parents:
diff changeset
1594 case REG:
kono
parents:
diff changeset
1595 switch (GET_CODE (src))
kono
parents:
diff changeset
1596 {
kono
parents:
diff changeset
1597 /* Setting FP from SP. */
kono
parents:
diff changeset
1598 case REG:
kono
parents:
diff changeset
1599 if (cur_cfa->reg == dwf_regno (src))
kono
parents:
diff changeset
1600 {
kono
parents:
diff changeset
1601 /* Rule 1 */
kono
parents:
diff changeset
1602 /* Update the CFA rule wrt SP or FP. Make sure src is
kono
parents:
diff changeset
1603 relative to the current CFA register.
kono
parents:
diff changeset
1604
kono
parents:
diff changeset
1605 We used to require that dest be either SP or FP, but the
kono
parents:
diff changeset
1606 ARM copies SP to a temporary register, and from there to
kono
parents:
diff changeset
1607 FP. So we just rely on the backends to only set
kono
parents:
diff changeset
1608 RTX_FRAME_RELATED_P on appropriate insns. */
kono
parents:
diff changeset
1609 cur_cfa->reg = dwf_regno (dest);
kono
parents:
diff changeset
1610 cur_trace->cfa_temp.reg = cur_cfa->reg;
kono
parents:
diff changeset
1611 cur_trace->cfa_temp.offset = cur_cfa->offset;
kono
parents:
diff changeset
1612 }
kono
parents:
diff changeset
1613 else
kono
parents:
diff changeset
1614 {
kono
parents:
diff changeset
1615 /* Saving a register in a register. */
kono
parents:
diff changeset
1616 gcc_assert (!fixed_regs [REGNO (dest)]
kono
parents:
diff changeset
1617 /* For the SPARC and its register window. */
kono
parents:
diff changeset
1618 || (dwf_regno (src) == DWARF_FRAME_RETURN_COLUMN));
kono
parents:
diff changeset
1619
kono
parents:
diff changeset
1620 /* After stack is aligned, we can only save SP in FP
kono
parents:
diff changeset
1621 if drap register is used. In this case, we have
kono
parents:
diff changeset
1622 to restore stack pointer with the CFA value and we
kono
parents:
diff changeset
1623 don't generate this DWARF information. */
kono
parents:
diff changeset
1624 if (fde
kono
parents:
diff changeset
1625 && fde->stack_realign
kono
parents:
diff changeset
1626 && REGNO (src) == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
1627 gcc_assert (REGNO (dest) == HARD_FRAME_POINTER_REGNUM
kono
parents:
diff changeset
1628 && fde->drap_reg != INVALID_REGNUM
kono
parents:
diff changeset
1629 && cur_cfa->reg != dwf_regno (src));
kono
parents:
diff changeset
1630 else
kono
parents:
diff changeset
1631 queue_reg_save (src, dest, 0);
kono
parents:
diff changeset
1632 }
kono
parents:
diff changeset
1633 break;
kono
parents:
diff changeset
1634
kono
parents:
diff changeset
1635 case PLUS:
kono
parents:
diff changeset
1636 case MINUS:
kono
parents:
diff changeset
1637 case LO_SUM:
kono
parents:
diff changeset
1638 if (dest == stack_pointer_rtx)
kono
parents:
diff changeset
1639 {
kono
parents:
diff changeset
1640 /* Rule 2 */
kono
parents:
diff changeset
1641 /* Adjusting SP. */
kono
parents:
diff changeset
1642 switch (GET_CODE (XEXP (src, 1)))
kono
parents:
diff changeset
1643 {
kono
parents:
diff changeset
1644 case CONST_INT:
kono
parents:
diff changeset
1645 offset = INTVAL (XEXP (src, 1));
kono
parents:
diff changeset
1646 break;
kono
parents:
diff changeset
1647 case REG:
kono
parents:
diff changeset
1648 gcc_assert (dwf_regno (XEXP (src, 1))
kono
parents:
diff changeset
1649 == cur_trace->cfa_temp.reg);
kono
parents:
diff changeset
1650 offset = cur_trace->cfa_temp.offset;
kono
parents:
diff changeset
1651 break;
kono
parents:
diff changeset
1652 default:
kono
parents:
diff changeset
1653 gcc_unreachable ();
kono
parents:
diff changeset
1654 }
kono
parents:
diff changeset
1655
kono
parents:
diff changeset
1656 if (XEXP (src, 0) == hard_frame_pointer_rtx)
kono
parents:
diff changeset
1657 {
kono
parents:
diff changeset
1658 /* Restoring SP from FP in the epilogue. */
kono
parents:
diff changeset
1659 gcc_assert (cur_cfa->reg == dw_frame_pointer_regnum);
kono
parents:
diff changeset
1660 cur_cfa->reg = dw_stack_pointer_regnum;
kono
parents:
diff changeset
1661 }
kono
parents:
diff changeset
1662 else if (GET_CODE (src) == LO_SUM)
kono
parents:
diff changeset
1663 /* Assume we've set the source reg of the LO_SUM from sp. */
kono
parents:
diff changeset
1664 ;
kono
parents:
diff changeset
1665 else
kono
parents:
diff changeset
1666 gcc_assert (XEXP (src, 0) == stack_pointer_rtx);
kono
parents:
diff changeset
1667
kono
parents:
diff changeset
1668 if (GET_CODE (src) != MINUS)
kono
parents:
diff changeset
1669 offset = -offset;
kono
parents:
diff changeset
1670 if (cur_cfa->reg == dw_stack_pointer_regnum)
kono
parents:
diff changeset
1671 cur_cfa->offset += offset;
kono
parents:
diff changeset
1672 if (cur_trace->cfa_store.reg == dw_stack_pointer_regnum)
kono
parents:
diff changeset
1673 cur_trace->cfa_store.offset += offset;
kono
parents:
diff changeset
1674 }
kono
parents:
diff changeset
1675 else if (dest == hard_frame_pointer_rtx)
kono
parents:
diff changeset
1676 {
kono
parents:
diff changeset
1677 /* Rule 3 */
kono
parents:
diff changeset
1678 /* Either setting the FP from an offset of the SP,
kono
parents:
diff changeset
1679 or adjusting the FP */
kono
parents:
diff changeset
1680 gcc_assert (frame_pointer_needed);
kono
parents:
diff changeset
1681
kono
parents:
diff changeset
1682 gcc_assert (REG_P (XEXP (src, 0))
kono
parents:
diff changeset
1683 && dwf_regno (XEXP (src, 0)) == cur_cfa->reg
kono
parents:
diff changeset
1684 && CONST_INT_P (XEXP (src, 1)));
kono
parents:
diff changeset
1685 offset = INTVAL (XEXP (src, 1));
kono
parents:
diff changeset
1686 if (GET_CODE (src) != MINUS)
kono
parents:
diff changeset
1687 offset = -offset;
kono
parents:
diff changeset
1688 cur_cfa->offset += offset;
kono
parents:
diff changeset
1689 cur_cfa->reg = dw_frame_pointer_regnum;
kono
parents:
diff changeset
1690 }
kono
parents:
diff changeset
1691 else
kono
parents:
diff changeset
1692 {
kono
parents:
diff changeset
1693 gcc_assert (GET_CODE (src) != MINUS);
kono
parents:
diff changeset
1694
kono
parents:
diff changeset
1695 /* Rule 4 */
kono
parents:
diff changeset
1696 if (REG_P (XEXP (src, 0))
kono
parents:
diff changeset
1697 && dwf_regno (XEXP (src, 0)) == cur_cfa->reg
kono
parents:
diff changeset
1698 && CONST_INT_P (XEXP (src, 1)))
kono
parents:
diff changeset
1699 {
kono
parents:
diff changeset
1700 /* Setting a temporary CFA register that will be copied
kono
parents:
diff changeset
1701 into the FP later on. */
kono
parents:
diff changeset
1702 offset = - INTVAL (XEXP (src, 1));
kono
parents:
diff changeset
1703 cur_cfa->offset += offset;
kono
parents:
diff changeset
1704 cur_cfa->reg = dwf_regno (dest);
kono
parents:
diff changeset
1705 /* Or used to save regs to the stack. */
kono
parents:
diff changeset
1706 cur_trace->cfa_temp.reg = cur_cfa->reg;
kono
parents:
diff changeset
1707 cur_trace->cfa_temp.offset = cur_cfa->offset;
kono
parents:
diff changeset
1708 }
kono
parents:
diff changeset
1709
kono
parents:
diff changeset
1710 /* Rule 5 */
kono
parents:
diff changeset
1711 else if (REG_P (XEXP (src, 0))
kono
parents:
diff changeset
1712 && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
kono
parents:
diff changeset
1713 && XEXP (src, 1) == stack_pointer_rtx)
kono
parents:
diff changeset
1714 {
kono
parents:
diff changeset
1715 /* Setting a scratch register that we will use instead
kono
parents:
diff changeset
1716 of SP for saving registers to the stack. */
kono
parents:
diff changeset
1717 gcc_assert (cur_cfa->reg == dw_stack_pointer_regnum);
kono
parents:
diff changeset
1718 cur_trace->cfa_store.reg = dwf_regno (dest);
kono
parents:
diff changeset
1719 cur_trace->cfa_store.offset
kono
parents:
diff changeset
1720 = cur_cfa->offset - cur_trace->cfa_temp.offset;
kono
parents:
diff changeset
1721 }
kono
parents:
diff changeset
1722
kono
parents:
diff changeset
1723 /* Rule 9 */
kono
parents:
diff changeset
1724 else if (GET_CODE (src) == LO_SUM
kono
parents:
diff changeset
1725 && CONST_INT_P (XEXP (src, 1)))
kono
parents:
diff changeset
1726 {
kono
parents:
diff changeset
1727 cur_trace->cfa_temp.reg = dwf_regno (dest);
kono
parents:
diff changeset
1728 cur_trace->cfa_temp.offset = INTVAL (XEXP (src, 1));
kono
parents:
diff changeset
1729 }
kono
parents:
diff changeset
1730 else
kono
parents:
diff changeset
1731 gcc_unreachable ();
kono
parents:
diff changeset
1732 }
kono
parents:
diff changeset
1733 break;
kono
parents:
diff changeset
1734
kono
parents:
diff changeset
1735 /* Rule 6 */
kono
parents:
diff changeset
1736 case CONST_INT:
kono
parents:
diff changeset
1737 cur_trace->cfa_temp.reg = dwf_regno (dest);
kono
parents:
diff changeset
1738 cur_trace->cfa_temp.offset = INTVAL (src);
kono
parents:
diff changeset
1739 break;
kono
parents:
diff changeset
1740
kono
parents:
diff changeset
1741 /* Rule 7 */
kono
parents:
diff changeset
1742 case IOR:
kono
parents:
diff changeset
1743 gcc_assert (REG_P (XEXP (src, 0))
kono
parents:
diff changeset
1744 && dwf_regno (XEXP (src, 0)) == cur_trace->cfa_temp.reg
kono
parents:
diff changeset
1745 && CONST_INT_P (XEXP (src, 1)));
kono
parents:
diff changeset
1746
kono
parents:
diff changeset
1747 cur_trace->cfa_temp.reg = dwf_regno (dest);
kono
parents:
diff changeset
1748 cur_trace->cfa_temp.offset |= INTVAL (XEXP (src, 1));
kono
parents:
diff changeset
1749 break;
kono
parents:
diff changeset
1750
kono
parents:
diff changeset
1751 /* Skip over HIGH, assuming it will be followed by a LO_SUM,
kono
parents:
diff changeset
1752 which will fill in all of the bits. */
kono
parents:
diff changeset
1753 /* Rule 8 */
kono
parents:
diff changeset
1754 case HIGH:
kono
parents:
diff changeset
1755 break;
kono
parents:
diff changeset
1756
kono
parents:
diff changeset
1757 /* Rule 15 */
kono
parents:
diff changeset
1758 case UNSPEC:
kono
parents:
diff changeset
1759 case UNSPEC_VOLATILE:
kono
parents:
diff changeset
1760 /* All unspecs should be represented by REG_CFA_* notes. */
kono
parents:
diff changeset
1761 gcc_unreachable ();
kono
parents:
diff changeset
1762 return;
kono
parents:
diff changeset
1763
kono
parents:
diff changeset
1764 /* Rule 16 */
kono
parents:
diff changeset
1765 case AND:
kono
parents:
diff changeset
1766 /* If this AND operation happens on stack pointer in prologue,
kono
parents:
diff changeset
1767 we assume the stack is realigned and we extract the
kono
parents:
diff changeset
1768 alignment. */
kono
parents:
diff changeset
1769 if (fde && XEXP (src, 0) == stack_pointer_rtx)
kono
parents:
diff changeset
1770 {
kono
parents:
diff changeset
1771 /* We interpret reg_save differently with stack_realign set.
kono
parents:
diff changeset
1772 Thus we must flush whatever we have queued first. */
kono
parents:
diff changeset
1773 dwarf2out_flush_queued_reg_saves ();
kono
parents:
diff changeset
1774
kono
parents:
diff changeset
1775 gcc_assert (cur_trace->cfa_store.reg
kono
parents:
diff changeset
1776 == dwf_regno (XEXP (src, 0)));
kono
parents:
diff changeset
1777 fde->stack_realign = 1;
kono
parents:
diff changeset
1778 fde->stack_realignment = INTVAL (XEXP (src, 1));
kono
parents:
diff changeset
1779 cur_trace->cfa_store.offset = 0;
kono
parents:
diff changeset
1780
kono
parents:
diff changeset
1781 if (cur_cfa->reg != dw_stack_pointer_regnum
kono
parents:
diff changeset
1782 && cur_cfa->reg != dw_frame_pointer_regnum)
kono
parents:
diff changeset
1783 fde->drap_reg = cur_cfa->reg;
kono
parents:
diff changeset
1784 }
kono
parents:
diff changeset
1785 return;
kono
parents:
diff changeset
1786
kono
parents:
diff changeset
1787 default:
kono
parents:
diff changeset
1788 gcc_unreachable ();
kono
parents:
diff changeset
1789 }
kono
parents:
diff changeset
1790 break;
kono
parents:
diff changeset
1791
kono
parents:
diff changeset
1792 case MEM:
kono
parents:
diff changeset
1793
kono
parents:
diff changeset
1794 /* Saving a register to the stack. Make sure dest is relative to the
kono
parents:
diff changeset
1795 CFA register. */
kono
parents:
diff changeset
1796 switch (GET_CODE (XEXP (dest, 0)))
kono
parents:
diff changeset
1797 {
kono
parents:
diff changeset
1798 /* Rule 10 */
kono
parents:
diff changeset
1799 /* With a push. */
kono
parents:
diff changeset
1800 case PRE_MODIFY:
kono
parents:
diff changeset
1801 case POST_MODIFY:
kono
parents:
diff changeset
1802 /* We can't handle variable size modifications. */
kono
parents:
diff changeset
1803 gcc_assert (GET_CODE (XEXP (XEXP (XEXP (dest, 0), 1), 1))
kono
parents:
diff changeset
1804 == CONST_INT);
kono
parents:
diff changeset
1805 offset = -INTVAL (XEXP (XEXP (XEXP (dest, 0), 1), 1));
kono
parents:
diff changeset
1806
kono
parents:
diff changeset
1807 gcc_assert (REGNO (XEXP (XEXP (dest, 0), 0)) == STACK_POINTER_REGNUM
kono
parents:
diff changeset
1808 && cur_trace->cfa_store.reg == dw_stack_pointer_regnum);
kono
parents:
diff changeset
1809
kono
parents:
diff changeset
1810 cur_trace->cfa_store.offset += offset;
kono
parents:
diff changeset
1811 if (cur_cfa->reg == dw_stack_pointer_regnum)
kono
parents:
diff changeset
1812 cur_cfa->offset = cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1813
kono
parents:
diff changeset
1814 if (GET_CODE (XEXP (dest, 0)) == POST_MODIFY)
kono
parents:
diff changeset
1815 offset -= cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1816 else
kono
parents:
diff changeset
1817 offset = -cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1818 break;
kono
parents:
diff changeset
1819
kono
parents:
diff changeset
1820 /* Rule 11 */
kono
parents:
diff changeset
1821 case PRE_INC:
kono
parents:
diff changeset
1822 case PRE_DEC:
kono
parents:
diff changeset
1823 case POST_DEC:
kono
parents:
diff changeset
1824 offset = GET_MODE_SIZE (GET_MODE (dest));
kono
parents:
diff changeset
1825 if (GET_CODE (XEXP (dest, 0)) == PRE_INC)
kono
parents:
diff changeset
1826 offset = -offset;
kono
parents:
diff changeset
1827
kono
parents:
diff changeset
1828 gcc_assert ((REGNO (XEXP (XEXP (dest, 0), 0))
kono
parents:
diff changeset
1829 == STACK_POINTER_REGNUM)
kono
parents:
diff changeset
1830 && cur_trace->cfa_store.reg == dw_stack_pointer_regnum);
kono
parents:
diff changeset
1831
kono
parents:
diff changeset
1832 cur_trace->cfa_store.offset += offset;
kono
parents:
diff changeset
1833
kono
parents:
diff changeset
1834 /* Rule 18: If stack is aligned, we will use FP as a
kono
parents:
diff changeset
1835 reference to represent the address of the stored
kono
parents:
diff changeset
1836 regiser. */
kono
parents:
diff changeset
1837 if (fde
kono
parents:
diff changeset
1838 && fde->stack_realign
kono
parents:
diff changeset
1839 && REG_P (src)
kono
parents:
diff changeset
1840 && REGNO (src) == HARD_FRAME_POINTER_REGNUM)
kono
parents:
diff changeset
1841 {
kono
parents:
diff changeset
1842 gcc_assert (cur_cfa->reg != dw_frame_pointer_regnum);
kono
parents:
diff changeset
1843 cur_trace->cfa_store.offset = 0;
kono
parents:
diff changeset
1844 }
kono
parents:
diff changeset
1845
kono
parents:
diff changeset
1846 if (cur_cfa->reg == dw_stack_pointer_regnum)
kono
parents:
diff changeset
1847 cur_cfa->offset = cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1848
kono
parents:
diff changeset
1849 if (GET_CODE (XEXP (dest, 0)) == POST_DEC)
kono
parents:
diff changeset
1850 offset += -cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1851 else
kono
parents:
diff changeset
1852 offset = -cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1853 break;
kono
parents:
diff changeset
1854
kono
parents:
diff changeset
1855 /* Rule 12 */
kono
parents:
diff changeset
1856 /* With an offset. */
kono
parents:
diff changeset
1857 case PLUS:
kono
parents:
diff changeset
1858 case MINUS:
kono
parents:
diff changeset
1859 case LO_SUM:
kono
parents:
diff changeset
1860 {
kono
parents:
diff changeset
1861 unsigned int regno;
kono
parents:
diff changeset
1862
kono
parents:
diff changeset
1863 gcc_assert (CONST_INT_P (XEXP (XEXP (dest, 0), 1))
kono
parents:
diff changeset
1864 && REG_P (XEXP (XEXP (dest, 0), 0)));
kono
parents:
diff changeset
1865 offset = INTVAL (XEXP (XEXP (dest, 0), 1));
kono
parents:
diff changeset
1866 if (GET_CODE (XEXP (dest, 0)) == MINUS)
kono
parents:
diff changeset
1867 offset = -offset;
kono
parents:
diff changeset
1868
kono
parents:
diff changeset
1869 regno = dwf_regno (XEXP (XEXP (dest, 0), 0));
kono
parents:
diff changeset
1870
kono
parents:
diff changeset
1871 if (cur_cfa->reg == regno)
kono
parents:
diff changeset
1872 offset -= cur_cfa->offset;
kono
parents:
diff changeset
1873 else if (cur_trace->cfa_store.reg == regno)
kono
parents:
diff changeset
1874 offset -= cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1875 else
kono
parents:
diff changeset
1876 {
kono
parents:
diff changeset
1877 gcc_assert (cur_trace->cfa_temp.reg == regno);
kono
parents:
diff changeset
1878 offset -= cur_trace->cfa_temp.offset;
kono
parents:
diff changeset
1879 }
kono
parents:
diff changeset
1880 }
kono
parents:
diff changeset
1881 break;
kono
parents:
diff changeset
1882
kono
parents:
diff changeset
1883 /* Rule 13 */
kono
parents:
diff changeset
1884 /* Without an offset. */
kono
parents:
diff changeset
1885 case REG:
kono
parents:
diff changeset
1886 {
kono
parents:
diff changeset
1887 unsigned int regno = dwf_regno (XEXP (dest, 0));
kono
parents:
diff changeset
1888
kono
parents:
diff changeset
1889 if (cur_cfa->reg == regno)
kono
parents:
diff changeset
1890 offset = -cur_cfa->offset;
kono
parents:
diff changeset
1891 else if (cur_trace->cfa_store.reg == regno)
kono
parents:
diff changeset
1892 offset = -cur_trace->cfa_store.offset;
kono
parents:
diff changeset
1893 else
kono
parents:
diff changeset
1894 {
kono
parents:
diff changeset
1895 gcc_assert (cur_trace->cfa_temp.reg == regno);
kono
parents:
diff changeset
1896 offset = -cur_trace->cfa_temp.offset;
kono
parents:
diff changeset
1897 }
kono
parents:
diff changeset
1898 }
kono
parents:
diff changeset
1899 break;
kono
parents:
diff changeset
1900
kono
parents:
diff changeset
1901 /* Rule 14 */
kono
parents:
diff changeset
1902 case POST_INC:
kono
parents:
diff changeset
1903 gcc_assert (cur_trace->cfa_temp.reg
kono
parents:
diff changeset
1904 == dwf_regno (XEXP (XEXP (dest, 0), 0)));
kono
parents:
diff changeset
1905 offset = -cur_trace->cfa_temp.offset;
kono
parents:
diff changeset
1906 cur_trace->cfa_temp.offset -= GET_MODE_SIZE (GET_MODE (dest));
kono
parents:
diff changeset
1907 break;
kono
parents:
diff changeset
1908
kono
parents:
diff changeset
1909 default:
kono
parents:
diff changeset
1910 gcc_unreachable ();
kono
parents:
diff changeset
1911 }
kono
parents:
diff changeset
1912
kono
parents:
diff changeset
1913 /* Rule 17 */
kono
parents:
diff changeset
1914 /* If the source operand of this MEM operation is a memory,
kono
parents:
diff changeset
1915 we only care how much stack grew. */
kono
parents:
diff changeset
1916 if (MEM_P (src))
kono
parents:
diff changeset
1917 break;
kono
parents:
diff changeset
1918
kono
parents:
diff changeset
1919 if (REG_P (src)
kono
parents:
diff changeset
1920 && REGNO (src) != STACK_POINTER_REGNUM
kono
parents:
diff changeset
1921 && REGNO (src) != HARD_FRAME_POINTER_REGNUM
kono
parents:
diff changeset
1922 && dwf_regno (src) == cur_cfa->reg)
kono
parents:
diff changeset
1923 {
kono
parents:
diff changeset
1924 /* We're storing the current CFA reg into the stack. */
kono
parents:
diff changeset
1925
kono
parents:
diff changeset
1926 if (cur_cfa->offset == 0)
kono
parents:
diff changeset
1927 {
kono
parents:
diff changeset
1928 /* Rule 19 */
kono
parents:
diff changeset
1929 /* If stack is aligned, putting CFA reg into stack means
kono
parents:
diff changeset
1930 we can no longer use reg + offset to represent CFA.
kono
parents:
diff changeset
1931 Here we use DW_CFA_def_cfa_expression instead. The
kono
parents:
diff changeset
1932 result of this expression equals to the original CFA
kono
parents:
diff changeset
1933 value. */
kono
parents:
diff changeset
1934 if (fde
kono
parents:
diff changeset
1935 && fde->stack_realign
kono
parents:
diff changeset
1936 && cur_cfa->indirect == 0
kono
parents:
diff changeset
1937 && cur_cfa->reg != dw_frame_pointer_regnum)
kono
parents:
diff changeset
1938 {
kono
parents:
diff changeset
1939 gcc_assert (fde->drap_reg == cur_cfa->reg);
kono
parents:
diff changeset
1940
kono
parents:
diff changeset
1941 cur_cfa->indirect = 1;
kono
parents:
diff changeset
1942 cur_cfa->reg = dw_frame_pointer_regnum;
kono
parents:
diff changeset
1943 cur_cfa->base_offset = offset;
kono
parents:
diff changeset
1944 cur_cfa->offset = 0;
kono
parents:
diff changeset
1945
kono
parents:
diff changeset
1946 fde->drap_reg_saved = 1;
kono
parents:
diff changeset
1947 break;
kono
parents:
diff changeset
1948 }
kono
parents:
diff changeset
1949
kono
parents:
diff changeset
1950 /* If the source register is exactly the CFA, assume
kono
parents:
diff changeset
1951 we're saving SP like any other register; this happens
kono
parents:
diff changeset
1952 on the ARM. */
kono
parents:
diff changeset
1953 queue_reg_save (stack_pointer_rtx, NULL_RTX, offset);
kono
parents:
diff changeset
1954 break;
kono
parents:
diff changeset
1955 }
kono
parents:
diff changeset
1956 else
kono
parents:
diff changeset
1957 {
kono
parents:
diff changeset
1958 /* Otherwise, we'll need to look in the stack to
kono
parents:
diff changeset
1959 calculate the CFA. */
kono
parents:
diff changeset
1960 rtx x = XEXP (dest, 0);
kono
parents:
diff changeset
1961
kono
parents:
diff changeset
1962 if (!REG_P (x))
kono
parents:
diff changeset
1963 x = XEXP (x, 0);
kono
parents:
diff changeset
1964 gcc_assert (REG_P (x));
kono
parents:
diff changeset
1965
kono
parents:
diff changeset
1966 cur_cfa->reg = dwf_regno (x);
kono
parents:
diff changeset
1967 cur_cfa->base_offset = offset;
kono
parents:
diff changeset
1968 cur_cfa->indirect = 1;
kono
parents:
diff changeset
1969 break;
kono
parents:
diff changeset
1970 }
kono
parents:
diff changeset
1971 }
kono
parents:
diff changeset
1972
kono
parents:
diff changeset
1973 if (REG_P (src))
kono
parents:
diff changeset
1974 span = targetm.dwarf_register_span (src);
kono
parents:
diff changeset
1975 else
kono
parents:
diff changeset
1976 span = NULL;
kono
parents:
diff changeset
1977
kono
parents:
diff changeset
1978 if (!span)
kono
parents:
diff changeset
1979 queue_reg_save (src, NULL_RTX, offset);
kono
parents:
diff changeset