Patches to fix GCC’s C++ exception handling on NetBSD/VAX
Hi all, 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’ve 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’t 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: > http://jakehamby.com/?p=7 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’s 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’t 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’s 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’d like to see for the final problem I discovered of the emit_mov
Re: Patches to fix GCC’s C++ exception handling on NetBSD/VAX
> On Mar 23, 2016, at 05:56, Christos Zoulas wrote: > > In article , > Jake Hamby wrote: > > Hi, > > Thanks a lot for your patch. I applied it to our gcc-5 in the tree. > Unfortunately gcc-5 seems that it was never tested to even compile. > I fixed the simple compilation issue, but it fails to compile some > files with an internal error trying to construct a dwarf frame info > element with the wrong register. If you have some time, can you > take a look? I will too. > > Thanks, > > christos Hi Christos, I just rebased my patches on top of GCC 5.3, which I see you have recently switched to. Here’s a brief explanation of how I patched the dwarf frame error. The problem is that FIRST_PSEUDO_REGISTER should be increased from 16 to 17, because PSW is considered a real register for DWARF debug purposes. This necessitated changing a few other macros, but nothing major. Since it’s marked as one of the FIXED_REGISTERS, it never actually gets used. Currently I’m doing a full build with GCC 5.3 and CONFIGURE_ARGS += —enable-checking=all, which is very much slower, of course. One bug I discovered with —enable-checking=all on GCC 4.8.5 is a call to XEXP() that may not be valid, but which can be prevented by checking the other conditions first, and then calling XEXP() if the other conditions are true. There seems to be a code generation bug with C++ that only affects a few things. Unfortunately, GCC itself (the native version, not the cross compiler) is one of the programs affected. The symptom when compiling almost anything complex in GCC 4.8.5 is a stack overflow as it recursively loops around trying to expand bits and pieces of the insns. It seems to be branching the wrong way. In looking at this, I discovered one really broken issue in the current vax.md, namely the three peephole optimizations at the bottom. The comment on the bottom one that says “Leave this commented out until we can determine whether the second move precedes a jump which relies on the CC flags being set correctly.” is absolutely correct and I believe all three should be removed. I’ve done so in the diff below, and added a comment explaining why. I have a theory that the source of any code generation bugs in GCC’s output (and I fear that GCC 5.3 won’t necessarily fix, even if the system itself is completely stable), is that the CC0 notification handler isn’t doing the right thing. I’ll send another email if I make any progress on this issue, but what I’ve discovered so far is that it makes no sense for VAX to switch away from the CC0 style of condition handling, because almost every single instruction updates PSW flags, and in a similar way. So the older style is really optimized for VAX, but it took me a very long time to understand exactly what vax_notice_update_cc() is doing and why correct behavior of it is so important. The idea is that some part of the optimizer is able to remove explicit tst / cmp insns when a previous one has already set the flags in a way that’s useful. So my theory is that the current version mostly works, but it’s very difficult to understand as it’s written, and it may be very occasionally giving the wrong results due to either bugs in its logic or the instructions emitted not setting the flags in the usual way. Unfortunately, the m68k version of NOTICE_UPDATE_CC (the only other arch supported by NetBSD that uses the CC0 style) is even more convoluted. So what I’d like to try next is rewriting the VAX version of notice_update_cc to use the style that the AVR backend and others use which is to add a “cc” attribute to the instructions themselves in the .md file describing what each one does in terms of flags. Then the notify function itself becomes much simpler, and, hopefully, more likely to be correct. I did spend a few hours yesterday investigating whether it would make sense to convert VAX to the newer condition codes style that all of the modern CPUs use, but because nearly every instruction, including all of the move instructions, clobbers / updates PSW, it would be much uglier than adding a cc attribute to every opcode, and, what’s worse, it caused all sorts of breakage in the compiler when I tried it because the (clobber (reg:CC VAX_PSW_REGNUM)) lines I had added prevented it from matching instructions. I did find a patch on the GCC Bugzilla for a different architecture, where someone had gone down the lines of fixing the emit stuff where I found breakage. But VAX is so well tuned to the CC0 style that it makes more sense to refactor it in place in the style of Atmel AVR, NEC V850, Renesas H8/300, all of which are built from a similar template. The m68k backend could benefit from being refactored in a similar way, but I’ll focus on VAX for now. :-) https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50582 Even with the patches attached to that bug, and the FIRST_PSEUDO_REGISTER that I’ve included bel
Re: Patches to fix GCC’s C++ exception handling on NetBSD/VAX
As an added bonus, I see that my patch set also included an old m68k patch that had been sitting in my tree, which fixes a crash when -m68040 is defined. I may have submitted it to port-m68k before. It hasn’t been tested with the new compiler either. Here’s that patch separately. It only matter when TARGET_68881 && TUNE_68040. -Jake Index: external/gpl3/gcc/dist/gcc/config/m68k/m68k.md === RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/config/m68k/m68k.md,v retrieving revision 1.4 diff -u -u -r1.4 m68k.md --- external/gpl3/gcc/dist/gcc/config/m68k/m68k.md 24 Jan 2016 09:43:33 - 1.4 +++ external/gpl3/gcc/dist/gcc/config/m68k/m68k.md 26 Mar 2016 10:42:41 - @@ -2132,9 +2132,9 @@ ;; into the kernel to emulate fintrz. They should also be faster ;; than calling the subroutines fixsfsi or fixdfsi. -(define_insn "fix_truncdfsi2" +(define_insn "fix_truncsi2" [(set (match_operand:SI 0 "nonimmediate_operand" "=dm") - (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f" + (fix:SI (match_operand:FP 1 "register_operand" "f"))) (clobber (match_scratch:SI 2 "=d")) (clobber (match_scratch:SI 3 "=d"))] "TARGET_68881 && TUNE_68040" @@ -2143,9 +2143,9 @@ return "fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.l %1,%0\;fmovem%.l %2,%!"; }) -(define_insn "fix_truncdfhi2" +(define_insn "fix_trunchi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") - (fix:HI (fix:DF (match_operand:DF 1 "register_operand" "f" + (fix:HI (match_operand:FP 1 "register_operand" "f"))) (clobber (match_scratch:SI 2 "=d")) (clobber (match_scratch:SI 3 "=d"))] "TARGET_68881 && TUNE_68040" @@ -2154,9 +2154,9 @@ return "fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w #-33,%3\;fmovem%.l %3,%!\;fmove%.w %1,%0\;fmovem%.l %2,%!"; }) -(define_insn "fix_truncdfqi2" +(define_insn "fix_truncqi2" [(set (match_operand:QI 0 "nonimmediate_operand" "=dm") - (fix:QI (fix:DF (match_operand:DF 1 "register_operand" "f" + (fix:QI (match_operand:FP 1 "register_operand" "f"))) (clobber (match_scratch:SI 2 "=d")) (clobber (match_scratch:SI 3 "=d"))] "TARGET_68881 && TUNE_68040"
Re: Patches to fix GCC’s C++ exception handling on NetBSD/VAX
Unfortunately, my previous patch that included a change to gcc/config/vax/vax.h that increased FIRST_PSEUDO_REGISTER from 16 to 17 breaks the C++ exception handling that I’d worked so hard to get right with the rest of the patch. I believe I need to define DWARF_FRAME_REGISTERS to 16 in the same file to fix the size of the array that libgcc/unwind-dw2.c creates. The i386 backend and several others also define it their .h file for the same reason (compatibility with hardcoded frame offsets). Here’s the first part of the patch to vax.h that increases FIRST_PSEUDO_REGISTER and also adds a definition of DWARF_FRAME_REGISTERS as 16, with suitable comment. I’m testing it now. I know that C++ exceptions were working before I increased FIRST_PSEUDO_REGISTER to 17. Regards, Jake Index: external/gpl3/gcc.old/dist/gcc/config/vax/vax.h === RCS file: /cvsroot/src/external/gpl3/gcc.old/dist/gcc/config/vax/vax.h,v retrieving revision 1.3 diff -u -r1.3 vax.h --- external/gpl3/gcc.old/dist/gcc/config/vax/vax.h 23 Sep 2015 03:39:18 - 1.3 +++ external/gpl3/gcc.old/dist/gcc/config/vax/vax.h 26 Mar 2016 14:34:29 - @@ -119,13 +119,17 @@ The hardware registers are assigned numbers for the compiler from 0 to just below FIRST_PSEUDO_REGISTER. All registers that the compiler knows about must be given numbers, - even those that are not normally considered general registers. */ -#define FIRST_PSEUDO_REGISTER 16 + even those that are not normally considered general registers. + This includes PSW, which the VAX backend did not originally include. */ +#define FIRST_PSEUDO_REGISTER 17 + +/* For compatibility, DWARF_FRAME_REGISTERS must still be 16. */ +#define DWARF_FRAME_REGISTERS 16 /* 1 for registers that have pervasive standard uses and are not available for the register allocator. - On the VAX, these are the AP, FP, SP and PC. */ -#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} + On the VAX, these are the AP, FP, SP, PC, and PSW. */ +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} /* 1 for registers not available across function calls. These must include the FIXED_REGISTERS and also any
Re: Patches to fix GCC's C++ exception_handling on NetBSD/VAX
Thank you for the offer. I already tested it on an Amiga 3000 w/ 68040 card when I made the fix. The bug manifested as the cross-compiler crashing with a failure to find a suitable insn, because it couldn’t find the correct FP instruction to expand to. I believe it manifested when running ./build.sh release with “-m68040” set in CPUFLAGS. I will test it myself and see if it’s still an issue without the patch. If you look at the .md file, there’s an entirely different code path to generate the same instructions when "TARGET_68881 && TUNE_68040" aren't defined. At the time I made the change, I had already been testing the code on an Amiga 3000 w/ 68040 card, so I know that the generated code is likely correct (also, the assembler accepted it). So I’m assuming that it’s a fairly safe thing. It was the difference between the build succeeding or failing, and not an issue with the generated code. So the only thing I can suggest is that you can try a build with the patch and make sure it's stable. I was never able to produce a build without it, because "TARGET_68881 && TUNE_68040" was excluding the other choices when building, I believe, libm or libc or the kernel or something like that. I do have a test case for C++ exceptions on VAX, which I will send separately. Thanks, Jake > On Mar 27, 2016, at 10:08, Mikael Pettersson wrote: > > Jake Hamby writes: >> As an added bonus, I see that my patch set also included an old m68k patch >> that had been sitting in my tree, which fixes a crash when -m68040 is >> defined. >> I may have submitted it to port-m68k before. It hasn't been tested with the >> new compiler either. Here's that patch separately. It only matter when >> TARGET_68881 && TUNE_68040. > > Do you have a test case or some recipe for reproducing the crash? > I'd be happy to test this patch on Linux/M68K. > > /Mikael > >> >> -Jake >> >> >> Index: external/gpl3/gcc/dist/gcc/config/m68k/m68k.md >> >> RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/config/m68k/m68k.md,v >> retrieving revision 1.4 >> diff -u -u -r1.4 m68k.md >> --- external/gpl3/gcc/dist/gcc/config/m68k/m68k.md 24 Jan 2016 09:43:33 >> - 1.4 >> +++ external/gpl3/gcc/dist/gcc/config/m68k/m68k.md 26 Mar 2016 10:42:41 >> - >> @@ -2132,9 +2132,9 @@ >> ;; into the kernel to emulate fintrz. They should also be faster >> ;; than calling the subroutines fixsfsi or fixdfsi. >> >> -(define_insn "fix_truncdfsi2" >> +(define_insn "fix_truncsi2" >> [(set (match_operand:SI 0 "nonimmediate_operand" "=dm") >> -(fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f" >> +(fix:SI (match_operand:FP 1 "register_operand" "f"))) >>(clobber (match_scratch:SI 2 "=d")) >>(clobber (match_scratch:SI 3 "=d"))] >> "TARGET_68881 && TUNE_68040" >> @@ -2143,9 +2143,9 @@ >> return "fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w >> #-33,%3\;fmovem%.l %3,%!\;fmove%.l %1,%0\;fmovem%.l %2,%!"; >> }) >> >> -(define_insn "fix_truncdfhi2" >> +(define_insn "fix_trunchi2" >> [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") >> -(fix:HI (fix:DF (match_operand:DF 1 "register_operand" "f" >> +(fix:HI (match_operand:FP 1 "register_operand" "f"))) >>(clobber (match_scratch:SI 2 "=d")) >>(clobber (match_scratch:SI 3 "=d"))] >> "TARGET_68881 && TUNE_68040" >> @@ -2154,9 +2154,9 @@ >> return "fmovem%.l %!,%2\;moveq #16,%3\;or%.l %2,%3\;and%.w >> #-33,%3\;fmovem%.l %3,%!\;fmove%.w %1,%0\;fmovem%.l %2,%!"; >> }) >> >> -(define_insn "fix_truncdfqi2" >> +(define_insn "fix_truncqi2" >> [(set (match_operand:QI 0 "nonimmediate_operand" "=dm") >> -(fix:QI (fix:DF (match_operand:DF 1 "register_operand" "f" >> +(fix:QI (match_operand:FP 1 "register_operand" "f"))) >>(clobber (match_scratch:SI 2 "=d")) >>(clobber (match_scratch:SI 3 "=d"))] >> "TARGET_68881 && TUNE_68040" > > --
Re: Patches to fix GCC’s C++ exception handling on NetBSD/VAX
ndition code settings. On VAX, the default value is "clobber". ;; The V flag is often set to zero, or else it has a special meaning, ;; usually related to testing for a signed integer range overflow. ;; "cmp_czn", "cmp_zn", and "cmp_z" are all assumed to modify V, and ;; none is expected to modify C. "plus" is used after an add/sub, ;; when the flags, including C, return info about the result, ;; including a carry bit to use with, e.g. "adwc". ;; The important thing to note is that the C flag, in the case of "plus", ;; doesn't reflect the results of a signed integer comparison, ;; as "cmp_czn" does. Finally, "cmp_zn_use_c" and "cmp_z_use_cn" indicate ;; that all four flags are updated: Z and N, or Z alone, will be a comparison, ;; but C is set to 0, or some other value, instead of retaining its old value. ;; Only instructions of type "compare" set the C, Z, and N flags correctly ;; for both signed and unsigned ordered comparisons. ;; For branching, only Z is needed to test for equality, between two ;; operands or between the first operand and 0. The N flag is necessary ;; to test for less than zero, and for FP or signed integer comparisons. ;; Both N and Z are required to branch on signed (a <= b) or (a > b). ;; For comparing unsigned integers, the C flag is used instead of N. ;; Both C and Z are required to branch on unsigned (a <= b) or (a > b). ;; The VAX instruction set is biased towards leaving C alone, relative to ;; the other flags, which tend to be modified on almost every instruction. ;; It's possible to cache the results of two signed int comparison, ;; as long as they're of the form (a < b) or (a >= b), where b may be 0, ;; in the C flag, while other instructions modify the other flags. Then, ;; a test for a branch can be saved later by referring to the previous value. ;; The cc attributes are intended so that this optimization may be performed. (define_attr "cc" "none,cmp_czn,cmp_zn,cmp_zn_use_c, cmp_z,cmp_z_use_czn,plus,clobber" (const_string "clobber")) I'll send another email once I have something substantial to contribute. I give my permission to NetBSD and the FSF to integrate any or all of my changes under the copyright terms of the original files. Please let me know if I have to do any additional legal stuff for code contributions. I'm doing this on my own time and not on behalf of any company or organization. Best regards, Jake > On Mar 26, 2016, at 07:38, Jake Hamby wrote: > > Unfortunately, my previous patch that included a change to > gcc/config/vax/vax.h that increased FIRST_PSEUDO_REGISTER from 16 to 17 > breaks the C++ exception handling that I’d worked so hard to get right with > the rest of the patch. I believe I need to define DWARF_FRAME_REGISTERS to 16 > in the same file to fix the size of the array that libgcc/unwind-dw2.c > creates. The i386 backend and several others also define it their .h file for > the same reason (compatibility with hardcoded frame offsets). > > Here’s the first part of the patch to vax.h that increases > FIRST_PSEUDO_REGISTER and also adds a definition of DWARF_FRAME_REGISTERS as > 16, with suitable comment. I’m testing it now. I know that C++ exceptions > were working before I increased FIRST_PSEUDO_REGISTER to 17. > > Regards, > Jake > > Index: external/gpl3/gcc.old/dist/gcc/config/vax/vax.h > === > RCS file: /cvsroot/src/external/gpl3/gcc.old/dist/gcc/config/vax/vax.h,v > retrieving revision 1.3 > diff -u -r1.3 vax.h > --- external/gpl3/gcc.old/dist/gcc/config/vax/vax.h 23 Sep 2015 03:39:18 > - 1.3 > +++ external/gpl3/gcc.old/dist/gcc/config/vax/vax.h 26 Mar 2016 14:34:29 > - > @@ -119,13 +119,17 @@ >The hardware registers are assigned numbers for the compiler >from 0 to just below FIRST_PSEUDO_REGISTER. >All registers that the compiler knows about must be given numbers, > - even those that are not normally considered general registers. */ > -#define FIRST_PSEUDO_REGISTER 16 > + even those that are not normally considered general registers. > + This includes PSW, which the VAX backend did not originally include. */ > +#define FIRST_PSEUDO_REGISTER 17 > + > +/* For compatibility, DWARF_FRAME_REGISTERS must still be 16. */ > +#define DWARF_FRAME_REGISTERS 16 > > /* 1 for registers that have pervasive standard uses >and are not available for the register allocator. > - On the VAX, these are the AP, FP, SP and PC. */ > -#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1} > + On the VAX, these are the AP, FP, SP, PC, and PSW. */ > +#define FIXED_REGISTERS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1} > > /* 1 for registers not available across function calls. >These must include the FIXED_REGISTERS and also any >
Re: Patches to fix GCC’s C++ exception handling on NetBSD/VAX
The results you want to see for the test program are the following: throwtest(0) returned 0 throwtest(1) returned 1 Caught int exception: 123 Caught double exception: 123.45 Caught float exception: 678.900024 enter recursive_throw(6) calling recursive_throw(5) enter recursive_throw(5) calling recursive_throw(4) enter recursive_throw(4) calling recursive_throw(3) enter recursive_throw(3) calling recursive_throw(2) enter recursive_throw(2) calling recursive_throw(1) enter recursive_throw(1) calling recursive_throw(0) enter recursive_throw(0) throwing exception Caught int exception: 456 Before I made the changes I've submitted, this worked on m68k and presumably everywhere else but VAX. On VAX, it crashed due to the pointer size discrepancies that I already talked about. I believe that it should be possible to improve GCC's backend by allowing %ap to be used as an additional general register (removing it from FIXED_REGISTERS, but leaving it in CALL_USED_REGISTERS, since it's modified on CALLS), without breaking the DWARF stack unwinding stuff, since the .cfi information it's emitting notes the correct %fp offset to find the frame, which it actually uses instead of the %ap in stack unwinding. Gaining an additional general register to use within a function would be a nice win if it worked. But there are at two problems that must be solved before doing this (that I know of). The first is that certain combinations of VAX instructions and addressing modes seem to have problems when %ap, %fp, and/or %sp are used. I discovered this in the OpenVMS VAX Macro reference (which is essentially an updated version of the 1977 VAX architecture handbook), in Table 8-5, General Register Addressing. An additional source of info on which modes fail with address faults when AP or above is used, SimH's vax_cpu.c correctly handles this, and you can trace these macros to find the conditions: #define CHECK_FOR_PCif (rn == nPC) \ RSVD_ADDR_FAULT #define CHECK_FOR_SPif (rn >= nSP) \ RSVD_ADDR_FAULT #define CHECK_FOR_APif (rn >= nAP) \ RSVD_ADDR_FAULT So as long as the correct code is added to vax.md and vax.c to never emit move instructions under the wrong circumstances when %ap is involved, it could be used as a general register. I wonder if the use of %ap to find address arguments is a special case that happens to never emit anything that would fail (with a SIGILL, I believe). But the other problem with making %ap available as a general (with a few special cases) register is that it would break one part of the patch I submitted at the beginning of the thread to fix C++ exceptions. One necessary part of that fix was to change "#define FRAME_POINTER_CFA_OFFSET(FNDECL) 0" to "#define ARG_POINTER_CFA_OFFSET(FNDECL) 0", which correctly generates the code to return the value for __builtin_dwarf_cfa () (as an offset of 0 from %ap). When I was working on that fix, it seemed like it should be possible, since the DWARF / CFA code that's in there now is using an offset from %fp that it knows, that an improved fix would define FRAME_POINTER_CFA_OFFSET(FNDECL) as something that knows how to return the current CFA (canonical frame address) as an offset from %fp, since that's what it's using for all the .cfi_* directives. But I don't know what a correct definition of FRAME_POINTER_CFA_OFFSET should be in order for it to return that value, instead of 0, because I know that a 0 offset from %fp is definitely wrong, and it's not a fixed offset either (it depends on the number of registers saved in the procedure entry mask). Fortunately, %ap points directly to CFA, so that always works. Just some thoughts on future areas for improval... I'm very happy to be able to run the NetBSD testsuite on VAX now. It gives me a lot of confidence as to what works and what doesn't. Most of the stuff I expected to fail (like libm tests, since it's not IEEE FP) failed, and most of the rest succeeded. -Jake > On Mar 27, 2016, at 15:34, Jake Hamby wrote: > > I'm very pleased to report that I was able to successfully build a NetBSD/vax > system using the checked-in GCC 5.3, with the patches I've submitted, setting > FIRST_PSEUDO_REGISTER to 17 and DWARF_FRAME_REGISTERS to 16. The kernel > produced with GCC 5.3 crashes (on a real VS4000/90 and also SimH) in UVM, > which may be a bug in the kernel that different optimization exposed, or a > bug in GCC's generated code. > > If you don't set DWARF_FRAME_REGISTERS to 16, then C++ exceptions break > again, and GDB suddenly can't deal with the larger debug frames because of > the data structure size mismatch between GCC and GDB. But with that > additional define, you can raise FIRST_PSEUDO_REGISTER to include PSW (wh
Bad CC0 optimizer in VAX backend (was Re: Patches to fix GCC’s C++ exception handling on NetBSD/VAX)
tatus.flags = CC_NO_OVERFLOW; cc_status.value1 = SET_DEST (exp); cc_status.value2 = SET_SRC (exp); } + else if (cc != CC_NONE) + CC_STATUS_INIT; } else if (GET_CODE (exp) == PARALLEL && GET_CODE (XVECEXP (exp, 0, 0)) == SET) { - if (GET_CODE (SET_SRC (XVECEXP (exp, 0, 0))) == CALL) + rtx exp0 = XVECEXP (exp, 0, 0); + if (GET_CODE (SET_SRC (exp0)) == CALL) CC_STATUS_INIT; - else if (GET_CODE (SET_DEST (XVECEXP (exp, 0, 0))) != PC) + else if (GET_CODE (SET_DEST (exp0)) != PC + && cc == CC_COMPARE) { - cc_status.flags = 0; - cc_status.value1 = SET_DEST (XVECEXP (exp, 0, 0)); - cc_status.value2 = SET_SRC (XVECEXP (exp, 0, 0)); + cc_status.flags = CC_NO_OVERFLOW; + cc_status.value1 = SET_DEST (exp0); + cc_status.value2 = SET_SRC (exp0); } - else + else if (cc != CC_NONE) /* PARALLELs whose first element sets the PC are aob, sob insns. They do change the cc's. */ CC_STATUS_INIT; } - else + else if (cc != CC_NONE) CC_STATUS_INIT; + if (cc_status.value1 && REG_P (cc_status.value1) && cc_status.value2 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2)) @@ -1909,12 +1904,20 @@ return true; if (indirectable_address_p (x, strict, false)) return true; - xfoo0 = XEXP (x, 0); - if (MEM_P (x) && indirectable_address_p (xfoo0, strict, true)) -return true; - if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC) - && BASE_REGISTER_P (xfoo0, strict)) -return true; + /* Note: avoid calling XEXP until needed. It may not be a valid type. + This fixes an assertion failure when RTX checking is enabled. */ + if (MEM_P (x)) +{ + xfoo0 = XEXP (x, 0); + if (indirectable_address_p (xfoo0, strict, true)) + return true; +} + if (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC) +{ + xfoo0 = XEXP (x, 0); + if (BASE_REGISTER_P (xfoo0, strict)) + return true; +} return false; } > On Mar 27, 2016, at 16:06, Jake Hamby wrote: > > The results you want to see for the test program are the following: > > throwtest(0) returned 0 > throwtest(1) returned 1 > Caught int exception: 123 > Caught double exception: 123.45 > Caught float exception: 678.900024 > enter recursive_throw(6) > calling recursive_throw(5) > enter recursive_throw(5) > calling recursive_throw(4) > enter recursive_throw(4) > calling recursive_throw(3) > enter recursive_throw(3) > calling recursive_throw(2) > enter recursive_throw(2) > calling recursive_throw(1) > enter recursive_throw(1) > calling recursive_throw(0) > enter recursive_throw(0) > throwing exception > Caught int exception: 456 > > Before I made the changes I've submitted, this worked on m68k and presumably > everywhere else but VAX. On VAX, it crashed due to the pointer size > discrepancies that I already talked about. I believe that it should be > possible to improve GCC's backend by allowing %ap to be used as an additional > general register (removing it from FIXED_REGISTERS, but leaving it in > CALL_USED_REGISTERS, since it's modified on CALLS), without breaking the > DWARF stack unwinding stuff, since the .cfi information it's emitting notes > the correct %fp offset to find the frame, which it actually uses instead of > the %ap in stack unwinding. > > Gaining an additional general register to use within a function would be a > nice win if it worked. But there are at two problems that must be solved > before doing this (that I know of). The first is that certain combinations of > VAX instructions and addressing modes seem to have problems when %ap, %fp, > and/or %sp are used. I discovered this in the OpenVMS VAX Macro reference > (which is essentially an updated version of the 1977 VAX architecture > handbook), in Table 8-5, General Register Addressing. > > An additional source of info on which modes fail with address faults when AP > or above is used, SimH's vax_cpu.c correctly handles this, and you can trace > these macros to find the conditions: > > #define CHECK_FOR_PCif (rn == nPC) \ >RSVD_ADDR_FAULT > #define CHECK_FOR_SPif (rn >= nSP) \ >RSVD_ADDR_FAULT > #define CHECK_FOR_APif (rn >= nAP) \ >RSVD_ADDR_FAULT > > So as long as the correct code is added to vax.md and vax.c to never emit > move instructions under the wrong circumstances when %ap is involved, it > could be used as a general register. I wonder if the use of %ap to find > address arguments is a special case that happens to ne
Patches to fix optimizer bug & C++ exceptions for GCC VAX backend
Amazingly enough, my patch worked well enough that my NetBSD VAX kernel built with GCC 5.3 is no longer crashing. I feel pretty good about what I have so far so here's the complete diff for both the C++ exception fix and the bad condition codes optimizer bug. It should be good enough to check into NetBSD current, at least, and I believe it does fix most, if not all, of the bad code generation bugs with optimization on VAX. -Jake Index: gcc/except.c === RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/except.c,v retrieving revision 1.3 diff -u -r1.3 except.c --- gcc/except.c23 Mar 2016 15:51:36 - 1.3 +++ gcc/except.c28 Mar 2016 23:24:40 - @@ -2288,7 +2288,8 @@ #endif { #ifdef EH_RETURN_HANDLER_RTX - emit_move_insn (EH_RETURN_HANDLER_RTX, crtl->eh.ehr_handler); + rtx insn = emit_move_insn (EH_RETURN_HANDLER_RTX, crtl->eh.ehr_handler); + RTX_FRAME_RELATED_P (insn) = 1; // XXX FIXME in VAX backend? #else error ("__builtin_eh_return not supported on this target"); #endif Index: gcc/config/vax/builtins.md === RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/config/vax/builtins.md,v retrieving revision 1.5 diff -u -r1.5 builtins.md --- gcc/config/vax/builtins.md 24 Jan 2016 09:43:34 - 1.5 +++ gcc/config/vax/builtins.md 28 Mar 2016 23:24:40 - @@ -50,7 +50,8 @@ (ctz:SI (match_operand:SI 1 "general_operand" "nrmT"))) (set (cc0) (match_dup 0))] "" - "ffs $0,$32,%1,%0") + "ffs $0,$32,%1,%0" + [(set_attr "cc" "clobber")]) (define_expand "sync_lock_test_and_set" [(set (match_operand:VAXint 0 "nonimmediate_operand" "=&g") @@ -88,7 +89,8 @@ (match_dup 1)) (const_int 1))])] "" - "jbssi %1,%0,%l2") + "jbssi %1,%0,%l2" + [(set_attr "cc" "none")]) (define_insn "jbbssihi" [(parallel @@ -105,7 +107,8 @@ (match_dup 1)) (const_int 1))])] "" - "jbssi %1,%0,%l2") + "jbssi %1,%0,%l2" + [(set_attr "cc" "none")]) (define_insn "jbbssisi" [(parallel @@ -122,8 +125,8 @@ (match_dup 1)) (const_int 1))])] "" - "jbssi %1,%0,%l2") - + "jbssi %1,%0,%l2" + [(set_attr "cc" "none")]) (define_expand "sync_lock_release" [(set (match_operand:VAXint 0 "memory_operand" "+m") @@ -160,7 +163,8 @@ (match_dup 1)) (const_int 0))])] "" - "jbcci %1,%0,%l2") + "jbcci %1,%0,%l2" + [(set_attr "cc" "none")]) (define_insn "jbbccihi" [(parallel @@ -177,7 +181,8 @@ (match_dup 1)) (const_int 0))])] "" - "jbcci %1,%0,%l2") + "jbcci %1,%0,%l2" + [(set_attr "cc" "none")]) (define_insn "jbbccisi" [(parallel @@ -194,4 +199,5 @@ (match_dup 1)) (const_int 0))])] "" - "jbcci %1,%0,%l2") + "jbcci %1,%0,%l2" + [(set_attr "cc" "none")]) Index: gcc/config/vax/elf.h === RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/config/vax/elf.h,v retrieving revision 1.6 diff -u -r1.6 elf.h --- gcc/config/vax/elf.h23 Mar 2016 15:51:37 - 1.6 +++ gcc/config/vax/elf.h28 Mar 2016 23:24:40 - @@ -26,7 +26,7 @@ #define REGISTER_PREFIX "%" #define REGISTER_NAMES \ { "%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7", \ -"%r8", "%r9", "%r10", "%r11", "%ap", "%fp", "%sp", "%pc", } +"%r8", "%r9", "%r10", "%r11", "%ap", "%fp", "%sp", "%pc", "%psw", } #undef SIZE_TYPE #define SIZE_TYPE "long unsigned int" @@ -45,18 +45,8 @@ count pushed by the CALLS and before the start of the saved registers. */ #define INCOMING_FRAME_SP_OFFSET 0 -/* Offset from the frame pointer register value to the top of the stack. */ -#define FRAME_POINTER_CFA_OFFSET(FNDECL) 0 - -/* We use R2-R5 (call-clobbered) registers for exceptions. */ -#define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 2 : INVALID_REGNUM) - -/* Place the top of the stack for the DWARF2 EH stackadj value. */ -#define EH_RETURN_STACKADJ_RTX \ - gen_rtx_MEM (SImode, \ - plus_constant (Pmode,\ - gen_rtx_REG (Pmode, FRAME_POINTER_REGNUM),\ - -4)) +/* We use R2-R3 (call-clobbered) registers for exceptions. */ +#define EH_RETURN_DATA_REGNO(N) ((N) < 2 ? (N) + 2 : INVALID_REGNUM) /* Simple store the return handler into the call frame. */ #define EH_RETURN_HANDLER_RTX \ @@ -66,10 +56,6 @@ 16)) -/* Reserve the top of the stack for exception handler stackadj value. */ -#undef STARTING_FRAME_OFFSET -#define STARTING_FRAME_OFFSET -4 - /* The VAX wants no space
Re: Patches to fix optimizer bug & C++ exceptions for GCC VAX backend
Hi JBG, Thanks for the interest! Unfortunately, I need a few more days to work on this patch to clean it up and fix a few more bugs, then I'll send out a new version to NetBSD port-vax for testing, with ChangeLog entry. Please consider what I sent out earlier to be a work-in-progress at this point. The version I have on my machine is now generating bad code, after trying to change a few "clobbers" to "compares", so I need to fix those bugs and also further clean up some stuff that I know is broken. For example, there's some old code in vax.c marked "#if HOST_BITS_PER_WIDE_INT == 32" and "if (HOST_BITS_PER_WIDE_INT == 32)" that will never be used because HOST_WIDE_INT is now always 64 (in hwint.h). I found another bug in a NetBSD command (/usr/sbin/pkg_info) processing command-line arguments in main() that goes away at "-O0". That bug should be easy to track down considering the small size of the program and that it's failing immediately in main(). There's one more thing that's broken in the VAX backend which I'd *really* like to fix: GCC can't compile many of its own files at -O2, as well as a few other .c files in the NetBSD tree, because it can't expand an insn pattern. The Makefiles have hacks to add "-O0" on VAX, and when I remove that workaround, I get GCC assertion failures, all of the form: /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/builtins.c: In function 'void maybe_emit_chk_warning(tree, built_in_function)': /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/builtins.c:11549:1: error: unrecognizable insn: } ^ (insn 295 294 296 25 (set (reg:SI 111) (subreg:SI (mem:DI (plus:SI (mult:SI (reg:SI 109) (const_int 8 [0x8])) (reg/f:SI 45 [ D.85015 ])) [7 *_98+0 S8 A32]) 4)) /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/wide-int.h:799 -1 (nil)) /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/builtins.c:11549:1: internal compiler error: in extract_insn, at recog.c:2343 0xbd0365 _fatal_insn(char const*, rtx_def const*, char const*, int, char const*) /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/rtl-error.c:110 0xbd03fa _fatal_insn_not_found(rtx_def const*, char const*, int, char const*) /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/rtl-error.c:118 0xb92a2d extract_insn(rtx_insn*) /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/recog.c:2343 0x9612cd instantiate_virtual_regs_in_insn /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/function.c:1598 0x9612cd instantiate_virtual_regs /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/function.c:1966 0x9612cd execute /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/function.c:2015 The failures all seem to be related to trying to read a value from an array of 64-bit values and loading it into a 32-bit register. It seems like there should be a special insn defined for this sort of array access, since VAX has mova* and pusha* variants to set a value from an address plus an index into a byte, word, long, or 64-bit array (it uses movab/pushab, put not the other variants). The addressing modes, constraints, and predicates all get very complicated, and I still need to understand a bit better what is actually required, and what could be simplified and cleaned up. If anyone has suggestions on how to define an instruction that would solve the previous failure, please let me know. Even without a special pattern for the "(plus:SI (mult:SI (reg:SI) (const_int 8)))", it should be able to generate something. It seems like it's expanding something and then the insn that's supposed to go with it isn't matching. I tried adding define_insns for "movstrictsi" and for "truncdisi2", hoping that one of them would solve the "(set (reg:SI (subreg:SI (mem:DI (...)" part of the situation, but it didn't help. The "(subreg:SI)" stuff is strange, and I don't understand exactly what GCC is expecting the backend to define. I'll keep working on things and as soon as I have something that I think is in a contributable state and doesn't generate bad code, I'll email it. Best regards, Jake > On Mar 31, 2016, at 07:30, Jan-Benedict Glaw wrote: > > Hi Jake! > > On Mon, 2016-03-28 16:34:56 -0700, Jake Hamby wrote: >> Amazingly enough, my patch worked well enough that my NetBSD VAX >> kernel built with GCC 5.3 is no longer crashing. I feel pretty good >> about what I have so far so here's the complete diff for both the >> C++ exception fix and the bad condition codes optimizer bug. It >> should be good enough to check into NetBSD current, at least, an
Re: Patches to fix optimizer bug & C++ exceptions for GCC VAX backend
Hi, I apologize for the poor quality of the initial version of the patch that I submitted. I think I may have also mangled it by not disabling the "smart quotes" feature on my Mac before I pasted in the diff from the terminal window. I intentionally did not use gmail for fear of adding word wraps or converting tabs to spaces, but apparently I mangled the patch anyway. I emailed Christos a .tar.gz version separately. Yes, the file you highlighted is definitely not correct and I need to figure out how to fix it properly. For some reason the optimizer is deleting the emit_move_insn() on VAX, while it seems to work on all the other platforms that define EH_RETURN_HANDLER_RTX() and depend on that instruction. So I'm looking into fixing it in gcc/config/vax/something. My next step to try to figure out what's going on is to dump the trees for all the phases when building unwind-dw2.o (the only file where __builtin_eh_return() has to work in GCC when libgcc is compiled in order for C++ exceptions to work) with and without "-O", and figure out when the instruction is being deleted and why. This only affects functions that call __builtin_eh_return() instead of return, but I think cc1plus may also need it to be defined correctly for some code that it generates. My theory is that it has to do with liveness detection and a write into the stack frame being incorrectly seen as updating a local variable, but that could be completely wrong. I was hoping that by cc'ing gcc-patches that somebody more familiar with why some phase of the optimizer might decide to delete this particular insn that copies data into the stack (to overwrite the return address, e.g. to move to EH_RETURN_HANDLER_RTX) immediately before returning. So far I haven't found any actual bugs in GCC that should be fixed. Perhaps it isn't correct to check in a hack like the change to gcc/except.c into netbsd-current except temporarily, until there's a correct fix for that part of the issue, which is what I'd like to figure out. In the meantime, I would highly recommend adding an #ifdef __vax around that line to avoid trouble with the other ports. Now that I think about it, please do not check in the patch to gcc/dist/gcc/except.c without an #ifdef __vax, and certainly this isn't ready to go into GCC mainline. But I think it will be ready with a few more adjustments. The important thing is that I think most, if not all of the necessary fixes will be entirely modifications to VAX-related files that can be locally patched in NetBSD regardless of whether the GCC maintainers accept them or not. To be honest, my hope by sending out my work now, even in such a rough state, would be to try to avoid deprecating the GCC port to VAX, if only because: 1) there doesn't seem to be a compelling reason to remove support for it since it doesn't use any really old code paths that aren't also used by other backends (e.g. m68k and Atmel AVR use cc0, IBM S/390 uses non-IEEE FP formats), so it doesn't seem to be preventing any optimizations or code refactoring elsewhere in GCC that I could see, 2) even though NetBSD could continue to support VAX GCC, I noticed in the ChangeLogs that whenever somebody has made a change to a definition that affects the backends, they're usually very good about updating all of the backends so that they continue to compile, at least. So leaving the VAX backend in the tree would be beneficial from a maintenance standpoint for users of it, 3) the VAX backend is perhaps somewhat useful as a test case for GCC because so many unusual RTX standard instructions were obviously defined *for* it (although x86 defines a lot of them, too), although my interest is personally in preserving an interesting piece of computer history, and for nostalgia purposes. I sent an earlier email to port-vax suggesting that future discussions of this project aren't relevant to gcc-patches, but I did want to get it on a few people's radar on the NetBSD side and try to solicit a bit of help on the questions I had as to how to avoid having to add that hack to gcc/except.c to make the optimizer not delete the insns. All of the other stuff can be worked on in NetBSD-current and avoid bothering the 99% of people who subscribe to gcc-patches who have no interest in the VAX backend. Best regards, Jake > On Apr 1, 2016, at 04:37, Bernd Schmidt wrote: > > Cc'ing Matt Thomas who is listed as the vax maintainer; most of the patch > should be reviewed by him IMO. If he is no longer active I'd frankly rather > deprecate the port rather than invest effort in keeping it running. > >> Index: gcc/except.c >> === >> RCS file: /cvsroot/src/external/gpl3/gcc/dist/gcc/except.c,v >> retrieving revision 1.3 >> diff -u -r1.3 except.c >> --- gcc/except.c 23 Mar 2016 15:51:36 - 1.3 >> +++ gcc/except.c 28 Mar 2016 23:24:40 - >> @@ -2288,7 +2288,8 @@ >> #en
Re: Patches to fix optimizer bug & C++ exceptions for GCC VAX backend
> On Apr 4, 2016, at 07:51, Maciej W. Rozycki wrote: > > On Thu, 31 Mar 2016, Jake Hamby wrote: > >> There's one more thing that's broken in the VAX backend which I'd >> *really* like to fix: GCC can't compile many of its own files at -O2, as >> well as a few other .c files in the NetBSD tree, because it can't expand >> an insn pattern. The Makefiles have hacks to add "-O0" on VAX, and when >> I remove that workaround, I get GCC assertion failures, all of the form: >> >> /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/builtins.c: In function >> 'void maybe_emit_chk_warning(tree, built_in_function)': >> /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/builtins.c:11549:1: >> error: unrecognizable insn: >> } >> ^ >> (insn 295 294 296 25 (set (reg:SI 111) >>(subreg:SI (mem:DI (plus:SI (mult:SI (reg:SI 109) >>(const_int 8 [0x8])) >>(reg/f:SI 45 [ D.85015 ])) [7 *_98+0 S8 A32]) 4)) >> /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/wide-int.h:799 -1 >> (nil)) >> /home/netbsd/current/src/external/gpl3/gcc/dist/gcc/builtins.c:11549:1: >> internal compiler error: in extract_insn, at recog.c:2343 >> 0xbd0365 _fatal_insn(char const*, rtx_def const*, char const*, int, char >> const*) >> >> /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/rtl-error.c:110 >> 0xbd03fa _fatal_insn_not_found(rtx_def const*, char const*, int, char const*) >> >> /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/rtl-error.c:118 >> 0xb92a2d extract_insn(rtx_insn*) >> >> /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/recog.c:2343 >> 0x9612cd instantiate_virtual_regs_in_insn >> >> /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/function.c:1598 >> 0x9612cd instantiate_virtual_regs >> >> /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/function.c:1966 >> 0x9612cd execute >> >> /home/netbsd/current/src/tools/gcc/../../external/gpl3/gcc/dist/gcc/function.c:2015 >> >> The failures all seem to be related to trying to read a value from an >> array of 64-bit values and loading it into a 32-bit register. It seems >> like there should be a special insn defined for this sort of array >> access, since VAX has mova* and pusha* variants to set a value from an >> address plus an index into a byte, word, long, or 64-bit array (it uses >> movab/pushab, put not the other variants). The addressing modes, >> constraints, and predicates all get very complicated, and I still need >> to understand a bit better what is actually required, and what could be >> simplified and cleaned up. > > Please note however that this RTL instruction is a memory reference, not > an address load. So the suitable hardware instruction would be MOVAQ for > an indexed DI mode memory load. If used to set a SI mode subreg at byte > number 4 (this would be the second hardware register of a pair a DI mode > value is held in) as seen here, it would have to address the immediately > preceding register however (so you can't load R0 this way) and it would > clobber it. > > So offhand I think you need an RTL instruction splitter to express this, > and then avoid fetching 64 bits worth of data from memory -- for the sake > of matching the indexed addressing mode -- where you only need 32 bits. > At the hardware instruction level I'd use a scratch register (as with > MOVAQ you'd have to waste one anyway) to scale the index and then use > MOVAL instead with the modified index. Where no index is used it gets > simpler even as you can just bump up the displacement according to the > subreg offset. Thanks for the info! I've discovered a few additional clues which should help, namely the optimizer pass that's introducing the problem. Through process of elimination, I discovered that adding "-fno-tree-ter" will prevent the unrecognizable insn error. Strangely, I can't cause the problem by using "-ftree-ter" and -O0, which seems odd, unless the code is checking directly for a -O flag. Here's an example of a similar line of code (it seems to be triggered by accessing a 64-bit int array embedded inside a struct) that fails w/ -O, but succeeded with the addition of -fno-tree-ter (assembly output with "-dP"): #(insn 682 680 686 (set (reg:DI 0 %r0 [orig:136 D.5219 ] [136]) #(mem:DI (plus:SI (plus:SI (mult:SI (reg/v:SI 11 %r11 [orig:138 j ] [138]) #(const_int 8 [0x8])) #