Wed Mar 23 12:52:43 2016 UTC ()
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?


(christos)
diff -r1.1.1.3 -r1.2 src/external/gpl3/gcc/dist/gcc/except.c
diff -r1.4 -r1.5 src/external/gpl3/gcc/dist/gcc/config/vax/elf.h
diff -r1.11 -r1.12 src/external/gpl3/gcc/dist/gcc/config/vax/vax.c
diff -r1.5 -r1.6 src/external/gpl3/gcc/dist/gcc/config/vax/vax.h
diff -r1.9 -r1.10 src/external/gpl3/gcc/dist/gcc/config/vax/vax.md

cvs diff -r1.1.1.3 -r1.2 src/external/gpl3/gcc/dist/gcc/except.c (expand / switch to unified diff)

--- 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
2303rtx 2304rtx
2304expand_builtin_extend_pointer (tree addr_tree) 2305expand_builtin_extend_pointer (tree addr_tree)

cvs diff -r1.4 -r1.5 src/external/gpl3/gcc/dist/gcc/config/vax/elf.h (expand / switch to unified diff)

--- 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)

cvs diff -r1.11 -r1.12 src/external/gpl3/gcc/dist/gcc/config/vax/vax.c (expand / switch to unified diff)

--- 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
188void 188void
189vax_expand_prologue (void) 189vax_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

cvs diff -r1.5 -r1.6 src/external/gpl3/gcc/dist/gcc/config/vax/vax.h (expand / switch to unified diff)

--- 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.

cvs diff -r1.9 -r1.10 src/external/gpl3/gcc/dist/gcc/config/vax/vax.md (expand / switch to unified diff)

--- 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{