From Jake Hamby For several years I've been eager to find the time to fix the bugs in C++ exceptions on VAX to get them working on NetBSD, because they穽e been broken for many years and it looked like only a few changes were needed to get them working. Without C++ exceptions, the NetBSD test suite can穰 be run. The good news is that I was able to fix all the bugs in the VAX machine description to make C++ exceptions work in GCC 4.8.5 (version unimportant). I wrote a blog post explaining the bugs, with patches: Here's a short summary, with the diffs in text form at the end of this email. 1) Replace #define FRAME_POINTER_CFA_OFFSET(FNDECL) 0 with #define ARG_POINTER_CFA_OFFSET(FNDECL) 0 in gcc/config/vax/elf.h and gcc/config/vax/vax.h. This changes the definition of __builtin_dwarf_cfa() to return %ap instead of %fp, which correctly points to CFA. Previously, the stack unwinder was crashing in _Unwind_RaiseException() trying to follow bad pointers from the initial CFA. 2) Define EH_RETURN_DATA_REGNO(N) to include only R2 and R3 (instead of R2-R5) and add code to vax_expand_prologue() in gcc/config/vax/vax.c to add R2-R3 to the procedure entry mask but only if crtl->calls_eh_return is set. This fixes a crash when the stack unwinder tried to write values to R2 and R3 in the previous stack frame via __builtin_eh_return_data_regno (0) and __builtin_eh_return_data_regno (1). 3) Removed definitions of EH_RETURN_STACKADJ_RTX and STARTING_FRAME_OFFSET from gcc/config/vax/elf.h. It's not necessary to remember the stack adjustment or to waste four bytes on every stack frame for a value that's not needed. Also remove the suspicious changes in gcc/config/vax/vax.md to the definitions of call_pop and call_value regarding DW_CFA_GNU_args_size and EH unwinding. I reverted to the previous versions from an older version of GCC, adding a few useful comments that had been removed. 4) The last bug is the one I understand the least. I'm hoping someone reading this can implement a correct fix. What I was seeing after making all the previous changes to fix the other bugs is that my test program failed to catch any exceptions, but instead returned normally to the original return path. Investigation revealed that GCC was correctly generating the necessary move instruction to copy the second parameter passed to __builtin_eh_return() into the return address, because EH_RETURN_HANDLER_RTX had been defined correctly in config/vax/elf.h. Here龝 what the call looks like in gcc/except.c: #ifdef EH_RETURN_HANDLER_RTX rtx insn = emit_move_insn (EH_RETURN_HANDLER_RTX, crtl->eh.ehr_handler); #else error ("__builtin_eh_return not supported on this target"); #endif The problem was that the optimizer is deleting the final move instruction when I compile with -O or higher. The assembly code at -O0 (no optimization) generated for the __builtin_eh_return() call at the end of _Unwind_RaiseException() looked like: calls $2,_Unwind_DebugHook movl -12(%fp),%r1 movl %r1,16(%fp) ret .cfi_endproc But then when I compiled with -O1 or -O2, all I saw was: calls $2,_Unwind_DebugHook ret .cfi_endproc This was a mystery for me and I don穰 know enough about how the final peephole optimizer works to really track down why it thinks it can remove the move call to store the previous return address. My workaround was to add a call to RTX_FRAME_RELATED_P (insn) = 1; after the emit_move_insn() in gcc/except.c, which was used in vax_expand_prologue() to mark the procedure entry mask. By making this change, the optimizer no longer removes the call to write the value to the previous stack pointer, but it adds an extra line of .cfi exception info, which seems unnecessary since the code is immediately going to return from the call and any adjustment made by the DWARF stack unwinder will already have been done. Here龝 what the optimized code looks like with the patch (%r6 had been loaded earlier): calls $2,_Unwind_DebugHook movl %r6,16(%fp) .cfi_offset 6, -36 ret .cfi_endproc With that final change, C++ exception handling now finally works on NetBSD/vax, and I was able to successfully run the vast majority of the tests in the ATF testsuite, which had been completely inaccessible when I started due to both atf-run and atf-report immediately dumping core due to the bad pointers that I fixed. Now I have a bunch of new bugs to track down fixes for, but I think this was the hardest set of problems that needed to be solved to bring NetBSD on VAX up to the level of the other NetBSD ports. Here are the diffs I have so far. They should apply to any recent version of GCC (tested on GCC 4.8.5). With the exception of the hack to gcc/except.c, the other diffs are ready to submit to NetBSD as well as to upstream GCC. The fix I稘 like to see for the final problem I discovered of the emit_move_insn() being deleted by the optimizer would be another patch to one of the files in the gcc/config/vax directory to explain to the optimizer that writing to 16(%fp) is important and not something to be deleted from the epilogue (perhaps it thinks it龝 writing to a local variable in the frame that's about to be destroyed?). I didn't see any indication that any other GCC ports required anything special to tell the optimizer not to delete the move instruction to EH_RETURN_HANDLER_RTX, so the other suspicion I have is that there may be a bug specific to VAX's peephole optimizer or related functions. Any ideas?diff -r1.1.1.3 -r1.2 src/external/gpl3/gcc/dist/gcc/except.c
(christos)
--- src/external/gpl3/gcc/dist/gcc/except.c 2016/01/24 06:06:09 1.1.1.3
+++ src/external/gpl3/gcc/dist/gcc/except.c 2016/03/23 12:52:43 1.2
@@ -2278,27 +2278,28 @@ expand_eh_return (void) | @@ -2278,27 +2278,28 @@ expand_eh_return (void) | |||
2278 | clobber_return_register (); | 2278 | clobber_return_register (); | |
2279 | 2279 | |||
2280 | #ifdef EH_RETURN_STACKADJ_RTX | 2280 | #ifdef EH_RETURN_STACKADJ_RTX | |
2281 | emit_move_insn (EH_RETURN_STACKADJ_RTX, crtl->eh.ehr_stackadj); | 2281 | emit_move_insn (EH_RETURN_STACKADJ_RTX, crtl->eh.ehr_stackadj); | |
2282 | #endif | 2282 | #endif | |
2283 | 2283 | |||
2284 | #ifdef HAVE_eh_return | 2284 | #ifdef HAVE_eh_return | |
2285 | if (HAVE_eh_return) | 2285 | if (HAVE_eh_return) | |
2286 | emit_insn (gen_eh_return (crtl->eh.ehr_handler)); | 2286 | emit_insn (gen_eh_return (crtl->eh.ehr_handler)); | |
2287 | else | 2287 | else | |
2288 | #endif | 2288 | #endif | |
2289 | { | 2289 | { | |
2290 | #ifdef EH_RETURN_HANDLER_RTX | 2290 | #ifdef EH_RETURN_HANDLER_RTX | |
2291 | emit_move_insn (EH_RETURN_HANDLER_RTX, crtl->eh.ehr_handler); | 2291 | rtx insn = emit_move_insn (EH_RETURN_HANDLER_RTX, crtl->eh.ehr_handler); | |
2292 | RTX_FRAME_RELATED_P (insn) = 1; | |||
2292 | #else | 2293 | #else | |
2293 | error ("__builtin_eh_return not supported on this target"); | 2294 | error ("__builtin_eh_return not supported on this target"); | |
2294 | #endif | 2295 | #endif | |
2295 | } | 2296 | } | |
2296 | 2297 | |||
2297 | emit_label (around_label); | 2298 | emit_label (around_label); | |
2298 | } | 2299 | } | |
2299 | 2300 | |||
2300 | /* Convert a ptr_mode address ADDR_TREE to a Pmode address controlled by | 2301 | /* Convert a ptr_mode address ADDR_TREE to a Pmode address controlled by | |
2301 | POINTERS_EXTEND_UNSIGNED and return it. */ | 2302 | POINTERS_EXTEND_UNSIGNED and return it. */ | |
2302 | 2303 | |||
2303 | rtx | 2304 | rtx | |
2304 | expand_builtin_extend_pointer (tree addr_tree) | 2305 | expand_builtin_extend_pointer (tree addr_tree) |
--- src/external/gpl3/gcc/dist/gcc/config/vax/elf.h 2016/01/24 09:43:34 1.4
+++ src/external/gpl3/gcc/dist/gcc/config/vax/elf.h 2016/03/23 12:52:43 1.5
@@ -35,51 +35,37 @@ along with GCC; see the file COPYING3. | @@ -35,51 +35,37 @@ along with GCC; see the file COPYING3. | |||
35 | #define PTRDIFF_TYPE "long int" | 35 | #define PTRDIFF_TYPE "long int" | |
36 | 36 | |||
37 | /* Profiling routine. */ | 37 | /* Profiling routine. */ | |
38 | #undef VAX_FUNCTION_PROFILER_NAME | 38 | #undef VAX_FUNCTION_PROFILER_NAME | |
39 | #define VAX_FUNCTION_PROFILER_NAME "__mcount" | 39 | #define VAX_FUNCTION_PROFILER_NAME "__mcount" | |
40 | 40 | |||
41 | /* Let's be re-entrant. */ | 41 | /* Let's be re-entrant. */ | |
42 | #undef PCC_STATIC_STRUCT_RETURN | 42 | #undef PCC_STATIC_STRUCT_RETURN | |
43 | 43 | |||
44 | /* Before the prologue, the top of the frame is below the argument | 44 | /* Before the prologue, the top of the frame is below the argument | |
45 | count pushed by the CALLS and before the start of the saved registers. */ | 45 | count pushed by the CALLS and before the start of the saved registers. */ | |
46 | #define INCOMING_FRAME_SP_OFFSET 0 | 46 | #define INCOMING_FRAME_SP_OFFSET 0 | |
47 | 47 | |||
48 | /* Offset from the frame pointer register value to the top of the stack. */ | 48 | /* We use R2-R3 (call-clobbered) registers for exceptions. */ | |
49 | #define FRAME_POINTER_CFA_OFFSET(FNDECL) 0 | 49 | #define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) + 2 : INVALID_REGNUM) | |
50 | ||||
51 | /* We use R2-R5 (call-clobbered) registers for exceptions. */ | |||
52 | #define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 2 : INVALID_REGNUM) | |||
53 | ||||
54 | /* Place the top of the stack for the DWARF2 EH stackadj value. */ | |||
55 | #define EH_RETURN_STACKADJ_RTX \ | |||
56 | gen_rtx_MEM (SImode, \ | |||
57 | plus_constant (Pmode, \ | |||
58 | gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),\ | |||
59 | -4)) | |||
60 | 50 | |||
61 | /* Simple store the return handler into the call frame. */ | 51 | /* Simple store the return handler into the call frame. */ | |
62 | #define EH_RETURN_HANDLER_RTX \ | 52 | #define EH_RETURN_HANDLER_RTX \ | |
63 | gen_rtx_MEM (Pmode, \ | 53 | gen_rtx_MEM (Pmode, \ | |
64 | plus_constant (Pmode, \ | 54 | plus_constant (Pmode, \ | |
65 | gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),\ | 55 | gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),\ | |
66 | 16)) | 56 | 16)) | |
67 | 57 | |||
68 | 58 | |||
69 | /* Reserve the top of the stack for exception handler stackadj value. */ | |||
70 | #undef STARTING_FRAME_OFFSET | |||
71 | #define STARTING_FRAME_OFFSET -4 | |||
72 | ||||
73 | /* The VAX wants no space between the case instruction and the jump table. */ | 59 | /* The VAX wants no space between the case instruction and the jump table. */ | |
74 | #undef ASM_OUTPUT_BEFORE_CASE_LABEL | 60 | #undef ASM_OUTPUT_BEFORE_CASE_LABEL | |
75 | #define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE) | 61 | #define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE) | |
76 | 62 | |||
77 | #undef SUBTARGET_OVERRIDE_OPTIONS | 63 | #undef SUBTARGET_OVERRIDE_OPTIONS | |
78 | #define SUBTARGET_OVERRIDE_OPTIONS \ | 64 | #define SUBTARGET_OVERRIDE_OPTIONS \ | |
79 | do \ | 65 | do \ | |
80 | { \ | 66 | { \ | |
81 | /* Turn off function CSE if we're doing PIC. */ \ | 67 | /* Turn off function CSE if we're doing PIC. */ \ | |
82 | if (flag_pic) \ | 68 | if (flag_pic) \ | |
83 | flag_no_function_cse = 1; \ | 69 | flag_no_function_cse = 1; \ | |
84 | } \ | 70 | } \ | |
85 | while (0) | 71 | while (0) |
--- src/external/gpl3/gcc/dist/gcc/config/vax/vax.c 2016/01/24 09:43:34 1.11
+++ src/external/gpl3/gcc/dist/gcc/config/vax/vax.c 2016/03/23 12:52:43 1.12
@@ -185,27 +185,28 @@ vax_add_reg_cfa_offset (rtx insn, int of | @@ -185,27 +185,28 @@ vax_add_reg_cfa_offset (rtx insn, int of | |||
185 | used in the function. This function is responsible for knowing | 185 | used in the function. This function is responsible for knowing | |
186 | which registers should not be saved even if used. */ | 186 | which registers should not be saved even if used. */ | |
187 | 187 | |||
188 | void | 188 | void | |
189 | vax_expand_prologue (void) | 189 | vax_expand_prologue (void) | |
190 | { | 190 | { | |
191 | int regno, offset; | 191 | int regno, offset; | |
192 | int mask = 0; | 192 | int mask = 0; | |
193 | HOST_WIDE_INT size; | 193 | HOST_WIDE_INT size; | |
194 | rtx insn; | 194 | rtx insn; | |
195 | 195 | |||
196 | offset = 20; | 196 | offset = 20; | |
197 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) | 197 | for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) | |
198 | if (df_regs_ever_live_p (regno) && !call_used_regs[regno]) | 198 | if ((df_regs_ever_live_p (regno) && !call_used_regs[regno]) | |
199 | || (crtl->calls_eh_return && regno >= 2 && regno < 4)) | |||
199 | { | 200 | { | |
200 | mask |= 1 << regno; | 201 | mask |= 1 << regno; | |
201 | offset += 4; | 202 | offset += 4; | |
202 | } | 203 | } | |
203 | 204 | |||
204 | insn = emit_insn (gen_procedure_entry_mask (GEN_INT (mask))); | 205 | insn = emit_insn (gen_procedure_entry_mask (GEN_INT (mask))); | |
205 | RTX_FRAME_RELATED_P (insn) = 1; | 206 | RTX_FRAME_RELATED_P (insn) = 1; | |
206 | 207 | |||
207 | /* The layout of the CALLG/S stack frame is follows: | 208 | /* The layout of the CALLG/S stack frame is follows: | |
208 | 209 | |||
209 | <- CFA, AP | 210 | <- CFA, AP | |
210 | r11 | 211 | r11 | |
211 | r10 | 212 | r10 |
--- src/external/gpl3/gcc/dist/gcc/config/vax/vax.h 2016/03/23 12:45:50 1.5
+++ src/external/gpl3/gcc/dist/gcc/config/vax/vax.h 2016/03/23 12:52:43 1.6
@@ -159,32 +159,32 @@ along with GCC; see the file COPYING3. | @@ -159,32 +159,32 @@ along with GCC; see the file COPYING3. | |||
159 | 159 | |||
160 | /* VAX PSW for DWARF-2 */ | 160 | /* VAX PSW for DWARF-2 */ | |
161 | #define PSW_REGNUM VAX_PSW_REGNUM | 161 | #define PSW_REGNUM VAX_PSW_REGNUM | |
162 | 162 | |||
163 | /* VAX pc is overloaded on a register. */ | 163 | /* VAX pc is overloaded on a register. */ | |
164 | #define PC_REGNUM VAX_PC_REGNUM | 164 | #define PC_REGNUM VAX_PC_REGNUM | |
165 | 165 | |||
166 | /* Register to use for pushing function arguments. */ | 166 | /* Register to use for pushing function arguments. */ | |
167 | #define STACK_POINTER_REGNUM VAX_SP_REGNUM | 167 | #define STACK_POINTER_REGNUM VAX_SP_REGNUM | |
168 | 168 | |||
169 | /* Base register for access to local variables of the function. */ | 169 | /* Base register for access to local variables of the function. */ | |
170 | #define FRAME_POINTER_REGNUM VAX_FP_REGNUM | 170 | #define FRAME_POINTER_REGNUM VAX_FP_REGNUM | |
171 | 171 | |||
172 | /* Offset from the frame pointer register value to the top of stack. */ | |||
173 | #define FRAME_POINTER_CFA_OFFSET(FNDECL) 0 | |||
174 | ||||
175 | /* Base register for access to arguments of the function. */ | 172 | /* Base register for access to arguments of the function. */ | |
176 | #define ARG_POINTER_REGNUM VAX_AP_REGNUM | 173 | #define ARG_POINTER_REGNUM VAX_AP_REGNUM | |
177 | 174 | |||
175 | /* Offset from the argument pointer register value to the CFA. */ | |||
176 | #define ARG_POINTER_CFA_OFFSET(FNDECL) 0 | |||
177 | ||||
178 | /* Register in which static-chain is passed to a function. */ | 178 | /* Register in which static-chain is passed to a function. */ | |
179 | #define STATIC_CHAIN_REGNUM 0 | 179 | #define STATIC_CHAIN_REGNUM 0 | |
180 | 180 | |||
181 | /* Register in which address to store a structure value | 181 | /* Register in which address to store a structure value | |
182 | is passed to a function. */ | 182 | is passed to a function. */ | |
183 | #define VAX_STRUCT_VALUE_REGNUM 1 | 183 | #define VAX_STRUCT_VALUE_REGNUM 1 | |
184 | 184 | |||
185 | /* Define the classes of registers for register constraints in the | 185 | /* Define the classes of registers for register constraints in the | |
186 | machine description. Also define ranges of constants. | 186 | machine description. Also define ranges of constants. | |
187 | 187 | |||
188 | One of the classes must always be named ALL_REGS and include all hard regs. | 188 | One of the classes must always be named ALL_REGS and include all hard regs. | |
189 | If there is more than one class, another class must be named NO_REGS | 189 | If there is more than one class, another class must be named NO_REGS | |
190 | and contain no registers. | 190 | and contain no registers. |
--- src/external/gpl3/gcc/dist/gcc/config/vax/vax.md 2016/01/24 09:43:34 1.9
+++ src/external/gpl3/gcc/dist/gcc/config/vax/vax.md 2016/03/23 12:52:43 1.10
@@ -8,26 +8,31 @@ | @@ -8,26 +8,31 @@ | |||
8 | ;; the Free Software Foundation; either version 3, or (at your option) | 8 | ;; the Free Software Foundation; either version 3, or (at your option) | |
9 | ;; any later version. | 9 | ;; any later version. | |
10 | 10 | |||
11 | ;; GCC is distributed in the hope that it will be useful, | 11 | ;; GCC is distributed in the hope that it will be useful, | |
12 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | ;; GNU General Public License for more details. | 14 | ;; GNU General Public License for more details. | |
15 | 15 | |||
16 | ;; You should have received a copy of the GNU General Public License | 16 | ;; You should have received a copy of the GNU General Public License | |
17 | ;; along with GCC; see the file COPYING3. If not see | 17 | ;; along with GCC; see the file COPYING3. If not see | |
18 | ;; <http://www.gnu.org/licenses/>. | 18 | ;; <http://www.gnu.org/licenses/>. | |
19 | 19 | |||
20 | 20 | |||
21 | ;; Note that operand 1 is total size of args, in bytes, | |||
22 | ;; and what the call insn wants is the number of words. | |||
23 | ;; It is used in the call instruction as a byte, but in the addl2 as | |||
24 | ;; a word. Since the only time we actually use it in the call instruction | |||
25 | ;; is when it is a constant, SImode (for addl2) is the proper mode. | |||
21 | ;;- Instruction patterns. When multiple patterns apply, | 26 | ;;- Instruction patterns. When multiple patterns apply, | |
22 | ;;- the first one in the file is chosen. | 27 | ;;- the first one in the file is chosen. | |
23 | ;;- | 28 | ;;- | |
24 | ;;- See file "rtl.def" for documentation on define_insn, match_*, et al. | 29 | ;;- See file "rtl.def" for documentation on define_insn, match_*, et al. | |
25 | ;;- | 30 | ;;- | |
26 | ;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code | 31 | ;;- cpp macro #define NOTICE_UPDATE_CC in file tm.h handles condition code | |
27 | ;;- updates for most instructions. | 32 | ;;- updates for most instructions. | |
28 | 33 | |||
29 | ;; UNSPEC_VOLATILE usage: | 34 | ;; UNSPEC_VOLATILE usage: | |
30 | 35 | |||
31 | (define_c_enum "unspecv" [ | 36 | (define_c_enum "unspecv" [ | |
32 | VUNSPEC_BLOCKAGE ; 'blockage' insn to prevent scheduling across an | 37 | VUNSPEC_BLOCKAGE ; 'blockage' insn to prevent scheduling across an | |
33 | ; insn in the code. | 38 | ; insn in the code. | |
@@ -1299,118 +1304,85 @@ | @@ -1299,118 +1304,85 @@ | |||
1299 | (define_insn "" | 1304 | (define_insn "" | |
1300 | [(set (pc) | 1305 | [(set (pc) | |
1301 | (if_then_else | 1306 | (if_then_else | |
1302 | (ne (match_operand:SI 0 "nonimmediate_operand" "+g") | 1307 | (ne (match_operand:SI 0 "nonimmediate_operand" "+g") | |
1303 | (const_int 0)) | 1308 | (const_int 0)) | |
1304 | (label_ref (match_operand 1 "" "")) | 1309 | (label_ref (match_operand 1 "" "")) | |
1305 | (pc))) | 1310 | (pc))) | |
1306 | (set (match_dup 0) | 1311 | (set (match_dup 0) | |
1307 | (plus:SI (match_dup 0) | 1312 | (plus:SI (match_dup 0) | |
1308 | (const_int -1)))] | 1313 | (const_int -1)))] | |
1309 | "" | 1314 | "" | |
1310 | "decl %0\;jgequ %l1") | 1315 | "decl %0\;jgequ %l1") | |
1311 | 1316 | |||
1317 | ;; Note that operand 1 is total size of args, in bytes, | |||
1318 | ;; and what the call insn wants is the number of words. | |||
1319 | ;; It is used in the call instruction as a byte, but in the addl2 as | |||
1320 | ;; a word. Since the only time we actually use it in the call instruction | |||
1321 | ;; is when it is a constant, SImode (for addl2) is the proper mode. | |||
1312 | (define_expand "call_pop" | 1322 | (define_expand "call_pop" | |
1313 | [(parallel [(call (match_operand:QI 0 "memory_operand" "") | 1323 | [(parallel [(call (match_operand:QI 0 "memory_operand" "") | |
1314 | (match_operand:SI 1 "const_int_operand" "")) | 1324 | (match_operand:SI 1 "const_int_operand" "")) | |
1315 | (set (reg:SI VAX_SP_REGNUM) | 1325 | (set (reg:SI VAX_SP_REGNUM) | |
1316 | (plus:SI (reg:SI VAX_SP_REGNUM) | 1326 | (plus:SI (reg:SI VAX_SP_REGNUM) | |
1317 | (match_operand:SI 3 "immediate_operand" "")))])] | 1327 | (match_operand:SI 3 "immediate_operand" "")))])] | |
1318 | "" | 1328 | "" | |
1319 | { | 1329 | { | |
1320 | gcc_assert (INTVAL (operands[3]) <= 255 * 4 && INTVAL (operands[3]) % 4 == 0); | 1330 | gcc_assert (INTVAL (operands[1]) <= 255 * 4); | |
1321 | 1331 | operands[1] = GEN_INT ((INTVAL (operands[1]) + 3) / 4); | ||
1322 | /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size | |||
1323 | during EH unwinding. We must include the argument count pushed by | |||
1324 | the calls instruction. */ | |||
1325 | operands[1] = GEN_INT (INTVAL (operands[3]) + 4); | |||
1326 | }) | 1332 | }) | |
1327 | 1333 | |||
1328 | (define_insn "*call_pop" | 1334 | (define_insn "*call_pop" | |
1329 | [(call (match_operand:QI 0 "memory_operand" "m") | 1335 | [(call (match_operand:QI 0 "memory_operand" "m") | |
1330 | (match_operand:SI 1 "const_int_operand" "n")) | 1336 | (match_operand:SI 1 "const_int_operand" "n")) | |
1331 | (set (reg:SI VAX_SP_REGNUM) (plus:SI (reg:SI VAX_SP_REGNUM) | 1337 | (set (reg:SI VAX_SP_REGNUM) (plus:SI (reg:SI VAX_SP_REGNUM) | |
1332 | (match_operand:SI 2 "immediate_operand" "i")))] | 1338 | (match_operand:SI 2 "immediate_operand" "i")))] | |
1333 | "" | 1339 | "" | |
1334 | { | 1340 | "calls %1,%0") | |
1335 | operands[1] = GEN_INT ((INTVAL (operands[1]) - 4) / 4); | |||
1336 | return "calls %1,%0"; | |||
1337 | }) | |||
1338 | 1341 | |||
1339 | (define_expand "call_value_pop" | 1342 | (define_expand "call_value_pop" | |
1340 | [(parallel [(set (match_operand 0 "" "") | 1343 | [(parallel [(set (match_operand 0 "" "") | |
1341 | (call (match_operand:QI 1 "memory_operand" "") | 1344 | (call (match_operand:QI 1 "memory_operand" "") | |
1342 | (match_operand:SI 2 "const_int_operand" ""))) | 1345 | (match_operand:SI 2 "const_int_operand" ""))) | |
1343 | (set (reg:SI VAX_SP_REGNUM) | 1346 | (set (reg:SI VAX_SP_REGNUM) | |
1344 | (plus:SI (reg:SI VAX_SP_REGNUM) | 1347 | (plus:SI (reg:SI VAX_SP_REGNUM) | |
1345 | (match_operand:SI 4 "immediate_operand" "")))])] | 1348 | (match_operand:SI 4 "immediate_operand" "")))])] | |
1346 | "" | 1349 | "" | |
1347 | { | 1350 | { | |
1348 | gcc_assert (INTVAL (operands[4]) <= 255 * 4 && INTVAL (operands[4]) % 4 == 0); | 1351 | gcc_assert (INTVAL (operands[2]) <= 255 * 4); | |
1349 | 1352 | operands[2] = GEN_INT ((INTVAL (operands[2]) + 3) / 4); | ||
1350 | /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size | |||
1351 | during EH unwinding. We must include the argument count pushed by | |||
1352 | the calls instruction. */ | |||
1353 | operands[2] = GEN_INT (INTVAL (operands[4]) + 4); | |||
1354 | }) | 1353 | }) | |
1355 | 1354 | |||
1356 | (define_insn "*call_value_pop" | 1355 | (define_insn "*call_value_pop" | |
1357 | [(set (match_operand 0 "" "") | 1356 | [(set (match_operand 0 "" "") | |
1358 | (call (match_operand:QI 1 "memory_operand" "m") | 1357 | (call (match_operand:QI 1 "memory_operand" "m") | |
1359 | (match_operand:SI 2 "const_int_operand" "n"))) | 1358 | (match_operand:SI 2 "const_int_operand" "n"))) | |
1360 | (set (reg:SI VAX_SP_REGNUM) (plus:SI (reg:SI VAX_SP_REGNUM) | 1359 | (set (reg:SI VAX_SP_REGNUM) (plus:SI (reg:SI VAX_SP_REGNUM) | |
1361 | (match_operand:SI 3 "immediate_operand" "i")))] | 1360 | (match_operand:SI 3 "immediate_operand" "i")))] | |
1362 | "" | 1361 | "" | |
1363 | "* | 1362 | "calls %2,%1") | |
1364 | { | |||
1365 | operands[2] = GEN_INT ((INTVAL (operands[2]) - 4) / 4); | |||
1366 | return \"calls %2,%1\"; | |||
1367 | }") | |||
1368 | 1363 | |||
1369 | (define_expand "call" | 1364 | ;; Define another set of these for the case of functions with no operands. | |
1370 | [(call (match_operand:QI 0 "memory_operand" "") | 1365 | ;; These will allow the optimizers to do a slightly better job. | |
1371 | (match_operand:SI 1 "const_int_operand" ""))] | 1366 | (define_insn "call" | |
1372 | "" | 1367 | [(call (match_operand:QI 0 "memory_operand" "m") | |
1373 | " | 1368 | (const_int 0))] | |
1374 | { | |||
1375 | /* Operand 1 is the number of bytes to be popped by DW_CFA_GNU_args_size | |||
1376 | during EH unwinding. We must include the argument count pushed by | |||
1377 | the calls instruction. */ | |||
1378 | operands[1] = GEN_INT (INTVAL (operands[1]) + 4); | |||
1379 | }") | |||
1380 | ||||
1381 | (define_insn "*call" | |||
1382 | [(call (match_operand:QI 0 "memory_operand" "m") | |||
1383 | (match_operand:SI 1 "const_int_operand" ""))] | |||
1384 | "" | 1369 | "" | |
1385 | "calls $0,%0") | 1370 | "calls $0,%0") | |
1386 | 1371 | |||
1387 | (define_expand "call_value" | 1372 | (define_insn "call_value" | |
1388 | [(set (match_operand 0 "" "") | |||
1389 | (call (match_operand:QI 1 "memory_operand" "") | |||
1390 | (match_operand:SI 2 "const_int_operand" "")))] | |||
1391 | "" | |||
1392 | " | |||
1393 | { | |||
1394 | /* Operand 2 is the number of bytes to be popped by DW_CFA_GNU_args_size | |||
1395 | during EH unwinding. We must include the argument count pushed by | |||
1396 | the calls instruction. */ | |||
1397 | operands[2] = GEN_INT (INTVAL (operands[2]) + 4); | |||
1398 | }") | |||
1399 | ||||
1400 | (define_insn "*call_value" | |||
1401 | [(set (match_operand 0 "" "") | 1373 | [(set (match_operand 0 "" "") | |
1402 | (call (match_operand:QI 1 "memory_operand" "m") | 1374 | (call (match_operand:QI 1 "memory_operand" "m") | |
1403 | (match_operand:SI 2 "const_int_operand" "")))] | 1375 | (const_int 0)))] | |
1404 | "" | 1376 | "" | |
1405 | "calls $0,%1") | 1377 | "calls $0,%1") | |
1406 | 1378 | |||
1407 | ;; Call subroutine returning any type. | 1379 | ;; Call subroutine returning any type. | |
1408 | 1380 | |||
1409 | (define_expand "untyped_call" | 1381 | (define_expand "untyped_call" | |
1410 | [(parallel [(call (match_operand 0 "" "") | 1382 | [(parallel [(call (match_operand 0 "" "") | |
1411 | (const_int 0)) | 1383 | (const_int 0)) | |
1412 | (match_operand 1 "" "") | 1384 | (match_operand 1 "" "") | |
1413 | (match_operand 2 "" "")])] | 1385 | (match_operand 2 "" "")])] | |
1414 | "" | 1386 | "" | |
1415 | " | 1387 | " | |
1416 | { | 1388 | { |