From 47501014fa60b2b20e33477338d91b7d55c69f9b Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 2 Jan 2008 18:47:08 +0000 Subject: buildroot snapshot git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@480 42af7a65-404d-4744-a932-0658087f49c3 --- .../toolchain/gcc/3.3.5/120-softfloat.patch | 14 + misc/buildroot/toolchain/gcc/3.3.5/500-loop.patch | 10 + .../toolchain/gcc/3.3.5/800-arm-bigendian.patch | 68 + .../gcc/3.3.5/820-no-mips-empic-relocs.patch | 59 + .../gcc/3.3.5/830-gcc-bug-num-22167.patch | 16 + .../toolchain/gcc/3.3.5/999-cvs-updates.patch | 4522 ++++++++ .../toolchain/gcc/3.3.5/specs-arm-soft-float | 124 + .../toolchain/gcc/3.3.5/specs-mips-soft-float | 145 + .../toolchain/gcc/3.3.5/specs-mipsel-soft-float | 145 + .../toolchain/gcc/3.3.5/specs-powerpc-soft-float | 352 + .../toolchain/gcc/3.3.6/120-softfloat.patch | 14 + misc/buildroot/toolchain/gcc/3.3.6/500-loop.patch | 10 + .../toolchain/gcc/3.3.6/800-arm-bigendian.patch | 68 + .../toolchain/gcc/3.3.6/810-mips-xgot.patch | 6 + .../gcc/3.3.6/820-no-mips-empic-relocs.patch | 59 + .../gcc/3.3.6/830-gcc-bug-num-22167.patch | 16 + .../toolchain/gcc/3.4.2/300-libstdc++-pic.patch | 47 + .../toolchain/gcc/3.4.2/300-pr15526.patch | 53 + .../toolchain/gcc/3.4.2/300-pr17541.patch | 234 + .../toolchain/gcc/3.4.2/300-pr17976.patch | 106 + .../toolchain/gcc/3.4.2/400-mips-pr17565.patch | 102 + .../toolchain/gcc/3.4.2/401-ppc-eabi-typo.patch | 20 + .../toolchain/gcc/3.4.2/402-mips-pr17770.patch | 12 + .../gcc/3.4.2/600-gcc34-arm-ldm-peephole.patch | 79 + .../toolchain/gcc/3.4.2/601-gcc34-arm-ldm.patch | 119 + .../gcc/3.4.2/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/3.4.2/700-pr15068-fix.patch | 44 + .../toolchain/gcc/3.4.2/800-arm-bigendian.patch | 68 + .../gcc/3.4.2/830-gcc-bug-num-22167.patch | 16 + misc/buildroot/toolchain/gcc/3.4.2/900-nios2.patch | 10211 +++++++++++++++++++ .../gcc/3.4.2/arm-softfloat.patch.conditional | 270 + .../toolchain/gcc/3.4.3/300-libstdc++-pic.patch | 47 + .../gcc/3.4.3/600-gcc34-arm-ldm-peephole.patch | 79 + .../toolchain/gcc/3.4.3/601-gcc34-arm-ldm.patch | 119 + .../gcc/3.4.3/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/3.4.3/700-pr15068-fix.patch | 44 + .../toolchain/gcc/3.4.3/800-arm-bigendian.patch | 68 + .../gcc/3.4.3/830-gcc-bug-num-22167.patch | 16 + misc/buildroot/toolchain/gcc/3.4.3/900-nios2.patch | 10211 +++++++++++++++++++ .../gcc/3.4.3/arm-softfloat.patch.conditional | 270 + .../toolchain/gcc/3.4.4/300-libstdc++-pic.patch | 47 + .../gcc/3.4.4/600-gcc34-arm-ldm-peephole.patch | 65 + .../gcc/3.4.4/601-gcc34-arm-ldm-peephole2.patch | 42 + .../toolchain/gcc/3.4.4/601-gcc34-arm-ldm.patch | 119 + .../gcc/3.4.4/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/3.4.4/700-pr15068-fix.patch | 44 + .../gcc/3.4.4/71_all_sh-pr16665-fix.patch | 43 + .../gcc/3.4.4/72_all_sh-no-reorder-blocks.patch | 13 + .../toolchain/gcc/3.4.4/73_all_sh-pr20617.patch | 28 + .../toolchain/gcc/3.4.4/800-arm-bigendian.patch | 68 + .../gcc/3.4.4/830-gcc-bug-num-22167.patch | 16 + misc/buildroot/toolchain/gcc/3.4.4/900-nios2.patch | 10211 +++++++++++++++++++ .../gcc/3.4.4/arm-softfloat.patch.conditional | 270 + .../toolchain/gcc/3.4.5/300-libstdc++-pic.patch | 47 + .../gcc/3.4.5/600-gcc34-arm-ldm-peephole.patch | 65 + .../gcc/3.4.5/601-gcc34-arm-ldm-peephole2.patch | 42 + .../toolchain/gcc/3.4.5/601-gcc34-arm-ldm.patch | 119 + .../gcc/3.4.5/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/3.4.5/700-pr15068-fix.patch | 44 + .../gcc/3.4.5/71_all_sh-pr16665-fix.patch | 43 + .../gcc/3.4.5/72_all_sh-no-reorder-blocks.patch | 13 + .../toolchain/gcc/3.4.5/73_all_sh-pr20617.patch | 28 + .../toolchain/gcc/3.4.5/800-arm-bigendian.patch | 68 + misc/buildroot/toolchain/gcc/3.4.5/900-nios2.patch | 10211 +++++++++++++++++++ .../gcc/3.4.5/arm-softfloat.patch.conditional | 270 + .../toolchain/gcc/3.4.6/300-libstdc++-pic.patch | 47 + .../toolchain/gcc/3.4.6/304-index_macro.patch | 24 + .../gcc/3.4.6/600-gcc34-arm-ldm-peephole.patch | 65 + .../gcc/3.4.6/601-gcc34-arm-ldm-peephole2.patch | 42 + .../toolchain/gcc/3.4.6/601-gcc34-arm-ldm.patch | 119 + .../gcc/3.4.6/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/3.4.6/700-pr15068-fix.patch | 44 + .../gcc/3.4.6/71_all_sh-pr16665-fix.patch | 43 + .../gcc/3.4.6/72_all_sh-no-reorder-blocks.patch | 13 + .../toolchain/gcc/3.4.6/73_all_sh-pr20617.patch | 28 + .../toolchain/gcc/3.4.6/800-arm-bigendian.patch | 68 + .../toolchain/gcc/3.4.6/810-mips-xgot.patch | 6 + misc/buildroot/toolchain/gcc/3.4.6/900-nios2.patch | 10211 +++++++++++++++++++ .../gcc/3.4.6/arm-softfloat.patch.conditional | 270 + .../toolchain/gcc/4.0.0/300-libstdc++-pic.patch | 45 + .../gcc/4.0.0/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.0.0/302-c99-snprintf.patch | 11 + .../gcc/4.0.0/303-c99-complex-ugly-hack.patch | 12 + .../gcc/4.0.0/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/4.0.0/800-arm-bigendian.patch | 67 + .../gcc/4.0.0/830-gcc-bug-num-22167.patch | 16 + .../toolchain/gcc/4.0.1/300-libstdc++-pic.patch | 45 + .../gcc/4.0.1/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.0.1/302-c99-snprintf.patch | 11 + .../gcc/4.0.1/303-c99-complex-ugly-hack.patch | 12 + .../gcc/4.0.1/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/4.0.1/800-arm-bigendian.patch | 67 + .../gcc/4.0.1/830-gcc-bug-num-22167.patch | 16 + .../toolchain/gcc/4.0.2/300-libstdc++-pic.patch | 45 + .../gcc/4.0.2/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.0.2/302-c99-snprintf.patch | 11 + .../gcc/4.0.2/303-c99-complex-ugly-hack.patch | 12 + .../gcc/4.0.2/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/4.0.2/800-arm-bigendian.patch | 67 + .../toolchain/gcc/4.0.3/300-libstdc++-pic.patch | 45 + .../gcc/4.0.3/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.0.3/302-c99-snprintf.patch | 11 + .../gcc/4.0.3/303-c99-complex-ugly-hack.patch | 12 + .../toolchain/gcc/4.0.3/304-index_macro.patch | 24 + .../gcc/4.0.3/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/4.0.3/800-arm-bigendian.patch | 67 + .../toolchain/gcc/4.0.4/300-libstdc++-pic.patch | 45 + .../gcc/4.0.4/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.0.4/302-c99-snprintf.patch | 11 + .../gcc/4.0.4/303-c99-complex-ugly-hack.patch | 12 + .../toolchain/gcc/4.0.4/304-index_macro.patch | 24 + .../gcc/4.0.4/305-libmudflap-susv3-legacy.patch | 49 + .../gcc/4.0.4/402-libbackend_dep_gcov-iov.h.patch | 11 + .../gcc/4.0.4/602-sdk-libstdc++-includes.patch | 22 + .../toolchain/gcc/4.0.4/800-arm-bigendian.patch | 67 + .../toolchain/gcc/4.1.0/110-arm-eabi.patch | 27 + .../toolchain/gcc/4.1.0/300-libstdc++-pic.patch | 46 + .../gcc/4.1.0/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.1.0/302-c99-snprintf.patch | 11 + .../gcc/4.1.0/303-c99-complex-ugly-hack.patch | 12 + .../toolchain/gcc/4.1.0/304-index_macro.patch | 24 + .../toolchain/gcc/4.1.0/740-sh-pr24836.patch | 25 + .../toolchain/gcc/4.1.0/800-arm-bigendian.patch | 67 + .../toolchain/gcc/4.1.1/110-arm-eabi.patch | 27 + .../toolchain/gcc/4.1.1/300-libstdc++-pic.patch | 50 + .../gcc/4.1.1/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.1.1/302-c99-snprintf.patch | 11 + .../gcc/4.1.1/303-c99-complex-ugly-hack.patch | 12 + .../toolchain/gcc/4.1.1/304-index_macro.patch | 24 + .../toolchain/gcc/4.1.1/740-sh-pr24836.patch | 25 + .../toolchain/gcc/4.1.1/800-arm-bigendian.patch | 67 + .../toolchain/gcc/4.1.2/110-arm-eabi.patch | 27 + .../toolchain/gcc/4.1.2/300-libstdc++-pic.patch | 50 + .../gcc/4.1.2/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.1.2/302-c99-snprintf.patch | 11 + .../gcc/4.1.2/303-c99-complex-ugly-hack.patch | 12 + .../toolchain/gcc/4.1.2/304-index_macro.patch | 24 + .../gcc/4.1.2/402-libbackend_dep_gcov-iov.h.patch | 12 + .../toolchain/gcc/4.1.2/740-sh-pr24836.patch | 25 + .../toolchain/gcc/4.1.2/800-arm-bigendian.patch | 127 + .../toolchain/gcc/4.2/300-libstdc++-pic.patch | 50 + .../toolchain/gcc/4.2/301-missing-execinfo_h.patch | 11 + .../toolchain/gcc/4.2/302-c99-snprintf.patch | 11 + .../gcc/4.2/303-c99-complex-ugly-hack.patch | 12 + .../toolchain/gcc/4.2/304-index_macro.patch | 24 + .../gcc/4.2/305-libmudflap-susv3-legacy.patch | 49 + .../gcc/4.2/306-libstdc++-namespace.patch | 36 + .../gcc/4.2/402-libbackend_dep_gcov-iov.h.patch | 13 + .../toolchain/gcc/4.2/800-arm-bigendian.patch | 67 + misc/buildroot/toolchain/gcc/Config.in | 153 + misc/buildroot/toolchain/gcc/Config.in.2 | 14 + misc/buildroot/toolchain/gcc/Makefile.in | 66 + misc/buildroot/toolchain/gcc/gcc-nuttx-3.x.mk | 435 + .../toolchain/gcc/i386-gcc-soft-float.patch | 61 + 154 files changed, 63600 insertions(+) create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/120-softfloat.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/500-loop.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/820-no-mips-empic-relocs.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/830-gcc-bug-num-22167.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/999-cvs-updates.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/specs-arm-soft-float create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/specs-mips-soft-float create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/specs-mipsel-soft-float create mode 100644 misc/buildroot/toolchain/gcc/3.3.5/specs-powerpc-soft-float create mode 100644 misc/buildroot/toolchain/gcc/3.3.6/120-softfloat.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.6/500-loop.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.6/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.6/810-mips-xgot.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.6/820-no-mips-empic-relocs.patch create mode 100644 misc/buildroot/toolchain/gcc/3.3.6/830-gcc-bug-num-22167.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/300-pr15526.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/300-pr17541.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/300-pr17976.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/400-mips-pr17565.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/401-ppc-eabi-typo.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/402-mips-pr17770.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/600-gcc34-arm-ldm-peephole.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/601-gcc34-arm-ldm.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/700-pr15068-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/830-gcc-bug-num-22167.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/900-nios2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.2/arm-softfloat.patch.conditional create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/600-gcc34-arm-ldm-peephole.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/601-gcc34-arm-ldm.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/700-pr15068-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/830-gcc-bug-num-22167.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/900-nios2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.3/arm-softfloat.patch.conditional create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/600-gcc34-arm-ldm-peephole.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm-peephole2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/700-pr15068-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/71_all_sh-pr16665-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/72_all_sh-no-reorder-blocks.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/73_all_sh-pr20617.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/830-gcc-bug-num-22167.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/900-nios2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.4/arm-softfloat.patch.conditional create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/600-gcc34-arm-ldm-peephole.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm-peephole2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/700-pr15068-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/71_all_sh-pr16665-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/72_all_sh-no-reorder-blocks.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/73_all_sh-pr20617.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/900-nios2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.5/arm-softfloat.patch.conditional create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/304-index_macro.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/600-gcc34-arm-ldm-peephole.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm-peephole2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/700-pr15068-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/71_all_sh-pr16665-fix.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/72_all_sh-no-reorder-blocks.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/73_all_sh-pr20617.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/810-mips-xgot.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/900-nios2.patch create mode 100644 misc/buildroot/toolchain/gcc/3.4.6/arm-softfloat.patch.conditional create mode 100644 misc/buildroot/toolchain/gcc/4.0.0/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.0/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.0/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.0/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.0/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.0/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.0/830-gcc-bug-num-22167.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.1/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.1/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.1/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.1/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.1/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.1/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.1/830-gcc-bug-num-22167.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.2/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.2/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.2/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.2/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.2/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.2/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.3/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.3/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.3/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.3/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.3/304-index_macro.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.3/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.3/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/304-index_macro.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/305-libmudflap-susv3-legacy.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/402-libbackend_dep_gcov-iov.h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/602-sdk-libstdc++-includes.patch create mode 100644 misc/buildroot/toolchain/gcc/4.0.4/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/110-arm-eabi.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/304-index_macro.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/740-sh-pr24836.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.0/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/110-arm-eabi.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/304-index_macro.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/740-sh-pr24836.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.1/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/110-arm-eabi.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/304-index_macro.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/402-libbackend_dep_gcov-iov.h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/740-sh-pr24836.patch create mode 100644 misc/buildroot/toolchain/gcc/4.1.2/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/300-libstdc++-pic.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/301-missing-execinfo_h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/302-c99-snprintf.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/303-c99-complex-ugly-hack.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/304-index_macro.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/305-libmudflap-susv3-legacy.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/306-libstdc++-namespace.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/402-libbackend_dep_gcov-iov.h.patch create mode 100644 misc/buildroot/toolchain/gcc/4.2/800-arm-bigendian.patch create mode 100644 misc/buildroot/toolchain/gcc/Config.in create mode 100644 misc/buildroot/toolchain/gcc/Config.in.2 create mode 100644 misc/buildroot/toolchain/gcc/Makefile.in create mode 100644 misc/buildroot/toolchain/gcc/gcc-nuttx-3.x.mk create mode 100644 misc/buildroot/toolchain/gcc/i386-gcc-soft-float.patch (limited to 'misc/buildroot/toolchain/gcc') diff --git a/misc/buildroot/toolchain/gcc/3.3.5/120-softfloat.patch b/misc/buildroot/toolchain/gcc/3.3.5/120-softfloat.patch new file mode 100644 index 000000000..f2431896c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/120-softfloat.patch @@ -0,0 +1,14 @@ +--- gcc-3.3.2-old/configure.in 2003-08-09 01:57:21.000000000 -0500 ++++ gcc-3.3.2/configure.in 2004-01-15 12:46:29.000000000 -0600 +@@ -1418,6 +1418,11 @@ + fi + + FLAGS_FOR_TARGET= ++case " $targargs " in ++ *" --nfp "* | *" --without-float "*) ++ FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -msoft-float' ++ ;; ++esac + case " $target_configdirs " in + *" newlib "*) + case " $targargs " in diff --git a/misc/buildroot/toolchain/gcc/3.3.5/500-loop.patch b/misc/buildroot/toolchain/gcc/3.3.5/500-loop.patch new file mode 100644 index 000000000..476f84b37 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/500-loop.patch @@ -0,0 +1,10 @@ +--- gcc/gcc/loop.c 14 Feb 2004 14:46:03 -0000 1.488.2.3 ++++ gcc/gcc/loop.c 28 Apr 2004 22:02:53 -0000 +@@ -929,6 +929,7 @@ + || (! (GET_CODE (SET_SRC (set)) == REG + && (REGNO (SET_SRC (set)) + < FIRST_PSEUDO_REGISTER)))) ++ && regno >= FIRST_PSEUDO_REGISTER + /* This test is not redundant; SET_SRC (set) might be + a call-clobbered register and the life of REGNO + might span a call. */ diff --git a/misc/buildroot/toolchain/gcc/3.3.5/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/3.3.5/800-arm-bigendian.patch new file mode 100644 index 000000000..79140ddf0 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/800-arm-bigendian.patch @@ -0,0 +1,68 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-3.3.5-dist/gcc/config/arm/linux-elf.h ++++ gcc-3.3.5/gcc/config/arm/linux-elf.h +@@ -30,17 +30,34 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + /* Default is to use APCS-32 mode. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 | \ ++ ARM_FLAG_MMU_TRAPS | \ ++ TARGET_ENDIAN_DEFAULT ) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -100,7 +117,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + #endif + +--- gcc-3.3.5-dist/gcc/config.gcc ++++ gcc-3.3.5/gcc/config.gcc +@@ -710,6 +710,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="t-slibgcc-elf-ver t-linux arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/3.3.5/820-no-mips-empic-relocs.patch b/misc/buildroot/toolchain/gcc/3.3.5/820-no-mips-empic-relocs.patch new file mode 100644 index 000000000..d5c4c9cb5 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/820-no-mips-empic-relocs.patch @@ -0,0 +1,59 @@ +From: cgd at broadcom dot com +To: gcc-patches at gcc dot gnu dot org +Cc: mark at codesourcery dot com +Date: 13 Jun 2004 22:51:30 -0700 +Subject: [trunk + 3.4-branch RFA] don't use empic relocs for mips-linuxeh + +This patch changes mips-linux to avoid using embedded-pic relocs for +its eh data. (Support for generating these for new code is removed in +current binutils srcs.) + +Relating to this, previously, mips-linux and mips64-linux would use +different representations for their EH data (even for mips64-linux o32 +abi), due to the mips64-linux n32/64 BFDs not supporting the +embedded-pic relocs. This was a bug. + +For more explanation, see the thread of the URL quoted in the comment +in linux.h. + + +Tested the same w/ sources of about a week ago for c/c++ for +mips-linux (native) before/after. Also verified .o compatibility +before/after just to be sure. + +I'd like this approved for the branch as well, so 3.4.1 will work +nicely w/ the next major binutils release. + + +thanks, + +chris + +2004-06-13 Chris Demetriou + + * config/mips/linux.h (ASM_PREFERRED_EH_DATA_FORMAT): Redefine + to return DW_EH_PE_absptr. + +Index: config/mips/linux.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/mips/linux.h,v +retrieving revision 1.77 +diff -u -p -r1.77 linux.h +--- gcc/gcc/config/mips/linux.h 19 Feb 2004 22:07:51 -0000 1.77 ++++ gcc/gcc/config/mips/linux.h 14 Jun 2004 05:49:51 -0000 +@@ -170,10 +170,11 @@ Boston, MA 02111-1307, USA. */ + #undef FUNCTION_NAME_ALREADY_DECLARED + #define FUNCTION_NAME_ALREADY_DECLARED 1 + +-#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ +- (flag_pic \ +- ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4\ +- : DW_EH_PE_absptr) ++/* If possible, we should attempt to use GP-relative relocs for this ++ (see http://sources.redhat.com/ml/binutils/2004-05/msg00227.html). ++ However, until that is implement, this just uses standard, absolute ++ references. */ ++#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) DW_EH_PE_absptr + + /* The glibc _mcount stub will save $v0 for us. Don't mess with saving + it, since ASM_OUTPUT_REG_PUSH/ASM_OUTPUT_REG_POP do not work in the diff --git a/misc/buildroot/toolchain/gcc/3.3.5/830-gcc-bug-num-22167.patch b/misc/buildroot/toolchain/gcc/3.3.5/830-gcc-bug-num-22167.patch new file mode 100644 index 000000000..c7419af90 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/830-gcc-bug-num-22167.patch @@ -0,0 +1,16 @@ +Index: gcc/gcse.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gcse.c,v +retrieving revision 1.288.2.9 +diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.288.2.9 gcse.c +--- gcc/gcc/gcse.c 30 Oct 2004 18:02:53 -0000 1.288.2.9 ++++ gcc/gcc/gcse.c 14 Jul 2005 13:19:57 -0000 +@@ -6445,7 +6445,7 @@ hoist_code (void) + insn_inserted_p = 0; + + /* These tests should be the same as the tests above. */ +- if (TEST_BIT (hoist_vbeout[bb->index], i)) ++ if (TEST_BIT (hoist_exprs[bb->index], i)) + { + /* We've found a potentially hoistable expression, now + we look at every block BB dominates to see if it diff --git a/misc/buildroot/toolchain/gcc/3.3.5/999-cvs-updates.patch b/misc/buildroot/toolchain/gcc/3.3.5/999-cvs-updates.patch new file mode 100644 index 000000000..5d3e8c68a --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/999-cvs-updates.patch @@ -0,0 +1,4522 @@ +Index: ChangeLog +=================================================================== +RCS file: /cvs/gcc/gcc/ChangeLog,v +retrieving revision 1.621.2.52 +retrieving revision 1.621.2.53 +diff -u -r1.621.2.52 -r1.621.2.53 +--- gcc/ChangeLog 30 Sep 2004 16:47:59 -0000 1.621.2.52 ++++ gcc/ChangeLog 6 Oct 2004 12:00:52 -0000 1.621.2.53 +@@ -1,3 +1,7 @@ ++2004-10-06 Josef Zlomek ++ ++ * MAINTAINERS: Update my e-mail address. ++ + 2004-09-30 Release Manager + + * GCC 3.3.5 Released. +Index: MAINTAINERS +=================================================================== +RCS file: /cvs/gcc/gcc/MAINTAINERS,v +retrieving revision 1.253.2.18 +retrieving revision 1.253.2.19 +diff -u -r1.253.2.18 -r1.253.2.19 +--- gcc/MAINTAINERS 16 Jan 2004 23:33:12 -0000 1.253.2.18 ++++ gcc/MAINTAINERS 6 Oct 2004 12:00:53 -0000 1.253.2.19 +@@ -258,7 +258,7 @@ + John Wehle john@feith.com + Florian Weimer fw@deneb.enyo.de + Mark Wielaard mark@gcc.gnu.org +-Josef Zlomek zlomekj@suse.cz ++Josef Zlomek josef.zlomek@email.cz + + GNATS only accounts + +Index: gcc/ChangeLog +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/ChangeLog,v +retrieving revision 1.16114.2.1019 +retrieving revision 1.16114.2.1059 +diff -u -r1.16114.2.1019 -r1.16114.2.1059 +--- gcc/gcc/ChangeLog 30 Sep 2004 16:45:01 -0000 1.16114.2.1019 ++++ gcc/gcc/ChangeLog 29 Jan 2005 11:53:57 -0000 1.16114.2.1059 +@@ -1,3 +1,314 @@ ++2005-01-29 Alan Modra ++ ++ * unwind-dw2.c (execute_stack_op): Add missing cases for ++ DW_OP_shl, DW_OP_shr, DW_OP_shra, DW_OP_xor. ++ ++2005-01-28 Stephane Carrez ++ ++ PR target/15384 ++ * config/m68hc11/t-m68hc11-gas (dp-bit.c): Fix typo causing a ++ configuration part of dp-bit.c to be lost. ++ ++2005-01-27 Ulrich Weigand ++ ++ PR target/17771 ++ Backport from mainline: ++ * config/s390/s390.md ("reload_outti"): Remove predicate for ++ output operand. Abort if operand is not a MEM. ++ ("reload_outdi", "reload_outdf"): Likewise. ++ ++2005-01-22 Roger Sayle ++ ++ PR target/18402 ++ Backport from mainline ++ 2003-02-05 Jakub Jelinek ++ ++ PR optimization/8555 ++ * config/i386/i386.md (sse_mov?fcc split): Handle op2 == op3 case ++ instead of aborting. ++ ++2005-01-21 Giovanni Bajo ++ ++ * gccbug.in: Update optimization -> tree-optimization/rtl-optimization. ++ ++2005-01-21 Giovanni Bajo ++ ++ PR c++/17115 ++ * tree-inline.c (expand_call_inline): Do not warn for functions ++ marked with attribute noinline. ++ ++2005-01-18 Eric Botcazou ++ ++ PR rtl-optimization/19296 ++ * combine.c (simplify_comparison): Rewrite the condition under ++ which a non-paradoxical SUBREG of a PLUS can be lifted when ++ compared against a constant. ++ ++2004-01-14 David Mosberger ++ James E Wilson ++ ++ PR target/18987 ++ * config/ia64/ia64.c (process_set): For alloc insn, only call ++ process_epilogue is !frame_pointer_needed. ++ ++ PR target/13158 ++ * config/ia64/ia64.c (ia64_expand_epilogue): Set RTX_FRAME_RELATED_P on ++ sibcall alloc instruction. ++ (process_set): Handle sibcall alloc instruction. ++ ++2005-01-13 David O'Brien ++ ++ Backport from mainline: ++ * config/freebsd-spec.h: Use KSE pthread lib for -pthread. ++ ++2005-01-08 Sergey M. Samoylov ++ ++ Backport: ++ 2004-02-12 Richard Sandiford ++ PR bootstrap/13617 ++ * config/mips/mips-protos.h (mips_output_aligned_decl_common): Declare. ++ (mips_declare_object): Make variadic. ++ * config/mips/mips.h (ASM_OUTPUT_ALIGNED_DECL_COMMON): Use ++ mips_output_aligned_decl_common. ++ * config/mips/mips.c (mips_output_aligned_decl_common): New function. ++ (mips_declare_object): Make variadic. ++ ++2005-01-08 Richard Sandiford ++ ++ PR target/17565 ++ * config/mips/mips.md (define_asm_attributes): Set can_delay to no. ++ ++2004-12-27 John David Anglin ++ ++ * vax.c (vax_address_cost, vax_rtx_cost): Correct casts. ++ (vax_rtx_cost): Handle small offsets for both PLUS and MINUS. ++ ++2004-12-27 Steven Bosscher ++ John David Anglin ++ ++ rtl-optimization/12863 ++ * config/vax/vax.h (CASE_DROPS_THROUGH): Don't define. ++ * config/vax/vax.md (casesi): Emit a test-and-branch to make sure ++ that the case is in range, to make sure the casesi insn is always ++ in range and never falls through. ++ (casesi1): Add comment to explain why casesi never falls through. ++ Remove the unnamed special case casesi pattern. ++ ++2004-12-26 John David Anglin ++ ++ PR target/17643 ++ * config/pa/pa32-linux.h (FUNCTION_OK_FOR_SIBCALL): Return false when ++ TARGET_PORTABLE_RUNTIME is true. ++ ++2004-12-25 Alan Modra ++ ++ PR target/19147 ++ * config/rs6000/rs6000.md (andsi3_internal7, andsi3_internal8): Delete. ++ ++2004-12-21 Joseph S. Myers ++ ++ PR c/14765 ++ * c-parse.in (compstmt_primary_start): Set last_expr_type to ++ NULL_TREE. ++ ++2004-12-19 Roger Sayle ++ ++ PR middle-end/19068 ++ * expr.c (expand_expr_real_1) : Ensure that target, op0 ++ and op1 are all registers (or constants) before expanding the RTL ++ comparison sequence [to avoid reg_overlap_mentioned (target, op1)]. ++ ++2004-12-16 Eric Botcazou ++ ++ PR middle-end/18882 ++ * function.c (assign_stack_local_1): Use BITS_PER_UNIT alignment ++ when passed -2 as 'align'. ++ (put_var_into_stack): Adjust calls to put_reg_into_stack. ++ When passed a CONCAT, instruct put_reg_into_stack to use ++ a consecutive stack slot for the second part. ++ (put_reg_into_stack): Remove 'promoted_mode' parameter, add ++ 'consecutive_p' parameter. Retrieve the register mode from 'reg'. ++ When consecutive_p is true, instruct assign_stack_local_1 to use ++ BITS_PER_UNIT alignment. ++ (put_addressof_into_stack): Adjust call to put_reg_into_stack. ++ ++2004-12-16 Eric Botcazou ++ ++ PR middle-end/18590 ++ * function.c (fixup_var_refs_insns_with_hash): Do not invoke ++ fixup_var_refs_insn on insns marked as deleted. ++ ++2004-12-15 Richard Henderson ++ ++ PR target/19005 ++ * config/i386/i386.md (swaphi_1): Swap with swaphi_2, allow with ++ optimize_size. ++ (swapqi_1): Rename from swapqi. Enable only for no partial reg ++ stall and optimize_size. ++ (swapqi_2): New. ++ (swaphi_1, swaphi_2, swapqi_1): Add athlon_decode. ++ (swapsi, swaphi_1, swaphi_2, swapqi_1, swapdi): Remove modrm override. ++ ++2004-12-13 John David Anglin ++ ++ PR middle-end/18730 ++ * emit-rtl.c (get_first_nonnote_insn, get_last_nonnote_insn): When ++ the first/last insn is a sequence, return the first/last insn of the ++ sequence. ++ ++2004-12-12 Richard Henderson ++ ++ PR target/18932 ++ * config/i386/i386.md (all splits and peepholes): Use flags_reg_operand ++ and compare_operator to propagate the input CC mode to the output. ++ * config/i386/i386.c (flags_reg_operand, compare_operator): New. ++ * config/i386/i386.h (PREDICATE_CODES): Add them. ++ * config/i386/i386-protos.h: Update. ++ ++2004-12-10 Volker Reichelt ++ ++ PR rtl-optimization/16536 ++ Backport from mainline: ++ 2004-06-25 Mark Mitchell ++ * alias.c (get_alias_set): Adjust setting of ++ DECL_POINTER_ALIAS_SET for pointers to aggregates. ++ ++2004-12-09 Richard Henderson ++ ++ PR target/17025 ++ * config/i386/i386.md (testqi_1_maybe_si, andqi_2_maybe_si): New. ++ (test_qi_1, andqi_2): Do not promote to simode. ++ ++2004-12-07 David Mosberger ++ ++ PR target/18443 ++ * config/ia64/ia64.c (ia64_assemble_integer): Add support for ++ emitting unaligned pointer-sized integers. ++ ++2004-12-05 Richard Henderson ++ ++ PR target/18841 ++ * config/alpha/alpha.md (UNSPECV_SETJMPR_ER): New. ++ (builtin_setjmp_receiver_er_sl_1): Use it. ++ (builtin_setjmp_receiver_er_1): Likewise. ++ (builtin_setjmp_receiver_er, exception_receiver_er): Remove. ++ (builtin_setjmp_receiver): Don't split for explicit relocs until ++ after reload. ++ (exception_receiver): Likewise. ++ ++2004-12-03 John David Anglin ++ ++ 2003-10-31 John David Anglin ++ Backport from mainline ++ * aclocal.m4 (gcc_AC_FUNC_MMAP_BLACKLIST): Blacklist ultrix*. ++ * configure: Rebuilt. ++ ++2004-12-03 Richard Henderson ++ ++ 2004-09-24 Richard Henderson ++ PR rtl-opt/17503 ++ * regclass.c (subregs_of_mode): Turn into an htab. Make static. ++ (som_hash, som_eq): New. ++ (init_subregs_of_mode, record_subregs_of_mode): New. ++ (cannot_change_mode_set_regs): Rewrite for htab implementation. ++ (invalid_mode_change_p): Likewise. ++ * combine.c (gen_lowpart_for_combine): Use record_subregs_of_mode. ++ * flow.c (mark_used_regs): Likewise. ++ (life_analysis): Use init_subregs_of_mode. ++ * regs.h (subregs_of_mode): Remove. ++ * rtl.h (init_subregs_of_mode, record_subregs_of_mode): Declare. ++ ++2004-12-03 Roger Sayle ++ ++ PR target/9908 ++ * config/i386/i386.md (*call_value_1): Correct Intel assembler ++ syntax by using %A1 instead of %*%1. ++ ++2004-12-01 Alan Modra ++ ++ PR target/12817 ++ * config/rs6000/rs6000.c (rs6000_emit_prologue): Use r0 for vrsave. ++ ++2004-11-29 Roger Sayle ++ ++ PR rtl-optimization/9771 ++ * regclass.c (CALL_REALLY_USED_REGNO_P): New macro to eliminate ++ conditional compilation in init_reg_sets_1. ++ (init_reg_sets_1): Let global_regs[i] take priority over the frame ++ (but not stack) pointer exceptions to regs_invalidated_by_call. ++ (globalize_reg): Globalizing a fixed register may need to update ++ regs_invalidated_by_call. ++ ++2004-11-27 Falk Hueffner ++ Eric Botcazou ++ ++ PR optimization/18577 ++ * unroll.c (unroll_loop): Test both REGNO_LAST_UID and ++ REGNO_LAST_NOTE_UID to decide whether a pseudo is local ++ to the loop. ++ ++2004-11-27 Alan Modra ++ ++ PR target/12769 ++ * config/rs6000/rs6000.c (init_cumulative_args): Set call_cookie ++ from rs6000_default_long_calls for libcalls. ++ ++2004-11-25 Richard Henderson ++ ++ PR c++/6764 ++ * reload1.c (set_initial_eh_label_offset): New. ++ (set_initial_label_offsets): Use it. ++ ++2004-11-22 John David Anglin ++ ++ PR rtl-optimization/14838 ++ * emit-rtl.c (get_first_nonnote_insn): Don't assume first insn is a ++ note. ++ (get_last_nonnote_insn): Don't assume last insn is a note. ++ ++2004-10-14 Kaveh R. Ghazi ++ ++ * doc/install.texi (*-*-solaris2*): Update with info about kernel ++ patches to solve spurious testsuite failures. ++ ++2004-10-13 Eric Botcazou ++ ++ PR target/14454 ++ * config/sparc/sparc.c (TARGET_ASM_CAN_OUTPUT_MI_THUNK): Set to ++ sparc_can_output_mi_thunk. ++ (sparc_output_mi_thunk): Simplify handling of delta offset. Add ++ handling of vcall offset. ++ (sparc_can_output_mi_thunk): New predicate. ++ * doc/tm.texi (TARGET_ASM_OUTPUT_MI_THUNK): Document VCALL_OFFSET. ++ (TARGET_ASM_OUTPUT_MI_VCALL_THUNK): Delete. ++ (TARGET_ASM_CAN_OUTPUT_MI_THUNK): New target hook. ++ ++ * config/sparc/sparc.md (movdi): Remove redundant test. ++ ++2004-10-07 Eric Botcazou ++ ++ * doc/install.texi (*-*-solaris2*): Fix marker for URL. ++ ++2004-10-06 Eric Botcazou ++ ++ PR target/16007 ++ * doc/install.texi (*-*-solaris2*): Mention potential problem ++ with Sun assembler + GNU linker and C++ programs. ++ Document status of binutils 2.15 release. ++ ++2004-09-30 Richard Henderson ++ ++ * config/alpha/qrnnd.asm: Mark for noexecstack. ++ ++2004-09-30 Richard Henderson ++ ++ * unwind-dw2.c (_Unwind_GetGR): Honor DWARF_ZERO_REG. ++ * doc/tm.texi (DWARF_ZERO_REG): New. ++ ++ * config/alpha/alpha.c (alpha_sa_mask, alpha_expand_prologue, ++ alpha_expand_epilogue): Revert 2003-09-30 change to store zero. ++ * config/alpha/alpha.h (DWARF_ZERO_REG): New. ++ + 2004-09-30 Release Manager + + * GCC 3.3.5 Released. +@@ -19,12 +330,12 @@ + + 2004-09-13 Richard Henderson + +- PR inline-asm/6806 +- * cselib.c (cselib_invalidate_rtx): Export. Remove unused args. +- (cselib_invalidate_rtx_note_stores): New. +- (cselib_record_sets, cselib_process_insn): Update to match. +- * cselib.h (cselib_invalidate_rtx): Declare. +- * reload1.c (reload_cse_simplify): Invalidate asm clobbers. ++ PR inline-asm/6806 ++ * cselib.c (cselib_invalidate_rtx): Export. Remove unused args. ++ (cselib_invalidate_rtx_note_stores): New. ++ (cselib_record_sets, cselib_process_insn): Update to match. ++ * cselib.h (cselib_invalidate_rtx): Declare. ++ * reload1.c (reload_cse_simplify): Invalidate asm clobbers. + + 2004-08-29 Jonathan Wakely + +@@ -83,7 +394,7 @@ + 2004-07-25 Andreas Jaeger + + Backport from mainline: +- * libgcc-std.ver: Add __unorddf2 and __unordsf2 with version 3.3.4. ++ * libgcc-std.ver: Add __unorddf2 and __unordsf2 with version 3.3.4. + + 2004-07-25 Kaz Kojima + +@@ -155,14 +466,14 @@ + side-effect of having a length greater or equal to 3. + + 2004-07-13 Eric Botcazou +- Lloyd Parkes ++ Lloyd Parkes + + PR target/15186 + * config/sparc/sol2-bi.h (LINK_ARCH64_SPEC_BASE): Pass + /usr/ucblib/sparcv9 as -R path when -compat-bsd is specified. + + 2004-07-13 Eric Botcazou +- Martin Sebor ++ Martin Sebor + + PR target/12602 + * doc/invoke.texi (SPARC options): Document -threads +@@ -252,18 +563,18 @@ + + Backport from mainline: + 2004-01-19 Richard Henderson +- * alpha.md (UNSPEC_NT_LDA): Renumber. +- (UNSPEC_CVTLQ, cvtlq): New. +- (extendsidi2_1): Rename from extendsidi2_nofix; remove f/f. +- (extendsidi2_fix): Remove. +- (extendsidi2 splitter): Use cvtlq. +- (extendsidi2 fp peepholes): Remove. +- (cvtql): Use SFmode instead of SImode. +- (fix_trunc?fsi): Update to match. +- (floatsisf2_ieee, floatsisf2, floatsidf2_ieee, floatsidf2): New. +- (movsi): Rename from movsi_nofix, remove f alternatives. +- (movsi_nt_vms): Similarly. +- (movsi_fix, movsi_nt_vms_fix): Remove. ++ * alpha.md (UNSPEC_NT_LDA): Renumber. ++ (UNSPEC_CVTLQ, cvtlq): New. ++ (extendsidi2_1): Rename from extendsidi2_nofix; remove f/f. ++ (extendsidi2_fix): Remove. ++ (extendsidi2 splitter): Use cvtlq. ++ (extendsidi2 fp peepholes): Remove. ++ (cvtql): Use SFmode instead of SImode. ++ (fix_trunc?fsi): Update to match. ++ (floatsisf2_ieee, floatsisf2, floatsidf2_ieee, floatsidf2): New. ++ (movsi): Rename from movsi_nofix, remove f alternatives. ++ (movsi_nt_vms): Similarly. ++ (movsi_fix, movsi_nt_vms_fix): Remove. + + 2004-05-26 Hans-Peter Nilsson + +Index: gcc/aclocal.m4 +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/aclocal.m4,v +retrieving revision 1.61.2.4 +retrieving revision 1.61.2.5 +diff -u -r1.61.2.4 -r1.61.2.5 +--- gcc/gcc/aclocal.m4 1 Oct 2003 21:56:34 -0000 1.61.2.4 ++++ gcc/gcc/aclocal.m4 4 Dec 2004 01:51:47 -0000 1.61.2.5 +@@ -413,7 +413,7 @@ + # read() to the same fd. The only system known to have a problem here + # is VMS, where text files have record structure. + case "$host_os" in +- vms*) ++ vms* | ultrix*) + gcc_cv_func_mmap_file=no ;; + *) + gcc_cv_func_mmap_file=yes;; +Index: gcc/alias.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/alias.c,v +retrieving revision 1.181.2.6 +retrieving revision 1.181.2.7 +diff -u -r1.181.2.6 -r1.181.2.7 +--- gcc/gcc/alias.c 28 May 2004 17:27:27 -0000 1.181.2.6 ++++ gcc/gcc/alias.c 10 Dec 2004 17:25:00 -0000 1.181.2.7 +@@ -508,6 +508,8 @@ + /* If we haven't computed the actual alias set, do it now. */ + if (DECL_POINTER_ALIAS_SET (decl) == -2) + { ++ tree pointed_to_type = TREE_TYPE (TREE_TYPE (decl)); ++ + /* No two restricted pointers can point at the same thing. + However, a restricted pointer can point at the same thing + as an unrestricted pointer, if that unrestricted pointer +@@ -516,11 +518,22 @@ + alias set for the type pointed to by the type of the + decl. */ + HOST_WIDE_INT pointed_to_alias_set +- = get_alias_set (TREE_TYPE (TREE_TYPE (decl))); ++ = get_alias_set (pointed_to_type); + + if (pointed_to_alias_set == 0) + /* It's not legal to make a subset of alias set zero. */ +- ; ++ DECL_POINTER_ALIAS_SET (decl) = 0; ++ else if (AGGREGATE_TYPE_P (pointed_to_type)) ++ /* For an aggregate, we must treat the restricted ++ pointer the same as an ordinary pointer. If we ++ were to make the type pointed to by the ++ restricted pointer a subset of the pointed-to ++ type, then we would believe that other subsets ++ of the pointed-to type (such as fields of that ++ type) do not conflict with the type pointed to ++ by the restricted pointer. */ ++ DECL_POINTER_ALIAS_SET (decl) ++ = pointed_to_alias_set; + else + { + DECL_POINTER_ALIAS_SET (decl) = new_alias_set (); +Index: gcc/c-parse.in +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v +retrieving revision 1.152.14.1 +retrieving revision 1.152.14.2 +diff -u -r1.152.14.1 -r1.152.14.2 +--- gcc/gcc/c-parse.in 28 Jan 2003 01:54:03 -0000 1.152.14.1 ++++ gcc/gcc/c-parse.in 21 Dec 2004 21:51:26 -0000 1.152.14.2 +@@ -2177,6 +2177,7 @@ + push_label_level (); + compstmt_count++; + $$ = add_stmt (build_stmt (COMPOUND_STMT, last_tree)); ++ last_expr_type = NULL_TREE; + } + ; + +Index: gcc/combine.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/combine.c,v +retrieving revision 1.325.2.17 +retrieving revision 1.325.2.19 +diff -u -r1.325.2.17 -r1.325.2.19 +--- gcc/gcc/combine.c 25 Jul 2004 18:49:54 -0000 1.325.2.17 ++++ gcc/gcc/combine.c 18 Jan 2005 08:39:05 -0000 1.325.2.19 +@@ -10138,13 +10138,8 @@ + + result = gen_lowpart_common (mode, x); + #ifdef CANNOT_CHANGE_MODE_CLASS +- if (result != 0 +- && GET_CODE (result) == SUBREG +- && GET_CODE (SUBREG_REG (result)) == REG +- && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER) +- bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (result)) +- * MAX_MACHINE_MODE +- + GET_MODE (result)); ++ if (result != 0 && GET_CODE (result) == SUBREG) ++ record_subregs_of_mode (result); + #endif + + if (result) +@@ -10818,34 +10813,61 @@ + break; + + case SUBREG: +- /* Check for the case where we are comparing A - C1 with C2, +- both constants are smaller than 1/2 the maximum positive +- value in MODE, and the comparison is equality or unsigned. +- In that case, if A is either zero-extended to MODE or has +- sufficient sign bits so that the high-order bit in MODE +- is a copy of the sign in the inner mode, we can prove that it is +- safe to do the operation in the wider mode. This simplifies +- many range checks. */ ++ /* Check for the case where we are comparing A - C1 with C2, that is ++ ++ (subreg:MODE (plus (A) (-C1))) op (C2) ++ ++ with C1 a constant, and try to lift the SUBREG, i.e. to do the ++ comparison in the wider mode. One of the following two conditions ++ must be true in order for this to be valid: ++ ++ 1. The mode extension results in the same bit pattern being added ++ on both sides and the comparison is equality or unsigned. As ++ C2 has been truncated to fit in MODE, the pattern can only be ++ all 0s or all 1s. ++ ++ 2. The mode extension results in the sign bit being copied on ++ each side. ++ ++ The difficulty here is that we have predicates for A but not for ++ (A - C1) so we need to check that C1 is within proper bounds so ++ as to perturbate A as little as possible. */ + + if (mode_width <= HOST_BITS_PER_WIDE_INT + && subreg_lowpart_p (op0) ++ && GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) > mode_width + && GET_CODE (SUBREG_REG (op0)) == PLUS +- && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT +- && INTVAL (XEXP (SUBREG_REG (op0), 1)) < 0 +- && (-INTVAL (XEXP (SUBREG_REG (op0), 1)) +- < (HOST_WIDE_INT) (GET_MODE_MASK (mode) / 2)) +- && (unsigned HOST_WIDE_INT) const_op < GET_MODE_MASK (mode) / 2 +- && (0 == (nonzero_bits (XEXP (SUBREG_REG (op0), 0), +- GET_MODE (SUBREG_REG (op0))) +- & ~GET_MODE_MASK (mode)) +- || (num_sign_bit_copies (XEXP (SUBREG_REG (op0), 0), +- GET_MODE (SUBREG_REG (op0))) +- > (unsigned int) +- (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (op0))) +- - GET_MODE_BITSIZE (mode))))) ++ && GET_CODE (XEXP (SUBREG_REG (op0), 1)) == CONST_INT) + { +- op0 = SUBREG_REG (op0); +- continue; ++ enum machine_mode inner_mode = GET_MODE (SUBREG_REG (op0)); ++ rtx a = XEXP (SUBREG_REG (op0), 0); ++ HOST_WIDE_INT c1 = -INTVAL (XEXP (SUBREG_REG (op0), 1)); ++ ++ if ((c1 > 0 ++ && (unsigned HOST_WIDE_INT) c1 ++ < (unsigned HOST_WIDE_INT) 1 << (mode_width - 1) ++ && (equality_comparison_p || unsigned_comparison_p) ++ /* (A - C1) zero-extends if it is positive and sign-extends ++ if it is negative, C2 both zero- and sign-extends. */ ++ && ((0 == (nonzero_bits (a, inner_mode) ++ & ~GET_MODE_MASK (mode)) ++ && const_op >= 0) ++ /* (A - C1) sign-extends if it is positive and 1-extends ++ if it is negative, C2 both sign- and 1-extends. */ ++ || (num_sign_bit_copies (a, inner_mode) ++ > (unsigned int) (GET_MODE_BITSIZE (inner_mode) ++ - mode_width) ++ && const_op < 0))) ++ || ((unsigned HOST_WIDE_INT) c1 ++ < (unsigned HOST_WIDE_INT) 1 << (mode_width - 2) ++ /* (A - C1) always sign-extends, like C2. */ ++ && num_sign_bit_copies (a, inner_mode) ++ > (unsigned int) (GET_MODE_BITSIZE (inner_mode) ++ - mode_width - 1))) ++ { ++ op0 = SUBREG_REG (op0); ++ continue; ++ } + } + + /* If the inner mode is narrower and we are extracting the low part, +Index: gcc/configure +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/configure,v +retrieving revision 1.641.2.23 +retrieving revision 1.641.2.24 +diff -u -r1.641.2.23 -r1.641.2.24 +--- gcc/gcc/configure 1 Apr 2004 16:55:23 -0000 1.641.2.23 ++++ gcc/gcc/configure 4 Dec 2004 01:51:43 -0000 1.641.2.24 +@@ -2399,7 +2399,7 @@ + fi + + # Find some useful tools +-for ac_prog in gawk mawk nawk awk ++for ac_prog in mawk gawk nawk awk + do + # Extract the first word of "$ac_prog", so it can be a program name with args. + set dummy $ac_prog; ac_word=$2 +@@ -3947,7 +3947,7 @@ + # read() to the same fd. The only system known to have a problem here + # is VMS, where text files have record structure. + case "$host_os" in +- vms*) ++ vms* | ultrix*) + gcc_cv_func_mmap_file=no ;; + *) + gcc_cv_func_mmap_file=yes;; +@@ -8120,7 +8120,7 @@ + echo "$ac_t""$gcc_cv_ld_eh_frame_hdr" 1>&6 + + echo $ac_n "checking linker --as-needed support""... $ac_c" 1>&6 +-echo "configure:8250: checking linker --as-needed support" >&5 ++echo "configure:8124: checking linker --as-needed support" >&5 + gcc_cv_ld_as_needed=no + if test x$gcc_cv_gld_major_version != x -a x$gcc_cv_gld_minor_version != x; then + if test "$gcc_cv_gld_major_version" -eq 2 -a "$gcc_cv_gld_minor_version" -ge 16 -o "$gcc_cv_gld_major_version" -gt 2 && grep 'EMUL = elf' ../ld/Makefile > /dev/null; then +@@ -8144,7 +8144,7 @@ + case "$target" in + mips*-*-*) + echo $ac_n "checking whether libgloss uses STARTUP directives consistently""... $ac_c" 1>&6 +-echo "configure:8127: checking whether libgloss uses STARTUP directives consistently" >&5 ++echo "configure:8148: checking whether libgloss uses STARTUP directives consistently" >&5 + gcc_cv_mips_libgloss_startup=no + gcc_cv_libgloss_srcdir=`echo $srcdir | sed -e 's,/gcc$,,'`/libgloss + if test "x$exec_prefix" = xNONE; then +@@ -8349,7 +8349,7 @@ + + + echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6 +-echo "configure:8332: checking whether to enable maintainer-specific portions of Makefiles" >&5 ++echo "configure:8353: checking whether to enable maintainer-specific portions of Makefiles" >&5 + # Check whether --enable-maintainer-mode or --disable-maintainer-mode was given. + if test "${enable_maintainer_mode+set}" = set; then + enableval="$enable_maintainer_mode" +Index: gcc/emit-rtl.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v +retrieving revision 1.303.2.5 +retrieving revision 1.303.2.7 +diff -u -r1.303.2.5 -r1.303.2.7 +--- gcc/gcc/emit-rtl.c 18 Jun 2004 17:08:48 -0000 1.303.2.5 ++++ gcc/gcc/emit-rtl.c 14 Dec 2004 04:06:08 -0000 1.303.2.7 +@@ -2890,11 +2890,19 @@ + { + rtx insn = first_insn; + +- while (insn) ++ if (insn) + { +- insn = next_insn (insn); +- if (insn == 0 || GET_CODE (insn) != NOTE) +- break; ++ if (NOTE_P (insn)) ++ for (insn = next_insn (insn); ++ insn && NOTE_P (insn); ++ insn = next_insn (insn)) ++ continue; ++ else ++ { ++ if (GET_CODE (insn) == INSN ++ && GET_CODE (PATTERN (insn)) == SEQUENCE) ++ insn = XVECEXP (PATTERN (insn), 0, 0); ++ } + } + + return insn; +@@ -2908,11 +2916,20 @@ + { + rtx insn = last_insn; + +- while (insn) ++ if (insn) + { +- insn = previous_insn (insn); +- if (insn == 0 || GET_CODE (insn) != NOTE) +- break; ++ if (NOTE_P (insn)) ++ for (insn = previous_insn (insn); ++ insn && NOTE_P (insn); ++ insn = previous_insn (insn)) ++ continue; ++ else ++ { ++ if (GET_CODE (insn) == INSN ++ && GET_CODE (PATTERN (insn)) == SEQUENCE) ++ insn = XVECEXP (PATTERN (insn), 0, ++ XVECLEN (PATTERN (insn), 0) - 1); ++ } + } + + return insn; +Index: gcc/expr.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/expr.c,v +retrieving revision 1.498.2.31 +retrieving revision 1.498.2.32 +diff -u -r1.498.2.31 -r1.498.2.32 +--- gcc/gcc/expr.c 16 May 2004 20:27:15 -0000 1.498.2.31 ++++ gcc/gcc/expr.c 20 Dec 2004 02:43:00 -0000 1.498.2.32 +@@ -8462,9 +8462,14 @@ + /* At this point, a MEM target is no longer useful; we will get better + code without it. */ + +- if (GET_CODE (target) == MEM) ++ if (! REG_P (target)) + target = gen_reg_rtx (mode); + ++ /* We generate better code and avoid problems with op1 mentioning ++ target by forcing op1 into a pseudo if it isn't a constant. */ ++ if (! CONSTANT_P (op1)) ++ op1 = force_reg (mode, op1); ++ + if (target != op0) + emit_move_insn (target, op0); + +Index: gcc/flow.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/flow.c,v +retrieving revision 1.541.2.6 +retrieving revision 1.541.2.7 +diff -u -r1.541.2.6 -r1.541.2.7 +--- gcc/gcc/flow.c 5 Mar 2004 17:55:50 -0000 1.541.2.6 ++++ gcc/gcc/flow.c 4 Dec 2004 00:36:35 -0000 1.541.2.7 +@@ -431,9 +431,8 @@ + SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM); + #endif + +- + #ifdef CANNOT_CHANGE_MODE_CLASS +- bitmap_initialize (&subregs_of_mode, 1); ++ init_subregs_of_mode (); + #endif + + if (! optimize) +@@ -3851,11 +3850,7 @@ + + case SUBREG: + #ifdef CANNOT_CHANGE_MODE_CLASS +- if (GET_CODE (SUBREG_REG (x)) == REG +- && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER) +- bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (x)) +- * MAX_MACHINE_MODE +- + GET_MODE (x)); ++ record_subregs_of_mode (x); + #endif + + /* While we're here, optimize this case. */ +@@ -3900,12 +3895,8 @@ + || GET_CODE (testreg) == SUBREG) + { + #ifdef CANNOT_CHANGE_MODE_CLASS +- if (GET_CODE (testreg) == SUBREG +- && GET_CODE (SUBREG_REG (testreg)) == REG +- && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER) +- bitmap_set_bit (&subregs_of_mode, REGNO (SUBREG_REG (testreg)) +- * MAX_MACHINE_MODE +- + GET_MODE (testreg)); ++ if (GET_CODE (testreg) == SUBREG) ++ record_subregs_of_mode (testreg); + #endif + + /* Modifying a single register in an alternate mode +Index: gcc/function.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/function.c,v +retrieving revision 1.389.2.16 +retrieving revision 1.389.2.18 +diff -u -r1.389.2.16 -r1.389.2.18 +--- gcc/gcc/function.c 16 May 2004 20:27:16 -0000 1.389.2.16 ++++ gcc/gcc/function.c 16 Dec 2004 14:04:34 -0000 1.389.2.18 +@@ -226,9 +226,8 @@ + int, struct function *)); + static struct temp_slot *find_temp_slot_from_address PARAMS ((rtx)); + static void put_reg_into_stack PARAMS ((struct function *, rtx, tree, +- enum machine_mode, enum machine_mode, +- int, unsigned int, int, +- htab_t)); ++ enum machine_mode, unsigned int, ++ int, int, int, htab_t)); + static void schedule_fixup_var_refs PARAMS ((struct function *, rtx, tree, + enum machine_mode, + htab_t)); +@@ -508,6 +507,7 @@ + ALIGN controls the amount of alignment for the address of the slot: + 0 means according to MODE, + -1 means use BIGGEST_ALIGNMENT and round size to multiple of that, ++ -2 means use BITS_PER_UNIT, + positive specifies alignment boundary in bits. + + We do not round to stack_boundary here. +@@ -548,6 +548,8 @@ + alignment = BIGGEST_ALIGNMENT / BITS_PER_UNIT; + size = CEIL_ROUND (size, alignment); + } ++ else if (align == -2) ++ alignment = 1; /* BITS_PER_UNIT / BITS_PER_UNIT */ + else + alignment = align / BITS_PER_UNIT; + +@@ -1342,9 +1344,9 @@ + enum machine_mode promoted_mode, decl_mode; + struct function *function = 0; + tree context; +- int can_use_addressof; +- int volatilep = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl); +- int usedp = (TREE_USED (decl) ++ int can_use_addressof_p; ++ int volatile_p = TREE_CODE (decl) != SAVE_EXPR && TREE_THIS_VOLATILE (decl); ++ int used_p = (TREE_USED (decl) + || (TREE_CODE (decl) != SAVE_EXPR && DECL_INITIAL (decl) != 0)); + + context = decl_function_context (decl); +@@ -1391,7 +1393,7 @@ + /* If this variable lives in the current function and we don't need to put it + in the stack for the sake of setjmp or the non-locality, try to keep it in + a register until we know we actually need the address. */ +- can_use_addressof ++ can_use_addressof_p + = (function == 0 + && ! (TREE_CODE (decl) != SAVE_EXPR && DECL_NONLOCAL (decl)) + && optimize > 0 +@@ -1404,7 +1406,8 @@ + + /* If we can't use ADDRESSOF, make sure we see through one we already + generated. */ +- if (! can_use_addressof && GET_CODE (reg) == MEM ++ if (! can_use_addressof_p ++ && GET_CODE (reg) == MEM + && GET_CODE (XEXP (reg, 0)) == ADDRESSOF) + reg = XEXP (XEXP (reg, 0), 0); + +@@ -1412,11 +1415,11 @@ + + if (GET_CODE (reg) == REG) + { +- if (can_use_addressof) ++ if (can_use_addressof_p) + gen_mem_addressof (reg, decl, rescan); + else +- put_reg_into_stack (function, reg, TREE_TYPE (decl), promoted_mode, +- decl_mode, volatilep, 0, usedp, 0); ++ put_reg_into_stack (function, reg, TREE_TYPE (decl), decl_mode, ++ 0, volatile_p, used_p, 0, 0); + } + else if (GET_CODE (reg) == CONCAT) + { +@@ -1432,14 +1435,14 @@ + #ifdef FRAME_GROWS_DOWNWARD + /* Since part 0 should have a lower address, do it second. */ + put_reg_into_stack (function, hipart, part_type, part_mode, +- part_mode, volatilep, 0, 0, 0); ++ 0, volatile_p, 0, 0, 0); + put_reg_into_stack (function, lopart, part_type, part_mode, +- part_mode, volatilep, 0, 0, 0); ++ 0, volatile_p, 0, 1, 0); + #else + put_reg_into_stack (function, lopart, part_type, part_mode, +- part_mode, volatilep, 0, 0, 0); ++ 0, volatile_p, 0, 0, 0); + put_reg_into_stack (function, hipart, part_type, part_mode, +- part_mode, volatilep, 0, 0, 0); ++ 0, volatile_p, 0, 1, 0); + #endif + + /* Change the CONCAT into a combined MEM for both parts. */ +@@ -1460,7 +1463,7 @@ + /* Prevent sharing of rtl that might lose. */ + if (GET_CODE (XEXP (reg, 0)) == PLUS) + XEXP (reg, 0) = copy_rtx (XEXP (reg, 0)); +- if (usedp && rescan) ++ if (used_p && rescan) + { + schedule_fixup_var_refs (function, reg, TREE_TYPE (decl), + promoted_mode, 0); +@@ -1474,26 +1477,29 @@ + + /* Subroutine of put_var_into_stack. This puts a single pseudo reg REG + into the stack frame of FUNCTION (0 means the current function). ++ TYPE is the user-level data type of the value hold in the register. + DECL_MODE is the machine mode of the user-level data type. +- PROMOTED_MODE is the machine mode of the register. +- VOLATILE_P is nonzero if this is for a "volatile" decl. +- USED_P is nonzero if this reg might have already been used in an insn. */ ++ ORIGINAL_REGNO must be set if the real regno is not visible in REG. ++ VOLATILE_P is true if this is for a "volatile" decl. ++ USED_P is true if this reg might have already been used in an insn. ++ CONSECUTIVE_P is true if the stack slot assigned to reg must be ++ consecutive with the previous stack slot. */ + + static void +-put_reg_into_stack (function, reg, type, promoted_mode, decl_mode, volatile_p, +- original_regno, used_p, ht) ++put_reg_into_stack (function, reg, type, decl_mode, original_regno, ++ volatile_p, used_p, consecutive_p, ht) + struct function *function; + rtx reg; + tree type; +- enum machine_mode promoted_mode, decl_mode; +- int volatile_p; ++ enum machine_mode decl_mode; + unsigned int original_regno; +- int used_p; ++ int volatile_p, used_p, consecutive_p; + htab_t ht; + { + struct function *func = function ? function : cfun; +- rtx new = 0; ++ enum machine_mode mode = GET_MODE (reg); + unsigned int regno = original_regno; ++ rtx new = 0; + + if (regno == 0) + regno = REGNO (reg); +@@ -1506,7 +1512,8 @@ + } + + if (new == 0) +- new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), 0, func); ++ new = assign_stack_local_1 (decl_mode, GET_MODE_SIZE (decl_mode), ++ consecutive_p ? -2 : 0, func); + + PUT_CODE (reg, MEM); + PUT_MODE (reg, decl_mode); +@@ -1528,7 +1535,7 @@ + } + + if (used_p) +- schedule_fixup_var_refs (function, reg, type, promoted_mode, ht); ++ schedule_fixup_var_refs (function, reg, type, mode, ht); + } + + /* Make sure that all refs to the variable, previously made +@@ -1716,7 +1723,7 @@ + tmp.key = var; + ime = (struct insns_for_mem_entry *) htab_find (ht, &tmp); + for (insn_list = ime->insns; insn_list != 0; insn_list = XEXP (insn_list, 1)) +- if (INSN_P (XEXP (insn_list, 0))) ++ if (INSN_P (XEXP (insn_list, 0)) && !INSN_DELETED_P (XEXP (insn_list, 0))) + fixup_var_refs_insn (XEXP (insn_list, 0), var, promoted_mode, + unsignedp, 1, may_share); + } +@@ -3025,8 +3032,8 @@ + used_p = 1; + } + +- put_reg_into_stack (0, reg, type, GET_MODE (reg), GET_MODE (reg), +- volatile_p, ADDRESSOF_REGNO (r), used_p, ht); ++ put_reg_into_stack (0, reg, type, GET_MODE (reg), ADDRESSOF_REGNO (r), ++ volatile_p, used_p, 0, ht); + } + + /* List of replacements made below in purge_addressof_1 when creating +Index: gcc/gccbug.in +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gccbug.in,v +retrieving revision 1.15.34.1 +retrieving revision 1.15.34.2 +diff -u -r1.15.34.1 -r1.15.34.2 +--- gcc/gcc/gccbug.in 2 Jan 2003 05:22:37 -0000 1.15.34.1 ++++ gcc/gcc/gccbug.in 21 Jan 2005 10:08:47 -0000 1.15.34.2 +@@ -198,7 +198,7 @@ + done + + # spam does not need to be listed here +-CATEGORIES="ada bootstrap c++ c debug driver fortran inline-asm java libf2c libgcj libobjc libstdc++ middle-end objc optimization other preprocessor target web" ++CATEGORIES="ada bootstrap c++ c debug driver fortran inline-asm java libf2c libgcj libobjc libstdc++ middle-end objc other preprocessor rtl-optimization target tree-optimization web" + + case "$FORMAT" in + lisp) echo "$CATEGORIES" | \ +Index: gcc/regclass.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/regclass.c,v +retrieving revision 1.160.4.5 +retrieving revision 1.160.4.8 +diff -u -r1.160.4.5 -r1.160.4.8 +--- gcc/gcc/regclass.c 3 Mar 2003 11:00:15 -0000 1.160.4.5 ++++ gcc/gcc/regclass.c 4 Dec 2004 00:36:37 -0000 1.160.4.8 +@@ -41,6 +41,7 @@ + #include "toplev.h" + #include "output.h" + #include "ggc.h" ++#include "hashtab.h" + + #ifndef REGISTER_MOVE_COST + #define REGISTER_MOVE_COST(m, x, y) 2 +@@ -105,6 +106,13 @@ + char call_really_used_regs[] = CALL_REALLY_USED_REGISTERS; + #endif + ++#ifdef CALL_REALLY_USED_REGISTERS ++#define CALL_REALLY_USED_REGNO_P(X) call_really_used_regs[X] ++#else ++#define CALL_REALLY_USED_REGNO_P(X) call_used_regs[X] ++#endif ++ ++ + /* Indexed by hard register number, contains 1 for registers that are + fixed use or call used registers that cannot hold quantities across + calls even if we are willing to save and restore them. call fixed +@@ -228,12 +236,6 @@ + + #endif /* FORBIDDEN_INC_DEC_CLASSES */ + +-#ifdef CANNOT_CHANGE_MODE_CLASS +-/* All registers that have been subreged. Indexed by regno * MAX_MACHINE_MODE +- + mode. */ +-bitmap_head subregs_of_mode; +-#endif +- + /* Sample MEM values for use by memory_move_secondary_cost. */ + + static GTY(()) rtx top_of_stack[MAX_MACHINE_MODE]; +@@ -447,7 +449,11 @@ + If we are generating PIC code, the PIC offset table register is + preserved across calls, though the target can override that. */ + +- if (i == STACK_POINTER_REGNUM || i == FRAME_POINTER_REGNUM) ++ if (i == STACK_POINTER_REGNUM) ++ ; ++ else if (global_regs[i]) ++ SET_HARD_REG_BIT (regs_invalidated_by_call, i); ++ else if (i == FRAME_POINTER_REGNUM) + ; + #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM + else if (i == HARD_FRAME_POINTER_REGNUM) +@@ -461,13 +467,7 @@ + else if (i == PIC_OFFSET_TABLE_REGNUM && fixed_regs[i]) + ; + #endif +- else if (0 +-#ifdef CALL_REALLY_USED_REGISTERS +- || call_really_used_regs[i] +-#else +- || call_used_regs[i] +-#endif +- || global_regs[i]) ++ else if (CALL_REALLY_USED_REGNO_P (i)) + SET_HARD_REG_BIT (regs_invalidated_by_call, i); + } + +@@ -792,6 +792,12 @@ + + global_regs[i] = 1; + ++ /* If we're globalizing the frame pointer, we need to set the ++ appropriate regs_invalidated_by_call bit, even if it's already ++ set in fixed_regs. */ ++ if (i != STACK_POINTER_REGNUM) ++ SET_HARD_REG_BIT (regs_invalidated_by_call, i); ++ + /* If already fixed, nothing else to do. */ + if (fixed_regs[i]) + return; +@@ -802,7 +808,6 @@ + SET_HARD_REG_BIT (fixed_reg_set, i); + SET_HARD_REG_BIT (call_used_reg_set, i); + SET_HARD_REG_BIT (call_fixed_reg_set, i); +- SET_HARD_REG_BIT (regs_invalidated_by_call, i); + } + + /* Now the data and code for the `regclass' pass, which happens +@@ -2415,9 +2420,15 @@ + + if (regno >= min_regno) + { ++ /* While the following 3 lines means that the inequality ++ REGNO_LAST_UID (regno) <= REGNO_LAST_NOTE_UID (regno) ++ is true at the end of the scanning, it may be subsequently ++ invalidated (e.g. in load_mems) so it should not be relied ++ upon. */ + REGNO_LAST_NOTE_UID (regno) = INSN_UID (insn); + if (!note_flag) + REGNO_LAST_UID (regno) = INSN_UID (insn); ++ + if (REGNO_FIRST_UID (regno) == 0) + REGNO_FIRST_UID (regno) = INSN_UID (insn); + /* If we are called by reg_scan_update() (indicated by min_regno +@@ -2614,6 +2625,77 @@ + } + + #ifdef CANNOT_CHANGE_MODE_CLASS ++ ++struct subregs_of_mode_node ++{ ++ unsigned int block; ++ unsigned char modes[MAX_MACHINE_MODE]; ++}; ++ ++static htab_t subregs_of_mode; ++ ++static hashval_t som_hash PARAMS ((const void *)); ++static int som_eq PARAMS ((const void *, const void *)); ++ ++static hashval_t ++som_hash (x) ++ const void *x; ++{ ++ const struct subregs_of_mode_node *a = x; ++ return a->block; ++} ++ ++static int ++som_eq (x, y) ++ const void *x; ++ const void *y; ++{ ++ const struct subregs_of_mode_node *a = x; ++ const struct subregs_of_mode_node *b = y; ++ return a->block == b->block; ++} ++ ++void ++init_subregs_of_mode () ++{ ++ if (subregs_of_mode) ++ htab_empty (subregs_of_mode); ++ else ++ subregs_of_mode = htab_create (100, som_hash, som_eq, free); ++} ++ ++void ++record_subregs_of_mode (subreg) ++ rtx subreg; ++{ ++ struct subregs_of_mode_node dummy, *node; ++ enum machine_mode mode; ++ unsigned int regno; ++ void **slot; ++ ++ if (!REG_P (SUBREG_REG (subreg))) ++ return; ++ ++ regno = REGNO (SUBREG_REG (subreg)); ++ mode = GET_MODE (subreg); ++ ++ if (regno < FIRST_PSEUDO_REGISTER) ++ return; ++ ++ dummy.block = regno & -8; ++ slot = htab_find_slot_with_hash (subregs_of_mode, &dummy, ++ dummy.block, INSERT); ++ node = *slot; ++ if (node == NULL) ++ { ++ node = xcalloc (1, sizeof (*node)); ++ node->block = regno & -8; ++ *slot = node; ++ } ++ ++ node->modes[mode] |= 1 << (regno & 7); ++} ++ + /* Set bits in *USED which correspond to registers which can't change + their mode from FROM to any mode in which REGNO was encountered. */ + +@@ -2623,42 +2705,50 @@ + enum machine_mode from; + unsigned int regno; + { ++ struct subregs_of_mode_node dummy, *node; + enum machine_mode to; +- int n, i; +- int start = regno * MAX_MACHINE_MODE; ++ unsigned char mask; ++ unsigned int i; + +- EXECUTE_IF_SET_IN_BITMAP (&subregs_of_mode, start, n, +- if (n >= MAX_MACHINE_MODE + start) +- return; +- to = n - start; +- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) +- if (! TEST_HARD_REG_BIT (*used, i) +- && REG_CANNOT_CHANGE_MODE_P (i, from, to)) +- SET_HARD_REG_BIT (*used, i); +- ); ++ dummy.block = regno & -8; ++ node = htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); ++ if (node == NULL) ++ return; ++ ++ mask = 1 << (regno & 7); ++ for (to = VOIDmode; to < NUM_MACHINE_MODES; to++) ++ if (node->modes[to] & mask) ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ if (!TEST_HARD_REG_BIT (*used, i) ++ && REG_CANNOT_CHANGE_MODE_P (i, from, to)) ++ SET_HARD_REG_BIT (*used, i); + } + + /* Return 1 if REGNO has had an invalid mode change in CLASS from FROM + mode. */ + + bool +-invalid_mode_change_p (regno, class, from_mode) ++invalid_mode_change_p (regno, class, from) + unsigned int regno; +- enum reg_class class; +- enum machine_mode from_mode; ++ enum reg_class class; ++ enum machine_mode from; + { +- enum machine_mode to_mode; +- int n; +- int start = regno * MAX_MACHINE_MODE; +- +- EXECUTE_IF_SET_IN_BITMAP (&subregs_of_mode, start, n, +- if (n >= MAX_MACHINE_MODE + start) +- return 0; +- to_mode = n - start; +- if (CANNOT_CHANGE_MODE_CLASS (from_mode, to_mode, class)) +- return 1; +- ); +- return 0; ++ struct subregs_of_mode_node dummy, *node; ++ enum machine_mode to; ++ unsigned char mask; ++ ++ dummy.block = regno & -8; ++ node = htab_find_with_hash (subregs_of_mode, &dummy, dummy.block); ++ if (node == NULL) ++ return false; ++ ++ mask = 1 << (regno & 7); ++ for (to = VOIDmode; to < NUM_MACHINE_MODES; to++) ++ if (node->modes[to] & mask) ++ if (CANNOT_CHANGE_MODE_CLASS (from, to, class)) ++ return true; ++ ++ return false; + } + #endif /* CANNOT_CHANGE_MODE_CLASS */ + +Index: gcc/regs.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/regs.h,v +retrieving revision 1.26.4.1 +retrieving revision 1.26.4.3 +diff -u -r1.26.4.1 -r1.26.4.3 +--- gcc/gcc/regs.h 3 Mar 2003 11:00:15 -0000 1.26.4.1 ++++ gcc/gcc/regs.h 4 Dec 2004 00:36:38 -0000 1.26.4.3 +@@ -49,6 +49,9 @@ + int first_uid; /* UID of first insn to use (REG n) */ + int last_uid; /* UID of last insn to use (REG n) */ + int last_note_uid; /* UID of last note to use (REG n) */ ++ /* See the comment in reg_scan_mark_refs on ++ the relationship between last_uid and ++ last_note_uid. */ + + /* fields set by reg_scan & flow_analysis */ + int sets; /* # of times (REG n) is set */ +@@ -66,8 +69,6 @@ + + extern varray_type reg_n_info; + +-extern bitmap_head subregs_of_mode; +- + /* Indexed by n, gives number of times (REG n) is used or set. */ + + #define REG_N_REFS(N) (VARRAY_REG (reg_n_info, N)->refs) +Index: gcc/reload1.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/reload1.c,v +retrieving revision 1.366.2.11 +retrieving revision 1.366.2.12 +diff -u -r1.366.2.11 -r1.366.2.12 +--- gcc/gcc/reload1.c 13 Sep 2004 08:54:35 -0000 1.366.2.11 ++++ gcc/gcc/reload1.c 26 Nov 2004 05:08:45 -0000 1.366.2.12 +@@ -3389,6 +3389,16 @@ + num_not_at_initial_offset = 0; + } + ++/* Subroutine of set_initial_label_offsets called via for_each_eh_label. */ ++ ++static void set_initial_eh_label_offset PARAMS ((rtx)); ++static void ++set_initial_eh_label_offset (label) ++ rtx label; ++{ ++ set_label_offsets (label, NULL_RTX, 1); ++} ++ + /* Initialize the known label offsets. + Set a known offset for each forced label to be at the initial offset + of each elimination. We do this because we assume that all +@@ -3405,6 +3415,8 @@ + for (x = forced_labels; x; x = XEXP (x, 1)) + if (XEXP (x, 0)) + set_label_offsets (XEXP (x, 0), NULL_RTX, 1); ++ ++ for_each_eh_label (set_initial_eh_label_offset); + } + + /* Set all elimination offsets to the known values for the code label given +Index: gcc/rtl.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/rtl.h,v +retrieving revision 1.375.2.8 +retrieving revision 1.375.2.9 +diff -u -r1.375.2.8 -r1.375.2.9 +--- gcc/gcc/rtl.h 24 Apr 2004 19:40:45 -0000 1.375.2.8 ++++ gcc/gcc/rtl.h 4 Dec 2004 00:36:38 -0000 1.375.2.9 +@@ -2120,6 +2120,8 @@ + extern void reg_scan PARAMS ((rtx, unsigned int, int)); + extern void reg_scan_update PARAMS ((rtx, rtx, unsigned int)); + extern void fix_register PARAMS ((const char *, int, int)); ++extern void init_subregs_of_mode PARAMS ((void)); ++extern void record_subregs_of_mode PARAMS ((rtx)); + #ifdef HARD_CONST + extern void cannot_change_mode_set_regs PARAMS ((HARD_REG_SET *, + enum machine_mode, +Index: gcc/tree-inline.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/tree-inline.c,v +retrieving revision 1.38.2.12 +retrieving revision 1.38.2.13 +diff -u -r1.38.2.12 -r1.38.2.13 +--- gcc/gcc/tree-inline.c 12 Mar 2004 22:43:29 -0000 1.38.2.12 ++++ gcc/gcc/tree-inline.c 21 Jan 2005 10:02:12 -0000 1.38.2.13 +@@ -1173,7 +1173,8 @@ + if (!inlinable_function_p (fn, id)) + { + if (warn_inline && DECL_INLINE (fn) && !DID_INLINE_FUNC (fn) +- && !DECL_IN_SYSTEM_HEADER (fn)) ++ && !DECL_IN_SYSTEM_HEADER (fn) ++ && !lookup_attribute ("noinline", DECL_ATTRIBUTES (fn))) + { + warning_with_decl (fn, "inlining failed in call to `%s'"); + warning ("called from here"); +Index: gcc/unroll.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/Attic/unroll.c,v +retrieving revision 1.184.2.9 +retrieving revision 1.184.2.10 +diff -u -r1.184.2.9 -r1.184.2.10 +--- gcc/gcc/unroll.c 17 May 2004 21:05:48 -0000 1.184.2.9 ++++ gcc/gcc/unroll.c 27 Nov 2004 16:59:15 -0000 1.184.2.10 +@@ -794,6 +794,10 @@ + for (r = FIRST_PSEUDO_REGISTER; r < max_reg_before_loop; ++r) + if (REGNO_FIRST_UID (r) > 0 && REGNO_FIRST_UID (r) < max_uid_for_loop + && REGNO_FIRST_LUID (r) >= copy_start_luid ++ /* See the comment in reg_scan_mark_refs on the relationship between ++ last_uid and last_note_uid. */ ++ && REGNO_LAST_UID (r) > 0 && REGNO_LAST_UID (r) < max_uid_for_loop ++ && REGNO_LAST_LUID (r) <= copy_end_luid + && REGNO_LAST_NOTE_UID (r) > 0 && REGNO_LAST_NOTE_UID (r) < max_uid_for_loop + && REGNO_LAST_NOTE_LUID (r) <= copy_end_luid) + { +Index: gcc/unwind-dw2.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/unwind-dw2.c,v +retrieving revision 1.22.2.9 +retrieving revision 1.22.2.11 +diff -u -r1.22.2.9 -r1.22.2.11 +--- gcc/gcc/unwind-dw2.c 8 May 2004 21:52:42 -0000 1.22.2.9 ++++ gcc/gcc/unwind-dw2.c 29 Jan 2005 11:54:24 -0000 1.22.2.11 +@@ -1,5 +1,5 @@ + /* DWARF2 exception handling and frame unwind runtime interface routines. +- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 ++ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + + This file is part of GCC. +@@ -165,6 +165,11 @@ + inline _Unwind_Word + _Unwind_GetGR (struct _Unwind_Context *context, int index) + { ++#ifdef DWARF_ZERO_REG ++ if (index == DWARF_ZERO_REG) ++ return 0; ++#endif ++ + /* This will segfault if the register hasn't been saved. */ + return * (_Unwind_Word *) context->reg[index]; + } +@@ -604,6 +609,10 @@ + case DW_OP_mul: + case DW_OP_or: + case DW_OP_plus: ++ case DW_OP_shl: ++ case DW_OP_shr: ++ case DW_OP_shra: ++ case DW_OP_xor: + case DW_OP_le: + case DW_OP_ge: + case DW_OP_eq: +Index: gcc/config/freebsd-spec.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/freebsd-spec.h,v +retrieving revision 1.2.4.1 +retrieving revision 1.2.4.2 +diff -u -r1.2.4.1 -r1.2.4.2 +--- gcc/gcc/config/freebsd-spec.h 12 Mar 2003 02:38:01 -0000 1.2.4.1 ++++ gcc/gcc/config/freebsd-spec.h 14 Jan 2005 02:06:26 -0000 1.2.4.2 +@@ -130,13 +130,7 @@ + %{pg: -lc_p} \ + }" + #else +-#if FBSD_MAJOR >= 5 +-#define FBSD_LIB_SPEC " \ +- %{!shared: \ +- %{!pg: %{pthread:-lc_r} -lc} \ +- %{pg: %{pthread:-lc_r_p} -lc_p} \ +- }" +-#else ++#if FBSD_MAJOR < 5 + #define FBSD_LIB_SPEC " \ + %{!shared: \ + %{!pg: \ +@@ -146,5 +140,11 @@ + %{!pthread:-lc_p} \ + %{pthread:-lc_r_p}} \ + }" ++#else ++#define FBSD_LIB_SPEC " \ ++ %{!shared: \ ++ %{!pg: %{pthread:-lpthread} -lc} \ ++ %{pg: %{pthread:-lpthread_p} -lc_p} \ ++ }" + #endif + #endif +Index: gcc/config/alpha/alpha.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.c,v +retrieving revision 1.282.4.11 +retrieving revision 1.282.4.12 +diff -u -r1.282.4.11 -r1.282.4.12 +--- gcc/gcc/config/alpha/alpha.c 8 Mar 2004 03:21:46 -0000 1.282.4.11 ++++ gcc/gcc/config/alpha/alpha.c 30 Sep 2004 19:36:26 -0000 1.282.4.12 +@@ -6766,11 +6766,6 @@ + break; + imask |= 1L << regno; + } +- +- /* Glibc likes to use $31 as an unwind stopper for crt0. To +- avoid hackery in unwind-dw2.c, we need to actively store a +- zero in the prologue of _Unwind_RaiseException et al. */ +- imask |= 1UL << 31; + } + + /* If any register spilled, then spill the return address also. */ +@@ -7236,24 +7231,6 @@ + reg_offset += 8; + } + +- /* Store a zero if requested for unwinding. */ +- if (imask & (1UL << 31)) +- { +- rtx insn, t; +- +- mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset)); +- set_mem_alias_set (mem, alpha_sr_alias_set); +- insn = emit_move_insn (mem, const0_rtx); +- +- RTX_FRAME_RELATED_P (insn) = 1; +- t = gen_rtx_REG (Pmode, 31); +- t = gen_rtx_SET (VOIDmode, mem, t); +- t = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, t, REG_NOTES (insn)); +- REG_NOTES (insn) = t; +- +- reg_offset += 8; +- } +- + for (i = 0; i < 31; i++) + if (fmask & (1L << i)) + { +@@ -7674,9 +7651,6 @@ + reg_offset += 8; + } + +- if (imask & (1UL << 31)) +- reg_offset += 8; +- + for (i = 0; i < 31; ++i) + if (fmask & (1L << i)) + { +Index: gcc/config/alpha/alpha.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.h,v +retrieving revision 1.185.4.6 +retrieving revision 1.185.4.7 +diff -u -r1.185.4.6 -r1.185.4.7 +--- gcc/gcc/config/alpha/alpha.h 27 Aug 2004 00:01:15 -0000 1.185.4.6 ++++ gcc/gcc/config/alpha/alpha.h 30 Sep 2004 19:36:28 -0000 1.185.4.7 +@@ -1299,6 +1299,7 @@ + #define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (Pmode, 26) + #define DWARF_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (26) + #define DWARF_ALT_FRAME_RETURN_COLUMN DWARF_FRAME_REGNUM (64) ++#define DWARF_ZERO_REG 31 + + /* Describe how we implement __builtin_eh_return. */ + #define EH_RETURN_DATA_REGNO(N) ((N) < 4 ? (N) + 16 : INVALID_REGNUM) +Index: gcc/config/alpha/alpha.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/alpha/alpha.md,v +retrieving revision 1.199.4.6 +retrieving revision 1.199.4.7 +diff -u -r1.199.4.6 -r1.199.4.7 +--- gcc/gcc/config/alpha/alpha.md 28 May 2004 00:02:03 -0000 1.199.4.6 ++++ gcc/gcc/config/alpha/alpha.md 5 Dec 2004 19:58:42 -0000 1.199.4.7 +@@ -80,6 +80,7 @@ + (UNSPECV_PLDGP2 11) ; prologue ldgp + (UNSPECV_SET_TP 12) + (UNSPECV_RPCC 13) ++ (UNSPECV_SETJMPR_ER 14) ; builtin_setjmp_receiver fragment + ]) + + ;; Where necessary, the suffixes _le and _be are used to distinguish between +@@ -6764,70 +6765,44 @@ + "jmp $31,(%0),0" + [(set_attr "type" "ibr")]) + +-(define_insn "*builtin_setjmp_receiver_er_sl_1" +- [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)] +- "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF && TARGET_AS_CAN_SUBTRACT_LABELS" +- "lda $27,$LSJ%=-%l0($27)\n$LSJ%=:") +- +-(define_insn "*builtin_setjmp_receiver_er_1" +- [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)] +- "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" +- "br $27,$LSJ%=\n$LSJ%=:" +- [(set_attr "type" "ibr")]) +- +-(define_split +- [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)] +- "TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF +- && prev_nonnote_insn (insn) == operands[0]" +- [(const_int 0)] +- " +-{ +- emit_note (NULL, NOTE_INSN_DELETED); +- DONE; +-}") +- +-(define_insn "*builtin_setjmp_receiver_1" ++(define_expand "builtin_setjmp_receiver" + [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)] + "TARGET_ABI_OSF" +- "br $27,$LSJ%=\n$LSJ%=:\;ldgp $29,0($27)" +- [(set_attr "length" "12") +- (set_attr "type" "multi")]) ++ "") + +-(define_expand "builtin_setjmp_receiver_er" +- [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR) ++(define_insn_and_split "*builtin_setjmp_receiver_1" ++ [(unspec_volatile [(match_operand 0 "" "")] UNSPECV_SETJMPR)] ++ "TARGET_ABI_OSF" ++{ ++ if (TARGET_EXPLICIT_RELOCS) ++ return "#"; ++ else ++ return "br $27,$LSJ%=\n$LSJ%=:\;ldgp $29,0($27)"; ++} ++ "&& TARGET_EXPLICIT_RELOCS && reload_completed" ++ [(unspec_volatile [(match_dup 0)] UNSPECV_SETJMPR_ER) + (set (match_dup 1) + (unspec_volatile:DI [(match_dup 2) (match_dup 3)] UNSPECV_LDGP1)) + (set (match_dup 1) + (unspec:DI [(match_dup 1) (match_dup 3)] UNSPEC_LDGP2))] +- "" + { + operands[1] = pic_offset_table_rtx; + operands[2] = gen_rtx_REG (Pmode, 27); + operands[3] = GEN_INT (alpha_next_sequence_number++); +-}) ++} ++ [(set_attr "length" "12") ++ (set_attr "type" "multi")]) + +-(define_expand "builtin_setjmp_receiver" +- [(unspec_volatile [(label_ref (match_operand 0 "" ""))] UNSPECV_SETJMPR)] +- "TARGET_ABI_OSF" +-{ +- if (TARGET_EXPLICIT_RELOCS) +- { +- emit_insn (gen_builtin_setjmp_receiver_er (operands[0])); +- DONE; +- } +-}) ++(define_insn "*builtin_setjmp_receiver_er_sl_1" ++ [(unspec_volatile [(match_operand 0 "" "")] UNSPECV_SETJMPR_ER)] ++ "TARGET_ABI_OSF && TARGET_EXPLICIT_RELOCS && TARGET_AS_CAN_SUBTRACT_LABELS" ++ "lda $27,$LSJ%=-%l0($27)\n$LSJ%=:") + +-(define_expand "exception_receiver_er" +- [(set (match_dup 0) +- (unspec_volatile:DI [(match_dup 1) (match_dup 2)] UNSPECV_LDGP1)) +- (set (match_dup 0) +- (unspec:DI [(match_dup 0) (match_dup 2)] UNSPEC_LDGP2))] +- "" +-{ +- operands[0] = pic_offset_table_rtx; +- operands[1] = gen_rtx_REG (Pmode, 26); +- operands[2] = GEN_INT (alpha_next_sequence_number++); +-}) ++(define_insn "*builtin_setjmp_receiver_er_1" ++ [(unspec_volatile [(match_operand 0 "" "")] UNSPECV_SETJMPR_ER)] ++ "TARGET_ABI_OSF && TARGET_EXPLICIT_RELOCS" ++ "br $27,$LSJ%=\n$LSJ%=:" ++ [(set_attr "type" "ibr")]) + + (define_expand "exception_receiver" + [(unspec_volatile [(match_dup 0)] UNSPECV_EHR)] +@@ -6835,28 +6810,38 @@ + { + if (TARGET_LD_BUGGY_LDGP) + operands[0] = alpha_gp_save_rtx (); +- else if (TARGET_EXPLICIT_RELOCS) +- { +- emit_insn (gen_exception_receiver_er ()); +- DONE; +- } + else + operands[0] = const0_rtx; + }) + +-(define_insn "*exception_receiver_1" +- [(unspec_volatile [(const_int 0)] UNSPECV_EHR)] +- "! TARGET_LD_BUGGY_LDGP" +- "ldgp $29,0($26)" +- [(set_attr "length" "8") +- (set_attr "type" "multi")]) +- + (define_insn "*exception_receiver_2" + [(unspec_volatile [(match_operand:DI 0 "memory_operand" "m")] UNSPECV_EHR)] +- "TARGET_LD_BUGGY_LDGP" ++ "TARGET_ABI_OSF && TARGET_LD_BUGGY_LDGP" + "ldq $29,%0" + [(set_attr "type" "ild")]) + ++(define_insn_and_split "*exception_receiver_1" ++ [(unspec_volatile [(const_int 0)] UNSPECV_EHR)] ++ "TARGET_ABI_OSF" ++{ ++ if (TARGET_EXPLICIT_RELOCS) ++ return "ldah $29,0($26)\t\t!gpdisp!%*\;lda $29,0($29)\t\t!gpdisp!%*"; ++ else ++ return "ldgp $29,0($26)"; ++} ++ "&& TARGET_EXPLICIT_RELOCS && reload_completed" ++ [(set (match_dup 0) ++ (unspec_volatile:DI [(match_dup 1) (match_dup 2)] UNSPECV_LDGP1)) ++ (set (match_dup 0) ++ (unspec:DI [(match_dup 0) (match_dup 2)] UNSPEC_LDGP2))] ++{ ++ operands[0] = pic_offset_table_rtx; ++ operands[1] = gen_rtx_REG (Pmode, 26); ++ operands[2] = GEN_INT (alpha_next_sequence_number++); ++} ++ [(set_attr "length" "8") ++ (set_attr "type" "multi")]) ++ + (define_expand "nonlocal_goto_receiver" + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE) + (set (reg:DI 27) (mem:DI (reg:DI 29))) +Index: gcc/config/alpha/qrnnd.asm +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/alpha/qrnnd.asm,v +retrieving revision 1.1 +retrieving revision 1.1.60.1 +diff -u -r1.1 -r1.1.60.1 +--- gcc/gcc/config/alpha/qrnnd.asm 15 Apr 2000 16:34:38 -0000 1.1 ++++ gcc/gcc/config/alpha/qrnnd.asm 30 Sep 2004 19:36:28 -0000 1.1.60.1 +@@ -26,6 +26,10 @@ + # Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + # MA 02111-1307, USA. + ++#ifdef __ELF__ ++.section .note.GNU-stack,"" ++#endif ++ + .set noreorder + .set noat + +Index: gcc/config/i386/i386-protos.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/i386/i386-protos.h,v +retrieving revision 1.86.2.2 +retrieving revision 1.86.2.3 +diff -u -r1.86.2.2 -r1.86.2.3 +--- gcc/gcc/config/i386/i386-protos.h 8 Jul 2003 19:16:44 -0000 1.86.2.2 ++++ gcc/gcc/config/i386/i386-protos.h 12 Dec 2004 21:00:44 -0000 1.86.2.3 +@@ -88,6 +88,8 @@ + extern int cmpsi_operand PARAMS ((rtx, enum machine_mode)); + extern int long_memory_operand PARAMS ((rtx, enum machine_mode)); + extern int aligned_operand PARAMS ((rtx, enum machine_mode)); ++extern int compare_operator PARAMS ((rtx, enum machine_mode)); ++extern int flags_reg_operand PARAMS ((rtx, enum machine_mode)); + extern enum machine_mode ix86_cc_mode PARAMS ((enum rtx_code, rtx, rtx)); + + extern int ix86_expand_movstr PARAMS ((rtx, rtx, rtx, rtx)); +Index: gcc/config/i386/i386.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.c,v +retrieving revision 1.495.2.36 +retrieving revision 1.495.2.37 +diff -u -r1.495.2.36 -r1.495.2.37 +--- gcc/gcc/config/i386/i386.c 18 May 2004 05:07:52 -0000 1.495.2.36 ++++ gcc/gcc/config/i386/i386.c 12 Dec 2004 21:00:44 -0000 1.495.2.37 +@@ -3609,6 +3609,20 @@ + return ANY_QI_REG_P (op); + } + ++/* Return true if op is an flags register. */ ++ ++int ++flags_reg_operand (op, mode) ++ register rtx op; ++ enum machine_mode mode; ++{ ++ if (mode != VOIDmode && GET_MODE (op) != mode) ++ return 0; ++ return (GET_CODE (op) == REG ++ && REGNO (op) == FLAGS_REG ++ && GET_MODE (op) != VOIDmode); ++} ++ + /* Return true if op is a NON_Q_REGS class register. */ + + int +@@ -3969,6 +3983,14 @@ + /* Didn't find one -- this must be an aligned address. */ + return 1; + } ++ ++int ++compare_operator (op, mode) ++ rtx op; ++ enum machine_mode mode ATTRIBUTE_UNUSED; ++{ ++ return GET_CODE (op) == COMPARE; ++} + + /* Return true if the constant is something that can be loaded with + a special instruction. Only handle 0.0 and 1.0; others are less +Index: gcc/config/i386/i386.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.h,v +retrieving revision 1.309.2.11 +retrieving revision 1.309.2.12 +diff -u -r1.309.2.11 -r1.309.2.12 +--- gcc/gcc/config/i386/i386.h 6 Feb 2004 19:43:31 -0000 1.309.2.11 ++++ gcc/gcc/config/i386/i386.h 12 Dec 2004 21:00:47 -0000 1.309.2.12 +@@ -3319,6 +3319,7 @@ + SYMBOL_REF, LABEL_REF, SUBREG, REG, MEM}}, \ + {"nonmemory_no_elim_operand", {CONST_INT, REG, SUBREG}}, \ + {"index_register_operand", {SUBREG, REG}}, \ ++ {"flags_reg_operand", {REG}}, \ + {"q_regs_operand", {SUBREG, REG}}, \ + {"non_q_regs_operand", {SUBREG, REG}}, \ + {"fcmov_comparison_operator", {EQ, NE, LTU, GTU, LEU, GEU, UNORDERED, \ +@@ -3354,6 +3355,7 @@ + {"fp_register_operand", {REG}}, \ + {"register_and_not_fp_reg_operand", {REG}}, \ + {"vector_move_operand", {CONST_VECTOR, SUBREG, REG, MEM}}, \ ++ {"compare_operator", {COMPARE}}, + + /* A list of predicates that do special things with modes, and so + should not elicit warnings for VOIDmode match_operand. */ +Index: gcc/config/i386/i386.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/i386/i386.md,v +retrieving revision 1.404.2.24 +retrieving revision 1.404.2.29 +diff -u -r1.404.2.24 -r1.404.2.29 +--- gcc/gcc/config/i386/i386.md 28 Apr 2004 17:00:03 -0000 1.404.2.24 ++++ gcc/gcc/config/i386/i386.md 23 Jan 2005 05:15:59 -0000 1.404.2.29 +@@ -1188,10 +1188,9 @@ + "" + "xchg{l}\t%1, %0" + [(set_attr "type" "imov") ++ (set_attr "mode" "SI") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") +- (set_attr "mode" "SI") +- (set_attr "modrm" "0") + (set_attr "ppro_uops" "few")]) + + (define_expand "movhi" +@@ -1304,12 +1303,12 @@ + (match_operand:HI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] +- "TARGET_PARTIAL_REG_STALL" +- "xchg{w}\t%1, %0" ++ "!TARGET_PARTIAL_REG_STALL || optimize_size" ++ "xchg{l}\t%k1, %k0" + [(set_attr "type" "imov") ++ (set_attr "mode" "SI") + (set_attr "pent_pair" "np") +- (set_attr "mode" "HI") +- (set_attr "modrm" "0") ++ (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) + + (define_insn "*swaphi_2" +@@ -1317,12 +1316,12 @@ + (match_operand:HI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] +- "! TARGET_PARTIAL_REG_STALL" +- "xchg{l}\t%k1, %k0" ++ "TARGET_PARTIAL_REG_STALL" ++ "xchg{w}\t%1, %0" + [(set_attr "type" "imov") ++ (set_attr "mode" "HI") + (set_attr "pent_pair" "np") +- (set_attr "mode" "SI") +- (set_attr "modrm" "0") ++ (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) + + (define_expand "movstricthi" +@@ -1470,17 +1469,30 @@ + DONE; + }) + +-(define_insn "*swapqi" ++(define_insn "*swapqi_1" + [(set (match_operand:QI 0 "register_operand" "+r") + (match_operand:QI 1 "register_operand" "+r")) + (set (match_dup 1) + (match_dup 0))] +- "" +- "xchg{b}\t%1, %0" ++ "!TARGET_PARTIAL_REG_STALL || optimize_size" ++ "xchg{l}\t%k1, %k0" + [(set_attr "type" "imov") ++ (set_attr "mode" "SI") + (set_attr "pent_pair" "np") ++ (set_attr "athlon_decode" "vector") ++ (set_attr "ppro_uops" "few")]) ++ ++(define_insn "*swapqi_2" ++ [(set (match_operand:QI 0 "register_operand" "+q") ++ (match_operand:QI 1 "register_operand" "+q")) ++ (set (match_dup 1) ++ (match_dup 0))] ++ "TARGET_PARTIAL_REG_STALL" ++ "xchg{b}\t%1, %0" ++ [(set_attr "type" "imov") + (set_attr "mode" "QI") +- (set_attr "modrm" "0") ++ (set_attr "pent_pair" "np") ++ (set_attr "athlon_decode" "vector") + (set_attr "ppro_uops" "few")]) + + (define_expand "movstrictqi" +@@ -1987,13 +1999,11 @@ + "TARGET_64BIT" + "xchg{q}\t%1, %0" + [(set_attr "type" "imov") ++ (set_attr "mode" "DI") + (set_attr "pent_pair" "np") + (set_attr "athlon_decode" "vector") +- (set_attr "mode" "DI") +- (set_attr "modrm" "0") + (set_attr "ppro_uops" "few")]) + +- + (define_expand "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "general_operand" ""))] +@@ -7559,17 +7569,21 @@ + "" + "") + +-(define_insn "*testqi_1" ++(define_insn "*testqi_1_maybe_si" + [(set (reg 17) +- (compare (and:QI (match_operand:QI 0 "nonimmediate_operand" "%*a,q,qm,r") +- (match_operand:QI 1 "nonmemory_operand" "n,n,qn,n")) +- (const_int 0)))] +- "ix86_match_ccmode (insn, CCNOmode)" ++ (compare ++ (and:QI ++ (match_operand:QI 0 "nonimmediate_operand" "%*a,q,qm,r") ++ (match_operand:QI 1 "nonmemory_operand" "n,n,qn,n")) ++ (const_int 0)))] ++ "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM) ++ && ix86_match_ccmode (insn, ++ GET_CODE (operands[1]) == CONST_INT ++ && INTVAL (operands[1]) >= 0 ? CCNOmode : CCZmode)" + { + if (which_alternative == 3) + { +- if (GET_CODE (operands[1]) == CONST_INT +- && (INTVAL (operands[1]) & 0xffffff00)) ++ if (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) < 0) + operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff); + return "test{l}\t{%1, %k0|%k0, %1}"; + } +@@ -7580,6 +7594,18 @@ + (set_attr "mode" "QI,QI,QI,SI") + (set_attr "pent_pair" "uv,np,uv,np")]) + ++(define_insn "*testqi_1" ++ [(set (reg 17) ++ (compare (and:QI (match_operand:QI 0 "nonimmediate_operand" "%*a,q,qm") ++ (match_operand:QI 1 "nonmemory_operand" "n,n,qn")) ++ (const_int 0)))] ++ "ix86_match_ccmode (insn, CCNOmode)" ++ "test{b}\t{%1, %0|%0, %1}" ++ [(set_attr "type" "test") ++ (set_attr "modrm" "0,1,1") ++ (set_attr "mode" "QI") ++ (set_attr "pent_pair" "uv,np,uv")]) ++ + (define_expand "testqi_ext_ccno_0" + [(set (reg:CCNO 17) + (compare:CCNO +@@ -7697,51 +7723,53 @@ + "#") + + (define_split +- [(set (reg 17) +- (compare (zero_extract +- (match_operand 0 "nonimmediate_operand" "") +- (match_operand 1 "const_int_operand" "") +- (match_operand 2 "const_int_operand" "")) +- (const_int 0)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(zero_extract ++ (match_operand 2 "nonimmediate_operand" "") ++ (match_operand 3 "const_int_operand" "") ++ (match_operand 4 "const_int_operand" "")) ++ (const_int 0)]))] + "ix86_match_ccmode (insn, CCNOmode)" +- [(set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))] ++ [(set (match_dup 0) (match_op_dup 1 [(match_dup 2) (const_int 0)]))] + { +- HOST_WIDE_INT len = INTVAL (operands[1]); +- HOST_WIDE_INT pos = INTVAL (operands[2]); ++ rtx val = operands[2]; ++ HOST_WIDE_INT len = INTVAL (operands[3]); ++ HOST_WIDE_INT pos = INTVAL (operands[4]); + HOST_WIDE_INT mask; + enum machine_mode mode, submode; + +- mode = GET_MODE (operands[0]); +- if (GET_CODE (operands[0]) == MEM) ++ mode = GET_MODE (val); ++ if (GET_CODE (val) == MEM) + { + /* ??? Combine likes to put non-volatile mem extractions in QImode + no matter the size of the test. So find a mode that works. */ +- if (! MEM_VOLATILE_P (operands[0])) ++ if (! MEM_VOLATILE_P (val)) + { + mode = smallest_mode_for_size (pos + len, MODE_INT); +- operands[0] = adjust_address (operands[0], mode, 0); ++ val = adjust_address (val, mode, 0); + } + } +- else if (GET_CODE (operands[0]) == SUBREG +- && (submode = GET_MODE (SUBREG_REG (operands[0])), ++ else if (GET_CODE (val) == SUBREG ++ && (submode = GET_MODE (SUBREG_REG (val)), + GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (submode)) + && pos + len <= GET_MODE_BITSIZE (submode)) + { + /* Narrow a paradoxical subreg to prevent partial register stalls. */ + mode = submode; +- operands[0] = SUBREG_REG (operands[0]); ++ val = SUBREG_REG (val); + } + else if (mode == HImode && pos + len <= 8) + { + /* Small HImode tests can be converted to QImode. */ + mode = QImode; +- operands[0] = gen_lowpart (QImode, operands[0]); ++ val = gen_lowpart (QImode, val); + } + + mask = ((HOST_WIDE_INT)1 << (pos + len)) - 1; + mask &= ~(((HOST_WIDE_INT)1 << pos) - 1); + +- operands[3] = gen_rtx_AND (mode, operands[0], gen_int_mode (mask, mode)); ++ operands[2] = gen_rtx_AND (mode, val, gen_int_mode (mask, mode)); + }) + + ;; Convert HImode/SImode test instructions with immediate to QImode ones. +@@ -7750,46 +7778,44 @@ + ;; Do the converison only post-reload to avoid limiting of the register class + ;; to QI regs. + (define_split +- [(set (reg 17) +- (compare +- (and (match_operand 0 "register_operand" "") +- (match_operand 1 "const_int_operand" "")) +- (const_int 0)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(and (match_operand 2 "register_operand" "") ++ (match_operand 3 "const_int_operand" "")) ++ (const_int 0)]))] + "reload_completed +- && QI_REG_P (operands[0]) ++ && QI_REG_P (operands[2]) ++ && GET_MODE (operands[2]) != QImode + && ((ix86_match_ccmode (insn, CCZmode) +- && !(INTVAL (operands[1]) & ~(255 << 8))) ++ && !(INTVAL (operands[3]) & ~(255 << 8))) + || (ix86_match_ccmode (insn, CCNOmode) +- && !(INTVAL (operands[1]) & ~(127 << 8)))) +- && GET_MODE (operands[0]) != QImode" +- [(set (reg:CCNO 17) +- (compare:CCNO +- (and:SI (zero_extract:SI (match_dup 0) (const_int 8) (const_int 8)) +- (match_dup 1)) +- (const_int 0)))] +- "operands[0] = gen_lowpart (SImode, operands[0]); +- operands[1] = gen_int_mode (INTVAL (operands[1]) >> 8, SImode);") ++ && !(INTVAL (operands[3]) & ~(127 << 8))))" ++ [(set (match_dup 0) ++ (match_op_dup 1 ++ [(and:SI (zero_extract:SI (match_dup 2) (const_int 8) (const_int 8)) ++ (match_dup 3)) ++ (const_int 0)]))] ++ "operands[2] = gen_lowpart (SImode, operands[2]); ++ operands[3] = gen_int_mode (INTVAL (operands[3]) >> 8, SImode);") + + (define_split +- [(set (reg 17) +- (compare +- (and (match_operand 0 "nonimmediate_operand" "") +- (match_operand 1 "const_int_operand" "")) +- (const_int 0)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(and (match_operand 2 "nonimmediate_operand" "") ++ (match_operand 3 "const_int_operand" "")) ++ (const_int 0)]))] + "reload_completed +- && (!REG_P (operands[0]) || ANY_QI_REG_P (operands[0])) ++ && GET_MODE (operands[2]) != QImode ++ && (!REG_P (operands[2]) || ANY_QI_REG_P (operands[2])) + && ((ix86_match_ccmode (insn, CCZmode) +- && !(INTVAL (operands[1]) & ~255)) ++ && !(INTVAL (operands[3]) & ~255)) + || (ix86_match_ccmode (insn, CCNOmode) +- && !(INTVAL (operands[1]) & ~127))) +- && GET_MODE (operands[0]) != QImode" +- [(set (reg:CCNO 17) +- (compare:CCNO +- (and:QI (match_dup 0) +- (match_dup 1)) +- (const_int 0)))] +- "operands[0] = gen_lowpart (QImode, operands[0]); +- operands[1] = gen_lowpart (QImode, operands[1]);") ++ && !(INTVAL (operands[3]) & ~127)))" ++ [(set (match_dup 0) ++ (match_op_dup 1 [(and:QI (match_dup 2) (match_dup 3)) ++ (const_int 0)]))] ++ "operands[2] = gen_lowpart (QImode, operands[2]); ++ operands[3] = gen_lowpart (QImode, operands[3]);") + + + ;; %%% This used to optimize known byte-wide and operations to memory, +@@ -8066,7 +8092,7 @@ + [(set_attr "type" "alu1") + (set_attr "mode" "QI")]) + +-(define_insn "*andqi_2" ++(define_insn "*andqi_2_maybe_si" + [(set (reg 17) + (compare (and:QI + (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") +@@ -8074,13 +8100,14 @@ + (const_int 0))) + (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm,*r") + (and:QI (match_dup 1) (match_dup 2)))] +- "ix86_match_ccmode (insn, CCNOmode) +- && ix86_binary_operator_ok (AND, QImode, operands)" ++ "ix86_binary_operator_ok (AND, QImode, operands) ++ && ix86_match_ccmode (insn, ++ GET_CODE (operands[2]) == CONST_INT ++ && INTVAL (operands[2]) >= 0 ? CCNOmode : CCZmode)" + { + if (which_alternative == 2) + { +- if (GET_CODE (operands[2]) == CONST_INT +- && (INTVAL (operands[2]) & 0xffffff00)) ++ if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0) + operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff); + return "and{l}\t{%2, %k0|%k0, %2}"; + } +@@ -8089,6 +8116,20 @@ + [(set_attr "type" "alu") + (set_attr "mode" "QI,QI,SI")]) + ++(define_insn "*andqi_2" ++ [(set (reg 17) ++ (compare (and:QI ++ (match_operand:QI 1 "nonimmediate_operand" "%0,0") ++ (match_operand:QI 2 "general_operand" "qim,qi")) ++ (const_int 0))) ++ (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") ++ (and:QI (match_dup 1) (match_dup 2)))] ++ "ix86_match_ccmode (insn, CCNOmode) ++ && ix86_binary_operator_ok (AND, QImode, operands)" ++ "and{b}\t{%2, %0|%0, %2}" ++ [(set_attr "type" "alu") ++ (set_attr "mode" "QI")]) ++ + (define_insn "*andqi_2_slp" + [(set (reg 17) + (compare (and:QI +@@ -10147,17 +10188,19 @@ + (set_attr "mode" "DI")]) + + (define_split +- [(set (reg 17) +- (compare (not:DI (match_operand:DI 1 "nonimmediate_operand" "")) +- (const_int 0))) +- (set (match_operand:DI 0 "nonimmediate_operand" "") +- (not:DI (match_dup 1)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 2 "compare_operator" ++ [(not:DI (match_operand:DI 3 "nonimmediate_operand" "")) ++ (const_int 0)])) ++ (set (match_operand:DI 1 "nonimmediate_operand" "") ++ (not:DI (match_dup 3)))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)" +- [(parallel [(set (reg:CCNO 17) +- (compare:CCNO (xor:DI (match_dup 1) (const_int -1)) +- (const_int 0))) +- (set (match_dup 0) +- (xor:DI (match_dup 1) (const_int -1)))])] ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 2 ++ [(xor:DI (match_dup 3) (const_int -1)) ++ (const_int 0)])) ++ (set (match_dup 1) ++ (xor:DI (match_dup 3) (const_int -1)))])] + "") + + (define_expand "one_cmplsi2" +@@ -10196,17 +10239,18 @@ + (set_attr "mode" "SI")]) + + (define_split +- [(set (reg 17) +- (compare (not:SI (match_operand:SI 1 "nonimmediate_operand" "")) +- (const_int 0))) +- (set (match_operand:SI 0 "nonimmediate_operand" "") +- (not:SI (match_dup 1)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 2 "compare_operator" ++ [(not:SI (match_operand:SI 3 "nonimmediate_operand" "")) ++ (const_int 0)])) ++ (set (match_operand:SI 1 "nonimmediate_operand" "") ++ (not:SI (match_dup 3)))] + "ix86_match_ccmode (insn, CCNOmode)" +- [(parallel [(set (reg:CCNO 17) +- (compare:CCNO (xor:SI (match_dup 1) (const_int -1)) +- (const_int 0))) +- (set (match_dup 0) +- (xor:SI (match_dup 1) (const_int -1)))])] ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 2 [(xor:SI (match_dup 3) (const_int -1)) ++ (const_int 0)])) ++ (set (match_dup 1) ++ (xor:SI (match_dup 3) (const_int -1)))])] + "") + + ;; ??? Currently never generated - xor is used instead. +@@ -10223,17 +10267,18 @@ + (set_attr "mode" "SI")]) + + (define_split +- [(set (reg 17) +- (compare (not:SI (match_operand:SI 1 "register_operand" "")) +- (const_int 0))) +- (set (match_operand:DI 0 "register_operand" "") +- (zero_extend:DI (not:SI (match_dup 1))))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 2 "compare_operator" ++ [(not:SI (match_operand:SI 3 "register_operand" "")) ++ (const_int 0)])) ++ (set (match_operand:DI 1 "register_operand" "") ++ (zero_extend:DI (not:SI (match_dup 3))))] + "ix86_match_ccmode (insn, CCNOmode)" +- [(parallel [(set (reg:CCNO 17) +- (compare:CCNO (xor:SI (match_dup 1) (const_int -1)) +- (const_int 0))) +- (set (match_dup 0) +- (zero_extend:DI (xor:SI (match_dup 1) (const_int -1))))])] ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 2 [(xor:SI (match_dup 3) (const_int -1)) ++ (const_int 0)])) ++ (set (match_dup 1) ++ (zero_extend:DI (xor:SI (match_dup 3) (const_int -1))))])] + "") + + (define_expand "one_cmplhi2" +@@ -10263,17 +10308,18 @@ + (set_attr "mode" "HI")]) + + (define_split +- [(set (reg 17) +- (compare (not:HI (match_operand:HI 1 "nonimmediate_operand" "")) +- (const_int 0))) +- (set (match_operand:HI 0 "nonimmediate_operand" "") +- (not:HI (match_dup 1)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 2 "compare_operator" ++ [(not:HI (match_operand:HI 3 "nonimmediate_operand" "")) ++ (const_int 0)])) ++ (set (match_operand:HI 1 "nonimmediate_operand" "") ++ (not:HI (match_dup 3)))] + "ix86_match_ccmode (insn, CCNOmode)" +- [(parallel [(set (reg:CCNO 17) +- (compare:CCNO (xor:HI (match_dup 1) (const_int -1)) +- (const_int 0))) +- (set (match_dup 0) +- (xor:HI (match_dup 1) (const_int -1)))])] ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 2 [(xor:HI (match_dup 3) (const_int -1)) ++ (const_int 0)])) ++ (set (match_dup 1) ++ (xor:HI (match_dup 3) (const_int -1)))])] + "") + + ;; %%% Potential partial reg stall on alternative 1. What to do? +@@ -10306,17 +10352,18 @@ + (set_attr "mode" "QI")]) + + (define_split +- [(set (reg 17) +- (compare (not:QI (match_operand:QI 1 "nonimmediate_operand" "")) +- (const_int 0))) +- (set (match_operand:QI 0 "nonimmediate_operand" "") +- (not:QI (match_dup 1)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 2 "compare_operator" ++ [(not:QI (match_operand:QI 3 "nonimmediate_operand" "")) ++ (const_int 0)])) ++ (set (match_operand:QI 1 "nonimmediate_operand" "") ++ (not:QI (match_dup 3)))] + "ix86_match_ccmode (insn, CCNOmode)" +- [(parallel [(set (reg:CCNO 17) +- (compare:CCNO (xor:QI (match_dup 1) (const_int -1)) +- (const_int 0))) +- (set (match_dup 0) +- (xor:QI (match_dup 1) (const_int -1)))])] ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 2 [(xor:QI (match_dup 3) (const_int -1)) ++ (const_int 0)])) ++ (set (match_dup 1) ++ (xor:QI (match_dup 3) (const_int -1)))])] + "") + + ;; Arithmetic shift instructions +@@ -16639,10 +16686,12 @@ + (set (subreg:TI (match_dup 0) 0) (ior:TI (subreg:TI (match_dup 6) 0) + (subreg:TI (match_dup 7) 0)))] + { +- /* If op2 == op3, op3 will be clobbered before it is used. +- This should be optimized out though. */ ++ /* If op2 == op3, op3 would be clobbered before it is used. */ + if (operands_match_p (operands[2], operands[3])) +- abort (); ++ { ++ emit_move_insn (operands[0], operands[2]); ++ DONE; ++ } + PUT_MODE (operands[1], GET_MODE (operands[0])); + if (operands_match_p (operands[0], operands[4])) + operands[6] = operands[4], operands[7] = operands[2]; +@@ -16863,52 +16912,56 @@ + ; instruction size is unchanged, except in the %eax case for + ; which it is increased by one byte, hence the ! optimize_size. + (define_split +- [(set (reg 17) +- (compare (and (match_operand 1 "aligned_operand" "") +- (match_operand 2 "const_int_operand" "")) +- (const_int 0))) +- (set (match_operand 0 "register_operand" "") +- (and (match_dup 1) (match_dup 2)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 2 "compare_operator" ++ [(and (match_operand 3 "aligned_operand" "") ++ (match_operand 4 "const_int_operand" "")) ++ (const_int 0)])) ++ (set (match_operand 1 "register_operand" "") ++ (and (match_dup 3) (match_dup 4)))] + "! TARGET_PARTIAL_REG_STALL && reload_completed + /* Ensure that the operand will remain sign-extended immediate. */ +- && ix86_match_ccmode (insn, INTVAL (operands[2]) >= 0 ? CCNOmode : CCZmode) ++ && ix86_match_ccmode (insn, INTVAL (operands[4]) >= 0 ? CCNOmode : CCZmode) + && ! optimize_size +- && ((GET_MODE (operands[0]) == HImode && ! TARGET_FAST_PREFIX) +- || (GET_MODE (operands[0]) == QImode && TARGET_PROMOTE_QImode))" +- [(parallel [(set (reg:CCNO 17) +- (compare:CCNO (and:SI (match_dup 1) (match_dup 2)) +- (const_int 0))) +- (set (match_dup 0) +- (and:SI (match_dup 1) (match_dup 2)))])] +- "operands[2] +- = gen_int_mode (INTVAL (operands[2]) +- & GET_MODE_MASK (GET_MODE (operands[0])), +- SImode); +- operands[0] = gen_lowpart (SImode, operands[0]); +- operands[1] = gen_lowpart (SImode, operands[1]);") ++ && ((GET_MODE (operands[1]) == HImode && ! TARGET_FAST_PREFIX) ++ || (GET_MODE (operands[1]) == QImode && TARGET_PROMOTE_QImode))" ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 2 [(and:SI (match_dup 3) (match_dup 4)) ++ (const_int 0)])) ++ (set (match_dup 1) ++ (and:SI (match_dup 3) (match_dup 4)))])] ++{ ++ operands[4] ++ = gen_int_mode (INTVAL (operands[4]) ++ & GET_MODE_MASK (GET_MODE (operands[1])), SImode); ++ operands[1] = gen_lowpart (SImode, operands[1]); ++ operands[3] = gen_lowpart (SImode, operands[3]); ++}) + + ; Don't promote the QImode tests, as i386 doesn't have encoding of + ; the TEST instruction with 32-bit sign-extended immediate and thus + ; the instruction size would at least double, which is not what we + ; want even with ! optimize_size. + (define_split +- [(set (reg 17) +- (compare (and (match_operand:HI 0 "aligned_operand" "") +- (match_operand:HI 1 "const_int_operand" "")) +- (const_int 0)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(and (match_operand:HI 2 "aligned_operand" "") ++ (match_operand:HI 3 "const_int_operand" "")) ++ (const_int 0)]))] + "! TARGET_PARTIAL_REG_STALL && reload_completed + /* Ensure that the operand will remain sign-extended immediate. */ +- && ix86_match_ccmode (insn, INTVAL (operands[1]) >= 0 ? CCNOmode : CCZmode) ++ && ix86_match_ccmode (insn, INTVAL (operands[3]) >= 0 ? CCNOmode : CCZmode) + && ! TARGET_FAST_PREFIX + && ! optimize_size" +- [(set (reg:CCNO 17) +- (compare:CCNO (and:SI (match_dup 0) (match_dup 1)) +- (const_int 0)))] +- "operands[1] +- = gen_int_mode (INTVAL (operands[1]) +- & GET_MODE_MASK (GET_MODE (operands[0])), +- SImode); +- operands[0] = gen_lowpart (SImode, operands[0]);") ++ [(set (match_dup 0) ++ (match_op_dup 1 [(and:SI (match_dup 2) (match_dup 3)) ++ (const_int 0)]))] ++{ ++ operands[3] ++ = gen_int_mode (INTVAL (operands[3]) ++ & GET_MODE_MASK (GET_MODE (operands[2])), SImode); ++ operands[2] = gen_lowpart (SImode, operands[2]); ++}) + + (define_split + [(set (match_operand 0 "register_operand" "") +@@ -17081,13 +17134,14 @@ + + ;; Don't compare memory with zero, load and use a test instead. + (define_peephole2 +- [(set (reg 17) +- (compare (match_operand:SI 0 "memory_operand" "") +- (const_int 0))) ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(match_operand:SI 2 "memory_operand" "") ++ (const_int 0)])) + (match_scratch:SI 3 "r")] + "ix86_match_ccmode (insn, CCNOmode) && ! optimize_size" +- [(set (match_dup 3) (match_dup 0)) +- (set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))] ++ [(set (match_dup 3) (match_dup 2)) ++ (set (match_dup 0) (match_op_dup 1 [(match_dup 3) (const_int 0)]))] + "") + + ;; NOT is not pairable on Pentium, while XOR is, but one byte longer. +@@ -17151,77 +17205,77 @@ + ;; versions if we're concerned about partial register stalls. + + (define_peephole2 +- [(set (reg 17) +- (compare (and:SI (match_operand:SI 0 "register_operand" "") +- (match_operand:SI 1 "immediate_operand" "")) +- (const_int 0)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(and:SI (match_operand:SI 2 "register_operand" "") ++ (match_operand:SI 3 "immediate_operand" "")) ++ (const_int 0)]))] + "ix86_match_ccmode (insn, CCNOmode) +- && (true_regnum (operands[0]) != 0 +- || (GET_CODE (operands[1]) == CONST_INT +- && CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))) +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" ++ && (true_regnum (operands[2]) != 0 ++ || (GET_CODE (operands[3]) == CONST_INT ++ && CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'K'))) ++ && peep2_reg_dead_p (1, operands[2])" + [(parallel +- [(set (reg:CCNO 17) +- (compare:CCNO (and:SI (match_dup 0) +- (match_dup 1)) +- (const_int 0))) +- (set (match_dup 0) +- (and:SI (match_dup 0) (match_dup 1)))])] ++ [(set (match_dup 0) ++ (match_op_dup 1 [(and:SI (match_dup 2) (match_dup 3)) ++ (const_int 0)])) ++ (set (match_dup 2) ++ (and:SI (match_dup 2) (match_dup 3)))])] + "") + + ;; We don't need to handle HImode case, because it will be promoted to SImode + ;; on ! TARGET_PARTIAL_REG_STALL + + (define_peephole2 +- [(set (reg 17) +- (compare (and:QI (match_operand:QI 0 "register_operand" "") +- (match_operand:QI 1 "immediate_operand" "")) +- (const_int 0)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(and:QI (match_operand:QI 2 "register_operand" "") ++ (match_operand:QI 3 "immediate_operand" "")) ++ (const_int 0)]))] + "! TARGET_PARTIAL_REG_STALL + && ix86_match_ccmode (insn, CCNOmode) +- && true_regnum (operands[0]) != 0 +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" ++ && true_regnum (operands[2]) != 0 ++ && peep2_reg_dead_p (1, operands[2])" + [(parallel +- [(set (reg:CCNO 17) +- (compare:CCNO (and:QI (match_dup 0) +- (match_dup 1)) +- (const_int 0))) +- (set (match_dup 0) +- (and:QI (match_dup 0) (match_dup 1)))])] ++ [(set (match_dup 0) ++ (match_op_dup 1 [(and:QI (match_dup 2) (match_dup 3)) ++ (const_int 0)])) ++ (set (match_dup 2) ++ (and:QI (match_dup 2) (match_dup 3)))])] + "") + + (define_peephole2 +- [(set (reg 17) +- (compare +- (and:SI +- (zero_extract:SI +- (match_operand 0 "ext_register_operand" "") +- (const_int 8) +- (const_int 8)) +- (match_operand 1 "const_int_operand" "")) +- (const_int 0)))] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(and:SI ++ (zero_extract:SI ++ (match_operand 2 "ext_register_operand" "") ++ (const_int 8) ++ (const_int 8)) ++ (match_operand 3 "const_int_operand" "")) ++ (const_int 0)]))] + "! TARGET_PARTIAL_REG_STALL + && ix86_match_ccmode (insn, CCNOmode) +- && true_regnum (operands[0]) != 0 +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" +- [(parallel [(set (reg:CCNO 17) +- (compare:CCNO +- (and:SI +- (zero_extract:SI +- (match_dup 0) +- (const_int 8) +- (const_int 8)) +- (match_dup 1)) +- (const_int 0))) +- (set (zero_extract:SI (match_dup 0) ++ && true_regnum (operands[2]) != 0 ++ && peep2_reg_dead_p (1, operands[2])" ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 1 ++ [(and:SI ++ (zero_extract:SI ++ (match_dup 2) ++ (const_int 8) ++ (const_int 8)) ++ (match_dup 3)) ++ (const_int 0)])) ++ (set (zero_extract:SI (match_dup 2) + (const_int 8) + (const_int 8)) + (and:SI + (zero_extract:SI +- (match_dup 0) ++ (match_dup 2) + (const_int 8) + (const_int 8)) +- (match_dup 1)))])] ++ (match_dup 3)))])] + "") + + ;; Don't do logical operations with memory inputs. +@@ -17523,66 +17577,20 @@ + "") + + ;; Convert compares with 1 to shorter inc/dec operations when CF is not +-;; required and register dies. +-(define_peephole2 +- [(set (reg 17) +- (compare (match_operand:SI 0 "register_operand" "") +- (match_operand:SI 1 "incdec_operand" "")))] +- "ix86_match_ccmode (insn, CCGCmode) +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" +- [(parallel [(set (reg:CCGC 17) +- (compare:CCGC (match_dup 0) +- (match_dup 1))) +- (clobber (match_dup 0))])] +- "") +- ++;; required and register dies. Similarly for 128 to plus -128. + (define_peephole2 +- [(set (reg 17) +- (compare (match_operand:HI 0 "register_operand" "") +- (match_operand:HI 1 "incdec_operand" "")))] +- "ix86_match_ccmode (insn, CCGCmode) +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" +- [(parallel [(set (reg:CCGC 17) +- (compare:CCGC (match_dup 0) +- (match_dup 1))) +- (clobber (match_dup 0))])] +- "") +- +-(define_peephole2 +- [(set (reg 17) +- (compare (match_operand:QI 0 "register_operand" "") +- (match_operand:QI 1 "incdec_operand" "")))] +- "ix86_match_ccmode (insn, CCGCmode) +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" +- [(parallel [(set (reg:CCGC 17) +- (compare:CCGC (match_dup 0) +- (match_dup 1))) +- (clobber (match_dup 0))])] +- "") +- +-;; Convert compares with 128 to shorter add -128 +-(define_peephole2 +- [(set (reg 17) +- (compare (match_operand:SI 0 "register_operand" "") +- (const_int 128)))] +- "ix86_match_ccmode (insn, CCGCmode) +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" +- [(parallel [(set (reg:CCGC 17) +- (compare:CCGC (match_dup 0) +- (const_int 128))) +- (clobber (match_dup 0))])] +- "") +- +-(define_peephole2 +- [(set (reg 17) +- (compare (match_operand:HI 0 "register_operand" "") +- (const_int 128)))] +- "ix86_match_ccmode (insn, CCGCmode) +- && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))" +- [(parallel [(set (reg:CCGC 17) +- (compare:CCGC (match_dup 0) +- (const_int 128))) +- (clobber (match_dup 0))])] ++ [(set (match_operand 0 "flags_reg_operand" "") ++ (match_operator 1 "compare_operator" ++ [(match_operand 2 "register_operand" "") ++ (match_operand 3 "const_int_operand" "")]))] ++ "(INTVAL (operands[3]) == -1 ++ || INTVAL (operands[3]) == 1 ++ || INTVAL (operands[3]) == 128) ++ && ix86_match_ccmode (insn, CCGCmode) ++ && peep2_reg_dead_p (1, operands[2])" ++ [(parallel [(set (match_dup 0) ++ (match_op_dup 1 [(match_dup 2) (match_dup 3)])) ++ (clobber (match_dup 2))])] + "") + + (define_peephole2 +@@ -17780,9 +17788,9 @@ + return "call\t%P1"; + } + if (SIBLING_CALL_P (insn)) +- return "jmp\t%*%1"; ++ return "jmp\t%A1"; + else +- return "call\t%*%1"; ++ return "call\t%A1"; + } + [(set_attr "type" "callv")]) + +Index: gcc/config/ia64/ia64.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/ia64/ia64.c,v +retrieving revision 1.198.2.22 +retrieving revision 1.198.2.24 +diff -u -r1.198.2.22 -r1.198.2.24 +--- gcc/gcc/config/ia64/ia64.c 17 Sep 2004 17:56:32 -0000 1.198.2.22 ++++ gcc/gcc/config/ia64/ia64.c 14 Jan 2005 19:15:40 -0000 1.198.2.24 +@@ -2884,10 +2884,13 @@ + preserve those input registers used as arguments to the sibling call. + It is unclear how to compute that number here. */ + if (current_frame_info.n_input_regs != 0) +- emit_insn (gen_alloc (gen_rtx_REG (DImode, fp), +- GEN_INT (0), GEN_INT (0), +- GEN_INT (current_frame_info.n_input_regs), +- GEN_INT (0))); ++ { ++ rtx n_inputs = GEN_INT (current_frame_info.n_input_regs); ++ insn = emit_insn (gen_alloc (gen_rtx_REG (DImode, fp), ++ const0_rtx, const0_rtx, ++ n_inputs, const0_rtx)); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } + } + } + +@@ -3021,15 +3024,16 @@ + int aligned_p; + { + if (size == (TARGET_ILP32 ? 4 : 8) +- && aligned_p + && !(TARGET_NO_PIC || TARGET_AUTO_PIC) + && GET_CODE (x) == SYMBOL_REF + && SYMBOL_REF_FLAG (x)) + { +- if (TARGET_ILP32) +- fputs ("\tdata4\t@fptr(", asm_out_file); +- else +- fputs ("\tdata8\t@fptr(", asm_out_file); ++ static const char * const directive[2][2] = { ++ /* 64-bit pointer */ /* 32-bit pointer */ ++ { "\tdata8.ua\t@fptr(", "\tdata4.ua\t@fptr("}, /* unaligned */ ++ { "\tdata8\t@fptr(", "\tdata4\t@fptr("} /* aligned */ ++ }; ++ fputs (directive[aligned_p != 0][TARGET_ILP32 != 0], asm_out_file); + output_addr_const (asm_out_file, x); + fputs (")\n", asm_out_file); + return true; +@@ -7451,13 +7455,24 @@ + { + dest_regno = REGNO (dest); + +- /* If this isn't the final destination for ar.pfs, the alloc +- shouldn't have been marked frame related. */ +- if (dest_regno != current_frame_info.reg_save_ar_pfs) +- abort (); +- +- fprintf (asm_out_file, "\t.save ar.pfs, r%d\n", +- ia64_dbx_register_number (dest_regno)); ++ /* If this is the final destination for ar.pfs, then this must ++ be the alloc in the prologue. */ ++ if (dest_regno == current_frame_info.reg_save_ar_pfs) ++ fprintf (asm_out_file, "\t.save ar.pfs, r%d\n", ++ ia64_dbx_register_number (dest_regno)); ++ else ++ { ++ /* This must be an alloc before a sibcall. We must drop the ++ old frame info. The easiest way to drop the old frame ++ info is to ensure we had a ".restore sp" directive ++ followed by a new prologue. If the procedure doesn't ++ have a memory-stack frame, we'll issue a dummy ".restore ++ sp" now. */ ++ if (current_frame_info.total_size == 0 && !frame_pointer_needed) ++ /* if haven't done process_epilogue() yet, do it now */ ++ process_epilogue (); ++ fprintf (asm_out_file, "\t.prologue\n"); ++ } + return 1; + } + +Index: gcc/config/m68hc11/t-m68hc11-gas +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/m68hc11/t-m68hc11-gas,v +retrieving revision 1.7.14.3 +retrieving revision 1.7.14.4 +diff -u -r1.7.14.3 -r1.7.14.4 +--- gcc/gcc/config/m68hc11/t-m68hc11-gas 4 Oct 2003 19:45:57 -0000 1.7.14.3 ++++ gcc/gcc/config/m68hc11/t-m68hc11-gas 28 Jan 2005 22:21:39 -0000 1.7.14.4 +@@ -53,7 +53,7 @@ + dp-bit.c: $(srcdir)/config/fp-bit.c + echo '#define SMALL_MACHINE' >> dp-bit.c + echo '#define CMPtype HItype' >> dp-bit.c +- echo '#ifdef __LITTLE_ENDIAN__' > dp-bit.c ++ echo '#ifdef __LITTLE_ENDIAN__' >> dp-bit.c + echo '#define FLOAT_BIT_ORDER_MISMATCH' >>dp-bit.c + echo '#endif' >> dp-bit.c + cat $(srcdir)/config/fp-bit.c >> dp-bit.c +Index: gcc/config/mips/mips-protos.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/mips/mips-protos.h,v +retrieving revision 1.30.4.1 +retrieving revision 1.30.4.2 +diff -u -r1.30.4.1 -r1.30.4.2 +--- gcc/gcc/config/mips/mips-protos.h 31 Jan 2003 23:51:22 -0000 1.30.4.1 ++++ gcc/gcc/config/mips/mips-protos.h 8 Jan 2005 14:33:32 -0000 1.30.4.2 +@@ -1,6 +1,6 @@ + /* Prototypes of target machine for GNU compiler. MIPS version. + Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, +- 1999, 2001, 2002 Free Software Foundation, Inc. ++ 1999, 2001, 2002, 2005 Free Software Foundation, Inc. + Contributed by A. Lichnewsky (lich@inria.inria.fr). + Changed by Michael Meissner (meissner@osf.org). + 64 bit r4000 support by Ian Lance Taylor (ian@cygnus.com) and +@@ -36,9 +36,13 @@ + extern const char * current_section_name PARAMS ((void)); + extern unsigned int current_section_flags PARAMS ((void)); + extern int mips_can_use_return_insn PARAMS ((void)); +-extern void mips_declare_object PARAMS ((FILE *, const char *, +- const char *, +- const char *, int)); ++extern void mips_output_aligned_decl_common ++ PARAMS ((FILE *, tree, const char *, ++ unsigned HOST_WIDE_INT, ++ unsigned int)); ++extern void mips_declare_object ++ PARAMS ((FILE *, const char *, const char *, ++ const char *, ...)); + extern void mips_expand_epilogue PARAMS ((void)); + extern void mips_expand_prologue PARAMS ((void)); + extern void mips_output_filename PARAMS ((FILE *, const char *)); +Index: gcc/config/mips/mips.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.c,v +retrieving revision 1.241.2.4 +retrieving revision 1.241.2.5 +diff -u -r1.241.2.4 -r1.241.2.5 +--- gcc/gcc/config/mips/mips.c 27 Jun 2003 11:44:23 -0000 1.241.2.4 ++++ gcc/gcc/config/mips/mips.c 8 Jan 2005 14:33:33 -0000 1.241.2.5 +@@ -1,6 +1,6 @@ + /* Subroutines for insn-output.c for MIPS + Copyright (C) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997, 1998, +- 1999, 2000, 2001, 2002 Free Software Foundation, Inc. ++ 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc. + Contributed by A. Lichnewsky, lich@inria.inria.fr. + Changes by Michael Meissner, meissner@osf.org. + 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and +@@ -6562,26 +6562,84 @@ + fatal_io_error ("can't close temp file"); + } + +-/* Emit either a label, .comm, or .lcomm directive, and mark that the symbol +- is used, so that we don't emit an .extern for it in mips_asm_file_end. */ ++/* Implement ASM_OUTPUT_ALIGNED_DECL_COMMON. This is usually the same as ++ the elfos.h version, but we also need to handle -muninit-const-in-rodata ++ and the limitations of the SGI o32 assembler. */ + + void +-mips_declare_object (stream, name, init_string, final_string, size) ++mips_output_aligned_decl_common (stream, decl, name, size, align) + FILE *stream; ++ tree decl; + const char *name; +- const char *init_string; +- const char *final_string; +- int size; ++ unsigned HOST_WIDE_INT size; ++ unsigned int align; + { +- fputs (init_string, stream); /* "", "\t.comm\t", or "\t.lcomm\t" */ ++ const char *format; ++ ++ /* If the target wants uninitialized const declarations in ++ .rdata then don't put them in .comm. */ ++ if (TARGET_EMBEDDED_DATA && TARGET_UNINIT_CONST_IN_RODATA ++ && TREE_CODE (decl) == VAR_DECL && TREE_READONLY (decl) ++ && (DECL_INITIAL (decl) == 0 || DECL_INITIAL (decl) == error_mark_node)) ++ { ++ if (TREE_PUBLIC (decl) && DECL_NAME (decl)) ++ targetm.asm_out.globalize_label (stream, name); ++ ++ readonly_data_section (); ++ ASM_OUTPUT_ALIGN (stream, floor_log2 (align / BITS_PER_UNIT)); ++ ++ format = ACONCAT ((":\n\t.space\t", HOST_WIDE_INT_PRINT_UNSIGNED, ++ "\n", NULL)); ++ mips_declare_object (stream, name, "", format, size); ++ } ++#ifdef TARGET_IRIX6 ++ /* The SGI o32 assembler doesn't accept an alignment, so round up ++ the size instead. */ ++ else if (mips_abi == ABI_32 && !TARGET_GAS) ++ { ++ size += (align / BITS_PER_UNIT) - 1; ++ size -= size % (align / BITS_PER_UNIT); ++ format = ACONCAT ((",", HOST_WIDE_INT_PRINT_UNSIGNED, "\n", NULL)); ++ mips_declare_object (stream, name, "\n\t.comm\t", format, size); ++ } ++#endif ++ else ++ { ++ format = ACONCAT ((",", HOST_WIDE_INT_PRINT_UNSIGNED, ",%u\n", NULL)); ++ mips_declare_object (stream, name, "\n\t.comm\t", format, ++ size, align / BITS_PER_UNIT); ++ } ++} ++ ++/* Emit either a label, .comm, or .lcomm directive. When using assembler ++ macros, mark the symbol as written so that mips_file_end won't emit an ++ .extern for it. STREAM is the output file, NAME is the name of the ++ symbol, INIT_STRING is the string that should be written before the ++ symbol and FINAL_STRING is the string that shoulbe written after it. ++ FINAL_STRING is a printf() format that consumes the remaining arguments. */ ++ ++void ++mips_declare_object VPARAMS ((FILE *stream, const char *name, ++ const char *init_string, ++ const char *final_string, ...)) ++{ ++ VA_OPEN (ap, final_string); ++ VA_FIXEDARG (ap, FILE *, stream); ++ VA_FIXEDARG (ap, const char *, name); ++ VA_FIXEDARG (ap, const char *, init_string); ++ VA_FIXEDARG (ap, const char *, final_string); ++ ++ fputs (init_string, stream); + assemble_name (stream, name); +- fprintf (stream, final_string, size); /* ":\n", ",%u\n", ",%u\n" */ ++ vfprintf (stream, final_string, ap); + + if (TARGET_GP_OPT) + { + tree name_tree = get_identifier (name); + TREE_ASM_WRITTEN (name_tree) = 1; + } ++ ++ VA_CLOSE (ap); + } + + /* Return the bytes needed to compute the frame pointer from the current +Index: gcc/config/mips/mips.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.h,v +retrieving revision 1.227.4.6 +retrieving revision 1.227.4.7 +diff -u -r1.227.4.6 -r1.227.4.7 +--- gcc/gcc/config/mips/mips.h 30 May 2003 12:00:42 -0000 1.227.4.6 ++++ gcc/gcc/config/mips/mips.h 8 Jan 2005 14:33:34 -0000 1.227.4.7 +@@ -1,6 +1,6 @@ + /* Definitions of target machine for GNU compiler. MIPS version. + Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998 +- 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. ++ 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + Contributed by A. Lichnewsky (lich@inria.inria.fr). + Changed by Michael Meissner (meissner@osf.org). + 64 bit r4000 support by Ian Lance Taylor (ian@cygnus.com) and +@@ -4326,28 +4326,7 @@ + + /* This says how to define a global common symbol. */ + +-#define ASM_OUTPUT_ALIGNED_DECL_COMMON(STREAM, DECL, NAME, SIZE, ALIGN) \ +- do { \ +- /* If the target wants uninitialized const declarations in \ +- .rdata then don't put them in .comm */ \ +- if (TARGET_EMBEDDED_DATA && TARGET_UNINIT_CONST_IN_RODATA \ +- && TREE_CODE (DECL) == VAR_DECL && TREE_READONLY (DECL) \ +- && (DECL_INITIAL (DECL) == 0 \ +- || DECL_INITIAL (DECL) == error_mark_node)) \ +- { \ +- if (TREE_PUBLIC (DECL) && DECL_NAME (DECL)) \ +- (*targetm.asm_out.globalize_label) (STREAM, NAME); \ +- \ +- readonly_data_section (); \ +- ASM_OUTPUT_ALIGN (STREAM, floor_log2 (ALIGN / BITS_PER_UNIT)); \ +- mips_declare_object (STREAM, NAME, "", ":\n\t.space\t%u\n", \ +- (SIZE)); \ +- } \ +- else \ +- mips_declare_object (STREAM, NAME, "\n\t.comm\t", ",%u\n", \ +- (SIZE)); \ +- } while (0) +- ++#define ASM_OUTPUT_ALIGNED_DECL_COMMON mips_output_aligned_decl_common + + /* This says how to define a local common symbol (ie, not visible to + linker). */ +Index: gcc/config/mips/mips.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v +retrieving revision 1.153.2.5 +retrieving revision 1.153.2.6 +diff -u -r1.153.2.5 -r1.153.2.6 +--- gcc/gcc/config/mips/mips.md 27 Mar 2004 10:35:03 -0000 1.153.2.5 ++++ gcc/gcc/config/mips/mips.md 8 Jan 2005 14:11:12 -0000 1.153.2.6 +@@ -1,6 +1,6 @@ + ;; Mips.md Machine Description for MIPS based processors + ;; Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, +-;; 1999, 2000, 2001, 2002 Free Software Foundation, Inc. ++;; 1999, 2000, 2001, 2002, 2005 Free Software Foundation, Inc. + ;; Contributed by A. Lichnewsky, lich@inria.inria.fr + ;; Changes by Michael Meissner, meissner@osf.org + ;; 64 bit r4000 support by Ian Lance Taylor, ian@cygnus.com, and +@@ -163,7 +163,8 @@ + + ;; Describe a user's asm statement. + (define_asm_attributes +- [(set_attr "type" "multi")]) ++ [(set_attr "type" "multi") ++ (set_attr "can_delay" "no")]) + + ;; whether or not generating calls to position independent functions + (define_attr "abicalls" "no,yes" +Index: gcc/config/pa/pa32-linux.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/pa/pa32-linux.h,v +retrieving revision 1.10 +retrieving revision 1.10.2.1 +diff -u -r1.10 -r1.10.2.1 +--- gcc/gcc/config/pa/pa32-linux.h 6 Dec 2002 02:54:38 -0000 1.10 ++++ gcc/gcc/config/pa/pa32-linux.h 27 Dec 2004 02:55:49 -0000 1.10.2.1 +@@ -28,7 +28,7 @@ + pointer into the frame. This target does not need multiple + subspace stubs, so we allow sibcalls to all functions. */ + #undef FUNCTION_OK_FOR_SIBCALL +-#define FUNCTION_OK_FOR_SIBCALL(DECL) 1 ++#define FUNCTION_OK_FOR_SIBCALL(DECL) (!TARGET_PORTABLE_RUNTIME) + + /* The libcall __canonicalize_funcptr_for_compare is referenced in + crtend.o and the reference isn't resolved in objects that don't +Index: gcc/config/rs6000/rs6000.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v +retrieving revision 1.403.2.14 +retrieving revision 1.403.2.16 +diff -u -r1.403.2.14 -r1.403.2.16 +--- gcc/gcc/config/rs6000/rs6000.c 14 Jan 2004 14:03:58 -0000 1.403.2.14 ++++ gcc/gcc/config/rs6000/rs6000.c 1 Dec 2004 06:13:16 -0000 1.403.2.16 +@@ -150,7 +150,8 @@ + /* Call distance, overridden by -mlongcall and #pragma longcall(1). + The only place that looks at this is rs6000_set_default_type_attributes; + everywhere else should rely on the presence or absence of a longcall +- attribute on the function declaration. */ ++ attribute on the function declaration. Exception: init_cumulative_args ++ looks at it too, for libcalls. */ + int rs6000_default_long_calls; + const char *rs6000_longcall_switch; + +@@ -2910,10 +2911,11 @@ + cum->orig_nargs = cum->nargs_prototype; + + /* Check for a longcall attribute. */ +- if (fntype +- && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)) +- && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype))) +- cum->call_cookie = CALL_LONG; ++ if ((!fntype && rs6000_default_long_calls) ++ || (fntype ++ && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)) ++ && !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))) ++ cum->call_cookie |= CALL_LONG; + + if (TARGET_DEBUG_ARG) + { +@@ -10356,8 +10358,10 @@ + rtx reg, mem, vrsave; + int offset; + +- /* Get VRSAVE onto a GPR. */ +- reg = gen_rtx_REG (SImode, 12); ++ /* Get VRSAVE onto a GPR. Note that ABI_V4 might be using r12 ++ as frame_reg_rtx and r11 as the static chain pointer for ++ nested functions. */ ++ reg = gen_rtx_REG (SImode, 0); + vrsave = gen_rtx_REG (SImode, VRSAVE_REGNO); + if (TARGET_MACHO) + emit_insn (gen_get_vrsave_internal (reg)); +Index: gcc/config/rs6000/rs6000.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v +retrieving revision 1.224.2.6 +retrieving revision 1.224.2.7 +diff -u -r1.224.2.6 -r1.224.2.7 +--- gcc/gcc/config/rs6000/rs6000.md 8 Mar 2004 04:20:45 -0000 1.224.2.6 ++++ gcc/gcc/config/rs6000/rs6000.md 24 Dec 2004 23:17:06 -0000 1.224.2.7 +@@ -3124,61 +3124,6 @@ + }" + [(set_attr "length" "8")]) + +-(define_insn_and_split "*andsi3_internal7" +- [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") +- (compare:CC (and:SI (match_operand:SI 0 "gpc_reg_operand" "r,r") +- (match_operand:SI 1 "mask_operand_wrap" "i,i")) +- (const_int 0))) +- (clobber (match_scratch:SI 3 "=r,r"))] +- "TARGET_POWERPC64" +- "#" +- "TARGET_POWERPC64" +- [(parallel [(set (match_dup 2) +- (compare:CC (and:SI (rotate:SI (match_dup 0) (match_dup 4)) +- (match_dup 5)) +- (const_int 0))) +- (clobber (match_dup 3))])] +- " +-{ +- int mb = extract_MB (operands[1]); +- int me = extract_ME (operands[1]); +- operands[4] = GEN_INT (me + 1); +- operands[5] = GEN_INT (~((HOST_WIDE_INT) -1 << (33 + me - mb))); +-}" +- [(set_attr "type" "delayed_compare,compare") +- (set_attr "length" "4,8")]) +- +-(define_insn_and_split "*andsi3_internal8" +- [(set (match_operand:CC 3 "cc_reg_operand" "=x,??y") +- (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") +- (match_operand:SI 2 "mask_operand_wrap" "i,i")) +- (const_int 0))) +- (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") +- (and:SI (match_dup 1) +- (match_dup 2)))] +- "TARGET_POWERPC64" +- "#" +- "TARGET_POWERPC64" +- [(parallel [(set (match_dup 3) +- (compare:CC (and:SI (rotate:SI (match_dup 1) (match_dup 4)) +- (match_dup 5)) +- (const_int 0))) +- (set (match_dup 0) +- (and:SI (rotate:SI (match_dup 1) (match_dup 4)) +- (match_dup 5)))]) +- (set (match_dup 0) +- (rotate:SI (match_dup 0) (match_dup 6)))] +- " +-{ +- int mb = extract_MB (operands[2]); +- int me = extract_ME (operands[2]); +- operands[4] = GEN_INT (me + 1); +- operands[6] = GEN_INT (32 - (me + 1)); +- operands[5] = GEN_INT (~((HOST_WIDE_INT) -1 << (33 + me - mb))); +-}" +- [(set_attr "type" "delayed_compare,compare") +- (set_attr "length" "8,12")]) +- + (define_expand "iorsi3" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (ior:SI (match_operand:SI 1 "gpc_reg_operand" "") +Index: gcc/config/s390/s390.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v +retrieving revision 1.41.2.12 +retrieving revision 1.41.2.13 +diff -u -r1.41.2.12 -r1.41.2.13 +--- gcc/gcc/config/s390/s390.md 3 Aug 2004 20:06:51 -0000 1.41.2.12 ++++ gcc/gcc/config/s390/s390.md 27 Jan 2005 23:38:39 -0000 1.41.2.13 +@@ -910,11 +910,13 @@ + }) + + (define_expand "reload_outti" +- [(parallel [(match_operand:TI 0 "memory_operand" "") ++ [(parallel [(match_operand:TI 0 "" "") + (match_operand:TI 1 "register_operand" "d") + (match_operand:DI 2 "register_operand" "=&a")])] + "TARGET_64BIT" + { ++ if (GET_CODE (operands[0]) != MEM) ++ abort (); + s390_load_address (operands[2], XEXP (operands[0], 0)); + operands[0] = replace_equiv_address (operands[0], operands[2]); + emit_move_insn (operands[0], operands[1]); +@@ -1060,11 +1062,13 @@ + }) + + (define_expand "reload_outdi" +- [(parallel [(match_operand:DI 0 "memory_operand" "") ++ [(parallel [(match_operand:DI 0 "" "") + (match_operand:DI 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "=&a")])] + "!TARGET_64BIT" + { ++ if (GET_CODE (operands[0]) != MEM) ++ abort (); + s390_load_address (operands[2], XEXP (operands[0], 0)); + operands[0] = replace_equiv_address (operands[0], operands[2]); + emit_move_insn (operands[0], operands[1]); +@@ -1374,11 +1378,13 @@ + }) + + (define_expand "reload_outdf" +- [(parallel [(match_operand:DF 0 "memory_operand" "") ++ [(parallel [(match_operand:DF 0 "" "") + (match_operand:DF 1 "register_operand" "d") + (match_operand:SI 2 "register_operand" "=&a")])] + "!TARGET_64BIT" + { ++ if (GET_CODE (operands[0]) != MEM) ++ abort (); + s390_load_address (operands[2], XEXP (operands[0], 0)); + operands[0] = replace_equiv_address (operands[0], operands[2]); + emit_move_insn (operands[0], operands[1]); +Index: gcc/config/sparc/sparc.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v +retrieving revision 1.233.4.12 +retrieving revision 1.233.4.13 +diff -u -r1.233.4.12 -r1.233.4.13 +--- gcc/gcc/config/sparc/sparc.c 17 Jul 2004 19:49:21 -0000 1.233.4.12 ++++ gcc/gcc/config/sparc/sparc.c 14 Oct 2004 06:54:26 -0000 1.233.4.13 +@@ -178,6 +178,8 @@ + static void sparc_encode_section_info PARAMS ((tree, int)); + static void sparc_output_mi_thunk PARAMS ((FILE *, tree, HOST_WIDE_INT, + HOST_WIDE_INT, tree)); ++static bool sparc_can_output_mi_thunk PARAMS ((tree, HOST_WIDE_INT, ++ HOST_WIDE_INT, tree)); + + /* Option handling. */ + +@@ -244,7 +246,7 @@ + #undef TARGET_ASM_OUTPUT_MI_THUNK + #define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk + #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK +-#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall ++#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk + + struct gcc_target targetm = TARGET_INITIALIZER; + +@@ -8622,18 +8624,21 @@ + SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1; + } + +-/* Output code to add DELTA to the first argument, and then jump to FUNCTION. +- Used for C++ multiple inheritance. */ ++/* Output the assembler code for a thunk function. THUNK_DECL is the ++ declaration for the thunk function itself, FUNCTION is the decl for ++ the target function. DELTA is an immediate constant offset to be ++ added to THIS. If VCALL_OFFSET is nonzero, the word at address ++ (*THIS + VCALL_OFFSET) should be additionally added to THIS. */ + + static void + sparc_output_mi_thunk (file, thunk_fndecl, delta, vcall_offset, function) + FILE *file; + tree thunk_fndecl ATTRIBUTE_UNUSED; + HOST_WIDE_INT delta; +- HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED; ++ HOST_WIDE_INT vcall_offset; + tree function; + { +- rtx this, insn, funexp, delta_rtx, tmp; ++ rtx this, insn, funexp; + + reload_completed = 1; + no_new_pseudos = 1; +@@ -8650,26 +8655,73 @@ + + /* Add DELTA. When possible use a plain add, otherwise load it into + a register first. */ +- delta_rtx = GEN_INT (delta); +- if (!SPARC_SIMM13_P (delta)) ++ if (delta) + { ++ rtx delta_rtx = GEN_INT (delta); ++ ++ if (! SPARC_SIMM13_P (delta)) ++ { ++ rtx scratch = gen_rtx_REG (Pmode, 1); ++ emit_move_insn (scratch, delta_rtx); ++ delta_rtx = scratch; ++ } ++ ++ /* THIS += DELTA. */ ++ emit_insn (gen_add2_insn (this, delta_rtx)); ++ } ++ ++ /* Add the word at address (*THIS + VCALL_OFFSET). */ ++ if (vcall_offset) ++ { ++ rtx vcall_offset_rtx = GEN_INT (vcall_offset); + rtx scratch = gen_rtx_REG (Pmode, 1); + +- if (input_operand (delta_rtx, GET_MODE (scratch))) +- emit_insn (gen_rtx_SET (VOIDmode, scratch, delta_rtx)); ++ if (vcall_offset >= 0) ++ abort (); ++ ++ /* SCRATCH = *THIS. */ ++ emit_move_insn (scratch, gen_rtx_MEM (Pmode, this)); ++ ++ /* Prepare for adding VCALL_OFFSET. The difficulty is that we ++ may not have any available scratch register at this point. */ ++ if (SPARC_SIMM13_P (vcall_offset)) ++ ; ++ /* This is the case if ARCH64 (unless -ffixed-g5 is passed). */ ++ else if (! fixed_regs[5] ++ /* The below sequence is made up of at least 2 insns, ++ while the default method may need only one. */ ++ && vcall_offset < -8192) ++ { ++ rtx scratch2 = gen_rtx_REG (Pmode, 5); ++ emit_move_insn (scratch2, vcall_offset_rtx); ++ vcall_offset_rtx = scratch2; ++ } + else + { +- if (TARGET_ARCH64) +- sparc_emit_set_const64 (scratch, delta_rtx); +- else +- sparc_emit_set_const32 (scratch, delta_rtx); ++ rtx increment = GEN_INT (-4096); ++ ++ /* VCALL_OFFSET is a negative number whose typical range can be ++ estimated as -32768..0 in 32-bit mode. In almost all cases ++ it is therefore cheaper to emit multiple add insns than ++ spilling and loading the constant into a register (at least ++ 6 insns). */ ++ while (! SPARC_SIMM13_P (vcall_offset)) ++ { ++ emit_insn (gen_add2_insn (scratch, increment)); ++ vcall_offset += 4096; ++ } ++ vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */ + } + +- delta_rtx = scratch; +- } ++ /* SCRATCH = *(*THIS + VCALL_OFFSET). */ ++ emit_move_insn (scratch, gen_rtx_MEM (Pmode, ++ gen_rtx_PLUS (Pmode, ++ scratch, ++ vcall_offset_rtx))); + +- tmp = gen_rtx_PLUS (Pmode, this, delta_rtx); +- emit_insn (gen_rtx_SET (VOIDmode, this, tmp)); ++ /* THIS += *(*THIS + VCALL_OFFSET). */ ++ emit_insn (gen_add2_insn (this, scratch)); ++ } + + /* Generate a tail call to the target function. */ + if (! TREE_USED (function)) +@@ -8697,4 +8749,18 @@ + no_new_pseudos = 0; + } + ++/* Return true if sparc_output_mi_thunk would be able to output the ++ assembler code for the thunk function specified by the arguments ++ it is passed, and false otherwise. */ ++static bool ++sparc_can_output_mi_thunk (thunk_fndecl, delta, vcall_offset, function) ++ tree thunk_fndecl ATTRIBUTE_UNUSED; ++ HOST_WIDE_INT delta ATTRIBUTE_UNUSED; ++ HOST_WIDE_INT vcall_offset; ++ tree function ATTRIBUTE_UNUSED; ++{ ++ /* Bound the loop used in the default method above. */ ++ return (vcall_offset >= -32768 || ! fixed_regs[5]); ++} ++ + #include "gt-sparc.h" +Index: gcc/config/sparc/sparc.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.md,v +retrieving revision 1.181.4.13 +retrieving revision 1.181.4.14 +diff -u -r1.181.4.13 -r1.181.4.14 +--- gcc/gcc/config/sparc/sparc.md 17 Jul 2004 19:49:21 -0000 1.181.4.13 ++++ gcc/gcc/config/sparc/sparc.md 14 Oct 2004 06:54:27 -0000 1.181.4.14 +@@ -2048,7 +2048,6 @@ + if (! CONSTANT_P (operands[1]) || input_operand (operands[1], DImode)) + ; + else if (TARGET_ARCH64 +- && CONSTANT_P (operands[1]) + && GET_CODE (operands[1]) != HIGH + && GET_CODE (operands[1]) != LO_SUM) + { +Index: gcc/config/vax/vax.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/vax/vax.c,v +retrieving revision 1.38 +retrieving revision 1.38.4.1 +diff -u -r1.38 -r1.38.4.1 +--- gcc/gcc/config/vax/vax.c 22 Oct 2002 23:05:24 -0000 1.38 ++++ gcc/gcc/config/vax/vax.c 28 Dec 2004 06:29:59 -0000 1.38.4.1 +@@ -462,7 +462,7 @@ + case CONST_INT: + /* byte offsets cost nothing (on a VAX 2, they cost 1 cycle) */ + if (offset == 0) +- offset = (unsigned)(INTVAL(addr)+128) > 256; ++ offset = (unsigned HOST_WIDE_INT)(INTVAL(addr)+128) > 256; + break; + case CONST: + case SYMBOL_REF: +@@ -595,13 +595,13 @@ + fmt = "e"; /* all constant rotate counts are short */ + break; + case PLUS: +- /* Check for small negative integer operand: subl2 can be used with +- a short positive constant instead. */ +- if (GET_CODE (XEXP (x, 1)) == CONST_INT) +- if ((unsigned)(INTVAL (XEXP (x, 1)) + 63) < 127) +- fmt = "e"; + case MINUS: + c = (mode == DFmode) ? 13 : 8; /* 6/8 on VAX 9000, 16/15 on VAX 2 */ ++ /* Small integer operands can use subl2 and addl2. */ ++ if ((GET_CODE (XEXP (x, 1)) == CONST_INT) ++ && (unsigned HOST_WIDE_INT)(INTVAL (XEXP (x, 1)) + 63) < 127) ++ fmt = "e"; ++ break; + case IOR: + case XOR: + c = 3; +@@ -611,7 +611,7 @@ + c = 3; + if (GET_CODE (XEXP (x, 0)) == CONST_INT) + { +- if ((unsigned)~INTVAL (XEXP (x, 0)) > 63) ++ if ((unsigned HOST_WIDE_INT)~INTVAL (XEXP (x, 0)) > 63) + c = 4; + fmt = "e"; + i = 1; +@@ -665,7 +665,8 @@ + switch (code) + { + case CONST_INT: +- if ((unsigned)INTVAL (op) > 63 && GET_MODE (x) != QImode) ++ if ((unsigned HOST_WIDE_INT)INTVAL (op) > 63 ++ && GET_MODE (x) != QImode) + c += 1; /* 2 on VAX 2 */ + break; + case CONST: +Index: gcc/config/vax/vax.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/vax/vax.h,v +retrieving revision 1.54 +retrieving revision 1.54.4.1 +diff -u -r1.54 -r1.54.4.1 +--- gcc/gcc/config/vax/vax.h 22 Oct 2002 23:05:24 -0000 1.54 ++++ gcc/gcc/config/vax/vax.h 28 Dec 2004 06:28:01 -0000 1.54.4.1 +@@ -800,11 +800,6 @@ + Do not define this if the table should contain absolute addresses. */ + #define CASE_VECTOR_PC_RELATIVE 1 + +-/* Define this if the case instruction drops through after the table +- when the index is out of range. Don't define it if the case insn +- jumps to the default label instead. */ +-#define CASE_DROPS_THROUGH +- + /* Indicate that jump tables go in the text section. This is + necessary when compiling PIC code. */ + #define JUMP_TABLES_IN_TEXT_SECTION 1 +Index: gcc/config/vax/vax.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/vax/vax.md,v +retrieving revision 1.23 +retrieving revision 1.23.4.1 +diff -u -r1.23 -r1.23.4.1 +--- gcc/gcc/config/vax/vax.md 1 Oct 2002 20:16:04 -0000 1.23 ++++ gcc/gcc/config/vax/vax.md 28 Dec 2004 06:28:01 -0000 1.23.4.1 +@@ -1969,68 +1969,63 @@ + "jmp (%0)") + + ;; This is here to accept 5 arguments (as passed by expand_end_case) +-;; and pass the first 4 along to the casesi1 pattern that really does the work. ++;; and pass the first 4 along to the casesi1 pattern that really does ++;; the actual casesi work. We emit a jump here to the default label ++;; _before_ the casesi so that we can be sure that the casesi never ++;; drops through. ++;; This is suboptimal perhaps, but so is much of the rest of this ++;; machine description. For what it's worth, HPPA uses the same trick. ++;; ++;; operand 0 is index ++;; operand 1 is the minimum bound (a const_int) ++;; operand 2 is the maximum bound - minimum bound + 1 (also a const_int) ++;; operand 3 is CODE_LABEL for the table; ++;; operand 4 is the CODE_LABEL to go to if index out of range (ie. default). ++;; ++;; We emit: ++;; i = index - minimum_bound ++;; if (i > (maximum_bound - minimum_bound + 1) goto default; ++;; casesi (i, 0, table); ++;; + (define_expand "casesi" +- [(match_operand:SI 0 "general_operand" "") ; index +- (match_operand:SI 1 "general_operand" "") ; lower +- (match_operand:SI 2 "general_operand" "") ; upper-lower +- (match_operand 3 "" "") ; table label +- (match_operand 4 "" "")] ; default label +- "" +-{ +- emit_jump_insn (gen_casesi1 (operands[0], operands[1], +- operands[2], operands[3])); ++ [(match_operand:SI 0 "general_operand" "") ++ (match_operand:SI 1 "general_operand" "") ++ (match_operand:SI 2 "general_operand" "") ++ (match_operand 3 "" "") ++ (match_operand 4 "" "")] ++ "" ++{ ++ /* i = index - minimum_bound; ++ But only if the lower bound is not already zero. */ ++ if (operands[1] != const0_rtx) ++ { ++ rtx index = gen_reg_rtx (SImode); ++ emit_insn (gen_addsi3 (index, ++ operands[0], ++ GEN_INT (-INTVAL (operands[1])))); ++ operands[0] = index; ++ } ++ ++ /* if (i > (maximum_bound - minimum_bound + 1) goto default; */ ++ emit_insn (gen_cmpsi (operands[0], operands[2])); ++ emit_jump_insn (gen_bgtu (operands[4])); ++ ++ /* casesi (i, 0, table); */ ++ emit_jump_insn (gen_casesi1 (operands[0], operands[2], operands[3])); + DONE; + }) + ++;; This insn is a bit of a lier. It actually falls through if no case ++;; matches. But, we prevent that from ever happening by emiting a jump ++;; before this, see the define_expand above. + (define_insn "casesi1" +- [(set (pc) +- (if_then_else +- (leu (minus:SI (match_operand:SI 0 "general_operand" "g") +- (match_operand:SI 1 "general_operand" "g")) +- (match_operand:SI 2 "general_operand" "g")) +- (plus:SI (sign_extend:SI +- (mem:HI (plus:SI (mult:SI (minus:SI (match_dup 0) +- (match_dup 1)) +- (const_int 2)) +- (pc)))) +- (label_ref:SI (match_operand 3 "" ""))) +- (pc)))] +- "" +- "casel %0,%1,%2") +- +-;; This can arise by simplification when operand 1 is a constant int. +-(define_insn "" +- [(set (pc) +- (if_then_else +- (leu (plus:SI (match_operand:SI 0 "general_operand" "g") +- (match_operand:SI 1 "const_int_operand" "n")) +- (match_operand:SI 2 "general_operand" "g")) +- (plus:SI (sign_extend:SI +- (mem:HI (plus:SI (mult:SI (plus:SI (match_dup 0) +- (match_dup 1)) +- (const_int 2)) +- (pc)))) +- (label_ref:SI (match_operand 3 "" ""))) +- (pc)))] +- "" +- "* +-{ +- operands[1] = GEN_INT (-INTVAL (operands[1])); +- return \"casel %0,%1,%2\"; +-}") +- +-;; This can arise by simplification when the base for the case insn is zero. +-(define_insn "" +- [(set (pc) +- (if_then_else (leu (match_operand:SI 0 "general_operand" "g") +- (match_operand:SI 1 "general_operand" "g")) +- (plus:SI (sign_extend:SI +- (mem:HI (plus:SI (mult:SI (match_dup 0) +- (const_int 2)) +- (pc)))) +- (label_ref:SI (match_operand 2 "" ""))) +- (pc)))] ++ [(match_operand:SI 1 "const_int_operand" "n") ++ (set (pc) ++ (plus:SI (sign_extend:SI ++ (mem:HI (plus:SI (mult:SI (match_operand:SI 0 "general_operand" "g") ++ (const_int 2)) ++ (pc)))) ++ (label_ref:SI (match_operand 2 "" ""))))] + "" + "casel %0,$0,%1") + +Index: gcc/cp/ChangeLog +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/cp/ChangeLog,v +retrieving revision 1.3076.2.277 +retrieving revision 1.3076.2.281 +diff -u -r1.3076.2.277 -r1.3076.2.281 +--- gcc/gcc/cp/ChangeLog 30 Sep 2004 16:44:00 -0000 1.3076.2.277 ++++ gcc/gcc/cp/ChangeLog 18 Dec 2004 20:26:04 -0000 1.3076.2.281 +@@ -1,3 +1,25 @@ ++2004-12-18 Volker Reichelt ++ ++ PR c++/17456 ++ * cvt.c (convert_to_void): Set expr to void_zero_node after ++ overload failure. ++ ++2004-12-15 Volker Reichelt ++ ++ PR c++/16806 ++ * error.c (dump_expr) [BASELINK]: Use dump_expr. ++ ++2004-12-10 Volker Reichelt ++ ++ PR c++/17868 ++ * error.c (dump_expr): Add missing case for RDIV_EXPR. ++ ++2004-12-09 Nathan Sidwell ++ ++ PR c++/16681 ++ * init.c (build_zero_init): Build a RANGE_EXPR for an array ++ initializer. ++ + 2004-09-30 Release Manager + + * GCC 3.3.5 Released. +Index: gcc/cp/cvt.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v +retrieving revision 1.126.2.4 +retrieving revision 1.126.2.5 +diff -u -r1.126.2.4 -r1.126.2.5 +--- gcc/gcc/cp/cvt.c 23 Feb 2004 12:50:50 -0000 1.126.2.4 ++++ gcc/gcc/cp/cvt.c 18 Dec 2004 20:26:10 -0000 1.126.2.5 +@@ -903,6 +903,7 @@ + of an overloaded function, and this is not one of them. */ + pedwarn ("%s cannot resolve address of overloaded function", + implicit ? implicit : "void cast"); ++ expr = void_zero_node; + } + else if (implicit && probe == expr && is_overloaded_fn (probe)) + /* Only warn when there is no &. */ +Index: gcc/cp/error.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/cp/error.c,v +retrieving revision 1.192.2.9 +retrieving revision 1.192.2.11 +diff -u -r1.192.2.9 -r1.192.2.11 +--- gcc/gcc/cp/error.c 24 Jul 2004 13:03:23 -0000 1.192.2.9 ++++ gcc/gcc/cp/error.c 15 Dec 2004 16:45:23 -0000 1.192.2.11 +@@ -1724,6 +1724,7 @@ + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: ++ case RDIV_EXPR: + dump_binary_op ("/", t, flags); + break; + +@@ -2070,7 +2071,7 @@ + break; + + case BASELINK: +- print_tree_identifier (scratch_buffer, DECL_NAME (get_first_fn (t))); ++ dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS); + break; + + case TREE_LIST: +Index: gcc/cp/init.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v +retrieving revision 1.299.2.18 +retrieving revision 1.299.2.19 +diff -u -r1.299.2.18 -r1.299.2.19 +--- gcc/gcc/cp/init.c 28 Jul 2004 02:17:28 -0000 1.299.2.18 ++++ gcc/gcc/cp/init.c 9 Dec 2004 15:09:19 -0000 1.299.2.19 +@@ -235,7 +235,6 @@ + } + else if (TREE_CODE (type) == ARRAY_TYPE) + { +- tree index; + tree max_index; + tree inits; + +@@ -249,15 +248,17 @@ + /* A zero-sized array, which is accepted as an extension, will + have an upper bound of -1. */ + if (!tree_int_cst_equal (max_index, integer_minus_one_node)) +- for (index = size_zero_node; +- !tree_int_cst_lt (max_index, index); +- index = size_binop (PLUS_EXPR, index, size_one_node)) +- inits = tree_cons (index, +- build_zero_init (TREE_TYPE (type), +- /*nelts=*/NULL_TREE, +- static_storage_p), +- inits); +- CONSTRUCTOR_ELTS (init) = nreverse (inits); ++ { ++ tree elt_init = build_zero_init (TREE_TYPE (type), ++ /*nelts=*/NULL_TREE, ++ static_storage_p); ++ tree range = build (RANGE_EXPR, ++ sizetype, size_zero_node, max_index); ++ ++ inits = tree_cons (range, elt_init, inits); ++ } ++ ++ CONSTRUCTOR_ELTS (init) = nreverse (inits); + } + else if (TREE_CODE (type) == REFERENCE_TYPE) + ; +Index: gcc/doc/install.texi +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/doc/install.texi,v +retrieving revision 1.151.2.53 +retrieving revision 1.151.2.56 +diff -u -r1.151.2.53 -r1.151.2.56 +--- gcc/gcc/doc/install.texi 8 May 2004 17:37:31 -0000 1.151.2.53 ++++ gcc/gcc/doc/install.texi 14 Oct 2004 12:31:38 -0000 1.151.2.56 +@@ -3098,8 +3098,19 @@ + @file{/usr/bin} before @file{/usr/xpg4/bin} for the duration of the build. + + All releases of GNU binutils prior to 2.11.2 have known bugs on this +-platform. We recommend the use of GNU binutils 2.11.2 or the vendor +-tools (Sun @command{as}, Sun @command{ld}). ++platform. We recommend the use of GNU binutils 2.11.2 or later, or the ++vendor tools (Sun @command{as}, Sun @command{ld}). Note that your mileage ++may vary if you use a combination of the GNU tools and the Sun tools: while ++the combination GNU @command{as} + Sun @command{ld} should reasonably work, ++the reverse combination Sun @command{as} + GNU @command{ld} is known to ++cause memory corruption at runtime in some cases for C++ programs. ++ ++The stock GNU binutils 2.15 release is broken on this platform because of a ++single bug. It has been fixed on the 2.15 branch in the CVS repository. ++You can obtain a working version by checking out the binutils-2_15-branch ++from the CVS repository or applying the patch ++@uref{http://sources.redhat.com/ml/binutils-cvs/2004-09/msg00036.html} to the ++release. + + Sun bug 4296832 turns up when compiling X11 headers with GCC 2.95 or + newer: @command{g++} will complain that types are missing. These headers assume +@@ -3115,6 +3126,17 @@ + 108377-20 for Intel), and Solaris 8 (108652-24 or newer for SPARC, + 108653-22 for Intel) that fix this bug. + ++Sun bug 4927647 sometimes causes random spurious testsuite failures ++related to missing diagnostic output. This bug doesn't affect GCC ++itself, rather it is a kernel bug triggered by the @command{expect} ++program which is used only by the GCC testsuite driver. When the bug ++causes the @command{expect} program to miss anticipated output, extra ++testsuite failures appear. ++ ++There are patches for Solaris 8 (117350-12 or newer for SPARC, ++117351-12 or newer for Intel) and Solaris 9 (117171-11 or newer for ++SPARC, 117172-11 or newer for Intel) that address this problem. ++ + @html +
+ @end html +Index: gcc/doc/tm.texi +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/doc/tm.texi,v +retrieving revision 1.182.2.8 +retrieving revision 1.182.2.9 +diff -u -r1.182.2.8 -r1.182.2.9 +--- gcc/gcc/doc/tm.texi 5 Mar 2004 17:55:57 -0000 1.182.2.8 ++++ gcc/gcc/doc/tm.texi 14 Oct 2004 06:54:32 -0000 1.182.2.9 +@@ -4160,7 +4160,7 @@ + @end table + + @findex TARGET_ASM_OUTPUT_MI_THUNK +-@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_MI_THUNK (FILE *@var{file}, tree @var{thunk_fndecl}, HOST_WIDE_INT @var{delta}, tree @var{function}) ++@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_MI_THUNK (FILE *@var{file}, tree @var{thunk_fndecl}, HOST_WIDE_INT @var{delta}, HOST_WIDE_INT @var{vcall_offset}, tree @var{function}) + A function that outputs the assembler code for a thunk + function, used to implement C++ virtual function calls with multiple + inheritance. The thunk acts as a wrapper around a virtual function, +@@ -4174,7 +4174,15 @@ + e.g.@: @samp{%o0} on a sparc. The addition must preserve the values of + all other incoming arguments. + +-After the addition, emit code to jump to @var{function}, which is a ++Then, if @var{vcall_offset} is nonzero, an additional adjustment should be ++made after adding @code{delta}. In particular, if @var{p} is the ++adjusted pointer, the following adjustment should be made: ++ ++@smallexample ++p += (*((ptrdiff_t **)p))[vcall_offset/sizeof(ptrdiff_t)] ++@end smallexample ++ ++After the additions, emit code to jump to @var{function}, which is a + @code{FUNCTION_DECL}. This is a direct pure jump, not a call, and does + not touch the return address. Hence returning from @var{FUNCTION} will + return to whoever called the current @samp{thunk}. +@@ -4194,21 +4202,13 @@ + not support varargs. + @end deftypefn + +-@findex TARGET_ASM_OUTPUT_MI_VCALL_THUNK +-@deftypefn {Target Hook} void TARGET_ASM_OUTPUT_MI_VCALL_THUNK (FILE *@var{file}, tree @var{thunk_fndecl}, HOST_WIDE_INT @var{delta}, int @var{vcall_offset}, tree @var{function}) +-A function like @code{TARGET_ASM_OUTPUT_MI_THUNK}, except that if +-@var{vcall_offset} is nonzero, an additional adjustment should be made +-after adding @code{delta}. In particular, if @var{p} is the +-adjusted pointer, the following adjustment should be made: +- +-@example +-p += (*((ptrdiff_t **)p))[vcall_offset/sizeof(ptrdiff_t)] +-@end example +- +-@noindent +-If this function is defined, it will always be used in place of +-@code{TARGET_ASM_OUTPUT_MI_THUNK}. +- ++@findex TARGET_ASM_CAN_OUTPUT_MI_THUNK ++@deftypefn {Target Hook} bool TARGET_ASM_CAN_OUTPUT_MI_THUNK (tree @var{thunk_fndecl}, HOST_WIDE_INT @var{delta}, HOST_WIDE_INT @var{vcall_offset}, tree @var{function}) ++A function that returns true if TARGET_ASM_OUTPUT_MI_THUNK would be able ++to output the assembler code for the thunk function specified by the ++arguments it is passed, and false otherwise. In the latter case, the ++generic approach will be used by the C++ front end, with the limitations ++previously exposed. + @end deftypefn + + @node Profiling +Index: gcc/testsuite/ChangeLog +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/testsuite/ChangeLog,v +retrieving revision 1.2261.2.384 +retrieving revision 1.2261.2.398 +diff -u -r1.2261.2.384 -r1.2261.2.398 +--- gcc/gcc/testsuite/ChangeLog 30 Sep 2004 16:45:41 -0000 1.2261.2.384 ++++ gcc/gcc/testsuite/ChangeLog 23 Jan 2005 05:16:05 -0000 1.2261.2.398 +@@ -1,3 +1,78 @@ ++2005-01-22 Roger Sayle ++ ++ PR target/18402 ++ Backport from mainline ++ 2003-02-05 Jakub Jelinek ++ ++ PR optimization/8555 ++ * gcc.dg/20030204-1.c: New test. ++ ++2005-01-21 Giovanni Bajo ++ ++ PR c++/17115 ++ * g++.dg/warn/Winline-4.C: New test. ++ ++2005-01-18 Eric Botcazou ++ ++ * gcc.dg/short-compare-1.c: New test. ++ * gcc.dg/short-compare-2.c: Likewise. ++ ++2005-01-03 Kaveh R. Ghazi ++ ++ Backport: ++ 2003-10-13 Geoffrey Keating ++ ++ * gcc.dg/asm-names.c: Use scan-assembler-not rather ++ than linker trickery. ++ ++2005-01-02 Kaveh R. Ghazi ++ ++ * gcc.c-torture/execute/20020720-1.x: XFAIL for x86 when using ++ -fpic or -fPIC. ++ ++2004-12-21 Joseph S. Myers ++ ++ PR c/14765 ++ * gcc.dg/pr14765-1.c: New test. ++ ++2004-12-20 Andrew Pinski ++ ++ PR other/19093 ++ * g++.dg/opt/max1.C: Fix for 64bit targets. ++ ++2004-12-19 Roger Sayle ++ ++ PR middle-end/19068 ++ * g++.dg/opt/max1.C: New test case. ++ ++2004-12-16 Wolfgang Bangerth ++ ++ * g++.dg/other/complex1.C: New test. ++ ++2004-12-10 Volker Reichelt ++ ++ PR rtl-optimization/16536 ++ * gcc.c-torture/execute/restrict-1.c: New test. ++ ++2004-12-09 Nathan Sidwell ++ ++ PR c++/16681 ++ * g++.dg/init/array15.C: New. ++ * g++.dg/init/array16.C: New. ++ ++2004-11-29 Roger Sayle ++ ++ PR rtl-optimization/9771 ++ * gcc.dg/pr9771-1.c: New test case. ++ ++2004-11-27 Falk Hueffner ++ ++ * gcc.dg/loop-6.c: New test. ++ ++2004-10-13 Eric Botcazou ++ ++ * g++.dg/inherit/thunk1.C: Run on the SPARC. ++ + 2004-09-30 Release Manager + + * GCC 3.3.5 Released. +Index: gcc/testsuite/g++.dg/inherit/thunk1.C +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/inherit/thunk1.C,v +retrieving revision 1.5 +retrieving revision 1.5.12.1 +diff -u -r1.5 -r1.5.12.1 +--- gcc/gcc/testsuite/g++.dg/inherit/thunk1.C 24 Oct 2002 09:16:36 -0000 1.5 ++++ gcc/gcc/testsuite/g++.dg/inherit/thunk1.C 14 Oct 2004 06:54:49 -0000 1.5.12.1 +@@ -1,4 +1,4 @@ +-// { dg-do run { target i?86-*-* x86_64-*-* s390*-*-* alpha*-*-* ia64-*-* } } ++// { dg-do run { target i?86-*-* x86_64-*-* s390*-*-* alpha*-*-* ia64-*-* sparc*-*-* } } + + #include + +Index: gcc/testsuite/g++.dg/init/array15.C +=================================================================== +RCS file: gcc/testsuite/g++.dg/init/array15.C +diff -N gcc/testsuite/g++.dg/init/array15.C +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/g++.dg/init/array15.C 9 Dec 2004 15:09:32 -0000 1.1.6.1 +@@ -0,0 +1,46 @@ ++// { dg-do run } ++ ++// Copyright (C) 2004 Free Software Foundation, Inc. ++// Contributed by Nathan Sidwell 8 Dec 2004 ++ ++// PR 16681 too much memory used ++// Origin: Matt LaFary ++ ++struct foo { ++ unsigned char buffer[4111222]; ++ foo() ; ++ bool check () const; ++}; ++ ++foo::foo () ++ : buffer() ++{} ++ ++bool foo::check () const ++{ ++ for (unsigned ix = sizeof (buffer); ix--;) ++ if (buffer[ix]) ++ return false; ++ return true; ++} ++ ++void *operator new (__SIZE_TYPE__ size, void *p) ++{ ++ return p; ++} ++ ++char heap[5000000]; ++ ++int main () ++{ ++ for (unsigned ix = sizeof (heap); ix--;) ++ heap[ix] = ix; ++ ++ foo *f = new (heap) foo (); ++ ++ if (!f->check ()) ++ return 1; ++ return 0; ++} ++ ++ +Index: gcc/testsuite/g++.dg/init/array16.C +=================================================================== +RCS file: gcc/testsuite/g++.dg/init/array16.C +diff -N gcc/testsuite/g++.dg/init/array16.C +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/g++.dg/init/array16.C 9 Dec 2004 15:09:32 -0000 1.1.6.1 +@@ -0,0 +1,106 @@ ++// { dg-do run } ++ ++// Copyright (C) 2004 Free Software Foundation, Inc. ++// Contributed by Nathan Sidwell 8 Dec 2004 ++ ++// PR 16681 too much memory used ++// Origin: Matt LaFary ++ ++ ++struct elt ++{ ++ static int count; ++ static elt*ptr; ++ static int abort; ++ char c; ++ ++ elt (); ++ ~elt (); ++ ++}; ++ ++int elt::count; ++elt *elt::ptr; ++int elt::abort; ++ ++elt::elt () ++ :c () ++{ ++ if (count >= 0) ++ { ++ if (!ptr) ++ ptr = this; ++ if (count == 100) ++ throw 2; ++ if (this != ptr) ++ abort = 1; ++ count++; ++ ptr++; ++ } ++} ++ ++elt::~elt () ++{ ++ if (count >= 0) ++ { ++ ptr--; ++ count--; ++ if (ptr != this) ++ abort = 2; ++ } ++} ++ ++struct foo { ++ elt buffer[4111222]; ++ foo() ; ++ bool check () const; ++}; ++ ++foo::foo () ++ : buffer() ++{} ++ ++bool foo::check () const ++{ ++ for (unsigned ix = sizeof (buffer)/ sizeof (buffer[0]); ix--;) ++ if (buffer[ix].c) ++ return false; ++ return true; ++} ++ ++void *operator new (__SIZE_TYPE__ size, void *p) ++{ ++ return p; ++} ++ ++char heap[5000000]; ++ ++int main () ++{ ++ for (unsigned ix = sizeof (heap); ix--;) ++ heap[ix] = ix; ++ ++ try ++ { ++ foo *f = new (heap) foo (); ++ return 1; ++ } ++ catch (...) ++ { ++ if (elt::count) ++ return 2; ++ if (elt::abort) ++ return elt::abort + 3; ++ } ++ ++ for (unsigned ix = sizeof (heap); ix--;) ++ heap[ix] = ix; ++ ++ elt::count = -1; ++ foo *f = new (heap) foo (); ++ if (!f->check ()) ++ return 3; ++ return 0; ++} ++ ++ +Index: gcc/testsuite/g++.dg/opt/max1.C +=================================================================== +RCS file: gcc/testsuite/g++.dg/opt/max1.C +diff -N gcc/testsuite/g++.dg/opt/max1.C +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/g++.dg/opt/max1.C 20 Dec 2004 21:12:34 -0000 1.2.2.2 +@@ -0,0 +1,29 @@ ++/* PR middle-end/19068 */ ++/* Test case by Andrew Pinski */ ++/* { dg-do run } */ ++/* { dg-options "-O2" } */ ++ ++extern "C" void abort (void); ++ ++long fff[10]; ++ ++void f(long a) ++{ ++ int i; ++ a = *((long*)(a+1+sizeof(long))) >? *((long*)(a+1)); ++ ++ for(i=0;i<10;i++) ++ fff[i] = a; ++} ++ ++int main(void) ++{ ++ int i; ++ long a[2] = {10,5}; ++ f((long)(&a)-1); ++ for(i = 0;i<10;i++) ++ if (fff[i]!=10) ++ abort (); ++ return 0; ++} ++ +Index: gcc/testsuite/g++.dg/other/complex1.C +=================================================================== +RCS file: gcc/testsuite/g++.dg/other/complex1.C +diff -N gcc/testsuite/g++.dg/other/complex1.C +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/g++.dg/other/complex1.C 16 Dec 2004 14:04:52 -0000 1.1.4.1 +@@ -0,0 +1,28 @@ ++// PR middle-end/18882 ++// Origin: Petr Mikulik ++// Testcase by Wolfgang Bangerth ++ ++// { dg-do run } ++// { dg-options "" } ++ ++extern "C" void abort (); ++ ++struct C { ++ __complex__ long double c; ++}; ++ ++void foo() ++{ ++ C x = {2+2i}; ++ ++ int n = 1; ++ C y = (n==1) ? x : (C){3+3i}; ++ if (__imag__ y.c != 2) ++ abort (); ++} ++ ++int main(void) ++{ ++ foo (); ++ return 0; ++} +Index: gcc/testsuite/g++.dg/warn/Winline-4.C +=================================================================== +RCS file: gcc/testsuite/g++.dg/warn/Winline-4.C +diff -N gcc/testsuite/g++.dg/warn/Winline-4.C +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/g++.dg/warn/Winline-4.C 21 Jan 2005 10:02:30 -0000 1.1.42.1 +@@ -0,0 +1,17 @@ ++// { dg-do compile } ++// { dg-options "-O2 -Winline" } ++// Origin: ++// PR 17115: We should not emit -Winline warning for functions marked with ++// noinline ++ ++struct Foo { ++ __attribute__((noinline)) int a(int r) { return r & 1; } ++ virtual __attribute__((noinline)) int b(int r) { return r & 1; } ++ static __attribute__((noinline)) int c(int r) { return r & 1; } ++}; ++ ++int bar(int r) { ++ Foo f; ++ int k = 1; k &= f.a(r); k &= f.b(r); k &= f.a(r); ++ return k; ++} +Index: gcc/testsuite/gcc.c-torture/execute/20020720-1.x +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.c-torture/execute/20020720-1.x,v +retrieving revision 1.8.6.2 +retrieving revision 1.8.6.3 +diff -u -r1.8.6.2 -r1.8.6.3 +--- gcc/gcc/testsuite/gcc.c-torture/execute/20020720-1.x 8 Mar 2003 14:34:06 -0000 1.8.6.2 ++++ gcc/gcc/testsuite/gcc.c-torture/execute/20020720-1.x 3 Jan 2005 01:43:45 -0000 1.8.6.3 +@@ -11,6 +11,19 @@ + # and can make the optimization. + + # Don't XFAIL at -O0, that should never fail. ++if { [istarget "i?86-*-*"] } { ++ set torture_eval_before_compile { ++ global compiler_conditional_xfail_data ++ set compiler_conditional_xfail_data { ++ "PR opt/10348" \ ++ { "*-*-*" } \ ++ { "-fpic" "-fPIC" } \ ++ { "-O0" } ++ } ++ } ++ return 0 ++} ++ + set torture_eval_before_compile { + global compiler_conditional_xfail_data + set compiler_conditional_xfail_data { +Index: gcc/testsuite/gcc.c-torture/execute/restrict-1.c +=================================================================== +RCS file: gcc/testsuite/gcc.c-torture/execute/restrict-1.c +diff -N gcc/testsuite/gcc.c-torture/execute/restrict-1.c +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/gcc.c-torture/execute/restrict-1.c 10 Dec 2004 17:25:07 -0000 1.2.44.1 +@@ -0,0 +1,30 @@ ++/* PR rtl-optimization/16536 ++ Origin: Jeremy Denise ++ Reduced: Wolfgang Bangerth ++ Volker Reichelt */ ++ ++extern void abort (); ++ ++typedef struct ++{ ++ int i, dummy; ++} A; ++ ++inline A foo (const A* p, const A* q) ++{ ++ return (A){p->i+q->i}; ++} ++ ++void bar (A* __restrict__ p) ++{ ++ *p=foo(p,p); ++ if (p->i!=2) ++ abort(); ++} ++ ++int main () ++{ ++ A a={1}; ++ bar(&a); ++ return 0; ++} +Index: gcc/testsuite/gcc.dg/20030204-1.c +=================================================================== +RCS file: gcc/testsuite/gcc.dg/20030204-1.c +diff -N gcc/testsuite/gcc.dg/20030204-1.c +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/gcc.dg/20030204-1.c 23 Jan 2005 05:16:14 -0000 1.3.6.1 +@@ -0,0 +1,16 @@ ++/* PR optimization/8555 */ ++/* { dg-do compile } */ ++/* { dg-options "-O -ffast-math -funroll-loops" } */ ++/* { dg-options "-march=pentium3 -O -ffast-math -funroll-loops" { target i?86-*-* } } */ ++ ++float foo (float *a, int i) ++{ ++ int j; ++ float x = a[j = i - 1], y; ++ ++ for (j = i; --j >= 0; ) ++ if ((y = a[j]) > x) ++ x = y; ++ ++ return x; ++} +Index: gcc/testsuite/gcc.dg/asm-names.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/testsuite/gcc.dg/asm-names.c,v +retrieving revision 1.2 +retrieving revision 1.2.44.1 +diff -u -r1.2 -r1.2.44.1 +--- gcc/gcc/testsuite/gcc.dg/asm-names.c 27 Aug 2001 19:23:11 -0000 1.2 ++++ gcc/gcc/testsuite/gcc.dg/asm-names.c 4 Jan 2005 00:20:35 -0000 1.2.44.1 +@@ -2,26 +2,15 @@ + to have an underscore prefixed, even if normal symbols are. + Problem reported by Krister Walfridsson . */ + +-/* { dg-do link } */ ++/* { dg-do compile } */ + /* { dg-options "-fleading-underscore" } */ ++/* { dg-final { scan-assembler-not "____frob14" } } */ + + extern void frobnicate (void) asm ("___frob14"); /* three underscores */ + +-void __frob14 (void) {} /* two underscores */ +- + int + main (void) + { + frobnicate (); + return 0; + } +- +-/* In case built where the runtime expects no leading underscore on +- main(). */ +-extern int xmain (void) asm ("main"); +- +-int xmain (void) { return main(); } +- +-/* In case built where the runtime calls __main. */ +-extern int ymain (void) asm ("___main"); +-int ymain (void) { return main(); } +Index: gcc/testsuite/gcc.dg/loop-6.c +=================================================================== +RCS file: gcc/testsuite/gcc.dg/loop-6.c +diff -N gcc/testsuite/gcc.dg/loop-6.c +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/gcc.dg/loop-6.c 27 Nov 2004 16:59:16 -0000 1.1.4.1 +@@ -0,0 +1,25 @@ ++/* PR optimization/18577 */ ++/* Origin: Falk Hueffner */ ++ ++/* { dg-do run } */ ++/* { dg-options "-O2 -funroll-all-loops" } */ ++ ++static float tfcos12[3]; ++__attribute__((noinline)) double f(double x) { return x; } ++int g; ++ ++int main(void) ++{ ++ int i, j; ++ for (i = 0; i < 1; i++) ++ tfcos12[i] = 0.5; ++ ++ for (i = 0; i < 1; i++) ++ { ++ tfcos12[i] = 0.5 * f(i); ++ for (j = 0; j < 12; j++) ++ g++; ++ } ++ ++ return 0; ++} +Index: gcc/testsuite/gcc.dg/pr14765-1.c +=================================================================== +RCS file: gcc/testsuite/gcc.dg/pr14765-1.c +diff -N gcc/testsuite/gcc.dg/pr14765-1.c +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/gcc.dg/pr14765-1.c 21 Dec 2004 21:51:29 -0000 1.1.48.1 +@@ -0,0 +1,11 @@ ++/* Empty statement expressions should get void type. Bug 14765 from ++ Serge Belyshev . */ ++/* { dg-do compile } */ ++/* { dg-options "" } */ ++ ++int a; ++void fun () ++{ ++ a = 0; ++ a = ({}); /* { dg-error "not ignored" "void stmt expr" } */ ++} +Index: gcc/testsuite/gcc.dg/pr9771-1.c +=================================================================== +RCS file: gcc/testsuite/gcc.dg/pr9771-1.c +diff -N gcc/testsuite/gcc.dg/pr9771-1.c +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/gcc.dg/pr9771-1.c 30 Nov 2004 04:34:21 -0000 1.1.44.1 +@@ -0,0 +1,43 @@ ++/* PR rtl-optimization/9771 */ ++/* { dg-do run { target i?86-*-* } } */ ++/* { dg-options "-O2 -fomit-frame-pointer -ffixed-ebp" } */ ++ ++extern void abort(void); ++extern void exit(int); ++ ++register long *B asm ("ebp"); ++ ++long x = 10; ++long y = 20; ++ ++void bar(void) ++{ ++ B = &y; ++} ++ ++void foo() ++{ ++ long *adr = B; ++ long save = *adr; ++ ++ *adr = 123; ++ ++ bar(); ++ ++ *adr = save; ++} ++ ++int main() ++{ ++ B = &x; ++ ++ foo(); ++ ++ if (x != 10 || y != 20) ++ abort(); ++ ++ /* We can't return, as our caller may assume %ebp is preserved! */ ++ /* We could save/restore it (like foo), but its easier to exit. */ ++ exit(0); ++} ++ +Index: gcc/testsuite/gcc.dg/short-compare-1.c +=================================================================== +RCS file: gcc/testsuite/gcc.dg/short-compare-1.c +diff -N gcc/testsuite/gcc.dg/short-compare-1.c +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/gcc.dg/short-compare-1.c 18 Jan 2005 08:39:29 -0000 1.1.4.1 +@@ -0,0 +1,21 @@ ++/* PR rtl-optimization/19296 */ ++/* Origin: Falk Hueffner */ ++ ++/* { dg-do run } */ ++/* { dg-options "-O" } */ ++/* { dg-options "-O -mcpu=i686" { target i?86-*-* } } */ ++/* { dg-options "-O -m32 -mcpu=i686" { target x86_64-*-* } } */ ++ ++extern void abort(void); ++ ++void f(unsigned short ad) ++{ ++ if (ad >= 0x4000 && ad < 0xc000) ++ abort(); ++} ++ ++int main(void) ++{ ++ f(0xff00); ++ return 0; ++} +Index: gcc/testsuite/gcc.dg/short-compare-2.c +=================================================================== +RCS file: gcc/testsuite/gcc.dg/short-compare-2.c +diff -N gcc/testsuite/gcc.dg/short-compare-2.c +--- gcc//dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/gcc.dg/short-compare-2.c 18 Jan 2005 08:39:29 -0000 1.1.4.1 +@@ -0,0 +1,22 @@ ++/* PR rtl-optimization/19296 */ ++/* Origin: Falk Hueffner */ ++/* Testcase by Andrew Pinski */ ++ ++/* { dg-do run } */ ++/* { dg-options "-O" } */ ++/* { dg-options "-O -mcpu=i686" { target i?86-*-* } } */ ++/* { dg-options "-O -m32 -mcpu=i686" { target x86_64-*-* } } */ ++ ++extern void abort(); ++ ++void f(unsigned short ad) ++{ ++ if ((short) (ad - 0x4000) >= 0) ++ abort(); ++} ++ ++int main(void) ++{ ++ f(0xc000); ++ return 0; ++} +Index: libstdc++-v3/ChangeLog +=================================================================== +RCS file: /cvs/gcc/gcc/libstdc++-v3/ChangeLog,v +retrieving revision 1.1464.2.192 +retrieving revision 1.1464.2.195 +diff -u -r1.1464.2.192 -r1.1464.2.195 +--- gcc/libstdc++-v3/ChangeLog 30 Sep 2004 16:47:23 -0000 1.1464.2.192 ++++ gcc/libstdc++-v3/ChangeLog 21 Jan 2005 23:52:45 -0000 1.1464.2.195 +@@ -1,3 +1,18 @@ ++2005-01-22 Volker Reichelt ++ ++ PR libstdc++/19510 ++ * include/bits/stl_list.h (_List_iterator_base): Initialize _M_node ++ in constructor. ++ (_List_iterator): Initialize _List_iterator_base in constructor. ++ * include/bits/stl_tree.h (_Rb_tree_iterator): Initialize _M_node ++ in constructor. ++ ++2004-12-03 Richard Henderson ++ ++ PR 17856 ++ * config/cpu/i486/atomicity.h (__exchange_and_add, __atomic_add): ++ Split in-out memory constraints. ++ + 2004-09-30 Release Manager + + * GCC 3.3.5 Released. +Index: libstdc++-v3/config/cpu/i486/atomicity.h +=================================================================== +RCS file: /cvs/gcc/gcc/libstdc++-v3/config/cpu/i486/atomicity.h,v +retrieving revision 1.1.22.1 +retrieving revision 1.1.22.2 +diff -u -r1.1.22.1 -r1.1.22.2 +--- gcc/libstdc++-v3/config/cpu/i486/atomicity.h 2 Jun 2003 18:48:52 -0000 1.1.22.1 ++++ gcc/libstdc++-v3/config/cpu/i486/atomicity.h 3 Dec 2004 23:44:07 -0000 1.1.22.2 +@@ -1,6 +1,6 @@ + // Low-level functions for atomic operations: x86, x >= 4 version -*- C++ -*- + +-// Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. ++// Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + // + // This file is part of the GNU ISO C++ Library. This library is free + // software; you can redistribute it and/or modify it under the +@@ -38,8 +38,8 @@ + { + register _Atomic_word __result; + __asm__ __volatile__ ("lock; xadd{l} {%0,%1|%1,%0}" +- : "=r" (__result), "+m" (*__mem) +- : "0" (__val) ++ : "=r" (__result), "=m" (*__mem) ++ : "0" (__val), "m"(*__mem) + : "memory"); + return __result; + } +@@ -49,7 +49,9 @@ + __atomic_add (volatile _Atomic_word* __mem, int __val) + { + __asm__ __volatile__ ("lock; add{l} {%1,%0|%0,%1}" +- : "+m" (*__mem) : "ir" (__val) : "memory"); ++ : "=m" (*__mem) ++ : "ir" (__val), "m"(*__mem) ++ : "memory"); + } + + #endif /* atomicity.h */ +Index: libstdc++-v3/include/bits/c++config +=================================================================== +RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/c++config,v +retrieving revision 1.574.2.657 +retrieving revision 1.574.2.779 +diff -u -r1.574.2.657 -r1.574.2.779 +--- gcc/libstdc++-v3/include/bits/c++config 30 Sep 2004 00:16:09 -0000 1.574.2.657 ++++ gcc/libstdc++-v3/include/bits/c++config 30 Jan 2005 00:16:14 -0000 1.574.2.779 +@@ -35,7 +35,7 @@ + #include + + // The current version of the C++ library in compressed ISO date format. +-#define __GLIBCPP__ 20040930 ++#define __GLIBCPP__ 20050130 + + // This is necessary until GCC supports separate template compilation. + #define _GLIBCPP_NO_TEMPLATE_EXPORT 1 +Index: libstdc++-v3/include/bits/stl_list.h +=================================================================== +RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/stl_list.h,v +retrieving revision 1.20 +retrieving revision 1.20.8.1 +diff -u -r1.20 -r1.20.8.1 +--- gcc/libstdc++-v3/include/bits/stl_list.h 10 Sep 2002 23:19:10 -0000 1.20 ++++ gcc/libstdc++-v3/include/bits/stl_list.h 21 Jan 2005 23:52:48 -0000 1.20.8.1 +@@ -1,6 +1,6 @@ + // List implementation -*- C++ -*- + +-// Copyright (C) 2001, 2002 Free Software Foundation, Inc. ++// Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. + // + // This file is part of the GNU ISO C++ Library. This library is free + // software; you can redistribute it and/or modify it under the +@@ -108,6 +108,7 @@ + { } + + _List_iterator_base() ++ : _M_node() + { } + + /// Walk the %list forward. +@@ -156,6 +157,7 @@ + { } + + _List_iterator() ++ : _List_iterator_base() + { } + + _List_iterator(const iterator& __x) +Index: libstdc++-v3/include/bits/stl_tree.h +=================================================================== +RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/stl_tree.h,v +retrieving revision 1.17 +retrieving revision 1.17.2.1 +diff -u -r1.17 -r1.17.2.1 +--- gcc/libstdc++-v3/include/bits/stl_tree.h 22 Nov 2002 18:53:53 -0000 1.17 ++++ gcc/libstdc++-v3/include/bits/stl_tree.h 21 Jan 2005 23:52:49 -0000 1.17.2.1 +@@ -1,6 +1,6 @@ + // RB tree implementation -*- C++ -*- + +-// Copyright (C) 2001, 2002 Free Software Foundation, Inc. ++// Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc. + // + // This file is part of the GNU ISO C++ Library. This library is free + // software; you can redistribute it and/or modify it under the +@@ -191,7 +191,7 @@ + typedef _Rb_tree_iterator<_Val, _Ref, _Ptr> _Self; + typedef _Rb_tree_node<_Val>* _Link_type; + +- _Rb_tree_iterator() {} ++ _Rb_tree_iterator() { _M_node = 0; } + _Rb_tree_iterator(_Link_type __x) { _M_node = __x; } + _Rb_tree_iterator(const iterator& __it) { _M_node = __it._M_node; } + diff --git a/misc/buildroot/toolchain/gcc/3.3.5/specs-arm-soft-float b/misc/buildroot/toolchain/gcc/3.3.5/specs-arm-soft-float new file mode 100644 index 000000000..d692174aa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/specs-arm-soft-float @@ -0,0 +1,124 @@ +*asm: +%{mbig-endian:-EB} %{mlittle-endian:-EL} %{mcpu=*:-mcpu=%*} %{march=*:-march=%*} %{mapcs-*:-mapcs-%*} %(subtarget_asm_float_spec) %{mthumb-interwork:-mthumb-interwork} %(subtarget_extra_asm_spec) + +*asm_debug: +%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}} + +*asm_final: + + +*asm_options: +%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} + +*invoke_as: +%{!S:-o %{|!pipe:%g.s} | + as %(asm_options) %{!pipe:%g.s} %A } + +*cpp: +%(cpp_cpu_arch) %(subtarget_cpp_spec) %{mapcs-32:%{mapcs-26: %e-mapcs-26 and -mapcs-32 may not be used together}} %{msoft-float:%{mhard-float: %e-msoft-float and -mhard_float may not be used together}} %{mbig-endian:%{mlittle-endian: %e-mbig-endian and -mlittle-endian may not be used together}} + +*cpp_options: +%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*} %{O*} %{undef} + +*cpp_debug_options: +%{d*} + +*cpp_unique_options: +%{C:%{!E:%eGNU C does not support -C without using -E}} %{CC:%{!E:%eGNU C does not support -CC without using -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}} %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3} %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{E|M|MM:%W{o*}} + +*trad_capable_cpp: +cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp} + +*cc1: +%{profile:-p} + +*cc1_options: +%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{msoft-float:%{mhard-float: %e-msoft-float and -mhard_float may not be used together}} %{!mhard-float:%{!msoft-float:-msoft-float}} + +*cc1plus: + + +*link_gcc_c_sequence: +%{static:--start-group} %G %L %{static:--end-group}%{!static:%G} + +*endfile: +%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s + +*link: +%{h*} %{version:-v} %{b} %{Wl,*:%*} %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0} -X %{mbig-endian:-EB} -m armelf_linux -p + +*lib: +%{pthread:-lpthread} %{shared:-lc} %{!shared:%{profile:-lc_p}%{!profile:-lc}} + +*libgcc: +%{!mhard-float:-lfloat} %{static|static-libgcc:-lgcc -lgcc_eh}%{!static:%{!static-libgcc:%{!shared:%{!shared-libgcc:-lgcc -lgcc_eh}%{shared-libgcc:-lgcc_s%M -lgcc}}%{shared:-lgcc_s%M}}} + +*startfile: +%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:%{profile:gcrt1.o%s} %{!profile:crt1.o%s}}}} crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s} + +*switches_need_spaces: + + +*predefines: + + +*cross_compile: +1 + +*version: +3.3.4 + +*multilib: +. ; + +*multilib_defaults: +marm mlittle-endian msoft-float mapcs-32 mno-thumb-interwork + +*multilib_extra: + + +*multilib_matches: + + +*multilib_exclusions: + + +*multilib_options: + + +*linker: +collect2 + +*link_libgcc: +%D + +*md_exec_prefix: + + +*md_startfile_prefix: + + +*md_startfile_prefix_1: + + +*startfile_prefix_spec: + + +*cpp_cpu_arch: +%{march=arm2:-D__ARM_ARCH_2__} %{march=arm250:-D__ARM_ARCH_2__} %{march=arm3:-D__ARM_ARCH_2__} %{march=arm6:-D__ARM_ARCH_3__} %{march=arm600:-D__ARM_ARCH_3__} %{march=arm610:-D__ARM_ARCH_3__} %{march=arm7:-D__ARM_ARCH_3__} %{march=arm700:-D__ARM_ARCH_3__} %{march=arm710:-D__ARM_ARCH_3__} %{march=arm720:-D__ARM_ARCH_3__} %{march=arm7100:-D__ARM_ARCH_3__} %{march=arm7500:-D__ARM_ARCH_3__} %{march=arm7500fe:-D__ARM_ARCH_3__} %{march=arm7m:-D__ARM_ARCH_3M__} %{march=arm7dm:-D__ARM_ARCH_3M__} %{march=arm7dmi:-D__ARM_ARCH_3M__} %{march=arm7tdmi:-D__ARM_ARCH_4T__} %{march=arm8:-D__ARM_ARCH_4__} %{march=arm810:-D__ARM_ARCH_4__} %{march=arm9:-D__ARM_ARCH_4T__} %{march=arm920:-D__ARM_ARCH_4__} %{march=arm920t:-D__ARM_ARCH_4T__} %{march=arm9tdmi:-D__ARM_ARCH_4T__} %{march=strongarm:-D__ARM_ARCH_4__} %{march=strongarm110:-D__ARM_ARCH_4__} %{march=strongarm1100:-D__ARM_ARCH_4__} %{march=xscale:-D__ARM_ARCH_5TE__} %{march=xscale:-D__XSCALE__} %{march=armv2:-D__ARM_ARCH_2__} %{march=armv2a:-D__ARM_ARCH_2__} %{march=armv3:-D__ARM_ARCH_3__} %{march=armv3m:-D__ARM_ARCH_3M__} %{march=armv4:-D__ARM_ARCH_4__} %{march=armv4t:-D__ARM_ARCH_4T__} %{march=armv5:-D__ARM_ARCH_5__} %{march=armv5t:-D__ARM_ARCH_5T__} %{march=armv5e:-D__ARM_ARCH_5E__} %{march=armv5te:-D__ARM_ARCH_5TE__} %{!march=*: %{mcpu=arm2:-D__ARM_ARCH_2__} %{mcpu=arm250:-D__ARM_ARCH_2__} %{mcpu=arm3:-D__ARM_ARCH_2__} %{mcpu=arm6:-D__ARM_ARCH_3__} %{mcpu=arm600:-D__ARM_ARCH_3__} %{mcpu=arm610:-D__ARM_ARCH_3__} %{mcpu=arm7:-D__ARM_ARCH_3__} %{mcpu=arm700:-D__ARM_ARCH_3__} %{mcpu=arm710:-D__ARM_ARCH_3__} %{mcpu=arm720:-D__ARM_ARCH_3__} %{mcpu=arm7100:-D__ARM_ARCH_3__} %{mcpu=arm7500:-D__ARM_ARCH_3__} %{mcpu=arm7500fe:-D__ARM_ARCH_3__} %{mcpu=arm7m:-D__ARM_ARCH_3M__} %{mcpu=arm7dm:-D__ARM_ARCH_3M__} %{mcpu=arm7dmi:-D__ARM_ARCH_3M__} %{mcpu=arm7tdmi:-D__ARM_ARCH_4T__} %{mcpu=arm8:-D__ARM_ARCH_4__} %{mcpu=arm810:-D__ARM_ARCH_4__} %{mcpu=arm9:-D__ARM_ARCH_4T__} %{mcpu=arm920:-D__ARM_ARCH_4__} %{mcpu=arm920t:-D__ARM_ARCH_4T__} %{mcpu=arm9tdmi:-D__ARM_ARCH_4T__} %{mcpu=strongarm:-D__ARM_ARCH_4__} %{mcpu=strongarm110:-D__ARM_ARCH_4__} %{mcpu=strongarm1100:-D__ARM_ARCH_4__} %{mcpu=xscale:-D__ARM_ARCH_5TE__} %{mcpu=xscale:-D__XSCALE__} %{!mcpu*:%(cpp_cpu_arch_default)}} + +*cpp_cpu_arch_default: +-D__ARM_ARCH_4T__ + +*subtarget_cpp_spec: +%{posix:-D_POSIX_SOURCE} %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} + +*subtarget_extra_asm_spec: + + +*subtarget_asm_float_spec: +%{mapcs-float:-mfloat} %{!mhard-float:-mno-fpu} + +*link_command: +%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S: %(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}} + diff --git a/misc/buildroot/toolchain/gcc/3.3.5/specs-mips-soft-float b/misc/buildroot/toolchain/gcc/3.3.5/specs-mips-soft-float new file mode 100644 index 000000000..2a4240012 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/specs-mips-soft-float @@ -0,0 +1,145 @@ +*asm: +%{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} %{mips32} %{mips64}%{mips16:%{!mno-mips16:-mips16}} %{mno-mips16:-no-mips16} %(subtarget_asm_optimizing_spec) %(subtarget_asm_debugging_spec) %{membedded-pic} %{mabi=32:-32}%{mabi=n32:-n32}%{mabi=64:-64}%{mabi=n64:-64} %{mabi=eabi} %{mabi=o64} %{!mabi*: %(asm_abi_default_spec)} %{mgp32} %{mgp64} %{march=*} %(target_asm_spec) %(subtarget_asm_spec) + +*asm_debug: +%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}} + +*asm_final: +%| + +*asm_options: +%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} + +*invoke_as: +%{!S:-o %{|!pipe:%g.s} | + as %(asm_options) %{!pipe:%g.s} %A } + +*cpp: +%(subtarget_cpp_spec) + +*cpp_options: +%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*} %{O*} %{undef} + +*cpp_debug_options: +%{d*} + +*cpp_unique_options: +%{C:%{!E:%eGNU C does not support -C without using -E}} %{CC:%{!E:%eGNU C does not support -CC without using -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}} %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3} %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{E|M|MM:%W{o*}} + +*trad_capable_cpp: +cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp} + +*cc1: +%{profile:-p} + +*cc1_options: +%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{msoft-float:%{mhard-float: %e-msoft-float and -mhard_float may not be used together}} %{!mhard-float:%{!msoft-float:-msoft-float}} + +*cc1plus: + + +*link_gcc_c_sequence: +%{static:--start-group} %G %L %{static:--end-group}%{!static:%G} + +*endfile: +%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s + +*link: +%{!static:--eh-frame-hdr} %(endian_spec) %{shared:-shared} %{!shared: %{!ibcs: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}} %{static:-static}}} + +*lib: +%{shared: -lc} %{!static:-rpath-link %R/lib:%R/usr/lib} %{!shared: %{pthread:-lpthread} %{profile:-lc_p} %{!profile: -lc}} + +*libgcc: +%{static|static-libgcc:-lgcc -lgcc_eh}%{!static:%{!static-libgcc:%{!shared:%{!shared-libgcc:-lgcc -lgcc_eh}%{shared-libgcc:-lgcc_s%M -lgcc}}%{shared:%{shared-libgcc:-lgcc_s%M}%{!shared-libgcc:-lgcc}}}} + +*startfile: +%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:%{profile:gcrt1.o%s} %{!profile:crt1.o%s}}}} crti.o%s %{static:crtbeginT.o%s} %{!static:%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}} + +*switches_need_spaces: + + +*predefines: + + +*cross_compile: +1 + +*version: +3.3.4 + +*multilib: +. ; + +*multilib_defaults: +EB mips1 mabi=32 + +*multilib_extra: + + +*multilib_matches: + + +*multilib_exclusions: + + +*multilib_options: + + +*linker: +collect2 + +*link_libgcc: +%D + +*md_exec_prefix: + + +*md_startfile_prefix: + + +*md_startfile_prefix_1: + + +*startfile_prefix_spec: + + +*subtarget_cc1_spec: + + +*subtarget_cpp_spec: +%{fno-PIC:-U__PIC__ -U__pic__} %{fno-pic:-U__PIC__ -U__pic__} %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{pthread:-D_REENTRANT} + +*mips_as_asm_spec: +%{!.s:-nocpp} %{.s: %{cpp} %{nocpp}} %{pipe: %e-pipe is not supported} %{K} %(subtarget_mips_as_asm_spec) + +*gas_asm_spec: +%{mtune=*} %{v} + +*target_asm_spec: +%{mmips-as: %(mips_as_asm_spec)} %{!mmips-as: %(gas_asm_spec)} + +*subtarget_mips_as_asm_spec: +%{v} + +*subtarget_asm_optimizing_spec: +%{noasmopt:-O0} %{!noasmopt:%{O:-O2} %{O1:-O2} %{O2:-O2} %{O3:-O3}} + +*subtarget_asm_debugging_spec: +-g0 + +*mdebug_asm_spec: +%{!gdwarf*:-mdebug} %{gdwarf*:-no-mdebug} + +*subtarget_asm_spec: +%{mabi=64: -64} %{!fno-PIC:%{!fno-pic:-KPIC}} %{fno-PIC:-non_shared} %{fno-pic:-non_shared} + +*asm_abi_default_spec: +-32 + +*endian_spec: +%{!EL:%{!mel:-EB}} %{EL|mel:-EL} + +*link_command: +%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S: %(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}} + diff --git a/misc/buildroot/toolchain/gcc/3.3.5/specs-mipsel-soft-float b/misc/buildroot/toolchain/gcc/3.3.5/specs-mipsel-soft-float new file mode 100644 index 000000000..481bf5a39 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/specs-mipsel-soft-float @@ -0,0 +1,145 @@ +*asm: +%{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} %{mips32} %{mips64}%{mips16:%{!mno-mips16:-mips16}} %{mno-mips16:-no-mips16} %(subtarget_asm_optimizing_spec) %(subtarget_asm_debugging_spec) %{membedded-pic} %{mabi=32:-32}%{mabi=n32:-n32}%{mabi=64:-64}%{mabi=n64:-64} %{mabi=eabi} %{mabi=o64} %{!mabi*: %(asm_abi_default_spec)} %{mgp32} %{mgp64} %{march=*} %(target_asm_spec) %(subtarget_asm_spec) + +*asm_debug: +%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}} + +*asm_final: +%| + +*asm_options: +%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} + +*invoke_as: +%{!S:-o %{|!pipe:%g.s} | + as %(asm_options) %{!pipe:%g.s} %A } + +*cpp: +%(subtarget_cpp_spec) + +*cpp_options: +%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*} %{O*} %{undef} + +*cpp_debug_options: +%{d*} + +*cpp_unique_options: +%{C:%{!E:%eGNU C does not support -C without using -E}} %{CC:%{!E:%eGNU C does not support -CC without using -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}} %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3} %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{E|M|MM:%W{o*}} + +*trad_capable_cpp: +cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp} + +*cc1: +%{profile:-p} + +*cc1_options: +%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{msoft-float:%{mhard-float: %e-msoft-float and -mhard_float may not be used together}} %{!mhard-float:%{!msoft-float:-msoft-float}} + +*cc1plus: + + +*link_gcc_c_sequence: +%{static:--start-group} %G %L %{static:--end-group}%{!static:%G} + +*endfile: +%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s + +*link: +%{!static:--eh-frame-hdr} %(endian_spec) %{shared:-shared} %{!shared: %{!ibcs: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}} %{static:-static}}} + +*lib: +%{shared: -lc} %{!static:-rpath-link %R/lib:%R/usr/lib} %{!shared: %{pthread:-lpthread} %{profile:-lc_p} %{!profile: -lc}} + +*libgcc: +%{static|static-libgcc:-lgcc -lgcc_eh}%{!static:%{!static-libgcc:%{!shared:%{!shared-libgcc:-lgcc -lgcc_eh}%{shared-libgcc:-lgcc_s%M -lgcc}}%{shared:%{shared-libgcc:-lgcc_s%M}%{!shared-libgcc:-lgcc}}}} + +*startfile: +%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:%{profile:gcrt1.o%s} %{!profile:crt1.o%s}}}} crti.o%s %{static:crtbeginT.o%s} %{!static:%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}} + +*switches_need_spaces: + + +*predefines: + + +*cross_compile: +1 + +*version: +3.3.4 + +*multilib: +. ; + +*multilib_defaults: +EL mips1 mabi=32 + +*multilib_extra: + + +*multilib_matches: + + +*multilib_exclusions: + + +*multilib_options: + + +*linker: +collect2 + +*link_libgcc: +%D + +*md_exec_prefix: + + +*md_startfile_prefix: + + +*md_startfile_prefix_1: + + +*startfile_prefix_spec: + + +*subtarget_cc1_spec: + + +*subtarget_cpp_spec: +%{fno-PIC:-U__PIC__ -U__pic__} %{fno-pic:-U__PIC__ -U__pic__} %{fPIC:-D__PIC__ -D__pic__} %{fpic:-D__PIC__ -D__pic__} %{pthread:-D_REENTRANT} + +*mips_as_asm_spec: +%{!.s:-nocpp} %{.s: %{cpp} %{nocpp}} %{pipe: %e-pipe is not supported} %{K} %(subtarget_mips_as_asm_spec) + +*gas_asm_spec: +%{mtune=*} %{v} + +*target_asm_spec: +%{mmips-as: %(mips_as_asm_spec)} %{!mmips-as: %(gas_asm_spec)} + +*subtarget_mips_as_asm_spec: +%{v} + +*subtarget_asm_optimizing_spec: +%{noasmopt:-O0} %{!noasmopt:%{O:-O2} %{O1:-O2} %{O2:-O2} %{O3:-O3}} + +*subtarget_asm_debugging_spec: +-g0 + +*mdebug_asm_spec: +%{!gdwarf*:-mdebug} %{gdwarf*:-no-mdebug} + +*subtarget_asm_spec: +%{mabi=64: -64} %{!fno-PIC:%{!fno-pic:-KPIC}} %{fno-PIC:-non_shared} %{fno-pic:-non_shared} + +*asm_abi_default_spec: +-32 + +*endian_spec: +%{!EB:%{!meb:-EL}} %{EB|meb:-EB} + +*link_command: +%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S: %(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}} + diff --git a/misc/buildroot/toolchain/gcc/3.3.5/specs-powerpc-soft-float b/misc/buildroot/toolchain/gcc/3.3.5/specs-powerpc-soft-float new file mode 100644 index 000000000..8a546ac8e --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.5/specs-powerpc-soft-float @@ -0,0 +1,352 @@ +*asm: +%(asm_cpu) %{.s: %{mregnames} %{mno-regnames}} %{.S: %{mregnames} %{mno-regnames}} %{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} %{mrelocatable} %{mrelocatable-lib} %{fpic:-K PIC} %{fPIC:-K PIC} %{memb} %{!memb: %{msdata: -memb} %{msdata=eabi: -memb}} %{mlittle} %{mlittle-endian} %{mbig} %{mbig-endian} %{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: %{mcall-freebsd: -mbig} %{mcall-i960-old: -mlittle} %{mcall-linux: -mbig} %{mcall-gnu: -mbig} %{mcall-netbsd: -mbig} }}}} + +*asm_debug: +%{gstabs*:--gstabs}%{!gstabs*:%{g*:--gdwarf2}} + +*asm_final: +%| + +*asm_options: +%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O} + +*invoke_as: +%{!S:-o %{|!pipe:%g.s} | + as %(asm_options) %{!pipe:%g.s} %A } + +*cpp: +%{posix: -D_POSIX_SOURCE} %(cpp_sysv) %{mads: %(cpp_os_ads) } %{myellowknife: %(cpp_os_yellowknife) } %{mmvme: %(cpp_os_mvme) } %{msim: %(cpp_os_sim) } %{mwindiss: %(cpp_os_windiss) } %{mcall-freebsd: %(cpp_os_freebsd) } %{mcall-linux: %(cpp_os_linux) } %{mcall-gnu: %(cpp_os_gnu) } %{mcall-netbsd: %(cpp_os_netbsd) } %{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mwindiss: %{!mcall-freebsd: %{!mcall-linux: %{!mcall-gnu: %{!mcall-netbsd: %(cpp_os_default) }}}}}}}}} + +*cpp_options: +%(cpp_unique_options) %1 %{m*} %{std*} %{ansi} %{W*&pedantic*} %{w} %{f*} %{O*} %{undef} + +*cpp_debug_options: +%{d*} + +*cpp_unique_options: +%{C:%{!E:%eGNU C does not support -C without using -E}} %{CC:%{!E:%eGNU C does not support -CC without using -E}} %{!Q:-quiet} %{nostdinc*} %{C} %{CC} %{v} %{I*} %{P} %I %{MD:-MD %{!o:%b.d}%{o*:%.d%*}} %{MMD:-MMD %{!o:%b.d}%{o*:%.d%*}} %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{!E:%{!M:%{!MM:%{MD|MMD:%{o*:-MQ %*}}}}} %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3} %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs} %{remap} %{g3:-dD} %{H} %C %{D*&U*&A*} %{i*} %Z %i %{E|M|MM:%W{o*}} + +*trad_capable_cpp: +cc1 -E %{traditional|ftraditional|traditional-cpp:-traditional-cpp} + +*cc1: +%{G*} %{mlittle: %(cc1_endian_little)} %{!mlittle: %{mlittle-endian: %(cc1_endian_little)}} %{mbig: %(cc1_endian_big)} %{!mbig: %{mbig-endian: %(cc1_endian_big)}} %{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: %{mcall-aixdesc: -mbig %(cc1_endian_big) } %{mcall-freebsd: -mbig %(cc1_endian_big) } %{mcall-i960-old: -mlittle %(cc1_endian_little) } %{mcall-linux: -mbig %(cc1_endian_big) } %{mcall-gnu: -mbig %(cc1_endian_big) } %{mcall-netbsd: -mbig %(cc1_endian_big) } %{!mcall-aixdesc: %{!mcall-freebsd: %{!mcall-i960-old: %{!mcall-linux: %{!mcall-gnu: %{!mcall-netbsd: %(cc1_endian_default) }}}}}} }}}} %{mno-sdata: -msdata=none } %{meabi: %{!mcall-*: -mcall-sysv }} %{!meabi: %{!mno-eabi: %{mrelocatable: -meabi } %{mcall-freebsd: -mno-eabi } %{mcall-i960-old: -meabi } %{mcall-linux: -mno-eabi } %{mcall-gnu: -mno-eabi } %{mcall-netbsd: -mno-eabi }}} %{msdata: -msdata=default} %{mno-sdata: -msdata=none} %{profile: -p} + +*cc1_options: +%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}} %1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*} %{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}%{!c:%{!S:-auxbase %b}} %{g*} %{O*} %{W*&pedantic*} %{w} %{std*} %{ansi} %{v:-version} %{pg:-p} %{p} %{f*} %{undef} %{Qn:-fno-ident} %{--help:--help} %{--target-help:--target-help} %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}} %{fsyntax-only:-o %j} %{-param*} %{msoft-float:%{mhard-float: %e-msoft-float and -mhard_float may not be used together}} %{!mhard-float:%{!msoft-float:-msoft-float}} + +*cc1plus: + + +*link_gcc_c_sequence: +%{static:--start-group} %G %L %{static:--end-group}%{!static:%G} + +*endfile: +%{mads: crtsavres.o%s %(endfile_ads)} %{myellowknife: crtsavres.o%s %(endfile_yellowknife)} %{mmvme: crtsavres.o%s %(endfile_mvme)} %{msim: crtsavres.o%s %(endfile_sim)} %{mwindiss: %(endfile_windiss)} %{mcall-freebsd: crtsavres.o%s %(endfile_freebsd) } %{mcall-linux: crtsavres.o%s %(endfile_linux) } %{mcall-gnu: crtsavres.o%s %(endfile_gnu) } %{mcall-netbsd: crtsavres.o%s %(endfile_netbsd) } %{mvxworks: crtsavres.o%s %(endfile_vxworks) } %{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mwindiss: %{!mcall-freebsd: %{!mcall-linux: %{!mcall-gnu: %{!mcall-netbsd: %{!mvxworks: %(crtsavres_default) %(endfile_default) }}}}}}}}}} + +*link: +%{!static:--eh-frame-hdr} %{h*} %{v:-V} %{!msdata=none:%{G*}} %{msdata=none:-G0} %{YP,*} %{R*} %{Qy:} %{!Qn:-Qy} %(link_shlib) %{!Wl,-T*: %{!T*: %(link_start) }} %(link_target) %(link_os) + +*lib: +%{mads: %(lib_ads) } %{myellowknife: %(lib_yellowknife) } %{mmvme: %(lib_mvme) } %{msim: %(lib_sim) } %{mwindiss: %(lib_windiss) } %{mcall-freebsd: %(lib_freebsd) } %{mcall-linux: %(lib_linux) } %{mcall-gnu: %(lib_gnu) } %{mcall-netbsd: %(lib_netbsd) } %{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mwindiss: %{!mcall-freebsd: %{!mcall-linux: %{!mcall-gnu: %{!mcall-netbsd: %(lib_default) }}}}}}}}} + +*libgcc: +%{static|static-libgcc:-lgcc -lgcc_eh}%{!static:%{!static-libgcc:%{!shared:%{!shared-libgcc:-lgcc -lgcc_eh}%{shared-libgcc:-lgcc_s%M -lgcc}}%{shared:%{shared-libgcc:-lgcc_s%M}%{!shared-libgcc:-lgcc}}}} + +*startfile: +%{mads: %(startfile_ads) } %{myellowknife: %(startfile_yellowknife) } %{mmvme: %(startfile_mvme) } %{msim: %(startfile_sim) } %{mwindiss: %(startfile_windiss) } %{mcall-freebsd: %(startfile_freebsd) } %{mcall-linux: %(startfile_linux) } %{mcall-gnu: %(startfile_gnu) } %{mcall-netbsd: %(startfile_netbsd) } %{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mwindiss: %{!mcall-freebsd: %{!mcall-linux: %{!mcall-gnu: %{!mcall-netbsd: %(startfile_default) }}}}}}}}} + +*switches_need_spaces: + + +*predefines: + + +*cross_compile: +1 + +*version: +3.3.4 + +*multilib: +. mhard-float;nof !mhard-float; + +*multilib_defaults: +mbig mcall-sysv + +*multilib_extra: +fPIC mstrict-align + +*multilib_matches: +mcpu=401 msoft-float;mcpu=403 msoft-float;mcpu=405 msoft-float;mcpu=ec603e msoft-float;mcpu=801 msoft-float;mcpu=821 msoft-float;mcpu=823 msoft-float;mcpu=860 msoft-float;msoft-float msoft-float; + +*multilib_exclusions: + + +*multilib_options: +msoft-float + +*linker: +collect2 + +*link_libgcc: +%D + +*md_exec_prefix: + + +*md_startfile_prefix: + + +*md_startfile_prefix_1: + + +*startfile_prefix_spec: + + +*cpp_default: + + +*asm_cpu: +%{!mcpu*: %{mpower: %{!mpower2: -mpwr}} %{mpower2: -mpwrx} %{mpowerpc*: -mppc} %{mno-power: %{!mpowerpc*: -mcom}} %{!mno-power: %{!mpower2: %(asm_default)}}} %{mcpu=common: -mcom} %{mcpu=power: -mpwr} %{mcpu=power2: -mpwrx} %{mcpu=power3: -m604} %{mcpu=power4: -mpower4} %{mcpu=powerpc: -mppc} %{mcpu=rios: -mpwr} %{mcpu=rios1: -mpwr} %{mcpu=rios2: -mpwrx} %{mcpu=rsc: -mpwr} %{mcpu=rsc1: -mpwr} %{mcpu=401: -mppc} %{mcpu=403: -m403} %{mcpu=405: -m405} %{mcpu=505: -mppc} %{mcpu=601: -m601} %{mcpu=602: -mppc} %{mcpu=603: -mppc} %{mcpu=603e: -mppc} %{mcpu=ec603e: -mppc} %{mcpu=604: -mppc} %{mcpu=604e: -mppc} %{mcpu=620: -mppc} %{mcpu=630: -m604} %{mcpu=740: -mppc} %{mcpu=7400: -mppc} %{mcpu=7450: -mppc} %{mcpu=750: -mppc} %{mcpu=801: -mppc} %{mcpu=821: -mppc} %{mcpu=823: -mppc} %{mcpu=860: -mppc} %{mcpu=8540: -me500} %{maltivec: -maltivec} + +*asm_default: +-mppc + +*cpp_sysv: +%{mrelocatable*: -D_RELOCATABLE} %{fpic: -D__PIC__=1 -D__pic__=1} %{!fpic: %{fPIC: -D__PIC__=2 -D__pic__=2}} + +*crtsavres_default: +crtsavres.o%s + +*lib_ads: +--start-group -lads -lc --end-group + +*lib_yellowknife: +--start-group -lyk -lc --end-group + +*lib_mvme: +--start-group -lmvme -lc --end-group + +*lib_sim: +--start-group -lsim -lc --end-group + +*lib_freebsd: + %{!shared: %{!pg: %{!pthread:-lc} %{pthread:-lc_r}} %{pg: %{!pthread:-lc_p} %{pthread:-lc_r_p}} } + +*lib_gnu: +%{mnewlib: --start-group -lgnu -lc --end-group } %{!mnewlib: %{shared:-lc} %{!shared: %{pthread:-lpthread } %{profile:-lc_p} %{!profile:-lc}}} + +*lib_linux: +%{mnewlib: --start-group -llinux -lc --end-group } %{!mnewlib: %{pthread:-lpthread} %{shared:-lc} %{!shared: %{profile:-lc_p} %{!profile:-lc}}} + +*lib_netbsd: +%{profile:-lgmon -lc_p} %{!profile:-lc} + +*lib_vxworks: + + +*lib_windiss: +--start-group -li -lcfp -lwindiss -lram -limpl -limpfp --end-group + +*lib_default: +%(lib_linux) + +*startfile_ads: +ecrti.o%s crt0.o%s crtbegin.o%s + +*startfile_yellowknife: +ecrti.o%s crt0.o%s crtbegin.o%s + +*startfile_mvme: +ecrti.o%s crt0.o%s crtbegin.o%s + +*startfile_sim: +ecrti.o%s sim-crt0.o%s crtbegin.o%s + +*startfile_freebsd: +%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:%{profile:gcrt1.o%s} %{!profile:crt1.o%s}}}} crti.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s} + +*startfile_gnu: +%{!shared: %{!static: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}}} %{static: %{pg:gcrt0.o%s} %{!pg:%{p:gcrt0.o%s} %{!p:crt0.o%s}}} %{mnewlib: ecrti.o%s} %{!mnewlib: crti.o%s} %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s} + +*startfile_linux: +%{!shared: %{pg:gcrt1.o%s} %{!pg:%{p:gcrt1.o%s} %{!p:crt1.o%s}}} %{mnewlib: ecrti.o%s} %{!mnewlib: crti.o%s} %{static:crtbeginT.o%s} %{!static:%{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s}} + +*startfile_netbsd: +ncrti.o%s crt0.o%s %{!shared:crtbegin.o%s} %{shared:crtbeginS.o%s} + +*startfile_vxworks: + + +*startfile_windiss: +crt0.o%s crtbegin.o%s + +*startfile_default: +%(startfile_linux) + +*endfile_ads: +crtend.o%s ecrtn.o%s + +*endfile_yellowknife: +crtend.o%s ecrtn.o%s + +*endfile_mvme: +crtend.o%s ecrtn.o%s + +*endfile_sim: +crtend.o%s ecrtn.o%s + +*endfile_freebsd: +%{!shared:crtend.o%s} %{shared:crtendS.o%s} crtn.o%s + +*endfile_gnu: +%{!shared:crtend.o%s} %{shared:crtendS.o%s} %{mnewlib: ecrtn.o%s} %{!mnewlib: crtn.o%s} + +*endfile_linux: +%{!shared:crtend.o%s} %{shared:crtendS.o%s} %{mnewlib: ecrtn.o%s} %{!mnewlib: crtn.o%s} + +*endfile_netbsd: +%{!shared:crtend.o%s} %{shared:crtendS.o%s} ncrtn.o%s + +*endfile_vxworks: + + +*endfile_windiss: +crtend.o%s + +*endfile_default: +%(endfile_linux) + +*link_path: + + +*link_shlib: +%{shared:-shared} %{!shared: %{static:-static}} + +*link_target: +%{mlittle: --oformat elf32-powerpcle } %{mlittle-endian: --oformat elf32-powerpcle } %{!mlittle: %{!mlittle-endian: %{!mbig: %{!mbig-endian: %{mcall-i960-old: --oformat elf32-powerpcle} }}}} + +*link_start: +%{mads: %(link_start_ads) } %{myellowknife: %(link_start_yellowknife) } %{mmvme: %(link_start_mvme) } %{msim: %(link_start_sim) } %{mwindiss: %(link_start_windiss) } %{mcall-freebsd: %(link_start_freebsd) } %{mcall-linux: %(link_start_linux) } %{mcall-gnu: %(link_start_gnu) } %{mcall-netbsd: %(link_start_netbsd) } %{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mwindiss: %{!mcall-linux: %{!mcall-gnu: %{!mcall-netbsd: %{!mcall-freebsd: %(link_start_default) }}}}}}}}} + +*link_start_ads: +-T ads.ld%s + +*link_start_yellowknife: +-T yellowknife.ld%s + +*link_start_mvme: +-Ttext 0x40000 + +*link_start_sim: + + +*link_start_freebsd: + + +*link_start_gnu: + + +*link_start_linux: + + +*link_start_netbsd: + + +*link_start_vxworks: + + +*link_start_windiss: + + +*link_start_default: +%(link_start_linux) + +*link_os: +%{mads: %(link_os_ads) } %{myellowknife: %(link_os_yellowknife) } %{mmvme: %(link_os_mvme) } %{msim: %(link_os_sim) } %{mwindiss: %(link_os_windiss) } %{mcall-freebsd: %(link_os_freebsd) } %{mcall-linux: %(link_os_linux) } %{mcall-gnu: %(link_os_gnu) } %{mcall-netbsd: %(link_os_netbsd) } %{mcall-uclibc: %(link_os_linux_uclibc) } %{!mads: %{!myellowknife: %{!mmvme: %{!msim: %{!mwindiss: %{!mcall-freebsd: %{!mcall-linux: %{!mcall-gnu: %{!mcall-netbsd: %{!mcall-uclibc: %(link_os_default) }}}}}}}}}} + +*link_os_ads: + + +*link_os_yellowknife: + + +*link_os_mvme: + + +*link_os_sim: +-m elf32ppcsim + +*link_os_freebsd: + %{p:%e`-p' not supported; use `-pg' and gprof(1)} %{Wl,*:%*} %{v:-V} %{assert*} %{R*} %{rpath*} %{defsym*} %{shared:-Bshareable %{h*} %{soname*}} %{!shared: %{!static: %{rdynamic: -export-dynamic} %{!dynamic-linker: -dynamic-linker /usr/libexec/ld-elf.so.1}} %{static:-Bstatic}} %{symbolic:-Bsymbolic} + +*link_os_linux: +-m elf32ppclinux %{!shared: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld.so.1}}} + +*link_os_gnu: +-m elf32ppclinux %{!shared: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld.so.1}}} + +*link_os_netbsd: +%{!shared: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /usr/libexec/ld.elf_so}}} + +*link_os_vxworks: +-r + +*link_os_windiss: + + +*link_os_linux_uclibc: +-m elf32ppclinux %{!shared: %{!static: %{rdynamic:-export-dynamic} %{!dynamic-linker:-dynamic-linker /lib/ld-uClibc.so.0}}} + +*link_os_default: +%(link_os_linux_uclibc) + +*cc1_endian_big: + + +*cc1_endian_little: +%{!mstrict-align: %{!mno-strict-align: %{!mcall-i960-old: -mstrict-align } }} + +*cc1_endian_default: +%(cc1_endian_big) + +*cpp_os_ads: + + +*cpp_os_yellowknife: + + +*cpp_os_mvme: + + +*cpp_os_sim: + + +*cpp_os_freebsd: + -D__ELF__ -D__PPC__ -D__ppc__ -D__PowerPC__ -D__powerpc__ -Acpu=powerpc -Amachine=powerpc + +*cpp_os_gnu: +-D__unix__ -D__gnu_hurd__ -D__GNU__ %{!undef: %{!ansi: -Dunix -D__unix}} -Asystem=gnu -Asystem=unix -Asystem=posix %{pthread:-D_REENTRANT} + +*cpp_os_linux: +-D__unix__ -D__gnu_linux__ -D__linux__ %{!undef: %{!ansi: %{!std=*:-Dunix -D__unix -Dlinux -D__linux} %{std=gnu*:-Dunix -D__unix -Dlinux -D__linux}}} -Asystem=unix -Asystem=posix %{pthread:-D_REENTRANT} + +*cpp_os_netbsd: +-D__powerpc__ -D__NetBSD__ -D__ELF__ -D__KPRINTF_ATTRIBUTE__ + +*cpp_os_rtems: +%{!mcpu*: %{!Dppc*: %{!Dmpc*: -Dmpc750} } }%{mcpu=403: %{!Dppc*: %{!Dmpc*: -Dppc403} } } %{mcpu=505: %{!Dppc*: %{!Dmpc*: -Dmpc505} } } %{mcpu=601: %{!Dppc*: %{!Dmpc*: -Dppc601} } } %{mcpu=602: %{!Dppc*: %{!Dmpc*: -Dppc602} } } %{mcpu=603: %{!Dppc*: %{!Dmpc*: -Dppc603} } } %{mcpu=603e: %{!Dppc*: %{!Dmpc*: -Dppc603e} } } %{mcpu=604: %{!Dppc*: %{!Dmpc*: -Dmpc604} } } %{mcpu=750: %{!Dppc*: %{!Dmpc*: -Dmpc750} } } %{mcpu=821: %{!Dppc*: %{!Dmpc*: -Dmpc821} } } %{mcpu=860: %{!Dppc*: %{!Dmpc*: -Dmpc860} } } + +*cpp_os_vxworks: +-DCPU_FAMILY=PPC %{!mcpu*: %{mpowerpc*: -DCPU=PPC603} %{!mno-powerpc: -DCPU=PPC603}} %{mcpu=powerpc: -DCPU=PPC603} %{mcpu=401: -DCPU=PPC403} %{mcpu=403: -DCPU=PPC403} %{mcpu=405: -DCPU=PPC405} %{mcpu=601: -DCPU=PPC601} %{mcpu=602: -DCPU=PPC603} %{mcpu=603: -DCPU=PPC603} %{mcpu=603e: -DCPU=PPC603} %{mcpu=ec603e: -DCPU=PPC603} %{mcpu=604: -DCPU=PPC604} %{mcpu=604e: -DCPU=PPC604} %{mcpu=620: -DCPU=PPC604} %{mcpu=740: -DCPU=PPC603} %{mcpu=7450: -DCPU=PPC603} %{mcpu=750: -DCPU=PPC603} %{mcpu=801: -DCPU=PPC603} %{mcpu=821: -DCPU=PPC603} %{mcpu=823: -DCPU=PPC603} %{mcpu=860: -DCPU=PPC603} + +*cpp_os_windiss: +-D__rtasim -D__EABI__ -D__ppc %{!msoft-float: -D__hardfp} + +*cpp_os_default: +%(cpp_os_linux) + +*link_command: +%{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S: %(linker) %l %X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r} %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}} %{static:} %{L*} %(link_libgcc) %o %{!nostdlib:%{!nodefaultlibs:%(link_gcc_c_sequence)}} %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}} + diff --git a/misc/buildroot/toolchain/gcc/3.3.6/120-softfloat.patch b/misc/buildroot/toolchain/gcc/3.3.6/120-softfloat.patch new file mode 100644 index 000000000..f2431896c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.6/120-softfloat.patch @@ -0,0 +1,14 @@ +--- gcc-3.3.2-old/configure.in 2003-08-09 01:57:21.000000000 -0500 ++++ gcc-3.3.2/configure.in 2004-01-15 12:46:29.000000000 -0600 +@@ -1418,6 +1418,11 @@ + fi + + FLAGS_FOR_TARGET= ++case " $targargs " in ++ *" --nfp "* | *" --without-float "*) ++ FLAGS_FOR_TARGET=$FLAGS_FOR_TARGET' -msoft-float' ++ ;; ++esac + case " $target_configdirs " in + *" newlib "*) + case " $targargs " in diff --git a/misc/buildroot/toolchain/gcc/3.3.6/500-loop.patch b/misc/buildroot/toolchain/gcc/3.3.6/500-loop.patch new file mode 100644 index 000000000..476f84b37 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.6/500-loop.patch @@ -0,0 +1,10 @@ +--- gcc/gcc/loop.c 14 Feb 2004 14:46:03 -0000 1.488.2.3 ++++ gcc/gcc/loop.c 28 Apr 2004 22:02:53 -0000 +@@ -929,6 +929,7 @@ + || (! (GET_CODE (SET_SRC (set)) == REG + && (REGNO (SET_SRC (set)) + < FIRST_PSEUDO_REGISTER)))) ++ && regno >= FIRST_PSEUDO_REGISTER + /* This test is not redundant; SET_SRC (set) might be + a call-clobbered register and the life of REGNO + might span a call. */ diff --git a/misc/buildroot/toolchain/gcc/3.3.6/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/3.3.6/800-arm-bigendian.patch new file mode 100644 index 000000000..79140ddf0 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.6/800-arm-bigendian.patch @@ -0,0 +1,68 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-3.3.5-dist/gcc/config/arm/linux-elf.h ++++ gcc-3.3.5/gcc/config/arm/linux-elf.h +@@ -30,17 +30,34 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + /* Default is to use APCS-32 mode. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 | \ ++ ARM_FLAG_MMU_TRAPS | \ ++ TARGET_ENDIAN_DEFAULT ) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -100,7 +117,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + #endif + +--- gcc-3.3.5-dist/gcc/config.gcc ++++ gcc-3.3.5/gcc/config.gcc +@@ -710,6 +710,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="t-slibgcc-elf-ver t-linux arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/3.3.6/810-mips-xgot.patch b/misc/buildroot/toolchain/gcc/3.3.6/810-mips-xgot.patch new file mode 100644 index 000000000..d7d6691ef --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.6/810-mips-xgot.patch @@ -0,0 +1,6 @@ +--- gcc.orig/gcc/config/mips/t-linux 1970-01-01 01:00:00.000000000 +0100 ++++ gcc/gcc/config/mips/t-linux 2004-08-26 18:28:12.000000000 +0200 +@@ -0,0 +1,3 @@ ++# Compile crtbegin/end with xgot so it works for both ++# normal and large GOTs. ++CRTSTUFF_T_CFLAGS = -Wa,-xgot diff --git a/misc/buildroot/toolchain/gcc/3.3.6/820-no-mips-empic-relocs.patch b/misc/buildroot/toolchain/gcc/3.3.6/820-no-mips-empic-relocs.patch new file mode 100644 index 000000000..d5c4c9cb5 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.6/820-no-mips-empic-relocs.patch @@ -0,0 +1,59 @@ +From: cgd at broadcom dot com +To: gcc-patches at gcc dot gnu dot org +Cc: mark at codesourcery dot com +Date: 13 Jun 2004 22:51:30 -0700 +Subject: [trunk + 3.4-branch RFA] don't use empic relocs for mips-linuxeh + +This patch changes mips-linux to avoid using embedded-pic relocs for +its eh data. (Support for generating these for new code is removed in +current binutils srcs.) + +Relating to this, previously, mips-linux and mips64-linux would use +different representations for their EH data (even for mips64-linux o32 +abi), due to the mips64-linux n32/64 BFDs not supporting the +embedded-pic relocs. This was a bug. + +For more explanation, see the thread of the URL quoted in the comment +in linux.h. + + +Tested the same w/ sources of about a week ago for c/c++ for +mips-linux (native) before/after. Also verified .o compatibility +before/after just to be sure. + +I'd like this approved for the branch as well, so 3.4.1 will work +nicely w/ the next major binutils release. + + +thanks, + +chris + +2004-06-13 Chris Demetriou + + * config/mips/linux.h (ASM_PREFERRED_EH_DATA_FORMAT): Redefine + to return DW_EH_PE_absptr. + +Index: config/mips/linux.h +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/mips/linux.h,v +retrieving revision 1.77 +diff -u -p -r1.77 linux.h +--- gcc/gcc/config/mips/linux.h 19 Feb 2004 22:07:51 -0000 1.77 ++++ gcc/gcc/config/mips/linux.h 14 Jun 2004 05:49:51 -0000 +@@ -170,10 +170,11 @@ Boston, MA 02111-1307, USA. */ + #undef FUNCTION_NAME_ALREADY_DECLARED + #define FUNCTION_NAME_ALREADY_DECLARED 1 + +-#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) \ +- (flag_pic \ +- ? ((GLOBAL) ? DW_EH_PE_indirect : 0) | DW_EH_PE_pcrel | DW_EH_PE_sdata4\ +- : DW_EH_PE_absptr) ++/* If possible, we should attempt to use GP-relative relocs for this ++ (see http://sources.redhat.com/ml/binutils/2004-05/msg00227.html). ++ However, until that is implement, this just uses standard, absolute ++ references. */ ++#define ASM_PREFERRED_EH_DATA_FORMAT(CODE, GLOBAL) DW_EH_PE_absptr + + /* The glibc _mcount stub will save $v0 for us. Don't mess with saving + it, since ASM_OUTPUT_REG_PUSH/ASM_OUTPUT_REG_POP do not work in the diff --git a/misc/buildroot/toolchain/gcc/3.3.6/830-gcc-bug-num-22167.patch b/misc/buildroot/toolchain/gcc/3.3.6/830-gcc-bug-num-22167.patch new file mode 100644 index 000000000..c7419af90 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.3.6/830-gcc-bug-num-22167.patch @@ -0,0 +1,16 @@ +Index: gcc/gcse.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gcse.c,v +retrieving revision 1.288.2.9 +diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.288.2.9 gcse.c +--- gcc/gcc/gcse.c 30 Oct 2004 18:02:53 -0000 1.288.2.9 ++++ gcc/gcc/gcse.c 14 Jul 2005 13:19:57 -0000 +@@ -6445,7 +6445,7 @@ hoist_code (void) + insn_inserted_p = 0; + + /* These tests should be the same as the tests above. */ +- if (TEST_BIT (hoist_vbeout[bb->index], i)) ++ if (TEST_BIT (hoist_exprs[bb->index], i)) + { + /* We've found a potentially hoistable expression, now + we look at every block BB dominates to see if it diff --git a/misc/buildroot/toolchain/gcc/3.4.2/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/3.4.2/300-libstdc++-pic.patch new file mode 100644 index 000000000..9f304a4c4 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/300-libstdc++-pic.patch @@ -0,0 +1,47 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -224,6 +224,10 @@ + @OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCPP_BUILD_DEBUG + all-local: build_debug + +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -585,7 +585,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -618,6 +618,7 @@ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-data-local \ + install-exec install-exec-am install-info install-info-am \ ++ install-exec-local \ + install-man install-strip install-toolexeclibLTLIBRARIES \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ +@@ -707,6 +708,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/3.4.2/300-pr15526.patch b/misc/buildroot/toolchain/gcc/3.4.2/300-pr15526.patch new file mode 100644 index 000000000..f01c59f11 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/300-pr15526.patch @@ -0,0 +1,53 @@ +# DP: 2004-09-26 Roger Sayle +# DP: +# DP: PR other/15526 +# DP: Backport from mainline +# DP: 2004-05-20 Falk Hueffner +# DP: * libgcc2.c (__mulvsi3): Fix overflow test. + +diff -u -r1.170.6.1 -r1.170.6.2 +--- gcc/gcc/libgcc2.c 2004/07/17 21:18:47 1.170.6.1 ++++ gcc/gcc/libgcc2.c 2004/09/26 20:47:14 1.170.6.2 +@@ -130,9 +130,7 @@ + { + const DWtype w = (DWtype) a * (DWtype) b; + +- if (((a >= 0) == (b >= 0)) +- ? (UDWtype) w > (UDWtype) (((DWtype) 1 << (WORD_SIZE - 1)) - 1) +- : (UDWtype) w < (UDWtype) ((DWtype) -1 << (WORD_SIZE - 1))) ++ if ((Wtype) (w >> WORD_SIZE) != (Wtype) w >> (WORD_SIZE - 1)) + abort (); + + return w; + +/cvs/gcc/gcc/gcc/testsuite/gcc.dg/ftrapv-1.c,v --> standard output +revision 1.1.22.1 +--- gcc/gcc/testsuite/gcc.dg/ftrapv-1.c ++++ /dev/null 2004-10-15 06:22:06.980596000 +0000 +@@ -0,0 +1,25 @@ ++/* Copyright (C) 2004 Free Software Foundation. ++ ++ PR other/15526 ++ Verify correct overflow checking with -ftrapv. ++ ++ Written by Falk Hueffner, 20th May 2004. */ ++ ++/* { dg-do run } */ ++/* { dg-options "-ftrapv" } */ ++ ++__attribute__((noinline)) int ++mulv(int a, int b) ++{ ++ return a * b; ++} ++ ++int ++main() ++{ ++ mulv( 0, 0); ++ mulv( 0, -1); ++ mulv(-1, 0); ++ mulv(-1, -1); ++ return 0; ++} + diff --git a/misc/buildroot/toolchain/gcc/3.4.2/300-pr17541.patch b/misc/buildroot/toolchain/gcc/3.4.2/300-pr17541.patch new file mode 100644 index 000000000..ca5fa09ab --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/300-pr17541.patch @@ -0,0 +1,234 @@ +# DP: 2004-09-21 Bud Davis +# DP: +# DP: PR fortran/17541 +# DP: * bld.c (ffebld_constant_new_real2_val): Fix typo, +# DP: +# DP: PR fortran/17541 +# DP: * g77.f-torture/execute/pr17541.f: New test. + +Index: gcc/gcc/f/bld.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/f/Attic/bld.c,v +retrieving revision 1.16.14.1 +retrieving revision 1.16.14.2 +diff -u -r1.16.14.1 -r1.16.14.2 +--- gcc/gcc/f/bld.c 12 Jul 2004 17:58:36 -0000 1.16.14.1 ++++ gcc/gcc/f/bld.c 21 Sep 2004 12:54:27 -0000 1.16.14.2 +@@ -1333,7 +1333,7 @@ + nc = malloc_new_kp (ffebld_constant_pool(), + "FFEBLD_constREAL2", + sizeof (*nc)); +- nc->consttype = FFEBLD_constREAL1; ++ nc->consttype = FFEBLD_constREAL2; + nc->u.real2 = val; + nc->hook = FFECOM_constantNULL; + nc->llink = NULL; +Index: gcc/gcc/testsuite/g77.f-torture/execute/pr17541.f +=================================================================== +RCS file: gcc/gcc/testsuite/g77.f-torture/execute/pr17541.f +diff -N gcc/gcc/testsuite/g77.f-torture/execute/pr17541.f +--- /dev/null 1 Jan 1970 00:00:00 -0000 ++++ gcc/gcc/testsuite/g77.f-torture/execute/pr17541.f 21 Sep 2004 12:54:35 -0000 1.1.2.1 +@@ -0,0 +1,202 @@ ++ program test ++ implicit none ++! check all types of data statements ++! pr 17541 ++ real r(2) ++ double precision s(2) ++ integer*1 ib(2) ++ integer*2 ih(2) ++ integer*4 iw(2) ++ integer*8 id(3) ++ logical*1 lb(2) ++ logical*2 lh(2) ++ logical*4 lw(2) ++ logical*8 ld(2) ++ character*1 a(2) ++ character*5 b(2) ++ complex c1(2) ++ complex*8 c2(2) ++ data r / 1.0,2.0 / ++ data s / 2.d0,1.d0/ ++ data ib / 1,-1 / ++ data ih / 2,100/ ++ data iw / 4,3560000 / ++ data id / 8,Z'ABCDEF01',Z'5555AAAA' / ++ data a / 'a', 'z' / ++ data b / 'xyz','abc'/ ++ data c1 /(1.0,2.0),(-1.0,-2.0)/ ++ data c2 /(1.d0,2.d0),(-1.d0,-2.d0)/ ++ data lb / .TRUE.,.FALSE. / ++ data lh / .TRUE.,.FALSE. / ++ data lw / .TRUE.,.FALSE. / ++ data ld / .TRUE.,.FALSE. / ++ logical dbug ++ data dbug /.FALSE./ ++! check the reals first ++ if (r(1).ne.1.0) then ++ if (dbug) then ++ print*,r(1), ' should be 1.0 ' ++ else ++ call abort ++ endif ++ endif ++ if (r(2).ne.2.0) then ++ if (dbug) then ++ print*,r(2), ' should be 2.0 ' ++ else ++ call abort ++ endif ++ endif ++ if (s(1).ne.2.d0) then ++ if (dbug) then ++ print*,s(1), ' xxshould be 2.d0 ' ++ else ++ call abort ++ endif ++ endif ++ if (s(2).ne.1.d0) then ++ if (dbug) then ++ print*,s(2), ' should be 1.d0 ' ++ else ++ call abort ++ endif ++ endif ++! now the integers ++ if (ib(1).ne.1) then ++ if (dbug) then ++ print*,ib(1), ' should be 1 ' ++ else ++ call abort ++ endif ++ endif ++ if (ib(2).ne.-1) then ++ if (dbug) then ++ print*,ib(2), ' should be -1 ' ++ else ++ call abort ++ endif ++ endif ++ if (ih(1).ne.2) then ++ if (dbug) then ++ print*,ih(2), ' should be 2 ' ++ else ++ call abort ++ endif ++ endif ++ if (ih(2).ne.100) then ++ if (dbug) then ++ print*,ih(2), ' should be 100 ' ++ else ++ call abort ++ endif ++ endif ++ if (iw(1).ne.4) then ++ if (dbug) then ++ print*,iw(1), ' should be 4 ' ++ else ++ call abort ++ endif ++ endif ++ if (iw(2).ne.3560000) then ++ if (dbug) then ++ print*,iw(2), ' should be 3560000 ' ++ else ++ call abort ++ endif ++ endif ++ if (id(1).ne.8) then ++ if (dbug) print*,id(1), ' should be 8 ' ++ call abort ++ endif ++ if (id(2).ne.Z'ABCDEF01') then ++ if (dbug) print*,id(2), " should be Z'ABCDEF01' " ++ call abort ++ endif ++ if (id(3).ne.Z'5555AAAA') then ++ if (dbug) print*,id(2), " should be Z'5555AAAA' " ++ call abort ++ endif ++! complex ++ if (c1(1).ne.(1.0,2.0)) then ++ if (dbug) then ++ print*,c1(1), ' should be (1.0,2.0) ' ++ else ++ call abort ++ endif ++ endif ++ if (c1(2).ne.(-1.0,-2.0)) then ++ if (dbug) then ++ print*,c1(2), ' should be (-1.0,-2.0) ' ++ else ++ call abort ++ endif ++ endif ++ if (c2(1).ne.(1.d0,2.d0)) then ++ if (dbug) then ++ print*,c2(1), ' should be (1.0,2.0) ' ++ else ++ call abort ++ endif ++ endif ++ if (c2(2).ne.(-1.d0,-2.d0)) then ++ if (dbug) then ++ print*,c2(2), ' should be (-1.0,-2.0) ' ++ else ++ call abort ++ endif ++ endif ++! character ++ if (a(1).ne.'a') then ++ if (dbug) then ++ print*,a(1), ' should be a ' ++ else ++ call abort ++ endif ++ endif ++ if (b(1).ne.'xyz') then ++ if (dbug) then ++ print*,b(1), ' should be xyz ' ++ else ++ call abort ++ endif ++ endif ++!logicals ++ if (.NOT.lb(1)) then ++ if (dbug) print*,lb(1), ' should be .T. ' ++ call abort ++ endif ++ if (lb(2)) then ++ if (dbug) print*,lb(2), ' should be .F. ' ++ call abort ++ endif ++ if (.NOT.lh(1)) then ++ if (dbug) print*,lh(1), ' should be .T. ' ++ call abort ++ endif ++ if (lh(2)) then ++ if (dbug) print*,lh(2), ' should be .F. ' ++ call abort ++ endif ++ if (.NOT.lw(1)) then ++ if (dbug) print*,lw(1), ' should be .T. ' ++ call abort ++ endif ++ if (lw(2)) then ++ if (dbug) print*,lw(2), ' should be .F. ' ++ call abort ++ endif ++ if (.NOT.ld(1)) then ++ if (dbug) then ++ print*,ld(1), ' should be .T. ' ++ else ++ call abort ++ endif ++ endif ++ if (ld(2)) then ++ if (dbug) then ++ print*,ld(2), ' should be .F. ' ++ else ++ call abort ++ endif ++ endif ++ end diff --git a/misc/buildroot/toolchain/gcc/3.4.2/300-pr17976.patch b/misc/buildroot/toolchain/gcc/3.4.2/300-pr17976.patch new file mode 100644 index 000000000..78bb3559f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/300-pr17976.patch @@ -0,0 +1,106 @@ +From: Mark Mitchell +Sender: gcc-patches-owner@gcc.gnu.org +To: gcc-patches@gcc.gnu.org +Subject: C++ PATCH: PR 17976 +Date: Thu, 14 Oct 2004 21:24:41 -0700 + + +This was a case where we generated multiple destructor calls for the +same global variable, in the (probably rare) situation that an +"extern" declaration followed the definition. + +Tested on i686-pc-linux-gnu, applied on the mainline and on the 3.4 +branch. + +-- +Mark Mitchell +CodeSourcery, LLC +mark@codesourcery.com + +# DP: 2004-10-14 Mark Mitchell +# DP: +# DP: PR c++/17976 +# DP: * decl.c (cp_finish_decl): Do not call expand_static_init more +# DP: than once for a single variable. +# DP: +# DP: 2004-10-14 Mark Mitchell +# DP: +# DP: PR c++/17976 +# DP: * g++.dg/init/dtor3.C: New test. + +Index: testsuite/g++.dg/init/dtor3.C +=================================================================== +RCS file: testsuite/g++.dg/init/dtor3.C +diff -N testsuite/g++.dg/init/dtor3.C +*** /dev/null 1 Jan 1970 00:00:00 -0000 +--- gcc/gcc/testsuite/g++.dg/init/dtor3.C 15 Oct 2004 04:02:22 -0000 +*************** +*** 0 **** +--- 1,21 ---- ++ // PR c++/17976 ++ // { dg-do run } ++ ++ extern "C" void abort(); ++ struct A ++ { ++ static int i; ++ A(){} ++ ~A(){i++;if(i>1)abort();} ++ }; ++ ++ int A::i = 0; ++ ++ A a; ++ extern A a; ++ ++ int main() ++ { ++ return 0; ++ } ++ +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v +retrieving revision 1.1174.2.26 +retrieving revision 1.1174.2.27 +diff -u -r1.1174.2.26 -r1.1174.2.27 +--- gcc/gcc/cp/decl.c 2004/10/10 21:54:59 1.1174.2.26 ++++ gcc/gcc/cp/decl.c 2004/10/15 04:23:46 1.1174.2.27 +@@ -4778,6 +4778,7 @@ + tree cleanup; + const char *asmspec = NULL; + int was_readonly = 0; ++ bool var_definition_p = false; + + if (decl == error_mark_node) + return; +@@ -4930,6 +4931,11 @@ + /* Remember that the initialization for this variable has + taken place. */ + DECL_INITIALIZED_P (decl) = 1; ++ /* This declaration is the definition of this variable, ++ unless we are initializing a static data member within ++ the class specifier. */ ++ if (!DECL_EXTERNAL (decl)) ++ var_definition_p = true; + } + /* If the variable has an array type, lay out the type, even if + there is no initializer. It is valid to index through the +@@ -5004,8 +5010,16 @@ + initialize_local_var (decl, init); + } + +- if (TREE_STATIC (decl)) +- expand_static_init (decl, init); ++ /* If a variable is defined, and then a subsequent ++ definintion with external linkage is encountered, we will ++ get here twice for the same variable. We want to avoid ++ calling expand_static_init more than once. For variables ++ that are not static data members, we can call ++ expand_static_init only when we actually process the ++ initializer. It is not legal to redeclare a static data ++ member, so this issue does not arise in that case. */ ++ if (var_definition_p && TREE_STATIC (decl)) ++ expand_static_init (decl, init); + } + finish_end0: + diff --git a/misc/buildroot/toolchain/gcc/3.4.2/400-mips-pr17565.patch b/misc/buildroot/toolchain/gcc/3.4.2/400-mips-pr17565.patch new file mode 100644 index 000000000..7ae6aa56f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/400-mips-pr17565.patch @@ -0,0 +1,102 @@ +[committed] Fix target/17565: asms in delay slots + + * From: Richard Sandiford + * To: gcc-patches at gcc dot gnu dot org + * Date: Mon, 20 Sep 2004 07:55:58 +0100 + * Subject: [committed] Fix target/17565: asms in delay slots + +The MIPS port was allowing asms to be put into delay slots if the +compiler guesses they are only one instruction long. This is wrong +because of the possibility of it containing macros. + +The problem can be reproduced as an assembler warning +in the following testcase: + +int foo (int n) +{ + register int k asm ("$16") = n; + if (k > 0) + { + bar (); + asm ("li %0,0x12345678" : "=r" (k)); + } + return k; +} + +because the multi-instruction asm statement goes into the delay +slot of the call to bar(). + +This is reduced from a much more serious linux problem. Linux is fond +of using empty asm statements, and since gcc estimates empty asms to be +one instruction long, they too might be put into delay slots. This +actually has the effect of putting the following instruction into the +delay slot instead. Since there's no assembler warning, the problem was +only detected as a run-time failure. + +The fix is simple: set the asm value of "can_delay" to "no". +Tested on mipsisa64-elf, applied to mainline. + +This problem goes back to at least 2.95, so it isn't technically a +regression. On the other hand, it's the kind of bug that could trigger +for different types of code in different releases, so I'm sure there's +a testcase that fails (say) in 3.4 and not in 2.95. Will probably ask +Mark for permission to backport to 3.4. + +Richard + + + PR target/17565 + * config/mips/mips.md (define_asm_attributes): Set can_delay to no. + +testsuite/ + * gcc.target/mips/asm-1.c: New test. + +Index: config/mips/mips.md +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/mips/mips.md,v +retrieving revision 1.306 +diff -c -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.306 mips.md +*** gcc/gcc/config/mips/mips.md 13 Sep 2004 19:32:05 -0000 1.306 +--- gcc/gcc/config/mips/mips.md 20 Sep 2004 06:52:31 -0000 +*************** (define_attr "may_clobber_hilo" "no,yes" +*** 266,272 **** + + ;; Describe a user's asm statement. + (define_asm_attributes +! [(set_attr "type" "multi")]) + + ;; ......................... + ;; +--- 266,273 ---- + + ;; Describe a user's asm statement. + (define_asm_attributes +! [(set_attr "type" "multi") +! (set_attr "can_delay" "no")]) + + ;; ......................... + ;; +Index: testsuite/gcc.target/mips/asm-1.c +=================================================================== +RCS file: testsuite/gcc.target/mips/asm-1.c +diff -N testsuite/gcc.target/mips/asm-1.c +*** gcc/gcc/testsuite/gcc.target/mips/asm-1.c 1 Jan 1970 00:00:00 -0000 +--- gcc/gcc/testsuite/gcc.target/mips/asm-1.c 20 Sep 2004 06:52:31 -0000 +*************** +*** 0 **** +--- 1,14 ---- ++ /* PR target/17565. GCC used to put the asm into the delay slot ++ of the call. */ ++ /* { dg-do assemble } */ ++ /* { dg-options "-O" } */ ++ int foo (int n) ++ { ++ register int k asm ("$16") = n; ++ if (k > 0) ++ { ++ bar (); ++ asm ("li %0,0x12345678" : "=r" (k)); ++ } ++ return k; ++ } + diff --git a/misc/buildroot/toolchain/gcc/3.4.2/401-ppc-eabi-typo.patch b/misc/buildroot/toolchain/gcc/3.4.2/401-ppc-eabi-typo.patch new file mode 100644 index 000000000..dbb856868 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/401-ppc-eabi-typo.patch @@ -0,0 +1,20 @@ +revision 1.12 +date: 2004/07/16 15:13:40; author: segher; state: Exp; lines: +1 -1 + * config/rs6000/eabi.asm (__eabi_convert): Fix typo (cmpi vs. cmpwi). +Index: gcc/config/rs6000/eabi.asm +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/config/rs6000/eabi.asm,v +retrieving revision 1.11 +retrieving revision 1.12 +diff -u -b -B -w -p -r1.11 -r1.12 +--- gcc/gcc/config/rs6000/eabi.asm 20 Sep 2002 23:46:58 -0000 1.11 ++++ gcc/gcc/config/rs6000/eabi.asm 16 Jul 2004 15:13:40 -0000 1.12 +@@ -252,7 +252,7 @@ FUNC_START(__eabi_convert) + + .Lcvt: + lwzu 6,4(3) /* pointer to convert */ +- cmpi 0,6,0 ++ cmpwi 0,6,0 + beq- .Lcvt2 /* if pointer is null, don't convert */ + + add 6,6,12 /* convert pointer */ diff --git a/misc/buildroot/toolchain/gcc/3.4.2/402-mips-pr17770.patch b/misc/buildroot/toolchain/gcc/3.4.2/402-mips-pr17770.patch new file mode 100644 index 000000000..87d603023 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/402-mips-pr17770.patch @@ -0,0 +1,12 @@ +--- gcc-3.4.2/gcc/config/mips/mips.md 2004-06-25 02:35:30.000000000 -0500 ++++ gcc-3.4-cvs/gcc/config/mips/mips.md 2004-10-26 01:54:56.000000000 -0500 +@@ -4073,8 +4073,7 @@ + "!TARGET_MIPS16" + "lwl\t%0,%2" + [(set_attr "type" "load") +- (set_attr "mode" "SI") +- (set_attr "hazard" "none")]) ++ (set_attr "mode" "SI")]) + + (define_insn "mov_lwr" + [(set (match_operand:SI 0 "register_operand" "=d") diff --git a/misc/buildroot/toolchain/gcc/3.4.2/600-gcc34-arm-ldm-peephole.patch b/misc/buildroot/toolchain/gcc/3.4.2/600-gcc34-arm-ldm-peephole.patch new file mode 100644 index 000000000..fb317e153 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/600-gcc34-arm-ldm-peephole.patch @@ -0,0 +1,79 @@ +--- gcc-3.4.0/gcc/config/arm/arm.md.arm-ldm-peephole 2004-01-13 08:24:37.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.md 2004-04-24 18:18:04.000000000 -0400 +@@ -8810,13 +8810,16 @@ + (set_attr "length" "4,8,8")] + ) + ++; Try to convert LDR+LDR+arith into [add+]LDM+arith ++; On XScale, LDM is always slower than two LDRs, so only do this if ++; optimising for size. + (define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] +- "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" ++ "TARGET_ARM && (!arm_tune_xscale || optimize_size) && adjacent_mem_locations (operands[2], operands[3])" + "* + { + rtx ldm[3]; +@@ -8851,6 +8854,8 @@ + } + if (val1 && val2) + { ++ /* This would be a loss on a Harvard core, but adjacent_mem_locations() ++ will prevent it from happening. */ + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm-peephole 2004-04-24 18:16:25.000000000 -0400 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:18:04.000000000 -0400 +@@ -4593,8 +4593,11 @@ + arith_adjacentmem pattern to output an overlong sequence. */ + if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1)) + return 0; +- +- return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4); ++ ++ /* For Harvard cores, only accept pairs where one offset is zero. ++ See comment in load_multiple_sequence. */ ++ return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4) ++ && (!arm_ld_sched || val0 == 0 || val1 == 0); + } + return 0; + } +@@ -4838,6 +4841,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* ldmia */ + +@@ -5064,6 +5072,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* stmia */ + +--- gcc-3.4.0/gcc/genpeep.c.arm-ldm-peephole 2003-07-05 01:27:22.000000000 -0400 ++++ gcc-3.4.0/gcc/genpeep.c 2004-04-24 18:18:04.000000000 -0400 +@@ -381,6 +381,7 @@ + printf ("#include \"recog.h\"\n"); + printf ("#include \"except.h\"\n\n"); + printf ("#include \"function.h\"\n\n"); ++ printf ("#include \"flags.h\"\n\n"); + + printf ("#ifdef HAVE_peephole\n"); + printf ("extern rtx peep_operand[];\n\n"); diff --git a/misc/buildroot/toolchain/gcc/3.4.2/601-gcc34-arm-ldm.patch b/misc/buildroot/toolchain/gcc/3.4.2/601-gcc34-arm-ldm.patch new file mode 100644 index 000000000..142052fdf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/601-gcc34-arm-ldm.patch @@ -0,0 +1,119 @@ +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm 2004-02-27 09:51:05.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:16:25.000000000 -0400 +@@ -8520,6 +8520,26 @@ + return_used_this_function = 0; + } + ++/* Return the number (counting from 0) of ++ the least significant set bit in MASK. */ ++ ++#ifdef __GNUC__ ++inline ++#endif ++static int ++number_of_first_bit_set (mask) ++ int mask; ++{ ++ int bit; ++ ++ for (bit = 0; ++ (mask & (1 << bit)) == 0; ++ ++bit) ++ continue; ++ ++ return bit; ++} ++ + const char * + arm_output_epilogue (rtx sibling) + { +@@ -8753,27 +8773,47 @@ + saved_regs_mask |= (1 << PC_REGNUM); + } + +- /* Load the registers off the stack. If we only have one register +- to load use the LDR instruction - it is faster. */ +- if (saved_regs_mask == (1 << LR_REGNUM)) +- { +- /* The exception handler ignores the LR, so we do +- not really need to load it off the stack. */ +- if (eh_ofs) +- asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); +- else +- asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM); +- } +- else if (saved_regs_mask) ++ if (saved_regs_mask) + { +- if (saved_regs_mask & (1 << SP_REGNUM)) +- /* Note - write back to the stack register is not enabled +- (ie "ldmfd sp!..."). We know that the stack pointer is +- in the list of registers and if we add writeback the +- instruction becomes UNPREDICTABLE. */ +- print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ /* Load the registers off the stack. If we only have one register ++ to load use the LDR instruction - it is faster. */ ++ if (bit_count (saved_regs_mask) == 1) ++ { ++ int reg = number_of_first_bit_set (saved_regs_mask); ++ ++ switch (reg) ++ { ++ case SP_REGNUM: ++ /* Mustn't use base writeback when loading SP. */ ++ asm_fprintf (f, "\tldr\t%r, [%r]\n", SP_REGNUM, SP_REGNUM); ++ break; ++ ++ case LR_REGNUM: ++ if (eh_ofs) ++ { ++ /* The exception handler ignores the LR, so we do ++ not really need to load it off the stack. */ ++ asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); ++ break; ++ } ++ /* else fall through */ ++ ++ default: ++ asm_fprintf (f, "\tldr\t%r, [%r], #4\n", reg, SP_REGNUM); ++ break; ++ } ++ } + else +- print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ { ++ if (saved_regs_mask & (1 << SP_REGNUM)) ++ /* Note - write back to the stack register is not enabled ++ (ie "ldmfd sp!..."). We know that the stack pointer is ++ in the list of registers and if we add writeback the ++ instruction becomes UNPREDICTABLE. */ ++ print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ else ++ print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ } + } + + if (current_function_pretend_args_size) +@@ -11401,22 +11441,6 @@ + } + } + +-/* Return the number (counting from 0) of +- the least significant set bit in MASK. */ +- +-inline static int +-number_of_first_bit_set (int mask) +-{ +- int bit; +- +- for (bit = 0; +- (mask & (1 << bit)) == 0; +- ++bit) +- continue; +- +- return bit; +-} +- + /* Generate code to return from a thumb function. + If 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ diff --git a/misc/buildroot/toolchain/gcc/3.4.2/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/3.4.2/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..4377c2143 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +--- gcc-3.4.1/libstdc++-v3/libmath/Makefile.am~ 2003-08-27 22:29:42.000000000 +0100 ++++ gcc-3.4.1/libstdc++-v3/libmath/Makefile.am 2004-07-22 16:41:45.152130128 +0100 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC +--- gcc-3.4.1/libstdc++-v3/fragment.am.old 2004-07-22 18:24:58.024083656 +0100 ++++ gcc-3.4.1/libstdc++-v3/fragment.am 2004-07-22 18:24:59.019932264 +0100 +@@ -18,7 +18,7 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + + + diff --git a/misc/buildroot/toolchain/gcc/3.4.2/700-pr15068-fix.patch b/misc/buildroot/toolchain/gcc/3.4.2/700-pr15068-fix.patch new file mode 100644 index 000000000..2977765c5 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/700-pr15068-fix.patch @@ -0,0 +1,44 @@ +See http://gcc.gnu.org/PR15068 + +Fixes error + +../sysdeps/generic/s_fmax.c: In function `__fmax': +../sysdeps/generic/s_fmax.c:28: internal compiler error: in elim_reg_cond, at flow.c:3257 +Please submit a full bug report, +with preprocessed source if appropriate. +See for instructions. +make[2]: *** [/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/build-glibc/math/s_fmax.o] Error 1 +make[2]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822/math' +make[1]: *** [math/others] Error 2 +make[1]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822' +make: *** [all] Error 2 + +[ rediffed against gcc-3.4.1, with elbow grease, ending up with same thing as +http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/flow.c.diff?cvsroot=gcc&only_with_tag=csl-arm-branch&r1=1.563.4.2&r2=1.563.4.3 ] + +--- gcc-3.4.1/gcc/flow.c.old 2004-02-27 19:39:19.000000000 -0800 ++++ gcc-3.4.1/gcc/flow.c 2004-08-26 07:29:46.000000000 -0700 +@@ -1878,6 +1878,7 @@ + rtx set_src = SET_SRC (pc_set (BB_END (bb))); + rtx cond_true = XEXP (set_src, 0); + rtx reg = XEXP (cond_true, 0); ++ enum rtx_code inv_cond; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); +@@ -1886,11 +1887,13 @@ + in the form of a comparison of a register against zero. + If the condition is more complex than that, then it is safe + not to record any information. */ +- if (GET_CODE (reg) == REG ++ inv_cond = reversed_comparison_code (cond_true, BB_END (bb)); ++ if (inv_cond != UNKNOWN ++ && GET_CODE (reg) == REG + && XEXP (cond_true, 1) == const0_rtx) + { + rtx cond_false +- = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)), ++ = gen_rtx_fmt_ee (inv_cond, + GET_MODE (cond_true), XEXP (cond_true, 0), + XEXP (cond_true, 1)); + if (GET_CODE (XEXP (set_src, 1)) == PC) diff --git a/misc/buildroot/toolchain/gcc/3.4.2/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/3.4.2/800-arm-bigendian.patch new file mode 100644 index 000000000..04e998419 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/800-arm-bigendian.patch @@ -0,0 +1,68 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-3.4.1-dist/gcc/config/arm/linux-elf.h ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h +@@ -30,17 +30,34 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + /* Default is to use APCS-32 mode. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 | \ ++ ARM_FLAG_MMU_TRAPS | \ ++ TARGET_ENDIAN_DEFAULT ) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -101,7 +118,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + #endif + +--- gcc-3.4.1-dist/gcc/config.gcc ++++ gcc-3.4.1/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="t-slibgcc-elf-ver t-linux arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/3.4.2/830-gcc-bug-num-22167.patch b/misc/buildroot/toolchain/gcc/3.4.2/830-gcc-bug-num-22167.patch new file mode 100644 index 000000000..c7419af90 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/830-gcc-bug-num-22167.patch @@ -0,0 +1,16 @@ +Index: gcc/gcse.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gcse.c,v +retrieving revision 1.288.2.9 +diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.288.2.9 gcse.c +--- gcc/gcc/gcse.c 30 Oct 2004 18:02:53 -0000 1.288.2.9 ++++ gcc/gcc/gcse.c 14 Jul 2005 13:19:57 -0000 +@@ -6445,7 +6445,7 @@ hoist_code (void) + insn_inserted_p = 0; + + /* These tests should be the same as the tests above. */ +- if (TEST_BIT (hoist_vbeout[bb->index], i)) ++ if (TEST_BIT (hoist_exprs[bb->index], i)) + { + /* We've found a potentially hoistable expression, now + we look at every block BB dominates to see if it diff --git a/misc/buildroot/toolchain/gcc/3.4.2/900-nios2.patch b/misc/buildroot/toolchain/gcc/3.4.2/900-nios2.patch new file mode 100644 index 000000000..bfa06a21c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/900-nios2.patch @@ -0,0 +1,10211 @@ +--- gcc-3.4.3/gcc/Makefile.in ++++ gcc-3.4.3-nios2/gcc/Makefile.in +@@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_ + $(INSTALL_DATA) $(srcdir)/README-fixinc \ + $(DESTDIR)$(itoolsdatadir)/include/README ; \ + $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \ +- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \ ++ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \ + $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ + $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \ + else :; fi +--- gcc-3.4.3/gcc/combine.c ++++ gcc-3.4.3-nios2/gcc/combine.c +@@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin + mode); + } + ++#ifndef __nios2__ ++/* This screws up Nios II in this test case: ++ ++if (x & 1) ++ return 2; ++else ++ return 3; ++*/ + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx +@@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin + gen_lowpart_for_combine (mode, op0), + const1_rtx); + } ++#endif + + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT +--- gcc-3.4.3/gcc/config/nios2/crti.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm +@@ -0,0 +1,88 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just make a stack frame for the contents of the .fini and ++.init sections. Users may put any desired instructions in those ++sections. ++ ++ ++While technically any code can be put in the init and fini sections ++most stuff will not work other than stuff which obeys the call frame ++and ABI. All the call-preserved registers are saved, the call clobbered ++registers should have been saved by the code calling init and fini. ++ ++See crtstuff.c for an example of code that inserts itself in the ++init and fini sections. ++ ++See crt0.s for the code that calls init and fini. ++*/ ++ ++ .file "crti.asm" ++ ++ .section ".init" ++ .align 2 ++ .global _init ++_init: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ ++ .section ".fini" ++ .align 2 ++ .global _fini ++_fini: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ +--- gcc-3.4.3/gcc/config/nios2/crtn.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm +@@ -0,0 +1,70 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just makes sure that the .fini and .init sections do in ++fact return. Users may put any desired instructions in those sections. ++This file is the last thing linked into any executable. ++*/ ++ .file "crtn.asm" ++ ++ ++ ++ .section ".init" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ ++ .section ".fini" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c +@@ -0,0 +1,123 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern HItype __modhi3 (HItype, HItype); ++extern HItype __divhi3 (HItype, HItype); ++extern HItype __umodhi3 (HItype, HItype); ++extern HItype __udivhi3 (HItype, HItype); ++ ++static UHItype udivmodhi4(UHItype, UHItype, word_type); ++ ++static UHItype ++udivmodhi4(UHItype num, UHItype den, word_type modwanted) ++{ ++ UHItype bit = 1; ++ UHItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<15))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++HItype ++__divhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodhi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__modhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodhi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__udivhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 0); ++} ++ ++ ++HItype ++__umodhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c +@@ -0,0 +1,126 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern SItype __modsi3 (SItype, SItype); ++extern SItype __divsi3 (SItype, SItype); ++extern SItype __umodsi3 (SItype, SItype); ++extern SItype __udivsi3 (SItype, SItype); ++ ++static USItype udivmodsi4(USItype, USItype, word_type); ++ ++/* 16-bit SI divide and modulo as used in NIOS */ ++ ++ ++static USItype ++udivmodsi4(USItype num, USItype den, word_type modwanted) ++{ ++ USItype bit = 1; ++ USItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<31))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__modsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__udivsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 0); ++} ++ ++ ++SItype ++__umodsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c +@@ -0,0 +1,46 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++UQItype __divsi3_table[] = ++{ ++ 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15, ++ 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15, ++ 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15, ++ 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15, ++ 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15, ++ 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15, ++ 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15, ++ 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15, ++ 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15, ++ 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15, ++ 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15, ++ 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15, ++ 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15, ++ 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15, ++ 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15, ++ 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15, ++}; ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-mul.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c +@@ -0,0 +1,103 @@ ++/* while we are debugging (ie compile outside of gcc build) ++ disable gcc specific headers */ ++#ifndef DEBUG_MULSI3 ++ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++#else ++#define SItype int ++#define USItype unsigned int ++#endif ++ ++ ++extern SItype __mulsi3 (SItype, SItype); ++ ++SItype ++__mulsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = a; ++ ++ while (cnt) ++ { ++ if (cnt & 1) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt >>= 1; ++ } ++ ++ return res; ++} ++/* ++TODO: Choose best alternative implementation. ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = 0; ++ ++ while (cnt < 32) ++ { ++ if (a & (1L << cnt)) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt++; ++ } ++ ++ return res; ++} ++*/ ++ ++ ++#ifdef DEBUG_MULSI3 ++ ++int ++main () ++{ ++ int i, j; ++ int error = 0; ++ ++ for (i = -1000; i < 1000; i++) ++ for (j = -1000; j < 1000; j++) ++ { ++ int expect = i * j; ++ int actual = A__divsi3 (i, j); ++ if (expect != actual) ++ { ++ printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++#endif +--- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c +@@ -0,0 +1,1652 @@ ++ ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c +@@ -0,0 +1,1652 @@ ++#define FLOAT ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-protos.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h +@@ -0,0 +1,70 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++extern void dump_frame_size (FILE *); ++extern HOST_WIDE_INT compute_frame_size (void); ++extern int nios2_initial_elimination_offset (int, int); ++extern void override_options (void); ++extern void optimization_options (int, int); ++extern int nios2_can_use_return_insn (void); ++extern void expand_prologue (void); ++extern void expand_epilogue (bool); ++extern void function_profiler (FILE *, int); ++ ++ ++#ifdef RTX_CODE ++extern int nios2_legitimate_address (rtx, enum machine_mode, int); ++extern void nios2_print_operand (FILE *, rtx, int); ++extern void nios2_print_operand_address (FILE *, rtx); ++ ++extern int nios2_emit_move_sequence (rtx *, enum machine_mode); ++extern int nios2_emit_expensive_div (rtx *, enum machine_mode); ++ ++extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); ++extern void gen_conditional_move (rtx *, enum machine_mode); ++extern const char *asm_output_opcode (FILE *, const char *); ++ ++/* predicates */ ++extern int arith_operand (rtx, enum machine_mode); ++extern int uns_arith_operand (rtx, enum machine_mode); ++extern int logical_operand (rtx, enum machine_mode); ++extern int shift_operand (rtx, enum machine_mode); ++extern int reg_or_0_operand (rtx, enum machine_mode); ++extern int equality_op (rtx, enum machine_mode); ++extern int custom_insn_opcode (rtx, enum machine_mode); ++extern int rdwrctl_operand (rtx, enum machine_mode); ++ ++# ifdef HAVE_MACHINE_MODES ++# if defined TREE_CODE ++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); ++extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++ ++# endif /* TREE_CODE */ ++# endif /* HAVE_MACHINE_MODES */ ++#endif ++ ++#ifdef TREE_CODE ++extern int nios2_return_in_memory (tree); ++ ++#endif /* TREE_CODE */ +--- gcc-3.4.3/gcc/config/nios2/nios2.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c +@@ -0,0 +1,2853 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++#include ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "rtl.h" ++#include "tree.h" ++#include "tm_p.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "recog.h" ++#include "expr.h" ++#include "toplev.h" ++#include "basic-block.h" ++#include "function.h" ++#include "ggc.h" ++#include "reload.h" ++#include "debug.h" ++#include "optabs.h" ++#include "target.h" ++#include "target-def.h" ++ ++/* local prototypes */ ++static bool nios2_rtx_costs (rtx, int, int, int *); ++ ++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); ++static int nios2_use_dfa_pipeline_interface (void); ++static int nios2_issue_rate (void); ++static struct machine_function *nios2_init_machine_status (void); ++static bool nios2_in_small_data_p (tree); ++static rtx save_reg (int, HOST_WIDE_INT, rtx); ++static rtx restore_reg (int, HOST_WIDE_INT); ++static unsigned int nios2_section_type_flags (tree, const char *, int); ++static void nios2_init_builtins (void); ++static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); ++static bool nios2_function_ok_for_sibcall (tree, tree); ++static void nios2_encode_section_info (tree, rtx, int); ++ ++/* Initialize the GCC target structure. */ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue ++ ++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE ++#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ ++ nios2_use_dfa_pipeline_interface ++#undef TARGET_SCHED_ISSUE_RATE ++#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate ++#undef TARGET_IN_SMALL_DATA_P ++#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p ++#undef TARGET_ENCODE_SECTION_INFO ++#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info ++#undef TARGET_SECTION_TYPE_FLAGS ++#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS nios2_init_builtins ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN nios2_expand_builtin ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS nios2_rtx_costs ++ ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++ ++ ++/* Threshold for data being put into the small data/bss area, instead ++ of the normal data area (references to the small data/bss area take ++ 1 instruction, and use the global pointer, references to the normal ++ data area takes 2 instructions). */ ++unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; ++ ++ ++/* Structure to be filled in by compute_frame_size with register ++ save masks, and offsets for the current function. */ ++ ++struct nios2_frame_info ++GTY (()) ++{ ++ long total_size; /* # bytes that the entire frame takes up */ ++ long var_size; /* # bytes that variables take up */ ++ long args_size; /* # bytes that outgoing arguments take up */ ++ int save_reg_size; /* # bytes needed to store gp regs */ ++ int save_reg_rounded; /* # bytes needed to store gp regs */ ++ long save_regs_offset; /* offset from new sp to store gp registers */ ++ int initialized; /* != 0 if frame size already calculated */ ++ int num_regs; /* number of gp registers saved */ ++}; ++ ++struct machine_function ++GTY (()) ++{ ++ ++ /* Current frame information, calculated by compute_frame_size. */ ++ struct nios2_frame_info frame; ++}; ++ ++ ++/*************************************** ++ * Section encodings ++ ***************************************/ ++ ++ ++ ++ ++ ++/*************************************** ++ * Stack Layout and Calling Conventions ++ ***************************************/ ++ ++ ++#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) ++#define TEMP_REG_NUM 8 ++ ++static void ++nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ++{ ++ if (flag_verbose_asm || flag_debug_asm) ++ { ++ compute_frame_size (); ++ dump_frame_size (file); ++ } ++} ++ ++static rtx ++save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg) ++{ ++ rtx insn, stack_slot; ++ ++ stack_slot = gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ GEN_INT (offset)); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_MEM (SImode, stack_slot), ++ gen_rtx_REG (SImode, regno))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ return insn; ++} ++ ++static rtx ++restore_reg (int regno, HOST_WIDE_INT offset) ++{ ++ rtx insn, stack_slot; ++ ++ if (TOO_BIG_OFFSET (offset)) ++ { ++ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ GEN_INT (offset))); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ gen_rtx_PLUS (SImode, ++ stack_slot, ++ stack_pointer_rtx))); ++ } ++ else ++ { ++ stack_slot = gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (offset)); ++ } ++ ++ stack_slot = gen_rtx_MEM (SImode, stack_slot); ++ ++ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot); ++ ++ return insn; ++} ++ ++ ++/* There are two possible paths for prologue expansion, ++- the first is if the total frame size is < 2^15-1. In that ++case all the immediates will fit into the 16-bit immediate ++fields. ++- the second is when the frame size is too big, in that ++case an additional temporary register is used, first ++as a cfa_temp to offset the sp, second as the cfa_store ++register. ++ ++See the comment above dwarf2out_frame_debug_expr in ++dwarf2out.c for more explanation of the "rules." ++ ++ ++Case 1: ++Rule # Example Insn Effect ++2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++12 stw ra, offset(sp) ++12 stw r16, offset(sp) ++1 mov fp, sp ++ ++Case 2: ++Rule # Example Insn Effect ++6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size ++2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0 ++12 stw ra, offset(r8) ++12 stw r16, offset(r8) ++1 mov fp, sp ++ ++*/ ++ ++void ++expand_prologue () ++{ ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int cfa_store_offset; ++ rtx insn; ++ rtx cfa_store_reg = 0; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (total_frame_size) ++ { ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ /* cfa_temp and cfa_store_reg are the same register, ++ cfa_store_reg overwrites cfa_temp */ ++ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ cfa_store_reg, ++ GEN_INT (total_frame_size))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_MINUS (SImode, ++ stack_pointer_rtx, ++ cfa_store_reg)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ /* if there are no registers to save, I don't need to ++ create a cfa_store */ ++ if (cfun->machine->frame.save_reg_size) ++ { ++ insn = gen_rtx_SET (SImode, ++ cfa_store_reg, ++ gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ stack_pointer_rtx)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ cfa_store_offset ++ = total_frame_size ++ - (cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded); ++ } ++ else ++ { ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (-total_frame_size))); ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ cfa_store_reg = stack_pointer_rtx; ++ cfa_store_offset ++ = cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded; ++ } ++ } ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ cfa_store_offset -= 4; ++ save_reg (i, cfa_store_offset, cfa_store_reg); ++ } ++ } ++ ++ if (frame_pointer_needed) ++ { ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_REG (SImode, FP_REGNO), ++ gen_rtx_REG (SImode, SP_REGNO))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ /* If we are profiling, make sure no instructions are scheduled before ++ the call to mcount. */ ++ if (current_function_profile) ++ emit_insn (gen_blockage ()); ++} ++ ++void ++expand_epilogue (bool sibcall_p) ++{ ++ rtx insn; ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int register_store_offset; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (!sibcall_p && nios2_can_use_return_insn ()) ++ { ++ insn = emit_jump_insn (gen_return ()); ++ return; ++ } ++ ++ emit_insn (gen_blockage ()); ++ ++ register_store_offset = ++ cfun->machine->frame.save_regs_offset + ++ cfun->machine->frame.save_reg_rounded; ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (RA_REGNO, register_store_offset); ++ } ++ ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (FP_REGNO, register_store_offset); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ register_store_offset -= 4; ++ restore_reg (i, register_store_offset); ++ } ++ } ++ ++ if (total_frame_size) ++ { ++ rtx sp_adjust; ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ sp_adjust, ++ GEN_INT (total_frame_size))); ++ ++ } ++ else ++ { ++ sp_adjust = GEN_INT (total_frame_size); ++ } ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ sp_adjust)); ++ insn = emit_insn (insn); ++ } ++ ++ ++ if (!sibcall_p) ++ { ++ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode, ++ RA_REGNO))); ++ } ++} ++ ++ ++bool ++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) ++{ ++ return true; ++} ++ ++ ++ ++ ++ ++/* ----------------------- * ++ * Profiling ++ * ----------------------- */ ++ ++void ++function_profiler (FILE *file, int labelno) ++{ ++ fprintf (file, "\t%s mcount begin, label: .LP%d\n", ++ ASM_COMMENT_START, labelno); ++ fprintf (file, "\tnextpc\tr8\n"); ++ fprintf (file, "\tmov\tr9, ra\n"); ++ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno); ++ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno); ++ fprintf (file, "\tcall\tmcount\n"); ++ fprintf (file, "\tmov\tra, r9\n"); ++ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START); ++} ++ ++ ++/*************************************** ++ * Stack Layout ++ ***************************************/ ++ ++ ++void ++dump_frame_size (FILE *file) ++{ ++ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); ++ ++ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.total_size); ++ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.var_size); ++ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.args_size); ++ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_size); ++ fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_rounded); ++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.initialized); ++ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.num_regs); ++ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_regs_offset); ++ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, ++ current_function_is_leaf); ++ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, ++ frame_pointer_needed); ++ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, ++ current_function_pretend_args_size); ++ ++} ++ ++ ++/* Return the bytes needed to compute the frame pointer from the current ++ stack pointer. ++*/ ++ ++HOST_WIDE_INT ++compute_frame_size () ++{ ++ unsigned int regno; ++ HOST_WIDE_INT var_size; /* # of var. bytes allocated */ ++ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */ ++ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */ ++ HOST_WIDE_INT save_reg_rounded; ++ /* # bytes needed to store callee save regs (rounded) */ ++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */ ++ ++ save_reg_size = 0; ++ var_size = STACK_ALIGN (get_frame_size ()); ++ out_args_size = STACK_ALIGN (current_function_outgoing_args_size); ++ ++ total_size = var_size + out_args_size; ++ ++ /* Calculate space needed for gp registers. */ ++ for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++) ++ { ++ if (MUST_SAVE_REGISTER (regno)) ++ { ++ save_reg_size += 4; ++ } ++ } ++ ++ save_reg_rounded = STACK_ALIGN (save_reg_size); ++ total_size += save_reg_rounded; ++ ++ total_size += STACK_ALIGN (current_function_pretend_args_size); ++ ++ /* Save other computed information. */ ++ cfun->machine->frame.total_size = total_size; ++ cfun->machine->frame.var_size = var_size; ++ cfun->machine->frame.args_size = current_function_outgoing_args_size; ++ cfun->machine->frame.save_reg_size = save_reg_size; ++ cfun->machine->frame.save_reg_rounded = save_reg_rounded; ++ cfun->machine->frame.initialized = reload_completed; ++ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD; ++ ++ cfun->machine->frame.save_regs_offset ++ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0; ++ ++ return total_size; ++} ++ ++ ++int ++nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) ++{ ++ int offset; ++ ++ /* Set OFFSET to the offset from the stack pointer. */ ++ switch (from) ++ { ++ case FRAME_POINTER_REGNUM: ++ offset = 0; ++ break; ++ ++ case ARG_POINTER_REGNUM: ++ compute_frame_size (); ++ offset = cfun->machine->frame.total_size; ++ offset -= current_function_pretend_args_size; ++ break; ++ ++ case RETURN_ADDRESS_POINTER_REGNUM: ++ compute_frame_size (); ++ /* since the return address is always the first of the ++ saved registers, return the offset to the beginning ++ of the saved registers block */ ++ offset = cfun->machine->frame.save_regs_offset; ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ return offset; ++} ++ ++/* Return nonzero if this function is known to have a null epilogue. ++ This allows the optimizer to omit jumps to jumps if no stack ++ was created. */ ++int ++nios2_can_use_return_insn () ++{ ++ if (!reload_completed) ++ return 0; ++ ++ if (regs_ever_live[RA_REGNO] || current_function_profile) ++ return 0; ++ ++ if (cfun->machine->frame.initialized) ++ return cfun->machine->frame.total_size == 0; ++ ++ return compute_frame_size () == 0; ++} ++ ++ ++ ++ ++ ++/*************************************** ++ * ++ ***************************************/ ++ ++const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++const char *nios2_sys_lib_string; /* for -msys-lib= */ ++const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++void ++override_options () ++{ ++ /* Function to allocate machine-dependent function status. */ ++ init_machine_status = &nios2_init_machine_status; ++ ++ nios2_section_threshold ++ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; ++ ++ if (nios2_sys_nosys_string && *nios2_sys_nosys_string) ++ { ++ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string); ++ } ++ ++ /* If we don't have mul, we don't have mulx either! */ ++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX) ++ { ++ target_flags &= ~HAS_MULX_FLAG; ++ } ++ ++} ++ ++void ++optimization_options (int level, int size) ++{ ++ if (level || size) ++ { ++ target_flags |= INLINE_MEMCPY_FLAG; ++ } ++ ++ if (level >= 3 && !size) ++ { ++ target_flags |= FAST_SW_DIV_FLAG; ++ } ++} ++ ++/* Allocate a chunk of memory for per-function machine-dependent data. */ ++static struct machine_function * ++nios2_init_machine_status () ++{ ++ return ((struct machine_function *) ++ ggc_alloc_cleared (sizeof (struct machine_function))); ++} ++ ++ ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++/* Compute a (partial) cost for rtx X. Return true if the complete ++ cost has been computed, and false if subexpressions should be ++ scanned. In either case, *TOTAL contains the cost result. */ ++ ++ ++ ++static bool ++nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) ++{ ++ switch (code) ++ { ++ case CONST_INT: ++ if (INTVAL (x) == 0) ++ { ++ *total = COSTS_N_INSNS (0); ++ return true; ++ } ++ else if (SMALL_INT (INTVAL (x)) ++ || SMALL_INT_UNSIGNED (INTVAL (x)) ++ || UPPER16_INT (INTVAL (x))) ++ { ++ *total = COSTS_N_INSNS (2); ++ return true; ++ } ++ else ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case LABEL_REF: ++ case SYMBOL_REF: ++ /* ??? gp relative stuff will fit in here */ ++ /* fall through */ ++ case CONST: ++ case CONST_DOUBLE: ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case MULT: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ case SIGN_EXTEND: ++ { ++ *total = COSTS_N_INSNS (3); ++ return false; ++ } ++ case ZERO_EXTEND: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ ++ default: ++ return false; ++ } ++} ++ ++ ++/*************************************** ++ * INSTRUCTION SUPPORT ++ * ++ * These functions are used within the Machine Description to ++ * handle common or complicated output and expansions from ++ * instructions. ++ ***************************************/ ++ ++int ++nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) ++{ ++ rtx to = operands[0]; ++ rtx from = operands[1]; ++ ++ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) ++ { ++ if (no_new_pseudos) ++ internal_error ("Trying to force_reg no_new_pseudos == 1"); ++ from = copy_to_mode_reg (mode, from); ++ } ++ ++ operands[0] = to; ++ operands[1] = from; ++ return 0; ++} ++ ++/* Divide Support */ ++ ++/* ++ If -O3 is used, we want to output a table lookup for ++ divides between small numbers (both num and den >= 0 ++ and < 0x10). The overhead of this method in the worse ++ case is 40 bytes in the text section (10 insns) and ++ 256 bytes in the data section. Additional divides do ++ not incur additional penalties in the data section. ++ ++ Code speed is improved for small divides by about 5x ++ when using this method in the worse case (~9 cycles ++ vs ~45). And in the worse case divides not within the ++ table are penalized by about 10% (~5 cycles vs ~45). ++ However in the typical case the penalty is not as bad ++ because doing the long divide in only 45 cycles is ++ quite optimistic. ++ ++ ??? It would be nice to have some benchmarks other ++ than Dhrystone to back this up. ++ ++ This bit of expansion is to create this instruction ++ sequence as rtl. ++ or $8, $4, $5 ++ slli $9, $4, 4 ++ cmpgeui $3, $8, 16 ++ beq $3, $0, .L3 ++ or $10, $9, $5 ++ add $12, $11, divide_table ++ ldbu $2, 0($12) ++ br .L1 ++.L3: ++ call slow_div ++.L1: ++# continue here with result in $2 ++ ++ ??? Ideally I would like the emit libcall block to contain ++ all of this code, but I don't know how to do that. What it ++ means is that if the divide can be eliminated, it may not ++ completely disappear. ++ ++ ??? The __divsi3_table label should ideally be moved out ++ of this block and into a global. If it is placed into the ++ sdata section we can save even more cycles by doing things ++ gp relative. ++*/ ++int ++nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) ++{ ++ rtx or_result, shift_left_result; ++ rtx lookup_value; ++ rtx lab1, lab3; ++ rtx insns; ++ rtx libfunc; ++ rtx final_result; ++ rtx tmp; ++ ++ /* it may look a little generic, but only SImode ++ is supported for now */ ++ if (mode != SImode) ++ abort (); ++ ++ libfunc = sdiv_optab->handlers[(int) SImode].libfunc; ++ ++ ++ ++ lab1 = gen_label_rtx (); ++ lab3 = gen_label_rtx (); ++ ++ or_result = expand_simple_binop (SImode, IOR, ++ operands[1], operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, ++ GET_MODE (or_result), 0, lab3); ++ JUMP_LABEL (get_last_insn ()) = lab3; ++ ++ shift_left_result = expand_simple_binop (SImode, ASHIFT, ++ operands[1], GEN_INT (4), ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ lookup_value = expand_simple_binop (SImode, IOR, ++ shift_left_result, operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ convert_move (operands[0], ++ gen_rtx (MEM, QImode, ++ gen_rtx (PLUS, SImode, ++ lookup_value, ++ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), ++ 1); ++ ++ ++ tmp = emit_jump_insn (gen_jump (lab1)); ++ JUMP_LABEL (tmp) = lab1; ++ emit_barrier (); ++ ++ emit_label (lab3); ++ LABEL_NUSES (lab3) = 1; ++ ++ start_sequence (); ++ final_result = emit_library_call_value (libfunc, NULL_RTX, ++ LCT_CONST, SImode, 2, ++ operands[1], SImode, ++ operands[2], SImode); ++ ++ ++ insns = get_insns (); ++ end_sequence (); ++ emit_libcall_block (insns, operands[0], final_result, ++ gen_rtx (DIV, SImode, operands[1], operands[2])); ++ ++ emit_label (lab1); ++ LABEL_NUSES (lab1) = 1; ++ return 1; ++} ++ ++/* Branches/Compares */ ++ ++/* the way of handling branches/compares ++ in gcc is heavily borrowed from MIPS */ ++ ++enum internal_test ++{ ++ ITEST_EQ, ++ ITEST_NE, ++ ITEST_GT, ++ ITEST_GE, ++ ITEST_LT, ++ ITEST_LE, ++ ITEST_GTU, ++ ITEST_GEU, ++ ITEST_LTU, ++ ITEST_LEU, ++ ITEST_MAX ++}; ++ ++static enum internal_test map_test_to_internal_test (enum rtx_code); ++ ++/* Cached operands, and operator to compare for use in set/branch/trap ++ on condition codes. */ ++rtx branch_cmp[2]; ++enum cmp_type branch_type; ++ ++/* Make normal rtx_code into something we can index from an array */ ++ ++static enum internal_test ++map_test_to_internal_test (enum rtx_code test_code) ++{ ++ enum internal_test test = ITEST_MAX; ++ ++ switch (test_code) ++ { ++ case EQ: ++ test = ITEST_EQ; ++ break; ++ case NE: ++ test = ITEST_NE; ++ break; ++ case GT: ++ test = ITEST_GT; ++ break; ++ case GE: ++ test = ITEST_GE; ++ break; ++ case LT: ++ test = ITEST_LT; ++ break; ++ case LE: ++ test = ITEST_LE; ++ break; ++ case GTU: ++ test = ITEST_GTU; ++ break; ++ case GEU: ++ test = ITEST_GEU; ++ break; ++ case LTU: ++ test = ITEST_LTU; ++ break; ++ case LEU: ++ test = ITEST_LEU; ++ break; ++ default: ++ break; ++ } ++ ++ return test; ++} ++ ++/* Generate the code to compare (and possibly branch) two integer values ++ TEST_CODE is the comparison code we are trying to emulate ++ (or implement directly) ++ RESULT is where to store the result of the comparison, ++ or null to emit a branch ++ CMP0 CMP1 are the two comparison operands ++ DESTINATION is the destination of the branch, or null to only compare ++ */ ++ ++void ++gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */ ++ rtx result, /* result to store comp. or 0 if branch */ ++ rtx cmp0, /* first operand to compare */ ++ rtx cmp1, /* second operand to compare */ ++ rtx destination) /* destination of the branch, or 0 if compare */ ++{ ++ struct cmp_info ++ { ++ /* for register (or 0) compares */ ++ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */ ++ int reverse_regs; /* reverse registers in test */ ++ ++ /* for immediate compares */ ++ enum rtx_code test_code_const; ++ /* code to use in instruction (LT vs. LTU) */ ++ int const_low; /* low bound of constant we can accept */ ++ int const_high; /* high bound of constant we can accept */ ++ int const_add; /* constant to add */ ++ ++ /* generic info */ ++ int unsignedp; /* != 0 for unsigned comparisons. */ ++ }; ++ ++ static const struct cmp_info info[(int) ITEST_MAX] = { ++ ++ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ ++ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ ++ ++ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ ++ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ ++ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ ++ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ ++ ++ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ ++ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ ++ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ ++ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ ++ }; ++ ++ enum internal_test test; ++ enum machine_mode mode; ++ const struct cmp_info *p_info; ++ int branch_p; ++ ++ ++ ++ ++ test = map_test_to_internal_test (test_code); ++ if (test == ITEST_MAX) ++ abort (); ++ ++ p_info = &info[(int) test]; ++ ++ mode = GET_MODE (cmp0); ++ if (mode == VOIDmode) ++ mode = GET_MODE (cmp1); ++ ++ branch_p = (destination != 0); ++ ++ /* We can't, under any circumstances, have const_ints in cmp0 ++ ??? Actually we could have const0 */ ++ if (GET_CODE (cmp0) == CONST_INT) ++ cmp0 = force_reg (mode, cmp0); ++ ++ /* if the comparison is against an int not in legal range ++ move it into a register */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ HOST_WIDE_INT value = INTVAL (cmp1); ++ ++ if (value < p_info->const_low || value > p_info->const_high) ++ cmp1 = force_reg (mode, cmp1); ++ } ++ ++ /* Comparison to constants, may involve adding 1 to change a GT into GE. ++ Comparison between two registers, may involve switching operands. */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ if (p_info->const_add != 0) ++ { ++ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; ++ ++ /* If modification of cmp1 caused overflow, ++ we would get the wrong answer if we follow the usual path; ++ thus, x > 0xffffffffU would turn into x > 0U. */ ++ if ((p_info->unsignedp ++ ? (unsigned HOST_WIDE_INT) new > ++ (unsigned HOST_WIDE_INT) INTVAL (cmp1) ++ : new > INTVAL (cmp1)) != (p_info->const_add > 0)) ++ { ++ /* ??? This case can never happen with the current numbers, ++ but I am paranoid and would rather an abort than ++ a bug I will never find */ ++ abort (); ++ } ++ else ++ cmp1 = GEN_INT (new); ++ } ++ } ++ ++ else if (p_info->reverse_regs) ++ { ++ rtx temp = cmp0; ++ cmp0 = cmp1; ++ cmp1 = temp; ++ } ++ ++ ++ ++ if (branch_p) ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ rtx insn; ++ rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1); ++ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ insn = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, label, pc_rtx)); ++ emit_jump_insn (insn); ++ } ++ else ++ { ++ rtx cond, label; ++ ++ result = gen_reg_rtx (mode); ++ ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ ++ cond = gen_rtx (NE, mode, result, const0_rtx); ++ label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, ++ label, pc_rtx))); ++ } ++ } ++ else ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1)); ++ } ++ else ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ } ++ } ++ ++} ++ ++ ++/* ??? For now conditional moves are only supported ++ when the mode of the operands being compared are ++ the same as the ones being moved */ ++ ++void ++gen_conditional_move (rtx *operands, enum machine_mode mode) ++{ ++ rtx insn, cond; ++ rtx cmp_reg = gen_reg_rtx (mode); ++ enum rtx_code cmp_code = GET_CODE (operands[1]); ++ enum rtx_code move_code = EQ; ++ ++ /* emit a comparison if it is not "simple". ++ Simple comparisons are X eq 0 and X ne 0 */ ++ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[0]; ++ move_code = cmp_code; ++ } ++ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[1]; ++ move_code = cmp_code == EQ ? NE : EQ; ++ } ++ else ++ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], ++ NULL_RTX); ++ ++ cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); ++ insn = gen_rtx_SET (mode, operands[0], ++ gen_rtx_IF_THEN_ELSE (mode, ++ cond, operands[2], operands[3])); ++ emit_insn (insn); ++} ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++int ++nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int strict) ++{ ++ int ret_val = 0; ++ ++ switch (GET_CODE (operand)) ++ { ++ /* direct. */ ++ case SYMBOL_REF: ++ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) ++ { ++ ret_val = 1; ++ break; ++ } ++ /* else, fall through */ ++ case LABEL_REF: ++ case CONST_INT: ++ case CONST: ++ case CONST_DOUBLE: ++ /* ??? In here I need to add gp addressing */ ++ ret_val = 0; ++ ++ break; ++ ++ /* Register indirect. */ ++ case REG: ++ ret_val = REG_OK_FOR_BASE_P2 (operand, strict); ++ break; ++ ++ /* Register indirect with displacement */ ++ case PLUS: ++ { ++ rtx op0 = XEXP (operand, 0); ++ rtx op1 = XEXP (operand, 1); ++ ++ if (REG_P (op0) && REG_P (op1)) ++ ret_val = 0; ++ else if (REG_P (op0) && CONSTANT_P (op1)) ++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict) ++ && SMALL_INT (INTVAL (op1)); ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ ret_val = REG_OK_FOR_BASE_P2 (op1, strict) ++ && SMALL_INT (INTVAL (op0)); ++ else ++ ret_val = 0; ++ } ++ break; ++ ++ default: ++ ret_val = 0; ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/* Return true if EXP should be placed in the small data section. */ ++ ++static bool ++nios2_in_small_data_p (tree exp) ++{ ++ /* We want to merge strings, so we never consider them small data. */ ++ if (TREE_CODE (exp) == STRING_CST) ++ return false; ++ ++ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) ++ { ++ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); ++ /* ??? these string names need moving into ++ an array in some header file */ ++ if (nios2_section_threshold > 0 ++ && (strcmp (section, ".sbss") == 0 ++ || strncmp (section, ".sbss.", 6) == 0 ++ || strcmp (section, ".sdata") == 0 ++ || strncmp (section, ".sdata.", 7) == 0)) ++ return true; ++ } ++ else if (TREE_CODE (exp) == VAR_DECL) ++ { ++ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); ++ ++ /* If this is an incomplete type with size 0, then we can't put it ++ in sdata because it might be too big when completed. */ ++ if (size > 0 && size <= nios2_section_threshold) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ++nios2_encode_section_info (tree decl, rtx rtl, int first) ++{ ++ ++ rtx symbol; ++ int flags; ++ ++ default_encode_section_info (decl, rtl, first); ++ ++ /* Careful not to prod global register variables. */ ++ if (GET_CODE (rtl) != MEM) ++ return; ++ symbol = XEXP (rtl, 0); ++ if (GET_CODE (symbol) != SYMBOL_REF) ++ return; ++ ++ flags = SYMBOL_REF_FLAGS (symbol); ++ ++ /* We don't want weak variables to be addressed with gp in case they end up with ++ value 0 which is not within 2^15 of $gp */ ++ if (DECL_P (decl) && DECL_WEAK (decl)) ++ flags |= SYMBOL_FLAG_WEAK_DECL; ++ ++ SYMBOL_REF_FLAGS (symbol) = flags; ++} ++ ++ ++static unsigned int ++nios2_section_type_flags (tree decl, const char *name, int reloc) ++{ ++ unsigned int flags; ++ ++ flags = default_section_type_flags (decl, name, reloc); ++ ++ /* ??? these string names need moving into an array in some header file */ ++ if (strcmp (name, ".sbss") == 0 ++ || strncmp (name, ".sbss.", 6) == 0 ++ || strcmp (name, ".sdata") == 0 ++ || strncmp (name, ".sdata.", 7) == 0) ++ flags |= SECTION_SMALL; ++ ++ return flags; ++} ++ ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++ ++/* print the operand OP to file stream ++ FILE modified by LETTER. LETTER ++ can be one of: ++ i: print "i" if OP is an immediate, except 0 ++ o: print "io" if OP is volatile ++ ++ z: for const0_rtx print $0 instead of 0 ++ H: for %hiadj ++ L: for %lo ++ U: for upper half of 32 bit value ++ */ ++ ++void ++nios2_print_operand (FILE *file, rtx op, int letter) ++{ ++ ++ switch (letter) ++ { ++ case 'i': ++ if (CONSTANT_P (op) && (op != const0_rtx)) ++ fprintf (file, "i"); ++ return; ++ ++ case 'o': ++ if (GET_CODE (op) == MEM ++ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE) ++ || TARGET_BYPASS_CACHE)) ++ fprintf (file, "io"); ++ return; ++ ++ default: ++ break; ++ } ++ ++ if (comparison_operator (op, VOIDmode)) ++ { ++ if (letter == 0) ++ { ++ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); ++ return; ++ } ++ } ++ ++ ++ switch (GET_CODE (op)) ++ { ++ case REG: ++ if (letter == 0 || letter == 'z') ++ { ++ fprintf (file, "%s", reg_names[REGNO (op)]); ++ return; ++ } ++ ++ case CONST_INT: ++ if (INTVAL (op) == 0 && letter == 'z') ++ { ++ fprintf (file, "zero"); ++ return; ++ } ++ else if (letter == 'U') ++ { ++ HOST_WIDE_INT val = INTVAL (op); ++ rtx new_op; ++ val = (val / 65536) & 0xFFFF; ++ new_op = GEN_INT (val); ++ output_addr_const (file, new_op); ++ return; ++ } ++ ++ /* else, fall through */ ++ case CONST: ++ case LABEL_REF: ++ case SYMBOL_REF: ++ case CONST_DOUBLE: ++ if (letter == 0 || letter == 'z') ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ else if (letter == 'H') ++ { ++ fprintf (file, "%%hiadj("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ else if (letter == 'L') ++ { ++ fprintf (file, "%%lo("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ ++ ++ case SUBREG: ++ case MEM: ++ if (letter == 0) ++ { ++ output_address (op); ++ return; ++ } ++ ++ case CODE_LABEL: ++ if (letter == 0) ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print (%c) ", letter); ++ debug_rtx (op); ++ abort (); ++} ++ ++static int gprel_constant (rtx); ++ ++static int ++gprel_constant (rtx op) ++{ ++ if (GET_CODE (op) == SYMBOL_REF ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) ++ { ++ return 1; ++ } ++ else if (GET_CODE (op) == CONST ++ && GET_CODE (XEXP (op, 0)) == PLUS) ++ { ++ return gprel_constant (XEXP (XEXP (op, 0), 0)); ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++void ++nios2_print_operand_address (FILE *file, rtx op) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST: ++ case CONST_INT: ++ case LABEL_REF: ++ case CONST_DOUBLE: ++ case SYMBOL_REF: ++ if (gprel_constant (op)) ++ { ++ fprintf (file, "%%gprel("); ++ output_addr_const (file, op); ++ fprintf (file, ")(%s)", reg_names[GP_REGNO]); ++ return; ++ } ++ ++ break; ++ ++ case PLUS: ++ { ++ rtx op0 = XEXP (op, 0); ++ rtx op1 = XEXP (op, 1); ++ ++ if (REG_P (op0) && CONSTANT_P (op1)) ++ { ++ output_addr_const (file, op1); ++ fprintf (file, "(%s)", reg_names[REGNO (op0)]); ++ return; ++ } ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ { ++ output_addr_const (file, op0); ++ fprintf (file, "(%s)", reg_names[REGNO (op1)]); ++ return; ++ } ++ } ++ break; ++ ++ case REG: ++ fprintf (file, "0(%s)", reg_names[REGNO (op)]); ++ return; ++ ++ case MEM: ++ { ++ rtx base = XEXP (op, 0); ++ PRINT_OPERAND_ADDRESS (file, base); ++ return; ++ } ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print address\n"); ++ debug_rtx (op); ++ abort (); ++} ++ ++ ++ ++ ++ ++/**************************** ++ * Predicates ++ ****************************/ ++ ++int ++arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++uns_arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++logical_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT ++ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++shift_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); ++} ++ ++/* Return truth value of whether OP is a register or the constant 0. */ ++ ++int ++reg_or_0_operand (rtx op, enum machine_mode mode) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST_INT: ++ return INTVAL (op) == 0; ++ ++ case CONST_DOUBLE: ++ return op == CONST0_RTX (mode); ++ ++ default: ++ break; ++ } ++ ++ return register_operand (op, mode); ++} ++ ++ ++int ++equality_op (rtx op, enum machine_mode mode) ++{ ++ if (mode != GET_MODE (op)) ++ return 0; ++ ++ return GET_CODE (op) == EQ || GET_CODE (op) == NE; ++} ++ ++int ++custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); ++} ++ ++ ++ ++ ++ ++ ++ ++/***************************************************************************** ++** ++** instruction scheduler ++** ++*****************************************************************************/ ++static int ++nios2_use_dfa_pipeline_interface () ++{ ++ return 1; ++} ++ ++ ++static int ++nios2_issue_rate () ++{ ++#ifdef MAX_DFA_ISSUE_RATE ++ return MAX_DFA_ISSUE_RATE; ++#else ++ return 1; ++#endif ++} ++ ++ ++const char * ++asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, ++ const char *ptr ATTRIBUTE_UNUSED) ++{ ++ const char *p; ++ ++ p = ptr; ++ return ptr; ++} ++ ++ ++ ++/***************************************************************************** ++** ++** function arguments ++** ++*****************************************************************************/ ++ ++void ++init_cumulative_args (CUMULATIVE_ARGS *cum, ++ tree fntype ATTRIBUTE_UNUSED, ++ rtx libname ATTRIBUTE_UNUSED, ++ tree fndecl ATTRIBUTE_UNUSED, ++ int n_named_args ATTRIBUTE_UNUSED) ++{ ++ cum->regs_used = 0; ++} ++ ++ ++/* Update the data in CUM to advance over an argument ++ of mode MODE and data type TYPE. ++ (TYPE is null for libcalls where that information may not be available.) */ ++ ++void ++function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ cum->regs_used = NUM_ARG_REGS; ++ } ++ else ++ { ++ cum->regs_used += param_size; ++ } ++ ++ return; ++} ++ ++/* Define where to put the arguments to a function. Value is zero to ++ push the argument on the stack, or a hard register in which to ++ store the argument. ++ ++ MODE is the argument's machine mode. ++ TYPE is the data type of the argument (as a tree). ++ This is null for libcalls where that information may ++ not be available. ++ CUM is a variable of type CUMULATIVE_ARGS which gives info about ++ the preceding args and about the function being called. ++ NAMED is nonzero if this argument is a named parameter ++ (otherwise it is an extra parameter matching an ellipsis). */ ++rtx ++function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ rtx return_rtx = NULL_RTX; ++ ++ if (cum->regs_used < NUM_ARG_REGS) ++ { ++ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); ++ } ++ ++ return return_rtx; ++} ++ ++int ++function_arg_partial_nregs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used < NUM_ARG_REGS ++ && cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ return NUM_ARG_REGS - cum->regs_used; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++ ++int ++nios2_return_in_memory (tree type) ++{ ++ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) ++ || (int_size_in_bytes (type) == -1)); ++ ++ return res; ++} ++ ++/* ??? It may be possible to eliminate the copyback and implement ++ my own va_arg type, but that is more work for now. */ ++int ++nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int no_rtl) ++{ ++ CUMULATIVE_ARGS local_cum; ++ int regs_to_push; ++ ++ local_cum = *cum; ++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); ++ ++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used; ++ ++ if (!no_rtl) ++ { ++ if (regs_to_push > 0) ++ { ++ rtx ptr, mem; ++ ++ ptr = virtual_incoming_args_rtx; ++ mem = gen_rtx_MEM (BLKmode, ptr); ++ ++ /* va_arg is an array access in this case, which causes ++ it to get MEM_IN_STRUCT_P set. We must set it here ++ so that the insn scheduler won't assume that these ++ stores can't possibly overlap with the va_arg loads. */ ++ MEM_SET_IN_STRUCT_P (mem, 1); ++ ++ emit_insn (gen_blockage ()); ++ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, ++ regs_to_push); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ ++ return regs_to_push * UNITS_PER_WORD; ++ ++} ++ ++ ++ ++/***************************************************************************** ++** ++** builtins ++** ++** This method for handling builtins is from CSP where _many_ more types of ++** expanders have already been written. Check there first before writing ++** new ones. ++** ++*****************************************************************************/ ++ ++enum nios2_builtins ++{ ++ NIOS2_BUILTIN_LDBIO, ++ NIOS2_BUILTIN_LDBUIO, ++ NIOS2_BUILTIN_LDHIO, ++ NIOS2_BUILTIN_LDHUIO, ++ NIOS2_BUILTIN_LDWIO, ++ NIOS2_BUILTIN_STBIO, ++ NIOS2_BUILTIN_STHIO, ++ NIOS2_BUILTIN_STWIO, ++ NIOS2_BUILTIN_SYNC, ++ NIOS2_BUILTIN_RDCTL, ++ NIOS2_BUILTIN_WRCTL, ++ ++ NIOS2_BUILTIN_CUSTOM_N, ++ NIOS2_BUILTIN_CUSTOM_NI, ++ NIOS2_BUILTIN_CUSTOM_NF, ++ NIOS2_BUILTIN_CUSTOM_NP, ++ NIOS2_BUILTIN_CUSTOM_NII, ++ NIOS2_BUILTIN_CUSTOM_NIF, ++ NIOS2_BUILTIN_CUSTOM_NIP, ++ NIOS2_BUILTIN_CUSTOM_NFI, ++ NIOS2_BUILTIN_CUSTOM_NFF, ++ NIOS2_BUILTIN_CUSTOM_NFP, ++ NIOS2_BUILTIN_CUSTOM_NPI, ++ NIOS2_BUILTIN_CUSTOM_NPF, ++ NIOS2_BUILTIN_CUSTOM_NPP, ++ NIOS2_BUILTIN_CUSTOM_IN, ++ NIOS2_BUILTIN_CUSTOM_INI, ++ NIOS2_BUILTIN_CUSTOM_INF, ++ NIOS2_BUILTIN_CUSTOM_INP, ++ NIOS2_BUILTIN_CUSTOM_INII, ++ NIOS2_BUILTIN_CUSTOM_INIF, ++ NIOS2_BUILTIN_CUSTOM_INIP, ++ NIOS2_BUILTIN_CUSTOM_INFI, ++ NIOS2_BUILTIN_CUSTOM_INFF, ++ NIOS2_BUILTIN_CUSTOM_INFP, ++ NIOS2_BUILTIN_CUSTOM_INPI, ++ NIOS2_BUILTIN_CUSTOM_INPF, ++ NIOS2_BUILTIN_CUSTOM_INPP, ++ NIOS2_BUILTIN_CUSTOM_FN, ++ NIOS2_BUILTIN_CUSTOM_FNI, ++ NIOS2_BUILTIN_CUSTOM_FNF, ++ NIOS2_BUILTIN_CUSTOM_FNP, ++ NIOS2_BUILTIN_CUSTOM_FNII, ++ NIOS2_BUILTIN_CUSTOM_FNIF, ++ NIOS2_BUILTIN_CUSTOM_FNIP, ++ NIOS2_BUILTIN_CUSTOM_FNFI, ++ NIOS2_BUILTIN_CUSTOM_FNFF, ++ NIOS2_BUILTIN_CUSTOM_FNFP, ++ NIOS2_BUILTIN_CUSTOM_FNPI, ++ NIOS2_BUILTIN_CUSTOM_FNPF, ++ NIOS2_BUILTIN_CUSTOM_FNPP, ++ NIOS2_BUILTIN_CUSTOM_PN, ++ NIOS2_BUILTIN_CUSTOM_PNI, ++ NIOS2_BUILTIN_CUSTOM_PNF, ++ NIOS2_BUILTIN_CUSTOM_PNP, ++ NIOS2_BUILTIN_CUSTOM_PNII, ++ NIOS2_BUILTIN_CUSTOM_PNIF, ++ NIOS2_BUILTIN_CUSTOM_PNIP, ++ NIOS2_BUILTIN_CUSTOM_PNFI, ++ NIOS2_BUILTIN_CUSTOM_PNFF, ++ NIOS2_BUILTIN_CUSTOM_PNFP, ++ NIOS2_BUILTIN_CUSTOM_PNPI, ++ NIOS2_BUILTIN_CUSTOM_PNPF, ++ NIOS2_BUILTIN_CUSTOM_PNPP, ++ ++ ++ LIM_NIOS2_BUILTINS ++}; ++ ++struct builtin_description ++{ ++ const enum insn_code icode; ++ const char *const name; ++ const enum nios2_builtins code; ++ const tree *type; ++ rtx (* expander) PARAMS ((const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int)); ++}; ++ ++static rtx nios2_expand_STXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_LDXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_sync (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_rdctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_wrctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static rtx nios2_expand_custom_n (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_Xn (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static tree endlink; ++ ++/* int fn (volatile const void *) ++ */ ++static tree int_ftype_volatile_const_void_p; ++ ++/* int fn (int) ++ */ ++static tree int_ftype_int; ++ ++/* void fn (int, int) ++ */ ++static tree void_ftype_int_int; ++ ++/* void fn (volatile void *, int) ++ */ ++static tree void_ftype_volatile_void_p_int; ++ ++/* void fn (void) ++ */ ++static tree void_ftype_void; ++ ++static tree custom_n; ++static tree custom_ni; ++static tree custom_nf; ++static tree custom_np; ++static tree custom_nii; ++static tree custom_nif; ++static tree custom_nip; ++static tree custom_nfi; ++static tree custom_nff; ++static tree custom_nfp; ++static tree custom_npi; ++static tree custom_npf; ++static tree custom_npp; ++static tree custom_in; ++static tree custom_ini; ++static tree custom_inf; ++static tree custom_inp; ++static tree custom_inii; ++static tree custom_inif; ++static tree custom_inip; ++static tree custom_infi; ++static tree custom_inff; ++static tree custom_infp; ++static tree custom_inpi; ++static tree custom_inpf; ++static tree custom_inpp; ++static tree custom_fn; ++static tree custom_fni; ++static tree custom_fnf; ++static tree custom_fnp; ++static tree custom_fnii; ++static tree custom_fnif; ++static tree custom_fnip; ++static tree custom_fnfi; ++static tree custom_fnff; ++static tree custom_fnfp; ++static tree custom_fnpi; ++static tree custom_fnpf; ++static tree custom_fnpp; ++static tree custom_pn; ++static tree custom_pni; ++static tree custom_pnf; ++static tree custom_pnp; ++static tree custom_pnii; ++static tree custom_pnif; ++static tree custom_pnip; ++static tree custom_pnfi; ++static tree custom_pnff; ++static tree custom_pnfp; ++static tree custom_pnpi; ++static tree custom_pnpf; ++static tree custom_pnpp; ++ ++ ++static const struct builtin_description bdesc[] = { ++ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ ++ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ ++ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync}, ++ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl}, ++ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl}, ++ ++ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n}, ++ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX}, ++ ++ ++ {0, 0, 0, 0, 0}, ++}; ++ ++/* This does not have a closing bracket on purpose (see use) */ ++#define def_param(TYPE) \ ++ tree_cons (NULL_TREE, TYPE, ++ ++static void ++nios2_init_builtins () ++{ ++ const struct builtin_description *d; ++ ++ ++ endlink = void_list_node; ++ ++ /* Special indenting here because one of the brackets is in def_param */ ++ /* *INDENT-OFF* */ ++ ++ /* int fn (volatile const void *) ++ */ ++ int_ftype_volatile_const_void_p ++ = build_function_type (integer_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) ++ endlink)); ++ ++ ++ /* void fn (volatile void *, int) ++ */ ++ void_ftype_volatile_void_p_int ++ = build_function_type (void_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_VOLATILE)) ++ def_param (integer_type_node) ++ endlink))); ++ ++ /* void fn (void) ++ */ ++ void_ftype_void ++ = build_function_type (void_type_node, ++ endlink); ++ ++ /* int fn (int) ++ */ ++ int_ftype_int ++ = build_function_type (integer_type_node, ++ def_param (integer_type_node) ++ endlink)); ++ ++ /* void fn (int, int) ++ */ ++ void_ftype_int_int ++ = build_function_type (void_type_node, ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink))); ++ ++ ++#define CUSTOM_NUM def_param (integer_type_node) ++ ++ custom_n ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ni ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_nf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_np ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_nii ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nif ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nip ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_nfi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nff ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nfp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_npi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_npf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_npp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_in ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ini ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_inf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_inp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_inii ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inif ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inip ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_infi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inff ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_infp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_inpi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inpf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inpp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_fn ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_fni ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_fnf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_fnp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_fnii ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnif ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnip ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnfi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnff ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnfp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnpi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnpf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnpp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ custom_pn ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_pni ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_pnf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_pnp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_pnii ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnif ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnip ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnfi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnff ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnfp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnpi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnpf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnpp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ ++ /* *INDENT-ON* */ ++ ++ ++ for (d = bdesc; d->name; d++) ++ { ++ builtin_function (d->name, *d->type, d->code, ++ BUILT_IN_MD, NULL, NULL); ++ } ++} ++ ++/* Expand an expression EXP that calls a built-in function, ++ with result going to TARGET if that's convenient ++ (and in mode MODE if that's convenient). ++ SUBTARGET may be used as the target for computing one of EXP's operands. ++ IGNORE is nonzero if the value is to be ignored. */ ++ ++static rtx ++nios2_expand_builtin (tree exp, rtx target, rtx subtarget, ++ enum machine_mode mode, int ignore) ++{ ++ const struct builtin_description *d; ++ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ ++ for (d = bdesc; d->name; d++) ++ if (d->code == fcode) ++ return (d->expander) (d, exp, target, subtarget, mode, ignore); ++ ++ /* we should have seen one of the functins we registered */ ++ abort (); ++} ++ ++static rtx nios2_create_target (const struct builtin_description *, rtx); ++ ++ ++static rtx ++nios2_create_target (const struct builtin_description *d, rtx target) ++{ ++ if (!target ++ || !(*insn_data[d->icode].operand[0].predicate) (target, ++ insn_data[d->icode].operand[0].mode)) ++ { ++ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); ++ } ++ ++ return target; ++} ++ ++ ++static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); ++static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree); ++ ++static rtx ++nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); ++ opcode = protect_from_queue (opcode, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) ++ error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name); ++ ++ return opcode; ++} ++ ++static rtx ++nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx operand = expand_expr (arg, NULL_RTX, mode, 0); ++ operand = protect_from_queue (operand, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ operand = copy_to_mode_reg (mode, operand); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ error ("Invalid argument %d to %s", argnum, d->name); ++ ++ return operand; ++} ++ ++ ++static rtx ++nios2_expand_custom_n (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_n should have exactly one operand */ ++ if (insn_data[d->icode].n_operands != 1) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ ++ pat = GEN_FCN (d->icode) (opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_Xn should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ pat = GEN_FCN (d->icode) (target, opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nX (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ ++ /* custom_nX should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ /* custom_Xn should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_nX should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_XnX should have exactly four operands */ ++ if (insn_data[d->icode].n_operands != 4) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++ ++static rtx ++nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx store_dest, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ store_dest = protect_from_queue (store_dest, 0); ++ ++ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (store_dest, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++static rtx ++nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx ld_src; ++ enum insn_code icode = d->icode; ++ ++ /* loads should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ld_src = protect_from_queue (ld_src, 0); ++ ++ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) ++ { ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, ld_src); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++static rtx ++nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ emit_insn (gen_sync ()); ++ return 0; ++} ++ ++static rtx ++nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx rdctl_reg; ++ enum insn_code icode = d->icode; ++ ++ /* rdctl should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ rdctl_reg = protect_from_queue (rdctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) ++ { ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, rdctl_reg); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx wrctl_reg, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ wrctl_reg = protect_from_queue (wrctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (wrctl_reg, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++#include "gt-nios2.h" ++ +--- gcc-3.4.3/gcc/config/nios2/nios2.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h +@@ -0,0 +1,824 @@ ++/* Definitions of target machine for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++ ++#define TARGET_CPU_CPP_BUILTINS() \ ++ do \ ++ { \ ++ builtin_define_std ("NIOS2"); \ ++ builtin_define_std ("nios2"); \ ++ builtin_define ("_GNU_SOURCE"); \ ++ } \ ++ while (0) ++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") ++ ++ ++ ++ ++ ++/********************************* ++ * Run-time Target Specification ++ *********************************/ ++ ++#define HAS_DIV_FLAG 0x0001 ++#define HAS_MUL_FLAG 0x0002 ++#define HAS_MULX_FLAG 0x0004 ++#define FAST_SW_DIV_FLAG 0x0008 ++#define INLINE_MEMCPY_FLAG 0x00010 ++#define CACHE_VOLATILE_FLAG 0x0020 ++#define BYPASS_CACHE_FLAG 0x0040 ++ ++extern int target_flags; ++#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG) ++#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG) ++#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG) ++#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG) ++#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG) ++#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG) ++#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG) ++ ++#define TARGET_SWITCHES \ ++{ \ ++ { "hw-div", HAS_DIV_FLAG, \ ++ N_("Enable DIV, DIVU") }, \ ++ { "no-hw-div", -HAS_DIV_FLAG, \ ++ N_("Disable DIV, DIVU (default)") }, \ ++ { "hw-mul", HAS_MUL_FLAG, \ ++ N_("Enable MUL instructions (default)") }, \ ++ { "hw-mulx", HAS_MULX_FLAG, \ ++ N_("Enable MULX instructions, assume fast shifter") }, \ ++ { "no-hw-mul", -HAS_MUL_FLAG, \ ++ N_("Disable MUL instructions") }, \ ++ { "no-hw-mulx", -HAS_MULX_FLAG, \ ++ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \ ++ { "fast-sw-div", FAST_SW_DIV_FLAG, \ ++ N_("Use table based fast divide (default at -O3)") }, \ ++ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \ ++ N_("Don't use table based fast divide ever") }, \ ++ { "inline-memcpy", INLINE_MEMCPY_FLAG, \ ++ N_("Inline small memcpy (default when optimizing)") }, \ ++ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \ ++ N_("Don't Inline small memcpy") }, \ ++ { "cache-volatile", CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use non-io variants of instructions (default)") }, \ ++ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use io variants of instructions") }, \ ++ { "bypass-cache", BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins use io variants") }, \ ++ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins do not use io variants (default)") }, \ ++ { "smallc", 0, \ ++ N_("Link with a limited version of the C library") }, \ ++ { "ctors-in-init", 0, \ ++ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \ ++ { "", TARGET_DEFAULT, 0 } \ ++} ++ ++ ++extern const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++extern const char *nios2_sys_lib_string; /* for -msys-lib= */ ++extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++#define TARGET_OPTIONS \ ++{ \ ++ { "sys=nosys", &nios2_sys_nosys_string, \ ++ N_("Use stub versions of OS library calls (default)"), 0}, \ ++ { "sys-lib=", &nios2_sys_lib_string, \ ++ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \ ++ { "sys-crt0=", &nios2_sys_crt0_string, \ ++ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \ ++} ++ ++ ++/* Default target_flags if no switches specified. */ ++#ifndef TARGET_DEFAULT ++# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG) ++#endif ++ ++/* Switch Recognition by gcc.c. Add -G xx support */ ++#undef SWITCH_TAKES_ARG ++#define SWITCH_TAKES_ARG(CHAR) \ ++ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') ++ ++#define OVERRIDE_OPTIONS override_options () ++#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) ++#define CAN_DEBUG_WITHOUT_FP ++ ++#define CC1_SPEC "\ ++%{G*}" ++ ++#undef LIB_SPEC ++#define LIB_SPEC \ ++"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \ ++ %{msys-lib=*: -l%*} \ ++ %{!msys-lib=*: -lc } \ ++ --end-group \ ++ %{msys-lib=: %eYou need a library name for -msys-lib=} \ ++" ++ ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC \ ++"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \ ++ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \ ++ %{mctors-in-init: crti%O%s crtbegin%O%s} \ ++" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++ "%{mctors-in-init: crtend%O%s crtn%O%s}" ++ ++ ++/*********************** ++ * Storage Layout ++ ***********************/ ++ ++#define DEFAULT_SIGNED_CHAR 1 ++#define BITS_BIG_ENDIAN 0 ++#define BYTES_BIG_ENDIAN 0 ++#define WORDS_BIG_ENDIAN 0 ++#define BITS_PER_UNIT 8 ++#define BITS_PER_WORD 32 ++#define UNITS_PER_WORD 4 ++#define POINTER_SIZE 32 ++#define BIGGEST_ALIGNMENT 32 ++#define STRICT_ALIGNMENT 1 ++#define FUNCTION_BOUNDARY 32 ++#define PARM_BOUNDARY 32 ++#define STACK_BOUNDARY 32 ++#define PREFERRED_STACK_BOUNDARY 32 ++#define MAX_FIXED_MODE_SIZE 64 ++ ++#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ ++ ((TREE_CODE (EXP) == STRING_CST) \ ++ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) ++ ++ ++/********************** ++ * Layout of Source Language Data Types ++ **********************/ ++ ++#define INT_TYPE_SIZE 32 ++#define SHORT_TYPE_SIZE 16 ++#define LONG_TYPE_SIZE 32 ++#define LONG_LONG_TYPE_SIZE 64 ++#define FLOAT_TYPE_SIZE 32 ++#define DOUBLE_TYPE_SIZE 64 ++#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE ++ ++ ++/************************* ++ * Condition Code Status ++ ************************/ ++ ++/* comparison type */ ++/* ??? currently only CMP_SI is used */ ++enum cmp_type { ++ CMP_SI, /* compare four byte integers */ ++ CMP_DI, /* compare eight byte integers */ ++ CMP_SF, /* compare single precision floats */ ++ CMP_DF, /* compare double precision floats */ ++ CMP_MAX /* max comparison type */ ++}; ++ ++extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ ++extern enum cmp_type branch_type; /* what type of branch to use */ ++ ++/********************** ++ * Register Usage ++ **********************/ ++ ++/* ---------------------------------- * ++ * Basic Characteristics of Registers ++ * ---------------------------------- */ ++ ++/* ++Register Number ++ Register Name ++ Alternate Name ++ Purpose ++0 r0 zero always zero ++1 r1 at Assembler Temporary ++2-3 r2-r3 Return Location ++4-7 r4-r7 Register Arguments ++8-15 r8-r15 Caller Saved Registers ++16-22 r16-r22 Callee Saved Registers ++23 r23 sc Static Chain (Callee Saved) ++ ??? Does $sc want to be caller or callee ++ saved. If caller, 15, else 23. ++24 r24 Exception Temporary ++25 r25 Breakpoint Temporary ++26 r26 gp Global Pointer ++27 r27 sp Stack Pointer ++28 r28 fp Frame Pointer ++29 r29 ea Exception Return Address ++30 r30 ba Breakpoint Return Address ++31 r31 ra Return Address ++ ++32 ctl0 status ++33 ctl1 estatus STATUS saved by exception ? ++34 ctl2 bstatus STATUS saved by break ? ++35 ctl3 ipri Interrupt Priority Mask ? ++36 ctl4 ecause Exception Cause ? ++ ++37 pc Not an actual register ++ ++38 rap Return address pointer, this does not ++ actually exist and will be eliminated ++ ++39 fake_fp Fake Frame Pointer which will always be eliminated. ++40 fake_ap Fake Argument Pointer which will always be eliminated. ++ ++41 First Pseudo Register ++ ++ ++The definitions for all the hard register numbers ++are located in nios2.md. ++*/ ++ ++#define FIRST_PSEUDO_REGISTER 41 ++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) ++ ++ ++ ++/* also see CONDITIONAL_REGISTER_USAGE */ ++#define FIXED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++/* call used is the same as caller saved ++ + fixed regs + args + ret vals */ ++#define CALL_USED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++/* --------------------------- * ++ * How Values Fit in Registers ++ * --------------------------- */ ++ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++ ++#define MODES_TIEABLE_P(MODE1, MODE2) 1 ++ ++ ++/************************* ++ * Register Classes ++ *************************/ ++ ++enum reg_class ++{ ++ NO_REGS, ++ ALL_REGS, ++ LIM_REG_CLASSES ++}; ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++ ++#define REG_CLASS_NAMES \ ++ {"NO_REGS", \ ++ "ALL_REGS"} ++ ++#define GENERAL_REGS ALL_REGS ++ ++#define REG_CLASS_CONTENTS \ ++/* NO_REGS */ {{ 0, 0}, \ ++/* ALL_REGS */ {~0,~0}} \ ++ ++#define REGNO_REG_CLASS(REGNO) ALL_REGS ++ ++#define BASE_REG_CLASS ALL_REGS ++#define INDEX_REG_CLASS ALL_REGS ++ ++/* only one reg class, 'r', is handled automatically */ ++#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS ++ ++#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ ++ ((STRICT) \ ++ ? (REGNO) < FIRST_PSEUDO_REGISTER \ ++ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) ++ ++#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) ++ ++#define REGNO_OK_FOR_BASE_P(REGNO) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) ++ ++#define REGNO_OK_FOR_INDEX_P(REGNO) \ ++ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) ++ ++#define REG_OK_FOR_BASE_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define REG_OK_FOR_INDEX_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++ ++#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) ++#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) ++#define UPPER16_INT(X) (((X) & 0xffff) == 0) ++#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) ++#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) ++#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ( \ ++ (C) == 'I' ? SMALL_INT (VALUE) : \ ++ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ ++ (C) == 'K' ? UPPER16_INT (VALUE) : \ ++ (C) == 'L' ? SHIFT_INT (VALUE) : \ ++ (C) == 'M' ? (VALUE) == 0 : \ ++ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ ++ (C) == 'O' ? RDWRCTL_INT (VALUE) : \ ++ 0) ++ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 ++ ++#define PREFERRED_RELOAD_CLASS(X, CLASS) \ ++ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) ++ ++/* 'S' matches immediates which are in small data ++ and therefore can be added to gp to create a ++ 32-bit value. */ ++#define EXTRA_CONSTRAINT(VALUE, C) \ ++ ((C) == 'S' \ ++ && (GET_CODE (VALUE) == SYMBOL_REF) \ ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) ++ ++ ++ ++ ++/* Say that the epilogue uses the return address register. Note that ++ in the case of sibcalls, the values "used by the epilogue" are ++ considered live at the start of the called function. */ ++#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) ++ ++ ++#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) ++ ++/********************************** ++ * Trampolines for Nested Functions ++ ***********************************/ ++ ++#define TRAMPOLINE_TEMPLATE(FILE) \ ++ error ("trampolines not yet implemented") ++#define TRAMPOLINE_SIZE 20 ++#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ ++ error ("trampolines not yet implemented") ++ ++/*************************** ++ * Stack Layout and Calling Conventions ++ ***************************/ ++ ++/* ------------------ * ++ * Basic Stack Layout ++ * ------------------ */ ++ ++/* The downward variants are used by the compiler, ++ the upward ones serve as documentation */ ++#define STACK_GROWS_DOWNWARD ++#define FRAME_GROWS_UPWARD ++#define ARGS_GROW_UPWARD ++ ++#define STARTING_FRAME_OFFSET current_function_outgoing_args_size ++#define FIRST_PARM_OFFSET(FUNDECL) 0 ++ ++/* Before the prologue, RA lives in r31. */ ++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) ++ ++/* -------------------------------------- * ++ * Registers That Address the Stack Frame ++ * -------------------------------------- */ ++ ++#define STACK_POINTER_REGNUM SP_REGNO ++#define STATIC_CHAIN_REGNUM SC_REGNO ++#define PC_REGNUM PC_REGNO ++#define DWARF_FRAME_RETURN_COLUMN RA_REGNO ++ ++/* Base register for access to local variables of the function. We ++ pretend that the frame pointer is a non-existent hard register, and ++ then eliminate it to HARD_FRAME_POINTER_REGNUM. */ ++#define FRAME_POINTER_REGNUM FAKE_FP_REGNO ++ ++#define HARD_FRAME_POINTER_REGNUM FP_REGNO ++#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO ++/* the argumnet pointer needs to always be eliminated ++ so it is set to a fake hard register. */ ++#define ARG_POINTER_REGNUM FAKE_AP_REGNO ++ ++/* ----------------------------------------- * ++ * Eliminating Frame Pointer and Arg Pointer ++ * ----------------------------------------- */ ++ ++#define FRAME_POINTER_REQUIRED 0 ++ ++#define ELIMINABLE_REGS \ ++{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} ++ ++#define CAN_ELIMINATE(FROM, TO) 1 ++ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) ++ ++#define MUST_SAVE_REGISTER(regno) \ ++ ((regs_ever_live[regno] && !call_used_regs[regno]) \ ++ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ ++ || (regno == RA_REGNO && regs_ever_live[RA_REGNO])) ++ ++/* Treat LOC as a byte offset from the stack pointer and round it up ++ to the next fully-aligned offset. */ ++#define STACK_ALIGN(LOC) \ ++ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) ++ ++ ++/* ------------------------------ * ++ * Passing Arguments in Registers ++ * ------------------------------ */ ++ ++/* see nios2.c */ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ (function_arg (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0 ++ ++#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 ++ ++typedef struct nios2_args ++{ ++ int regs_used; ++} CUMULATIVE_ARGS; ++ ++/* This is to initialize the above unused CUM data type */ ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ ++ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) ++ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_advance (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_REGNO_P(REGNO) \ ++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) ++ ++#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ ++ { \ ++ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \ ++ (TYPE), (NO_RTL)); \ ++ if (pret_size) \ ++ (PRETEND_SIZE) = pret_size; \ ++ } ++ ++/* ----------------------------- * ++ * Generating Code for Profiling ++ * ----------------------------- */ ++ ++#define PROFILE_BEFORE_PROLOGUE ++ ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ function_profiler ((FILE), (LABELNO)) ++ ++/* --------------------------------------- * ++ * Passing Function Arguments on the Stack ++ * --------------------------------------- */ ++ ++#define PROMOTE_PROTOTYPES 1 ++ ++#define PUSH_ARGS 0 ++#define ACCUMULATE_OUTGOING_ARGS 1 ++ ++#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 ++ ++/* --------------------------------------- * ++ * How Scalar Function Values Are Returned ++ * --------------------------------------- */ ++ ++#define FUNCTION_VALUE(VALTYPE, FUNC) \ ++ gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) ++ ++#define LIBCALL_VALUE(MODE) \ ++ gen_rtx(REG, MODE, FIRST_RETVAL_REGNO) ++ ++#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) ++ ++/* ----------------------------- * ++ * How Large Values Are Returned ++ * ----------------------------- */ ++ ++ ++#define RETURN_IN_MEMORY(TYPE) \ ++ nios2_return_in_memory (TYPE) ++ ++ ++#define STRUCT_VALUE 0 ++ ++#define DEFAULT_PCC_STRUCT_RETURN 0 ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++ ++#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) ++ ++#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) ++ ++#define MAX_REGS_PER_ADDRESS 1 ++ ++/* Go to ADDR if X is a valid address. */ ++#ifndef REG_OK_STRICT ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 0)) \ ++ goto ADDR; \ ++ } ++#else ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 1)) \ ++ goto ADDR; \ ++ } ++#endif ++ ++#ifndef REG_OK_STRICT ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) ++#else ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) ++#endif ++ ++#define LEGITIMATE_CONSTANT_P(X) 1 ++ ++/* Nios II has no mode dependent addresses. */ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) ++ ++/* Set if this has a weak declaration */ ++#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) ++#define SYMBOL_REF_WEAK_DECL_P(RTX) \ ++ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) ++ ++ ++/* true if a symbol is both small and not weak. In this case, gp ++ relative access can be used */ ++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ ++ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX)) ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++#define SLOW_BYTE_ACCESS 1 ++ ++/* It is as good to call a constant function address as to call an address ++ kept in a register. ++ ??? Not true anymore really. Now that call cannot address full range ++ of memory callr may need to be used */ ++ ++#define NO_FUNCTION_CSE ++#define NO_RECURSIVE_FUNCTION_CSE ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* ------------------------------------------ * ++ * The Overall Framework of an Assembler File ++ * ------------------------------------------ */ ++ ++#define ASM_APP_ON "#APP\n" ++#define ASM_APP_OFF "#NO_APP\n" ++ ++#define ASM_COMMENT_START "# " ++ ++/* ------------------------------- * ++ * Output and Generation of Labels ++ * ------------------------------- */ ++ ++#define GLOBAL_ASM_OP "\t.global\t" ++ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++#define DWARF2_UNWIND_INFO 0 ++ ++ ++/* -------------------------------- * ++ * Assembler Commands for Alignment ++ * -------------------------------- */ ++ ++#define ASM_OUTPUT_ALIGN(FILE, LOG) \ ++ do { \ ++ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ ++ } while (0) ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++#define REGISTER_NAMES \ ++{ \ ++ "zero", \ ++ "at", \ ++ "r2", \ ++ "r3", \ ++ "r4", \ ++ "r5", \ ++ "r6", \ ++ "r7", \ ++ "r8", \ ++ "r9", \ ++ "r10", \ ++ "r11", \ ++ "r12", \ ++ "r13", \ ++ "r14", \ ++ "r15", \ ++ "r16", \ ++ "r17", \ ++ "r18", \ ++ "r19", \ ++ "r20", \ ++ "r21", \ ++ "r22", \ ++ "r23", \ ++ "r24", \ ++ "r25", \ ++ "gp", \ ++ "sp", \ ++ "fp", \ ++ "ta", \ ++ "ba", \ ++ "ra", \ ++ "status", \ ++ "estatus", \ ++ "bstatus", \ ++ "ipri", \ ++ "ecause", \ ++ "pc", \ ++ "rap", \ ++ "fake_fp", \ ++ "fake_ap", \ ++} ++ ++#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ ++ (PTR) = asm_output_opcode (STREAM, PTR) ++ ++#define PRINT_OPERAND(STREAM, X, CODE) \ ++ nios2_print_operand (STREAM, X, CODE) ++ ++#define PRINT_OPERAND_ADDRESS(STREAM, X) \ ++ nios2_print_operand_address (STREAM, X) ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ ++do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ ++ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ ++ } while (0) ++ ++ ++/* ------------ * ++ * Label Output ++ * ------------ */ ++ ++ ++/* ---------------------------------------------------- * ++ * Dividing the Output into Sections (Texts, Data, ...) ++ * ---------------------------------------------------- */ ++ ++/* Output before read-only data. */ ++#define TEXT_SECTION_ASM_OP ("\t.section\t.text") ++ ++/* Output before writable data. */ ++#define DATA_SECTION_ASM_OP ("\t.section\t.data") ++ ++ ++/* Default the definition of "small data" to 8 bytes. */ ++/* ??? How come I can't use HOST_WIDE_INT here? */ ++extern unsigned long nios2_section_threshold; ++#define NIOS2_DEFAULT_GVALUE 8 ++ ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized external linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef COMMON_ASM_OP ++#define COMMON_ASM_OP "\t.comm\t" ++ ++#undef ASM_OUTPUT_ALIGNED_COMMON ++#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ ++do \ ++{ \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ { \ ++ named_section (0, ".sbss", 0); \ ++ (*targetm.asm_out.globalize_label) (FILE, NAME); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++ } \ ++ else \ ++ { \ ++ fprintf ((FILE), "%s", COMMON_ASM_OP); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ ++ } \ ++} \ ++while (0) ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized internal linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef ASM_OUTPUT_ALIGNED_LOCAL ++#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ ++do { \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ named_section (0, ".sbss", 0); \ ++ else \ ++ named_section (0, ".bss", 0); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++} while (0) ++ ++ ++ ++/*************************** ++ * Miscellaneous Parameters ++ ***************************/ ++ ++#define MOVE_MAX 4 ++ ++#define Pmode SImode ++#define FUNCTION_MODE QImode ++ ++#define CASE_VECTOR_MODE Pmode ++ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++ ++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) ++ ++#define WORD_REGISTER_OPERATIONS +--- gcc-3.4.3/gcc/config/nios2/nios2.md ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md +@@ -0,0 +1,2078 @@ ++;; Machine Description for Altera NIOS 2G NIOS2 version. ++;; Copyright (C) 2003 Altera ++;; Contributed by Jonah Graham (jgraham@altera.com). ++;; ++;; This file is part of GNU CC. ++;; ++;; GNU CC is free software; you can redistribute it and/or modify ++;; it under the terms of the GNU General Public License as published by ++;; the Free Software Foundation; either version 2, or (at your option) ++;; any later version. ++;; ++;; GNU CC is distributed in the hope that it will be useful, ++;; but WITHOUT ANY WARRANTY; without even the implied warranty of ++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++;; GNU General Public License for more details. ++;; ++;; You should have received a copy of the GNU General Public License ++;; along with GNU CC; see the file COPYING. If not, write to ++;; the Free Software Foundation, 59 Temple Place - Suite 330, ++;; Boston, MA 02111-1307, USA. */ ++ ++ ++ ++;***************************************************************************** ++;* ++;* constants ++;* ++;***************************************************************************** ++(define_constants [ ++ (GP_REGNO 26) ++ (SP_REGNO 27) ++ (FP_REGNO 28) ++ (RA_REGNO 31) ++ (RAP_REGNO 38) ++ (FIRST_RETVAL_REGNO 2) ++ (LAST_RETVAL_REGNO 3) ++ (FIRST_ARG_REGNO 4) ++ (LAST_ARG_REGNO 7) ++ (SC_REGNO 23) ++ (PC_REGNO 37) ++ (FAKE_FP_REGNO 39) ++ (FAKE_AP_REGNO 40) ++ ++ ++ (UNSPEC_BLOCKAGE 0) ++ (UNSPEC_LDBIO 1) ++ (UNSPEC_LDBUIO 2) ++ (UNSPEC_LDHIO 3) ++ (UNSPEC_LDHUIO 4) ++ (UNSPEC_LDWIO 5) ++ (UNSPEC_STBIO 6) ++ (UNSPEC_STHIO 7) ++ (UNSPEC_STWIO 8) ++ (UNSPEC_SYNC 9) ++ (UNSPEC_WRCTL 10) ++ (UNSPEC_RDCTL 11) ++ ++]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* instruction scheduler ++;* ++;***************************************************************************** ++ ++; No schedule info is currently available, using an assumption that no ++; instruction can use the results of the previous instruction without ++; incuring a stall. ++ ++; length of an instruction (in bytes) ++(define_attr "length" "" (const_int 4)) ++(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex")) ++ ++(define_asm_attributes ++ [(set_attr "length" "4") ++ (set_attr "type" "complex")]) ++ ++(define_automaton "nios2") ++(automata_option "v") ++;(automata_option "no-minimization") ++(automata_option "ndfa") ++ ++; The nios2 pipeline is fairly straightforward for the fast model. ++; Every alu operation is pipelined so that an instruction can ++; be issued every cycle. However, there are still potential ++; stalls which this description tries to deal with. ++ ++(define_cpu_unit "cpu" "nios2") ++ ++(define_insn_reservation "complex" 1 ++ (eq_attr "type" "complex") ++ "cpu") ++ ++(define_insn_reservation "control" 1 ++ (eq_attr "type" "control") ++ "cpu") ++ ++(define_insn_reservation "alu" 1 ++ (eq_attr "type" "alu") ++ "cpu") ++ ++(define_insn_reservation "cond_alu" 1 ++ (eq_attr "type" "cond_alu") ++ "cpu") ++ ++(define_insn_reservation "st" 1 ++ (eq_attr "type" "st") ++ "cpu") ++ ++(define_insn_reservation "custom" 1 ++ (eq_attr "type" "custom") ++ "cpu") ++ ++; shifts, muls and lds have three cycle latency ++(define_insn_reservation "ld" 3 ++ (eq_attr "type" "ld") ++ "cpu") ++ ++(define_insn_reservation "shift" 3 ++ (eq_attr "type" "shift") ++ "cpu") ++ ++(define_insn_reservation "mul" 3 ++ (eq_attr "type" "mul") ++ "cpu") ++ ++(define_insn_reservation "div" 1 ++ (eq_attr "type" "div") ++ "cpu") ++ ++ ++;***************************************************************************** ++;* ++;* MOV Instructions ++;* ++;***************************************************************************** ++ ++(define_expand "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (match_operand:QI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, QImode)) ++ DONE; ++}) ++ ++(define_insn "movqi_internal" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") ++ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] ++ "(register_operand (operands[0], QImode) ++ || register_operand (operands[1], QImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stb%o0\\t%z1, %0 ++ ldbu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu")]) ++ ++(define_insn "ldbio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldbuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stbio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] ++ "" ++ "stbio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, HImode)) ++ DONE; ++}) ++ ++(define_insn "movhi_internal" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") ++ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] ++ "(register_operand (operands[0], HImode) ++ || register_operand (operands[1], HImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ sth%o0\\t%z1, %0 ++ ldhu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu,alu")]) ++ ++(define_insn "ldhio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldhuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "sthio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] ++ "" ++ "sthio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++(define_expand "movsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (match_operand:SI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, SImode)) ++ DONE; ++}) ++ ++(define_insn "movsi_internal" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") ++ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] ++ "(register_operand (operands[0], SImode) ++ || register_operand (operands[1], SImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stw%o0\\t%z1, %0 ++ ldw%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1 ++ addi\\t%0, gp, %%gprel(%1) ++ movhi\\t%0, %H1\;addi\\t%0, %0, %L1" ++ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) ++ ++(define_insn "ldwio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldwio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stwio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] ++ "" ++ "stwio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* zero extension ++;* ++;***************************************************************************** ++ ++ ++(define_insn "zero_extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xffff ++ ldhu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=r,r") ++ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* sign extension ++;* ++;***************************************************************************** ++ ++(define_expand "extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (16); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendhisi2_internal" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ++ "" ++ "ldh%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_expand "extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op0 = gen_lowpart (SImode, operands[0]); ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (op0, temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqihi2_internal" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++(define_expand "extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqisi2_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Arithmetic Operations ++;* ++;***************************************************************************** ++ ++(define_insn "addsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (plus:SI (match_operand:SI 1 "register_operand" "%r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "" ++ "add%i2\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "subsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++ "sub\\t%0, %z1, %2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "mulsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (mult:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "TARGET_HAS_MUL" ++ "mul%i2\\t%0, %1, %z2" ++ [(set_attr "type" "mul")]) ++ ++(define_expand "divsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++{ ++ if (!TARGET_HAS_DIV) ++ { ++ if (!TARGET_FAST_SW_DIV) ++ FAIL; ++ else ++ { ++ if (nios2_emit_expensive_div (operands, SImode)) ++ DONE; ++ } ++ } ++}) ++ ++(define_insn "divsi3_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "div\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "udivsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (udiv:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "divu\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "smulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxss\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++(define_insn "umulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxuu\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++ ++(define_expand "mulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) ++ (sign_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++(define_expand "umulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) ++ (zero_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++ ++ ++;***************************************************************************** ++;* ++;* Negate and ones complement ++;* ++;***************************************************************************** ++ ++(define_insn "negsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (neg:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "sub\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++(define_insn "one_cmplsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (not:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "nor\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++ ++ ++; Logical Operantions ++ ++(define_insn "andsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ and\\t%0, %1, %z2 ++ and%i2\\t%0, %1, %2 ++ andh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "iorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ or\\t%0, %1, %z2 ++ or%i2\\t%0, %1, %2 ++ orh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "*norsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) ++ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] ++ "" ++ "nor\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "xorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ xor\\t%0, %1, %z2 ++ xor%i2\\t%0, %1, %2 ++ xorh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Shifts ++;* ++;***************************************************************************** ++ ++(define_insn "ashlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashift:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sll%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "ashrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sra%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "lshrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "srl%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotate:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "rol%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "register_operand" "r,r")))] ++ "" ++ "ror\\t%0, %1, %2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "*shift_mul_constants" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "const_int_operand" "I")) ++ (match_operand:SI 3 "const_int_operand" "I")))] ++ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" ++{ ++ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); ++ rtx ops[3]; ++ ++ ops[0] = operands[0]; ++ ops[1] = operands[1]; ++ ops[2] = GEN_INT (mul); ++ ++ output_asm_insn ("muli\t%0, %1, %2", ops); ++ return ""; ++} ++ [(set_attr "type" "mul")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Prologue, Epilogue and Return ++;* ++;***************************************************************************** ++ ++(define_expand "prologue" ++ [(const_int 1)] ++ "" ++{ ++ expand_prologue (); ++ DONE; ++}) ++ ++(define_expand "epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (false); ++ DONE; ++}) ++ ++(define_expand "sibcall_epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (true); ++ DONE; ++}) ++ ++(define_insn "return" ++ [(return)] ++ "reload_completed && nios2_can_use_return_insn ()" ++ "ret\\t" ++) ++ ++(define_insn "return_from_epilogue" ++ [(use (match_operand 0 "pmode_register_operand" "")) ++ (return)] ++ "reload_completed" ++ "ret\\t" ++) ++ ++;; Block any insns from being moved before this point, since the ++;; profiling call to mcount can use various registers that aren't ++;; saved or used to pass arguments. ++ ++(define_insn "blockage" ++ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] ++ "" ++ "" ++ [(set_attr "type" "unknown") ++ (set_attr "length" "0")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Jumps and Calls ++;* ++;***************************************************************************** ++ ++(define_insn "indirect_jump" ++ [(set (pc) (match_operand:SI 0 "register_operand" "r"))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "jump" ++ [(set (pc) ++ (label_ref (match_operand 0 "" "")))] ++ "" ++ "br\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "indirect_call" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "indirect_call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%1" ++) ++ ++(define_expand "call" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_expand "call_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_insn "*call" ++ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) ++ (match_operand 1 "" "")) ++ (clobber (match_operand:SI 2 "register_operand" "=r"))] ++ "" ++ "call\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "*call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) ++ (match_operand 2 "" ""))) ++ (clobber (match_operand:SI 3 "register_operand" "=r"))] ++ "" ++ "call\\t%1" ++ [(set_attr "type" "control")]) ++ ++(define_expand "sibcall" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))])] ++ "" ++ { ++ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); ++ ++ if (operands[2] == NULL_RTX) ++ operands[2] = const0_rtx; ++ } ++) ++ ++(define_expand "sibcall_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))])] ++ "" ++ { ++ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); ++ ++ if (operands[3] == NULL_RTX) ++ operands[3] = const0_rtx; ++ } ++) ++ ++(define_insn "sibcall_insn" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))] ++ "" ++ "jmp\\t%0" ++) ++ ++(define_insn "sibcall_value_insn" ++ [(set (match_operand 0 "register_operand" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))] ++ "" ++ "jmp\\t%1" ++) ++ ++ ++ ++ ++(define_expand "tablejump" ++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))])] ++ "" ++ "" ++) ++ ++(define_insn "*tablejump" ++ [(set (pc) ++ (match_operand:SI 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Comparisons ++;* ++;***************************************************************************** ++;; Flow here is rather complex (based on MIPS): ++;; ++;; 1) The cmp{si,di,sf,df} routine is called. It deposits the ++;; arguments into the branch_cmp array, and the type into ++;; branch_type. No RTL is generated. ++;; ++;; 2) The appropriate branch define_expand is called, which then ++;; creates the appropriate RTL for the comparison and branch. ++;; Different CC modes are used, based on what type of branch is ++;; done, so that we can constrain things appropriately. There ++;; are assumptions in the rest of GCC that break if we fold the ++;; operands into the branchs for integer operations, and use cc0 ++;; for floating point, so we use the fp status register instead. ++;; If needed, an appropriate temporary is created to hold the ++;; of the integer compare. ++ ++(define_expand "cmpsi" ++ [(set (cc0) ++ (compare:CC (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "arith_operand" "")))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++(define_expand "tstsi" ++ [(set (cc0) ++ (match_operand:SI 0 "register_operand" ""))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = const0_rtx; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* setting a register from a comparison ++;* ++;***************************************************************************** ++ ++(define_expand "seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpeq%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpne%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmplt\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpge%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpge\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmplt%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpltu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpgeu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpgeu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpltu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* branches ++;* ++;***************************************************************************** ++ ++(define_insn "*cbranch" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:SI 2 "reg_or_0_operand" "rM") ++ (match_operand:SI 3 "reg_or_0_operand" "rM")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ "b%0\\t%z2, %z3, %l1" ++ [(set_attr "type" "control")]) ++ ++ ++(define_expand "beq" ++ [(set (pc) ++ (if_then_else (eq:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bne" ++ [(set (pc) ++ (if_then_else (ne:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgt" ++ [(set (pc) ++ (if_then_else (gt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bge" ++ [(set (pc) ++ (if_then_else (ge:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "ble" ++ [(set (pc) ++ (if_then_else (le:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "blt" ++ [(set (pc) ++ (if_then_else (lt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgtu" ++ [(set (pc) ++ (if_then_else (gtu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bgeu" ++ [(set (pc) ++ (if_then_else (geu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bleu" ++ [(set (pc) ++ (if_then_else (leu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bltu" ++ [(set (pc) ++ (if_then_else (ltu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* String and Block Operations ++;* ++;***************************************************************************** ++ ++; ??? This is all really a hack to get Dhrystone to work as fast as possible ++; things to be fixed: ++; * let the compiler core handle all of this, for that to work the extra ++; aliasing needs to be addressed. ++; * we use three temporary registers for loading and storing to ensure no ++; ld use stalls, this is excessive, because after the first ld/st only ++; two are needed. Only two would be needed all the way through if ++; we could schedule with other code. Consider: ++; 1 ld $1, 0($src) ++; 2 ld $2, 4($src) ++; 3 ld $3, 8($src) ++; 4 st $1, 0($dest) ++; 5 ld $1, 12($src) ++; 6 st $2, 4($src) ++; 7 etc. ++; The first store has to wait until 4. If it does not there will be one ++; cycle of stalling. However, if any other instruction could be placed ++; between 1 and 4, $3 would not be needed. ++; * In small we probably don't want to ever do this ourself because there ++; is no ld use stall. ++ ++(define_expand "movstrsi" ++ [(parallel [(set (match_operand:BLK 0 "general_operand" "") ++ (match_operand:BLK 1 "general_operand" "")) ++ (use (match_operand:SI 2 "const_int_operand" "")) ++ (use (match_operand:SI 3 "const_int_operand" "")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))])] ++ "TARGET_INLINE_MEMCPY" ++{ ++ rtx ld_addr_reg, st_addr_reg; ++ ++ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr ++ it trys to copy to a register, but does not re-try the predicate. ++ ??? Intead of fixing expr.c, I fix it here. */ ++ if (!const_int_operand (operands[2], SImode)) ++ FAIL; ++ ++ /* ??? there are some magic numbers which need to be sorted out here. ++ the basis for them is not increasing code size hugely or going ++ out of range of offset addressing */ ++ if (INTVAL (operands[3]) < 4) ++ FAIL; ++ if (!optimize ++ || (optimize_size && INTVAL (operands[2]) > 12) ++ || (optimize < 3 && INTVAL (operands[2]) > 100) ++ || INTVAL (operands[2]) > 200) ++ FAIL; ++ ++ st_addr_reg ++ = replace_equiv_address (operands[0], ++ copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); ++ ld_addr_reg ++ = replace_equiv_address (operands[1], ++ copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); ++ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, ++ operands[2], operands[3])); ++ ++ DONE; ++}) ++ ++ ++(define_insn "movstrsi_internal" ++ [(set (match_operand:BLK 0 "memory_operand" "=o") ++ (match_operand:BLK 1 "memory_operand" "o")) ++ (use (match_operand:SI 2 "const_int_operand" "i")) ++ (use (match_operand:SI 3 "const_int_operand" "i")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))] ++ "TARGET_INLINE_MEMCPY" ++{ ++ int ld_offset = INTVAL (operands[2]); ++ int ld_len = INTVAL (operands[2]); ++ int ld_reg = 0; ++ rtx ld_addr_reg = XEXP (operands[1], 0); ++ int st_offset = INTVAL (operands[2]); ++ int st_len = INTVAL (operands[2]); ++ int st_reg = 0; ++ rtx st_addr_reg = XEXP (operands[0], 0); ++ int delay_count = 0; ++ ++ /* ops[0] is the address used by the insn ++ ops[1] is the register being loaded or stored */ ++ rtx ops[2]; ++ ++ if (INTVAL (operands[3]) < 4) ++ abort (); ++ ++ while (ld_offset >= 4) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldw\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 4; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 2) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldh\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 2; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 1) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldb\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 1; ++ delay_count++; ++ } ++ ++ while (st_offset >= 4) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ while (st_offset >= 2) ++ { ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("sth\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 2; ++ } ++ ++ while (st_offset >= 1) ++ { ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stb\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 1; ++ } ++ ++ return ""; ++} ++; ??? lengths are not being used yet, but I will probably forget ++; to update this once I am using lengths, so set it to something ++; definetely big enough to cover it. 400 allows for 200 bytes ++; of motion. ++ [(set_attr "length" "400")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Custom instructions ++;* ++;***************************************************************************** ++ ++(define_constants [ ++ (CUSTOM_N 100) ++ (CUSTOM_NI 101) ++ (CUSTOM_NF 102) ++ (CUSTOM_NP 103) ++ (CUSTOM_NII 104) ++ (CUSTOM_NIF 105) ++ (CUSTOM_NIP 106) ++ (CUSTOM_NFI 107) ++ (CUSTOM_NFF 108) ++ (CUSTOM_NFP 109) ++ (CUSTOM_NPI 110) ++ (CUSTOM_NPF 111) ++ (CUSTOM_NPP 112) ++ (CUSTOM_IN 113) ++ (CUSTOM_INI 114) ++ (CUSTOM_INF 115) ++ (CUSTOM_INP 116) ++ (CUSTOM_INII 117) ++ (CUSTOM_INIF 118) ++ (CUSTOM_INIP 119) ++ (CUSTOM_INFI 120) ++ (CUSTOM_INFF 121) ++ (CUSTOM_INFP 122) ++ (CUSTOM_INPI 123) ++ (CUSTOM_INPF 124) ++ (CUSTOM_INPP 125) ++ (CUSTOM_FN 126) ++ (CUSTOM_FNI 127) ++ (CUSTOM_FNF 128) ++ (CUSTOM_FNP 129) ++ (CUSTOM_FNII 130) ++ (CUSTOM_FNIF 131) ++ (CUSTOM_FNIP 132) ++ (CUSTOM_FNFI 133) ++ (CUSTOM_FNFF 134) ++ (CUSTOM_FNFP 135) ++ (CUSTOM_FNPI 136) ++ (CUSTOM_FNPF 137) ++ (CUSTOM_FNPP 138) ++ (CUSTOM_PN 139) ++ (CUSTOM_PNI 140) ++ (CUSTOM_PNF 141) ++ (CUSTOM_PNP 142) ++ (CUSTOM_PNII 143) ++ (CUSTOM_PNIF 144) ++ (CUSTOM_PNIP 145) ++ (CUSTOM_PNFI 146) ++ (CUSTOM_PNFF 147) ++ (CUSTOM_PNFP 148) ++ (CUSTOM_PNPI 149) ++ (CUSTOM_PNPF 150) ++ (CUSTOM_PNPP 151) ++]) ++ ++ ++(define_insn "custom_n" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] ++ "" ++ "custom\\t%0, zero, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ni" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_np" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nii" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nif" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nip" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nff" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_in" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ini" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++(define_insn "custom_fn" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fni" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnii" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnif" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnip" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnff" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_pn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pni" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Misc ++;* ++;***************************************************************************** ++ ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop\\t" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "sync" ++ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] ++ "" ++ "sync\\t" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "rdctl" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))] ++ "" ++ "rdctl\\t%0, ctl%1" ++ [(set_attr "type" "control")]) ++ ++(define_insn "wrctl" ++ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") ++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_WRCTL)] ++ "" ++ "wrctl\\tctl%0, %1" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Peepholes ++;* ++;***************************************************************************** ++ ++ +--- gcc-3.4.3/gcc/config/nios2/t-nios2 ++++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2 +@@ -0,0 +1,123 @@ ++## ++## Compiler flags to use when compiling libgcc2.c. ++## ++## LIB2FUNCS_EXTRA ++## A list of source file names to be compiled or assembled and inserted into libgcc.a. ++ ++LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ ++ $(srcdir)/config/nios2/lib2-divmod-hi.c \ ++ $(srcdir)/config/nios2/lib2-divtable.c \ ++ $(srcdir)/config/nios2/lib2-mul.c ++ ++## ++## Floating Point Emulation ++## To have GCC include software floating point libraries in libgcc.a define FPBIT ++## and DPBIT along with a few rules as follows: ++## ++## # We want fine grained libraries, so use the new code ++## # to build the floating point emulation libraries. ++FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c ++DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c ++ ++TARGET_LIBGCC2_CFLAGS = -O2 ++ ++# FLOAT_ONLY - no doubles ++# SMALL_MACHINE - QI/HI is faster than SI ++# Actually SMALL_MACHINE uses chars and shorts instead of ints ++# since ints (16-bit ones as they are today) are at least as fast ++# as chars and shorts, don't define SMALL_MACHINE ++# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) ++ ++$(FPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '#define FLOAT' > ${FPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT} ++ ++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '' > ${DPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT} ++ ++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o ++ ++# Assemble startup files. ++$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm ++ ++$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm ++ ++ ++## You may need to provide additional #defines at the beginning of ++## fp-bit.c and dp-bit.c to control target endianness and other options ++## ++## CRTSTUFF_T_CFLAGS ++## Special flags used when compiling crtstuff.c. See Initialization. ++## ++## CRTSTUFF_T_CFLAGS_S ++## Special flags used when compiling crtstuff.c for shared linking. Used ++## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. ++## ++## MULTILIB_OPTIONS ++## For some targets, invoking GCC in different ways produces objects that ++## can not be linked together. For example, for some targets GCC produces ++## both big and little endian code. For these targets, you must arrange ++## for multiple versions of libgcc.a to be compiled, one for each set of ++## incompatible options. When GCC invokes the linker, it arranges to link ++## in the right version of libgcc.a, based on the command line options ++## used. ++## The MULTILIB_OPTIONS macro lists the set of options for which special ++## versions of libgcc.a must be built. Write options that are mutually ++## incompatible side by side, separated by a slash. Write options that may ++## be used together separated by a space. The build procedure will build ++## all combinations of compatible options. ++## ++## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, ++## Makefile will build special versions of libgcc.a using the following ++## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, ++## and -m68020 -msoft-float. ++ ++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx ++ ++## MULTILIB_DIRNAMES ++## If MULTILIB_OPTIONS is used, this variable specifies the directory names ++## that should be used to hold the various libraries. Write one element in ++## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If ++## MULTILIB_DIRNAMES is not used, the default value will be ++## MULTILIB_OPTIONS, with all slashes treated as spaces. ++## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, ++## then the default value of MULTILIB_DIRNAMES is m68000 m68020 ++## msoft-float. You may specify a different value if you desire a ++## different set of directory names. ++ ++# MULTILIB_DIRNAMES = ++ ++## MULTILIB_MATCHES ++## Sometimes the same option may be written in two different ways. If an ++## option is listed in MULTILIB_OPTIONS, GCC needs to know about any ++## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the ++## form option=option to describe all relevant synonyms. For example, ++## m68000=mc68000 m68020=mc68020. ++## ++## MULTILIB_EXCEPTIONS ++## Sometimes when there are multiple sets of MULTILIB_OPTIONS being ++## specified, there are combinations that should not be built. In that ++## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in ++## shell case syntax that should not be built. ++## For example, in the PowerPC embedded ABI support, it is not desirable to ++## build libraries compiled with the -mcall-aix option and either of the ++## -fleading-underscore or -mlittle options at the same time. Therefore ++## MULTILIB_EXCEPTIONS is set to ++## ++## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* ++## ++ ++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* ++ ++## ++## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building ++## multiple versions of libgcc.a certain options should always be passed on ++## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list ++## of options to be used for all builds. ++## ++ +--- gcc-3.4.3/gcc/config.gcc ++++ gcc-3.4.3-nios2/gcc/config.gcc +@@ -1321,6 +1321,10 @@ m32rle-*-linux*) + thread_file='posix' + fi + ;; ++# JBG ++nios2-*-* | nios2-*-*) ++ tm_file="elfos.h ${tm_file}" ++ ;; + # m68hc11 and m68hc12 share the same machine description. + m68hc11-*-*|m6811-*-*) + tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h" +--- gcc-3.4.3/gcc/cse.c ++++ gcc-3.4.3-nios2/gcc/cse.c +@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code + #ifdef FLOAT_STORE_FLAG_VALUE + REAL_VALUE_TYPE fsfv; + #endif ++#ifdef __nios2__ ++ if (p->is_const) ++ break; ++#endif + + /* If the entry isn't valid, skip it. */ + if (! exp_equiv_p (p->exp, p->exp, 1, 0)) +--- gcc-3.4.3/gcc/doc/extend.texi ++++ gcc-3.4.3-nios2/gcc/doc/extend.texi +@@ -5636,12 +5636,118 @@ to those machines. Generally these gene + instructions, but allow the compiler to schedule those calls. + + @menu ++* Altera Nios II Built-in Functions:: + * Alpha Built-in Functions:: + * ARM Built-in Functions:: + * X86 Built-in Functions:: + * PowerPC AltiVec Built-in Functions:: + @end menu + ++@node Altera Nios II Built-in Functions ++@subsection Altera Nios II Built-in Functions ++ ++These built-in functions are available for the Altera Nios II ++family of processors. ++ ++The following built-in functions are always available. They ++all generate the machine instruction that is part of the name. ++ ++@example ++int __builtin_ldbio (volatile const void *) ++int __builtin_ldbuio (volatile const void *) ++int __builtin_ldhio (volatile const void *) ++int __builtin_ldhuio (volatile const void *) ++int __builtin_ldwio (volatile const void *) ++void __builtin_stbio (volatile void *, int) ++void __builtin_sthio (volatile void *, int) ++void __builtin_stwio (volatile void *, int) ++void __builtin_sync (void) ++int __builtin_rdctl (int) ++void __builtin_wrctl (int, int) ++@end example ++ ++The following built-in functions are always available. They ++all generate a Nios II Custom Instruction. The name of the ++function represents the types that the function takes and ++returns. The letter before the @code{n} is the return type ++or void if absent. The @code{n} represnts the first parameter ++to all the custom instructions, the custom instruction number. ++The two letters after the @code{n} represent the up to two ++parameters to the function. ++ ++The letters reprsent the following data types: ++@table @code ++@item ++@code{void} for return type and no parameter for parameter types. ++ ++@item i ++@code{int} for return type and parameter type ++ ++@item f ++@code{float} for return type and parameter type ++ ++@item p ++@code{void *} for return type and parameter type ++ ++@end table ++ ++And the function names are: ++@example ++void __builtin_custom_n (void) ++void __builtin_custom_ni (int) ++void __builtin_custom_nf (float) ++void __builtin_custom_np (void *) ++void __builtin_custom_nii (int, int) ++void __builtin_custom_nif (int, float) ++void __builtin_custom_nip (int, void *) ++void __builtin_custom_nfi (float, int) ++void __builtin_custom_nff (float, float) ++void __builtin_custom_nfp (float, void *) ++void __builtin_custom_npi (void *, int) ++void __builtin_custom_npf (void *, float) ++void __builtin_custom_npp (void *, void *) ++int __builtin_custom_in (void) ++int __builtin_custom_ini (int) ++int __builtin_custom_inf (float) ++int __builtin_custom_inp (void *) ++int __builtin_custom_inii (int, int) ++int __builtin_custom_inif (int, float) ++int __builtin_custom_inip (int, void *) ++int __builtin_custom_infi (float, int) ++int __builtin_custom_inff (float, float) ++int __builtin_custom_infp (float, void *) ++int __builtin_custom_inpi (void *, int) ++int __builtin_custom_inpf (void *, float) ++int __builtin_custom_inpp (void *, void *) ++float __builtin_custom_fn (void) ++float __builtin_custom_fni (int) ++float __builtin_custom_fnf (float) ++float __builtin_custom_fnp (void *) ++float __builtin_custom_fnii (int, int) ++float __builtin_custom_fnif (int, float) ++float __builtin_custom_fnip (int, void *) ++float __builtin_custom_fnfi (float, int) ++float __builtin_custom_fnff (float, float) ++float __builtin_custom_fnfp (float, void *) ++float __builtin_custom_fnpi (void *, int) ++float __builtin_custom_fnpf (void *, float) ++float __builtin_custom_fnpp (void *, void *) ++void * __builtin_custom_pn (void) ++void * __builtin_custom_pni (int) ++void * __builtin_custom_pnf (float) ++void * __builtin_custom_pnp (void *) ++void * __builtin_custom_pnii (int, int) ++void * __builtin_custom_pnif (int, float) ++void * __builtin_custom_pnip (int, void *) ++void * __builtin_custom_pnfi (float, int) ++void * __builtin_custom_pnff (float, float) ++void * __builtin_custom_pnfp (float, void *) ++void * __builtin_custom_pnpi (void *, int) ++void * __builtin_custom_pnpf (void *, float) ++void * __builtin_custom_pnpp (void *, void *) ++@end example ++ ++ + @node Alpha Built-in Functions + @subsection Alpha Built-in Functions + +--- gcc-3.4.3/gcc/doc/invoke.texi ++++ gcc-3.4.3-nios2/gcc/doc/invoke.texi +@@ -337,6 +337,14 @@ in the following sections. + @item Machine Dependent Options + @xref{Submodel Options,,Hardware Models and Configurations}. + ++@emph{Altera Nios II Options} ++@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol ++-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol ++-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol ++-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol ++-mno-hw-div -mhw-div @gol ++-msys-crt0= -msys-lib= -msys=nosys } ++ + @emph{M680x0 Options} + @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol + -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol +@@ -5836,6 +5844,7 @@ machine description. The default for th + that macro, which enables you to change the defaults. + + @menu ++* Altera Nios II Options:: + * M680x0 Options:: + * M68hc1x Options:: + * VAX Options:: +@@ -5871,6 +5880,103 @@ that macro, which enables you to change + * FRV Options:: + @end menu + ++ ++@node Altera Nios II Options ++@subsection Altera Nios II Options ++@cindex Altera Nios II options ++ ++These are the @samp{-m} options defined for the Altera Nios II ++processor. ++ ++@table @gcctabopt ++ ++@item -msmallc ++@opindex msmallc ++ ++Link with a limited version of the C library, -lsmallc. For more ++information see the C Library Documentation. ++ ++ ++@item -mbypass-cache ++@itemx -mno-bypass-cache ++@opindex mno-bypass-cache ++@opindex mbypass-cache ++ ++Force all load and store instructions to always bypass cache by ++using io variants of the instructions. The default is to not ++bypass the cache. ++ ++@item -mno-cache-volatile ++@itemx -mcache-volatile ++@opindex mcache-volatile ++@opindex mno-cache-volatile ++ ++Volatile memory access bypass the cache using the io variants of ++the ld and st instructions. The default is to cache volatile ++accesses. ++ ++-mno-cache-volatile is deprecated and will be deleted in a ++future GCC release. ++ ++ ++@item -mno-inline-memcpy ++@itemx -minline-memcpy ++@opindex mno-inline-memcpy ++@opindex minline-memcpy ++ ++Do not inline memcpy. The default is to inline when -O is on. ++ ++ ++@item -mno-fast-sw-div ++@itemx -mfast-sw-div ++@opindex mno-fast-sw-div ++@opindex mfast-sw-div ++ ++Do no use table based fast divide for small numbers. The default ++is to use the fast divide at -O3 and above. ++ ++ ++@item -mno-hw-mul ++@itemx -mhw-mul ++@itemx -mno-hw-mulx ++@itemx -mhw-mulx ++@itemx -mno-hw-div ++@itemx -mhw-div ++@opindex mno-hw-mul ++@opindex mhw-mul ++@opindex mno-hw-mulx ++@opindex mhw-mulx ++@opindex mno-hw-div ++@opindex mhw-div ++ ++Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of ++instructions by the compiler. The default is to emit @code{mul} ++and not emit @code{div} and @code{mulx}. ++ ++The different combinations of @code{mul} and @code{mulx} instructions ++generate a different multilib options. ++ ++ ++@item -msys-crt0=@var{startfile} ++@opindex msys-crt0 ++ ++@var{startfile} is the file name of the startfile (crt0) to use ++when linking. The default is crt0.o that comes with libgloss ++and is only suitable for use with the instruction set ++simulator. ++ ++@item -msys-lib=@var{systemlib} ++@itemx -msys-lib=nosys ++@opindex msys-lib ++ ++@var{systemlib} is the library name of the library which provides ++the system calls required by the C library, e.g. @code{read}, @code{write} ++etc. The default is to use nosys, this library provides ++stub implementations of the calls and is part of libgloss. ++ ++@end table ++ ++ + @node M680x0 Options + @subsection M680x0 Options + @cindex M680x0 options +--- gcc-3.4.3/gcc/doc/md.texi ++++ gcc-3.4.3-nios2/gcc/doc/md.texi +@@ -1335,6 +1335,49 @@ However, here is a summary of the machin + available on some particular machines. + + @table @emph ++ ++@item Altera Nios II family---@file{nios2.h} ++@table @code ++ ++@item I ++Integer that is valid as an immediate operand in an ++instruction taking a signed 16-bit number. Range ++@minus{}32768 to 32767. ++ ++@item J ++Integer that is valid as an immediate operand in an ++instruction taking an unsigned 16-bit number. Range ++0 to 65535. ++ ++@item K ++Integer that is valid as an immediate operand in an ++instruction taking only the upper 16-bits of a ++32-bit number. Range 32-bit numbers with the lower ++16-bits being 0. ++ ++@item L ++Integer that is valid as an immediate operand for a ++shift instruction. Range 0 to 31. ++ ++ ++@item M ++Integer that is valid as an immediate operand for ++only the value 0. Can be used in conjunction with ++the format modifier @code{z} to use @code{r0} ++instead of @code{0} in the assembly output. ++ ++@item N ++Integer that is valid as an immediate operand for ++a custom instruction opcode. Range 0 to 255. ++ ++@item S ++Matches immediates which are addresses in the small ++data section and therefore can be added to @code{gp} ++as a 16-bit immediate to re-create their 32-bit value. ++ ++@end table ++ ++ + @item ARM family---@file{arm.h} + @table @code + @item f diff --git a/misc/buildroot/toolchain/gcc/3.4.2/arm-softfloat.patch.conditional b/misc/buildroot/toolchain/gcc/3.4.2/arm-softfloat.patch.conditional new file mode 100644 index 000000000..19d1b90da --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.2/arm-softfloat.patch.conditional @@ -0,0 +1,270 @@ +Note... modified my mjn3 to not conflict with the big endian arm patch. +Warning!!! Only the linux target is aware of TARGET_ENDIAN_DEFAULT. +Also changed + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{!mcpu=*:-mcpu=xscale} \ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +to + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +in gcc/config/arm/linux-elf.h. +# +# Submitted: +# +# Dimitry Andric , 2004-05-01 +# +# Description: +# +# Nicholas Pitre released this patch for gcc soft-float support here: +# http://lists.arm.linux.org.uk/pipermail/linux-arm/2003-October/006436.html +# +# This version has been adapted to work with gcc 3.4.0. +# +# The original patch doesn't distinguish between softfpa and softvfp modes +# in the way Nicholas Pitre probably meant. His description is: +# +# "Default is to use APCS-32 mode with soft-vfp. The old Linux default for +# floats can be achieved with -mhard-float or with the configure +# --with-float=hard option. If -msoft-float or --with-float=soft is used then +# software float support will be used just like the default but with the legacy +# big endian word ordering for double float representation instead." +# +# Which means the following: +# +# * If you compile without -mhard-float or -msoft-float, you should get +# software floating point, using the VFP format. The produced object file +# should have these flags in its header: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# * If you compile with -mhard-float, you should get hardware floating point, +# which always uses the FPA format. Object file header flags should be: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# * If you compile with -msoft-float, you should get software floating point, +# using the FPA format. This is done for compatibility reasons with many +# existing distributions. Object file header flags should be: +# +# private flags = 200: [APCS-32] [FPA float format] [software FP] +# +# The original patch from Nicholas Pitre contained the following constructs: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" +# +# However, gcc doesn't accept this ";:" notation, used in the 3rd line. This +# is probably the reason Robert Schwebel modified it to: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa -mfpu=softvfp}}" +# +# But this causes the following behaviour: +# +# * If you compile without -mhard-float or -msoft-float, the compiler generates +# software floating point instructions, but *nothing* is passed to the +# assembler, which results in an object file which has flags: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# This is not correct! +# +# * If you compile with -mhard-float, the compiler generates hardware floating +# point instructions, and passes "-mfpu=fpa" to the assembler, which results +# in an object file which has the same flags as in the previous item, but now +# those *are* correct. +# +# * If you compile with -msoft-float, the compiler generates software floating +# point instructions, and passes "-mfpu=softfpa -mfpu=softvfp" (in that +# order) to the assembler, which results in an object file with flags: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# This is not correct, because the last "-mfpu=" option on the assembler +# command line determines the actual FPU convention used (which should be FPA +# in this case). +# +# Therefore, I modified this patch to get the desired behaviour. Every +# instance of the notation: +# +# %{msoft-float:-mfpu=softfpa -mfpu=softvfp} +# +# was changed to: +# +# %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp} +# +# I also did the following: +# +# * Modified all TARGET_DEFAULT macros I could find to include ARM_FLAG_VFP, to +# be consistent with Nicholas' original patch. +# * Removed any "msoft-float" or "mhard-float" from all MULTILIB_DEFAULTS +# macros I could find. I think that if you compile without any options, you +# would like to get the defaults. :) +# * Removed the extra -lfloat option from LIBGCC_SPEC, since it isn't needed +# anymore. (The required functions are now in libgcc.) + +diff -urN gcc-3.4.1-old/gcc/config/arm/coff.h gcc-3.4.1/gcc/config/arm/coff.h +--- gcc-3.4.1-old/gcc/config/arm/coff.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/coff.h 2004-09-02 21:51:15.000000000 -0500 +@@ -31,11 +31,16 @@ + #define TARGET_VERSION fputs (" (ARM/coff)", stderr) + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork" } + #endif + + /* This is COFF, but prefer stabs. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/elf.h gcc-3.4.1/gcc/config/arm/elf.h +--- gcc-3.4.1-old/gcc/config/arm/elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -46,7 +46,9 @@ + + #ifndef SUBTARGET_ASM_FLOAT_SPEC + #define SUBTARGET_ASM_FLOAT_SPEC "\ +-%{mapcs-float:-mfloat} %{msoft-float:-mfpu=softfpa}" ++%{mapcs-float:-mfloat} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + #endif + + #ifndef ASM_SPEC +@@ -106,12 +108,17 @@ + #endif + + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } + #endif + + #define TARGET_ASM_FILE_START_APP_OFF true +diff -urN gcc-3.4.1-old/gcc/config/arm/linux-elf.h gcc-3.4.1/gcc/config/arm/linux-elf.h +--- gcc-3.4.1-old/gcc/config/arm/linux-elf.h 2004-09-02 21:50:52.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h 2004-09-02 22:00:49.000000000 -0500 +@@ -44,12 +44,26 @@ + #define TARGET_LINKER_EMULATION "armelf_linux" + #endif + +-/* Default is to use APCS-32 mode. */ ++/* ++ * Default is to use APCS-32 mode with soft-vfp. ++ * The old Linux default for floats can be achieved with -mhard-float ++ * or with the configure --with-float=hard option. ++ * If -msoft-float or --with-float=soft is used then software float ++ * support will be used just like the default but with the legacy ++ * big endian word ordering for double float representation instead. ++ */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT \ +- ( ARM_FLAG_APCS_32 | \ +- ARM_FLAG_MMU_TRAPS | \ +- TARGET_ENDIAN_DEFAULT ) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_SOFT_FLOAT \ ++ | TARGET_ENDIAN_DEFAULT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_MMU_TRAPS ) ++ ++#undef SUBTARGET_EXTRA_ASM_SPEC ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +@@ -57,7 +71,7 @@ + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -72,7 +86,7 @@ + %{shared:-lc} \ + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" + +-#define LIBGCC_SPEC "%{msoft-float:-lfloat} -lgcc" ++#define LIBGCC_SPEC "-lgcc" + + /* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add + the GNU/Linux magical crtbegin.o file (see crtstuff.c) which +diff -urN gcc-3.4.1-old/gcc/config/arm/t-linux gcc-3.4.1/gcc/config/arm/t-linux +--- gcc-3.4.1-old/gcc/config/arm/t-linux 2003-09-20 16:09:07.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/t-linux 2004-09-02 21:51:15.000000000 -0500 +@@ -4,7 +4,10 @@ + LIBGCC2_DEBUG_CFLAGS = -g0 + + LIB1ASMSRC = arm/lib1funcs.asm +-LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx ++LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx \ ++ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \ ++ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ ++ _fixsfsi _fixunssfsi + + # MULTILIB_OPTIONS = mhard-float/msoft-float + # MULTILIB_DIRNAMES = hard-float soft-float +diff -urN gcc-3.4.1-old/gcc/config/arm/unknown-elf.h gcc-3.4.1/gcc/config/arm/unknown-elf.h +--- gcc-3.4.1-old/gcc/config/arm/unknown-elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/unknown-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -30,7 +30,12 @@ + + /* Default to using APCS-32 and software floating point. */ + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + /* Now we define the strings used to build the spec file. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/xscale-elf.h gcc-3.4.1/gcc/config/arm/xscale-elf.h +--- gcc-3.4.1-old/gcc/config/arm/xscale-elf.h 2003-07-01 18:26:43.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/xscale-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -49,11 +49,12 @@ + endian, regardless of the endian-ness of the memory + system. */ + +-#define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +- %{mhard-float:-mfpu=fpa} \ +- %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{!mcpu=*:-mcpu=xscale} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "mlittle-endian", "mno-thumb-interwork", "marm", "msoft-float" } ++ { "mlittle-endian", "mno-thumb-interwork", "marm" } + #endif diff --git a/misc/buildroot/toolchain/gcc/3.4.3/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/3.4.3/300-libstdc++-pic.patch new file mode 100644 index 000000000..9f304a4c4 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/300-libstdc++-pic.patch @@ -0,0 +1,47 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -224,6 +224,10 @@ + @OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCPP_BUILD_DEBUG + all-local: build_debug + +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -585,7 +585,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -618,6 +618,7 @@ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-data-local \ + install-exec install-exec-am install-info install-info-am \ ++ install-exec-local \ + install-man install-strip install-toolexeclibLTLIBRARIES \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ +@@ -707,6 +708,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/3.4.3/600-gcc34-arm-ldm-peephole.patch b/misc/buildroot/toolchain/gcc/3.4.3/600-gcc34-arm-ldm-peephole.patch new file mode 100644 index 000000000..fb317e153 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/600-gcc34-arm-ldm-peephole.patch @@ -0,0 +1,79 @@ +--- gcc-3.4.0/gcc/config/arm/arm.md.arm-ldm-peephole 2004-01-13 08:24:37.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.md 2004-04-24 18:18:04.000000000 -0400 +@@ -8810,13 +8810,16 @@ + (set_attr "length" "4,8,8")] + ) + ++; Try to convert LDR+LDR+arith into [add+]LDM+arith ++; On XScale, LDM is always slower than two LDRs, so only do this if ++; optimising for size. + (define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] +- "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" ++ "TARGET_ARM && (!arm_tune_xscale || optimize_size) && adjacent_mem_locations (operands[2], operands[3])" + "* + { + rtx ldm[3]; +@@ -8851,6 +8854,8 @@ + } + if (val1 && val2) + { ++ /* This would be a loss on a Harvard core, but adjacent_mem_locations() ++ will prevent it from happening. */ + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm-peephole 2004-04-24 18:16:25.000000000 -0400 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:18:04.000000000 -0400 +@@ -4593,8 +4593,11 @@ + arith_adjacentmem pattern to output an overlong sequence. */ + if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1)) + return 0; +- +- return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4); ++ ++ /* For Harvard cores, only accept pairs where one offset is zero. ++ See comment in load_multiple_sequence. */ ++ return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4) ++ && (!arm_ld_sched || val0 == 0 || val1 == 0); + } + return 0; + } +@@ -4838,6 +4841,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* ldmia */ + +@@ -5064,6 +5072,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* stmia */ + +--- gcc-3.4.0/gcc/genpeep.c.arm-ldm-peephole 2003-07-05 01:27:22.000000000 -0400 ++++ gcc-3.4.0/gcc/genpeep.c 2004-04-24 18:18:04.000000000 -0400 +@@ -381,6 +381,7 @@ + printf ("#include \"recog.h\"\n"); + printf ("#include \"except.h\"\n\n"); + printf ("#include \"function.h\"\n\n"); ++ printf ("#include \"flags.h\"\n\n"); + + printf ("#ifdef HAVE_peephole\n"); + printf ("extern rtx peep_operand[];\n\n"); diff --git a/misc/buildroot/toolchain/gcc/3.4.3/601-gcc34-arm-ldm.patch b/misc/buildroot/toolchain/gcc/3.4.3/601-gcc34-arm-ldm.patch new file mode 100644 index 000000000..142052fdf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/601-gcc34-arm-ldm.patch @@ -0,0 +1,119 @@ +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm 2004-02-27 09:51:05.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:16:25.000000000 -0400 +@@ -8520,6 +8520,26 @@ + return_used_this_function = 0; + } + ++/* Return the number (counting from 0) of ++ the least significant set bit in MASK. */ ++ ++#ifdef __GNUC__ ++inline ++#endif ++static int ++number_of_first_bit_set (mask) ++ int mask; ++{ ++ int bit; ++ ++ for (bit = 0; ++ (mask & (1 << bit)) == 0; ++ ++bit) ++ continue; ++ ++ return bit; ++} ++ + const char * + arm_output_epilogue (rtx sibling) + { +@@ -8753,27 +8773,47 @@ + saved_regs_mask |= (1 << PC_REGNUM); + } + +- /* Load the registers off the stack. If we only have one register +- to load use the LDR instruction - it is faster. */ +- if (saved_regs_mask == (1 << LR_REGNUM)) +- { +- /* The exception handler ignores the LR, so we do +- not really need to load it off the stack. */ +- if (eh_ofs) +- asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); +- else +- asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM); +- } +- else if (saved_regs_mask) ++ if (saved_regs_mask) + { +- if (saved_regs_mask & (1 << SP_REGNUM)) +- /* Note - write back to the stack register is not enabled +- (ie "ldmfd sp!..."). We know that the stack pointer is +- in the list of registers and if we add writeback the +- instruction becomes UNPREDICTABLE. */ +- print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ /* Load the registers off the stack. If we only have one register ++ to load use the LDR instruction - it is faster. */ ++ if (bit_count (saved_regs_mask) == 1) ++ { ++ int reg = number_of_first_bit_set (saved_regs_mask); ++ ++ switch (reg) ++ { ++ case SP_REGNUM: ++ /* Mustn't use base writeback when loading SP. */ ++ asm_fprintf (f, "\tldr\t%r, [%r]\n", SP_REGNUM, SP_REGNUM); ++ break; ++ ++ case LR_REGNUM: ++ if (eh_ofs) ++ { ++ /* The exception handler ignores the LR, so we do ++ not really need to load it off the stack. */ ++ asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); ++ break; ++ } ++ /* else fall through */ ++ ++ default: ++ asm_fprintf (f, "\tldr\t%r, [%r], #4\n", reg, SP_REGNUM); ++ break; ++ } ++ } + else +- print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ { ++ if (saved_regs_mask & (1 << SP_REGNUM)) ++ /* Note - write back to the stack register is not enabled ++ (ie "ldmfd sp!..."). We know that the stack pointer is ++ in the list of registers and if we add writeback the ++ instruction becomes UNPREDICTABLE. */ ++ print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ else ++ print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ } + } + + if (current_function_pretend_args_size) +@@ -11401,22 +11441,6 @@ + } + } + +-/* Return the number (counting from 0) of +- the least significant set bit in MASK. */ +- +-inline static int +-number_of_first_bit_set (int mask) +-{ +- int bit; +- +- for (bit = 0; +- (mask & (1 << bit)) == 0; +- ++bit) +- continue; +- +- return bit; +-} +- + /* Generate code to return from a thumb function. + If 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ diff --git a/misc/buildroot/toolchain/gcc/3.4.3/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/3.4.3/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..4377c2143 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +--- gcc-3.4.1/libstdc++-v3/libmath/Makefile.am~ 2003-08-27 22:29:42.000000000 +0100 ++++ gcc-3.4.1/libstdc++-v3/libmath/Makefile.am 2004-07-22 16:41:45.152130128 +0100 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC +--- gcc-3.4.1/libstdc++-v3/fragment.am.old 2004-07-22 18:24:58.024083656 +0100 ++++ gcc-3.4.1/libstdc++-v3/fragment.am 2004-07-22 18:24:59.019932264 +0100 +@@ -18,7 +18,7 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + + + diff --git a/misc/buildroot/toolchain/gcc/3.4.3/700-pr15068-fix.patch b/misc/buildroot/toolchain/gcc/3.4.3/700-pr15068-fix.patch new file mode 100644 index 000000000..2977765c5 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/700-pr15068-fix.patch @@ -0,0 +1,44 @@ +See http://gcc.gnu.org/PR15068 + +Fixes error + +../sysdeps/generic/s_fmax.c: In function `__fmax': +../sysdeps/generic/s_fmax.c:28: internal compiler error: in elim_reg_cond, at flow.c:3257 +Please submit a full bug report, +with preprocessed source if appropriate. +See for instructions. +make[2]: *** [/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/build-glibc/math/s_fmax.o] Error 1 +make[2]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822/math' +make[1]: *** [math/others] Error 2 +make[1]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822' +make: *** [all] Error 2 + +[ rediffed against gcc-3.4.1, with elbow grease, ending up with same thing as +http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/flow.c.diff?cvsroot=gcc&only_with_tag=csl-arm-branch&r1=1.563.4.2&r2=1.563.4.3 ] + +--- gcc-3.4.1/gcc/flow.c.old 2004-02-27 19:39:19.000000000 -0800 ++++ gcc-3.4.1/gcc/flow.c 2004-08-26 07:29:46.000000000 -0700 +@@ -1878,6 +1878,7 @@ + rtx set_src = SET_SRC (pc_set (BB_END (bb))); + rtx cond_true = XEXP (set_src, 0); + rtx reg = XEXP (cond_true, 0); ++ enum rtx_code inv_cond; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); +@@ -1886,11 +1887,13 @@ + in the form of a comparison of a register against zero. + If the condition is more complex than that, then it is safe + not to record any information. */ +- if (GET_CODE (reg) == REG ++ inv_cond = reversed_comparison_code (cond_true, BB_END (bb)); ++ if (inv_cond != UNKNOWN ++ && GET_CODE (reg) == REG + && XEXP (cond_true, 1) == const0_rtx) + { + rtx cond_false +- = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)), ++ = gen_rtx_fmt_ee (inv_cond, + GET_MODE (cond_true), XEXP (cond_true, 0), + XEXP (cond_true, 1)); + if (GET_CODE (XEXP (set_src, 1)) == PC) diff --git a/misc/buildroot/toolchain/gcc/3.4.3/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/3.4.3/800-arm-bigendian.patch new file mode 100644 index 000000000..04e998419 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/800-arm-bigendian.patch @@ -0,0 +1,68 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-3.4.1-dist/gcc/config/arm/linux-elf.h ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h +@@ -30,17 +30,34 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + /* Default is to use APCS-32 mode. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 | \ ++ ARM_FLAG_MMU_TRAPS | \ ++ TARGET_ENDIAN_DEFAULT ) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -101,7 +118,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + #endif + +--- gcc-3.4.1-dist/gcc/config.gcc ++++ gcc-3.4.1/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="t-slibgcc-elf-ver t-linux arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/3.4.3/830-gcc-bug-num-22167.patch b/misc/buildroot/toolchain/gcc/3.4.3/830-gcc-bug-num-22167.patch new file mode 100644 index 000000000..c7419af90 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/830-gcc-bug-num-22167.patch @@ -0,0 +1,16 @@ +Index: gcc/gcse.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gcse.c,v +retrieving revision 1.288.2.9 +diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.288.2.9 gcse.c +--- gcc/gcc/gcse.c 30 Oct 2004 18:02:53 -0000 1.288.2.9 ++++ gcc/gcc/gcse.c 14 Jul 2005 13:19:57 -0000 +@@ -6445,7 +6445,7 @@ hoist_code (void) + insn_inserted_p = 0; + + /* These tests should be the same as the tests above. */ +- if (TEST_BIT (hoist_vbeout[bb->index], i)) ++ if (TEST_BIT (hoist_exprs[bb->index], i)) + { + /* We've found a potentially hoistable expression, now + we look at every block BB dominates to see if it diff --git a/misc/buildroot/toolchain/gcc/3.4.3/900-nios2.patch b/misc/buildroot/toolchain/gcc/3.4.3/900-nios2.patch new file mode 100644 index 000000000..bfa06a21c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/900-nios2.patch @@ -0,0 +1,10211 @@ +--- gcc-3.4.3/gcc/Makefile.in ++++ gcc-3.4.3-nios2/gcc/Makefile.in +@@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_ + $(INSTALL_DATA) $(srcdir)/README-fixinc \ + $(DESTDIR)$(itoolsdatadir)/include/README ; \ + $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \ +- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \ ++ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \ + $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ + $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \ + else :; fi +--- gcc-3.4.3/gcc/combine.c ++++ gcc-3.4.3-nios2/gcc/combine.c +@@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin + mode); + } + ++#ifndef __nios2__ ++/* This screws up Nios II in this test case: ++ ++if (x & 1) ++ return 2; ++else ++ return 3; ++*/ + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx +@@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin + gen_lowpart_for_combine (mode, op0), + const1_rtx); + } ++#endif + + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT +--- gcc-3.4.3/gcc/config/nios2/crti.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm +@@ -0,0 +1,88 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just make a stack frame for the contents of the .fini and ++.init sections. Users may put any desired instructions in those ++sections. ++ ++ ++While technically any code can be put in the init and fini sections ++most stuff will not work other than stuff which obeys the call frame ++and ABI. All the call-preserved registers are saved, the call clobbered ++registers should have been saved by the code calling init and fini. ++ ++See crtstuff.c for an example of code that inserts itself in the ++init and fini sections. ++ ++See crt0.s for the code that calls init and fini. ++*/ ++ ++ .file "crti.asm" ++ ++ .section ".init" ++ .align 2 ++ .global _init ++_init: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ ++ .section ".fini" ++ .align 2 ++ .global _fini ++_fini: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ +--- gcc-3.4.3/gcc/config/nios2/crtn.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm +@@ -0,0 +1,70 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just makes sure that the .fini and .init sections do in ++fact return. Users may put any desired instructions in those sections. ++This file is the last thing linked into any executable. ++*/ ++ .file "crtn.asm" ++ ++ ++ ++ .section ".init" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ ++ .section ".fini" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c +@@ -0,0 +1,123 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern HItype __modhi3 (HItype, HItype); ++extern HItype __divhi3 (HItype, HItype); ++extern HItype __umodhi3 (HItype, HItype); ++extern HItype __udivhi3 (HItype, HItype); ++ ++static UHItype udivmodhi4(UHItype, UHItype, word_type); ++ ++static UHItype ++udivmodhi4(UHItype num, UHItype den, word_type modwanted) ++{ ++ UHItype bit = 1; ++ UHItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<15))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++HItype ++__divhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodhi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__modhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodhi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__udivhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 0); ++} ++ ++ ++HItype ++__umodhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c +@@ -0,0 +1,126 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern SItype __modsi3 (SItype, SItype); ++extern SItype __divsi3 (SItype, SItype); ++extern SItype __umodsi3 (SItype, SItype); ++extern SItype __udivsi3 (SItype, SItype); ++ ++static USItype udivmodsi4(USItype, USItype, word_type); ++ ++/* 16-bit SI divide and modulo as used in NIOS */ ++ ++ ++static USItype ++udivmodsi4(USItype num, USItype den, word_type modwanted) ++{ ++ USItype bit = 1; ++ USItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<31))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__modsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__udivsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 0); ++} ++ ++ ++SItype ++__umodsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c +@@ -0,0 +1,46 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++UQItype __divsi3_table[] = ++{ ++ 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15, ++ 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15, ++ 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15, ++ 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15, ++ 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15, ++ 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15, ++ 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15, ++ 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15, ++ 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15, ++ 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15, ++ 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15, ++ 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15, ++ 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15, ++ 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15, ++ 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15, ++ 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15, ++}; ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-mul.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c +@@ -0,0 +1,103 @@ ++/* while we are debugging (ie compile outside of gcc build) ++ disable gcc specific headers */ ++#ifndef DEBUG_MULSI3 ++ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++#else ++#define SItype int ++#define USItype unsigned int ++#endif ++ ++ ++extern SItype __mulsi3 (SItype, SItype); ++ ++SItype ++__mulsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = a; ++ ++ while (cnt) ++ { ++ if (cnt & 1) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt >>= 1; ++ } ++ ++ return res; ++} ++/* ++TODO: Choose best alternative implementation. ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = 0; ++ ++ while (cnt < 32) ++ { ++ if (a & (1L << cnt)) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt++; ++ } ++ ++ return res; ++} ++*/ ++ ++ ++#ifdef DEBUG_MULSI3 ++ ++int ++main () ++{ ++ int i, j; ++ int error = 0; ++ ++ for (i = -1000; i < 1000; i++) ++ for (j = -1000; j < 1000; j++) ++ { ++ int expect = i * j; ++ int actual = A__divsi3 (i, j); ++ if (expect != actual) ++ { ++ printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++#endif +--- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c +@@ -0,0 +1,1652 @@ ++ ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c +@@ -0,0 +1,1652 @@ ++#define FLOAT ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-protos.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h +@@ -0,0 +1,70 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++extern void dump_frame_size (FILE *); ++extern HOST_WIDE_INT compute_frame_size (void); ++extern int nios2_initial_elimination_offset (int, int); ++extern void override_options (void); ++extern void optimization_options (int, int); ++extern int nios2_can_use_return_insn (void); ++extern void expand_prologue (void); ++extern void expand_epilogue (bool); ++extern void function_profiler (FILE *, int); ++ ++ ++#ifdef RTX_CODE ++extern int nios2_legitimate_address (rtx, enum machine_mode, int); ++extern void nios2_print_operand (FILE *, rtx, int); ++extern void nios2_print_operand_address (FILE *, rtx); ++ ++extern int nios2_emit_move_sequence (rtx *, enum machine_mode); ++extern int nios2_emit_expensive_div (rtx *, enum machine_mode); ++ ++extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); ++extern void gen_conditional_move (rtx *, enum machine_mode); ++extern const char *asm_output_opcode (FILE *, const char *); ++ ++/* predicates */ ++extern int arith_operand (rtx, enum machine_mode); ++extern int uns_arith_operand (rtx, enum machine_mode); ++extern int logical_operand (rtx, enum machine_mode); ++extern int shift_operand (rtx, enum machine_mode); ++extern int reg_or_0_operand (rtx, enum machine_mode); ++extern int equality_op (rtx, enum machine_mode); ++extern int custom_insn_opcode (rtx, enum machine_mode); ++extern int rdwrctl_operand (rtx, enum machine_mode); ++ ++# ifdef HAVE_MACHINE_MODES ++# if defined TREE_CODE ++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); ++extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++ ++# endif /* TREE_CODE */ ++# endif /* HAVE_MACHINE_MODES */ ++#endif ++ ++#ifdef TREE_CODE ++extern int nios2_return_in_memory (tree); ++ ++#endif /* TREE_CODE */ +--- gcc-3.4.3/gcc/config/nios2/nios2.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c +@@ -0,0 +1,2853 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++#include ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "rtl.h" ++#include "tree.h" ++#include "tm_p.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "recog.h" ++#include "expr.h" ++#include "toplev.h" ++#include "basic-block.h" ++#include "function.h" ++#include "ggc.h" ++#include "reload.h" ++#include "debug.h" ++#include "optabs.h" ++#include "target.h" ++#include "target-def.h" ++ ++/* local prototypes */ ++static bool nios2_rtx_costs (rtx, int, int, int *); ++ ++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); ++static int nios2_use_dfa_pipeline_interface (void); ++static int nios2_issue_rate (void); ++static struct machine_function *nios2_init_machine_status (void); ++static bool nios2_in_small_data_p (tree); ++static rtx save_reg (int, HOST_WIDE_INT, rtx); ++static rtx restore_reg (int, HOST_WIDE_INT); ++static unsigned int nios2_section_type_flags (tree, const char *, int); ++static void nios2_init_builtins (void); ++static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); ++static bool nios2_function_ok_for_sibcall (tree, tree); ++static void nios2_encode_section_info (tree, rtx, int); ++ ++/* Initialize the GCC target structure. */ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue ++ ++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE ++#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ ++ nios2_use_dfa_pipeline_interface ++#undef TARGET_SCHED_ISSUE_RATE ++#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate ++#undef TARGET_IN_SMALL_DATA_P ++#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p ++#undef TARGET_ENCODE_SECTION_INFO ++#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info ++#undef TARGET_SECTION_TYPE_FLAGS ++#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS nios2_init_builtins ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN nios2_expand_builtin ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS nios2_rtx_costs ++ ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++ ++ ++/* Threshold for data being put into the small data/bss area, instead ++ of the normal data area (references to the small data/bss area take ++ 1 instruction, and use the global pointer, references to the normal ++ data area takes 2 instructions). */ ++unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; ++ ++ ++/* Structure to be filled in by compute_frame_size with register ++ save masks, and offsets for the current function. */ ++ ++struct nios2_frame_info ++GTY (()) ++{ ++ long total_size; /* # bytes that the entire frame takes up */ ++ long var_size; /* # bytes that variables take up */ ++ long args_size; /* # bytes that outgoing arguments take up */ ++ int save_reg_size; /* # bytes needed to store gp regs */ ++ int save_reg_rounded; /* # bytes needed to store gp regs */ ++ long save_regs_offset; /* offset from new sp to store gp registers */ ++ int initialized; /* != 0 if frame size already calculated */ ++ int num_regs; /* number of gp registers saved */ ++}; ++ ++struct machine_function ++GTY (()) ++{ ++ ++ /* Current frame information, calculated by compute_frame_size. */ ++ struct nios2_frame_info frame; ++}; ++ ++ ++/*************************************** ++ * Section encodings ++ ***************************************/ ++ ++ ++ ++ ++ ++/*************************************** ++ * Stack Layout and Calling Conventions ++ ***************************************/ ++ ++ ++#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) ++#define TEMP_REG_NUM 8 ++ ++static void ++nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ++{ ++ if (flag_verbose_asm || flag_debug_asm) ++ { ++ compute_frame_size (); ++ dump_frame_size (file); ++ } ++} ++ ++static rtx ++save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg) ++{ ++ rtx insn, stack_slot; ++ ++ stack_slot = gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ GEN_INT (offset)); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_MEM (SImode, stack_slot), ++ gen_rtx_REG (SImode, regno))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ return insn; ++} ++ ++static rtx ++restore_reg (int regno, HOST_WIDE_INT offset) ++{ ++ rtx insn, stack_slot; ++ ++ if (TOO_BIG_OFFSET (offset)) ++ { ++ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ GEN_INT (offset))); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ gen_rtx_PLUS (SImode, ++ stack_slot, ++ stack_pointer_rtx))); ++ } ++ else ++ { ++ stack_slot = gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (offset)); ++ } ++ ++ stack_slot = gen_rtx_MEM (SImode, stack_slot); ++ ++ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot); ++ ++ return insn; ++} ++ ++ ++/* There are two possible paths for prologue expansion, ++- the first is if the total frame size is < 2^15-1. In that ++case all the immediates will fit into the 16-bit immediate ++fields. ++- the second is when the frame size is too big, in that ++case an additional temporary register is used, first ++as a cfa_temp to offset the sp, second as the cfa_store ++register. ++ ++See the comment above dwarf2out_frame_debug_expr in ++dwarf2out.c for more explanation of the "rules." ++ ++ ++Case 1: ++Rule # Example Insn Effect ++2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++12 stw ra, offset(sp) ++12 stw r16, offset(sp) ++1 mov fp, sp ++ ++Case 2: ++Rule # Example Insn Effect ++6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size ++2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0 ++12 stw ra, offset(r8) ++12 stw r16, offset(r8) ++1 mov fp, sp ++ ++*/ ++ ++void ++expand_prologue () ++{ ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int cfa_store_offset; ++ rtx insn; ++ rtx cfa_store_reg = 0; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (total_frame_size) ++ { ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ /* cfa_temp and cfa_store_reg are the same register, ++ cfa_store_reg overwrites cfa_temp */ ++ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ cfa_store_reg, ++ GEN_INT (total_frame_size))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_MINUS (SImode, ++ stack_pointer_rtx, ++ cfa_store_reg)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ /* if there are no registers to save, I don't need to ++ create a cfa_store */ ++ if (cfun->machine->frame.save_reg_size) ++ { ++ insn = gen_rtx_SET (SImode, ++ cfa_store_reg, ++ gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ stack_pointer_rtx)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ cfa_store_offset ++ = total_frame_size ++ - (cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded); ++ } ++ else ++ { ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (-total_frame_size))); ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ cfa_store_reg = stack_pointer_rtx; ++ cfa_store_offset ++ = cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded; ++ } ++ } ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ cfa_store_offset -= 4; ++ save_reg (i, cfa_store_offset, cfa_store_reg); ++ } ++ } ++ ++ if (frame_pointer_needed) ++ { ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_REG (SImode, FP_REGNO), ++ gen_rtx_REG (SImode, SP_REGNO))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ /* If we are profiling, make sure no instructions are scheduled before ++ the call to mcount. */ ++ if (current_function_profile) ++ emit_insn (gen_blockage ()); ++} ++ ++void ++expand_epilogue (bool sibcall_p) ++{ ++ rtx insn; ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int register_store_offset; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (!sibcall_p && nios2_can_use_return_insn ()) ++ { ++ insn = emit_jump_insn (gen_return ()); ++ return; ++ } ++ ++ emit_insn (gen_blockage ()); ++ ++ register_store_offset = ++ cfun->machine->frame.save_regs_offset + ++ cfun->machine->frame.save_reg_rounded; ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (RA_REGNO, register_store_offset); ++ } ++ ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (FP_REGNO, register_store_offset); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ register_store_offset -= 4; ++ restore_reg (i, register_store_offset); ++ } ++ } ++ ++ if (total_frame_size) ++ { ++ rtx sp_adjust; ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ sp_adjust, ++ GEN_INT (total_frame_size))); ++ ++ } ++ else ++ { ++ sp_adjust = GEN_INT (total_frame_size); ++ } ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ sp_adjust)); ++ insn = emit_insn (insn); ++ } ++ ++ ++ if (!sibcall_p) ++ { ++ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode, ++ RA_REGNO))); ++ } ++} ++ ++ ++bool ++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) ++{ ++ return true; ++} ++ ++ ++ ++ ++ ++/* ----------------------- * ++ * Profiling ++ * ----------------------- */ ++ ++void ++function_profiler (FILE *file, int labelno) ++{ ++ fprintf (file, "\t%s mcount begin, label: .LP%d\n", ++ ASM_COMMENT_START, labelno); ++ fprintf (file, "\tnextpc\tr8\n"); ++ fprintf (file, "\tmov\tr9, ra\n"); ++ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno); ++ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno); ++ fprintf (file, "\tcall\tmcount\n"); ++ fprintf (file, "\tmov\tra, r9\n"); ++ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START); ++} ++ ++ ++/*************************************** ++ * Stack Layout ++ ***************************************/ ++ ++ ++void ++dump_frame_size (FILE *file) ++{ ++ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); ++ ++ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.total_size); ++ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.var_size); ++ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.args_size); ++ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_size); ++ fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_rounded); ++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.initialized); ++ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.num_regs); ++ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_regs_offset); ++ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, ++ current_function_is_leaf); ++ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, ++ frame_pointer_needed); ++ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, ++ current_function_pretend_args_size); ++ ++} ++ ++ ++/* Return the bytes needed to compute the frame pointer from the current ++ stack pointer. ++*/ ++ ++HOST_WIDE_INT ++compute_frame_size () ++{ ++ unsigned int regno; ++ HOST_WIDE_INT var_size; /* # of var. bytes allocated */ ++ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */ ++ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */ ++ HOST_WIDE_INT save_reg_rounded; ++ /* # bytes needed to store callee save regs (rounded) */ ++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */ ++ ++ save_reg_size = 0; ++ var_size = STACK_ALIGN (get_frame_size ()); ++ out_args_size = STACK_ALIGN (current_function_outgoing_args_size); ++ ++ total_size = var_size + out_args_size; ++ ++ /* Calculate space needed for gp registers. */ ++ for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++) ++ { ++ if (MUST_SAVE_REGISTER (regno)) ++ { ++ save_reg_size += 4; ++ } ++ } ++ ++ save_reg_rounded = STACK_ALIGN (save_reg_size); ++ total_size += save_reg_rounded; ++ ++ total_size += STACK_ALIGN (current_function_pretend_args_size); ++ ++ /* Save other computed information. */ ++ cfun->machine->frame.total_size = total_size; ++ cfun->machine->frame.var_size = var_size; ++ cfun->machine->frame.args_size = current_function_outgoing_args_size; ++ cfun->machine->frame.save_reg_size = save_reg_size; ++ cfun->machine->frame.save_reg_rounded = save_reg_rounded; ++ cfun->machine->frame.initialized = reload_completed; ++ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD; ++ ++ cfun->machine->frame.save_regs_offset ++ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0; ++ ++ return total_size; ++} ++ ++ ++int ++nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) ++{ ++ int offset; ++ ++ /* Set OFFSET to the offset from the stack pointer. */ ++ switch (from) ++ { ++ case FRAME_POINTER_REGNUM: ++ offset = 0; ++ break; ++ ++ case ARG_POINTER_REGNUM: ++ compute_frame_size (); ++ offset = cfun->machine->frame.total_size; ++ offset -= current_function_pretend_args_size; ++ break; ++ ++ case RETURN_ADDRESS_POINTER_REGNUM: ++ compute_frame_size (); ++ /* since the return address is always the first of the ++ saved registers, return the offset to the beginning ++ of the saved registers block */ ++ offset = cfun->machine->frame.save_regs_offset; ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ return offset; ++} ++ ++/* Return nonzero if this function is known to have a null epilogue. ++ This allows the optimizer to omit jumps to jumps if no stack ++ was created. */ ++int ++nios2_can_use_return_insn () ++{ ++ if (!reload_completed) ++ return 0; ++ ++ if (regs_ever_live[RA_REGNO] || current_function_profile) ++ return 0; ++ ++ if (cfun->machine->frame.initialized) ++ return cfun->machine->frame.total_size == 0; ++ ++ return compute_frame_size () == 0; ++} ++ ++ ++ ++ ++ ++/*************************************** ++ * ++ ***************************************/ ++ ++const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++const char *nios2_sys_lib_string; /* for -msys-lib= */ ++const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++void ++override_options () ++{ ++ /* Function to allocate machine-dependent function status. */ ++ init_machine_status = &nios2_init_machine_status; ++ ++ nios2_section_threshold ++ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; ++ ++ if (nios2_sys_nosys_string && *nios2_sys_nosys_string) ++ { ++ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string); ++ } ++ ++ /* If we don't have mul, we don't have mulx either! */ ++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX) ++ { ++ target_flags &= ~HAS_MULX_FLAG; ++ } ++ ++} ++ ++void ++optimization_options (int level, int size) ++{ ++ if (level || size) ++ { ++ target_flags |= INLINE_MEMCPY_FLAG; ++ } ++ ++ if (level >= 3 && !size) ++ { ++ target_flags |= FAST_SW_DIV_FLAG; ++ } ++} ++ ++/* Allocate a chunk of memory for per-function machine-dependent data. */ ++static struct machine_function * ++nios2_init_machine_status () ++{ ++ return ((struct machine_function *) ++ ggc_alloc_cleared (sizeof (struct machine_function))); ++} ++ ++ ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++/* Compute a (partial) cost for rtx X. Return true if the complete ++ cost has been computed, and false if subexpressions should be ++ scanned. In either case, *TOTAL contains the cost result. */ ++ ++ ++ ++static bool ++nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) ++{ ++ switch (code) ++ { ++ case CONST_INT: ++ if (INTVAL (x) == 0) ++ { ++ *total = COSTS_N_INSNS (0); ++ return true; ++ } ++ else if (SMALL_INT (INTVAL (x)) ++ || SMALL_INT_UNSIGNED (INTVAL (x)) ++ || UPPER16_INT (INTVAL (x))) ++ { ++ *total = COSTS_N_INSNS (2); ++ return true; ++ } ++ else ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case LABEL_REF: ++ case SYMBOL_REF: ++ /* ??? gp relative stuff will fit in here */ ++ /* fall through */ ++ case CONST: ++ case CONST_DOUBLE: ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case MULT: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ case SIGN_EXTEND: ++ { ++ *total = COSTS_N_INSNS (3); ++ return false; ++ } ++ case ZERO_EXTEND: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ ++ default: ++ return false; ++ } ++} ++ ++ ++/*************************************** ++ * INSTRUCTION SUPPORT ++ * ++ * These functions are used within the Machine Description to ++ * handle common or complicated output and expansions from ++ * instructions. ++ ***************************************/ ++ ++int ++nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) ++{ ++ rtx to = operands[0]; ++ rtx from = operands[1]; ++ ++ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) ++ { ++ if (no_new_pseudos) ++ internal_error ("Trying to force_reg no_new_pseudos == 1"); ++ from = copy_to_mode_reg (mode, from); ++ } ++ ++ operands[0] = to; ++ operands[1] = from; ++ return 0; ++} ++ ++/* Divide Support */ ++ ++/* ++ If -O3 is used, we want to output a table lookup for ++ divides between small numbers (both num and den >= 0 ++ and < 0x10). The overhead of this method in the worse ++ case is 40 bytes in the text section (10 insns) and ++ 256 bytes in the data section. Additional divides do ++ not incur additional penalties in the data section. ++ ++ Code speed is improved for small divides by about 5x ++ when using this method in the worse case (~9 cycles ++ vs ~45). And in the worse case divides not within the ++ table are penalized by about 10% (~5 cycles vs ~45). ++ However in the typical case the penalty is not as bad ++ because doing the long divide in only 45 cycles is ++ quite optimistic. ++ ++ ??? It would be nice to have some benchmarks other ++ than Dhrystone to back this up. ++ ++ This bit of expansion is to create this instruction ++ sequence as rtl. ++ or $8, $4, $5 ++ slli $9, $4, 4 ++ cmpgeui $3, $8, 16 ++ beq $3, $0, .L3 ++ or $10, $9, $5 ++ add $12, $11, divide_table ++ ldbu $2, 0($12) ++ br .L1 ++.L3: ++ call slow_div ++.L1: ++# continue here with result in $2 ++ ++ ??? Ideally I would like the emit libcall block to contain ++ all of this code, but I don't know how to do that. What it ++ means is that if the divide can be eliminated, it may not ++ completely disappear. ++ ++ ??? The __divsi3_table label should ideally be moved out ++ of this block and into a global. If it is placed into the ++ sdata section we can save even more cycles by doing things ++ gp relative. ++*/ ++int ++nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) ++{ ++ rtx or_result, shift_left_result; ++ rtx lookup_value; ++ rtx lab1, lab3; ++ rtx insns; ++ rtx libfunc; ++ rtx final_result; ++ rtx tmp; ++ ++ /* it may look a little generic, but only SImode ++ is supported for now */ ++ if (mode != SImode) ++ abort (); ++ ++ libfunc = sdiv_optab->handlers[(int) SImode].libfunc; ++ ++ ++ ++ lab1 = gen_label_rtx (); ++ lab3 = gen_label_rtx (); ++ ++ or_result = expand_simple_binop (SImode, IOR, ++ operands[1], operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, ++ GET_MODE (or_result), 0, lab3); ++ JUMP_LABEL (get_last_insn ()) = lab3; ++ ++ shift_left_result = expand_simple_binop (SImode, ASHIFT, ++ operands[1], GEN_INT (4), ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ lookup_value = expand_simple_binop (SImode, IOR, ++ shift_left_result, operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ convert_move (operands[0], ++ gen_rtx (MEM, QImode, ++ gen_rtx (PLUS, SImode, ++ lookup_value, ++ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), ++ 1); ++ ++ ++ tmp = emit_jump_insn (gen_jump (lab1)); ++ JUMP_LABEL (tmp) = lab1; ++ emit_barrier (); ++ ++ emit_label (lab3); ++ LABEL_NUSES (lab3) = 1; ++ ++ start_sequence (); ++ final_result = emit_library_call_value (libfunc, NULL_RTX, ++ LCT_CONST, SImode, 2, ++ operands[1], SImode, ++ operands[2], SImode); ++ ++ ++ insns = get_insns (); ++ end_sequence (); ++ emit_libcall_block (insns, operands[0], final_result, ++ gen_rtx (DIV, SImode, operands[1], operands[2])); ++ ++ emit_label (lab1); ++ LABEL_NUSES (lab1) = 1; ++ return 1; ++} ++ ++/* Branches/Compares */ ++ ++/* the way of handling branches/compares ++ in gcc is heavily borrowed from MIPS */ ++ ++enum internal_test ++{ ++ ITEST_EQ, ++ ITEST_NE, ++ ITEST_GT, ++ ITEST_GE, ++ ITEST_LT, ++ ITEST_LE, ++ ITEST_GTU, ++ ITEST_GEU, ++ ITEST_LTU, ++ ITEST_LEU, ++ ITEST_MAX ++}; ++ ++static enum internal_test map_test_to_internal_test (enum rtx_code); ++ ++/* Cached operands, and operator to compare for use in set/branch/trap ++ on condition codes. */ ++rtx branch_cmp[2]; ++enum cmp_type branch_type; ++ ++/* Make normal rtx_code into something we can index from an array */ ++ ++static enum internal_test ++map_test_to_internal_test (enum rtx_code test_code) ++{ ++ enum internal_test test = ITEST_MAX; ++ ++ switch (test_code) ++ { ++ case EQ: ++ test = ITEST_EQ; ++ break; ++ case NE: ++ test = ITEST_NE; ++ break; ++ case GT: ++ test = ITEST_GT; ++ break; ++ case GE: ++ test = ITEST_GE; ++ break; ++ case LT: ++ test = ITEST_LT; ++ break; ++ case LE: ++ test = ITEST_LE; ++ break; ++ case GTU: ++ test = ITEST_GTU; ++ break; ++ case GEU: ++ test = ITEST_GEU; ++ break; ++ case LTU: ++ test = ITEST_LTU; ++ break; ++ case LEU: ++ test = ITEST_LEU; ++ break; ++ default: ++ break; ++ } ++ ++ return test; ++} ++ ++/* Generate the code to compare (and possibly branch) two integer values ++ TEST_CODE is the comparison code we are trying to emulate ++ (or implement directly) ++ RESULT is where to store the result of the comparison, ++ or null to emit a branch ++ CMP0 CMP1 are the two comparison operands ++ DESTINATION is the destination of the branch, or null to only compare ++ */ ++ ++void ++gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */ ++ rtx result, /* result to store comp. or 0 if branch */ ++ rtx cmp0, /* first operand to compare */ ++ rtx cmp1, /* second operand to compare */ ++ rtx destination) /* destination of the branch, or 0 if compare */ ++{ ++ struct cmp_info ++ { ++ /* for register (or 0) compares */ ++ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */ ++ int reverse_regs; /* reverse registers in test */ ++ ++ /* for immediate compares */ ++ enum rtx_code test_code_const; ++ /* code to use in instruction (LT vs. LTU) */ ++ int const_low; /* low bound of constant we can accept */ ++ int const_high; /* high bound of constant we can accept */ ++ int const_add; /* constant to add */ ++ ++ /* generic info */ ++ int unsignedp; /* != 0 for unsigned comparisons. */ ++ }; ++ ++ static const struct cmp_info info[(int) ITEST_MAX] = { ++ ++ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ ++ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ ++ ++ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ ++ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ ++ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ ++ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ ++ ++ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ ++ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ ++ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ ++ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ ++ }; ++ ++ enum internal_test test; ++ enum machine_mode mode; ++ const struct cmp_info *p_info; ++ int branch_p; ++ ++ ++ ++ ++ test = map_test_to_internal_test (test_code); ++ if (test == ITEST_MAX) ++ abort (); ++ ++ p_info = &info[(int) test]; ++ ++ mode = GET_MODE (cmp0); ++ if (mode == VOIDmode) ++ mode = GET_MODE (cmp1); ++ ++ branch_p = (destination != 0); ++ ++ /* We can't, under any circumstances, have const_ints in cmp0 ++ ??? Actually we could have const0 */ ++ if (GET_CODE (cmp0) == CONST_INT) ++ cmp0 = force_reg (mode, cmp0); ++ ++ /* if the comparison is against an int not in legal range ++ move it into a register */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ HOST_WIDE_INT value = INTVAL (cmp1); ++ ++ if (value < p_info->const_low || value > p_info->const_high) ++ cmp1 = force_reg (mode, cmp1); ++ } ++ ++ /* Comparison to constants, may involve adding 1 to change a GT into GE. ++ Comparison between two registers, may involve switching operands. */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ if (p_info->const_add != 0) ++ { ++ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; ++ ++ /* If modification of cmp1 caused overflow, ++ we would get the wrong answer if we follow the usual path; ++ thus, x > 0xffffffffU would turn into x > 0U. */ ++ if ((p_info->unsignedp ++ ? (unsigned HOST_WIDE_INT) new > ++ (unsigned HOST_WIDE_INT) INTVAL (cmp1) ++ : new > INTVAL (cmp1)) != (p_info->const_add > 0)) ++ { ++ /* ??? This case can never happen with the current numbers, ++ but I am paranoid and would rather an abort than ++ a bug I will never find */ ++ abort (); ++ } ++ else ++ cmp1 = GEN_INT (new); ++ } ++ } ++ ++ else if (p_info->reverse_regs) ++ { ++ rtx temp = cmp0; ++ cmp0 = cmp1; ++ cmp1 = temp; ++ } ++ ++ ++ ++ if (branch_p) ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ rtx insn; ++ rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1); ++ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ insn = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, label, pc_rtx)); ++ emit_jump_insn (insn); ++ } ++ else ++ { ++ rtx cond, label; ++ ++ result = gen_reg_rtx (mode); ++ ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ ++ cond = gen_rtx (NE, mode, result, const0_rtx); ++ label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, ++ label, pc_rtx))); ++ } ++ } ++ else ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1)); ++ } ++ else ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ } ++ } ++ ++} ++ ++ ++/* ??? For now conditional moves are only supported ++ when the mode of the operands being compared are ++ the same as the ones being moved */ ++ ++void ++gen_conditional_move (rtx *operands, enum machine_mode mode) ++{ ++ rtx insn, cond; ++ rtx cmp_reg = gen_reg_rtx (mode); ++ enum rtx_code cmp_code = GET_CODE (operands[1]); ++ enum rtx_code move_code = EQ; ++ ++ /* emit a comparison if it is not "simple". ++ Simple comparisons are X eq 0 and X ne 0 */ ++ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[0]; ++ move_code = cmp_code; ++ } ++ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[1]; ++ move_code = cmp_code == EQ ? NE : EQ; ++ } ++ else ++ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], ++ NULL_RTX); ++ ++ cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); ++ insn = gen_rtx_SET (mode, operands[0], ++ gen_rtx_IF_THEN_ELSE (mode, ++ cond, operands[2], operands[3])); ++ emit_insn (insn); ++} ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++int ++nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int strict) ++{ ++ int ret_val = 0; ++ ++ switch (GET_CODE (operand)) ++ { ++ /* direct. */ ++ case SYMBOL_REF: ++ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) ++ { ++ ret_val = 1; ++ break; ++ } ++ /* else, fall through */ ++ case LABEL_REF: ++ case CONST_INT: ++ case CONST: ++ case CONST_DOUBLE: ++ /* ??? In here I need to add gp addressing */ ++ ret_val = 0; ++ ++ break; ++ ++ /* Register indirect. */ ++ case REG: ++ ret_val = REG_OK_FOR_BASE_P2 (operand, strict); ++ break; ++ ++ /* Register indirect with displacement */ ++ case PLUS: ++ { ++ rtx op0 = XEXP (operand, 0); ++ rtx op1 = XEXP (operand, 1); ++ ++ if (REG_P (op0) && REG_P (op1)) ++ ret_val = 0; ++ else if (REG_P (op0) && CONSTANT_P (op1)) ++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict) ++ && SMALL_INT (INTVAL (op1)); ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ ret_val = REG_OK_FOR_BASE_P2 (op1, strict) ++ && SMALL_INT (INTVAL (op0)); ++ else ++ ret_val = 0; ++ } ++ break; ++ ++ default: ++ ret_val = 0; ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/* Return true if EXP should be placed in the small data section. */ ++ ++static bool ++nios2_in_small_data_p (tree exp) ++{ ++ /* We want to merge strings, so we never consider them small data. */ ++ if (TREE_CODE (exp) == STRING_CST) ++ return false; ++ ++ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) ++ { ++ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); ++ /* ??? these string names need moving into ++ an array in some header file */ ++ if (nios2_section_threshold > 0 ++ && (strcmp (section, ".sbss") == 0 ++ || strncmp (section, ".sbss.", 6) == 0 ++ || strcmp (section, ".sdata") == 0 ++ || strncmp (section, ".sdata.", 7) == 0)) ++ return true; ++ } ++ else if (TREE_CODE (exp) == VAR_DECL) ++ { ++ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); ++ ++ /* If this is an incomplete type with size 0, then we can't put it ++ in sdata because it might be too big when completed. */ ++ if (size > 0 && size <= nios2_section_threshold) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ++nios2_encode_section_info (tree decl, rtx rtl, int first) ++{ ++ ++ rtx symbol; ++ int flags; ++ ++ default_encode_section_info (decl, rtl, first); ++ ++ /* Careful not to prod global register variables. */ ++ if (GET_CODE (rtl) != MEM) ++ return; ++ symbol = XEXP (rtl, 0); ++ if (GET_CODE (symbol) != SYMBOL_REF) ++ return; ++ ++ flags = SYMBOL_REF_FLAGS (symbol); ++ ++ /* We don't want weak variables to be addressed with gp in case they end up with ++ value 0 which is not within 2^15 of $gp */ ++ if (DECL_P (decl) && DECL_WEAK (decl)) ++ flags |= SYMBOL_FLAG_WEAK_DECL; ++ ++ SYMBOL_REF_FLAGS (symbol) = flags; ++} ++ ++ ++static unsigned int ++nios2_section_type_flags (tree decl, const char *name, int reloc) ++{ ++ unsigned int flags; ++ ++ flags = default_section_type_flags (decl, name, reloc); ++ ++ /* ??? these string names need moving into an array in some header file */ ++ if (strcmp (name, ".sbss") == 0 ++ || strncmp (name, ".sbss.", 6) == 0 ++ || strcmp (name, ".sdata") == 0 ++ || strncmp (name, ".sdata.", 7) == 0) ++ flags |= SECTION_SMALL; ++ ++ return flags; ++} ++ ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++ ++/* print the operand OP to file stream ++ FILE modified by LETTER. LETTER ++ can be one of: ++ i: print "i" if OP is an immediate, except 0 ++ o: print "io" if OP is volatile ++ ++ z: for const0_rtx print $0 instead of 0 ++ H: for %hiadj ++ L: for %lo ++ U: for upper half of 32 bit value ++ */ ++ ++void ++nios2_print_operand (FILE *file, rtx op, int letter) ++{ ++ ++ switch (letter) ++ { ++ case 'i': ++ if (CONSTANT_P (op) && (op != const0_rtx)) ++ fprintf (file, "i"); ++ return; ++ ++ case 'o': ++ if (GET_CODE (op) == MEM ++ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE) ++ || TARGET_BYPASS_CACHE)) ++ fprintf (file, "io"); ++ return; ++ ++ default: ++ break; ++ } ++ ++ if (comparison_operator (op, VOIDmode)) ++ { ++ if (letter == 0) ++ { ++ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); ++ return; ++ } ++ } ++ ++ ++ switch (GET_CODE (op)) ++ { ++ case REG: ++ if (letter == 0 || letter == 'z') ++ { ++ fprintf (file, "%s", reg_names[REGNO (op)]); ++ return; ++ } ++ ++ case CONST_INT: ++ if (INTVAL (op) == 0 && letter == 'z') ++ { ++ fprintf (file, "zero"); ++ return; ++ } ++ else if (letter == 'U') ++ { ++ HOST_WIDE_INT val = INTVAL (op); ++ rtx new_op; ++ val = (val / 65536) & 0xFFFF; ++ new_op = GEN_INT (val); ++ output_addr_const (file, new_op); ++ return; ++ } ++ ++ /* else, fall through */ ++ case CONST: ++ case LABEL_REF: ++ case SYMBOL_REF: ++ case CONST_DOUBLE: ++ if (letter == 0 || letter == 'z') ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ else if (letter == 'H') ++ { ++ fprintf (file, "%%hiadj("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ else if (letter == 'L') ++ { ++ fprintf (file, "%%lo("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ ++ ++ case SUBREG: ++ case MEM: ++ if (letter == 0) ++ { ++ output_address (op); ++ return; ++ } ++ ++ case CODE_LABEL: ++ if (letter == 0) ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print (%c) ", letter); ++ debug_rtx (op); ++ abort (); ++} ++ ++static int gprel_constant (rtx); ++ ++static int ++gprel_constant (rtx op) ++{ ++ if (GET_CODE (op) == SYMBOL_REF ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) ++ { ++ return 1; ++ } ++ else if (GET_CODE (op) == CONST ++ && GET_CODE (XEXP (op, 0)) == PLUS) ++ { ++ return gprel_constant (XEXP (XEXP (op, 0), 0)); ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++void ++nios2_print_operand_address (FILE *file, rtx op) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST: ++ case CONST_INT: ++ case LABEL_REF: ++ case CONST_DOUBLE: ++ case SYMBOL_REF: ++ if (gprel_constant (op)) ++ { ++ fprintf (file, "%%gprel("); ++ output_addr_const (file, op); ++ fprintf (file, ")(%s)", reg_names[GP_REGNO]); ++ return; ++ } ++ ++ break; ++ ++ case PLUS: ++ { ++ rtx op0 = XEXP (op, 0); ++ rtx op1 = XEXP (op, 1); ++ ++ if (REG_P (op0) && CONSTANT_P (op1)) ++ { ++ output_addr_const (file, op1); ++ fprintf (file, "(%s)", reg_names[REGNO (op0)]); ++ return; ++ } ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ { ++ output_addr_const (file, op0); ++ fprintf (file, "(%s)", reg_names[REGNO (op1)]); ++ return; ++ } ++ } ++ break; ++ ++ case REG: ++ fprintf (file, "0(%s)", reg_names[REGNO (op)]); ++ return; ++ ++ case MEM: ++ { ++ rtx base = XEXP (op, 0); ++ PRINT_OPERAND_ADDRESS (file, base); ++ return; ++ } ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print address\n"); ++ debug_rtx (op); ++ abort (); ++} ++ ++ ++ ++ ++ ++/**************************** ++ * Predicates ++ ****************************/ ++ ++int ++arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++uns_arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++logical_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT ++ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++shift_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); ++} ++ ++/* Return truth value of whether OP is a register or the constant 0. */ ++ ++int ++reg_or_0_operand (rtx op, enum machine_mode mode) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST_INT: ++ return INTVAL (op) == 0; ++ ++ case CONST_DOUBLE: ++ return op == CONST0_RTX (mode); ++ ++ default: ++ break; ++ } ++ ++ return register_operand (op, mode); ++} ++ ++ ++int ++equality_op (rtx op, enum machine_mode mode) ++{ ++ if (mode != GET_MODE (op)) ++ return 0; ++ ++ return GET_CODE (op) == EQ || GET_CODE (op) == NE; ++} ++ ++int ++custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); ++} ++ ++ ++ ++ ++ ++ ++ ++/***************************************************************************** ++** ++** instruction scheduler ++** ++*****************************************************************************/ ++static int ++nios2_use_dfa_pipeline_interface () ++{ ++ return 1; ++} ++ ++ ++static int ++nios2_issue_rate () ++{ ++#ifdef MAX_DFA_ISSUE_RATE ++ return MAX_DFA_ISSUE_RATE; ++#else ++ return 1; ++#endif ++} ++ ++ ++const char * ++asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, ++ const char *ptr ATTRIBUTE_UNUSED) ++{ ++ const char *p; ++ ++ p = ptr; ++ return ptr; ++} ++ ++ ++ ++/***************************************************************************** ++** ++** function arguments ++** ++*****************************************************************************/ ++ ++void ++init_cumulative_args (CUMULATIVE_ARGS *cum, ++ tree fntype ATTRIBUTE_UNUSED, ++ rtx libname ATTRIBUTE_UNUSED, ++ tree fndecl ATTRIBUTE_UNUSED, ++ int n_named_args ATTRIBUTE_UNUSED) ++{ ++ cum->regs_used = 0; ++} ++ ++ ++/* Update the data in CUM to advance over an argument ++ of mode MODE and data type TYPE. ++ (TYPE is null for libcalls where that information may not be available.) */ ++ ++void ++function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ cum->regs_used = NUM_ARG_REGS; ++ } ++ else ++ { ++ cum->regs_used += param_size; ++ } ++ ++ return; ++} ++ ++/* Define where to put the arguments to a function. Value is zero to ++ push the argument on the stack, or a hard register in which to ++ store the argument. ++ ++ MODE is the argument's machine mode. ++ TYPE is the data type of the argument (as a tree). ++ This is null for libcalls where that information may ++ not be available. ++ CUM is a variable of type CUMULATIVE_ARGS which gives info about ++ the preceding args and about the function being called. ++ NAMED is nonzero if this argument is a named parameter ++ (otherwise it is an extra parameter matching an ellipsis). */ ++rtx ++function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ rtx return_rtx = NULL_RTX; ++ ++ if (cum->regs_used < NUM_ARG_REGS) ++ { ++ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); ++ } ++ ++ return return_rtx; ++} ++ ++int ++function_arg_partial_nregs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used < NUM_ARG_REGS ++ && cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ return NUM_ARG_REGS - cum->regs_used; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++ ++int ++nios2_return_in_memory (tree type) ++{ ++ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) ++ || (int_size_in_bytes (type) == -1)); ++ ++ return res; ++} ++ ++/* ??? It may be possible to eliminate the copyback and implement ++ my own va_arg type, but that is more work for now. */ ++int ++nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int no_rtl) ++{ ++ CUMULATIVE_ARGS local_cum; ++ int regs_to_push; ++ ++ local_cum = *cum; ++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); ++ ++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used; ++ ++ if (!no_rtl) ++ { ++ if (regs_to_push > 0) ++ { ++ rtx ptr, mem; ++ ++ ptr = virtual_incoming_args_rtx; ++ mem = gen_rtx_MEM (BLKmode, ptr); ++ ++ /* va_arg is an array access in this case, which causes ++ it to get MEM_IN_STRUCT_P set. We must set it here ++ so that the insn scheduler won't assume that these ++ stores can't possibly overlap with the va_arg loads. */ ++ MEM_SET_IN_STRUCT_P (mem, 1); ++ ++ emit_insn (gen_blockage ()); ++ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, ++ regs_to_push); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ ++ return regs_to_push * UNITS_PER_WORD; ++ ++} ++ ++ ++ ++/***************************************************************************** ++** ++** builtins ++** ++** This method for handling builtins is from CSP where _many_ more types of ++** expanders have already been written. Check there first before writing ++** new ones. ++** ++*****************************************************************************/ ++ ++enum nios2_builtins ++{ ++ NIOS2_BUILTIN_LDBIO, ++ NIOS2_BUILTIN_LDBUIO, ++ NIOS2_BUILTIN_LDHIO, ++ NIOS2_BUILTIN_LDHUIO, ++ NIOS2_BUILTIN_LDWIO, ++ NIOS2_BUILTIN_STBIO, ++ NIOS2_BUILTIN_STHIO, ++ NIOS2_BUILTIN_STWIO, ++ NIOS2_BUILTIN_SYNC, ++ NIOS2_BUILTIN_RDCTL, ++ NIOS2_BUILTIN_WRCTL, ++ ++ NIOS2_BUILTIN_CUSTOM_N, ++ NIOS2_BUILTIN_CUSTOM_NI, ++ NIOS2_BUILTIN_CUSTOM_NF, ++ NIOS2_BUILTIN_CUSTOM_NP, ++ NIOS2_BUILTIN_CUSTOM_NII, ++ NIOS2_BUILTIN_CUSTOM_NIF, ++ NIOS2_BUILTIN_CUSTOM_NIP, ++ NIOS2_BUILTIN_CUSTOM_NFI, ++ NIOS2_BUILTIN_CUSTOM_NFF, ++ NIOS2_BUILTIN_CUSTOM_NFP, ++ NIOS2_BUILTIN_CUSTOM_NPI, ++ NIOS2_BUILTIN_CUSTOM_NPF, ++ NIOS2_BUILTIN_CUSTOM_NPP, ++ NIOS2_BUILTIN_CUSTOM_IN, ++ NIOS2_BUILTIN_CUSTOM_INI, ++ NIOS2_BUILTIN_CUSTOM_INF, ++ NIOS2_BUILTIN_CUSTOM_INP, ++ NIOS2_BUILTIN_CUSTOM_INII, ++ NIOS2_BUILTIN_CUSTOM_INIF, ++ NIOS2_BUILTIN_CUSTOM_INIP, ++ NIOS2_BUILTIN_CUSTOM_INFI, ++ NIOS2_BUILTIN_CUSTOM_INFF, ++ NIOS2_BUILTIN_CUSTOM_INFP, ++ NIOS2_BUILTIN_CUSTOM_INPI, ++ NIOS2_BUILTIN_CUSTOM_INPF, ++ NIOS2_BUILTIN_CUSTOM_INPP, ++ NIOS2_BUILTIN_CUSTOM_FN, ++ NIOS2_BUILTIN_CUSTOM_FNI, ++ NIOS2_BUILTIN_CUSTOM_FNF, ++ NIOS2_BUILTIN_CUSTOM_FNP, ++ NIOS2_BUILTIN_CUSTOM_FNII, ++ NIOS2_BUILTIN_CUSTOM_FNIF, ++ NIOS2_BUILTIN_CUSTOM_FNIP, ++ NIOS2_BUILTIN_CUSTOM_FNFI, ++ NIOS2_BUILTIN_CUSTOM_FNFF, ++ NIOS2_BUILTIN_CUSTOM_FNFP, ++ NIOS2_BUILTIN_CUSTOM_FNPI, ++ NIOS2_BUILTIN_CUSTOM_FNPF, ++ NIOS2_BUILTIN_CUSTOM_FNPP, ++ NIOS2_BUILTIN_CUSTOM_PN, ++ NIOS2_BUILTIN_CUSTOM_PNI, ++ NIOS2_BUILTIN_CUSTOM_PNF, ++ NIOS2_BUILTIN_CUSTOM_PNP, ++ NIOS2_BUILTIN_CUSTOM_PNII, ++ NIOS2_BUILTIN_CUSTOM_PNIF, ++ NIOS2_BUILTIN_CUSTOM_PNIP, ++ NIOS2_BUILTIN_CUSTOM_PNFI, ++ NIOS2_BUILTIN_CUSTOM_PNFF, ++ NIOS2_BUILTIN_CUSTOM_PNFP, ++ NIOS2_BUILTIN_CUSTOM_PNPI, ++ NIOS2_BUILTIN_CUSTOM_PNPF, ++ NIOS2_BUILTIN_CUSTOM_PNPP, ++ ++ ++ LIM_NIOS2_BUILTINS ++}; ++ ++struct builtin_description ++{ ++ const enum insn_code icode; ++ const char *const name; ++ const enum nios2_builtins code; ++ const tree *type; ++ rtx (* expander) PARAMS ((const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int)); ++}; ++ ++static rtx nios2_expand_STXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_LDXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_sync (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_rdctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_wrctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static rtx nios2_expand_custom_n (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_Xn (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static tree endlink; ++ ++/* int fn (volatile const void *) ++ */ ++static tree int_ftype_volatile_const_void_p; ++ ++/* int fn (int) ++ */ ++static tree int_ftype_int; ++ ++/* void fn (int, int) ++ */ ++static tree void_ftype_int_int; ++ ++/* void fn (volatile void *, int) ++ */ ++static tree void_ftype_volatile_void_p_int; ++ ++/* void fn (void) ++ */ ++static tree void_ftype_void; ++ ++static tree custom_n; ++static tree custom_ni; ++static tree custom_nf; ++static tree custom_np; ++static tree custom_nii; ++static tree custom_nif; ++static tree custom_nip; ++static tree custom_nfi; ++static tree custom_nff; ++static tree custom_nfp; ++static tree custom_npi; ++static tree custom_npf; ++static tree custom_npp; ++static tree custom_in; ++static tree custom_ini; ++static tree custom_inf; ++static tree custom_inp; ++static tree custom_inii; ++static tree custom_inif; ++static tree custom_inip; ++static tree custom_infi; ++static tree custom_inff; ++static tree custom_infp; ++static tree custom_inpi; ++static tree custom_inpf; ++static tree custom_inpp; ++static tree custom_fn; ++static tree custom_fni; ++static tree custom_fnf; ++static tree custom_fnp; ++static tree custom_fnii; ++static tree custom_fnif; ++static tree custom_fnip; ++static tree custom_fnfi; ++static tree custom_fnff; ++static tree custom_fnfp; ++static tree custom_fnpi; ++static tree custom_fnpf; ++static tree custom_fnpp; ++static tree custom_pn; ++static tree custom_pni; ++static tree custom_pnf; ++static tree custom_pnp; ++static tree custom_pnii; ++static tree custom_pnif; ++static tree custom_pnip; ++static tree custom_pnfi; ++static tree custom_pnff; ++static tree custom_pnfp; ++static tree custom_pnpi; ++static tree custom_pnpf; ++static tree custom_pnpp; ++ ++ ++static const struct builtin_description bdesc[] = { ++ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ ++ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ ++ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync}, ++ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl}, ++ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl}, ++ ++ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n}, ++ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX}, ++ ++ ++ {0, 0, 0, 0, 0}, ++}; ++ ++/* This does not have a closing bracket on purpose (see use) */ ++#define def_param(TYPE) \ ++ tree_cons (NULL_TREE, TYPE, ++ ++static void ++nios2_init_builtins () ++{ ++ const struct builtin_description *d; ++ ++ ++ endlink = void_list_node; ++ ++ /* Special indenting here because one of the brackets is in def_param */ ++ /* *INDENT-OFF* */ ++ ++ /* int fn (volatile const void *) ++ */ ++ int_ftype_volatile_const_void_p ++ = build_function_type (integer_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) ++ endlink)); ++ ++ ++ /* void fn (volatile void *, int) ++ */ ++ void_ftype_volatile_void_p_int ++ = build_function_type (void_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_VOLATILE)) ++ def_param (integer_type_node) ++ endlink))); ++ ++ /* void fn (void) ++ */ ++ void_ftype_void ++ = build_function_type (void_type_node, ++ endlink); ++ ++ /* int fn (int) ++ */ ++ int_ftype_int ++ = build_function_type (integer_type_node, ++ def_param (integer_type_node) ++ endlink)); ++ ++ /* void fn (int, int) ++ */ ++ void_ftype_int_int ++ = build_function_type (void_type_node, ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink))); ++ ++ ++#define CUSTOM_NUM def_param (integer_type_node) ++ ++ custom_n ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ni ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_nf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_np ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_nii ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nif ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nip ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_nfi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nff ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nfp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_npi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_npf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_npp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_in ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ini ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_inf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_inp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_inii ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inif ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inip ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_infi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inff ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_infp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_inpi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inpf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inpp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_fn ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_fni ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_fnf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_fnp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_fnii ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnif ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnip ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnfi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnff ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnfp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnpi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnpf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnpp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ custom_pn ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_pni ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_pnf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_pnp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_pnii ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnif ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnip ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnfi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnff ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnfp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnpi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnpf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnpp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ ++ /* *INDENT-ON* */ ++ ++ ++ for (d = bdesc; d->name; d++) ++ { ++ builtin_function (d->name, *d->type, d->code, ++ BUILT_IN_MD, NULL, NULL); ++ } ++} ++ ++/* Expand an expression EXP that calls a built-in function, ++ with result going to TARGET if that's convenient ++ (and in mode MODE if that's convenient). ++ SUBTARGET may be used as the target for computing one of EXP's operands. ++ IGNORE is nonzero if the value is to be ignored. */ ++ ++static rtx ++nios2_expand_builtin (tree exp, rtx target, rtx subtarget, ++ enum machine_mode mode, int ignore) ++{ ++ const struct builtin_description *d; ++ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ ++ for (d = bdesc; d->name; d++) ++ if (d->code == fcode) ++ return (d->expander) (d, exp, target, subtarget, mode, ignore); ++ ++ /* we should have seen one of the functins we registered */ ++ abort (); ++} ++ ++static rtx nios2_create_target (const struct builtin_description *, rtx); ++ ++ ++static rtx ++nios2_create_target (const struct builtin_description *d, rtx target) ++{ ++ if (!target ++ || !(*insn_data[d->icode].operand[0].predicate) (target, ++ insn_data[d->icode].operand[0].mode)) ++ { ++ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); ++ } ++ ++ return target; ++} ++ ++ ++static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); ++static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree); ++ ++static rtx ++nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); ++ opcode = protect_from_queue (opcode, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) ++ error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name); ++ ++ return opcode; ++} ++ ++static rtx ++nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx operand = expand_expr (arg, NULL_RTX, mode, 0); ++ operand = protect_from_queue (operand, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ operand = copy_to_mode_reg (mode, operand); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ error ("Invalid argument %d to %s", argnum, d->name); ++ ++ return operand; ++} ++ ++ ++static rtx ++nios2_expand_custom_n (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_n should have exactly one operand */ ++ if (insn_data[d->icode].n_operands != 1) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ ++ pat = GEN_FCN (d->icode) (opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_Xn should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ pat = GEN_FCN (d->icode) (target, opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nX (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ ++ /* custom_nX should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ /* custom_Xn should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_nX should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_XnX should have exactly four operands */ ++ if (insn_data[d->icode].n_operands != 4) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++ ++static rtx ++nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx store_dest, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ store_dest = protect_from_queue (store_dest, 0); ++ ++ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (store_dest, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++static rtx ++nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx ld_src; ++ enum insn_code icode = d->icode; ++ ++ /* loads should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ld_src = protect_from_queue (ld_src, 0); ++ ++ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) ++ { ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, ld_src); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++static rtx ++nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ emit_insn (gen_sync ()); ++ return 0; ++} ++ ++static rtx ++nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx rdctl_reg; ++ enum insn_code icode = d->icode; ++ ++ /* rdctl should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ rdctl_reg = protect_from_queue (rdctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) ++ { ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, rdctl_reg); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx wrctl_reg, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ wrctl_reg = protect_from_queue (wrctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (wrctl_reg, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++#include "gt-nios2.h" ++ +--- gcc-3.4.3/gcc/config/nios2/nios2.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h +@@ -0,0 +1,824 @@ ++/* Definitions of target machine for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++ ++#define TARGET_CPU_CPP_BUILTINS() \ ++ do \ ++ { \ ++ builtin_define_std ("NIOS2"); \ ++ builtin_define_std ("nios2"); \ ++ builtin_define ("_GNU_SOURCE"); \ ++ } \ ++ while (0) ++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") ++ ++ ++ ++ ++ ++/********************************* ++ * Run-time Target Specification ++ *********************************/ ++ ++#define HAS_DIV_FLAG 0x0001 ++#define HAS_MUL_FLAG 0x0002 ++#define HAS_MULX_FLAG 0x0004 ++#define FAST_SW_DIV_FLAG 0x0008 ++#define INLINE_MEMCPY_FLAG 0x00010 ++#define CACHE_VOLATILE_FLAG 0x0020 ++#define BYPASS_CACHE_FLAG 0x0040 ++ ++extern int target_flags; ++#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG) ++#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG) ++#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG) ++#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG) ++#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG) ++#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG) ++#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG) ++ ++#define TARGET_SWITCHES \ ++{ \ ++ { "hw-div", HAS_DIV_FLAG, \ ++ N_("Enable DIV, DIVU") }, \ ++ { "no-hw-div", -HAS_DIV_FLAG, \ ++ N_("Disable DIV, DIVU (default)") }, \ ++ { "hw-mul", HAS_MUL_FLAG, \ ++ N_("Enable MUL instructions (default)") }, \ ++ { "hw-mulx", HAS_MULX_FLAG, \ ++ N_("Enable MULX instructions, assume fast shifter") }, \ ++ { "no-hw-mul", -HAS_MUL_FLAG, \ ++ N_("Disable MUL instructions") }, \ ++ { "no-hw-mulx", -HAS_MULX_FLAG, \ ++ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \ ++ { "fast-sw-div", FAST_SW_DIV_FLAG, \ ++ N_("Use table based fast divide (default at -O3)") }, \ ++ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \ ++ N_("Don't use table based fast divide ever") }, \ ++ { "inline-memcpy", INLINE_MEMCPY_FLAG, \ ++ N_("Inline small memcpy (default when optimizing)") }, \ ++ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \ ++ N_("Don't Inline small memcpy") }, \ ++ { "cache-volatile", CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use non-io variants of instructions (default)") }, \ ++ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use io variants of instructions") }, \ ++ { "bypass-cache", BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins use io variants") }, \ ++ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins do not use io variants (default)") }, \ ++ { "smallc", 0, \ ++ N_("Link with a limited version of the C library") }, \ ++ { "ctors-in-init", 0, \ ++ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \ ++ { "", TARGET_DEFAULT, 0 } \ ++} ++ ++ ++extern const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++extern const char *nios2_sys_lib_string; /* for -msys-lib= */ ++extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++#define TARGET_OPTIONS \ ++{ \ ++ { "sys=nosys", &nios2_sys_nosys_string, \ ++ N_("Use stub versions of OS library calls (default)"), 0}, \ ++ { "sys-lib=", &nios2_sys_lib_string, \ ++ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \ ++ { "sys-crt0=", &nios2_sys_crt0_string, \ ++ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \ ++} ++ ++ ++/* Default target_flags if no switches specified. */ ++#ifndef TARGET_DEFAULT ++# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG) ++#endif ++ ++/* Switch Recognition by gcc.c. Add -G xx support */ ++#undef SWITCH_TAKES_ARG ++#define SWITCH_TAKES_ARG(CHAR) \ ++ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') ++ ++#define OVERRIDE_OPTIONS override_options () ++#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) ++#define CAN_DEBUG_WITHOUT_FP ++ ++#define CC1_SPEC "\ ++%{G*}" ++ ++#undef LIB_SPEC ++#define LIB_SPEC \ ++"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \ ++ %{msys-lib=*: -l%*} \ ++ %{!msys-lib=*: -lc } \ ++ --end-group \ ++ %{msys-lib=: %eYou need a library name for -msys-lib=} \ ++" ++ ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC \ ++"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \ ++ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \ ++ %{mctors-in-init: crti%O%s crtbegin%O%s} \ ++" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++ "%{mctors-in-init: crtend%O%s crtn%O%s}" ++ ++ ++/*********************** ++ * Storage Layout ++ ***********************/ ++ ++#define DEFAULT_SIGNED_CHAR 1 ++#define BITS_BIG_ENDIAN 0 ++#define BYTES_BIG_ENDIAN 0 ++#define WORDS_BIG_ENDIAN 0 ++#define BITS_PER_UNIT 8 ++#define BITS_PER_WORD 32 ++#define UNITS_PER_WORD 4 ++#define POINTER_SIZE 32 ++#define BIGGEST_ALIGNMENT 32 ++#define STRICT_ALIGNMENT 1 ++#define FUNCTION_BOUNDARY 32 ++#define PARM_BOUNDARY 32 ++#define STACK_BOUNDARY 32 ++#define PREFERRED_STACK_BOUNDARY 32 ++#define MAX_FIXED_MODE_SIZE 64 ++ ++#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ ++ ((TREE_CODE (EXP) == STRING_CST) \ ++ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) ++ ++ ++/********************** ++ * Layout of Source Language Data Types ++ **********************/ ++ ++#define INT_TYPE_SIZE 32 ++#define SHORT_TYPE_SIZE 16 ++#define LONG_TYPE_SIZE 32 ++#define LONG_LONG_TYPE_SIZE 64 ++#define FLOAT_TYPE_SIZE 32 ++#define DOUBLE_TYPE_SIZE 64 ++#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE ++ ++ ++/************************* ++ * Condition Code Status ++ ************************/ ++ ++/* comparison type */ ++/* ??? currently only CMP_SI is used */ ++enum cmp_type { ++ CMP_SI, /* compare four byte integers */ ++ CMP_DI, /* compare eight byte integers */ ++ CMP_SF, /* compare single precision floats */ ++ CMP_DF, /* compare double precision floats */ ++ CMP_MAX /* max comparison type */ ++}; ++ ++extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ ++extern enum cmp_type branch_type; /* what type of branch to use */ ++ ++/********************** ++ * Register Usage ++ **********************/ ++ ++/* ---------------------------------- * ++ * Basic Characteristics of Registers ++ * ---------------------------------- */ ++ ++/* ++Register Number ++ Register Name ++ Alternate Name ++ Purpose ++0 r0 zero always zero ++1 r1 at Assembler Temporary ++2-3 r2-r3 Return Location ++4-7 r4-r7 Register Arguments ++8-15 r8-r15 Caller Saved Registers ++16-22 r16-r22 Callee Saved Registers ++23 r23 sc Static Chain (Callee Saved) ++ ??? Does $sc want to be caller or callee ++ saved. If caller, 15, else 23. ++24 r24 Exception Temporary ++25 r25 Breakpoint Temporary ++26 r26 gp Global Pointer ++27 r27 sp Stack Pointer ++28 r28 fp Frame Pointer ++29 r29 ea Exception Return Address ++30 r30 ba Breakpoint Return Address ++31 r31 ra Return Address ++ ++32 ctl0 status ++33 ctl1 estatus STATUS saved by exception ? ++34 ctl2 bstatus STATUS saved by break ? ++35 ctl3 ipri Interrupt Priority Mask ? ++36 ctl4 ecause Exception Cause ? ++ ++37 pc Not an actual register ++ ++38 rap Return address pointer, this does not ++ actually exist and will be eliminated ++ ++39 fake_fp Fake Frame Pointer which will always be eliminated. ++40 fake_ap Fake Argument Pointer which will always be eliminated. ++ ++41 First Pseudo Register ++ ++ ++The definitions for all the hard register numbers ++are located in nios2.md. ++*/ ++ ++#define FIRST_PSEUDO_REGISTER 41 ++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) ++ ++ ++ ++/* also see CONDITIONAL_REGISTER_USAGE */ ++#define FIXED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++/* call used is the same as caller saved ++ + fixed regs + args + ret vals */ ++#define CALL_USED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++/* --------------------------- * ++ * How Values Fit in Registers ++ * --------------------------- */ ++ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++ ++#define MODES_TIEABLE_P(MODE1, MODE2) 1 ++ ++ ++/************************* ++ * Register Classes ++ *************************/ ++ ++enum reg_class ++{ ++ NO_REGS, ++ ALL_REGS, ++ LIM_REG_CLASSES ++}; ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++ ++#define REG_CLASS_NAMES \ ++ {"NO_REGS", \ ++ "ALL_REGS"} ++ ++#define GENERAL_REGS ALL_REGS ++ ++#define REG_CLASS_CONTENTS \ ++/* NO_REGS */ {{ 0, 0}, \ ++/* ALL_REGS */ {~0,~0}} \ ++ ++#define REGNO_REG_CLASS(REGNO) ALL_REGS ++ ++#define BASE_REG_CLASS ALL_REGS ++#define INDEX_REG_CLASS ALL_REGS ++ ++/* only one reg class, 'r', is handled automatically */ ++#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS ++ ++#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ ++ ((STRICT) \ ++ ? (REGNO) < FIRST_PSEUDO_REGISTER \ ++ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) ++ ++#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) ++ ++#define REGNO_OK_FOR_BASE_P(REGNO) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) ++ ++#define REGNO_OK_FOR_INDEX_P(REGNO) \ ++ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) ++ ++#define REG_OK_FOR_BASE_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define REG_OK_FOR_INDEX_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++ ++#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) ++#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) ++#define UPPER16_INT(X) (((X) & 0xffff) == 0) ++#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) ++#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) ++#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ( \ ++ (C) == 'I' ? SMALL_INT (VALUE) : \ ++ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ ++ (C) == 'K' ? UPPER16_INT (VALUE) : \ ++ (C) == 'L' ? SHIFT_INT (VALUE) : \ ++ (C) == 'M' ? (VALUE) == 0 : \ ++ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ ++ (C) == 'O' ? RDWRCTL_INT (VALUE) : \ ++ 0) ++ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 ++ ++#define PREFERRED_RELOAD_CLASS(X, CLASS) \ ++ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) ++ ++/* 'S' matches immediates which are in small data ++ and therefore can be added to gp to create a ++ 32-bit value. */ ++#define EXTRA_CONSTRAINT(VALUE, C) \ ++ ((C) == 'S' \ ++ && (GET_CODE (VALUE) == SYMBOL_REF) \ ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) ++ ++ ++ ++ ++/* Say that the epilogue uses the return address register. Note that ++ in the case of sibcalls, the values "used by the epilogue" are ++ considered live at the start of the called function. */ ++#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) ++ ++ ++#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) ++ ++/********************************** ++ * Trampolines for Nested Functions ++ ***********************************/ ++ ++#define TRAMPOLINE_TEMPLATE(FILE) \ ++ error ("trampolines not yet implemented") ++#define TRAMPOLINE_SIZE 20 ++#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ ++ error ("trampolines not yet implemented") ++ ++/*************************** ++ * Stack Layout and Calling Conventions ++ ***************************/ ++ ++/* ------------------ * ++ * Basic Stack Layout ++ * ------------------ */ ++ ++/* The downward variants are used by the compiler, ++ the upward ones serve as documentation */ ++#define STACK_GROWS_DOWNWARD ++#define FRAME_GROWS_UPWARD ++#define ARGS_GROW_UPWARD ++ ++#define STARTING_FRAME_OFFSET current_function_outgoing_args_size ++#define FIRST_PARM_OFFSET(FUNDECL) 0 ++ ++/* Before the prologue, RA lives in r31. */ ++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) ++ ++/* -------------------------------------- * ++ * Registers That Address the Stack Frame ++ * -------------------------------------- */ ++ ++#define STACK_POINTER_REGNUM SP_REGNO ++#define STATIC_CHAIN_REGNUM SC_REGNO ++#define PC_REGNUM PC_REGNO ++#define DWARF_FRAME_RETURN_COLUMN RA_REGNO ++ ++/* Base register for access to local variables of the function. We ++ pretend that the frame pointer is a non-existent hard register, and ++ then eliminate it to HARD_FRAME_POINTER_REGNUM. */ ++#define FRAME_POINTER_REGNUM FAKE_FP_REGNO ++ ++#define HARD_FRAME_POINTER_REGNUM FP_REGNO ++#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO ++/* the argumnet pointer needs to always be eliminated ++ so it is set to a fake hard register. */ ++#define ARG_POINTER_REGNUM FAKE_AP_REGNO ++ ++/* ----------------------------------------- * ++ * Eliminating Frame Pointer and Arg Pointer ++ * ----------------------------------------- */ ++ ++#define FRAME_POINTER_REQUIRED 0 ++ ++#define ELIMINABLE_REGS \ ++{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} ++ ++#define CAN_ELIMINATE(FROM, TO) 1 ++ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) ++ ++#define MUST_SAVE_REGISTER(regno) \ ++ ((regs_ever_live[regno] && !call_used_regs[regno]) \ ++ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ ++ || (regno == RA_REGNO && regs_ever_live[RA_REGNO])) ++ ++/* Treat LOC as a byte offset from the stack pointer and round it up ++ to the next fully-aligned offset. */ ++#define STACK_ALIGN(LOC) \ ++ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) ++ ++ ++/* ------------------------------ * ++ * Passing Arguments in Registers ++ * ------------------------------ */ ++ ++/* see nios2.c */ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ (function_arg (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0 ++ ++#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 ++ ++typedef struct nios2_args ++{ ++ int regs_used; ++} CUMULATIVE_ARGS; ++ ++/* This is to initialize the above unused CUM data type */ ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ ++ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) ++ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_advance (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_REGNO_P(REGNO) \ ++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) ++ ++#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ ++ { \ ++ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \ ++ (TYPE), (NO_RTL)); \ ++ if (pret_size) \ ++ (PRETEND_SIZE) = pret_size; \ ++ } ++ ++/* ----------------------------- * ++ * Generating Code for Profiling ++ * ----------------------------- */ ++ ++#define PROFILE_BEFORE_PROLOGUE ++ ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ function_profiler ((FILE), (LABELNO)) ++ ++/* --------------------------------------- * ++ * Passing Function Arguments on the Stack ++ * --------------------------------------- */ ++ ++#define PROMOTE_PROTOTYPES 1 ++ ++#define PUSH_ARGS 0 ++#define ACCUMULATE_OUTGOING_ARGS 1 ++ ++#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 ++ ++/* --------------------------------------- * ++ * How Scalar Function Values Are Returned ++ * --------------------------------------- */ ++ ++#define FUNCTION_VALUE(VALTYPE, FUNC) \ ++ gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) ++ ++#define LIBCALL_VALUE(MODE) \ ++ gen_rtx(REG, MODE, FIRST_RETVAL_REGNO) ++ ++#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) ++ ++/* ----------------------------- * ++ * How Large Values Are Returned ++ * ----------------------------- */ ++ ++ ++#define RETURN_IN_MEMORY(TYPE) \ ++ nios2_return_in_memory (TYPE) ++ ++ ++#define STRUCT_VALUE 0 ++ ++#define DEFAULT_PCC_STRUCT_RETURN 0 ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++ ++#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) ++ ++#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) ++ ++#define MAX_REGS_PER_ADDRESS 1 ++ ++/* Go to ADDR if X is a valid address. */ ++#ifndef REG_OK_STRICT ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 0)) \ ++ goto ADDR; \ ++ } ++#else ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 1)) \ ++ goto ADDR; \ ++ } ++#endif ++ ++#ifndef REG_OK_STRICT ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) ++#else ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) ++#endif ++ ++#define LEGITIMATE_CONSTANT_P(X) 1 ++ ++/* Nios II has no mode dependent addresses. */ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) ++ ++/* Set if this has a weak declaration */ ++#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) ++#define SYMBOL_REF_WEAK_DECL_P(RTX) \ ++ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) ++ ++ ++/* true if a symbol is both small and not weak. In this case, gp ++ relative access can be used */ ++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ ++ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX)) ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++#define SLOW_BYTE_ACCESS 1 ++ ++/* It is as good to call a constant function address as to call an address ++ kept in a register. ++ ??? Not true anymore really. Now that call cannot address full range ++ of memory callr may need to be used */ ++ ++#define NO_FUNCTION_CSE ++#define NO_RECURSIVE_FUNCTION_CSE ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* ------------------------------------------ * ++ * The Overall Framework of an Assembler File ++ * ------------------------------------------ */ ++ ++#define ASM_APP_ON "#APP\n" ++#define ASM_APP_OFF "#NO_APP\n" ++ ++#define ASM_COMMENT_START "# " ++ ++/* ------------------------------- * ++ * Output and Generation of Labels ++ * ------------------------------- */ ++ ++#define GLOBAL_ASM_OP "\t.global\t" ++ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++#define DWARF2_UNWIND_INFO 0 ++ ++ ++/* -------------------------------- * ++ * Assembler Commands for Alignment ++ * -------------------------------- */ ++ ++#define ASM_OUTPUT_ALIGN(FILE, LOG) \ ++ do { \ ++ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ ++ } while (0) ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++#define REGISTER_NAMES \ ++{ \ ++ "zero", \ ++ "at", \ ++ "r2", \ ++ "r3", \ ++ "r4", \ ++ "r5", \ ++ "r6", \ ++ "r7", \ ++ "r8", \ ++ "r9", \ ++ "r10", \ ++ "r11", \ ++ "r12", \ ++ "r13", \ ++ "r14", \ ++ "r15", \ ++ "r16", \ ++ "r17", \ ++ "r18", \ ++ "r19", \ ++ "r20", \ ++ "r21", \ ++ "r22", \ ++ "r23", \ ++ "r24", \ ++ "r25", \ ++ "gp", \ ++ "sp", \ ++ "fp", \ ++ "ta", \ ++ "ba", \ ++ "ra", \ ++ "status", \ ++ "estatus", \ ++ "bstatus", \ ++ "ipri", \ ++ "ecause", \ ++ "pc", \ ++ "rap", \ ++ "fake_fp", \ ++ "fake_ap", \ ++} ++ ++#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ ++ (PTR) = asm_output_opcode (STREAM, PTR) ++ ++#define PRINT_OPERAND(STREAM, X, CODE) \ ++ nios2_print_operand (STREAM, X, CODE) ++ ++#define PRINT_OPERAND_ADDRESS(STREAM, X) \ ++ nios2_print_operand_address (STREAM, X) ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ ++do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ ++ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ ++ } while (0) ++ ++ ++/* ------------ * ++ * Label Output ++ * ------------ */ ++ ++ ++/* ---------------------------------------------------- * ++ * Dividing the Output into Sections (Texts, Data, ...) ++ * ---------------------------------------------------- */ ++ ++/* Output before read-only data. */ ++#define TEXT_SECTION_ASM_OP ("\t.section\t.text") ++ ++/* Output before writable data. */ ++#define DATA_SECTION_ASM_OP ("\t.section\t.data") ++ ++ ++/* Default the definition of "small data" to 8 bytes. */ ++/* ??? How come I can't use HOST_WIDE_INT here? */ ++extern unsigned long nios2_section_threshold; ++#define NIOS2_DEFAULT_GVALUE 8 ++ ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized external linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef COMMON_ASM_OP ++#define COMMON_ASM_OP "\t.comm\t" ++ ++#undef ASM_OUTPUT_ALIGNED_COMMON ++#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ ++do \ ++{ \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ { \ ++ named_section (0, ".sbss", 0); \ ++ (*targetm.asm_out.globalize_label) (FILE, NAME); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++ } \ ++ else \ ++ { \ ++ fprintf ((FILE), "%s", COMMON_ASM_OP); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ ++ } \ ++} \ ++while (0) ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized internal linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef ASM_OUTPUT_ALIGNED_LOCAL ++#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ ++do { \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ named_section (0, ".sbss", 0); \ ++ else \ ++ named_section (0, ".bss", 0); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++} while (0) ++ ++ ++ ++/*************************** ++ * Miscellaneous Parameters ++ ***************************/ ++ ++#define MOVE_MAX 4 ++ ++#define Pmode SImode ++#define FUNCTION_MODE QImode ++ ++#define CASE_VECTOR_MODE Pmode ++ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++ ++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) ++ ++#define WORD_REGISTER_OPERATIONS +--- gcc-3.4.3/gcc/config/nios2/nios2.md ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md +@@ -0,0 +1,2078 @@ ++;; Machine Description for Altera NIOS 2G NIOS2 version. ++;; Copyright (C) 2003 Altera ++;; Contributed by Jonah Graham (jgraham@altera.com). ++;; ++;; This file is part of GNU CC. ++;; ++;; GNU CC is free software; you can redistribute it and/or modify ++;; it under the terms of the GNU General Public License as published by ++;; the Free Software Foundation; either version 2, or (at your option) ++;; any later version. ++;; ++;; GNU CC is distributed in the hope that it will be useful, ++;; but WITHOUT ANY WARRANTY; without even the implied warranty of ++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++;; GNU General Public License for more details. ++;; ++;; You should have received a copy of the GNU General Public License ++;; along with GNU CC; see the file COPYING. If not, write to ++;; the Free Software Foundation, 59 Temple Place - Suite 330, ++;; Boston, MA 02111-1307, USA. */ ++ ++ ++ ++;***************************************************************************** ++;* ++;* constants ++;* ++;***************************************************************************** ++(define_constants [ ++ (GP_REGNO 26) ++ (SP_REGNO 27) ++ (FP_REGNO 28) ++ (RA_REGNO 31) ++ (RAP_REGNO 38) ++ (FIRST_RETVAL_REGNO 2) ++ (LAST_RETVAL_REGNO 3) ++ (FIRST_ARG_REGNO 4) ++ (LAST_ARG_REGNO 7) ++ (SC_REGNO 23) ++ (PC_REGNO 37) ++ (FAKE_FP_REGNO 39) ++ (FAKE_AP_REGNO 40) ++ ++ ++ (UNSPEC_BLOCKAGE 0) ++ (UNSPEC_LDBIO 1) ++ (UNSPEC_LDBUIO 2) ++ (UNSPEC_LDHIO 3) ++ (UNSPEC_LDHUIO 4) ++ (UNSPEC_LDWIO 5) ++ (UNSPEC_STBIO 6) ++ (UNSPEC_STHIO 7) ++ (UNSPEC_STWIO 8) ++ (UNSPEC_SYNC 9) ++ (UNSPEC_WRCTL 10) ++ (UNSPEC_RDCTL 11) ++ ++]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* instruction scheduler ++;* ++;***************************************************************************** ++ ++; No schedule info is currently available, using an assumption that no ++; instruction can use the results of the previous instruction without ++; incuring a stall. ++ ++; length of an instruction (in bytes) ++(define_attr "length" "" (const_int 4)) ++(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex")) ++ ++(define_asm_attributes ++ [(set_attr "length" "4") ++ (set_attr "type" "complex")]) ++ ++(define_automaton "nios2") ++(automata_option "v") ++;(automata_option "no-minimization") ++(automata_option "ndfa") ++ ++; The nios2 pipeline is fairly straightforward for the fast model. ++; Every alu operation is pipelined so that an instruction can ++; be issued every cycle. However, there are still potential ++; stalls which this description tries to deal with. ++ ++(define_cpu_unit "cpu" "nios2") ++ ++(define_insn_reservation "complex" 1 ++ (eq_attr "type" "complex") ++ "cpu") ++ ++(define_insn_reservation "control" 1 ++ (eq_attr "type" "control") ++ "cpu") ++ ++(define_insn_reservation "alu" 1 ++ (eq_attr "type" "alu") ++ "cpu") ++ ++(define_insn_reservation "cond_alu" 1 ++ (eq_attr "type" "cond_alu") ++ "cpu") ++ ++(define_insn_reservation "st" 1 ++ (eq_attr "type" "st") ++ "cpu") ++ ++(define_insn_reservation "custom" 1 ++ (eq_attr "type" "custom") ++ "cpu") ++ ++; shifts, muls and lds have three cycle latency ++(define_insn_reservation "ld" 3 ++ (eq_attr "type" "ld") ++ "cpu") ++ ++(define_insn_reservation "shift" 3 ++ (eq_attr "type" "shift") ++ "cpu") ++ ++(define_insn_reservation "mul" 3 ++ (eq_attr "type" "mul") ++ "cpu") ++ ++(define_insn_reservation "div" 1 ++ (eq_attr "type" "div") ++ "cpu") ++ ++ ++;***************************************************************************** ++;* ++;* MOV Instructions ++;* ++;***************************************************************************** ++ ++(define_expand "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (match_operand:QI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, QImode)) ++ DONE; ++}) ++ ++(define_insn "movqi_internal" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") ++ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] ++ "(register_operand (operands[0], QImode) ++ || register_operand (operands[1], QImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stb%o0\\t%z1, %0 ++ ldbu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu")]) ++ ++(define_insn "ldbio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldbuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stbio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] ++ "" ++ "stbio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, HImode)) ++ DONE; ++}) ++ ++(define_insn "movhi_internal" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") ++ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] ++ "(register_operand (operands[0], HImode) ++ || register_operand (operands[1], HImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ sth%o0\\t%z1, %0 ++ ldhu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu,alu")]) ++ ++(define_insn "ldhio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldhuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "sthio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] ++ "" ++ "sthio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++(define_expand "movsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (match_operand:SI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, SImode)) ++ DONE; ++}) ++ ++(define_insn "movsi_internal" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") ++ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] ++ "(register_operand (operands[0], SImode) ++ || register_operand (operands[1], SImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stw%o0\\t%z1, %0 ++ ldw%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1 ++ addi\\t%0, gp, %%gprel(%1) ++ movhi\\t%0, %H1\;addi\\t%0, %0, %L1" ++ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) ++ ++(define_insn "ldwio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldwio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stwio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] ++ "" ++ "stwio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* zero extension ++;* ++;***************************************************************************** ++ ++ ++(define_insn "zero_extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xffff ++ ldhu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=r,r") ++ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* sign extension ++;* ++;***************************************************************************** ++ ++(define_expand "extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (16); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendhisi2_internal" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ++ "" ++ "ldh%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_expand "extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op0 = gen_lowpart (SImode, operands[0]); ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (op0, temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqihi2_internal" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++(define_expand "extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqisi2_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Arithmetic Operations ++;* ++;***************************************************************************** ++ ++(define_insn "addsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (plus:SI (match_operand:SI 1 "register_operand" "%r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "" ++ "add%i2\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "subsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++ "sub\\t%0, %z1, %2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "mulsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (mult:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "TARGET_HAS_MUL" ++ "mul%i2\\t%0, %1, %z2" ++ [(set_attr "type" "mul")]) ++ ++(define_expand "divsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++{ ++ if (!TARGET_HAS_DIV) ++ { ++ if (!TARGET_FAST_SW_DIV) ++ FAIL; ++ else ++ { ++ if (nios2_emit_expensive_div (operands, SImode)) ++ DONE; ++ } ++ } ++}) ++ ++(define_insn "divsi3_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "div\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "udivsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (udiv:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "divu\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "smulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxss\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++(define_insn "umulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxuu\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++ ++(define_expand "mulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) ++ (sign_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++(define_expand "umulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) ++ (zero_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++ ++ ++;***************************************************************************** ++;* ++;* Negate and ones complement ++;* ++;***************************************************************************** ++ ++(define_insn "negsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (neg:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "sub\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++(define_insn "one_cmplsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (not:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "nor\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++ ++ ++; Logical Operantions ++ ++(define_insn "andsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ and\\t%0, %1, %z2 ++ and%i2\\t%0, %1, %2 ++ andh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "iorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ or\\t%0, %1, %z2 ++ or%i2\\t%0, %1, %2 ++ orh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "*norsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) ++ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] ++ "" ++ "nor\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "xorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ xor\\t%0, %1, %z2 ++ xor%i2\\t%0, %1, %2 ++ xorh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Shifts ++;* ++;***************************************************************************** ++ ++(define_insn "ashlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashift:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sll%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "ashrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sra%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "lshrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "srl%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotate:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "rol%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "register_operand" "r,r")))] ++ "" ++ "ror\\t%0, %1, %2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "*shift_mul_constants" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "const_int_operand" "I")) ++ (match_operand:SI 3 "const_int_operand" "I")))] ++ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" ++{ ++ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); ++ rtx ops[3]; ++ ++ ops[0] = operands[0]; ++ ops[1] = operands[1]; ++ ops[2] = GEN_INT (mul); ++ ++ output_asm_insn ("muli\t%0, %1, %2", ops); ++ return ""; ++} ++ [(set_attr "type" "mul")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Prologue, Epilogue and Return ++;* ++;***************************************************************************** ++ ++(define_expand "prologue" ++ [(const_int 1)] ++ "" ++{ ++ expand_prologue (); ++ DONE; ++}) ++ ++(define_expand "epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (false); ++ DONE; ++}) ++ ++(define_expand "sibcall_epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (true); ++ DONE; ++}) ++ ++(define_insn "return" ++ [(return)] ++ "reload_completed && nios2_can_use_return_insn ()" ++ "ret\\t" ++) ++ ++(define_insn "return_from_epilogue" ++ [(use (match_operand 0 "pmode_register_operand" "")) ++ (return)] ++ "reload_completed" ++ "ret\\t" ++) ++ ++;; Block any insns from being moved before this point, since the ++;; profiling call to mcount can use various registers that aren't ++;; saved or used to pass arguments. ++ ++(define_insn "blockage" ++ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] ++ "" ++ "" ++ [(set_attr "type" "unknown") ++ (set_attr "length" "0")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Jumps and Calls ++;* ++;***************************************************************************** ++ ++(define_insn "indirect_jump" ++ [(set (pc) (match_operand:SI 0 "register_operand" "r"))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "jump" ++ [(set (pc) ++ (label_ref (match_operand 0 "" "")))] ++ "" ++ "br\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "indirect_call" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "indirect_call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%1" ++) ++ ++(define_expand "call" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_expand "call_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_insn "*call" ++ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) ++ (match_operand 1 "" "")) ++ (clobber (match_operand:SI 2 "register_operand" "=r"))] ++ "" ++ "call\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "*call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) ++ (match_operand 2 "" ""))) ++ (clobber (match_operand:SI 3 "register_operand" "=r"))] ++ "" ++ "call\\t%1" ++ [(set_attr "type" "control")]) ++ ++(define_expand "sibcall" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))])] ++ "" ++ { ++ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); ++ ++ if (operands[2] == NULL_RTX) ++ operands[2] = const0_rtx; ++ } ++) ++ ++(define_expand "sibcall_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))])] ++ "" ++ { ++ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); ++ ++ if (operands[3] == NULL_RTX) ++ operands[3] = const0_rtx; ++ } ++) ++ ++(define_insn "sibcall_insn" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))] ++ "" ++ "jmp\\t%0" ++) ++ ++(define_insn "sibcall_value_insn" ++ [(set (match_operand 0 "register_operand" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))] ++ "" ++ "jmp\\t%1" ++) ++ ++ ++ ++ ++(define_expand "tablejump" ++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))])] ++ "" ++ "" ++) ++ ++(define_insn "*tablejump" ++ [(set (pc) ++ (match_operand:SI 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Comparisons ++;* ++;***************************************************************************** ++;; Flow here is rather complex (based on MIPS): ++;; ++;; 1) The cmp{si,di,sf,df} routine is called. It deposits the ++;; arguments into the branch_cmp array, and the type into ++;; branch_type. No RTL is generated. ++;; ++;; 2) The appropriate branch define_expand is called, which then ++;; creates the appropriate RTL for the comparison and branch. ++;; Different CC modes are used, based on what type of branch is ++;; done, so that we can constrain things appropriately. There ++;; are assumptions in the rest of GCC that break if we fold the ++;; operands into the branchs for integer operations, and use cc0 ++;; for floating point, so we use the fp status register instead. ++;; If needed, an appropriate temporary is created to hold the ++;; of the integer compare. ++ ++(define_expand "cmpsi" ++ [(set (cc0) ++ (compare:CC (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "arith_operand" "")))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++(define_expand "tstsi" ++ [(set (cc0) ++ (match_operand:SI 0 "register_operand" ""))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = const0_rtx; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* setting a register from a comparison ++;* ++;***************************************************************************** ++ ++(define_expand "seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpeq%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpne%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmplt\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpge%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpge\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmplt%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpltu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpgeu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpgeu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpltu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* branches ++;* ++;***************************************************************************** ++ ++(define_insn "*cbranch" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:SI 2 "reg_or_0_operand" "rM") ++ (match_operand:SI 3 "reg_or_0_operand" "rM")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ "b%0\\t%z2, %z3, %l1" ++ [(set_attr "type" "control")]) ++ ++ ++(define_expand "beq" ++ [(set (pc) ++ (if_then_else (eq:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bne" ++ [(set (pc) ++ (if_then_else (ne:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgt" ++ [(set (pc) ++ (if_then_else (gt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bge" ++ [(set (pc) ++ (if_then_else (ge:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "ble" ++ [(set (pc) ++ (if_then_else (le:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "blt" ++ [(set (pc) ++ (if_then_else (lt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgtu" ++ [(set (pc) ++ (if_then_else (gtu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bgeu" ++ [(set (pc) ++ (if_then_else (geu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bleu" ++ [(set (pc) ++ (if_then_else (leu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bltu" ++ [(set (pc) ++ (if_then_else (ltu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* String and Block Operations ++;* ++;***************************************************************************** ++ ++; ??? This is all really a hack to get Dhrystone to work as fast as possible ++; things to be fixed: ++; * let the compiler core handle all of this, for that to work the extra ++; aliasing needs to be addressed. ++; * we use three temporary registers for loading and storing to ensure no ++; ld use stalls, this is excessive, because after the first ld/st only ++; two are needed. Only two would be needed all the way through if ++; we could schedule with other code. Consider: ++; 1 ld $1, 0($src) ++; 2 ld $2, 4($src) ++; 3 ld $3, 8($src) ++; 4 st $1, 0($dest) ++; 5 ld $1, 12($src) ++; 6 st $2, 4($src) ++; 7 etc. ++; The first store has to wait until 4. If it does not there will be one ++; cycle of stalling. However, if any other instruction could be placed ++; between 1 and 4, $3 would not be needed. ++; * In small we probably don't want to ever do this ourself because there ++; is no ld use stall. ++ ++(define_expand "movstrsi" ++ [(parallel [(set (match_operand:BLK 0 "general_operand" "") ++ (match_operand:BLK 1 "general_operand" "")) ++ (use (match_operand:SI 2 "const_int_operand" "")) ++ (use (match_operand:SI 3 "const_int_operand" "")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))])] ++ "TARGET_INLINE_MEMCPY" ++{ ++ rtx ld_addr_reg, st_addr_reg; ++ ++ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr ++ it trys to copy to a register, but does not re-try the predicate. ++ ??? Intead of fixing expr.c, I fix it here. */ ++ if (!const_int_operand (operands[2], SImode)) ++ FAIL; ++ ++ /* ??? there are some magic numbers which need to be sorted out here. ++ the basis for them is not increasing code size hugely or going ++ out of range of offset addressing */ ++ if (INTVAL (operands[3]) < 4) ++ FAIL; ++ if (!optimize ++ || (optimize_size && INTVAL (operands[2]) > 12) ++ || (optimize < 3 && INTVAL (operands[2]) > 100) ++ || INTVAL (operands[2]) > 200) ++ FAIL; ++ ++ st_addr_reg ++ = replace_equiv_address (operands[0], ++ copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); ++ ld_addr_reg ++ = replace_equiv_address (operands[1], ++ copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); ++ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, ++ operands[2], operands[3])); ++ ++ DONE; ++}) ++ ++ ++(define_insn "movstrsi_internal" ++ [(set (match_operand:BLK 0 "memory_operand" "=o") ++ (match_operand:BLK 1 "memory_operand" "o")) ++ (use (match_operand:SI 2 "const_int_operand" "i")) ++ (use (match_operand:SI 3 "const_int_operand" "i")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))] ++ "TARGET_INLINE_MEMCPY" ++{ ++ int ld_offset = INTVAL (operands[2]); ++ int ld_len = INTVAL (operands[2]); ++ int ld_reg = 0; ++ rtx ld_addr_reg = XEXP (operands[1], 0); ++ int st_offset = INTVAL (operands[2]); ++ int st_len = INTVAL (operands[2]); ++ int st_reg = 0; ++ rtx st_addr_reg = XEXP (operands[0], 0); ++ int delay_count = 0; ++ ++ /* ops[0] is the address used by the insn ++ ops[1] is the register being loaded or stored */ ++ rtx ops[2]; ++ ++ if (INTVAL (operands[3]) < 4) ++ abort (); ++ ++ while (ld_offset >= 4) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldw\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 4; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 2) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldh\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 2; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 1) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldb\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 1; ++ delay_count++; ++ } ++ ++ while (st_offset >= 4) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ while (st_offset >= 2) ++ { ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("sth\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 2; ++ } ++ ++ while (st_offset >= 1) ++ { ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stb\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 1; ++ } ++ ++ return ""; ++} ++; ??? lengths are not being used yet, but I will probably forget ++; to update this once I am using lengths, so set it to something ++; definetely big enough to cover it. 400 allows for 200 bytes ++; of motion. ++ [(set_attr "length" "400")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Custom instructions ++;* ++;***************************************************************************** ++ ++(define_constants [ ++ (CUSTOM_N 100) ++ (CUSTOM_NI 101) ++ (CUSTOM_NF 102) ++ (CUSTOM_NP 103) ++ (CUSTOM_NII 104) ++ (CUSTOM_NIF 105) ++ (CUSTOM_NIP 106) ++ (CUSTOM_NFI 107) ++ (CUSTOM_NFF 108) ++ (CUSTOM_NFP 109) ++ (CUSTOM_NPI 110) ++ (CUSTOM_NPF 111) ++ (CUSTOM_NPP 112) ++ (CUSTOM_IN 113) ++ (CUSTOM_INI 114) ++ (CUSTOM_INF 115) ++ (CUSTOM_INP 116) ++ (CUSTOM_INII 117) ++ (CUSTOM_INIF 118) ++ (CUSTOM_INIP 119) ++ (CUSTOM_INFI 120) ++ (CUSTOM_INFF 121) ++ (CUSTOM_INFP 122) ++ (CUSTOM_INPI 123) ++ (CUSTOM_INPF 124) ++ (CUSTOM_INPP 125) ++ (CUSTOM_FN 126) ++ (CUSTOM_FNI 127) ++ (CUSTOM_FNF 128) ++ (CUSTOM_FNP 129) ++ (CUSTOM_FNII 130) ++ (CUSTOM_FNIF 131) ++ (CUSTOM_FNIP 132) ++ (CUSTOM_FNFI 133) ++ (CUSTOM_FNFF 134) ++ (CUSTOM_FNFP 135) ++ (CUSTOM_FNPI 136) ++ (CUSTOM_FNPF 137) ++ (CUSTOM_FNPP 138) ++ (CUSTOM_PN 139) ++ (CUSTOM_PNI 140) ++ (CUSTOM_PNF 141) ++ (CUSTOM_PNP 142) ++ (CUSTOM_PNII 143) ++ (CUSTOM_PNIF 144) ++ (CUSTOM_PNIP 145) ++ (CUSTOM_PNFI 146) ++ (CUSTOM_PNFF 147) ++ (CUSTOM_PNFP 148) ++ (CUSTOM_PNPI 149) ++ (CUSTOM_PNPF 150) ++ (CUSTOM_PNPP 151) ++]) ++ ++ ++(define_insn "custom_n" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] ++ "" ++ "custom\\t%0, zero, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ni" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_np" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nii" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nif" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nip" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nff" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_in" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ini" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++(define_insn "custom_fn" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fni" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnii" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnif" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnip" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnff" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_pn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pni" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Misc ++;* ++;***************************************************************************** ++ ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop\\t" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "sync" ++ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] ++ "" ++ "sync\\t" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "rdctl" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))] ++ "" ++ "rdctl\\t%0, ctl%1" ++ [(set_attr "type" "control")]) ++ ++(define_insn "wrctl" ++ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") ++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_WRCTL)] ++ "" ++ "wrctl\\tctl%0, %1" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Peepholes ++;* ++;***************************************************************************** ++ ++ +--- gcc-3.4.3/gcc/config/nios2/t-nios2 ++++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2 +@@ -0,0 +1,123 @@ ++## ++## Compiler flags to use when compiling libgcc2.c. ++## ++## LIB2FUNCS_EXTRA ++## A list of source file names to be compiled or assembled and inserted into libgcc.a. ++ ++LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ ++ $(srcdir)/config/nios2/lib2-divmod-hi.c \ ++ $(srcdir)/config/nios2/lib2-divtable.c \ ++ $(srcdir)/config/nios2/lib2-mul.c ++ ++## ++## Floating Point Emulation ++## To have GCC include software floating point libraries in libgcc.a define FPBIT ++## and DPBIT along with a few rules as follows: ++## ++## # We want fine grained libraries, so use the new code ++## # to build the floating point emulation libraries. ++FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c ++DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c ++ ++TARGET_LIBGCC2_CFLAGS = -O2 ++ ++# FLOAT_ONLY - no doubles ++# SMALL_MACHINE - QI/HI is faster than SI ++# Actually SMALL_MACHINE uses chars and shorts instead of ints ++# since ints (16-bit ones as they are today) are at least as fast ++# as chars and shorts, don't define SMALL_MACHINE ++# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) ++ ++$(FPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '#define FLOAT' > ${FPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT} ++ ++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '' > ${DPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT} ++ ++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o ++ ++# Assemble startup files. ++$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm ++ ++$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm ++ ++ ++## You may need to provide additional #defines at the beginning of ++## fp-bit.c and dp-bit.c to control target endianness and other options ++## ++## CRTSTUFF_T_CFLAGS ++## Special flags used when compiling crtstuff.c. See Initialization. ++## ++## CRTSTUFF_T_CFLAGS_S ++## Special flags used when compiling crtstuff.c for shared linking. Used ++## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. ++## ++## MULTILIB_OPTIONS ++## For some targets, invoking GCC in different ways produces objects that ++## can not be linked together. For example, for some targets GCC produces ++## both big and little endian code. For these targets, you must arrange ++## for multiple versions of libgcc.a to be compiled, one for each set of ++## incompatible options. When GCC invokes the linker, it arranges to link ++## in the right version of libgcc.a, based on the command line options ++## used. ++## The MULTILIB_OPTIONS macro lists the set of options for which special ++## versions of libgcc.a must be built. Write options that are mutually ++## incompatible side by side, separated by a slash. Write options that may ++## be used together separated by a space. The build procedure will build ++## all combinations of compatible options. ++## ++## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, ++## Makefile will build special versions of libgcc.a using the following ++## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, ++## and -m68020 -msoft-float. ++ ++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx ++ ++## MULTILIB_DIRNAMES ++## If MULTILIB_OPTIONS is used, this variable specifies the directory names ++## that should be used to hold the various libraries. Write one element in ++## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If ++## MULTILIB_DIRNAMES is not used, the default value will be ++## MULTILIB_OPTIONS, with all slashes treated as spaces. ++## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, ++## then the default value of MULTILIB_DIRNAMES is m68000 m68020 ++## msoft-float. You may specify a different value if you desire a ++## different set of directory names. ++ ++# MULTILIB_DIRNAMES = ++ ++## MULTILIB_MATCHES ++## Sometimes the same option may be written in two different ways. If an ++## option is listed in MULTILIB_OPTIONS, GCC needs to know about any ++## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the ++## form option=option to describe all relevant synonyms. For example, ++## m68000=mc68000 m68020=mc68020. ++## ++## MULTILIB_EXCEPTIONS ++## Sometimes when there are multiple sets of MULTILIB_OPTIONS being ++## specified, there are combinations that should not be built. In that ++## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in ++## shell case syntax that should not be built. ++## For example, in the PowerPC embedded ABI support, it is not desirable to ++## build libraries compiled with the -mcall-aix option and either of the ++## -fleading-underscore or -mlittle options at the same time. Therefore ++## MULTILIB_EXCEPTIONS is set to ++## ++## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* ++## ++ ++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* ++ ++## ++## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building ++## multiple versions of libgcc.a certain options should always be passed on ++## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list ++## of options to be used for all builds. ++## ++ +--- gcc-3.4.3/gcc/config.gcc ++++ gcc-3.4.3-nios2/gcc/config.gcc +@@ -1321,6 +1321,10 @@ m32rle-*-linux*) + thread_file='posix' + fi + ;; ++# JBG ++nios2-*-* | nios2-*-*) ++ tm_file="elfos.h ${tm_file}" ++ ;; + # m68hc11 and m68hc12 share the same machine description. + m68hc11-*-*|m6811-*-*) + tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h" +--- gcc-3.4.3/gcc/cse.c ++++ gcc-3.4.3-nios2/gcc/cse.c +@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code + #ifdef FLOAT_STORE_FLAG_VALUE + REAL_VALUE_TYPE fsfv; + #endif ++#ifdef __nios2__ ++ if (p->is_const) ++ break; ++#endif + + /* If the entry isn't valid, skip it. */ + if (! exp_equiv_p (p->exp, p->exp, 1, 0)) +--- gcc-3.4.3/gcc/doc/extend.texi ++++ gcc-3.4.3-nios2/gcc/doc/extend.texi +@@ -5636,12 +5636,118 @@ to those machines. Generally these gene + instructions, but allow the compiler to schedule those calls. + + @menu ++* Altera Nios II Built-in Functions:: + * Alpha Built-in Functions:: + * ARM Built-in Functions:: + * X86 Built-in Functions:: + * PowerPC AltiVec Built-in Functions:: + @end menu + ++@node Altera Nios II Built-in Functions ++@subsection Altera Nios II Built-in Functions ++ ++These built-in functions are available for the Altera Nios II ++family of processors. ++ ++The following built-in functions are always available. They ++all generate the machine instruction that is part of the name. ++ ++@example ++int __builtin_ldbio (volatile const void *) ++int __builtin_ldbuio (volatile const void *) ++int __builtin_ldhio (volatile const void *) ++int __builtin_ldhuio (volatile const void *) ++int __builtin_ldwio (volatile const void *) ++void __builtin_stbio (volatile void *, int) ++void __builtin_sthio (volatile void *, int) ++void __builtin_stwio (volatile void *, int) ++void __builtin_sync (void) ++int __builtin_rdctl (int) ++void __builtin_wrctl (int, int) ++@end example ++ ++The following built-in functions are always available. They ++all generate a Nios II Custom Instruction. The name of the ++function represents the types that the function takes and ++returns. The letter before the @code{n} is the return type ++or void if absent. The @code{n} represnts the first parameter ++to all the custom instructions, the custom instruction number. ++The two letters after the @code{n} represent the up to two ++parameters to the function. ++ ++The letters reprsent the following data types: ++@table @code ++@item ++@code{void} for return type and no parameter for parameter types. ++ ++@item i ++@code{int} for return type and parameter type ++ ++@item f ++@code{float} for return type and parameter type ++ ++@item p ++@code{void *} for return type and parameter type ++ ++@end table ++ ++And the function names are: ++@example ++void __builtin_custom_n (void) ++void __builtin_custom_ni (int) ++void __builtin_custom_nf (float) ++void __builtin_custom_np (void *) ++void __builtin_custom_nii (int, int) ++void __builtin_custom_nif (int, float) ++void __builtin_custom_nip (int, void *) ++void __builtin_custom_nfi (float, int) ++void __builtin_custom_nff (float, float) ++void __builtin_custom_nfp (float, void *) ++void __builtin_custom_npi (void *, int) ++void __builtin_custom_npf (void *, float) ++void __builtin_custom_npp (void *, void *) ++int __builtin_custom_in (void) ++int __builtin_custom_ini (int) ++int __builtin_custom_inf (float) ++int __builtin_custom_inp (void *) ++int __builtin_custom_inii (int, int) ++int __builtin_custom_inif (int, float) ++int __builtin_custom_inip (int, void *) ++int __builtin_custom_infi (float, int) ++int __builtin_custom_inff (float, float) ++int __builtin_custom_infp (float, void *) ++int __builtin_custom_inpi (void *, int) ++int __builtin_custom_inpf (void *, float) ++int __builtin_custom_inpp (void *, void *) ++float __builtin_custom_fn (void) ++float __builtin_custom_fni (int) ++float __builtin_custom_fnf (float) ++float __builtin_custom_fnp (void *) ++float __builtin_custom_fnii (int, int) ++float __builtin_custom_fnif (int, float) ++float __builtin_custom_fnip (int, void *) ++float __builtin_custom_fnfi (float, int) ++float __builtin_custom_fnff (float, float) ++float __builtin_custom_fnfp (float, void *) ++float __builtin_custom_fnpi (void *, int) ++float __builtin_custom_fnpf (void *, float) ++float __builtin_custom_fnpp (void *, void *) ++void * __builtin_custom_pn (void) ++void * __builtin_custom_pni (int) ++void * __builtin_custom_pnf (float) ++void * __builtin_custom_pnp (void *) ++void * __builtin_custom_pnii (int, int) ++void * __builtin_custom_pnif (int, float) ++void * __builtin_custom_pnip (int, void *) ++void * __builtin_custom_pnfi (float, int) ++void * __builtin_custom_pnff (float, float) ++void * __builtin_custom_pnfp (float, void *) ++void * __builtin_custom_pnpi (void *, int) ++void * __builtin_custom_pnpf (void *, float) ++void * __builtin_custom_pnpp (void *, void *) ++@end example ++ ++ + @node Alpha Built-in Functions + @subsection Alpha Built-in Functions + +--- gcc-3.4.3/gcc/doc/invoke.texi ++++ gcc-3.4.3-nios2/gcc/doc/invoke.texi +@@ -337,6 +337,14 @@ in the following sections. + @item Machine Dependent Options + @xref{Submodel Options,,Hardware Models and Configurations}. + ++@emph{Altera Nios II Options} ++@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol ++-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol ++-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol ++-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol ++-mno-hw-div -mhw-div @gol ++-msys-crt0= -msys-lib= -msys=nosys } ++ + @emph{M680x0 Options} + @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol + -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol +@@ -5836,6 +5844,7 @@ machine description. The default for th + that macro, which enables you to change the defaults. + + @menu ++* Altera Nios II Options:: + * M680x0 Options:: + * M68hc1x Options:: + * VAX Options:: +@@ -5871,6 +5880,103 @@ that macro, which enables you to change + * FRV Options:: + @end menu + ++ ++@node Altera Nios II Options ++@subsection Altera Nios II Options ++@cindex Altera Nios II options ++ ++These are the @samp{-m} options defined for the Altera Nios II ++processor. ++ ++@table @gcctabopt ++ ++@item -msmallc ++@opindex msmallc ++ ++Link with a limited version of the C library, -lsmallc. For more ++information see the C Library Documentation. ++ ++ ++@item -mbypass-cache ++@itemx -mno-bypass-cache ++@opindex mno-bypass-cache ++@opindex mbypass-cache ++ ++Force all load and store instructions to always bypass cache by ++using io variants of the instructions. The default is to not ++bypass the cache. ++ ++@item -mno-cache-volatile ++@itemx -mcache-volatile ++@opindex mcache-volatile ++@opindex mno-cache-volatile ++ ++Volatile memory access bypass the cache using the io variants of ++the ld and st instructions. The default is to cache volatile ++accesses. ++ ++-mno-cache-volatile is deprecated and will be deleted in a ++future GCC release. ++ ++ ++@item -mno-inline-memcpy ++@itemx -minline-memcpy ++@opindex mno-inline-memcpy ++@opindex minline-memcpy ++ ++Do not inline memcpy. The default is to inline when -O is on. ++ ++ ++@item -mno-fast-sw-div ++@itemx -mfast-sw-div ++@opindex mno-fast-sw-div ++@opindex mfast-sw-div ++ ++Do no use table based fast divide for small numbers. The default ++is to use the fast divide at -O3 and above. ++ ++ ++@item -mno-hw-mul ++@itemx -mhw-mul ++@itemx -mno-hw-mulx ++@itemx -mhw-mulx ++@itemx -mno-hw-div ++@itemx -mhw-div ++@opindex mno-hw-mul ++@opindex mhw-mul ++@opindex mno-hw-mulx ++@opindex mhw-mulx ++@opindex mno-hw-div ++@opindex mhw-div ++ ++Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of ++instructions by the compiler. The default is to emit @code{mul} ++and not emit @code{div} and @code{mulx}. ++ ++The different combinations of @code{mul} and @code{mulx} instructions ++generate a different multilib options. ++ ++ ++@item -msys-crt0=@var{startfile} ++@opindex msys-crt0 ++ ++@var{startfile} is the file name of the startfile (crt0) to use ++when linking. The default is crt0.o that comes with libgloss ++and is only suitable for use with the instruction set ++simulator. ++ ++@item -msys-lib=@var{systemlib} ++@itemx -msys-lib=nosys ++@opindex msys-lib ++ ++@var{systemlib} is the library name of the library which provides ++the system calls required by the C library, e.g. @code{read}, @code{write} ++etc. The default is to use nosys, this library provides ++stub implementations of the calls and is part of libgloss. ++ ++@end table ++ ++ + @node M680x0 Options + @subsection M680x0 Options + @cindex M680x0 options +--- gcc-3.4.3/gcc/doc/md.texi ++++ gcc-3.4.3-nios2/gcc/doc/md.texi +@@ -1335,6 +1335,49 @@ However, here is a summary of the machin + available on some particular machines. + + @table @emph ++ ++@item Altera Nios II family---@file{nios2.h} ++@table @code ++ ++@item I ++Integer that is valid as an immediate operand in an ++instruction taking a signed 16-bit number. Range ++@minus{}32768 to 32767. ++ ++@item J ++Integer that is valid as an immediate operand in an ++instruction taking an unsigned 16-bit number. Range ++0 to 65535. ++ ++@item K ++Integer that is valid as an immediate operand in an ++instruction taking only the upper 16-bits of a ++32-bit number. Range 32-bit numbers with the lower ++16-bits being 0. ++ ++@item L ++Integer that is valid as an immediate operand for a ++shift instruction. Range 0 to 31. ++ ++ ++@item M ++Integer that is valid as an immediate operand for ++only the value 0. Can be used in conjunction with ++the format modifier @code{z} to use @code{r0} ++instead of @code{0} in the assembly output. ++ ++@item N ++Integer that is valid as an immediate operand for ++a custom instruction opcode. Range 0 to 255. ++ ++@item S ++Matches immediates which are addresses in the small ++data section and therefore can be added to @code{gp} ++as a 16-bit immediate to re-create their 32-bit value. ++ ++@end table ++ ++ + @item ARM family---@file{arm.h} + @table @code + @item f diff --git a/misc/buildroot/toolchain/gcc/3.4.3/arm-softfloat.patch.conditional b/misc/buildroot/toolchain/gcc/3.4.3/arm-softfloat.patch.conditional new file mode 100644 index 000000000..19d1b90da --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.3/arm-softfloat.patch.conditional @@ -0,0 +1,270 @@ +Note... modified my mjn3 to not conflict with the big endian arm patch. +Warning!!! Only the linux target is aware of TARGET_ENDIAN_DEFAULT. +Also changed + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{!mcpu=*:-mcpu=xscale} \ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +to + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +in gcc/config/arm/linux-elf.h. +# +# Submitted: +# +# Dimitry Andric , 2004-05-01 +# +# Description: +# +# Nicholas Pitre released this patch for gcc soft-float support here: +# http://lists.arm.linux.org.uk/pipermail/linux-arm/2003-October/006436.html +# +# This version has been adapted to work with gcc 3.4.0. +# +# The original patch doesn't distinguish between softfpa and softvfp modes +# in the way Nicholas Pitre probably meant. His description is: +# +# "Default is to use APCS-32 mode with soft-vfp. The old Linux default for +# floats can be achieved with -mhard-float or with the configure +# --with-float=hard option. If -msoft-float or --with-float=soft is used then +# software float support will be used just like the default but with the legacy +# big endian word ordering for double float representation instead." +# +# Which means the following: +# +# * If you compile without -mhard-float or -msoft-float, you should get +# software floating point, using the VFP format. The produced object file +# should have these flags in its header: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# * If you compile with -mhard-float, you should get hardware floating point, +# which always uses the FPA format. Object file header flags should be: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# * If you compile with -msoft-float, you should get software floating point, +# using the FPA format. This is done for compatibility reasons with many +# existing distributions. Object file header flags should be: +# +# private flags = 200: [APCS-32] [FPA float format] [software FP] +# +# The original patch from Nicholas Pitre contained the following constructs: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" +# +# However, gcc doesn't accept this ";:" notation, used in the 3rd line. This +# is probably the reason Robert Schwebel modified it to: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa -mfpu=softvfp}}" +# +# But this causes the following behaviour: +# +# * If you compile without -mhard-float or -msoft-float, the compiler generates +# software floating point instructions, but *nothing* is passed to the +# assembler, which results in an object file which has flags: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# This is not correct! +# +# * If you compile with -mhard-float, the compiler generates hardware floating +# point instructions, and passes "-mfpu=fpa" to the assembler, which results +# in an object file which has the same flags as in the previous item, but now +# those *are* correct. +# +# * If you compile with -msoft-float, the compiler generates software floating +# point instructions, and passes "-mfpu=softfpa -mfpu=softvfp" (in that +# order) to the assembler, which results in an object file with flags: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# This is not correct, because the last "-mfpu=" option on the assembler +# command line determines the actual FPU convention used (which should be FPA +# in this case). +# +# Therefore, I modified this patch to get the desired behaviour. Every +# instance of the notation: +# +# %{msoft-float:-mfpu=softfpa -mfpu=softvfp} +# +# was changed to: +# +# %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp} +# +# I also did the following: +# +# * Modified all TARGET_DEFAULT macros I could find to include ARM_FLAG_VFP, to +# be consistent with Nicholas' original patch. +# * Removed any "msoft-float" or "mhard-float" from all MULTILIB_DEFAULTS +# macros I could find. I think that if you compile without any options, you +# would like to get the defaults. :) +# * Removed the extra -lfloat option from LIBGCC_SPEC, since it isn't needed +# anymore. (The required functions are now in libgcc.) + +diff -urN gcc-3.4.1-old/gcc/config/arm/coff.h gcc-3.4.1/gcc/config/arm/coff.h +--- gcc-3.4.1-old/gcc/config/arm/coff.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/coff.h 2004-09-02 21:51:15.000000000 -0500 +@@ -31,11 +31,16 @@ + #define TARGET_VERSION fputs (" (ARM/coff)", stderr) + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork" } + #endif + + /* This is COFF, but prefer stabs. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/elf.h gcc-3.4.1/gcc/config/arm/elf.h +--- gcc-3.4.1-old/gcc/config/arm/elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -46,7 +46,9 @@ + + #ifndef SUBTARGET_ASM_FLOAT_SPEC + #define SUBTARGET_ASM_FLOAT_SPEC "\ +-%{mapcs-float:-mfloat} %{msoft-float:-mfpu=softfpa}" ++%{mapcs-float:-mfloat} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + #endif + + #ifndef ASM_SPEC +@@ -106,12 +108,17 @@ + #endif + + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } + #endif + + #define TARGET_ASM_FILE_START_APP_OFF true +diff -urN gcc-3.4.1-old/gcc/config/arm/linux-elf.h gcc-3.4.1/gcc/config/arm/linux-elf.h +--- gcc-3.4.1-old/gcc/config/arm/linux-elf.h 2004-09-02 21:50:52.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h 2004-09-02 22:00:49.000000000 -0500 +@@ -44,12 +44,26 @@ + #define TARGET_LINKER_EMULATION "armelf_linux" + #endif + +-/* Default is to use APCS-32 mode. */ ++/* ++ * Default is to use APCS-32 mode with soft-vfp. ++ * The old Linux default for floats can be achieved with -mhard-float ++ * or with the configure --with-float=hard option. ++ * If -msoft-float or --with-float=soft is used then software float ++ * support will be used just like the default but with the legacy ++ * big endian word ordering for double float representation instead. ++ */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT \ +- ( ARM_FLAG_APCS_32 | \ +- ARM_FLAG_MMU_TRAPS | \ +- TARGET_ENDIAN_DEFAULT ) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_SOFT_FLOAT \ ++ | TARGET_ENDIAN_DEFAULT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_MMU_TRAPS ) ++ ++#undef SUBTARGET_EXTRA_ASM_SPEC ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +@@ -57,7 +71,7 @@ + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -72,7 +86,7 @@ + %{shared:-lc} \ + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" + +-#define LIBGCC_SPEC "%{msoft-float:-lfloat} -lgcc" ++#define LIBGCC_SPEC "-lgcc" + + /* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add + the GNU/Linux magical crtbegin.o file (see crtstuff.c) which +diff -urN gcc-3.4.1-old/gcc/config/arm/t-linux gcc-3.4.1/gcc/config/arm/t-linux +--- gcc-3.4.1-old/gcc/config/arm/t-linux 2003-09-20 16:09:07.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/t-linux 2004-09-02 21:51:15.000000000 -0500 +@@ -4,7 +4,10 @@ + LIBGCC2_DEBUG_CFLAGS = -g0 + + LIB1ASMSRC = arm/lib1funcs.asm +-LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx ++LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx \ ++ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \ ++ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ ++ _fixsfsi _fixunssfsi + + # MULTILIB_OPTIONS = mhard-float/msoft-float + # MULTILIB_DIRNAMES = hard-float soft-float +diff -urN gcc-3.4.1-old/gcc/config/arm/unknown-elf.h gcc-3.4.1/gcc/config/arm/unknown-elf.h +--- gcc-3.4.1-old/gcc/config/arm/unknown-elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/unknown-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -30,7 +30,12 @@ + + /* Default to using APCS-32 and software floating point. */ + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + /* Now we define the strings used to build the spec file. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/xscale-elf.h gcc-3.4.1/gcc/config/arm/xscale-elf.h +--- gcc-3.4.1-old/gcc/config/arm/xscale-elf.h 2003-07-01 18:26:43.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/xscale-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -49,11 +49,12 @@ + endian, regardless of the endian-ness of the memory + system. */ + +-#define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +- %{mhard-float:-mfpu=fpa} \ +- %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{!mcpu=*:-mcpu=xscale} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "mlittle-endian", "mno-thumb-interwork", "marm", "msoft-float" } ++ { "mlittle-endian", "mno-thumb-interwork", "marm" } + #endif diff --git a/misc/buildroot/toolchain/gcc/3.4.4/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/3.4.4/300-libstdc++-pic.patch new file mode 100644 index 000000000..9f304a4c4 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/300-libstdc++-pic.patch @@ -0,0 +1,47 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -224,6 +224,10 @@ + @OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCPP_BUILD_DEBUG + all-local: build_debug + +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -585,7 +585,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -618,6 +618,7 @@ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-data-local \ + install-exec install-exec-am install-info install-info-am \ ++ install-exec-local \ + install-man install-strip install-toolexeclibLTLIBRARIES \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ +@@ -707,6 +708,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/3.4.4/600-gcc34-arm-ldm-peephole.patch b/misc/buildroot/toolchain/gcc/3.4.4/600-gcc34-arm-ldm-peephole.patch new file mode 100644 index 000000000..0c370502c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/600-gcc34-arm-ldm-peephole.patch @@ -0,0 +1,65 @@ +--- gcc-3.4.0/gcc/config/arm/arm.md.arm-ldm-peephole 2004-01-13 08:24:37.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.md 2004-04-24 18:18:04.000000000 -0400 +@@ -8810,13 +8810,16 @@ + (set_attr "length" "4,8,8")] + ) + ++; Try to convert LDR+LDR+arith into [add+]LDM+arith ++; On XScale, LDM is always slower than two LDRs, so only do this if ++; optimising for size. + (define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] +- "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" ++ "TARGET_ARM && (!arm_tune_xscale || optimize_size) && adjacent_mem_locations (operands[2], operands[3])" + "* + { + rtx ldm[3]; +@@ -8851,6 +8854,8 @@ + } + if (val1 && val2) + { ++ /* This would be a loss on a Harvard core, but adjacent_mem_locations() ++ will prevent it from happening. */ + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm-peephole 2004-04-24 18:16:25.000000000 -0400 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:18:04.000000000 -0400 +@@ -4838,6 +4841,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* ldmia */ + +@@ -5064,6 +5072,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* stmia */ + +--- gcc-3.4.0/gcc/genpeep.c.arm-ldm-peephole 2003-07-05 01:27:22.000000000 -0400 ++++ gcc-3.4.0/gcc/genpeep.c 2004-04-24 18:18:04.000000000 -0400 +@@ -381,6 +381,7 @@ + printf ("#include \"recog.h\"\n"); + printf ("#include \"except.h\"\n\n"); + printf ("#include \"function.h\"\n\n"); ++ printf ("#include \"flags.h\"\n\n"); + + printf ("#ifdef HAVE_peephole\n"); + printf ("extern rtx peep_operand[];\n\n"); diff --git a/misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm-peephole2.patch b/misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm-peephole2.patch new file mode 100644 index 000000000..27f7c07db --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm-peephole2.patch @@ -0,0 +1,42 @@ +The 30_all_gcc34-arm-ldm-peephole.patch from Debian was conflicting +with the newer 36_all_pr16201-fix.patch, so i cut out the hunk from +it that was causing problems and grabbed an updated version from +upstream cvs. + +Index: gcc/config/arm/arm.c +=================================================================== +RCS file: /cvsroot/gcc/gcc/gcc/config/arm/arm.c,v +retrieving revision 1.432 +retrieving revision 1.433 +diff -u -r1.432 -r1.433 +--- gcc-3.4.4/gcc/config/arm/arm.c 29 Mar 2005 03:00:23 -0000 1.432 ++++ gcc-3.4.4/gcc/config/arm/arm.c 1 Apr 2005 11:02:22 -0000 1.433 +@@ -5139,6 +5139,10 @@ + int + adjacent_mem_locations (rtx a, rtx b) + { ++ /* We don't guarantee to preserve the order of these memory refs. */ ++ if (volatile_refs_p (a) || volatile_refs_p (b)) ++ return 0; ++ + if ((GET_CODE (XEXP (a, 0)) == REG + || (GET_CODE (XEXP (a, 0)) == PLUS + && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT)) +@@ -5178,6 +5182,17 @@ + return 0; + + val_diff = val1 - val0; ++ ++ if (arm_ld_sched) ++ { ++ /* If the target has load delay slots, then there's no benefit ++ to using an ldm instruction unless the offset is zero and ++ we are optimizing for size. */ ++ return (optimize_size && (REGNO (reg0) == REGNO (reg1)) ++ && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4) ++ && (val_diff == 4 || val_diff == -4)); ++ } ++ + return ((REGNO (reg0) == REGNO (reg1)) + && (val_diff == 4 || val_diff == -4)); + } diff --git a/misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm.patch b/misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm.patch new file mode 100644 index 000000000..142052fdf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/601-gcc34-arm-ldm.patch @@ -0,0 +1,119 @@ +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm 2004-02-27 09:51:05.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:16:25.000000000 -0400 +@@ -8520,6 +8520,26 @@ + return_used_this_function = 0; + } + ++/* Return the number (counting from 0) of ++ the least significant set bit in MASK. */ ++ ++#ifdef __GNUC__ ++inline ++#endif ++static int ++number_of_first_bit_set (mask) ++ int mask; ++{ ++ int bit; ++ ++ for (bit = 0; ++ (mask & (1 << bit)) == 0; ++ ++bit) ++ continue; ++ ++ return bit; ++} ++ + const char * + arm_output_epilogue (rtx sibling) + { +@@ -8753,27 +8773,47 @@ + saved_regs_mask |= (1 << PC_REGNUM); + } + +- /* Load the registers off the stack. If we only have one register +- to load use the LDR instruction - it is faster. */ +- if (saved_regs_mask == (1 << LR_REGNUM)) +- { +- /* The exception handler ignores the LR, so we do +- not really need to load it off the stack. */ +- if (eh_ofs) +- asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); +- else +- asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM); +- } +- else if (saved_regs_mask) ++ if (saved_regs_mask) + { +- if (saved_regs_mask & (1 << SP_REGNUM)) +- /* Note - write back to the stack register is not enabled +- (ie "ldmfd sp!..."). We know that the stack pointer is +- in the list of registers and if we add writeback the +- instruction becomes UNPREDICTABLE. */ +- print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ /* Load the registers off the stack. If we only have one register ++ to load use the LDR instruction - it is faster. */ ++ if (bit_count (saved_regs_mask) == 1) ++ { ++ int reg = number_of_first_bit_set (saved_regs_mask); ++ ++ switch (reg) ++ { ++ case SP_REGNUM: ++ /* Mustn't use base writeback when loading SP. */ ++ asm_fprintf (f, "\tldr\t%r, [%r]\n", SP_REGNUM, SP_REGNUM); ++ break; ++ ++ case LR_REGNUM: ++ if (eh_ofs) ++ { ++ /* The exception handler ignores the LR, so we do ++ not really need to load it off the stack. */ ++ asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); ++ break; ++ } ++ /* else fall through */ ++ ++ default: ++ asm_fprintf (f, "\tldr\t%r, [%r], #4\n", reg, SP_REGNUM); ++ break; ++ } ++ } + else +- print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ { ++ if (saved_regs_mask & (1 << SP_REGNUM)) ++ /* Note - write back to the stack register is not enabled ++ (ie "ldmfd sp!..."). We know that the stack pointer is ++ in the list of registers and if we add writeback the ++ instruction becomes UNPREDICTABLE. */ ++ print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ else ++ print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ } + } + + if (current_function_pretend_args_size) +@@ -11401,22 +11441,6 @@ + } + } + +-/* Return the number (counting from 0) of +- the least significant set bit in MASK. */ +- +-inline static int +-number_of_first_bit_set (int mask) +-{ +- int bit; +- +- for (bit = 0; +- (mask & (1 << bit)) == 0; +- ++bit) +- continue; +- +- return bit; +-} +- + /* Generate code to return from a thumb function. + If 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ diff --git a/misc/buildroot/toolchain/gcc/3.4.4/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/3.4.4/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..4377c2143 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +--- gcc-3.4.1/libstdc++-v3/libmath/Makefile.am~ 2003-08-27 22:29:42.000000000 +0100 ++++ gcc-3.4.1/libstdc++-v3/libmath/Makefile.am 2004-07-22 16:41:45.152130128 +0100 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC +--- gcc-3.4.1/libstdc++-v3/fragment.am.old 2004-07-22 18:24:58.024083656 +0100 ++++ gcc-3.4.1/libstdc++-v3/fragment.am 2004-07-22 18:24:59.019932264 +0100 +@@ -18,7 +18,7 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + + + diff --git a/misc/buildroot/toolchain/gcc/3.4.4/700-pr15068-fix.patch b/misc/buildroot/toolchain/gcc/3.4.4/700-pr15068-fix.patch new file mode 100644 index 000000000..2977765c5 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/700-pr15068-fix.patch @@ -0,0 +1,44 @@ +See http://gcc.gnu.org/PR15068 + +Fixes error + +../sysdeps/generic/s_fmax.c: In function `__fmax': +../sysdeps/generic/s_fmax.c:28: internal compiler error: in elim_reg_cond, at flow.c:3257 +Please submit a full bug report, +with preprocessed source if appropriate. +See for instructions. +make[2]: *** [/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/build-glibc/math/s_fmax.o] Error 1 +make[2]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822/math' +make[1]: *** [math/others] Error 2 +make[1]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822' +make: *** [all] Error 2 + +[ rediffed against gcc-3.4.1, with elbow grease, ending up with same thing as +http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/flow.c.diff?cvsroot=gcc&only_with_tag=csl-arm-branch&r1=1.563.4.2&r2=1.563.4.3 ] + +--- gcc-3.4.1/gcc/flow.c.old 2004-02-27 19:39:19.000000000 -0800 ++++ gcc-3.4.1/gcc/flow.c 2004-08-26 07:29:46.000000000 -0700 +@@ -1878,6 +1878,7 @@ + rtx set_src = SET_SRC (pc_set (BB_END (bb))); + rtx cond_true = XEXP (set_src, 0); + rtx reg = XEXP (cond_true, 0); ++ enum rtx_code inv_cond; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); +@@ -1886,11 +1887,13 @@ + in the form of a comparison of a register against zero. + If the condition is more complex than that, then it is safe + not to record any information. */ +- if (GET_CODE (reg) == REG ++ inv_cond = reversed_comparison_code (cond_true, BB_END (bb)); ++ if (inv_cond != UNKNOWN ++ && GET_CODE (reg) == REG + && XEXP (cond_true, 1) == const0_rtx) + { + rtx cond_false +- = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)), ++ = gen_rtx_fmt_ee (inv_cond, + GET_MODE (cond_true), XEXP (cond_true, 0), + XEXP (cond_true, 1)); + if (GET_CODE (XEXP (set_src, 1)) == PC) diff --git a/misc/buildroot/toolchain/gcc/3.4.4/71_all_sh-pr16665-fix.patch b/misc/buildroot/toolchain/gcc/3.4.4/71_all_sh-pr16665-fix.patch new file mode 100644 index 000000000..680bb3978 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/71_all_sh-pr16665-fix.patch @@ -0,0 +1,43 @@ +--- gcc/gcc/config/sh/sh.c ++++ gcc/gcc/config/sh/sh.c +@@ -9106,6 +9106,15 @@ sh_output_mi_thunk (FILE *file, tree thu + } + this = FUNCTION_ARG (cum, Pmode, ptr_type_node, 1); + ++ /* In PIC case, we set PIC register to compute the target address. We ++ can use a scratch register to save and restore the original value ++ except for SHcompact. For SHcompact, use stack. */ ++ if (flag_pic && TARGET_SHCOMPACT) ++ { ++ push (PIC_OFFSET_TABLE_REGNUM); ++ emit_insn (gen_GOTaddr2picreg ()); ++ } ++ + /* For SHcompact, we only have r0 for a scratch register: r1 is the + static chain pointer (even if you can't have nested virtual functions + right now, someone might implement them sometime), and the rest of the +@@ -9188,8 +9197,24 @@ sh_output_mi_thunk (FILE *file, tree thu + assemble_external (function); + TREE_USED (function) = 1; + } ++ /* We can use scratch1 to save and restore the original value of ++ PIC register except for SHcompact. */ ++ if (flag_pic && ! TARGET_SHCOMPACT) ++ { ++ emit_move_insn (scratch1, ++ gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)); ++ emit_insn (gen_GOTaddr2picreg ()); ++ } + funexp = XEXP (DECL_RTL (function), 0); + emit_move_insn (scratch2, funexp); ++ if (flag_pic) ++ { ++ if (! TARGET_SHCOMPACT) ++ emit_move_insn (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM), ++ scratch1); ++ else ++ pop (PIC_OFFSET_TABLE_REGNUM); ++ } + funexp = gen_rtx_MEM (FUNCTION_MODE, scratch2); + sibcall = emit_call_insn (gen_sibcall (funexp, const0_rtx, NULL_RTX)); + SIBLING_CALL_P (sibcall) = 1; diff --git a/misc/buildroot/toolchain/gcc/3.4.4/72_all_sh-no-reorder-blocks.patch b/misc/buildroot/toolchain/gcc/3.4.4/72_all_sh-no-reorder-blocks.patch new file mode 100644 index 000000000..8b9826831 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/72_all_sh-no-reorder-blocks.patch @@ -0,0 +1,13 @@ +--- g/gcc/config/sh/sh.h ++++ g/gcc/config/sh/sh.h +@@ -422,6 +422,10 @@ + do { \ + if (LEVEL) \ + flag_omit_frame_pointer = -1; \ ++ if (LEVEL <= 2) \ ++ { \ ++ flag_reorder_blocks = 0; \ ++ } \ + if (SIZE) \ + target_flags |= SPACE_BIT; \ + if (TARGET_SHMEDIA && LEVEL > 1) \ diff --git a/misc/buildroot/toolchain/gcc/3.4.4/73_all_sh-pr20617.patch b/misc/buildroot/toolchain/gcc/3.4.4/73_all_sh-pr20617.patch new file mode 100644 index 000000000..6d8021cc7 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/73_all_sh-pr20617.patch @@ -0,0 +1,28 @@ +2005-03-24 J"orn Rennecke + + Band aid for PR target/20617: + * config/sh/lib1funcs.asm (FUNC, ALIAS): Add .hidden directive. + +--- g/gcc/config/sh/lib1funcs.asm ++++ g/gcc/config/sh/lib1funcs.asm +@@ -37,9 +37,19 @@ Boston, MA 02111-1307, USA. */ + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + ++#define ALIAS(X,Y) .global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y) ++ + #ifdef __ELF__ + #define LOCAL(X) .L_##X +-#define FUNC(X) .type X,@function ++ ++#if 1 /* ??? The export list mechanism is broken, everything that is not ++ hidden is exported. */ ++#undef FUNC ++#define FUNC(X) .type X,@function; .hidden X ++#undef ALIAS ++#define ALIAS(X,Y) .global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y); .hidden GLOBAL(X) ++#endif ++ + #define ENDFUNC0(X) .Lfe_##X: .size X,.Lfe_##X-X + #define ENDFUNC(X) ENDFUNC0(X) + #else diff --git a/misc/buildroot/toolchain/gcc/3.4.4/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/3.4.4/800-arm-bigendian.patch new file mode 100644 index 000000000..04e998419 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/800-arm-bigendian.patch @@ -0,0 +1,68 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-3.4.1-dist/gcc/config/arm/linux-elf.h ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h +@@ -30,17 +30,34 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + /* Default is to use APCS-32 mode. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 | \ ++ ARM_FLAG_MMU_TRAPS | \ ++ TARGET_ENDIAN_DEFAULT ) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -101,7 +118,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + #endif + +--- gcc-3.4.1-dist/gcc/config.gcc ++++ gcc-3.4.1/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="t-slibgcc-elf-ver t-linux arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/3.4.4/830-gcc-bug-num-22167.patch b/misc/buildroot/toolchain/gcc/3.4.4/830-gcc-bug-num-22167.patch new file mode 100644 index 000000000..c7419af90 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/830-gcc-bug-num-22167.patch @@ -0,0 +1,16 @@ +Index: gcc/gcse.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gcse.c,v +retrieving revision 1.288.2.9 +diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.288.2.9 gcse.c +--- gcc/gcc/gcse.c 30 Oct 2004 18:02:53 -0000 1.288.2.9 ++++ gcc/gcc/gcse.c 14 Jul 2005 13:19:57 -0000 +@@ -6445,7 +6445,7 @@ hoist_code (void) + insn_inserted_p = 0; + + /* These tests should be the same as the tests above. */ +- if (TEST_BIT (hoist_vbeout[bb->index], i)) ++ if (TEST_BIT (hoist_exprs[bb->index], i)) + { + /* We've found a potentially hoistable expression, now + we look at every block BB dominates to see if it diff --git a/misc/buildroot/toolchain/gcc/3.4.4/900-nios2.patch b/misc/buildroot/toolchain/gcc/3.4.4/900-nios2.patch new file mode 100644 index 000000000..bfa06a21c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/900-nios2.patch @@ -0,0 +1,10211 @@ +--- gcc-3.4.3/gcc/Makefile.in ++++ gcc-3.4.3-nios2/gcc/Makefile.in +@@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_ + $(INSTALL_DATA) $(srcdir)/README-fixinc \ + $(DESTDIR)$(itoolsdatadir)/include/README ; \ + $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \ +- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \ ++ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \ + $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ + $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \ + else :; fi +--- gcc-3.4.3/gcc/combine.c ++++ gcc-3.4.3-nios2/gcc/combine.c +@@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin + mode); + } + ++#ifndef __nios2__ ++/* This screws up Nios II in this test case: ++ ++if (x & 1) ++ return 2; ++else ++ return 3; ++*/ + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx +@@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin + gen_lowpart_for_combine (mode, op0), + const1_rtx); + } ++#endif + + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT +--- gcc-3.4.3/gcc/config/nios2/crti.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm +@@ -0,0 +1,88 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just make a stack frame for the contents of the .fini and ++.init sections. Users may put any desired instructions in those ++sections. ++ ++ ++While technically any code can be put in the init and fini sections ++most stuff will not work other than stuff which obeys the call frame ++and ABI. All the call-preserved registers are saved, the call clobbered ++registers should have been saved by the code calling init and fini. ++ ++See crtstuff.c for an example of code that inserts itself in the ++init and fini sections. ++ ++See crt0.s for the code that calls init and fini. ++*/ ++ ++ .file "crti.asm" ++ ++ .section ".init" ++ .align 2 ++ .global _init ++_init: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ ++ .section ".fini" ++ .align 2 ++ .global _fini ++_fini: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ +--- gcc-3.4.3/gcc/config/nios2/crtn.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm +@@ -0,0 +1,70 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just makes sure that the .fini and .init sections do in ++fact return. Users may put any desired instructions in those sections. ++This file is the last thing linked into any executable. ++*/ ++ .file "crtn.asm" ++ ++ ++ ++ .section ".init" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ ++ .section ".fini" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c +@@ -0,0 +1,123 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern HItype __modhi3 (HItype, HItype); ++extern HItype __divhi3 (HItype, HItype); ++extern HItype __umodhi3 (HItype, HItype); ++extern HItype __udivhi3 (HItype, HItype); ++ ++static UHItype udivmodhi4(UHItype, UHItype, word_type); ++ ++static UHItype ++udivmodhi4(UHItype num, UHItype den, word_type modwanted) ++{ ++ UHItype bit = 1; ++ UHItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<15))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++HItype ++__divhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodhi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__modhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodhi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__udivhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 0); ++} ++ ++ ++HItype ++__umodhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c +@@ -0,0 +1,126 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern SItype __modsi3 (SItype, SItype); ++extern SItype __divsi3 (SItype, SItype); ++extern SItype __umodsi3 (SItype, SItype); ++extern SItype __udivsi3 (SItype, SItype); ++ ++static USItype udivmodsi4(USItype, USItype, word_type); ++ ++/* 16-bit SI divide and modulo as used in NIOS */ ++ ++ ++static USItype ++udivmodsi4(USItype num, USItype den, word_type modwanted) ++{ ++ USItype bit = 1; ++ USItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<31))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__modsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__udivsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 0); ++} ++ ++ ++SItype ++__umodsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c +@@ -0,0 +1,46 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++UQItype __divsi3_table[] = ++{ ++ 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15, ++ 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15, ++ 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15, ++ 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15, ++ 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15, ++ 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15, ++ 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15, ++ 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15, ++ 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15, ++ 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15, ++ 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15, ++ 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15, ++ 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15, ++ 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15, ++ 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15, ++ 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15, ++}; ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-mul.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c +@@ -0,0 +1,103 @@ ++/* while we are debugging (ie compile outside of gcc build) ++ disable gcc specific headers */ ++#ifndef DEBUG_MULSI3 ++ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++#else ++#define SItype int ++#define USItype unsigned int ++#endif ++ ++ ++extern SItype __mulsi3 (SItype, SItype); ++ ++SItype ++__mulsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = a; ++ ++ while (cnt) ++ { ++ if (cnt & 1) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt >>= 1; ++ } ++ ++ return res; ++} ++/* ++TODO: Choose best alternative implementation. ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = 0; ++ ++ while (cnt < 32) ++ { ++ if (a & (1L << cnt)) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt++; ++ } ++ ++ return res; ++} ++*/ ++ ++ ++#ifdef DEBUG_MULSI3 ++ ++int ++main () ++{ ++ int i, j; ++ int error = 0; ++ ++ for (i = -1000; i < 1000; i++) ++ for (j = -1000; j < 1000; j++) ++ { ++ int expect = i * j; ++ int actual = A__divsi3 (i, j); ++ if (expect != actual) ++ { ++ printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++#endif +--- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c +@@ -0,0 +1,1652 @@ ++ ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c +@@ -0,0 +1,1652 @@ ++#define FLOAT ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-protos.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h +@@ -0,0 +1,70 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++extern void dump_frame_size (FILE *); ++extern HOST_WIDE_INT compute_frame_size (void); ++extern int nios2_initial_elimination_offset (int, int); ++extern void override_options (void); ++extern void optimization_options (int, int); ++extern int nios2_can_use_return_insn (void); ++extern void expand_prologue (void); ++extern void expand_epilogue (bool); ++extern void function_profiler (FILE *, int); ++ ++ ++#ifdef RTX_CODE ++extern int nios2_legitimate_address (rtx, enum machine_mode, int); ++extern void nios2_print_operand (FILE *, rtx, int); ++extern void nios2_print_operand_address (FILE *, rtx); ++ ++extern int nios2_emit_move_sequence (rtx *, enum machine_mode); ++extern int nios2_emit_expensive_div (rtx *, enum machine_mode); ++ ++extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); ++extern void gen_conditional_move (rtx *, enum machine_mode); ++extern const char *asm_output_opcode (FILE *, const char *); ++ ++/* predicates */ ++extern int arith_operand (rtx, enum machine_mode); ++extern int uns_arith_operand (rtx, enum machine_mode); ++extern int logical_operand (rtx, enum machine_mode); ++extern int shift_operand (rtx, enum machine_mode); ++extern int reg_or_0_operand (rtx, enum machine_mode); ++extern int equality_op (rtx, enum machine_mode); ++extern int custom_insn_opcode (rtx, enum machine_mode); ++extern int rdwrctl_operand (rtx, enum machine_mode); ++ ++# ifdef HAVE_MACHINE_MODES ++# if defined TREE_CODE ++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); ++extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++ ++# endif /* TREE_CODE */ ++# endif /* HAVE_MACHINE_MODES */ ++#endif ++ ++#ifdef TREE_CODE ++extern int nios2_return_in_memory (tree); ++ ++#endif /* TREE_CODE */ +--- gcc-3.4.3/gcc/config/nios2/nios2.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c +@@ -0,0 +1,2853 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++#include ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "rtl.h" ++#include "tree.h" ++#include "tm_p.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "recog.h" ++#include "expr.h" ++#include "toplev.h" ++#include "basic-block.h" ++#include "function.h" ++#include "ggc.h" ++#include "reload.h" ++#include "debug.h" ++#include "optabs.h" ++#include "target.h" ++#include "target-def.h" ++ ++/* local prototypes */ ++static bool nios2_rtx_costs (rtx, int, int, int *); ++ ++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); ++static int nios2_use_dfa_pipeline_interface (void); ++static int nios2_issue_rate (void); ++static struct machine_function *nios2_init_machine_status (void); ++static bool nios2_in_small_data_p (tree); ++static rtx save_reg (int, HOST_WIDE_INT, rtx); ++static rtx restore_reg (int, HOST_WIDE_INT); ++static unsigned int nios2_section_type_flags (tree, const char *, int); ++static void nios2_init_builtins (void); ++static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); ++static bool nios2_function_ok_for_sibcall (tree, tree); ++static void nios2_encode_section_info (tree, rtx, int); ++ ++/* Initialize the GCC target structure. */ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue ++ ++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE ++#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ ++ nios2_use_dfa_pipeline_interface ++#undef TARGET_SCHED_ISSUE_RATE ++#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate ++#undef TARGET_IN_SMALL_DATA_P ++#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p ++#undef TARGET_ENCODE_SECTION_INFO ++#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info ++#undef TARGET_SECTION_TYPE_FLAGS ++#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS nios2_init_builtins ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN nios2_expand_builtin ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS nios2_rtx_costs ++ ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++ ++ ++/* Threshold for data being put into the small data/bss area, instead ++ of the normal data area (references to the small data/bss area take ++ 1 instruction, and use the global pointer, references to the normal ++ data area takes 2 instructions). */ ++unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; ++ ++ ++/* Structure to be filled in by compute_frame_size with register ++ save masks, and offsets for the current function. */ ++ ++struct nios2_frame_info ++GTY (()) ++{ ++ long total_size; /* # bytes that the entire frame takes up */ ++ long var_size; /* # bytes that variables take up */ ++ long args_size; /* # bytes that outgoing arguments take up */ ++ int save_reg_size; /* # bytes needed to store gp regs */ ++ int save_reg_rounded; /* # bytes needed to store gp regs */ ++ long save_regs_offset; /* offset from new sp to store gp registers */ ++ int initialized; /* != 0 if frame size already calculated */ ++ int num_regs; /* number of gp registers saved */ ++}; ++ ++struct machine_function ++GTY (()) ++{ ++ ++ /* Current frame information, calculated by compute_frame_size. */ ++ struct nios2_frame_info frame; ++}; ++ ++ ++/*************************************** ++ * Section encodings ++ ***************************************/ ++ ++ ++ ++ ++ ++/*************************************** ++ * Stack Layout and Calling Conventions ++ ***************************************/ ++ ++ ++#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) ++#define TEMP_REG_NUM 8 ++ ++static void ++nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ++{ ++ if (flag_verbose_asm || flag_debug_asm) ++ { ++ compute_frame_size (); ++ dump_frame_size (file); ++ } ++} ++ ++static rtx ++save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg) ++{ ++ rtx insn, stack_slot; ++ ++ stack_slot = gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ GEN_INT (offset)); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_MEM (SImode, stack_slot), ++ gen_rtx_REG (SImode, regno))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ return insn; ++} ++ ++static rtx ++restore_reg (int regno, HOST_WIDE_INT offset) ++{ ++ rtx insn, stack_slot; ++ ++ if (TOO_BIG_OFFSET (offset)) ++ { ++ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ GEN_INT (offset))); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ gen_rtx_PLUS (SImode, ++ stack_slot, ++ stack_pointer_rtx))); ++ } ++ else ++ { ++ stack_slot = gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (offset)); ++ } ++ ++ stack_slot = gen_rtx_MEM (SImode, stack_slot); ++ ++ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot); ++ ++ return insn; ++} ++ ++ ++/* There are two possible paths for prologue expansion, ++- the first is if the total frame size is < 2^15-1. In that ++case all the immediates will fit into the 16-bit immediate ++fields. ++- the second is when the frame size is too big, in that ++case an additional temporary register is used, first ++as a cfa_temp to offset the sp, second as the cfa_store ++register. ++ ++See the comment above dwarf2out_frame_debug_expr in ++dwarf2out.c for more explanation of the "rules." ++ ++ ++Case 1: ++Rule # Example Insn Effect ++2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++12 stw ra, offset(sp) ++12 stw r16, offset(sp) ++1 mov fp, sp ++ ++Case 2: ++Rule # Example Insn Effect ++6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size ++2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0 ++12 stw ra, offset(r8) ++12 stw r16, offset(r8) ++1 mov fp, sp ++ ++*/ ++ ++void ++expand_prologue () ++{ ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int cfa_store_offset; ++ rtx insn; ++ rtx cfa_store_reg = 0; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (total_frame_size) ++ { ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ /* cfa_temp and cfa_store_reg are the same register, ++ cfa_store_reg overwrites cfa_temp */ ++ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ cfa_store_reg, ++ GEN_INT (total_frame_size))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_MINUS (SImode, ++ stack_pointer_rtx, ++ cfa_store_reg)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ /* if there are no registers to save, I don't need to ++ create a cfa_store */ ++ if (cfun->machine->frame.save_reg_size) ++ { ++ insn = gen_rtx_SET (SImode, ++ cfa_store_reg, ++ gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ stack_pointer_rtx)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ cfa_store_offset ++ = total_frame_size ++ - (cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded); ++ } ++ else ++ { ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (-total_frame_size))); ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ cfa_store_reg = stack_pointer_rtx; ++ cfa_store_offset ++ = cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded; ++ } ++ } ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ cfa_store_offset -= 4; ++ save_reg (i, cfa_store_offset, cfa_store_reg); ++ } ++ } ++ ++ if (frame_pointer_needed) ++ { ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_REG (SImode, FP_REGNO), ++ gen_rtx_REG (SImode, SP_REGNO))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ /* If we are profiling, make sure no instructions are scheduled before ++ the call to mcount. */ ++ if (current_function_profile) ++ emit_insn (gen_blockage ()); ++} ++ ++void ++expand_epilogue (bool sibcall_p) ++{ ++ rtx insn; ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int register_store_offset; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (!sibcall_p && nios2_can_use_return_insn ()) ++ { ++ insn = emit_jump_insn (gen_return ()); ++ return; ++ } ++ ++ emit_insn (gen_blockage ()); ++ ++ register_store_offset = ++ cfun->machine->frame.save_regs_offset + ++ cfun->machine->frame.save_reg_rounded; ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (RA_REGNO, register_store_offset); ++ } ++ ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (FP_REGNO, register_store_offset); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ register_store_offset -= 4; ++ restore_reg (i, register_store_offset); ++ } ++ } ++ ++ if (total_frame_size) ++ { ++ rtx sp_adjust; ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ sp_adjust, ++ GEN_INT (total_frame_size))); ++ ++ } ++ else ++ { ++ sp_adjust = GEN_INT (total_frame_size); ++ } ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ sp_adjust)); ++ insn = emit_insn (insn); ++ } ++ ++ ++ if (!sibcall_p) ++ { ++ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode, ++ RA_REGNO))); ++ } ++} ++ ++ ++bool ++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) ++{ ++ return true; ++} ++ ++ ++ ++ ++ ++/* ----------------------- * ++ * Profiling ++ * ----------------------- */ ++ ++void ++function_profiler (FILE *file, int labelno) ++{ ++ fprintf (file, "\t%s mcount begin, label: .LP%d\n", ++ ASM_COMMENT_START, labelno); ++ fprintf (file, "\tnextpc\tr8\n"); ++ fprintf (file, "\tmov\tr9, ra\n"); ++ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno); ++ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno); ++ fprintf (file, "\tcall\tmcount\n"); ++ fprintf (file, "\tmov\tra, r9\n"); ++ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START); ++} ++ ++ ++/*************************************** ++ * Stack Layout ++ ***************************************/ ++ ++ ++void ++dump_frame_size (FILE *file) ++{ ++ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); ++ ++ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.total_size); ++ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.var_size); ++ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.args_size); ++ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_size); ++ fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_rounded); ++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.initialized); ++ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.num_regs); ++ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_regs_offset); ++ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, ++ current_function_is_leaf); ++ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, ++ frame_pointer_needed); ++ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, ++ current_function_pretend_args_size); ++ ++} ++ ++ ++/* Return the bytes needed to compute the frame pointer from the current ++ stack pointer. ++*/ ++ ++HOST_WIDE_INT ++compute_frame_size () ++{ ++ unsigned int regno; ++ HOST_WIDE_INT var_size; /* # of var. bytes allocated */ ++ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */ ++ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */ ++ HOST_WIDE_INT save_reg_rounded; ++ /* # bytes needed to store callee save regs (rounded) */ ++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */ ++ ++ save_reg_size = 0; ++ var_size = STACK_ALIGN (get_frame_size ()); ++ out_args_size = STACK_ALIGN (current_function_outgoing_args_size); ++ ++ total_size = var_size + out_args_size; ++ ++ /* Calculate space needed for gp registers. */ ++ for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++) ++ { ++ if (MUST_SAVE_REGISTER (regno)) ++ { ++ save_reg_size += 4; ++ } ++ } ++ ++ save_reg_rounded = STACK_ALIGN (save_reg_size); ++ total_size += save_reg_rounded; ++ ++ total_size += STACK_ALIGN (current_function_pretend_args_size); ++ ++ /* Save other computed information. */ ++ cfun->machine->frame.total_size = total_size; ++ cfun->machine->frame.var_size = var_size; ++ cfun->machine->frame.args_size = current_function_outgoing_args_size; ++ cfun->machine->frame.save_reg_size = save_reg_size; ++ cfun->machine->frame.save_reg_rounded = save_reg_rounded; ++ cfun->machine->frame.initialized = reload_completed; ++ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD; ++ ++ cfun->machine->frame.save_regs_offset ++ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0; ++ ++ return total_size; ++} ++ ++ ++int ++nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) ++{ ++ int offset; ++ ++ /* Set OFFSET to the offset from the stack pointer. */ ++ switch (from) ++ { ++ case FRAME_POINTER_REGNUM: ++ offset = 0; ++ break; ++ ++ case ARG_POINTER_REGNUM: ++ compute_frame_size (); ++ offset = cfun->machine->frame.total_size; ++ offset -= current_function_pretend_args_size; ++ break; ++ ++ case RETURN_ADDRESS_POINTER_REGNUM: ++ compute_frame_size (); ++ /* since the return address is always the first of the ++ saved registers, return the offset to the beginning ++ of the saved registers block */ ++ offset = cfun->machine->frame.save_regs_offset; ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ return offset; ++} ++ ++/* Return nonzero if this function is known to have a null epilogue. ++ This allows the optimizer to omit jumps to jumps if no stack ++ was created. */ ++int ++nios2_can_use_return_insn () ++{ ++ if (!reload_completed) ++ return 0; ++ ++ if (regs_ever_live[RA_REGNO] || current_function_profile) ++ return 0; ++ ++ if (cfun->machine->frame.initialized) ++ return cfun->machine->frame.total_size == 0; ++ ++ return compute_frame_size () == 0; ++} ++ ++ ++ ++ ++ ++/*************************************** ++ * ++ ***************************************/ ++ ++const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++const char *nios2_sys_lib_string; /* for -msys-lib= */ ++const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++void ++override_options () ++{ ++ /* Function to allocate machine-dependent function status. */ ++ init_machine_status = &nios2_init_machine_status; ++ ++ nios2_section_threshold ++ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; ++ ++ if (nios2_sys_nosys_string && *nios2_sys_nosys_string) ++ { ++ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string); ++ } ++ ++ /* If we don't have mul, we don't have mulx either! */ ++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX) ++ { ++ target_flags &= ~HAS_MULX_FLAG; ++ } ++ ++} ++ ++void ++optimization_options (int level, int size) ++{ ++ if (level || size) ++ { ++ target_flags |= INLINE_MEMCPY_FLAG; ++ } ++ ++ if (level >= 3 && !size) ++ { ++ target_flags |= FAST_SW_DIV_FLAG; ++ } ++} ++ ++/* Allocate a chunk of memory for per-function machine-dependent data. */ ++static struct machine_function * ++nios2_init_machine_status () ++{ ++ return ((struct machine_function *) ++ ggc_alloc_cleared (sizeof (struct machine_function))); ++} ++ ++ ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++/* Compute a (partial) cost for rtx X. Return true if the complete ++ cost has been computed, and false if subexpressions should be ++ scanned. In either case, *TOTAL contains the cost result. */ ++ ++ ++ ++static bool ++nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) ++{ ++ switch (code) ++ { ++ case CONST_INT: ++ if (INTVAL (x) == 0) ++ { ++ *total = COSTS_N_INSNS (0); ++ return true; ++ } ++ else if (SMALL_INT (INTVAL (x)) ++ || SMALL_INT_UNSIGNED (INTVAL (x)) ++ || UPPER16_INT (INTVAL (x))) ++ { ++ *total = COSTS_N_INSNS (2); ++ return true; ++ } ++ else ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case LABEL_REF: ++ case SYMBOL_REF: ++ /* ??? gp relative stuff will fit in here */ ++ /* fall through */ ++ case CONST: ++ case CONST_DOUBLE: ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case MULT: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ case SIGN_EXTEND: ++ { ++ *total = COSTS_N_INSNS (3); ++ return false; ++ } ++ case ZERO_EXTEND: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ ++ default: ++ return false; ++ } ++} ++ ++ ++/*************************************** ++ * INSTRUCTION SUPPORT ++ * ++ * These functions are used within the Machine Description to ++ * handle common or complicated output and expansions from ++ * instructions. ++ ***************************************/ ++ ++int ++nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) ++{ ++ rtx to = operands[0]; ++ rtx from = operands[1]; ++ ++ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) ++ { ++ if (no_new_pseudos) ++ internal_error ("Trying to force_reg no_new_pseudos == 1"); ++ from = copy_to_mode_reg (mode, from); ++ } ++ ++ operands[0] = to; ++ operands[1] = from; ++ return 0; ++} ++ ++/* Divide Support */ ++ ++/* ++ If -O3 is used, we want to output a table lookup for ++ divides between small numbers (both num and den >= 0 ++ and < 0x10). The overhead of this method in the worse ++ case is 40 bytes in the text section (10 insns) and ++ 256 bytes in the data section. Additional divides do ++ not incur additional penalties in the data section. ++ ++ Code speed is improved for small divides by about 5x ++ when using this method in the worse case (~9 cycles ++ vs ~45). And in the worse case divides not within the ++ table are penalized by about 10% (~5 cycles vs ~45). ++ However in the typical case the penalty is not as bad ++ because doing the long divide in only 45 cycles is ++ quite optimistic. ++ ++ ??? It would be nice to have some benchmarks other ++ than Dhrystone to back this up. ++ ++ This bit of expansion is to create this instruction ++ sequence as rtl. ++ or $8, $4, $5 ++ slli $9, $4, 4 ++ cmpgeui $3, $8, 16 ++ beq $3, $0, .L3 ++ or $10, $9, $5 ++ add $12, $11, divide_table ++ ldbu $2, 0($12) ++ br .L1 ++.L3: ++ call slow_div ++.L1: ++# continue here with result in $2 ++ ++ ??? Ideally I would like the emit libcall block to contain ++ all of this code, but I don't know how to do that. What it ++ means is that if the divide can be eliminated, it may not ++ completely disappear. ++ ++ ??? The __divsi3_table label should ideally be moved out ++ of this block and into a global. If it is placed into the ++ sdata section we can save even more cycles by doing things ++ gp relative. ++*/ ++int ++nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) ++{ ++ rtx or_result, shift_left_result; ++ rtx lookup_value; ++ rtx lab1, lab3; ++ rtx insns; ++ rtx libfunc; ++ rtx final_result; ++ rtx tmp; ++ ++ /* it may look a little generic, but only SImode ++ is supported for now */ ++ if (mode != SImode) ++ abort (); ++ ++ libfunc = sdiv_optab->handlers[(int) SImode].libfunc; ++ ++ ++ ++ lab1 = gen_label_rtx (); ++ lab3 = gen_label_rtx (); ++ ++ or_result = expand_simple_binop (SImode, IOR, ++ operands[1], operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, ++ GET_MODE (or_result), 0, lab3); ++ JUMP_LABEL (get_last_insn ()) = lab3; ++ ++ shift_left_result = expand_simple_binop (SImode, ASHIFT, ++ operands[1], GEN_INT (4), ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ lookup_value = expand_simple_binop (SImode, IOR, ++ shift_left_result, operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ convert_move (operands[0], ++ gen_rtx (MEM, QImode, ++ gen_rtx (PLUS, SImode, ++ lookup_value, ++ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), ++ 1); ++ ++ ++ tmp = emit_jump_insn (gen_jump (lab1)); ++ JUMP_LABEL (tmp) = lab1; ++ emit_barrier (); ++ ++ emit_label (lab3); ++ LABEL_NUSES (lab3) = 1; ++ ++ start_sequence (); ++ final_result = emit_library_call_value (libfunc, NULL_RTX, ++ LCT_CONST, SImode, 2, ++ operands[1], SImode, ++ operands[2], SImode); ++ ++ ++ insns = get_insns (); ++ end_sequence (); ++ emit_libcall_block (insns, operands[0], final_result, ++ gen_rtx (DIV, SImode, operands[1], operands[2])); ++ ++ emit_label (lab1); ++ LABEL_NUSES (lab1) = 1; ++ return 1; ++} ++ ++/* Branches/Compares */ ++ ++/* the way of handling branches/compares ++ in gcc is heavily borrowed from MIPS */ ++ ++enum internal_test ++{ ++ ITEST_EQ, ++ ITEST_NE, ++ ITEST_GT, ++ ITEST_GE, ++ ITEST_LT, ++ ITEST_LE, ++ ITEST_GTU, ++ ITEST_GEU, ++ ITEST_LTU, ++ ITEST_LEU, ++ ITEST_MAX ++}; ++ ++static enum internal_test map_test_to_internal_test (enum rtx_code); ++ ++/* Cached operands, and operator to compare for use in set/branch/trap ++ on condition codes. */ ++rtx branch_cmp[2]; ++enum cmp_type branch_type; ++ ++/* Make normal rtx_code into something we can index from an array */ ++ ++static enum internal_test ++map_test_to_internal_test (enum rtx_code test_code) ++{ ++ enum internal_test test = ITEST_MAX; ++ ++ switch (test_code) ++ { ++ case EQ: ++ test = ITEST_EQ; ++ break; ++ case NE: ++ test = ITEST_NE; ++ break; ++ case GT: ++ test = ITEST_GT; ++ break; ++ case GE: ++ test = ITEST_GE; ++ break; ++ case LT: ++ test = ITEST_LT; ++ break; ++ case LE: ++ test = ITEST_LE; ++ break; ++ case GTU: ++ test = ITEST_GTU; ++ break; ++ case GEU: ++ test = ITEST_GEU; ++ break; ++ case LTU: ++ test = ITEST_LTU; ++ break; ++ case LEU: ++ test = ITEST_LEU; ++ break; ++ default: ++ break; ++ } ++ ++ return test; ++} ++ ++/* Generate the code to compare (and possibly branch) two integer values ++ TEST_CODE is the comparison code we are trying to emulate ++ (or implement directly) ++ RESULT is where to store the result of the comparison, ++ or null to emit a branch ++ CMP0 CMP1 are the two comparison operands ++ DESTINATION is the destination of the branch, or null to only compare ++ */ ++ ++void ++gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */ ++ rtx result, /* result to store comp. or 0 if branch */ ++ rtx cmp0, /* first operand to compare */ ++ rtx cmp1, /* second operand to compare */ ++ rtx destination) /* destination of the branch, or 0 if compare */ ++{ ++ struct cmp_info ++ { ++ /* for register (or 0) compares */ ++ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */ ++ int reverse_regs; /* reverse registers in test */ ++ ++ /* for immediate compares */ ++ enum rtx_code test_code_const; ++ /* code to use in instruction (LT vs. LTU) */ ++ int const_low; /* low bound of constant we can accept */ ++ int const_high; /* high bound of constant we can accept */ ++ int const_add; /* constant to add */ ++ ++ /* generic info */ ++ int unsignedp; /* != 0 for unsigned comparisons. */ ++ }; ++ ++ static const struct cmp_info info[(int) ITEST_MAX] = { ++ ++ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ ++ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ ++ ++ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ ++ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ ++ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ ++ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ ++ ++ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ ++ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ ++ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ ++ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ ++ }; ++ ++ enum internal_test test; ++ enum machine_mode mode; ++ const struct cmp_info *p_info; ++ int branch_p; ++ ++ ++ ++ ++ test = map_test_to_internal_test (test_code); ++ if (test == ITEST_MAX) ++ abort (); ++ ++ p_info = &info[(int) test]; ++ ++ mode = GET_MODE (cmp0); ++ if (mode == VOIDmode) ++ mode = GET_MODE (cmp1); ++ ++ branch_p = (destination != 0); ++ ++ /* We can't, under any circumstances, have const_ints in cmp0 ++ ??? Actually we could have const0 */ ++ if (GET_CODE (cmp0) == CONST_INT) ++ cmp0 = force_reg (mode, cmp0); ++ ++ /* if the comparison is against an int not in legal range ++ move it into a register */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ HOST_WIDE_INT value = INTVAL (cmp1); ++ ++ if (value < p_info->const_low || value > p_info->const_high) ++ cmp1 = force_reg (mode, cmp1); ++ } ++ ++ /* Comparison to constants, may involve adding 1 to change a GT into GE. ++ Comparison between two registers, may involve switching operands. */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ if (p_info->const_add != 0) ++ { ++ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; ++ ++ /* If modification of cmp1 caused overflow, ++ we would get the wrong answer if we follow the usual path; ++ thus, x > 0xffffffffU would turn into x > 0U. */ ++ if ((p_info->unsignedp ++ ? (unsigned HOST_WIDE_INT) new > ++ (unsigned HOST_WIDE_INT) INTVAL (cmp1) ++ : new > INTVAL (cmp1)) != (p_info->const_add > 0)) ++ { ++ /* ??? This case can never happen with the current numbers, ++ but I am paranoid and would rather an abort than ++ a bug I will never find */ ++ abort (); ++ } ++ else ++ cmp1 = GEN_INT (new); ++ } ++ } ++ ++ else if (p_info->reverse_regs) ++ { ++ rtx temp = cmp0; ++ cmp0 = cmp1; ++ cmp1 = temp; ++ } ++ ++ ++ ++ if (branch_p) ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ rtx insn; ++ rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1); ++ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ insn = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, label, pc_rtx)); ++ emit_jump_insn (insn); ++ } ++ else ++ { ++ rtx cond, label; ++ ++ result = gen_reg_rtx (mode); ++ ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ ++ cond = gen_rtx (NE, mode, result, const0_rtx); ++ label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, ++ label, pc_rtx))); ++ } ++ } ++ else ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1)); ++ } ++ else ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ } ++ } ++ ++} ++ ++ ++/* ??? For now conditional moves are only supported ++ when the mode of the operands being compared are ++ the same as the ones being moved */ ++ ++void ++gen_conditional_move (rtx *operands, enum machine_mode mode) ++{ ++ rtx insn, cond; ++ rtx cmp_reg = gen_reg_rtx (mode); ++ enum rtx_code cmp_code = GET_CODE (operands[1]); ++ enum rtx_code move_code = EQ; ++ ++ /* emit a comparison if it is not "simple". ++ Simple comparisons are X eq 0 and X ne 0 */ ++ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[0]; ++ move_code = cmp_code; ++ } ++ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[1]; ++ move_code = cmp_code == EQ ? NE : EQ; ++ } ++ else ++ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], ++ NULL_RTX); ++ ++ cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); ++ insn = gen_rtx_SET (mode, operands[0], ++ gen_rtx_IF_THEN_ELSE (mode, ++ cond, operands[2], operands[3])); ++ emit_insn (insn); ++} ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++int ++nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int strict) ++{ ++ int ret_val = 0; ++ ++ switch (GET_CODE (operand)) ++ { ++ /* direct. */ ++ case SYMBOL_REF: ++ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) ++ { ++ ret_val = 1; ++ break; ++ } ++ /* else, fall through */ ++ case LABEL_REF: ++ case CONST_INT: ++ case CONST: ++ case CONST_DOUBLE: ++ /* ??? In here I need to add gp addressing */ ++ ret_val = 0; ++ ++ break; ++ ++ /* Register indirect. */ ++ case REG: ++ ret_val = REG_OK_FOR_BASE_P2 (operand, strict); ++ break; ++ ++ /* Register indirect with displacement */ ++ case PLUS: ++ { ++ rtx op0 = XEXP (operand, 0); ++ rtx op1 = XEXP (operand, 1); ++ ++ if (REG_P (op0) && REG_P (op1)) ++ ret_val = 0; ++ else if (REG_P (op0) && CONSTANT_P (op1)) ++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict) ++ && SMALL_INT (INTVAL (op1)); ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ ret_val = REG_OK_FOR_BASE_P2 (op1, strict) ++ && SMALL_INT (INTVAL (op0)); ++ else ++ ret_val = 0; ++ } ++ break; ++ ++ default: ++ ret_val = 0; ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/* Return true if EXP should be placed in the small data section. */ ++ ++static bool ++nios2_in_small_data_p (tree exp) ++{ ++ /* We want to merge strings, so we never consider them small data. */ ++ if (TREE_CODE (exp) == STRING_CST) ++ return false; ++ ++ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) ++ { ++ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); ++ /* ??? these string names need moving into ++ an array in some header file */ ++ if (nios2_section_threshold > 0 ++ && (strcmp (section, ".sbss") == 0 ++ || strncmp (section, ".sbss.", 6) == 0 ++ || strcmp (section, ".sdata") == 0 ++ || strncmp (section, ".sdata.", 7) == 0)) ++ return true; ++ } ++ else if (TREE_CODE (exp) == VAR_DECL) ++ { ++ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); ++ ++ /* If this is an incomplete type with size 0, then we can't put it ++ in sdata because it might be too big when completed. */ ++ if (size > 0 && size <= nios2_section_threshold) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ++nios2_encode_section_info (tree decl, rtx rtl, int first) ++{ ++ ++ rtx symbol; ++ int flags; ++ ++ default_encode_section_info (decl, rtl, first); ++ ++ /* Careful not to prod global register variables. */ ++ if (GET_CODE (rtl) != MEM) ++ return; ++ symbol = XEXP (rtl, 0); ++ if (GET_CODE (symbol) != SYMBOL_REF) ++ return; ++ ++ flags = SYMBOL_REF_FLAGS (symbol); ++ ++ /* We don't want weak variables to be addressed with gp in case they end up with ++ value 0 which is not within 2^15 of $gp */ ++ if (DECL_P (decl) && DECL_WEAK (decl)) ++ flags |= SYMBOL_FLAG_WEAK_DECL; ++ ++ SYMBOL_REF_FLAGS (symbol) = flags; ++} ++ ++ ++static unsigned int ++nios2_section_type_flags (tree decl, const char *name, int reloc) ++{ ++ unsigned int flags; ++ ++ flags = default_section_type_flags (decl, name, reloc); ++ ++ /* ??? these string names need moving into an array in some header file */ ++ if (strcmp (name, ".sbss") == 0 ++ || strncmp (name, ".sbss.", 6) == 0 ++ || strcmp (name, ".sdata") == 0 ++ || strncmp (name, ".sdata.", 7) == 0) ++ flags |= SECTION_SMALL; ++ ++ return flags; ++} ++ ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++ ++/* print the operand OP to file stream ++ FILE modified by LETTER. LETTER ++ can be one of: ++ i: print "i" if OP is an immediate, except 0 ++ o: print "io" if OP is volatile ++ ++ z: for const0_rtx print $0 instead of 0 ++ H: for %hiadj ++ L: for %lo ++ U: for upper half of 32 bit value ++ */ ++ ++void ++nios2_print_operand (FILE *file, rtx op, int letter) ++{ ++ ++ switch (letter) ++ { ++ case 'i': ++ if (CONSTANT_P (op) && (op != const0_rtx)) ++ fprintf (file, "i"); ++ return; ++ ++ case 'o': ++ if (GET_CODE (op) == MEM ++ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE) ++ || TARGET_BYPASS_CACHE)) ++ fprintf (file, "io"); ++ return; ++ ++ default: ++ break; ++ } ++ ++ if (comparison_operator (op, VOIDmode)) ++ { ++ if (letter == 0) ++ { ++ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); ++ return; ++ } ++ } ++ ++ ++ switch (GET_CODE (op)) ++ { ++ case REG: ++ if (letter == 0 || letter == 'z') ++ { ++ fprintf (file, "%s", reg_names[REGNO (op)]); ++ return; ++ } ++ ++ case CONST_INT: ++ if (INTVAL (op) == 0 && letter == 'z') ++ { ++ fprintf (file, "zero"); ++ return; ++ } ++ else if (letter == 'U') ++ { ++ HOST_WIDE_INT val = INTVAL (op); ++ rtx new_op; ++ val = (val / 65536) & 0xFFFF; ++ new_op = GEN_INT (val); ++ output_addr_const (file, new_op); ++ return; ++ } ++ ++ /* else, fall through */ ++ case CONST: ++ case LABEL_REF: ++ case SYMBOL_REF: ++ case CONST_DOUBLE: ++ if (letter == 0 || letter == 'z') ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ else if (letter == 'H') ++ { ++ fprintf (file, "%%hiadj("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ else if (letter == 'L') ++ { ++ fprintf (file, "%%lo("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ ++ ++ case SUBREG: ++ case MEM: ++ if (letter == 0) ++ { ++ output_address (op); ++ return; ++ } ++ ++ case CODE_LABEL: ++ if (letter == 0) ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print (%c) ", letter); ++ debug_rtx (op); ++ abort (); ++} ++ ++static int gprel_constant (rtx); ++ ++static int ++gprel_constant (rtx op) ++{ ++ if (GET_CODE (op) == SYMBOL_REF ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) ++ { ++ return 1; ++ } ++ else if (GET_CODE (op) == CONST ++ && GET_CODE (XEXP (op, 0)) == PLUS) ++ { ++ return gprel_constant (XEXP (XEXP (op, 0), 0)); ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++void ++nios2_print_operand_address (FILE *file, rtx op) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST: ++ case CONST_INT: ++ case LABEL_REF: ++ case CONST_DOUBLE: ++ case SYMBOL_REF: ++ if (gprel_constant (op)) ++ { ++ fprintf (file, "%%gprel("); ++ output_addr_const (file, op); ++ fprintf (file, ")(%s)", reg_names[GP_REGNO]); ++ return; ++ } ++ ++ break; ++ ++ case PLUS: ++ { ++ rtx op0 = XEXP (op, 0); ++ rtx op1 = XEXP (op, 1); ++ ++ if (REG_P (op0) && CONSTANT_P (op1)) ++ { ++ output_addr_const (file, op1); ++ fprintf (file, "(%s)", reg_names[REGNO (op0)]); ++ return; ++ } ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ { ++ output_addr_const (file, op0); ++ fprintf (file, "(%s)", reg_names[REGNO (op1)]); ++ return; ++ } ++ } ++ break; ++ ++ case REG: ++ fprintf (file, "0(%s)", reg_names[REGNO (op)]); ++ return; ++ ++ case MEM: ++ { ++ rtx base = XEXP (op, 0); ++ PRINT_OPERAND_ADDRESS (file, base); ++ return; ++ } ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print address\n"); ++ debug_rtx (op); ++ abort (); ++} ++ ++ ++ ++ ++ ++/**************************** ++ * Predicates ++ ****************************/ ++ ++int ++arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++uns_arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++logical_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT ++ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++shift_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); ++} ++ ++/* Return truth value of whether OP is a register or the constant 0. */ ++ ++int ++reg_or_0_operand (rtx op, enum machine_mode mode) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST_INT: ++ return INTVAL (op) == 0; ++ ++ case CONST_DOUBLE: ++ return op == CONST0_RTX (mode); ++ ++ default: ++ break; ++ } ++ ++ return register_operand (op, mode); ++} ++ ++ ++int ++equality_op (rtx op, enum machine_mode mode) ++{ ++ if (mode != GET_MODE (op)) ++ return 0; ++ ++ return GET_CODE (op) == EQ || GET_CODE (op) == NE; ++} ++ ++int ++custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); ++} ++ ++ ++ ++ ++ ++ ++ ++/***************************************************************************** ++** ++** instruction scheduler ++** ++*****************************************************************************/ ++static int ++nios2_use_dfa_pipeline_interface () ++{ ++ return 1; ++} ++ ++ ++static int ++nios2_issue_rate () ++{ ++#ifdef MAX_DFA_ISSUE_RATE ++ return MAX_DFA_ISSUE_RATE; ++#else ++ return 1; ++#endif ++} ++ ++ ++const char * ++asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, ++ const char *ptr ATTRIBUTE_UNUSED) ++{ ++ const char *p; ++ ++ p = ptr; ++ return ptr; ++} ++ ++ ++ ++/***************************************************************************** ++** ++** function arguments ++** ++*****************************************************************************/ ++ ++void ++init_cumulative_args (CUMULATIVE_ARGS *cum, ++ tree fntype ATTRIBUTE_UNUSED, ++ rtx libname ATTRIBUTE_UNUSED, ++ tree fndecl ATTRIBUTE_UNUSED, ++ int n_named_args ATTRIBUTE_UNUSED) ++{ ++ cum->regs_used = 0; ++} ++ ++ ++/* Update the data in CUM to advance over an argument ++ of mode MODE and data type TYPE. ++ (TYPE is null for libcalls where that information may not be available.) */ ++ ++void ++function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ cum->regs_used = NUM_ARG_REGS; ++ } ++ else ++ { ++ cum->regs_used += param_size; ++ } ++ ++ return; ++} ++ ++/* Define where to put the arguments to a function. Value is zero to ++ push the argument on the stack, or a hard register in which to ++ store the argument. ++ ++ MODE is the argument's machine mode. ++ TYPE is the data type of the argument (as a tree). ++ This is null for libcalls where that information may ++ not be available. ++ CUM is a variable of type CUMULATIVE_ARGS which gives info about ++ the preceding args and about the function being called. ++ NAMED is nonzero if this argument is a named parameter ++ (otherwise it is an extra parameter matching an ellipsis). */ ++rtx ++function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ rtx return_rtx = NULL_RTX; ++ ++ if (cum->regs_used < NUM_ARG_REGS) ++ { ++ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); ++ } ++ ++ return return_rtx; ++} ++ ++int ++function_arg_partial_nregs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used < NUM_ARG_REGS ++ && cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ return NUM_ARG_REGS - cum->regs_used; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++ ++int ++nios2_return_in_memory (tree type) ++{ ++ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) ++ || (int_size_in_bytes (type) == -1)); ++ ++ return res; ++} ++ ++/* ??? It may be possible to eliminate the copyback and implement ++ my own va_arg type, but that is more work for now. */ ++int ++nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int no_rtl) ++{ ++ CUMULATIVE_ARGS local_cum; ++ int regs_to_push; ++ ++ local_cum = *cum; ++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); ++ ++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used; ++ ++ if (!no_rtl) ++ { ++ if (regs_to_push > 0) ++ { ++ rtx ptr, mem; ++ ++ ptr = virtual_incoming_args_rtx; ++ mem = gen_rtx_MEM (BLKmode, ptr); ++ ++ /* va_arg is an array access in this case, which causes ++ it to get MEM_IN_STRUCT_P set. We must set it here ++ so that the insn scheduler won't assume that these ++ stores can't possibly overlap with the va_arg loads. */ ++ MEM_SET_IN_STRUCT_P (mem, 1); ++ ++ emit_insn (gen_blockage ()); ++ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, ++ regs_to_push); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ ++ return regs_to_push * UNITS_PER_WORD; ++ ++} ++ ++ ++ ++/***************************************************************************** ++** ++** builtins ++** ++** This method for handling builtins is from CSP where _many_ more types of ++** expanders have already been written. Check there first before writing ++** new ones. ++** ++*****************************************************************************/ ++ ++enum nios2_builtins ++{ ++ NIOS2_BUILTIN_LDBIO, ++ NIOS2_BUILTIN_LDBUIO, ++ NIOS2_BUILTIN_LDHIO, ++ NIOS2_BUILTIN_LDHUIO, ++ NIOS2_BUILTIN_LDWIO, ++ NIOS2_BUILTIN_STBIO, ++ NIOS2_BUILTIN_STHIO, ++ NIOS2_BUILTIN_STWIO, ++ NIOS2_BUILTIN_SYNC, ++ NIOS2_BUILTIN_RDCTL, ++ NIOS2_BUILTIN_WRCTL, ++ ++ NIOS2_BUILTIN_CUSTOM_N, ++ NIOS2_BUILTIN_CUSTOM_NI, ++ NIOS2_BUILTIN_CUSTOM_NF, ++ NIOS2_BUILTIN_CUSTOM_NP, ++ NIOS2_BUILTIN_CUSTOM_NII, ++ NIOS2_BUILTIN_CUSTOM_NIF, ++ NIOS2_BUILTIN_CUSTOM_NIP, ++ NIOS2_BUILTIN_CUSTOM_NFI, ++ NIOS2_BUILTIN_CUSTOM_NFF, ++ NIOS2_BUILTIN_CUSTOM_NFP, ++ NIOS2_BUILTIN_CUSTOM_NPI, ++ NIOS2_BUILTIN_CUSTOM_NPF, ++ NIOS2_BUILTIN_CUSTOM_NPP, ++ NIOS2_BUILTIN_CUSTOM_IN, ++ NIOS2_BUILTIN_CUSTOM_INI, ++ NIOS2_BUILTIN_CUSTOM_INF, ++ NIOS2_BUILTIN_CUSTOM_INP, ++ NIOS2_BUILTIN_CUSTOM_INII, ++ NIOS2_BUILTIN_CUSTOM_INIF, ++ NIOS2_BUILTIN_CUSTOM_INIP, ++ NIOS2_BUILTIN_CUSTOM_INFI, ++ NIOS2_BUILTIN_CUSTOM_INFF, ++ NIOS2_BUILTIN_CUSTOM_INFP, ++ NIOS2_BUILTIN_CUSTOM_INPI, ++ NIOS2_BUILTIN_CUSTOM_INPF, ++ NIOS2_BUILTIN_CUSTOM_INPP, ++ NIOS2_BUILTIN_CUSTOM_FN, ++ NIOS2_BUILTIN_CUSTOM_FNI, ++ NIOS2_BUILTIN_CUSTOM_FNF, ++ NIOS2_BUILTIN_CUSTOM_FNP, ++ NIOS2_BUILTIN_CUSTOM_FNII, ++ NIOS2_BUILTIN_CUSTOM_FNIF, ++ NIOS2_BUILTIN_CUSTOM_FNIP, ++ NIOS2_BUILTIN_CUSTOM_FNFI, ++ NIOS2_BUILTIN_CUSTOM_FNFF, ++ NIOS2_BUILTIN_CUSTOM_FNFP, ++ NIOS2_BUILTIN_CUSTOM_FNPI, ++ NIOS2_BUILTIN_CUSTOM_FNPF, ++ NIOS2_BUILTIN_CUSTOM_FNPP, ++ NIOS2_BUILTIN_CUSTOM_PN, ++ NIOS2_BUILTIN_CUSTOM_PNI, ++ NIOS2_BUILTIN_CUSTOM_PNF, ++ NIOS2_BUILTIN_CUSTOM_PNP, ++ NIOS2_BUILTIN_CUSTOM_PNII, ++ NIOS2_BUILTIN_CUSTOM_PNIF, ++ NIOS2_BUILTIN_CUSTOM_PNIP, ++ NIOS2_BUILTIN_CUSTOM_PNFI, ++ NIOS2_BUILTIN_CUSTOM_PNFF, ++ NIOS2_BUILTIN_CUSTOM_PNFP, ++ NIOS2_BUILTIN_CUSTOM_PNPI, ++ NIOS2_BUILTIN_CUSTOM_PNPF, ++ NIOS2_BUILTIN_CUSTOM_PNPP, ++ ++ ++ LIM_NIOS2_BUILTINS ++}; ++ ++struct builtin_description ++{ ++ const enum insn_code icode; ++ const char *const name; ++ const enum nios2_builtins code; ++ const tree *type; ++ rtx (* expander) PARAMS ((const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int)); ++}; ++ ++static rtx nios2_expand_STXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_LDXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_sync (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_rdctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_wrctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static rtx nios2_expand_custom_n (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_Xn (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static tree endlink; ++ ++/* int fn (volatile const void *) ++ */ ++static tree int_ftype_volatile_const_void_p; ++ ++/* int fn (int) ++ */ ++static tree int_ftype_int; ++ ++/* void fn (int, int) ++ */ ++static tree void_ftype_int_int; ++ ++/* void fn (volatile void *, int) ++ */ ++static tree void_ftype_volatile_void_p_int; ++ ++/* void fn (void) ++ */ ++static tree void_ftype_void; ++ ++static tree custom_n; ++static tree custom_ni; ++static tree custom_nf; ++static tree custom_np; ++static tree custom_nii; ++static tree custom_nif; ++static tree custom_nip; ++static tree custom_nfi; ++static tree custom_nff; ++static tree custom_nfp; ++static tree custom_npi; ++static tree custom_npf; ++static tree custom_npp; ++static tree custom_in; ++static tree custom_ini; ++static tree custom_inf; ++static tree custom_inp; ++static tree custom_inii; ++static tree custom_inif; ++static tree custom_inip; ++static tree custom_infi; ++static tree custom_inff; ++static tree custom_infp; ++static tree custom_inpi; ++static tree custom_inpf; ++static tree custom_inpp; ++static tree custom_fn; ++static tree custom_fni; ++static tree custom_fnf; ++static tree custom_fnp; ++static tree custom_fnii; ++static tree custom_fnif; ++static tree custom_fnip; ++static tree custom_fnfi; ++static tree custom_fnff; ++static tree custom_fnfp; ++static tree custom_fnpi; ++static tree custom_fnpf; ++static tree custom_fnpp; ++static tree custom_pn; ++static tree custom_pni; ++static tree custom_pnf; ++static tree custom_pnp; ++static tree custom_pnii; ++static tree custom_pnif; ++static tree custom_pnip; ++static tree custom_pnfi; ++static tree custom_pnff; ++static tree custom_pnfp; ++static tree custom_pnpi; ++static tree custom_pnpf; ++static tree custom_pnpp; ++ ++ ++static const struct builtin_description bdesc[] = { ++ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ ++ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ ++ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync}, ++ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl}, ++ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl}, ++ ++ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n}, ++ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX}, ++ ++ ++ {0, 0, 0, 0, 0}, ++}; ++ ++/* This does not have a closing bracket on purpose (see use) */ ++#define def_param(TYPE) \ ++ tree_cons (NULL_TREE, TYPE, ++ ++static void ++nios2_init_builtins () ++{ ++ const struct builtin_description *d; ++ ++ ++ endlink = void_list_node; ++ ++ /* Special indenting here because one of the brackets is in def_param */ ++ /* *INDENT-OFF* */ ++ ++ /* int fn (volatile const void *) ++ */ ++ int_ftype_volatile_const_void_p ++ = build_function_type (integer_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) ++ endlink)); ++ ++ ++ /* void fn (volatile void *, int) ++ */ ++ void_ftype_volatile_void_p_int ++ = build_function_type (void_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_VOLATILE)) ++ def_param (integer_type_node) ++ endlink))); ++ ++ /* void fn (void) ++ */ ++ void_ftype_void ++ = build_function_type (void_type_node, ++ endlink); ++ ++ /* int fn (int) ++ */ ++ int_ftype_int ++ = build_function_type (integer_type_node, ++ def_param (integer_type_node) ++ endlink)); ++ ++ /* void fn (int, int) ++ */ ++ void_ftype_int_int ++ = build_function_type (void_type_node, ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink))); ++ ++ ++#define CUSTOM_NUM def_param (integer_type_node) ++ ++ custom_n ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ni ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_nf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_np ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_nii ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nif ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nip ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_nfi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nff ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nfp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_npi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_npf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_npp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_in ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ini ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_inf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_inp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_inii ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inif ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inip ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_infi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inff ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_infp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_inpi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inpf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inpp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_fn ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_fni ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_fnf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_fnp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_fnii ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnif ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnip ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnfi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnff ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnfp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnpi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnpf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnpp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ custom_pn ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_pni ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_pnf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_pnp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_pnii ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnif ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnip ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnfi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnff ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnfp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnpi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnpf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnpp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ ++ /* *INDENT-ON* */ ++ ++ ++ for (d = bdesc; d->name; d++) ++ { ++ builtin_function (d->name, *d->type, d->code, ++ BUILT_IN_MD, NULL, NULL); ++ } ++} ++ ++/* Expand an expression EXP that calls a built-in function, ++ with result going to TARGET if that's convenient ++ (and in mode MODE if that's convenient). ++ SUBTARGET may be used as the target for computing one of EXP's operands. ++ IGNORE is nonzero if the value is to be ignored. */ ++ ++static rtx ++nios2_expand_builtin (tree exp, rtx target, rtx subtarget, ++ enum machine_mode mode, int ignore) ++{ ++ const struct builtin_description *d; ++ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ ++ for (d = bdesc; d->name; d++) ++ if (d->code == fcode) ++ return (d->expander) (d, exp, target, subtarget, mode, ignore); ++ ++ /* we should have seen one of the functins we registered */ ++ abort (); ++} ++ ++static rtx nios2_create_target (const struct builtin_description *, rtx); ++ ++ ++static rtx ++nios2_create_target (const struct builtin_description *d, rtx target) ++{ ++ if (!target ++ || !(*insn_data[d->icode].operand[0].predicate) (target, ++ insn_data[d->icode].operand[0].mode)) ++ { ++ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); ++ } ++ ++ return target; ++} ++ ++ ++static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); ++static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree); ++ ++static rtx ++nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); ++ opcode = protect_from_queue (opcode, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) ++ error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name); ++ ++ return opcode; ++} ++ ++static rtx ++nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx operand = expand_expr (arg, NULL_RTX, mode, 0); ++ operand = protect_from_queue (operand, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ operand = copy_to_mode_reg (mode, operand); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ error ("Invalid argument %d to %s", argnum, d->name); ++ ++ return operand; ++} ++ ++ ++static rtx ++nios2_expand_custom_n (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_n should have exactly one operand */ ++ if (insn_data[d->icode].n_operands != 1) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ ++ pat = GEN_FCN (d->icode) (opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_Xn should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ pat = GEN_FCN (d->icode) (target, opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nX (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ ++ /* custom_nX should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ /* custom_Xn should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_nX should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_XnX should have exactly four operands */ ++ if (insn_data[d->icode].n_operands != 4) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++ ++static rtx ++nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx store_dest, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ store_dest = protect_from_queue (store_dest, 0); ++ ++ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (store_dest, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++static rtx ++nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx ld_src; ++ enum insn_code icode = d->icode; ++ ++ /* loads should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ld_src = protect_from_queue (ld_src, 0); ++ ++ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) ++ { ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, ld_src); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++static rtx ++nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ emit_insn (gen_sync ()); ++ return 0; ++} ++ ++static rtx ++nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx rdctl_reg; ++ enum insn_code icode = d->icode; ++ ++ /* rdctl should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ rdctl_reg = protect_from_queue (rdctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) ++ { ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, rdctl_reg); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx wrctl_reg, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ wrctl_reg = protect_from_queue (wrctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (wrctl_reg, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++#include "gt-nios2.h" ++ +--- gcc-3.4.3/gcc/config/nios2/nios2.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h +@@ -0,0 +1,824 @@ ++/* Definitions of target machine for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++ ++#define TARGET_CPU_CPP_BUILTINS() \ ++ do \ ++ { \ ++ builtin_define_std ("NIOS2"); \ ++ builtin_define_std ("nios2"); \ ++ builtin_define ("_GNU_SOURCE"); \ ++ } \ ++ while (0) ++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") ++ ++ ++ ++ ++ ++/********************************* ++ * Run-time Target Specification ++ *********************************/ ++ ++#define HAS_DIV_FLAG 0x0001 ++#define HAS_MUL_FLAG 0x0002 ++#define HAS_MULX_FLAG 0x0004 ++#define FAST_SW_DIV_FLAG 0x0008 ++#define INLINE_MEMCPY_FLAG 0x00010 ++#define CACHE_VOLATILE_FLAG 0x0020 ++#define BYPASS_CACHE_FLAG 0x0040 ++ ++extern int target_flags; ++#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG) ++#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG) ++#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG) ++#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG) ++#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG) ++#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG) ++#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG) ++ ++#define TARGET_SWITCHES \ ++{ \ ++ { "hw-div", HAS_DIV_FLAG, \ ++ N_("Enable DIV, DIVU") }, \ ++ { "no-hw-div", -HAS_DIV_FLAG, \ ++ N_("Disable DIV, DIVU (default)") }, \ ++ { "hw-mul", HAS_MUL_FLAG, \ ++ N_("Enable MUL instructions (default)") }, \ ++ { "hw-mulx", HAS_MULX_FLAG, \ ++ N_("Enable MULX instructions, assume fast shifter") }, \ ++ { "no-hw-mul", -HAS_MUL_FLAG, \ ++ N_("Disable MUL instructions") }, \ ++ { "no-hw-mulx", -HAS_MULX_FLAG, \ ++ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \ ++ { "fast-sw-div", FAST_SW_DIV_FLAG, \ ++ N_("Use table based fast divide (default at -O3)") }, \ ++ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \ ++ N_("Don't use table based fast divide ever") }, \ ++ { "inline-memcpy", INLINE_MEMCPY_FLAG, \ ++ N_("Inline small memcpy (default when optimizing)") }, \ ++ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \ ++ N_("Don't Inline small memcpy") }, \ ++ { "cache-volatile", CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use non-io variants of instructions (default)") }, \ ++ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use io variants of instructions") }, \ ++ { "bypass-cache", BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins use io variants") }, \ ++ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins do not use io variants (default)") }, \ ++ { "smallc", 0, \ ++ N_("Link with a limited version of the C library") }, \ ++ { "ctors-in-init", 0, \ ++ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \ ++ { "", TARGET_DEFAULT, 0 } \ ++} ++ ++ ++extern const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++extern const char *nios2_sys_lib_string; /* for -msys-lib= */ ++extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++#define TARGET_OPTIONS \ ++{ \ ++ { "sys=nosys", &nios2_sys_nosys_string, \ ++ N_("Use stub versions of OS library calls (default)"), 0}, \ ++ { "sys-lib=", &nios2_sys_lib_string, \ ++ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \ ++ { "sys-crt0=", &nios2_sys_crt0_string, \ ++ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \ ++} ++ ++ ++/* Default target_flags if no switches specified. */ ++#ifndef TARGET_DEFAULT ++# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG) ++#endif ++ ++/* Switch Recognition by gcc.c. Add -G xx support */ ++#undef SWITCH_TAKES_ARG ++#define SWITCH_TAKES_ARG(CHAR) \ ++ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') ++ ++#define OVERRIDE_OPTIONS override_options () ++#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) ++#define CAN_DEBUG_WITHOUT_FP ++ ++#define CC1_SPEC "\ ++%{G*}" ++ ++#undef LIB_SPEC ++#define LIB_SPEC \ ++"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \ ++ %{msys-lib=*: -l%*} \ ++ %{!msys-lib=*: -lc } \ ++ --end-group \ ++ %{msys-lib=: %eYou need a library name for -msys-lib=} \ ++" ++ ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC \ ++"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \ ++ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \ ++ %{mctors-in-init: crti%O%s crtbegin%O%s} \ ++" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++ "%{mctors-in-init: crtend%O%s crtn%O%s}" ++ ++ ++/*********************** ++ * Storage Layout ++ ***********************/ ++ ++#define DEFAULT_SIGNED_CHAR 1 ++#define BITS_BIG_ENDIAN 0 ++#define BYTES_BIG_ENDIAN 0 ++#define WORDS_BIG_ENDIAN 0 ++#define BITS_PER_UNIT 8 ++#define BITS_PER_WORD 32 ++#define UNITS_PER_WORD 4 ++#define POINTER_SIZE 32 ++#define BIGGEST_ALIGNMENT 32 ++#define STRICT_ALIGNMENT 1 ++#define FUNCTION_BOUNDARY 32 ++#define PARM_BOUNDARY 32 ++#define STACK_BOUNDARY 32 ++#define PREFERRED_STACK_BOUNDARY 32 ++#define MAX_FIXED_MODE_SIZE 64 ++ ++#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ ++ ((TREE_CODE (EXP) == STRING_CST) \ ++ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) ++ ++ ++/********************** ++ * Layout of Source Language Data Types ++ **********************/ ++ ++#define INT_TYPE_SIZE 32 ++#define SHORT_TYPE_SIZE 16 ++#define LONG_TYPE_SIZE 32 ++#define LONG_LONG_TYPE_SIZE 64 ++#define FLOAT_TYPE_SIZE 32 ++#define DOUBLE_TYPE_SIZE 64 ++#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE ++ ++ ++/************************* ++ * Condition Code Status ++ ************************/ ++ ++/* comparison type */ ++/* ??? currently only CMP_SI is used */ ++enum cmp_type { ++ CMP_SI, /* compare four byte integers */ ++ CMP_DI, /* compare eight byte integers */ ++ CMP_SF, /* compare single precision floats */ ++ CMP_DF, /* compare double precision floats */ ++ CMP_MAX /* max comparison type */ ++}; ++ ++extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ ++extern enum cmp_type branch_type; /* what type of branch to use */ ++ ++/********************** ++ * Register Usage ++ **********************/ ++ ++/* ---------------------------------- * ++ * Basic Characteristics of Registers ++ * ---------------------------------- */ ++ ++/* ++Register Number ++ Register Name ++ Alternate Name ++ Purpose ++0 r0 zero always zero ++1 r1 at Assembler Temporary ++2-3 r2-r3 Return Location ++4-7 r4-r7 Register Arguments ++8-15 r8-r15 Caller Saved Registers ++16-22 r16-r22 Callee Saved Registers ++23 r23 sc Static Chain (Callee Saved) ++ ??? Does $sc want to be caller or callee ++ saved. If caller, 15, else 23. ++24 r24 Exception Temporary ++25 r25 Breakpoint Temporary ++26 r26 gp Global Pointer ++27 r27 sp Stack Pointer ++28 r28 fp Frame Pointer ++29 r29 ea Exception Return Address ++30 r30 ba Breakpoint Return Address ++31 r31 ra Return Address ++ ++32 ctl0 status ++33 ctl1 estatus STATUS saved by exception ? ++34 ctl2 bstatus STATUS saved by break ? ++35 ctl3 ipri Interrupt Priority Mask ? ++36 ctl4 ecause Exception Cause ? ++ ++37 pc Not an actual register ++ ++38 rap Return address pointer, this does not ++ actually exist and will be eliminated ++ ++39 fake_fp Fake Frame Pointer which will always be eliminated. ++40 fake_ap Fake Argument Pointer which will always be eliminated. ++ ++41 First Pseudo Register ++ ++ ++The definitions for all the hard register numbers ++are located in nios2.md. ++*/ ++ ++#define FIRST_PSEUDO_REGISTER 41 ++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) ++ ++ ++ ++/* also see CONDITIONAL_REGISTER_USAGE */ ++#define FIXED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++/* call used is the same as caller saved ++ + fixed regs + args + ret vals */ ++#define CALL_USED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++/* --------------------------- * ++ * How Values Fit in Registers ++ * --------------------------- */ ++ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++ ++#define MODES_TIEABLE_P(MODE1, MODE2) 1 ++ ++ ++/************************* ++ * Register Classes ++ *************************/ ++ ++enum reg_class ++{ ++ NO_REGS, ++ ALL_REGS, ++ LIM_REG_CLASSES ++}; ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++ ++#define REG_CLASS_NAMES \ ++ {"NO_REGS", \ ++ "ALL_REGS"} ++ ++#define GENERAL_REGS ALL_REGS ++ ++#define REG_CLASS_CONTENTS \ ++/* NO_REGS */ {{ 0, 0}, \ ++/* ALL_REGS */ {~0,~0}} \ ++ ++#define REGNO_REG_CLASS(REGNO) ALL_REGS ++ ++#define BASE_REG_CLASS ALL_REGS ++#define INDEX_REG_CLASS ALL_REGS ++ ++/* only one reg class, 'r', is handled automatically */ ++#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS ++ ++#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ ++ ((STRICT) \ ++ ? (REGNO) < FIRST_PSEUDO_REGISTER \ ++ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) ++ ++#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) ++ ++#define REGNO_OK_FOR_BASE_P(REGNO) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) ++ ++#define REGNO_OK_FOR_INDEX_P(REGNO) \ ++ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) ++ ++#define REG_OK_FOR_BASE_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define REG_OK_FOR_INDEX_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++ ++#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) ++#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) ++#define UPPER16_INT(X) (((X) & 0xffff) == 0) ++#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) ++#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) ++#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ( \ ++ (C) == 'I' ? SMALL_INT (VALUE) : \ ++ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ ++ (C) == 'K' ? UPPER16_INT (VALUE) : \ ++ (C) == 'L' ? SHIFT_INT (VALUE) : \ ++ (C) == 'M' ? (VALUE) == 0 : \ ++ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ ++ (C) == 'O' ? RDWRCTL_INT (VALUE) : \ ++ 0) ++ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 ++ ++#define PREFERRED_RELOAD_CLASS(X, CLASS) \ ++ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) ++ ++/* 'S' matches immediates which are in small data ++ and therefore can be added to gp to create a ++ 32-bit value. */ ++#define EXTRA_CONSTRAINT(VALUE, C) \ ++ ((C) == 'S' \ ++ && (GET_CODE (VALUE) == SYMBOL_REF) \ ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) ++ ++ ++ ++ ++/* Say that the epilogue uses the return address register. Note that ++ in the case of sibcalls, the values "used by the epilogue" are ++ considered live at the start of the called function. */ ++#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) ++ ++ ++#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) ++ ++/********************************** ++ * Trampolines for Nested Functions ++ ***********************************/ ++ ++#define TRAMPOLINE_TEMPLATE(FILE) \ ++ error ("trampolines not yet implemented") ++#define TRAMPOLINE_SIZE 20 ++#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ ++ error ("trampolines not yet implemented") ++ ++/*************************** ++ * Stack Layout and Calling Conventions ++ ***************************/ ++ ++/* ------------------ * ++ * Basic Stack Layout ++ * ------------------ */ ++ ++/* The downward variants are used by the compiler, ++ the upward ones serve as documentation */ ++#define STACK_GROWS_DOWNWARD ++#define FRAME_GROWS_UPWARD ++#define ARGS_GROW_UPWARD ++ ++#define STARTING_FRAME_OFFSET current_function_outgoing_args_size ++#define FIRST_PARM_OFFSET(FUNDECL) 0 ++ ++/* Before the prologue, RA lives in r31. */ ++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) ++ ++/* -------------------------------------- * ++ * Registers That Address the Stack Frame ++ * -------------------------------------- */ ++ ++#define STACK_POINTER_REGNUM SP_REGNO ++#define STATIC_CHAIN_REGNUM SC_REGNO ++#define PC_REGNUM PC_REGNO ++#define DWARF_FRAME_RETURN_COLUMN RA_REGNO ++ ++/* Base register for access to local variables of the function. We ++ pretend that the frame pointer is a non-existent hard register, and ++ then eliminate it to HARD_FRAME_POINTER_REGNUM. */ ++#define FRAME_POINTER_REGNUM FAKE_FP_REGNO ++ ++#define HARD_FRAME_POINTER_REGNUM FP_REGNO ++#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO ++/* the argumnet pointer needs to always be eliminated ++ so it is set to a fake hard register. */ ++#define ARG_POINTER_REGNUM FAKE_AP_REGNO ++ ++/* ----------------------------------------- * ++ * Eliminating Frame Pointer and Arg Pointer ++ * ----------------------------------------- */ ++ ++#define FRAME_POINTER_REQUIRED 0 ++ ++#define ELIMINABLE_REGS \ ++{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} ++ ++#define CAN_ELIMINATE(FROM, TO) 1 ++ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) ++ ++#define MUST_SAVE_REGISTER(regno) \ ++ ((regs_ever_live[regno] && !call_used_regs[regno]) \ ++ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ ++ || (regno == RA_REGNO && regs_ever_live[RA_REGNO])) ++ ++/* Treat LOC as a byte offset from the stack pointer and round it up ++ to the next fully-aligned offset. */ ++#define STACK_ALIGN(LOC) \ ++ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) ++ ++ ++/* ------------------------------ * ++ * Passing Arguments in Registers ++ * ------------------------------ */ ++ ++/* see nios2.c */ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ (function_arg (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0 ++ ++#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 ++ ++typedef struct nios2_args ++{ ++ int regs_used; ++} CUMULATIVE_ARGS; ++ ++/* This is to initialize the above unused CUM data type */ ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ ++ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) ++ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_advance (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_REGNO_P(REGNO) \ ++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) ++ ++#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ ++ { \ ++ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \ ++ (TYPE), (NO_RTL)); \ ++ if (pret_size) \ ++ (PRETEND_SIZE) = pret_size; \ ++ } ++ ++/* ----------------------------- * ++ * Generating Code for Profiling ++ * ----------------------------- */ ++ ++#define PROFILE_BEFORE_PROLOGUE ++ ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ function_profiler ((FILE), (LABELNO)) ++ ++/* --------------------------------------- * ++ * Passing Function Arguments on the Stack ++ * --------------------------------------- */ ++ ++#define PROMOTE_PROTOTYPES 1 ++ ++#define PUSH_ARGS 0 ++#define ACCUMULATE_OUTGOING_ARGS 1 ++ ++#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 ++ ++/* --------------------------------------- * ++ * How Scalar Function Values Are Returned ++ * --------------------------------------- */ ++ ++#define FUNCTION_VALUE(VALTYPE, FUNC) \ ++ gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) ++ ++#define LIBCALL_VALUE(MODE) \ ++ gen_rtx(REG, MODE, FIRST_RETVAL_REGNO) ++ ++#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) ++ ++/* ----------------------------- * ++ * How Large Values Are Returned ++ * ----------------------------- */ ++ ++ ++#define RETURN_IN_MEMORY(TYPE) \ ++ nios2_return_in_memory (TYPE) ++ ++ ++#define STRUCT_VALUE 0 ++ ++#define DEFAULT_PCC_STRUCT_RETURN 0 ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++ ++#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) ++ ++#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) ++ ++#define MAX_REGS_PER_ADDRESS 1 ++ ++/* Go to ADDR if X is a valid address. */ ++#ifndef REG_OK_STRICT ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 0)) \ ++ goto ADDR; \ ++ } ++#else ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 1)) \ ++ goto ADDR; \ ++ } ++#endif ++ ++#ifndef REG_OK_STRICT ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) ++#else ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) ++#endif ++ ++#define LEGITIMATE_CONSTANT_P(X) 1 ++ ++/* Nios II has no mode dependent addresses. */ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) ++ ++/* Set if this has a weak declaration */ ++#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) ++#define SYMBOL_REF_WEAK_DECL_P(RTX) \ ++ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) ++ ++ ++/* true if a symbol is both small and not weak. In this case, gp ++ relative access can be used */ ++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ ++ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX)) ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++#define SLOW_BYTE_ACCESS 1 ++ ++/* It is as good to call a constant function address as to call an address ++ kept in a register. ++ ??? Not true anymore really. Now that call cannot address full range ++ of memory callr may need to be used */ ++ ++#define NO_FUNCTION_CSE ++#define NO_RECURSIVE_FUNCTION_CSE ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* ------------------------------------------ * ++ * The Overall Framework of an Assembler File ++ * ------------------------------------------ */ ++ ++#define ASM_APP_ON "#APP\n" ++#define ASM_APP_OFF "#NO_APP\n" ++ ++#define ASM_COMMENT_START "# " ++ ++/* ------------------------------- * ++ * Output and Generation of Labels ++ * ------------------------------- */ ++ ++#define GLOBAL_ASM_OP "\t.global\t" ++ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++#define DWARF2_UNWIND_INFO 0 ++ ++ ++/* -------------------------------- * ++ * Assembler Commands for Alignment ++ * -------------------------------- */ ++ ++#define ASM_OUTPUT_ALIGN(FILE, LOG) \ ++ do { \ ++ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ ++ } while (0) ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++#define REGISTER_NAMES \ ++{ \ ++ "zero", \ ++ "at", \ ++ "r2", \ ++ "r3", \ ++ "r4", \ ++ "r5", \ ++ "r6", \ ++ "r7", \ ++ "r8", \ ++ "r9", \ ++ "r10", \ ++ "r11", \ ++ "r12", \ ++ "r13", \ ++ "r14", \ ++ "r15", \ ++ "r16", \ ++ "r17", \ ++ "r18", \ ++ "r19", \ ++ "r20", \ ++ "r21", \ ++ "r22", \ ++ "r23", \ ++ "r24", \ ++ "r25", \ ++ "gp", \ ++ "sp", \ ++ "fp", \ ++ "ta", \ ++ "ba", \ ++ "ra", \ ++ "status", \ ++ "estatus", \ ++ "bstatus", \ ++ "ipri", \ ++ "ecause", \ ++ "pc", \ ++ "rap", \ ++ "fake_fp", \ ++ "fake_ap", \ ++} ++ ++#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ ++ (PTR) = asm_output_opcode (STREAM, PTR) ++ ++#define PRINT_OPERAND(STREAM, X, CODE) \ ++ nios2_print_operand (STREAM, X, CODE) ++ ++#define PRINT_OPERAND_ADDRESS(STREAM, X) \ ++ nios2_print_operand_address (STREAM, X) ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ ++do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ ++ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ ++ } while (0) ++ ++ ++/* ------------ * ++ * Label Output ++ * ------------ */ ++ ++ ++/* ---------------------------------------------------- * ++ * Dividing the Output into Sections (Texts, Data, ...) ++ * ---------------------------------------------------- */ ++ ++/* Output before read-only data. */ ++#define TEXT_SECTION_ASM_OP ("\t.section\t.text") ++ ++/* Output before writable data. */ ++#define DATA_SECTION_ASM_OP ("\t.section\t.data") ++ ++ ++/* Default the definition of "small data" to 8 bytes. */ ++/* ??? How come I can't use HOST_WIDE_INT here? */ ++extern unsigned long nios2_section_threshold; ++#define NIOS2_DEFAULT_GVALUE 8 ++ ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized external linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef COMMON_ASM_OP ++#define COMMON_ASM_OP "\t.comm\t" ++ ++#undef ASM_OUTPUT_ALIGNED_COMMON ++#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ ++do \ ++{ \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ { \ ++ named_section (0, ".sbss", 0); \ ++ (*targetm.asm_out.globalize_label) (FILE, NAME); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++ } \ ++ else \ ++ { \ ++ fprintf ((FILE), "%s", COMMON_ASM_OP); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ ++ } \ ++} \ ++while (0) ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized internal linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef ASM_OUTPUT_ALIGNED_LOCAL ++#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ ++do { \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ named_section (0, ".sbss", 0); \ ++ else \ ++ named_section (0, ".bss", 0); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++} while (0) ++ ++ ++ ++/*************************** ++ * Miscellaneous Parameters ++ ***************************/ ++ ++#define MOVE_MAX 4 ++ ++#define Pmode SImode ++#define FUNCTION_MODE QImode ++ ++#define CASE_VECTOR_MODE Pmode ++ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++ ++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) ++ ++#define WORD_REGISTER_OPERATIONS +--- gcc-3.4.3/gcc/config/nios2/nios2.md ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md +@@ -0,0 +1,2078 @@ ++;; Machine Description for Altera NIOS 2G NIOS2 version. ++;; Copyright (C) 2003 Altera ++;; Contributed by Jonah Graham (jgraham@altera.com). ++;; ++;; This file is part of GNU CC. ++;; ++;; GNU CC is free software; you can redistribute it and/or modify ++;; it under the terms of the GNU General Public License as published by ++;; the Free Software Foundation; either version 2, or (at your option) ++;; any later version. ++;; ++;; GNU CC is distributed in the hope that it will be useful, ++;; but WITHOUT ANY WARRANTY; without even the implied warranty of ++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++;; GNU General Public License for more details. ++;; ++;; You should have received a copy of the GNU General Public License ++;; along with GNU CC; see the file COPYING. If not, write to ++;; the Free Software Foundation, 59 Temple Place - Suite 330, ++;; Boston, MA 02111-1307, USA. */ ++ ++ ++ ++;***************************************************************************** ++;* ++;* constants ++;* ++;***************************************************************************** ++(define_constants [ ++ (GP_REGNO 26) ++ (SP_REGNO 27) ++ (FP_REGNO 28) ++ (RA_REGNO 31) ++ (RAP_REGNO 38) ++ (FIRST_RETVAL_REGNO 2) ++ (LAST_RETVAL_REGNO 3) ++ (FIRST_ARG_REGNO 4) ++ (LAST_ARG_REGNO 7) ++ (SC_REGNO 23) ++ (PC_REGNO 37) ++ (FAKE_FP_REGNO 39) ++ (FAKE_AP_REGNO 40) ++ ++ ++ (UNSPEC_BLOCKAGE 0) ++ (UNSPEC_LDBIO 1) ++ (UNSPEC_LDBUIO 2) ++ (UNSPEC_LDHIO 3) ++ (UNSPEC_LDHUIO 4) ++ (UNSPEC_LDWIO 5) ++ (UNSPEC_STBIO 6) ++ (UNSPEC_STHIO 7) ++ (UNSPEC_STWIO 8) ++ (UNSPEC_SYNC 9) ++ (UNSPEC_WRCTL 10) ++ (UNSPEC_RDCTL 11) ++ ++]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* instruction scheduler ++;* ++;***************************************************************************** ++ ++; No schedule info is currently available, using an assumption that no ++; instruction can use the results of the previous instruction without ++; incuring a stall. ++ ++; length of an instruction (in bytes) ++(define_attr "length" "" (const_int 4)) ++(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex")) ++ ++(define_asm_attributes ++ [(set_attr "length" "4") ++ (set_attr "type" "complex")]) ++ ++(define_automaton "nios2") ++(automata_option "v") ++;(automata_option "no-minimization") ++(automata_option "ndfa") ++ ++; The nios2 pipeline is fairly straightforward for the fast model. ++; Every alu operation is pipelined so that an instruction can ++; be issued every cycle. However, there are still potential ++; stalls which this description tries to deal with. ++ ++(define_cpu_unit "cpu" "nios2") ++ ++(define_insn_reservation "complex" 1 ++ (eq_attr "type" "complex") ++ "cpu") ++ ++(define_insn_reservation "control" 1 ++ (eq_attr "type" "control") ++ "cpu") ++ ++(define_insn_reservation "alu" 1 ++ (eq_attr "type" "alu") ++ "cpu") ++ ++(define_insn_reservation "cond_alu" 1 ++ (eq_attr "type" "cond_alu") ++ "cpu") ++ ++(define_insn_reservation "st" 1 ++ (eq_attr "type" "st") ++ "cpu") ++ ++(define_insn_reservation "custom" 1 ++ (eq_attr "type" "custom") ++ "cpu") ++ ++; shifts, muls and lds have three cycle latency ++(define_insn_reservation "ld" 3 ++ (eq_attr "type" "ld") ++ "cpu") ++ ++(define_insn_reservation "shift" 3 ++ (eq_attr "type" "shift") ++ "cpu") ++ ++(define_insn_reservation "mul" 3 ++ (eq_attr "type" "mul") ++ "cpu") ++ ++(define_insn_reservation "div" 1 ++ (eq_attr "type" "div") ++ "cpu") ++ ++ ++;***************************************************************************** ++;* ++;* MOV Instructions ++;* ++;***************************************************************************** ++ ++(define_expand "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (match_operand:QI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, QImode)) ++ DONE; ++}) ++ ++(define_insn "movqi_internal" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") ++ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] ++ "(register_operand (operands[0], QImode) ++ || register_operand (operands[1], QImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stb%o0\\t%z1, %0 ++ ldbu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu")]) ++ ++(define_insn "ldbio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldbuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stbio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] ++ "" ++ "stbio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, HImode)) ++ DONE; ++}) ++ ++(define_insn "movhi_internal" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") ++ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] ++ "(register_operand (operands[0], HImode) ++ || register_operand (operands[1], HImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ sth%o0\\t%z1, %0 ++ ldhu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu,alu")]) ++ ++(define_insn "ldhio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldhuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "sthio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] ++ "" ++ "sthio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++(define_expand "movsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (match_operand:SI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, SImode)) ++ DONE; ++}) ++ ++(define_insn "movsi_internal" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") ++ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] ++ "(register_operand (operands[0], SImode) ++ || register_operand (operands[1], SImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stw%o0\\t%z1, %0 ++ ldw%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1 ++ addi\\t%0, gp, %%gprel(%1) ++ movhi\\t%0, %H1\;addi\\t%0, %0, %L1" ++ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) ++ ++(define_insn "ldwio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldwio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stwio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] ++ "" ++ "stwio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* zero extension ++;* ++;***************************************************************************** ++ ++ ++(define_insn "zero_extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xffff ++ ldhu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=r,r") ++ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* sign extension ++;* ++;***************************************************************************** ++ ++(define_expand "extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (16); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendhisi2_internal" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ++ "" ++ "ldh%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_expand "extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op0 = gen_lowpart (SImode, operands[0]); ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (op0, temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqihi2_internal" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++(define_expand "extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqisi2_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Arithmetic Operations ++;* ++;***************************************************************************** ++ ++(define_insn "addsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (plus:SI (match_operand:SI 1 "register_operand" "%r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "" ++ "add%i2\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "subsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++ "sub\\t%0, %z1, %2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "mulsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (mult:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "TARGET_HAS_MUL" ++ "mul%i2\\t%0, %1, %z2" ++ [(set_attr "type" "mul")]) ++ ++(define_expand "divsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++{ ++ if (!TARGET_HAS_DIV) ++ { ++ if (!TARGET_FAST_SW_DIV) ++ FAIL; ++ else ++ { ++ if (nios2_emit_expensive_div (operands, SImode)) ++ DONE; ++ } ++ } ++}) ++ ++(define_insn "divsi3_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "div\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "udivsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (udiv:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "divu\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "smulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxss\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++(define_insn "umulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxuu\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++ ++(define_expand "mulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) ++ (sign_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++(define_expand "umulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) ++ (zero_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++ ++ ++;***************************************************************************** ++;* ++;* Negate and ones complement ++;* ++;***************************************************************************** ++ ++(define_insn "negsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (neg:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "sub\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++(define_insn "one_cmplsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (not:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "nor\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++ ++ ++; Logical Operantions ++ ++(define_insn "andsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ and\\t%0, %1, %z2 ++ and%i2\\t%0, %1, %2 ++ andh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "iorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ or\\t%0, %1, %z2 ++ or%i2\\t%0, %1, %2 ++ orh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "*norsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) ++ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] ++ "" ++ "nor\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "xorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ xor\\t%0, %1, %z2 ++ xor%i2\\t%0, %1, %2 ++ xorh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Shifts ++;* ++;***************************************************************************** ++ ++(define_insn "ashlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashift:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sll%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "ashrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sra%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "lshrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "srl%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotate:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "rol%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "register_operand" "r,r")))] ++ "" ++ "ror\\t%0, %1, %2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "*shift_mul_constants" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "const_int_operand" "I")) ++ (match_operand:SI 3 "const_int_operand" "I")))] ++ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" ++{ ++ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); ++ rtx ops[3]; ++ ++ ops[0] = operands[0]; ++ ops[1] = operands[1]; ++ ops[2] = GEN_INT (mul); ++ ++ output_asm_insn ("muli\t%0, %1, %2", ops); ++ return ""; ++} ++ [(set_attr "type" "mul")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Prologue, Epilogue and Return ++;* ++;***************************************************************************** ++ ++(define_expand "prologue" ++ [(const_int 1)] ++ "" ++{ ++ expand_prologue (); ++ DONE; ++}) ++ ++(define_expand "epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (false); ++ DONE; ++}) ++ ++(define_expand "sibcall_epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (true); ++ DONE; ++}) ++ ++(define_insn "return" ++ [(return)] ++ "reload_completed && nios2_can_use_return_insn ()" ++ "ret\\t" ++) ++ ++(define_insn "return_from_epilogue" ++ [(use (match_operand 0 "pmode_register_operand" "")) ++ (return)] ++ "reload_completed" ++ "ret\\t" ++) ++ ++;; Block any insns from being moved before this point, since the ++;; profiling call to mcount can use various registers that aren't ++;; saved or used to pass arguments. ++ ++(define_insn "blockage" ++ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] ++ "" ++ "" ++ [(set_attr "type" "unknown") ++ (set_attr "length" "0")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Jumps and Calls ++;* ++;***************************************************************************** ++ ++(define_insn "indirect_jump" ++ [(set (pc) (match_operand:SI 0 "register_operand" "r"))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "jump" ++ [(set (pc) ++ (label_ref (match_operand 0 "" "")))] ++ "" ++ "br\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "indirect_call" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "indirect_call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%1" ++) ++ ++(define_expand "call" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_expand "call_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_insn "*call" ++ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) ++ (match_operand 1 "" "")) ++ (clobber (match_operand:SI 2 "register_operand" "=r"))] ++ "" ++ "call\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "*call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) ++ (match_operand 2 "" ""))) ++ (clobber (match_operand:SI 3 "register_operand" "=r"))] ++ "" ++ "call\\t%1" ++ [(set_attr "type" "control")]) ++ ++(define_expand "sibcall" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))])] ++ "" ++ { ++ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); ++ ++ if (operands[2] == NULL_RTX) ++ operands[2] = const0_rtx; ++ } ++) ++ ++(define_expand "sibcall_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))])] ++ "" ++ { ++ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); ++ ++ if (operands[3] == NULL_RTX) ++ operands[3] = const0_rtx; ++ } ++) ++ ++(define_insn "sibcall_insn" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))] ++ "" ++ "jmp\\t%0" ++) ++ ++(define_insn "sibcall_value_insn" ++ [(set (match_operand 0 "register_operand" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))] ++ "" ++ "jmp\\t%1" ++) ++ ++ ++ ++ ++(define_expand "tablejump" ++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))])] ++ "" ++ "" ++) ++ ++(define_insn "*tablejump" ++ [(set (pc) ++ (match_operand:SI 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Comparisons ++;* ++;***************************************************************************** ++;; Flow here is rather complex (based on MIPS): ++;; ++;; 1) The cmp{si,di,sf,df} routine is called. It deposits the ++;; arguments into the branch_cmp array, and the type into ++;; branch_type. No RTL is generated. ++;; ++;; 2) The appropriate branch define_expand is called, which then ++;; creates the appropriate RTL for the comparison and branch. ++;; Different CC modes are used, based on what type of branch is ++;; done, so that we can constrain things appropriately. There ++;; are assumptions in the rest of GCC that break if we fold the ++;; operands into the branchs for integer operations, and use cc0 ++;; for floating point, so we use the fp status register instead. ++;; If needed, an appropriate temporary is created to hold the ++;; of the integer compare. ++ ++(define_expand "cmpsi" ++ [(set (cc0) ++ (compare:CC (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "arith_operand" "")))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++(define_expand "tstsi" ++ [(set (cc0) ++ (match_operand:SI 0 "register_operand" ""))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = const0_rtx; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* setting a register from a comparison ++;* ++;***************************************************************************** ++ ++(define_expand "seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpeq%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpne%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmplt\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpge%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpge\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmplt%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpltu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpgeu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpgeu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpltu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* branches ++;* ++;***************************************************************************** ++ ++(define_insn "*cbranch" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:SI 2 "reg_or_0_operand" "rM") ++ (match_operand:SI 3 "reg_or_0_operand" "rM")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ "b%0\\t%z2, %z3, %l1" ++ [(set_attr "type" "control")]) ++ ++ ++(define_expand "beq" ++ [(set (pc) ++ (if_then_else (eq:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bne" ++ [(set (pc) ++ (if_then_else (ne:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgt" ++ [(set (pc) ++ (if_then_else (gt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bge" ++ [(set (pc) ++ (if_then_else (ge:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "ble" ++ [(set (pc) ++ (if_then_else (le:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "blt" ++ [(set (pc) ++ (if_then_else (lt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgtu" ++ [(set (pc) ++ (if_then_else (gtu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bgeu" ++ [(set (pc) ++ (if_then_else (geu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bleu" ++ [(set (pc) ++ (if_then_else (leu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bltu" ++ [(set (pc) ++ (if_then_else (ltu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* String and Block Operations ++;* ++;***************************************************************************** ++ ++; ??? This is all really a hack to get Dhrystone to work as fast as possible ++; things to be fixed: ++; * let the compiler core handle all of this, for that to work the extra ++; aliasing needs to be addressed. ++; * we use three temporary registers for loading and storing to ensure no ++; ld use stalls, this is excessive, because after the first ld/st only ++; two are needed. Only two would be needed all the way through if ++; we could schedule with other code. Consider: ++; 1 ld $1, 0($src) ++; 2 ld $2, 4($src) ++; 3 ld $3, 8($src) ++; 4 st $1, 0($dest) ++; 5 ld $1, 12($src) ++; 6 st $2, 4($src) ++; 7 etc. ++; The first store has to wait until 4. If it does not there will be one ++; cycle of stalling. However, if any other instruction could be placed ++; between 1 and 4, $3 would not be needed. ++; * In small we probably don't want to ever do this ourself because there ++; is no ld use stall. ++ ++(define_expand "movstrsi" ++ [(parallel [(set (match_operand:BLK 0 "general_operand" "") ++ (match_operand:BLK 1 "general_operand" "")) ++ (use (match_operand:SI 2 "const_int_operand" "")) ++ (use (match_operand:SI 3 "const_int_operand" "")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))])] ++ "TARGET_INLINE_MEMCPY" ++{ ++ rtx ld_addr_reg, st_addr_reg; ++ ++ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr ++ it trys to copy to a register, but does not re-try the predicate. ++ ??? Intead of fixing expr.c, I fix it here. */ ++ if (!const_int_operand (operands[2], SImode)) ++ FAIL; ++ ++ /* ??? there are some magic numbers which need to be sorted out here. ++ the basis for them is not increasing code size hugely or going ++ out of range of offset addressing */ ++ if (INTVAL (operands[3]) < 4) ++ FAIL; ++ if (!optimize ++ || (optimize_size && INTVAL (operands[2]) > 12) ++ || (optimize < 3 && INTVAL (operands[2]) > 100) ++ || INTVAL (operands[2]) > 200) ++ FAIL; ++ ++ st_addr_reg ++ = replace_equiv_address (operands[0], ++ copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); ++ ld_addr_reg ++ = replace_equiv_address (operands[1], ++ copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); ++ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, ++ operands[2], operands[3])); ++ ++ DONE; ++}) ++ ++ ++(define_insn "movstrsi_internal" ++ [(set (match_operand:BLK 0 "memory_operand" "=o") ++ (match_operand:BLK 1 "memory_operand" "o")) ++ (use (match_operand:SI 2 "const_int_operand" "i")) ++ (use (match_operand:SI 3 "const_int_operand" "i")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))] ++ "TARGET_INLINE_MEMCPY" ++{ ++ int ld_offset = INTVAL (operands[2]); ++ int ld_len = INTVAL (operands[2]); ++ int ld_reg = 0; ++ rtx ld_addr_reg = XEXP (operands[1], 0); ++ int st_offset = INTVAL (operands[2]); ++ int st_len = INTVAL (operands[2]); ++ int st_reg = 0; ++ rtx st_addr_reg = XEXP (operands[0], 0); ++ int delay_count = 0; ++ ++ /* ops[0] is the address used by the insn ++ ops[1] is the register being loaded or stored */ ++ rtx ops[2]; ++ ++ if (INTVAL (operands[3]) < 4) ++ abort (); ++ ++ while (ld_offset >= 4) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldw\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 4; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 2) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldh\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 2; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 1) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldb\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 1; ++ delay_count++; ++ } ++ ++ while (st_offset >= 4) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ while (st_offset >= 2) ++ { ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("sth\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 2; ++ } ++ ++ while (st_offset >= 1) ++ { ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stb\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 1; ++ } ++ ++ return ""; ++} ++; ??? lengths are not being used yet, but I will probably forget ++; to update this once I am using lengths, so set it to something ++; definetely big enough to cover it. 400 allows for 200 bytes ++; of motion. ++ [(set_attr "length" "400")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Custom instructions ++;* ++;***************************************************************************** ++ ++(define_constants [ ++ (CUSTOM_N 100) ++ (CUSTOM_NI 101) ++ (CUSTOM_NF 102) ++ (CUSTOM_NP 103) ++ (CUSTOM_NII 104) ++ (CUSTOM_NIF 105) ++ (CUSTOM_NIP 106) ++ (CUSTOM_NFI 107) ++ (CUSTOM_NFF 108) ++ (CUSTOM_NFP 109) ++ (CUSTOM_NPI 110) ++ (CUSTOM_NPF 111) ++ (CUSTOM_NPP 112) ++ (CUSTOM_IN 113) ++ (CUSTOM_INI 114) ++ (CUSTOM_INF 115) ++ (CUSTOM_INP 116) ++ (CUSTOM_INII 117) ++ (CUSTOM_INIF 118) ++ (CUSTOM_INIP 119) ++ (CUSTOM_INFI 120) ++ (CUSTOM_INFF 121) ++ (CUSTOM_INFP 122) ++ (CUSTOM_INPI 123) ++ (CUSTOM_INPF 124) ++ (CUSTOM_INPP 125) ++ (CUSTOM_FN 126) ++ (CUSTOM_FNI 127) ++ (CUSTOM_FNF 128) ++ (CUSTOM_FNP 129) ++ (CUSTOM_FNII 130) ++ (CUSTOM_FNIF 131) ++ (CUSTOM_FNIP 132) ++ (CUSTOM_FNFI 133) ++ (CUSTOM_FNFF 134) ++ (CUSTOM_FNFP 135) ++ (CUSTOM_FNPI 136) ++ (CUSTOM_FNPF 137) ++ (CUSTOM_FNPP 138) ++ (CUSTOM_PN 139) ++ (CUSTOM_PNI 140) ++ (CUSTOM_PNF 141) ++ (CUSTOM_PNP 142) ++ (CUSTOM_PNII 143) ++ (CUSTOM_PNIF 144) ++ (CUSTOM_PNIP 145) ++ (CUSTOM_PNFI 146) ++ (CUSTOM_PNFF 147) ++ (CUSTOM_PNFP 148) ++ (CUSTOM_PNPI 149) ++ (CUSTOM_PNPF 150) ++ (CUSTOM_PNPP 151) ++]) ++ ++ ++(define_insn "custom_n" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] ++ "" ++ "custom\\t%0, zero, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ni" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_np" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nii" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nif" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nip" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nff" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_in" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ini" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++(define_insn "custom_fn" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fni" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnii" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnif" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnip" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnff" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_pn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pni" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Misc ++;* ++;***************************************************************************** ++ ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop\\t" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "sync" ++ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] ++ "" ++ "sync\\t" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "rdctl" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))] ++ "" ++ "rdctl\\t%0, ctl%1" ++ [(set_attr "type" "control")]) ++ ++(define_insn "wrctl" ++ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") ++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_WRCTL)] ++ "" ++ "wrctl\\tctl%0, %1" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Peepholes ++;* ++;***************************************************************************** ++ ++ +--- gcc-3.4.3/gcc/config/nios2/t-nios2 ++++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2 +@@ -0,0 +1,123 @@ ++## ++## Compiler flags to use when compiling libgcc2.c. ++## ++## LIB2FUNCS_EXTRA ++## A list of source file names to be compiled or assembled and inserted into libgcc.a. ++ ++LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ ++ $(srcdir)/config/nios2/lib2-divmod-hi.c \ ++ $(srcdir)/config/nios2/lib2-divtable.c \ ++ $(srcdir)/config/nios2/lib2-mul.c ++ ++## ++## Floating Point Emulation ++## To have GCC include software floating point libraries in libgcc.a define FPBIT ++## and DPBIT along with a few rules as follows: ++## ++## # We want fine grained libraries, so use the new code ++## # to build the floating point emulation libraries. ++FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c ++DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c ++ ++TARGET_LIBGCC2_CFLAGS = -O2 ++ ++# FLOAT_ONLY - no doubles ++# SMALL_MACHINE - QI/HI is faster than SI ++# Actually SMALL_MACHINE uses chars and shorts instead of ints ++# since ints (16-bit ones as they are today) are at least as fast ++# as chars and shorts, don't define SMALL_MACHINE ++# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) ++ ++$(FPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '#define FLOAT' > ${FPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT} ++ ++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '' > ${DPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT} ++ ++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o ++ ++# Assemble startup files. ++$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm ++ ++$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm ++ ++ ++## You may need to provide additional #defines at the beginning of ++## fp-bit.c and dp-bit.c to control target endianness and other options ++## ++## CRTSTUFF_T_CFLAGS ++## Special flags used when compiling crtstuff.c. See Initialization. ++## ++## CRTSTUFF_T_CFLAGS_S ++## Special flags used when compiling crtstuff.c for shared linking. Used ++## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. ++## ++## MULTILIB_OPTIONS ++## For some targets, invoking GCC in different ways produces objects that ++## can not be linked together. For example, for some targets GCC produces ++## both big and little endian code. For these targets, you must arrange ++## for multiple versions of libgcc.a to be compiled, one for each set of ++## incompatible options. When GCC invokes the linker, it arranges to link ++## in the right version of libgcc.a, based on the command line options ++## used. ++## The MULTILIB_OPTIONS macro lists the set of options for which special ++## versions of libgcc.a must be built. Write options that are mutually ++## incompatible side by side, separated by a slash. Write options that may ++## be used together separated by a space. The build procedure will build ++## all combinations of compatible options. ++## ++## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, ++## Makefile will build special versions of libgcc.a using the following ++## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, ++## and -m68020 -msoft-float. ++ ++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx ++ ++## MULTILIB_DIRNAMES ++## If MULTILIB_OPTIONS is used, this variable specifies the directory names ++## that should be used to hold the various libraries. Write one element in ++## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If ++## MULTILIB_DIRNAMES is not used, the default value will be ++## MULTILIB_OPTIONS, with all slashes treated as spaces. ++## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, ++## then the default value of MULTILIB_DIRNAMES is m68000 m68020 ++## msoft-float. You may specify a different value if you desire a ++## different set of directory names. ++ ++# MULTILIB_DIRNAMES = ++ ++## MULTILIB_MATCHES ++## Sometimes the same option may be written in two different ways. If an ++## option is listed in MULTILIB_OPTIONS, GCC needs to know about any ++## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the ++## form option=option to describe all relevant synonyms. For example, ++## m68000=mc68000 m68020=mc68020. ++## ++## MULTILIB_EXCEPTIONS ++## Sometimes when there are multiple sets of MULTILIB_OPTIONS being ++## specified, there are combinations that should not be built. In that ++## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in ++## shell case syntax that should not be built. ++## For example, in the PowerPC embedded ABI support, it is not desirable to ++## build libraries compiled with the -mcall-aix option and either of the ++## -fleading-underscore or -mlittle options at the same time. Therefore ++## MULTILIB_EXCEPTIONS is set to ++## ++## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* ++## ++ ++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* ++ ++## ++## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building ++## multiple versions of libgcc.a certain options should always be passed on ++## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list ++## of options to be used for all builds. ++## ++ +--- gcc-3.4.3/gcc/config.gcc ++++ gcc-3.4.3-nios2/gcc/config.gcc +@@ -1321,6 +1321,10 @@ m32rle-*-linux*) + thread_file='posix' + fi + ;; ++# JBG ++nios2-*-* | nios2-*-*) ++ tm_file="elfos.h ${tm_file}" ++ ;; + # m68hc11 and m68hc12 share the same machine description. + m68hc11-*-*|m6811-*-*) + tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h" +--- gcc-3.4.3/gcc/cse.c ++++ gcc-3.4.3-nios2/gcc/cse.c +@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code + #ifdef FLOAT_STORE_FLAG_VALUE + REAL_VALUE_TYPE fsfv; + #endif ++#ifdef __nios2__ ++ if (p->is_const) ++ break; ++#endif + + /* If the entry isn't valid, skip it. */ + if (! exp_equiv_p (p->exp, p->exp, 1, 0)) +--- gcc-3.4.3/gcc/doc/extend.texi ++++ gcc-3.4.3-nios2/gcc/doc/extend.texi +@@ -5636,12 +5636,118 @@ to those machines. Generally these gene + instructions, but allow the compiler to schedule those calls. + + @menu ++* Altera Nios II Built-in Functions:: + * Alpha Built-in Functions:: + * ARM Built-in Functions:: + * X86 Built-in Functions:: + * PowerPC AltiVec Built-in Functions:: + @end menu + ++@node Altera Nios II Built-in Functions ++@subsection Altera Nios II Built-in Functions ++ ++These built-in functions are available for the Altera Nios II ++family of processors. ++ ++The following built-in functions are always available. They ++all generate the machine instruction that is part of the name. ++ ++@example ++int __builtin_ldbio (volatile const void *) ++int __builtin_ldbuio (volatile const void *) ++int __builtin_ldhio (volatile const void *) ++int __builtin_ldhuio (volatile const void *) ++int __builtin_ldwio (volatile const void *) ++void __builtin_stbio (volatile void *, int) ++void __builtin_sthio (volatile void *, int) ++void __builtin_stwio (volatile void *, int) ++void __builtin_sync (void) ++int __builtin_rdctl (int) ++void __builtin_wrctl (int, int) ++@end example ++ ++The following built-in functions are always available. They ++all generate a Nios II Custom Instruction. The name of the ++function represents the types that the function takes and ++returns. The letter before the @code{n} is the return type ++or void if absent. The @code{n} represnts the first parameter ++to all the custom instructions, the custom instruction number. ++The two letters after the @code{n} represent the up to two ++parameters to the function. ++ ++The letters reprsent the following data types: ++@table @code ++@item ++@code{void} for return type and no parameter for parameter types. ++ ++@item i ++@code{int} for return type and parameter type ++ ++@item f ++@code{float} for return type and parameter type ++ ++@item p ++@code{void *} for return type and parameter type ++ ++@end table ++ ++And the function names are: ++@example ++void __builtin_custom_n (void) ++void __builtin_custom_ni (int) ++void __builtin_custom_nf (float) ++void __builtin_custom_np (void *) ++void __builtin_custom_nii (int, int) ++void __builtin_custom_nif (int, float) ++void __builtin_custom_nip (int, void *) ++void __builtin_custom_nfi (float, int) ++void __builtin_custom_nff (float, float) ++void __builtin_custom_nfp (float, void *) ++void __builtin_custom_npi (void *, int) ++void __builtin_custom_npf (void *, float) ++void __builtin_custom_npp (void *, void *) ++int __builtin_custom_in (void) ++int __builtin_custom_ini (int) ++int __builtin_custom_inf (float) ++int __builtin_custom_inp (void *) ++int __builtin_custom_inii (int, int) ++int __builtin_custom_inif (int, float) ++int __builtin_custom_inip (int, void *) ++int __builtin_custom_infi (float, int) ++int __builtin_custom_inff (float, float) ++int __builtin_custom_infp (float, void *) ++int __builtin_custom_inpi (void *, int) ++int __builtin_custom_inpf (void *, float) ++int __builtin_custom_inpp (void *, void *) ++float __builtin_custom_fn (void) ++float __builtin_custom_fni (int) ++float __builtin_custom_fnf (float) ++float __builtin_custom_fnp (void *) ++float __builtin_custom_fnii (int, int) ++float __builtin_custom_fnif (int, float) ++float __builtin_custom_fnip (int, void *) ++float __builtin_custom_fnfi (float, int) ++float __builtin_custom_fnff (float, float) ++float __builtin_custom_fnfp (float, void *) ++float __builtin_custom_fnpi (void *, int) ++float __builtin_custom_fnpf (void *, float) ++float __builtin_custom_fnpp (void *, void *) ++void * __builtin_custom_pn (void) ++void * __builtin_custom_pni (int) ++void * __builtin_custom_pnf (float) ++void * __builtin_custom_pnp (void *) ++void * __builtin_custom_pnii (int, int) ++void * __builtin_custom_pnif (int, float) ++void * __builtin_custom_pnip (int, void *) ++void * __builtin_custom_pnfi (float, int) ++void * __builtin_custom_pnff (float, float) ++void * __builtin_custom_pnfp (float, void *) ++void * __builtin_custom_pnpi (void *, int) ++void * __builtin_custom_pnpf (void *, float) ++void * __builtin_custom_pnpp (void *, void *) ++@end example ++ ++ + @node Alpha Built-in Functions + @subsection Alpha Built-in Functions + +--- gcc-3.4.3/gcc/doc/invoke.texi ++++ gcc-3.4.3-nios2/gcc/doc/invoke.texi +@@ -337,6 +337,14 @@ in the following sections. + @item Machine Dependent Options + @xref{Submodel Options,,Hardware Models and Configurations}. + ++@emph{Altera Nios II Options} ++@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol ++-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol ++-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol ++-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol ++-mno-hw-div -mhw-div @gol ++-msys-crt0= -msys-lib= -msys=nosys } ++ + @emph{M680x0 Options} + @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol + -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol +@@ -5836,6 +5844,7 @@ machine description. The default for th + that macro, which enables you to change the defaults. + + @menu ++* Altera Nios II Options:: + * M680x0 Options:: + * M68hc1x Options:: + * VAX Options:: +@@ -5871,6 +5880,103 @@ that macro, which enables you to change + * FRV Options:: + @end menu + ++ ++@node Altera Nios II Options ++@subsection Altera Nios II Options ++@cindex Altera Nios II options ++ ++These are the @samp{-m} options defined for the Altera Nios II ++processor. ++ ++@table @gcctabopt ++ ++@item -msmallc ++@opindex msmallc ++ ++Link with a limited version of the C library, -lsmallc. For more ++information see the C Library Documentation. ++ ++ ++@item -mbypass-cache ++@itemx -mno-bypass-cache ++@opindex mno-bypass-cache ++@opindex mbypass-cache ++ ++Force all load and store instructions to always bypass cache by ++using io variants of the instructions. The default is to not ++bypass the cache. ++ ++@item -mno-cache-volatile ++@itemx -mcache-volatile ++@opindex mcache-volatile ++@opindex mno-cache-volatile ++ ++Volatile memory access bypass the cache using the io variants of ++the ld and st instructions. The default is to cache volatile ++accesses. ++ ++-mno-cache-volatile is deprecated and will be deleted in a ++future GCC release. ++ ++ ++@item -mno-inline-memcpy ++@itemx -minline-memcpy ++@opindex mno-inline-memcpy ++@opindex minline-memcpy ++ ++Do not inline memcpy. The default is to inline when -O is on. ++ ++ ++@item -mno-fast-sw-div ++@itemx -mfast-sw-div ++@opindex mno-fast-sw-div ++@opindex mfast-sw-div ++ ++Do no use table based fast divide for small numbers. The default ++is to use the fast divide at -O3 and above. ++ ++ ++@item -mno-hw-mul ++@itemx -mhw-mul ++@itemx -mno-hw-mulx ++@itemx -mhw-mulx ++@itemx -mno-hw-div ++@itemx -mhw-div ++@opindex mno-hw-mul ++@opindex mhw-mul ++@opindex mno-hw-mulx ++@opindex mhw-mulx ++@opindex mno-hw-div ++@opindex mhw-div ++ ++Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of ++instructions by the compiler. The default is to emit @code{mul} ++and not emit @code{div} and @code{mulx}. ++ ++The different combinations of @code{mul} and @code{mulx} instructions ++generate a different multilib options. ++ ++ ++@item -msys-crt0=@var{startfile} ++@opindex msys-crt0 ++ ++@var{startfile} is the file name of the startfile (crt0) to use ++when linking. The default is crt0.o that comes with libgloss ++and is only suitable for use with the instruction set ++simulator. ++ ++@item -msys-lib=@var{systemlib} ++@itemx -msys-lib=nosys ++@opindex msys-lib ++ ++@var{systemlib} is the library name of the library which provides ++the system calls required by the C library, e.g. @code{read}, @code{write} ++etc. The default is to use nosys, this library provides ++stub implementations of the calls and is part of libgloss. ++ ++@end table ++ ++ + @node M680x0 Options + @subsection M680x0 Options + @cindex M680x0 options +--- gcc-3.4.3/gcc/doc/md.texi ++++ gcc-3.4.3-nios2/gcc/doc/md.texi +@@ -1335,6 +1335,49 @@ However, here is a summary of the machin + available on some particular machines. + + @table @emph ++ ++@item Altera Nios II family---@file{nios2.h} ++@table @code ++ ++@item I ++Integer that is valid as an immediate operand in an ++instruction taking a signed 16-bit number. Range ++@minus{}32768 to 32767. ++ ++@item J ++Integer that is valid as an immediate operand in an ++instruction taking an unsigned 16-bit number. Range ++0 to 65535. ++ ++@item K ++Integer that is valid as an immediate operand in an ++instruction taking only the upper 16-bits of a ++32-bit number. Range 32-bit numbers with the lower ++16-bits being 0. ++ ++@item L ++Integer that is valid as an immediate operand for a ++shift instruction. Range 0 to 31. ++ ++ ++@item M ++Integer that is valid as an immediate operand for ++only the value 0. Can be used in conjunction with ++the format modifier @code{z} to use @code{r0} ++instead of @code{0} in the assembly output. ++ ++@item N ++Integer that is valid as an immediate operand for ++a custom instruction opcode. Range 0 to 255. ++ ++@item S ++Matches immediates which are addresses in the small ++data section and therefore can be added to @code{gp} ++as a 16-bit immediate to re-create their 32-bit value. ++ ++@end table ++ ++ + @item ARM family---@file{arm.h} + @table @code + @item f diff --git a/misc/buildroot/toolchain/gcc/3.4.4/arm-softfloat.patch.conditional b/misc/buildroot/toolchain/gcc/3.4.4/arm-softfloat.patch.conditional new file mode 100644 index 000000000..19d1b90da --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.4/arm-softfloat.patch.conditional @@ -0,0 +1,270 @@ +Note... modified my mjn3 to not conflict with the big endian arm patch. +Warning!!! Only the linux target is aware of TARGET_ENDIAN_DEFAULT. +Also changed + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{!mcpu=*:-mcpu=xscale} \ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +to + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +in gcc/config/arm/linux-elf.h. +# +# Submitted: +# +# Dimitry Andric , 2004-05-01 +# +# Description: +# +# Nicholas Pitre released this patch for gcc soft-float support here: +# http://lists.arm.linux.org.uk/pipermail/linux-arm/2003-October/006436.html +# +# This version has been adapted to work with gcc 3.4.0. +# +# The original patch doesn't distinguish between softfpa and softvfp modes +# in the way Nicholas Pitre probably meant. His description is: +# +# "Default is to use APCS-32 mode with soft-vfp. The old Linux default for +# floats can be achieved with -mhard-float or with the configure +# --with-float=hard option. If -msoft-float or --with-float=soft is used then +# software float support will be used just like the default but with the legacy +# big endian word ordering for double float representation instead." +# +# Which means the following: +# +# * If you compile without -mhard-float or -msoft-float, you should get +# software floating point, using the VFP format. The produced object file +# should have these flags in its header: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# * If you compile with -mhard-float, you should get hardware floating point, +# which always uses the FPA format. Object file header flags should be: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# * If you compile with -msoft-float, you should get software floating point, +# using the FPA format. This is done for compatibility reasons with many +# existing distributions. Object file header flags should be: +# +# private flags = 200: [APCS-32] [FPA float format] [software FP] +# +# The original patch from Nicholas Pitre contained the following constructs: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" +# +# However, gcc doesn't accept this ";:" notation, used in the 3rd line. This +# is probably the reason Robert Schwebel modified it to: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa -mfpu=softvfp}}" +# +# But this causes the following behaviour: +# +# * If you compile without -mhard-float or -msoft-float, the compiler generates +# software floating point instructions, but *nothing* is passed to the +# assembler, which results in an object file which has flags: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# This is not correct! +# +# * If you compile with -mhard-float, the compiler generates hardware floating +# point instructions, and passes "-mfpu=fpa" to the assembler, which results +# in an object file which has the same flags as in the previous item, but now +# those *are* correct. +# +# * If you compile with -msoft-float, the compiler generates software floating +# point instructions, and passes "-mfpu=softfpa -mfpu=softvfp" (in that +# order) to the assembler, which results in an object file with flags: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# This is not correct, because the last "-mfpu=" option on the assembler +# command line determines the actual FPU convention used (which should be FPA +# in this case). +# +# Therefore, I modified this patch to get the desired behaviour. Every +# instance of the notation: +# +# %{msoft-float:-mfpu=softfpa -mfpu=softvfp} +# +# was changed to: +# +# %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp} +# +# I also did the following: +# +# * Modified all TARGET_DEFAULT macros I could find to include ARM_FLAG_VFP, to +# be consistent with Nicholas' original patch. +# * Removed any "msoft-float" or "mhard-float" from all MULTILIB_DEFAULTS +# macros I could find. I think that if you compile without any options, you +# would like to get the defaults. :) +# * Removed the extra -lfloat option from LIBGCC_SPEC, since it isn't needed +# anymore. (The required functions are now in libgcc.) + +diff -urN gcc-3.4.1-old/gcc/config/arm/coff.h gcc-3.4.1/gcc/config/arm/coff.h +--- gcc-3.4.1-old/gcc/config/arm/coff.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/coff.h 2004-09-02 21:51:15.000000000 -0500 +@@ -31,11 +31,16 @@ + #define TARGET_VERSION fputs (" (ARM/coff)", stderr) + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork" } + #endif + + /* This is COFF, but prefer stabs. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/elf.h gcc-3.4.1/gcc/config/arm/elf.h +--- gcc-3.4.1-old/gcc/config/arm/elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -46,7 +46,9 @@ + + #ifndef SUBTARGET_ASM_FLOAT_SPEC + #define SUBTARGET_ASM_FLOAT_SPEC "\ +-%{mapcs-float:-mfloat} %{msoft-float:-mfpu=softfpa}" ++%{mapcs-float:-mfloat} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + #endif + + #ifndef ASM_SPEC +@@ -106,12 +108,17 @@ + #endif + + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } + #endif + + #define TARGET_ASM_FILE_START_APP_OFF true +diff -urN gcc-3.4.1-old/gcc/config/arm/linux-elf.h gcc-3.4.1/gcc/config/arm/linux-elf.h +--- gcc-3.4.1-old/gcc/config/arm/linux-elf.h 2004-09-02 21:50:52.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h 2004-09-02 22:00:49.000000000 -0500 +@@ -44,12 +44,26 @@ + #define TARGET_LINKER_EMULATION "armelf_linux" + #endif + +-/* Default is to use APCS-32 mode. */ ++/* ++ * Default is to use APCS-32 mode with soft-vfp. ++ * The old Linux default for floats can be achieved with -mhard-float ++ * or with the configure --with-float=hard option. ++ * If -msoft-float or --with-float=soft is used then software float ++ * support will be used just like the default but with the legacy ++ * big endian word ordering for double float representation instead. ++ */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT \ +- ( ARM_FLAG_APCS_32 | \ +- ARM_FLAG_MMU_TRAPS | \ +- TARGET_ENDIAN_DEFAULT ) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_SOFT_FLOAT \ ++ | TARGET_ENDIAN_DEFAULT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_MMU_TRAPS ) ++ ++#undef SUBTARGET_EXTRA_ASM_SPEC ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +@@ -57,7 +71,7 @@ + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -72,7 +86,7 @@ + %{shared:-lc} \ + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" + +-#define LIBGCC_SPEC "%{msoft-float:-lfloat} -lgcc" ++#define LIBGCC_SPEC "-lgcc" + + /* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add + the GNU/Linux magical crtbegin.o file (see crtstuff.c) which +diff -urN gcc-3.4.1-old/gcc/config/arm/t-linux gcc-3.4.1/gcc/config/arm/t-linux +--- gcc-3.4.1-old/gcc/config/arm/t-linux 2003-09-20 16:09:07.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/t-linux 2004-09-02 21:51:15.000000000 -0500 +@@ -4,7 +4,10 @@ + LIBGCC2_DEBUG_CFLAGS = -g0 + + LIB1ASMSRC = arm/lib1funcs.asm +-LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx ++LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx \ ++ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \ ++ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ ++ _fixsfsi _fixunssfsi + + # MULTILIB_OPTIONS = mhard-float/msoft-float + # MULTILIB_DIRNAMES = hard-float soft-float +diff -urN gcc-3.4.1-old/gcc/config/arm/unknown-elf.h gcc-3.4.1/gcc/config/arm/unknown-elf.h +--- gcc-3.4.1-old/gcc/config/arm/unknown-elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/unknown-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -30,7 +30,12 @@ + + /* Default to using APCS-32 and software floating point. */ + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + /* Now we define the strings used to build the spec file. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/xscale-elf.h gcc-3.4.1/gcc/config/arm/xscale-elf.h +--- gcc-3.4.1-old/gcc/config/arm/xscale-elf.h 2003-07-01 18:26:43.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/xscale-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -49,11 +49,12 @@ + endian, regardless of the endian-ness of the memory + system. */ + +-#define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +- %{mhard-float:-mfpu=fpa} \ +- %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{!mcpu=*:-mcpu=xscale} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "mlittle-endian", "mno-thumb-interwork", "marm", "msoft-float" } ++ { "mlittle-endian", "mno-thumb-interwork", "marm" } + #endif diff --git a/misc/buildroot/toolchain/gcc/3.4.5/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/3.4.5/300-libstdc++-pic.patch new file mode 100644 index 000000000..9f304a4c4 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/300-libstdc++-pic.patch @@ -0,0 +1,47 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -224,6 +224,10 @@ + @OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCPP_BUILD_DEBUG + all-local: build_debug + +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -585,7 +585,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -618,6 +618,7 @@ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-data-local \ + install-exec install-exec-am install-info install-info-am \ ++ install-exec-local \ + install-man install-strip install-toolexeclibLTLIBRARIES \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ +@@ -707,6 +708,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/3.4.5/600-gcc34-arm-ldm-peephole.patch b/misc/buildroot/toolchain/gcc/3.4.5/600-gcc34-arm-ldm-peephole.patch new file mode 100644 index 000000000..0c370502c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/600-gcc34-arm-ldm-peephole.patch @@ -0,0 +1,65 @@ +--- gcc-3.4.0/gcc/config/arm/arm.md.arm-ldm-peephole 2004-01-13 08:24:37.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.md 2004-04-24 18:18:04.000000000 -0400 +@@ -8810,13 +8810,16 @@ + (set_attr "length" "4,8,8")] + ) + ++; Try to convert LDR+LDR+arith into [add+]LDM+arith ++; On XScale, LDM is always slower than two LDRs, so only do this if ++; optimising for size. + (define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] +- "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" ++ "TARGET_ARM && (!arm_tune_xscale || optimize_size) && adjacent_mem_locations (operands[2], operands[3])" + "* + { + rtx ldm[3]; +@@ -8851,6 +8854,8 @@ + } + if (val1 && val2) + { ++ /* This would be a loss on a Harvard core, but adjacent_mem_locations() ++ will prevent it from happening. */ + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm-peephole 2004-04-24 18:16:25.000000000 -0400 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:18:04.000000000 -0400 +@@ -4838,6 +4841,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* ldmia */ + +@@ -5064,6 +5072,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* stmia */ + +--- gcc-3.4.0/gcc/genpeep.c.arm-ldm-peephole 2003-07-05 01:27:22.000000000 -0400 ++++ gcc-3.4.0/gcc/genpeep.c 2004-04-24 18:18:04.000000000 -0400 +@@ -381,6 +381,7 @@ + printf ("#include \"recog.h\"\n"); + printf ("#include \"except.h\"\n\n"); + printf ("#include \"function.h\"\n\n"); ++ printf ("#include \"flags.h\"\n\n"); + + printf ("#ifdef HAVE_peephole\n"); + printf ("extern rtx peep_operand[];\n\n"); diff --git a/misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm-peephole2.patch b/misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm-peephole2.patch new file mode 100644 index 000000000..27f7c07db --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm-peephole2.patch @@ -0,0 +1,42 @@ +The 30_all_gcc34-arm-ldm-peephole.patch from Debian was conflicting +with the newer 36_all_pr16201-fix.patch, so i cut out the hunk from +it that was causing problems and grabbed an updated version from +upstream cvs. + +Index: gcc/config/arm/arm.c +=================================================================== +RCS file: /cvsroot/gcc/gcc/gcc/config/arm/arm.c,v +retrieving revision 1.432 +retrieving revision 1.433 +diff -u -r1.432 -r1.433 +--- gcc-3.4.4/gcc/config/arm/arm.c 29 Mar 2005 03:00:23 -0000 1.432 ++++ gcc-3.4.4/gcc/config/arm/arm.c 1 Apr 2005 11:02:22 -0000 1.433 +@@ -5139,6 +5139,10 @@ + int + adjacent_mem_locations (rtx a, rtx b) + { ++ /* We don't guarantee to preserve the order of these memory refs. */ ++ if (volatile_refs_p (a) || volatile_refs_p (b)) ++ return 0; ++ + if ((GET_CODE (XEXP (a, 0)) == REG + || (GET_CODE (XEXP (a, 0)) == PLUS + && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT)) +@@ -5178,6 +5182,17 @@ + return 0; + + val_diff = val1 - val0; ++ ++ if (arm_ld_sched) ++ { ++ /* If the target has load delay slots, then there's no benefit ++ to using an ldm instruction unless the offset is zero and ++ we are optimizing for size. */ ++ return (optimize_size && (REGNO (reg0) == REGNO (reg1)) ++ && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4) ++ && (val_diff == 4 || val_diff == -4)); ++ } ++ + return ((REGNO (reg0) == REGNO (reg1)) + && (val_diff == 4 || val_diff == -4)); + } diff --git a/misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm.patch b/misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm.patch new file mode 100644 index 000000000..142052fdf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/601-gcc34-arm-ldm.patch @@ -0,0 +1,119 @@ +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm 2004-02-27 09:51:05.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:16:25.000000000 -0400 +@@ -8520,6 +8520,26 @@ + return_used_this_function = 0; + } + ++/* Return the number (counting from 0) of ++ the least significant set bit in MASK. */ ++ ++#ifdef __GNUC__ ++inline ++#endif ++static int ++number_of_first_bit_set (mask) ++ int mask; ++{ ++ int bit; ++ ++ for (bit = 0; ++ (mask & (1 << bit)) == 0; ++ ++bit) ++ continue; ++ ++ return bit; ++} ++ + const char * + arm_output_epilogue (rtx sibling) + { +@@ -8753,27 +8773,47 @@ + saved_regs_mask |= (1 << PC_REGNUM); + } + +- /* Load the registers off the stack. If we only have one register +- to load use the LDR instruction - it is faster. */ +- if (saved_regs_mask == (1 << LR_REGNUM)) +- { +- /* The exception handler ignores the LR, so we do +- not really need to load it off the stack. */ +- if (eh_ofs) +- asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); +- else +- asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM); +- } +- else if (saved_regs_mask) ++ if (saved_regs_mask) + { +- if (saved_regs_mask & (1 << SP_REGNUM)) +- /* Note - write back to the stack register is not enabled +- (ie "ldmfd sp!..."). We know that the stack pointer is +- in the list of registers and if we add writeback the +- instruction becomes UNPREDICTABLE. */ +- print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ /* Load the registers off the stack. If we only have one register ++ to load use the LDR instruction - it is faster. */ ++ if (bit_count (saved_regs_mask) == 1) ++ { ++ int reg = number_of_first_bit_set (saved_regs_mask); ++ ++ switch (reg) ++ { ++ case SP_REGNUM: ++ /* Mustn't use base writeback when loading SP. */ ++ asm_fprintf (f, "\tldr\t%r, [%r]\n", SP_REGNUM, SP_REGNUM); ++ break; ++ ++ case LR_REGNUM: ++ if (eh_ofs) ++ { ++ /* The exception handler ignores the LR, so we do ++ not really need to load it off the stack. */ ++ asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); ++ break; ++ } ++ /* else fall through */ ++ ++ default: ++ asm_fprintf (f, "\tldr\t%r, [%r], #4\n", reg, SP_REGNUM); ++ break; ++ } ++ } + else +- print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ { ++ if (saved_regs_mask & (1 << SP_REGNUM)) ++ /* Note - write back to the stack register is not enabled ++ (ie "ldmfd sp!..."). We know that the stack pointer is ++ in the list of registers and if we add writeback the ++ instruction becomes UNPREDICTABLE. */ ++ print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ else ++ print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ } + } + + if (current_function_pretend_args_size) +@@ -11401,22 +11441,6 @@ + } + } + +-/* Return the number (counting from 0) of +- the least significant set bit in MASK. */ +- +-inline static int +-number_of_first_bit_set (int mask) +-{ +- int bit; +- +- for (bit = 0; +- (mask & (1 << bit)) == 0; +- ++bit) +- continue; +- +- return bit; +-} +- + /* Generate code to return from a thumb function. + If 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ diff --git a/misc/buildroot/toolchain/gcc/3.4.5/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/3.4.5/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..4377c2143 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +--- gcc-3.4.1/libstdc++-v3/libmath/Makefile.am~ 2003-08-27 22:29:42.000000000 +0100 ++++ gcc-3.4.1/libstdc++-v3/libmath/Makefile.am 2004-07-22 16:41:45.152130128 +0100 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC +--- gcc-3.4.1/libstdc++-v3/fragment.am.old 2004-07-22 18:24:58.024083656 +0100 ++++ gcc-3.4.1/libstdc++-v3/fragment.am 2004-07-22 18:24:59.019932264 +0100 +@@ -18,7 +18,7 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + + + diff --git a/misc/buildroot/toolchain/gcc/3.4.5/700-pr15068-fix.patch b/misc/buildroot/toolchain/gcc/3.4.5/700-pr15068-fix.patch new file mode 100644 index 000000000..2977765c5 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/700-pr15068-fix.patch @@ -0,0 +1,44 @@ +See http://gcc.gnu.org/PR15068 + +Fixes error + +../sysdeps/generic/s_fmax.c: In function `__fmax': +../sysdeps/generic/s_fmax.c:28: internal compiler error: in elim_reg_cond, at flow.c:3257 +Please submit a full bug report, +with preprocessed source if appropriate. +See for instructions. +make[2]: *** [/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/build-glibc/math/s_fmax.o] Error 1 +make[2]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822/math' +make[1]: *** [math/others] Error 2 +make[1]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822' +make: *** [all] Error 2 + +[ rediffed against gcc-3.4.1, with elbow grease, ending up with same thing as +http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/flow.c.diff?cvsroot=gcc&only_with_tag=csl-arm-branch&r1=1.563.4.2&r2=1.563.4.3 ] + +--- gcc-3.4.1/gcc/flow.c.old 2004-02-27 19:39:19.000000000 -0800 ++++ gcc-3.4.1/gcc/flow.c 2004-08-26 07:29:46.000000000 -0700 +@@ -1878,6 +1878,7 @@ + rtx set_src = SET_SRC (pc_set (BB_END (bb))); + rtx cond_true = XEXP (set_src, 0); + rtx reg = XEXP (cond_true, 0); ++ enum rtx_code inv_cond; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); +@@ -1886,11 +1887,13 @@ + in the form of a comparison of a register against zero. + If the condition is more complex than that, then it is safe + not to record any information. */ +- if (GET_CODE (reg) == REG ++ inv_cond = reversed_comparison_code (cond_true, BB_END (bb)); ++ if (inv_cond != UNKNOWN ++ && GET_CODE (reg) == REG + && XEXP (cond_true, 1) == const0_rtx) + { + rtx cond_false +- = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)), ++ = gen_rtx_fmt_ee (inv_cond, + GET_MODE (cond_true), XEXP (cond_true, 0), + XEXP (cond_true, 1)); + if (GET_CODE (XEXP (set_src, 1)) == PC) diff --git a/misc/buildroot/toolchain/gcc/3.4.5/71_all_sh-pr16665-fix.patch b/misc/buildroot/toolchain/gcc/3.4.5/71_all_sh-pr16665-fix.patch new file mode 100644 index 000000000..680bb3978 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/71_all_sh-pr16665-fix.patch @@ -0,0 +1,43 @@ +--- gcc/gcc/config/sh/sh.c ++++ gcc/gcc/config/sh/sh.c +@@ -9106,6 +9106,15 @@ sh_output_mi_thunk (FILE *file, tree thu + } + this = FUNCTION_ARG (cum, Pmode, ptr_type_node, 1); + ++ /* In PIC case, we set PIC register to compute the target address. We ++ can use a scratch register to save and restore the original value ++ except for SHcompact. For SHcompact, use stack. */ ++ if (flag_pic && TARGET_SHCOMPACT) ++ { ++ push (PIC_OFFSET_TABLE_REGNUM); ++ emit_insn (gen_GOTaddr2picreg ()); ++ } ++ + /* For SHcompact, we only have r0 for a scratch register: r1 is the + static chain pointer (even if you can't have nested virtual functions + right now, someone might implement them sometime), and the rest of the +@@ -9188,8 +9197,24 @@ sh_output_mi_thunk (FILE *file, tree thu + assemble_external (function); + TREE_USED (function) = 1; + } ++ /* We can use scratch1 to save and restore the original value of ++ PIC register except for SHcompact. */ ++ if (flag_pic && ! TARGET_SHCOMPACT) ++ { ++ emit_move_insn (scratch1, ++ gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)); ++ emit_insn (gen_GOTaddr2picreg ()); ++ } + funexp = XEXP (DECL_RTL (function), 0); + emit_move_insn (scratch2, funexp); ++ if (flag_pic) ++ { ++ if (! TARGET_SHCOMPACT) ++ emit_move_insn (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM), ++ scratch1); ++ else ++ pop (PIC_OFFSET_TABLE_REGNUM); ++ } + funexp = gen_rtx_MEM (FUNCTION_MODE, scratch2); + sibcall = emit_call_insn (gen_sibcall (funexp, const0_rtx, NULL_RTX)); + SIBLING_CALL_P (sibcall) = 1; diff --git a/misc/buildroot/toolchain/gcc/3.4.5/72_all_sh-no-reorder-blocks.patch b/misc/buildroot/toolchain/gcc/3.4.5/72_all_sh-no-reorder-blocks.patch new file mode 100644 index 000000000..8b9826831 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/72_all_sh-no-reorder-blocks.patch @@ -0,0 +1,13 @@ +--- g/gcc/config/sh/sh.h ++++ g/gcc/config/sh/sh.h +@@ -422,6 +422,10 @@ + do { \ + if (LEVEL) \ + flag_omit_frame_pointer = -1; \ ++ if (LEVEL <= 2) \ ++ { \ ++ flag_reorder_blocks = 0; \ ++ } \ + if (SIZE) \ + target_flags |= SPACE_BIT; \ + if (TARGET_SHMEDIA && LEVEL > 1) \ diff --git a/misc/buildroot/toolchain/gcc/3.4.5/73_all_sh-pr20617.patch b/misc/buildroot/toolchain/gcc/3.4.5/73_all_sh-pr20617.patch new file mode 100644 index 000000000..6d8021cc7 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/73_all_sh-pr20617.patch @@ -0,0 +1,28 @@ +2005-03-24 J"orn Rennecke + + Band aid for PR target/20617: + * config/sh/lib1funcs.asm (FUNC, ALIAS): Add .hidden directive. + +--- g/gcc/config/sh/lib1funcs.asm ++++ g/gcc/config/sh/lib1funcs.asm +@@ -37,9 +37,19 @@ Boston, MA 02111-1307, USA. */ + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + ++#define ALIAS(X,Y) .global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y) ++ + #ifdef __ELF__ + #define LOCAL(X) .L_##X +-#define FUNC(X) .type X,@function ++ ++#if 1 /* ??? The export list mechanism is broken, everything that is not ++ hidden is exported. */ ++#undef FUNC ++#define FUNC(X) .type X,@function; .hidden X ++#undef ALIAS ++#define ALIAS(X,Y) .global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y); .hidden GLOBAL(X) ++#endif ++ + #define ENDFUNC0(X) .Lfe_##X: .size X,.Lfe_##X-X + #define ENDFUNC(X) ENDFUNC0(X) + #else diff --git a/misc/buildroot/toolchain/gcc/3.4.5/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/3.4.5/800-arm-bigendian.patch new file mode 100644 index 000000000..04e998419 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/800-arm-bigendian.patch @@ -0,0 +1,68 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-3.4.1-dist/gcc/config/arm/linux-elf.h ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h +@@ -30,17 +30,34 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + /* Default is to use APCS-32 mode. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 | \ ++ ARM_FLAG_MMU_TRAPS | \ ++ TARGET_ENDIAN_DEFAULT ) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -101,7 +118,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + #endif + +--- gcc-3.4.1-dist/gcc/config.gcc ++++ gcc-3.4.1/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="t-slibgcc-elf-ver t-linux arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/3.4.5/900-nios2.patch b/misc/buildroot/toolchain/gcc/3.4.5/900-nios2.patch new file mode 100644 index 000000000..bfa06a21c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/900-nios2.patch @@ -0,0 +1,10211 @@ +--- gcc-3.4.3/gcc/Makefile.in ++++ gcc-3.4.3-nios2/gcc/Makefile.in +@@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_ + $(INSTALL_DATA) $(srcdir)/README-fixinc \ + $(DESTDIR)$(itoolsdatadir)/include/README ; \ + $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \ +- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \ ++ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \ + $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ + $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \ + else :; fi +--- gcc-3.4.3/gcc/combine.c ++++ gcc-3.4.3-nios2/gcc/combine.c +@@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin + mode); + } + ++#ifndef __nios2__ ++/* This screws up Nios II in this test case: ++ ++if (x & 1) ++ return 2; ++else ++ return 3; ++*/ + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx +@@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin + gen_lowpart_for_combine (mode, op0), + const1_rtx); + } ++#endif + + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT +--- gcc-3.4.3/gcc/config/nios2/crti.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm +@@ -0,0 +1,88 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just make a stack frame for the contents of the .fini and ++.init sections. Users may put any desired instructions in those ++sections. ++ ++ ++While technically any code can be put in the init and fini sections ++most stuff will not work other than stuff which obeys the call frame ++and ABI. All the call-preserved registers are saved, the call clobbered ++registers should have been saved by the code calling init and fini. ++ ++See crtstuff.c for an example of code that inserts itself in the ++init and fini sections. ++ ++See crt0.s for the code that calls init and fini. ++*/ ++ ++ .file "crti.asm" ++ ++ .section ".init" ++ .align 2 ++ .global _init ++_init: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ ++ .section ".fini" ++ .align 2 ++ .global _fini ++_fini: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ +--- gcc-3.4.3/gcc/config/nios2/crtn.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm +@@ -0,0 +1,70 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just makes sure that the .fini and .init sections do in ++fact return. Users may put any desired instructions in those sections. ++This file is the last thing linked into any executable. ++*/ ++ .file "crtn.asm" ++ ++ ++ ++ .section ".init" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ ++ .section ".fini" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c +@@ -0,0 +1,123 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern HItype __modhi3 (HItype, HItype); ++extern HItype __divhi3 (HItype, HItype); ++extern HItype __umodhi3 (HItype, HItype); ++extern HItype __udivhi3 (HItype, HItype); ++ ++static UHItype udivmodhi4(UHItype, UHItype, word_type); ++ ++static UHItype ++udivmodhi4(UHItype num, UHItype den, word_type modwanted) ++{ ++ UHItype bit = 1; ++ UHItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<15))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++HItype ++__divhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodhi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__modhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodhi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__udivhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 0); ++} ++ ++ ++HItype ++__umodhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c +@@ -0,0 +1,126 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern SItype __modsi3 (SItype, SItype); ++extern SItype __divsi3 (SItype, SItype); ++extern SItype __umodsi3 (SItype, SItype); ++extern SItype __udivsi3 (SItype, SItype); ++ ++static USItype udivmodsi4(USItype, USItype, word_type); ++ ++/* 16-bit SI divide and modulo as used in NIOS */ ++ ++ ++static USItype ++udivmodsi4(USItype num, USItype den, word_type modwanted) ++{ ++ USItype bit = 1; ++ USItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<31))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__modsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__udivsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 0); ++} ++ ++ ++SItype ++__umodsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c +@@ -0,0 +1,46 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++UQItype __divsi3_table[] = ++{ ++ 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15, ++ 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15, ++ 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15, ++ 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15, ++ 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15, ++ 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15, ++ 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15, ++ 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15, ++ 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15, ++ 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15, ++ 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15, ++ 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15, ++ 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15, ++ 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15, ++ 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15, ++ 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15, ++}; ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-mul.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c +@@ -0,0 +1,103 @@ ++/* while we are debugging (ie compile outside of gcc build) ++ disable gcc specific headers */ ++#ifndef DEBUG_MULSI3 ++ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++#else ++#define SItype int ++#define USItype unsigned int ++#endif ++ ++ ++extern SItype __mulsi3 (SItype, SItype); ++ ++SItype ++__mulsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = a; ++ ++ while (cnt) ++ { ++ if (cnt & 1) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt >>= 1; ++ } ++ ++ return res; ++} ++/* ++TODO: Choose best alternative implementation. ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = 0; ++ ++ while (cnt < 32) ++ { ++ if (a & (1L << cnt)) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt++; ++ } ++ ++ return res; ++} ++*/ ++ ++ ++#ifdef DEBUG_MULSI3 ++ ++int ++main () ++{ ++ int i, j; ++ int error = 0; ++ ++ for (i = -1000; i < 1000; i++) ++ for (j = -1000; j < 1000; j++) ++ { ++ int expect = i * j; ++ int actual = A__divsi3 (i, j); ++ if (expect != actual) ++ { ++ printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++#endif +--- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c +@@ -0,0 +1,1652 @@ ++ ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c +@@ -0,0 +1,1652 @@ ++#define FLOAT ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-protos.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h +@@ -0,0 +1,70 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++extern void dump_frame_size (FILE *); ++extern HOST_WIDE_INT compute_frame_size (void); ++extern int nios2_initial_elimination_offset (int, int); ++extern void override_options (void); ++extern void optimization_options (int, int); ++extern int nios2_can_use_return_insn (void); ++extern void expand_prologue (void); ++extern void expand_epilogue (bool); ++extern void function_profiler (FILE *, int); ++ ++ ++#ifdef RTX_CODE ++extern int nios2_legitimate_address (rtx, enum machine_mode, int); ++extern void nios2_print_operand (FILE *, rtx, int); ++extern void nios2_print_operand_address (FILE *, rtx); ++ ++extern int nios2_emit_move_sequence (rtx *, enum machine_mode); ++extern int nios2_emit_expensive_div (rtx *, enum machine_mode); ++ ++extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); ++extern void gen_conditional_move (rtx *, enum machine_mode); ++extern const char *asm_output_opcode (FILE *, const char *); ++ ++/* predicates */ ++extern int arith_operand (rtx, enum machine_mode); ++extern int uns_arith_operand (rtx, enum machine_mode); ++extern int logical_operand (rtx, enum machine_mode); ++extern int shift_operand (rtx, enum machine_mode); ++extern int reg_or_0_operand (rtx, enum machine_mode); ++extern int equality_op (rtx, enum machine_mode); ++extern int custom_insn_opcode (rtx, enum machine_mode); ++extern int rdwrctl_operand (rtx, enum machine_mode); ++ ++# ifdef HAVE_MACHINE_MODES ++# if defined TREE_CODE ++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); ++extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++ ++# endif /* TREE_CODE */ ++# endif /* HAVE_MACHINE_MODES */ ++#endif ++ ++#ifdef TREE_CODE ++extern int nios2_return_in_memory (tree); ++ ++#endif /* TREE_CODE */ +--- gcc-3.4.3/gcc/config/nios2/nios2.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c +@@ -0,0 +1,2853 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++#include ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "rtl.h" ++#include "tree.h" ++#include "tm_p.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "recog.h" ++#include "expr.h" ++#include "toplev.h" ++#include "basic-block.h" ++#include "function.h" ++#include "ggc.h" ++#include "reload.h" ++#include "debug.h" ++#include "optabs.h" ++#include "target.h" ++#include "target-def.h" ++ ++/* local prototypes */ ++static bool nios2_rtx_costs (rtx, int, int, int *); ++ ++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); ++static int nios2_use_dfa_pipeline_interface (void); ++static int nios2_issue_rate (void); ++static struct machine_function *nios2_init_machine_status (void); ++static bool nios2_in_small_data_p (tree); ++static rtx save_reg (int, HOST_WIDE_INT, rtx); ++static rtx restore_reg (int, HOST_WIDE_INT); ++static unsigned int nios2_section_type_flags (tree, const char *, int); ++static void nios2_init_builtins (void); ++static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); ++static bool nios2_function_ok_for_sibcall (tree, tree); ++static void nios2_encode_section_info (tree, rtx, int); ++ ++/* Initialize the GCC target structure. */ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue ++ ++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE ++#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ ++ nios2_use_dfa_pipeline_interface ++#undef TARGET_SCHED_ISSUE_RATE ++#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate ++#undef TARGET_IN_SMALL_DATA_P ++#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p ++#undef TARGET_ENCODE_SECTION_INFO ++#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info ++#undef TARGET_SECTION_TYPE_FLAGS ++#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS nios2_init_builtins ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN nios2_expand_builtin ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS nios2_rtx_costs ++ ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++ ++ ++/* Threshold for data being put into the small data/bss area, instead ++ of the normal data area (references to the small data/bss area take ++ 1 instruction, and use the global pointer, references to the normal ++ data area takes 2 instructions). */ ++unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; ++ ++ ++/* Structure to be filled in by compute_frame_size with register ++ save masks, and offsets for the current function. */ ++ ++struct nios2_frame_info ++GTY (()) ++{ ++ long total_size; /* # bytes that the entire frame takes up */ ++ long var_size; /* # bytes that variables take up */ ++ long args_size; /* # bytes that outgoing arguments take up */ ++ int save_reg_size; /* # bytes needed to store gp regs */ ++ int save_reg_rounded; /* # bytes needed to store gp regs */ ++ long save_regs_offset; /* offset from new sp to store gp registers */ ++ int initialized; /* != 0 if frame size already calculated */ ++ int num_regs; /* number of gp registers saved */ ++}; ++ ++struct machine_function ++GTY (()) ++{ ++ ++ /* Current frame information, calculated by compute_frame_size. */ ++ struct nios2_frame_info frame; ++}; ++ ++ ++/*************************************** ++ * Section encodings ++ ***************************************/ ++ ++ ++ ++ ++ ++/*************************************** ++ * Stack Layout and Calling Conventions ++ ***************************************/ ++ ++ ++#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) ++#define TEMP_REG_NUM 8 ++ ++static void ++nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ++{ ++ if (flag_verbose_asm || flag_debug_asm) ++ { ++ compute_frame_size (); ++ dump_frame_size (file); ++ } ++} ++ ++static rtx ++save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg) ++{ ++ rtx insn, stack_slot; ++ ++ stack_slot = gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ GEN_INT (offset)); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_MEM (SImode, stack_slot), ++ gen_rtx_REG (SImode, regno))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ return insn; ++} ++ ++static rtx ++restore_reg (int regno, HOST_WIDE_INT offset) ++{ ++ rtx insn, stack_slot; ++ ++ if (TOO_BIG_OFFSET (offset)) ++ { ++ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ GEN_INT (offset))); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ gen_rtx_PLUS (SImode, ++ stack_slot, ++ stack_pointer_rtx))); ++ } ++ else ++ { ++ stack_slot = gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (offset)); ++ } ++ ++ stack_slot = gen_rtx_MEM (SImode, stack_slot); ++ ++ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot); ++ ++ return insn; ++} ++ ++ ++/* There are two possible paths for prologue expansion, ++- the first is if the total frame size is < 2^15-1. In that ++case all the immediates will fit into the 16-bit immediate ++fields. ++- the second is when the frame size is too big, in that ++case an additional temporary register is used, first ++as a cfa_temp to offset the sp, second as the cfa_store ++register. ++ ++See the comment above dwarf2out_frame_debug_expr in ++dwarf2out.c for more explanation of the "rules." ++ ++ ++Case 1: ++Rule # Example Insn Effect ++2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++12 stw ra, offset(sp) ++12 stw r16, offset(sp) ++1 mov fp, sp ++ ++Case 2: ++Rule # Example Insn Effect ++6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size ++2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0 ++12 stw ra, offset(r8) ++12 stw r16, offset(r8) ++1 mov fp, sp ++ ++*/ ++ ++void ++expand_prologue () ++{ ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int cfa_store_offset; ++ rtx insn; ++ rtx cfa_store_reg = 0; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (total_frame_size) ++ { ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ /* cfa_temp and cfa_store_reg are the same register, ++ cfa_store_reg overwrites cfa_temp */ ++ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ cfa_store_reg, ++ GEN_INT (total_frame_size))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_MINUS (SImode, ++ stack_pointer_rtx, ++ cfa_store_reg)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ /* if there are no registers to save, I don't need to ++ create a cfa_store */ ++ if (cfun->machine->frame.save_reg_size) ++ { ++ insn = gen_rtx_SET (SImode, ++ cfa_store_reg, ++ gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ stack_pointer_rtx)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ cfa_store_offset ++ = total_frame_size ++ - (cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded); ++ } ++ else ++ { ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (-total_frame_size))); ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ cfa_store_reg = stack_pointer_rtx; ++ cfa_store_offset ++ = cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded; ++ } ++ } ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ cfa_store_offset -= 4; ++ save_reg (i, cfa_store_offset, cfa_store_reg); ++ } ++ } ++ ++ if (frame_pointer_needed) ++ { ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_REG (SImode, FP_REGNO), ++ gen_rtx_REG (SImode, SP_REGNO))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ /* If we are profiling, make sure no instructions are scheduled before ++ the call to mcount. */ ++ if (current_function_profile) ++ emit_insn (gen_blockage ()); ++} ++ ++void ++expand_epilogue (bool sibcall_p) ++{ ++ rtx insn; ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int register_store_offset; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (!sibcall_p && nios2_can_use_return_insn ()) ++ { ++ insn = emit_jump_insn (gen_return ()); ++ return; ++ } ++ ++ emit_insn (gen_blockage ()); ++ ++ register_store_offset = ++ cfun->machine->frame.save_regs_offset + ++ cfun->machine->frame.save_reg_rounded; ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (RA_REGNO, register_store_offset); ++ } ++ ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (FP_REGNO, register_store_offset); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ register_store_offset -= 4; ++ restore_reg (i, register_store_offset); ++ } ++ } ++ ++ if (total_frame_size) ++ { ++ rtx sp_adjust; ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ sp_adjust, ++ GEN_INT (total_frame_size))); ++ ++ } ++ else ++ { ++ sp_adjust = GEN_INT (total_frame_size); ++ } ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ sp_adjust)); ++ insn = emit_insn (insn); ++ } ++ ++ ++ if (!sibcall_p) ++ { ++ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode, ++ RA_REGNO))); ++ } ++} ++ ++ ++bool ++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) ++{ ++ return true; ++} ++ ++ ++ ++ ++ ++/* ----------------------- * ++ * Profiling ++ * ----------------------- */ ++ ++void ++function_profiler (FILE *file, int labelno) ++{ ++ fprintf (file, "\t%s mcount begin, label: .LP%d\n", ++ ASM_COMMENT_START, labelno); ++ fprintf (file, "\tnextpc\tr8\n"); ++ fprintf (file, "\tmov\tr9, ra\n"); ++ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno); ++ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno); ++ fprintf (file, "\tcall\tmcount\n"); ++ fprintf (file, "\tmov\tra, r9\n"); ++ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START); ++} ++ ++ ++/*************************************** ++ * Stack Layout ++ ***************************************/ ++ ++ ++void ++dump_frame_size (FILE *file) ++{ ++ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); ++ ++ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.total_size); ++ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.var_size); ++ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.args_size); ++ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_size); ++ fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_rounded); ++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.initialized); ++ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.num_regs); ++ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_regs_offset); ++ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, ++ current_function_is_leaf); ++ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, ++ frame_pointer_needed); ++ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, ++ current_function_pretend_args_size); ++ ++} ++ ++ ++/* Return the bytes needed to compute the frame pointer from the current ++ stack pointer. ++*/ ++ ++HOST_WIDE_INT ++compute_frame_size () ++{ ++ unsigned int regno; ++ HOST_WIDE_INT var_size; /* # of var. bytes allocated */ ++ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */ ++ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */ ++ HOST_WIDE_INT save_reg_rounded; ++ /* # bytes needed to store callee save regs (rounded) */ ++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */ ++ ++ save_reg_size = 0; ++ var_size = STACK_ALIGN (get_frame_size ()); ++ out_args_size = STACK_ALIGN (current_function_outgoing_args_size); ++ ++ total_size = var_size + out_args_size; ++ ++ /* Calculate space needed for gp registers. */ ++ for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++) ++ { ++ if (MUST_SAVE_REGISTER (regno)) ++ { ++ save_reg_size += 4; ++ } ++ } ++ ++ save_reg_rounded = STACK_ALIGN (save_reg_size); ++ total_size += save_reg_rounded; ++ ++ total_size += STACK_ALIGN (current_function_pretend_args_size); ++ ++ /* Save other computed information. */ ++ cfun->machine->frame.total_size = total_size; ++ cfun->machine->frame.var_size = var_size; ++ cfun->machine->frame.args_size = current_function_outgoing_args_size; ++ cfun->machine->frame.save_reg_size = save_reg_size; ++ cfun->machine->frame.save_reg_rounded = save_reg_rounded; ++ cfun->machine->frame.initialized = reload_completed; ++ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD; ++ ++ cfun->machine->frame.save_regs_offset ++ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0; ++ ++ return total_size; ++} ++ ++ ++int ++nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) ++{ ++ int offset; ++ ++ /* Set OFFSET to the offset from the stack pointer. */ ++ switch (from) ++ { ++ case FRAME_POINTER_REGNUM: ++ offset = 0; ++ break; ++ ++ case ARG_POINTER_REGNUM: ++ compute_frame_size (); ++ offset = cfun->machine->frame.total_size; ++ offset -= current_function_pretend_args_size; ++ break; ++ ++ case RETURN_ADDRESS_POINTER_REGNUM: ++ compute_frame_size (); ++ /* since the return address is always the first of the ++ saved registers, return the offset to the beginning ++ of the saved registers block */ ++ offset = cfun->machine->frame.save_regs_offset; ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ return offset; ++} ++ ++/* Return nonzero if this function is known to have a null epilogue. ++ This allows the optimizer to omit jumps to jumps if no stack ++ was created. */ ++int ++nios2_can_use_return_insn () ++{ ++ if (!reload_completed) ++ return 0; ++ ++ if (regs_ever_live[RA_REGNO] || current_function_profile) ++ return 0; ++ ++ if (cfun->machine->frame.initialized) ++ return cfun->machine->frame.total_size == 0; ++ ++ return compute_frame_size () == 0; ++} ++ ++ ++ ++ ++ ++/*************************************** ++ * ++ ***************************************/ ++ ++const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++const char *nios2_sys_lib_string; /* for -msys-lib= */ ++const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++void ++override_options () ++{ ++ /* Function to allocate machine-dependent function status. */ ++ init_machine_status = &nios2_init_machine_status; ++ ++ nios2_section_threshold ++ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; ++ ++ if (nios2_sys_nosys_string && *nios2_sys_nosys_string) ++ { ++ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string); ++ } ++ ++ /* If we don't have mul, we don't have mulx either! */ ++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX) ++ { ++ target_flags &= ~HAS_MULX_FLAG; ++ } ++ ++} ++ ++void ++optimization_options (int level, int size) ++{ ++ if (level || size) ++ { ++ target_flags |= INLINE_MEMCPY_FLAG; ++ } ++ ++ if (level >= 3 && !size) ++ { ++ target_flags |= FAST_SW_DIV_FLAG; ++ } ++} ++ ++/* Allocate a chunk of memory for per-function machine-dependent data. */ ++static struct machine_function * ++nios2_init_machine_status () ++{ ++ return ((struct machine_function *) ++ ggc_alloc_cleared (sizeof (struct machine_function))); ++} ++ ++ ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++/* Compute a (partial) cost for rtx X. Return true if the complete ++ cost has been computed, and false if subexpressions should be ++ scanned. In either case, *TOTAL contains the cost result. */ ++ ++ ++ ++static bool ++nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) ++{ ++ switch (code) ++ { ++ case CONST_INT: ++ if (INTVAL (x) == 0) ++ { ++ *total = COSTS_N_INSNS (0); ++ return true; ++ } ++ else if (SMALL_INT (INTVAL (x)) ++ || SMALL_INT_UNSIGNED (INTVAL (x)) ++ || UPPER16_INT (INTVAL (x))) ++ { ++ *total = COSTS_N_INSNS (2); ++ return true; ++ } ++ else ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case LABEL_REF: ++ case SYMBOL_REF: ++ /* ??? gp relative stuff will fit in here */ ++ /* fall through */ ++ case CONST: ++ case CONST_DOUBLE: ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case MULT: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ case SIGN_EXTEND: ++ { ++ *total = COSTS_N_INSNS (3); ++ return false; ++ } ++ case ZERO_EXTEND: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ ++ default: ++ return false; ++ } ++} ++ ++ ++/*************************************** ++ * INSTRUCTION SUPPORT ++ * ++ * These functions are used within the Machine Description to ++ * handle common or complicated output and expansions from ++ * instructions. ++ ***************************************/ ++ ++int ++nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) ++{ ++ rtx to = operands[0]; ++ rtx from = operands[1]; ++ ++ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) ++ { ++ if (no_new_pseudos) ++ internal_error ("Trying to force_reg no_new_pseudos == 1"); ++ from = copy_to_mode_reg (mode, from); ++ } ++ ++ operands[0] = to; ++ operands[1] = from; ++ return 0; ++} ++ ++/* Divide Support */ ++ ++/* ++ If -O3 is used, we want to output a table lookup for ++ divides between small numbers (both num and den >= 0 ++ and < 0x10). The overhead of this method in the worse ++ case is 40 bytes in the text section (10 insns) and ++ 256 bytes in the data section. Additional divides do ++ not incur additional penalties in the data section. ++ ++ Code speed is improved for small divides by about 5x ++ when using this method in the worse case (~9 cycles ++ vs ~45). And in the worse case divides not within the ++ table are penalized by about 10% (~5 cycles vs ~45). ++ However in the typical case the penalty is not as bad ++ because doing the long divide in only 45 cycles is ++ quite optimistic. ++ ++ ??? It would be nice to have some benchmarks other ++ than Dhrystone to back this up. ++ ++ This bit of expansion is to create this instruction ++ sequence as rtl. ++ or $8, $4, $5 ++ slli $9, $4, 4 ++ cmpgeui $3, $8, 16 ++ beq $3, $0, .L3 ++ or $10, $9, $5 ++ add $12, $11, divide_table ++ ldbu $2, 0($12) ++ br .L1 ++.L3: ++ call slow_div ++.L1: ++# continue here with result in $2 ++ ++ ??? Ideally I would like the emit libcall block to contain ++ all of this code, but I don't know how to do that. What it ++ means is that if the divide can be eliminated, it may not ++ completely disappear. ++ ++ ??? The __divsi3_table label should ideally be moved out ++ of this block and into a global. If it is placed into the ++ sdata section we can save even more cycles by doing things ++ gp relative. ++*/ ++int ++nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) ++{ ++ rtx or_result, shift_left_result; ++ rtx lookup_value; ++ rtx lab1, lab3; ++ rtx insns; ++ rtx libfunc; ++ rtx final_result; ++ rtx tmp; ++ ++ /* it may look a little generic, but only SImode ++ is supported for now */ ++ if (mode != SImode) ++ abort (); ++ ++ libfunc = sdiv_optab->handlers[(int) SImode].libfunc; ++ ++ ++ ++ lab1 = gen_label_rtx (); ++ lab3 = gen_label_rtx (); ++ ++ or_result = expand_simple_binop (SImode, IOR, ++ operands[1], operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, ++ GET_MODE (or_result), 0, lab3); ++ JUMP_LABEL (get_last_insn ()) = lab3; ++ ++ shift_left_result = expand_simple_binop (SImode, ASHIFT, ++ operands[1], GEN_INT (4), ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ lookup_value = expand_simple_binop (SImode, IOR, ++ shift_left_result, operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ convert_move (operands[0], ++ gen_rtx (MEM, QImode, ++ gen_rtx (PLUS, SImode, ++ lookup_value, ++ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), ++ 1); ++ ++ ++ tmp = emit_jump_insn (gen_jump (lab1)); ++ JUMP_LABEL (tmp) = lab1; ++ emit_barrier (); ++ ++ emit_label (lab3); ++ LABEL_NUSES (lab3) = 1; ++ ++ start_sequence (); ++ final_result = emit_library_call_value (libfunc, NULL_RTX, ++ LCT_CONST, SImode, 2, ++ operands[1], SImode, ++ operands[2], SImode); ++ ++ ++ insns = get_insns (); ++ end_sequence (); ++ emit_libcall_block (insns, operands[0], final_result, ++ gen_rtx (DIV, SImode, operands[1], operands[2])); ++ ++ emit_label (lab1); ++ LABEL_NUSES (lab1) = 1; ++ return 1; ++} ++ ++/* Branches/Compares */ ++ ++/* the way of handling branches/compares ++ in gcc is heavily borrowed from MIPS */ ++ ++enum internal_test ++{ ++ ITEST_EQ, ++ ITEST_NE, ++ ITEST_GT, ++ ITEST_GE, ++ ITEST_LT, ++ ITEST_LE, ++ ITEST_GTU, ++ ITEST_GEU, ++ ITEST_LTU, ++ ITEST_LEU, ++ ITEST_MAX ++}; ++ ++static enum internal_test map_test_to_internal_test (enum rtx_code); ++ ++/* Cached operands, and operator to compare for use in set/branch/trap ++ on condition codes. */ ++rtx branch_cmp[2]; ++enum cmp_type branch_type; ++ ++/* Make normal rtx_code into something we can index from an array */ ++ ++static enum internal_test ++map_test_to_internal_test (enum rtx_code test_code) ++{ ++ enum internal_test test = ITEST_MAX; ++ ++ switch (test_code) ++ { ++ case EQ: ++ test = ITEST_EQ; ++ break; ++ case NE: ++ test = ITEST_NE; ++ break; ++ case GT: ++ test = ITEST_GT; ++ break; ++ case GE: ++ test = ITEST_GE; ++ break; ++ case LT: ++ test = ITEST_LT; ++ break; ++ case LE: ++ test = ITEST_LE; ++ break; ++ case GTU: ++ test = ITEST_GTU; ++ break; ++ case GEU: ++ test = ITEST_GEU; ++ break; ++ case LTU: ++ test = ITEST_LTU; ++ break; ++ case LEU: ++ test = ITEST_LEU; ++ break; ++ default: ++ break; ++ } ++ ++ return test; ++} ++ ++/* Generate the code to compare (and possibly branch) two integer values ++ TEST_CODE is the comparison code we are trying to emulate ++ (or implement directly) ++ RESULT is where to store the result of the comparison, ++ or null to emit a branch ++ CMP0 CMP1 are the two comparison operands ++ DESTINATION is the destination of the branch, or null to only compare ++ */ ++ ++void ++gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */ ++ rtx result, /* result to store comp. or 0 if branch */ ++ rtx cmp0, /* first operand to compare */ ++ rtx cmp1, /* second operand to compare */ ++ rtx destination) /* destination of the branch, or 0 if compare */ ++{ ++ struct cmp_info ++ { ++ /* for register (or 0) compares */ ++ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */ ++ int reverse_regs; /* reverse registers in test */ ++ ++ /* for immediate compares */ ++ enum rtx_code test_code_const; ++ /* code to use in instruction (LT vs. LTU) */ ++ int const_low; /* low bound of constant we can accept */ ++ int const_high; /* high bound of constant we can accept */ ++ int const_add; /* constant to add */ ++ ++ /* generic info */ ++ int unsignedp; /* != 0 for unsigned comparisons. */ ++ }; ++ ++ static const struct cmp_info info[(int) ITEST_MAX] = { ++ ++ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ ++ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ ++ ++ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ ++ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ ++ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ ++ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ ++ ++ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ ++ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ ++ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ ++ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ ++ }; ++ ++ enum internal_test test; ++ enum machine_mode mode; ++ const struct cmp_info *p_info; ++ int branch_p; ++ ++ ++ ++ ++ test = map_test_to_internal_test (test_code); ++ if (test == ITEST_MAX) ++ abort (); ++ ++ p_info = &info[(int) test]; ++ ++ mode = GET_MODE (cmp0); ++ if (mode == VOIDmode) ++ mode = GET_MODE (cmp1); ++ ++ branch_p = (destination != 0); ++ ++ /* We can't, under any circumstances, have const_ints in cmp0 ++ ??? Actually we could have const0 */ ++ if (GET_CODE (cmp0) == CONST_INT) ++ cmp0 = force_reg (mode, cmp0); ++ ++ /* if the comparison is against an int not in legal range ++ move it into a register */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ HOST_WIDE_INT value = INTVAL (cmp1); ++ ++ if (value < p_info->const_low || value > p_info->const_high) ++ cmp1 = force_reg (mode, cmp1); ++ } ++ ++ /* Comparison to constants, may involve adding 1 to change a GT into GE. ++ Comparison between two registers, may involve switching operands. */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ if (p_info->const_add != 0) ++ { ++ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; ++ ++ /* If modification of cmp1 caused overflow, ++ we would get the wrong answer if we follow the usual path; ++ thus, x > 0xffffffffU would turn into x > 0U. */ ++ if ((p_info->unsignedp ++ ? (unsigned HOST_WIDE_INT) new > ++ (unsigned HOST_WIDE_INT) INTVAL (cmp1) ++ : new > INTVAL (cmp1)) != (p_info->const_add > 0)) ++ { ++ /* ??? This case can never happen with the current numbers, ++ but I am paranoid and would rather an abort than ++ a bug I will never find */ ++ abort (); ++ } ++ else ++ cmp1 = GEN_INT (new); ++ } ++ } ++ ++ else if (p_info->reverse_regs) ++ { ++ rtx temp = cmp0; ++ cmp0 = cmp1; ++ cmp1 = temp; ++ } ++ ++ ++ ++ if (branch_p) ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ rtx insn; ++ rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1); ++ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ insn = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, label, pc_rtx)); ++ emit_jump_insn (insn); ++ } ++ else ++ { ++ rtx cond, label; ++ ++ result = gen_reg_rtx (mode); ++ ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ ++ cond = gen_rtx (NE, mode, result, const0_rtx); ++ label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, ++ label, pc_rtx))); ++ } ++ } ++ else ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1)); ++ } ++ else ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ } ++ } ++ ++} ++ ++ ++/* ??? For now conditional moves are only supported ++ when the mode of the operands being compared are ++ the same as the ones being moved */ ++ ++void ++gen_conditional_move (rtx *operands, enum machine_mode mode) ++{ ++ rtx insn, cond; ++ rtx cmp_reg = gen_reg_rtx (mode); ++ enum rtx_code cmp_code = GET_CODE (operands[1]); ++ enum rtx_code move_code = EQ; ++ ++ /* emit a comparison if it is not "simple". ++ Simple comparisons are X eq 0 and X ne 0 */ ++ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[0]; ++ move_code = cmp_code; ++ } ++ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[1]; ++ move_code = cmp_code == EQ ? NE : EQ; ++ } ++ else ++ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], ++ NULL_RTX); ++ ++ cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); ++ insn = gen_rtx_SET (mode, operands[0], ++ gen_rtx_IF_THEN_ELSE (mode, ++ cond, operands[2], operands[3])); ++ emit_insn (insn); ++} ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++int ++nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int strict) ++{ ++ int ret_val = 0; ++ ++ switch (GET_CODE (operand)) ++ { ++ /* direct. */ ++ case SYMBOL_REF: ++ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) ++ { ++ ret_val = 1; ++ break; ++ } ++ /* else, fall through */ ++ case LABEL_REF: ++ case CONST_INT: ++ case CONST: ++ case CONST_DOUBLE: ++ /* ??? In here I need to add gp addressing */ ++ ret_val = 0; ++ ++ break; ++ ++ /* Register indirect. */ ++ case REG: ++ ret_val = REG_OK_FOR_BASE_P2 (operand, strict); ++ break; ++ ++ /* Register indirect with displacement */ ++ case PLUS: ++ { ++ rtx op0 = XEXP (operand, 0); ++ rtx op1 = XEXP (operand, 1); ++ ++ if (REG_P (op0) && REG_P (op1)) ++ ret_val = 0; ++ else if (REG_P (op0) && CONSTANT_P (op1)) ++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict) ++ && SMALL_INT (INTVAL (op1)); ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ ret_val = REG_OK_FOR_BASE_P2 (op1, strict) ++ && SMALL_INT (INTVAL (op0)); ++ else ++ ret_val = 0; ++ } ++ break; ++ ++ default: ++ ret_val = 0; ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/* Return true if EXP should be placed in the small data section. */ ++ ++static bool ++nios2_in_small_data_p (tree exp) ++{ ++ /* We want to merge strings, so we never consider them small data. */ ++ if (TREE_CODE (exp) == STRING_CST) ++ return false; ++ ++ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) ++ { ++ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); ++ /* ??? these string names need moving into ++ an array in some header file */ ++ if (nios2_section_threshold > 0 ++ && (strcmp (section, ".sbss") == 0 ++ || strncmp (section, ".sbss.", 6) == 0 ++ || strcmp (section, ".sdata") == 0 ++ || strncmp (section, ".sdata.", 7) == 0)) ++ return true; ++ } ++ else if (TREE_CODE (exp) == VAR_DECL) ++ { ++ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); ++ ++ /* If this is an incomplete type with size 0, then we can't put it ++ in sdata because it might be too big when completed. */ ++ if (size > 0 && size <= nios2_section_threshold) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ++nios2_encode_section_info (tree decl, rtx rtl, int first) ++{ ++ ++ rtx symbol; ++ int flags; ++ ++ default_encode_section_info (decl, rtl, first); ++ ++ /* Careful not to prod global register variables. */ ++ if (GET_CODE (rtl) != MEM) ++ return; ++ symbol = XEXP (rtl, 0); ++ if (GET_CODE (symbol) != SYMBOL_REF) ++ return; ++ ++ flags = SYMBOL_REF_FLAGS (symbol); ++ ++ /* We don't want weak variables to be addressed with gp in case they end up with ++ value 0 which is not within 2^15 of $gp */ ++ if (DECL_P (decl) && DECL_WEAK (decl)) ++ flags |= SYMBOL_FLAG_WEAK_DECL; ++ ++ SYMBOL_REF_FLAGS (symbol) = flags; ++} ++ ++ ++static unsigned int ++nios2_section_type_flags (tree decl, const char *name, int reloc) ++{ ++ unsigned int flags; ++ ++ flags = default_section_type_flags (decl, name, reloc); ++ ++ /* ??? these string names need moving into an array in some header file */ ++ if (strcmp (name, ".sbss") == 0 ++ || strncmp (name, ".sbss.", 6) == 0 ++ || strcmp (name, ".sdata") == 0 ++ || strncmp (name, ".sdata.", 7) == 0) ++ flags |= SECTION_SMALL; ++ ++ return flags; ++} ++ ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++ ++/* print the operand OP to file stream ++ FILE modified by LETTER. LETTER ++ can be one of: ++ i: print "i" if OP is an immediate, except 0 ++ o: print "io" if OP is volatile ++ ++ z: for const0_rtx print $0 instead of 0 ++ H: for %hiadj ++ L: for %lo ++ U: for upper half of 32 bit value ++ */ ++ ++void ++nios2_print_operand (FILE *file, rtx op, int letter) ++{ ++ ++ switch (letter) ++ { ++ case 'i': ++ if (CONSTANT_P (op) && (op != const0_rtx)) ++ fprintf (file, "i"); ++ return; ++ ++ case 'o': ++ if (GET_CODE (op) == MEM ++ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE) ++ || TARGET_BYPASS_CACHE)) ++ fprintf (file, "io"); ++ return; ++ ++ default: ++ break; ++ } ++ ++ if (comparison_operator (op, VOIDmode)) ++ { ++ if (letter == 0) ++ { ++ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); ++ return; ++ } ++ } ++ ++ ++ switch (GET_CODE (op)) ++ { ++ case REG: ++ if (letter == 0 || letter == 'z') ++ { ++ fprintf (file, "%s", reg_names[REGNO (op)]); ++ return; ++ } ++ ++ case CONST_INT: ++ if (INTVAL (op) == 0 && letter == 'z') ++ { ++ fprintf (file, "zero"); ++ return; ++ } ++ else if (letter == 'U') ++ { ++ HOST_WIDE_INT val = INTVAL (op); ++ rtx new_op; ++ val = (val / 65536) & 0xFFFF; ++ new_op = GEN_INT (val); ++ output_addr_const (file, new_op); ++ return; ++ } ++ ++ /* else, fall through */ ++ case CONST: ++ case LABEL_REF: ++ case SYMBOL_REF: ++ case CONST_DOUBLE: ++ if (letter == 0 || letter == 'z') ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ else if (letter == 'H') ++ { ++ fprintf (file, "%%hiadj("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ else if (letter == 'L') ++ { ++ fprintf (file, "%%lo("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ ++ ++ case SUBREG: ++ case MEM: ++ if (letter == 0) ++ { ++ output_address (op); ++ return; ++ } ++ ++ case CODE_LABEL: ++ if (letter == 0) ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print (%c) ", letter); ++ debug_rtx (op); ++ abort (); ++} ++ ++static int gprel_constant (rtx); ++ ++static int ++gprel_constant (rtx op) ++{ ++ if (GET_CODE (op) == SYMBOL_REF ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) ++ { ++ return 1; ++ } ++ else if (GET_CODE (op) == CONST ++ && GET_CODE (XEXP (op, 0)) == PLUS) ++ { ++ return gprel_constant (XEXP (XEXP (op, 0), 0)); ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++void ++nios2_print_operand_address (FILE *file, rtx op) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST: ++ case CONST_INT: ++ case LABEL_REF: ++ case CONST_DOUBLE: ++ case SYMBOL_REF: ++ if (gprel_constant (op)) ++ { ++ fprintf (file, "%%gprel("); ++ output_addr_const (file, op); ++ fprintf (file, ")(%s)", reg_names[GP_REGNO]); ++ return; ++ } ++ ++ break; ++ ++ case PLUS: ++ { ++ rtx op0 = XEXP (op, 0); ++ rtx op1 = XEXP (op, 1); ++ ++ if (REG_P (op0) && CONSTANT_P (op1)) ++ { ++ output_addr_const (file, op1); ++ fprintf (file, "(%s)", reg_names[REGNO (op0)]); ++ return; ++ } ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ { ++ output_addr_const (file, op0); ++ fprintf (file, "(%s)", reg_names[REGNO (op1)]); ++ return; ++ } ++ } ++ break; ++ ++ case REG: ++ fprintf (file, "0(%s)", reg_names[REGNO (op)]); ++ return; ++ ++ case MEM: ++ { ++ rtx base = XEXP (op, 0); ++ PRINT_OPERAND_ADDRESS (file, base); ++ return; ++ } ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print address\n"); ++ debug_rtx (op); ++ abort (); ++} ++ ++ ++ ++ ++ ++/**************************** ++ * Predicates ++ ****************************/ ++ ++int ++arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++uns_arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++logical_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT ++ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++shift_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); ++} ++ ++/* Return truth value of whether OP is a register or the constant 0. */ ++ ++int ++reg_or_0_operand (rtx op, enum machine_mode mode) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST_INT: ++ return INTVAL (op) == 0; ++ ++ case CONST_DOUBLE: ++ return op == CONST0_RTX (mode); ++ ++ default: ++ break; ++ } ++ ++ return register_operand (op, mode); ++} ++ ++ ++int ++equality_op (rtx op, enum machine_mode mode) ++{ ++ if (mode != GET_MODE (op)) ++ return 0; ++ ++ return GET_CODE (op) == EQ || GET_CODE (op) == NE; ++} ++ ++int ++custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); ++} ++ ++ ++ ++ ++ ++ ++ ++/***************************************************************************** ++** ++** instruction scheduler ++** ++*****************************************************************************/ ++static int ++nios2_use_dfa_pipeline_interface () ++{ ++ return 1; ++} ++ ++ ++static int ++nios2_issue_rate () ++{ ++#ifdef MAX_DFA_ISSUE_RATE ++ return MAX_DFA_ISSUE_RATE; ++#else ++ return 1; ++#endif ++} ++ ++ ++const char * ++asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, ++ const char *ptr ATTRIBUTE_UNUSED) ++{ ++ const char *p; ++ ++ p = ptr; ++ return ptr; ++} ++ ++ ++ ++/***************************************************************************** ++** ++** function arguments ++** ++*****************************************************************************/ ++ ++void ++init_cumulative_args (CUMULATIVE_ARGS *cum, ++ tree fntype ATTRIBUTE_UNUSED, ++ rtx libname ATTRIBUTE_UNUSED, ++ tree fndecl ATTRIBUTE_UNUSED, ++ int n_named_args ATTRIBUTE_UNUSED) ++{ ++ cum->regs_used = 0; ++} ++ ++ ++/* Update the data in CUM to advance over an argument ++ of mode MODE and data type TYPE. ++ (TYPE is null for libcalls where that information may not be available.) */ ++ ++void ++function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ cum->regs_used = NUM_ARG_REGS; ++ } ++ else ++ { ++ cum->regs_used += param_size; ++ } ++ ++ return; ++} ++ ++/* Define where to put the arguments to a function. Value is zero to ++ push the argument on the stack, or a hard register in which to ++ store the argument. ++ ++ MODE is the argument's machine mode. ++ TYPE is the data type of the argument (as a tree). ++ This is null for libcalls where that information may ++ not be available. ++ CUM is a variable of type CUMULATIVE_ARGS which gives info about ++ the preceding args and about the function being called. ++ NAMED is nonzero if this argument is a named parameter ++ (otherwise it is an extra parameter matching an ellipsis). */ ++rtx ++function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ rtx return_rtx = NULL_RTX; ++ ++ if (cum->regs_used < NUM_ARG_REGS) ++ { ++ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); ++ } ++ ++ return return_rtx; ++} ++ ++int ++function_arg_partial_nregs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used < NUM_ARG_REGS ++ && cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ return NUM_ARG_REGS - cum->regs_used; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++ ++int ++nios2_return_in_memory (tree type) ++{ ++ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) ++ || (int_size_in_bytes (type) == -1)); ++ ++ return res; ++} ++ ++/* ??? It may be possible to eliminate the copyback and implement ++ my own va_arg type, but that is more work for now. */ ++int ++nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int no_rtl) ++{ ++ CUMULATIVE_ARGS local_cum; ++ int regs_to_push; ++ ++ local_cum = *cum; ++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); ++ ++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used; ++ ++ if (!no_rtl) ++ { ++ if (regs_to_push > 0) ++ { ++ rtx ptr, mem; ++ ++ ptr = virtual_incoming_args_rtx; ++ mem = gen_rtx_MEM (BLKmode, ptr); ++ ++ /* va_arg is an array access in this case, which causes ++ it to get MEM_IN_STRUCT_P set. We must set it here ++ so that the insn scheduler won't assume that these ++ stores can't possibly overlap with the va_arg loads. */ ++ MEM_SET_IN_STRUCT_P (mem, 1); ++ ++ emit_insn (gen_blockage ()); ++ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, ++ regs_to_push); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ ++ return regs_to_push * UNITS_PER_WORD; ++ ++} ++ ++ ++ ++/***************************************************************************** ++** ++** builtins ++** ++** This method for handling builtins is from CSP where _many_ more types of ++** expanders have already been written. Check there first before writing ++** new ones. ++** ++*****************************************************************************/ ++ ++enum nios2_builtins ++{ ++ NIOS2_BUILTIN_LDBIO, ++ NIOS2_BUILTIN_LDBUIO, ++ NIOS2_BUILTIN_LDHIO, ++ NIOS2_BUILTIN_LDHUIO, ++ NIOS2_BUILTIN_LDWIO, ++ NIOS2_BUILTIN_STBIO, ++ NIOS2_BUILTIN_STHIO, ++ NIOS2_BUILTIN_STWIO, ++ NIOS2_BUILTIN_SYNC, ++ NIOS2_BUILTIN_RDCTL, ++ NIOS2_BUILTIN_WRCTL, ++ ++ NIOS2_BUILTIN_CUSTOM_N, ++ NIOS2_BUILTIN_CUSTOM_NI, ++ NIOS2_BUILTIN_CUSTOM_NF, ++ NIOS2_BUILTIN_CUSTOM_NP, ++ NIOS2_BUILTIN_CUSTOM_NII, ++ NIOS2_BUILTIN_CUSTOM_NIF, ++ NIOS2_BUILTIN_CUSTOM_NIP, ++ NIOS2_BUILTIN_CUSTOM_NFI, ++ NIOS2_BUILTIN_CUSTOM_NFF, ++ NIOS2_BUILTIN_CUSTOM_NFP, ++ NIOS2_BUILTIN_CUSTOM_NPI, ++ NIOS2_BUILTIN_CUSTOM_NPF, ++ NIOS2_BUILTIN_CUSTOM_NPP, ++ NIOS2_BUILTIN_CUSTOM_IN, ++ NIOS2_BUILTIN_CUSTOM_INI, ++ NIOS2_BUILTIN_CUSTOM_INF, ++ NIOS2_BUILTIN_CUSTOM_INP, ++ NIOS2_BUILTIN_CUSTOM_INII, ++ NIOS2_BUILTIN_CUSTOM_INIF, ++ NIOS2_BUILTIN_CUSTOM_INIP, ++ NIOS2_BUILTIN_CUSTOM_INFI, ++ NIOS2_BUILTIN_CUSTOM_INFF, ++ NIOS2_BUILTIN_CUSTOM_INFP, ++ NIOS2_BUILTIN_CUSTOM_INPI, ++ NIOS2_BUILTIN_CUSTOM_INPF, ++ NIOS2_BUILTIN_CUSTOM_INPP, ++ NIOS2_BUILTIN_CUSTOM_FN, ++ NIOS2_BUILTIN_CUSTOM_FNI, ++ NIOS2_BUILTIN_CUSTOM_FNF, ++ NIOS2_BUILTIN_CUSTOM_FNP, ++ NIOS2_BUILTIN_CUSTOM_FNII, ++ NIOS2_BUILTIN_CUSTOM_FNIF, ++ NIOS2_BUILTIN_CUSTOM_FNIP, ++ NIOS2_BUILTIN_CUSTOM_FNFI, ++ NIOS2_BUILTIN_CUSTOM_FNFF, ++ NIOS2_BUILTIN_CUSTOM_FNFP, ++ NIOS2_BUILTIN_CUSTOM_FNPI, ++ NIOS2_BUILTIN_CUSTOM_FNPF, ++ NIOS2_BUILTIN_CUSTOM_FNPP, ++ NIOS2_BUILTIN_CUSTOM_PN, ++ NIOS2_BUILTIN_CUSTOM_PNI, ++ NIOS2_BUILTIN_CUSTOM_PNF, ++ NIOS2_BUILTIN_CUSTOM_PNP, ++ NIOS2_BUILTIN_CUSTOM_PNII, ++ NIOS2_BUILTIN_CUSTOM_PNIF, ++ NIOS2_BUILTIN_CUSTOM_PNIP, ++ NIOS2_BUILTIN_CUSTOM_PNFI, ++ NIOS2_BUILTIN_CUSTOM_PNFF, ++ NIOS2_BUILTIN_CUSTOM_PNFP, ++ NIOS2_BUILTIN_CUSTOM_PNPI, ++ NIOS2_BUILTIN_CUSTOM_PNPF, ++ NIOS2_BUILTIN_CUSTOM_PNPP, ++ ++ ++ LIM_NIOS2_BUILTINS ++}; ++ ++struct builtin_description ++{ ++ const enum insn_code icode; ++ const char *const name; ++ const enum nios2_builtins code; ++ const tree *type; ++ rtx (* expander) PARAMS ((const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int)); ++}; ++ ++static rtx nios2_expand_STXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_LDXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_sync (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_rdctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_wrctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static rtx nios2_expand_custom_n (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_Xn (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static tree endlink; ++ ++/* int fn (volatile const void *) ++ */ ++static tree int_ftype_volatile_const_void_p; ++ ++/* int fn (int) ++ */ ++static tree int_ftype_int; ++ ++/* void fn (int, int) ++ */ ++static tree void_ftype_int_int; ++ ++/* void fn (volatile void *, int) ++ */ ++static tree void_ftype_volatile_void_p_int; ++ ++/* void fn (void) ++ */ ++static tree void_ftype_void; ++ ++static tree custom_n; ++static tree custom_ni; ++static tree custom_nf; ++static tree custom_np; ++static tree custom_nii; ++static tree custom_nif; ++static tree custom_nip; ++static tree custom_nfi; ++static tree custom_nff; ++static tree custom_nfp; ++static tree custom_npi; ++static tree custom_npf; ++static tree custom_npp; ++static tree custom_in; ++static tree custom_ini; ++static tree custom_inf; ++static tree custom_inp; ++static tree custom_inii; ++static tree custom_inif; ++static tree custom_inip; ++static tree custom_infi; ++static tree custom_inff; ++static tree custom_infp; ++static tree custom_inpi; ++static tree custom_inpf; ++static tree custom_inpp; ++static tree custom_fn; ++static tree custom_fni; ++static tree custom_fnf; ++static tree custom_fnp; ++static tree custom_fnii; ++static tree custom_fnif; ++static tree custom_fnip; ++static tree custom_fnfi; ++static tree custom_fnff; ++static tree custom_fnfp; ++static tree custom_fnpi; ++static tree custom_fnpf; ++static tree custom_fnpp; ++static tree custom_pn; ++static tree custom_pni; ++static tree custom_pnf; ++static tree custom_pnp; ++static tree custom_pnii; ++static tree custom_pnif; ++static tree custom_pnip; ++static tree custom_pnfi; ++static tree custom_pnff; ++static tree custom_pnfp; ++static tree custom_pnpi; ++static tree custom_pnpf; ++static tree custom_pnpp; ++ ++ ++static const struct builtin_description bdesc[] = { ++ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ ++ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ ++ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync}, ++ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl}, ++ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl}, ++ ++ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n}, ++ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX}, ++ ++ ++ {0, 0, 0, 0, 0}, ++}; ++ ++/* This does not have a closing bracket on purpose (see use) */ ++#define def_param(TYPE) \ ++ tree_cons (NULL_TREE, TYPE, ++ ++static void ++nios2_init_builtins () ++{ ++ const struct builtin_description *d; ++ ++ ++ endlink = void_list_node; ++ ++ /* Special indenting here because one of the brackets is in def_param */ ++ /* *INDENT-OFF* */ ++ ++ /* int fn (volatile const void *) ++ */ ++ int_ftype_volatile_const_void_p ++ = build_function_type (integer_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) ++ endlink)); ++ ++ ++ /* void fn (volatile void *, int) ++ */ ++ void_ftype_volatile_void_p_int ++ = build_function_type (void_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_VOLATILE)) ++ def_param (integer_type_node) ++ endlink))); ++ ++ /* void fn (void) ++ */ ++ void_ftype_void ++ = build_function_type (void_type_node, ++ endlink); ++ ++ /* int fn (int) ++ */ ++ int_ftype_int ++ = build_function_type (integer_type_node, ++ def_param (integer_type_node) ++ endlink)); ++ ++ /* void fn (int, int) ++ */ ++ void_ftype_int_int ++ = build_function_type (void_type_node, ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink))); ++ ++ ++#define CUSTOM_NUM def_param (integer_type_node) ++ ++ custom_n ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ni ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_nf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_np ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_nii ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nif ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nip ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_nfi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nff ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nfp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_npi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_npf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_npp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_in ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ini ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_inf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_inp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_inii ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inif ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inip ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_infi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inff ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_infp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_inpi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inpf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inpp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_fn ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_fni ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_fnf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_fnp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_fnii ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnif ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnip ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnfi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnff ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnfp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnpi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnpf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnpp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ custom_pn ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_pni ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_pnf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_pnp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_pnii ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnif ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnip ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnfi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnff ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnfp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnpi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnpf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnpp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ ++ /* *INDENT-ON* */ ++ ++ ++ for (d = bdesc; d->name; d++) ++ { ++ builtin_function (d->name, *d->type, d->code, ++ BUILT_IN_MD, NULL, NULL); ++ } ++} ++ ++/* Expand an expression EXP that calls a built-in function, ++ with result going to TARGET if that's convenient ++ (and in mode MODE if that's convenient). ++ SUBTARGET may be used as the target for computing one of EXP's operands. ++ IGNORE is nonzero if the value is to be ignored. */ ++ ++static rtx ++nios2_expand_builtin (tree exp, rtx target, rtx subtarget, ++ enum machine_mode mode, int ignore) ++{ ++ const struct builtin_description *d; ++ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ ++ for (d = bdesc; d->name; d++) ++ if (d->code == fcode) ++ return (d->expander) (d, exp, target, subtarget, mode, ignore); ++ ++ /* we should have seen one of the functins we registered */ ++ abort (); ++} ++ ++static rtx nios2_create_target (const struct builtin_description *, rtx); ++ ++ ++static rtx ++nios2_create_target (const struct builtin_description *d, rtx target) ++{ ++ if (!target ++ || !(*insn_data[d->icode].operand[0].predicate) (target, ++ insn_data[d->icode].operand[0].mode)) ++ { ++ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); ++ } ++ ++ return target; ++} ++ ++ ++static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); ++static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree); ++ ++static rtx ++nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); ++ opcode = protect_from_queue (opcode, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) ++ error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name); ++ ++ return opcode; ++} ++ ++static rtx ++nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx operand = expand_expr (arg, NULL_RTX, mode, 0); ++ operand = protect_from_queue (operand, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ operand = copy_to_mode_reg (mode, operand); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ error ("Invalid argument %d to %s", argnum, d->name); ++ ++ return operand; ++} ++ ++ ++static rtx ++nios2_expand_custom_n (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_n should have exactly one operand */ ++ if (insn_data[d->icode].n_operands != 1) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ ++ pat = GEN_FCN (d->icode) (opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_Xn should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ pat = GEN_FCN (d->icode) (target, opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nX (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ ++ /* custom_nX should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ /* custom_Xn should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_nX should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_XnX should have exactly four operands */ ++ if (insn_data[d->icode].n_operands != 4) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++ ++static rtx ++nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx store_dest, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ store_dest = protect_from_queue (store_dest, 0); ++ ++ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (store_dest, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++static rtx ++nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx ld_src; ++ enum insn_code icode = d->icode; ++ ++ /* loads should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ld_src = protect_from_queue (ld_src, 0); ++ ++ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) ++ { ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, ld_src); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++static rtx ++nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ emit_insn (gen_sync ()); ++ return 0; ++} ++ ++static rtx ++nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx rdctl_reg; ++ enum insn_code icode = d->icode; ++ ++ /* rdctl should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ rdctl_reg = protect_from_queue (rdctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) ++ { ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, rdctl_reg); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx wrctl_reg, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ wrctl_reg = protect_from_queue (wrctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (wrctl_reg, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++#include "gt-nios2.h" ++ +--- gcc-3.4.3/gcc/config/nios2/nios2.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h +@@ -0,0 +1,824 @@ ++/* Definitions of target machine for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++ ++#define TARGET_CPU_CPP_BUILTINS() \ ++ do \ ++ { \ ++ builtin_define_std ("NIOS2"); \ ++ builtin_define_std ("nios2"); \ ++ builtin_define ("_GNU_SOURCE"); \ ++ } \ ++ while (0) ++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") ++ ++ ++ ++ ++ ++/********************************* ++ * Run-time Target Specification ++ *********************************/ ++ ++#define HAS_DIV_FLAG 0x0001 ++#define HAS_MUL_FLAG 0x0002 ++#define HAS_MULX_FLAG 0x0004 ++#define FAST_SW_DIV_FLAG 0x0008 ++#define INLINE_MEMCPY_FLAG 0x00010 ++#define CACHE_VOLATILE_FLAG 0x0020 ++#define BYPASS_CACHE_FLAG 0x0040 ++ ++extern int target_flags; ++#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG) ++#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG) ++#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG) ++#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG) ++#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG) ++#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG) ++#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG) ++ ++#define TARGET_SWITCHES \ ++{ \ ++ { "hw-div", HAS_DIV_FLAG, \ ++ N_("Enable DIV, DIVU") }, \ ++ { "no-hw-div", -HAS_DIV_FLAG, \ ++ N_("Disable DIV, DIVU (default)") }, \ ++ { "hw-mul", HAS_MUL_FLAG, \ ++ N_("Enable MUL instructions (default)") }, \ ++ { "hw-mulx", HAS_MULX_FLAG, \ ++ N_("Enable MULX instructions, assume fast shifter") }, \ ++ { "no-hw-mul", -HAS_MUL_FLAG, \ ++ N_("Disable MUL instructions") }, \ ++ { "no-hw-mulx", -HAS_MULX_FLAG, \ ++ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \ ++ { "fast-sw-div", FAST_SW_DIV_FLAG, \ ++ N_("Use table based fast divide (default at -O3)") }, \ ++ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \ ++ N_("Don't use table based fast divide ever") }, \ ++ { "inline-memcpy", INLINE_MEMCPY_FLAG, \ ++ N_("Inline small memcpy (default when optimizing)") }, \ ++ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \ ++ N_("Don't Inline small memcpy") }, \ ++ { "cache-volatile", CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use non-io variants of instructions (default)") }, \ ++ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use io variants of instructions") }, \ ++ { "bypass-cache", BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins use io variants") }, \ ++ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins do not use io variants (default)") }, \ ++ { "smallc", 0, \ ++ N_("Link with a limited version of the C library") }, \ ++ { "ctors-in-init", 0, \ ++ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \ ++ { "", TARGET_DEFAULT, 0 } \ ++} ++ ++ ++extern const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++extern const char *nios2_sys_lib_string; /* for -msys-lib= */ ++extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++#define TARGET_OPTIONS \ ++{ \ ++ { "sys=nosys", &nios2_sys_nosys_string, \ ++ N_("Use stub versions of OS library calls (default)"), 0}, \ ++ { "sys-lib=", &nios2_sys_lib_string, \ ++ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \ ++ { "sys-crt0=", &nios2_sys_crt0_string, \ ++ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \ ++} ++ ++ ++/* Default target_flags if no switches specified. */ ++#ifndef TARGET_DEFAULT ++# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG) ++#endif ++ ++/* Switch Recognition by gcc.c. Add -G xx support */ ++#undef SWITCH_TAKES_ARG ++#define SWITCH_TAKES_ARG(CHAR) \ ++ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') ++ ++#define OVERRIDE_OPTIONS override_options () ++#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) ++#define CAN_DEBUG_WITHOUT_FP ++ ++#define CC1_SPEC "\ ++%{G*}" ++ ++#undef LIB_SPEC ++#define LIB_SPEC \ ++"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \ ++ %{msys-lib=*: -l%*} \ ++ %{!msys-lib=*: -lc } \ ++ --end-group \ ++ %{msys-lib=: %eYou need a library name for -msys-lib=} \ ++" ++ ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC \ ++"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \ ++ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \ ++ %{mctors-in-init: crti%O%s crtbegin%O%s} \ ++" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++ "%{mctors-in-init: crtend%O%s crtn%O%s}" ++ ++ ++/*********************** ++ * Storage Layout ++ ***********************/ ++ ++#define DEFAULT_SIGNED_CHAR 1 ++#define BITS_BIG_ENDIAN 0 ++#define BYTES_BIG_ENDIAN 0 ++#define WORDS_BIG_ENDIAN 0 ++#define BITS_PER_UNIT 8 ++#define BITS_PER_WORD 32 ++#define UNITS_PER_WORD 4 ++#define POINTER_SIZE 32 ++#define BIGGEST_ALIGNMENT 32 ++#define STRICT_ALIGNMENT 1 ++#define FUNCTION_BOUNDARY 32 ++#define PARM_BOUNDARY 32 ++#define STACK_BOUNDARY 32 ++#define PREFERRED_STACK_BOUNDARY 32 ++#define MAX_FIXED_MODE_SIZE 64 ++ ++#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ ++ ((TREE_CODE (EXP) == STRING_CST) \ ++ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) ++ ++ ++/********************** ++ * Layout of Source Language Data Types ++ **********************/ ++ ++#define INT_TYPE_SIZE 32 ++#define SHORT_TYPE_SIZE 16 ++#define LONG_TYPE_SIZE 32 ++#define LONG_LONG_TYPE_SIZE 64 ++#define FLOAT_TYPE_SIZE 32 ++#define DOUBLE_TYPE_SIZE 64 ++#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE ++ ++ ++/************************* ++ * Condition Code Status ++ ************************/ ++ ++/* comparison type */ ++/* ??? currently only CMP_SI is used */ ++enum cmp_type { ++ CMP_SI, /* compare four byte integers */ ++ CMP_DI, /* compare eight byte integers */ ++ CMP_SF, /* compare single precision floats */ ++ CMP_DF, /* compare double precision floats */ ++ CMP_MAX /* max comparison type */ ++}; ++ ++extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ ++extern enum cmp_type branch_type; /* what type of branch to use */ ++ ++/********************** ++ * Register Usage ++ **********************/ ++ ++/* ---------------------------------- * ++ * Basic Characteristics of Registers ++ * ---------------------------------- */ ++ ++/* ++Register Number ++ Register Name ++ Alternate Name ++ Purpose ++0 r0 zero always zero ++1 r1 at Assembler Temporary ++2-3 r2-r3 Return Location ++4-7 r4-r7 Register Arguments ++8-15 r8-r15 Caller Saved Registers ++16-22 r16-r22 Callee Saved Registers ++23 r23 sc Static Chain (Callee Saved) ++ ??? Does $sc want to be caller or callee ++ saved. If caller, 15, else 23. ++24 r24 Exception Temporary ++25 r25 Breakpoint Temporary ++26 r26 gp Global Pointer ++27 r27 sp Stack Pointer ++28 r28 fp Frame Pointer ++29 r29 ea Exception Return Address ++30 r30 ba Breakpoint Return Address ++31 r31 ra Return Address ++ ++32 ctl0 status ++33 ctl1 estatus STATUS saved by exception ? ++34 ctl2 bstatus STATUS saved by break ? ++35 ctl3 ipri Interrupt Priority Mask ? ++36 ctl4 ecause Exception Cause ? ++ ++37 pc Not an actual register ++ ++38 rap Return address pointer, this does not ++ actually exist and will be eliminated ++ ++39 fake_fp Fake Frame Pointer which will always be eliminated. ++40 fake_ap Fake Argument Pointer which will always be eliminated. ++ ++41 First Pseudo Register ++ ++ ++The definitions for all the hard register numbers ++are located in nios2.md. ++*/ ++ ++#define FIRST_PSEUDO_REGISTER 41 ++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) ++ ++ ++ ++/* also see CONDITIONAL_REGISTER_USAGE */ ++#define FIXED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++/* call used is the same as caller saved ++ + fixed regs + args + ret vals */ ++#define CALL_USED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++/* --------------------------- * ++ * How Values Fit in Registers ++ * --------------------------- */ ++ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++ ++#define MODES_TIEABLE_P(MODE1, MODE2) 1 ++ ++ ++/************************* ++ * Register Classes ++ *************************/ ++ ++enum reg_class ++{ ++ NO_REGS, ++ ALL_REGS, ++ LIM_REG_CLASSES ++}; ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++ ++#define REG_CLASS_NAMES \ ++ {"NO_REGS", \ ++ "ALL_REGS"} ++ ++#define GENERAL_REGS ALL_REGS ++ ++#define REG_CLASS_CONTENTS \ ++/* NO_REGS */ {{ 0, 0}, \ ++/* ALL_REGS */ {~0,~0}} \ ++ ++#define REGNO_REG_CLASS(REGNO) ALL_REGS ++ ++#define BASE_REG_CLASS ALL_REGS ++#define INDEX_REG_CLASS ALL_REGS ++ ++/* only one reg class, 'r', is handled automatically */ ++#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS ++ ++#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ ++ ((STRICT) \ ++ ? (REGNO) < FIRST_PSEUDO_REGISTER \ ++ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) ++ ++#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) ++ ++#define REGNO_OK_FOR_BASE_P(REGNO) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) ++ ++#define REGNO_OK_FOR_INDEX_P(REGNO) \ ++ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) ++ ++#define REG_OK_FOR_BASE_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define REG_OK_FOR_INDEX_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++ ++#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) ++#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) ++#define UPPER16_INT(X) (((X) & 0xffff) == 0) ++#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) ++#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) ++#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ( \ ++ (C) == 'I' ? SMALL_INT (VALUE) : \ ++ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ ++ (C) == 'K' ? UPPER16_INT (VALUE) : \ ++ (C) == 'L' ? SHIFT_INT (VALUE) : \ ++ (C) == 'M' ? (VALUE) == 0 : \ ++ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ ++ (C) == 'O' ? RDWRCTL_INT (VALUE) : \ ++ 0) ++ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 ++ ++#define PREFERRED_RELOAD_CLASS(X, CLASS) \ ++ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) ++ ++/* 'S' matches immediates which are in small data ++ and therefore can be added to gp to create a ++ 32-bit value. */ ++#define EXTRA_CONSTRAINT(VALUE, C) \ ++ ((C) == 'S' \ ++ && (GET_CODE (VALUE) == SYMBOL_REF) \ ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) ++ ++ ++ ++ ++/* Say that the epilogue uses the return address register. Note that ++ in the case of sibcalls, the values "used by the epilogue" are ++ considered live at the start of the called function. */ ++#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) ++ ++ ++#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) ++ ++/********************************** ++ * Trampolines for Nested Functions ++ ***********************************/ ++ ++#define TRAMPOLINE_TEMPLATE(FILE) \ ++ error ("trampolines not yet implemented") ++#define TRAMPOLINE_SIZE 20 ++#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ ++ error ("trampolines not yet implemented") ++ ++/*************************** ++ * Stack Layout and Calling Conventions ++ ***************************/ ++ ++/* ------------------ * ++ * Basic Stack Layout ++ * ------------------ */ ++ ++/* The downward variants are used by the compiler, ++ the upward ones serve as documentation */ ++#define STACK_GROWS_DOWNWARD ++#define FRAME_GROWS_UPWARD ++#define ARGS_GROW_UPWARD ++ ++#define STARTING_FRAME_OFFSET current_function_outgoing_args_size ++#define FIRST_PARM_OFFSET(FUNDECL) 0 ++ ++/* Before the prologue, RA lives in r31. */ ++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) ++ ++/* -------------------------------------- * ++ * Registers That Address the Stack Frame ++ * -------------------------------------- */ ++ ++#define STACK_POINTER_REGNUM SP_REGNO ++#define STATIC_CHAIN_REGNUM SC_REGNO ++#define PC_REGNUM PC_REGNO ++#define DWARF_FRAME_RETURN_COLUMN RA_REGNO ++ ++/* Base register for access to local variables of the function. We ++ pretend that the frame pointer is a non-existent hard register, and ++ then eliminate it to HARD_FRAME_POINTER_REGNUM. */ ++#define FRAME_POINTER_REGNUM FAKE_FP_REGNO ++ ++#define HARD_FRAME_POINTER_REGNUM FP_REGNO ++#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO ++/* the argumnet pointer needs to always be eliminated ++ so it is set to a fake hard register. */ ++#define ARG_POINTER_REGNUM FAKE_AP_REGNO ++ ++/* ----------------------------------------- * ++ * Eliminating Frame Pointer and Arg Pointer ++ * ----------------------------------------- */ ++ ++#define FRAME_POINTER_REQUIRED 0 ++ ++#define ELIMINABLE_REGS \ ++{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} ++ ++#define CAN_ELIMINATE(FROM, TO) 1 ++ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) ++ ++#define MUST_SAVE_REGISTER(regno) \ ++ ((regs_ever_live[regno] && !call_used_regs[regno]) \ ++ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ ++ || (regno == RA_REGNO && regs_ever_live[RA_REGNO])) ++ ++/* Treat LOC as a byte offset from the stack pointer and round it up ++ to the next fully-aligned offset. */ ++#define STACK_ALIGN(LOC) \ ++ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) ++ ++ ++/* ------------------------------ * ++ * Passing Arguments in Registers ++ * ------------------------------ */ ++ ++/* see nios2.c */ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ (function_arg (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0 ++ ++#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 ++ ++typedef struct nios2_args ++{ ++ int regs_used; ++} CUMULATIVE_ARGS; ++ ++/* This is to initialize the above unused CUM data type */ ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ ++ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) ++ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_advance (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_REGNO_P(REGNO) \ ++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) ++ ++#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ ++ { \ ++ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \ ++ (TYPE), (NO_RTL)); \ ++ if (pret_size) \ ++ (PRETEND_SIZE) = pret_size; \ ++ } ++ ++/* ----------------------------- * ++ * Generating Code for Profiling ++ * ----------------------------- */ ++ ++#define PROFILE_BEFORE_PROLOGUE ++ ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ function_profiler ((FILE), (LABELNO)) ++ ++/* --------------------------------------- * ++ * Passing Function Arguments on the Stack ++ * --------------------------------------- */ ++ ++#define PROMOTE_PROTOTYPES 1 ++ ++#define PUSH_ARGS 0 ++#define ACCUMULATE_OUTGOING_ARGS 1 ++ ++#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 ++ ++/* --------------------------------------- * ++ * How Scalar Function Values Are Returned ++ * --------------------------------------- */ ++ ++#define FUNCTION_VALUE(VALTYPE, FUNC) \ ++ gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) ++ ++#define LIBCALL_VALUE(MODE) \ ++ gen_rtx(REG, MODE, FIRST_RETVAL_REGNO) ++ ++#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) ++ ++/* ----------------------------- * ++ * How Large Values Are Returned ++ * ----------------------------- */ ++ ++ ++#define RETURN_IN_MEMORY(TYPE) \ ++ nios2_return_in_memory (TYPE) ++ ++ ++#define STRUCT_VALUE 0 ++ ++#define DEFAULT_PCC_STRUCT_RETURN 0 ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++ ++#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) ++ ++#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) ++ ++#define MAX_REGS_PER_ADDRESS 1 ++ ++/* Go to ADDR if X is a valid address. */ ++#ifndef REG_OK_STRICT ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 0)) \ ++ goto ADDR; \ ++ } ++#else ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 1)) \ ++ goto ADDR; \ ++ } ++#endif ++ ++#ifndef REG_OK_STRICT ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) ++#else ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) ++#endif ++ ++#define LEGITIMATE_CONSTANT_P(X) 1 ++ ++/* Nios II has no mode dependent addresses. */ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) ++ ++/* Set if this has a weak declaration */ ++#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) ++#define SYMBOL_REF_WEAK_DECL_P(RTX) \ ++ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) ++ ++ ++/* true if a symbol is both small and not weak. In this case, gp ++ relative access can be used */ ++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ ++ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX)) ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++#define SLOW_BYTE_ACCESS 1 ++ ++/* It is as good to call a constant function address as to call an address ++ kept in a register. ++ ??? Not true anymore really. Now that call cannot address full range ++ of memory callr may need to be used */ ++ ++#define NO_FUNCTION_CSE ++#define NO_RECURSIVE_FUNCTION_CSE ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* ------------------------------------------ * ++ * The Overall Framework of an Assembler File ++ * ------------------------------------------ */ ++ ++#define ASM_APP_ON "#APP\n" ++#define ASM_APP_OFF "#NO_APP\n" ++ ++#define ASM_COMMENT_START "# " ++ ++/* ------------------------------- * ++ * Output and Generation of Labels ++ * ------------------------------- */ ++ ++#define GLOBAL_ASM_OP "\t.global\t" ++ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++#define DWARF2_UNWIND_INFO 0 ++ ++ ++/* -------------------------------- * ++ * Assembler Commands for Alignment ++ * -------------------------------- */ ++ ++#define ASM_OUTPUT_ALIGN(FILE, LOG) \ ++ do { \ ++ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ ++ } while (0) ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++#define REGISTER_NAMES \ ++{ \ ++ "zero", \ ++ "at", \ ++ "r2", \ ++ "r3", \ ++ "r4", \ ++ "r5", \ ++ "r6", \ ++ "r7", \ ++ "r8", \ ++ "r9", \ ++ "r10", \ ++ "r11", \ ++ "r12", \ ++ "r13", \ ++ "r14", \ ++ "r15", \ ++ "r16", \ ++ "r17", \ ++ "r18", \ ++ "r19", \ ++ "r20", \ ++ "r21", \ ++ "r22", \ ++ "r23", \ ++ "r24", \ ++ "r25", \ ++ "gp", \ ++ "sp", \ ++ "fp", \ ++ "ta", \ ++ "ba", \ ++ "ra", \ ++ "status", \ ++ "estatus", \ ++ "bstatus", \ ++ "ipri", \ ++ "ecause", \ ++ "pc", \ ++ "rap", \ ++ "fake_fp", \ ++ "fake_ap", \ ++} ++ ++#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ ++ (PTR) = asm_output_opcode (STREAM, PTR) ++ ++#define PRINT_OPERAND(STREAM, X, CODE) \ ++ nios2_print_operand (STREAM, X, CODE) ++ ++#define PRINT_OPERAND_ADDRESS(STREAM, X) \ ++ nios2_print_operand_address (STREAM, X) ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ ++do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ ++ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ ++ } while (0) ++ ++ ++/* ------------ * ++ * Label Output ++ * ------------ */ ++ ++ ++/* ---------------------------------------------------- * ++ * Dividing the Output into Sections (Texts, Data, ...) ++ * ---------------------------------------------------- */ ++ ++/* Output before read-only data. */ ++#define TEXT_SECTION_ASM_OP ("\t.section\t.text") ++ ++/* Output before writable data. */ ++#define DATA_SECTION_ASM_OP ("\t.section\t.data") ++ ++ ++/* Default the definition of "small data" to 8 bytes. */ ++/* ??? How come I can't use HOST_WIDE_INT here? */ ++extern unsigned long nios2_section_threshold; ++#define NIOS2_DEFAULT_GVALUE 8 ++ ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized external linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef COMMON_ASM_OP ++#define COMMON_ASM_OP "\t.comm\t" ++ ++#undef ASM_OUTPUT_ALIGNED_COMMON ++#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ ++do \ ++{ \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ { \ ++ named_section (0, ".sbss", 0); \ ++ (*targetm.asm_out.globalize_label) (FILE, NAME); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++ } \ ++ else \ ++ { \ ++ fprintf ((FILE), "%s", COMMON_ASM_OP); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ ++ } \ ++} \ ++while (0) ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized internal linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef ASM_OUTPUT_ALIGNED_LOCAL ++#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ ++do { \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ named_section (0, ".sbss", 0); \ ++ else \ ++ named_section (0, ".bss", 0); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++} while (0) ++ ++ ++ ++/*************************** ++ * Miscellaneous Parameters ++ ***************************/ ++ ++#define MOVE_MAX 4 ++ ++#define Pmode SImode ++#define FUNCTION_MODE QImode ++ ++#define CASE_VECTOR_MODE Pmode ++ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++ ++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) ++ ++#define WORD_REGISTER_OPERATIONS +--- gcc-3.4.3/gcc/config/nios2/nios2.md ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md +@@ -0,0 +1,2078 @@ ++;; Machine Description for Altera NIOS 2G NIOS2 version. ++;; Copyright (C) 2003 Altera ++;; Contributed by Jonah Graham (jgraham@altera.com). ++;; ++;; This file is part of GNU CC. ++;; ++;; GNU CC is free software; you can redistribute it and/or modify ++;; it under the terms of the GNU General Public License as published by ++;; the Free Software Foundation; either version 2, or (at your option) ++;; any later version. ++;; ++;; GNU CC is distributed in the hope that it will be useful, ++;; but WITHOUT ANY WARRANTY; without even the implied warranty of ++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++;; GNU General Public License for more details. ++;; ++;; You should have received a copy of the GNU General Public License ++;; along with GNU CC; see the file COPYING. If not, write to ++;; the Free Software Foundation, 59 Temple Place - Suite 330, ++;; Boston, MA 02111-1307, USA. */ ++ ++ ++ ++;***************************************************************************** ++;* ++;* constants ++;* ++;***************************************************************************** ++(define_constants [ ++ (GP_REGNO 26) ++ (SP_REGNO 27) ++ (FP_REGNO 28) ++ (RA_REGNO 31) ++ (RAP_REGNO 38) ++ (FIRST_RETVAL_REGNO 2) ++ (LAST_RETVAL_REGNO 3) ++ (FIRST_ARG_REGNO 4) ++ (LAST_ARG_REGNO 7) ++ (SC_REGNO 23) ++ (PC_REGNO 37) ++ (FAKE_FP_REGNO 39) ++ (FAKE_AP_REGNO 40) ++ ++ ++ (UNSPEC_BLOCKAGE 0) ++ (UNSPEC_LDBIO 1) ++ (UNSPEC_LDBUIO 2) ++ (UNSPEC_LDHIO 3) ++ (UNSPEC_LDHUIO 4) ++ (UNSPEC_LDWIO 5) ++ (UNSPEC_STBIO 6) ++ (UNSPEC_STHIO 7) ++ (UNSPEC_STWIO 8) ++ (UNSPEC_SYNC 9) ++ (UNSPEC_WRCTL 10) ++ (UNSPEC_RDCTL 11) ++ ++]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* instruction scheduler ++;* ++;***************************************************************************** ++ ++; No schedule info is currently available, using an assumption that no ++; instruction can use the results of the previous instruction without ++; incuring a stall. ++ ++; length of an instruction (in bytes) ++(define_attr "length" "" (const_int 4)) ++(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex")) ++ ++(define_asm_attributes ++ [(set_attr "length" "4") ++ (set_attr "type" "complex")]) ++ ++(define_automaton "nios2") ++(automata_option "v") ++;(automata_option "no-minimization") ++(automata_option "ndfa") ++ ++; The nios2 pipeline is fairly straightforward for the fast model. ++; Every alu operation is pipelined so that an instruction can ++; be issued every cycle. However, there are still potential ++; stalls which this description tries to deal with. ++ ++(define_cpu_unit "cpu" "nios2") ++ ++(define_insn_reservation "complex" 1 ++ (eq_attr "type" "complex") ++ "cpu") ++ ++(define_insn_reservation "control" 1 ++ (eq_attr "type" "control") ++ "cpu") ++ ++(define_insn_reservation "alu" 1 ++ (eq_attr "type" "alu") ++ "cpu") ++ ++(define_insn_reservation "cond_alu" 1 ++ (eq_attr "type" "cond_alu") ++ "cpu") ++ ++(define_insn_reservation "st" 1 ++ (eq_attr "type" "st") ++ "cpu") ++ ++(define_insn_reservation "custom" 1 ++ (eq_attr "type" "custom") ++ "cpu") ++ ++; shifts, muls and lds have three cycle latency ++(define_insn_reservation "ld" 3 ++ (eq_attr "type" "ld") ++ "cpu") ++ ++(define_insn_reservation "shift" 3 ++ (eq_attr "type" "shift") ++ "cpu") ++ ++(define_insn_reservation "mul" 3 ++ (eq_attr "type" "mul") ++ "cpu") ++ ++(define_insn_reservation "div" 1 ++ (eq_attr "type" "div") ++ "cpu") ++ ++ ++;***************************************************************************** ++;* ++;* MOV Instructions ++;* ++;***************************************************************************** ++ ++(define_expand "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (match_operand:QI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, QImode)) ++ DONE; ++}) ++ ++(define_insn "movqi_internal" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") ++ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] ++ "(register_operand (operands[0], QImode) ++ || register_operand (operands[1], QImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stb%o0\\t%z1, %0 ++ ldbu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu")]) ++ ++(define_insn "ldbio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldbuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stbio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] ++ "" ++ "stbio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, HImode)) ++ DONE; ++}) ++ ++(define_insn "movhi_internal" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") ++ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] ++ "(register_operand (operands[0], HImode) ++ || register_operand (operands[1], HImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ sth%o0\\t%z1, %0 ++ ldhu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu,alu")]) ++ ++(define_insn "ldhio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldhuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "sthio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] ++ "" ++ "sthio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++(define_expand "movsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (match_operand:SI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, SImode)) ++ DONE; ++}) ++ ++(define_insn "movsi_internal" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") ++ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] ++ "(register_operand (operands[0], SImode) ++ || register_operand (operands[1], SImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stw%o0\\t%z1, %0 ++ ldw%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1 ++ addi\\t%0, gp, %%gprel(%1) ++ movhi\\t%0, %H1\;addi\\t%0, %0, %L1" ++ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) ++ ++(define_insn "ldwio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldwio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stwio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] ++ "" ++ "stwio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* zero extension ++;* ++;***************************************************************************** ++ ++ ++(define_insn "zero_extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xffff ++ ldhu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=r,r") ++ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* sign extension ++;* ++;***************************************************************************** ++ ++(define_expand "extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (16); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendhisi2_internal" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ++ "" ++ "ldh%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_expand "extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op0 = gen_lowpart (SImode, operands[0]); ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (op0, temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqihi2_internal" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++(define_expand "extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqisi2_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Arithmetic Operations ++;* ++;***************************************************************************** ++ ++(define_insn "addsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (plus:SI (match_operand:SI 1 "register_operand" "%r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "" ++ "add%i2\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "subsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++ "sub\\t%0, %z1, %2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "mulsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (mult:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "TARGET_HAS_MUL" ++ "mul%i2\\t%0, %1, %z2" ++ [(set_attr "type" "mul")]) ++ ++(define_expand "divsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++{ ++ if (!TARGET_HAS_DIV) ++ { ++ if (!TARGET_FAST_SW_DIV) ++ FAIL; ++ else ++ { ++ if (nios2_emit_expensive_div (operands, SImode)) ++ DONE; ++ } ++ } ++}) ++ ++(define_insn "divsi3_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "div\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "udivsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (udiv:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "divu\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "smulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxss\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++(define_insn "umulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxuu\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++ ++(define_expand "mulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) ++ (sign_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++(define_expand "umulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) ++ (zero_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++ ++ ++;***************************************************************************** ++;* ++;* Negate and ones complement ++;* ++;***************************************************************************** ++ ++(define_insn "negsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (neg:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "sub\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++(define_insn "one_cmplsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (not:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "nor\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++ ++ ++; Logical Operantions ++ ++(define_insn "andsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ and\\t%0, %1, %z2 ++ and%i2\\t%0, %1, %2 ++ andh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "iorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ or\\t%0, %1, %z2 ++ or%i2\\t%0, %1, %2 ++ orh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "*norsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) ++ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] ++ "" ++ "nor\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "xorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ xor\\t%0, %1, %z2 ++ xor%i2\\t%0, %1, %2 ++ xorh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Shifts ++;* ++;***************************************************************************** ++ ++(define_insn "ashlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashift:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sll%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "ashrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sra%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "lshrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "srl%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotate:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "rol%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "register_operand" "r,r")))] ++ "" ++ "ror\\t%0, %1, %2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "*shift_mul_constants" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "const_int_operand" "I")) ++ (match_operand:SI 3 "const_int_operand" "I")))] ++ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" ++{ ++ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); ++ rtx ops[3]; ++ ++ ops[0] = operands[0]; ++ ops[1] = operands[1]; ++ ops[2] = GEN_INT (mul); ++ ++ output_asm_insn ("muli\t%0, %1, %2", ops); ++ return ""; ++} ++ [(set_attr "type" "mul")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Prologue, Epilogue and Return ++;* ++;***************************************************************************** ++ ++(define_expand "prologue" ++ [(const_int 1)] ++ "" ++{ ++ expand_prologue (); ++ DONE; ++}) ++ ++(define_expand "epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (false); ++ DONE; ++}) ++ ++(define_expand "sibcall_epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (true); ++ DONE; ++}) ++ ++(define_insn "return" ++ [(return)] ++ "reload_completed && nios2_can_use_return_insn ()" ++ "ret\\t" ++) ++ ++(define_insn "return_from_epilogue" ++ [(use (match_operand 0 "pmode_register_operand" "")) ++ (return)] ++ "reload_completed" ++ "ret\\t" ++) ++ ++;; Block any insns from being moved before this point, since the ++;; profiling call to mcount can use various registers that aren't ++;; saved or used to pass arguments. ++ ++(define_insn "blockage" ++ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] ++ "" ++ "" ++ [(set_attr "type" "unknown") ++ (set_attr "length" "0")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Jumps and Calls ++;* ++;***************************************************************************** ++ ++(define_insn "indirect_jump" ++ [(set (pc) (match_operand:SI 0 "register_operand" "r"))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "jump" ++ [(set (pc) ++ (label_ref (match_operand 0 "" "")))] ++ "" ++ "br\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "indirect_call" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "indirect_call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%1" ++) ++ ++(define_expand "call" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_expand "call_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_insn "*call" ++ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) ++ (match_operand 1 "" "")) ++ (clobber (match_operand:SI 2 "register_operand" "=r"))] ++ "" ++ "call\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "*call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) ++ (match_operand 2 "" ""))) ++ (clobber (match_operand:SI 3 "register_operand" "=r"))] ++ "" ++ "call\\t%1" ++ [(set_attr "type" "control")]) ++ ++(define_expand "sibcall" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))])] ++ "" ++ { ++ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); ++ ++ if (operands[2] == NULL_RTX) ++ operands[2] = const0_rtx; ++ } ++) ++ ++(define_expand "sibcall_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))])] ++ "" ++ { ++ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); ++ ++ if (operands[3] == NULL_RTX) ++ operands[3] = const0_rtx; ++ } ++) ++ ++(define_insn "sibcall_insn" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))] ++ "" ++ "jmp\\t%0" ++) ++ ++(define_insn "sibcall_value_insn" ++ [(set (match_operand 0 "register_operand" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))] ++ "" ++ "jmp\\t%1" ++) ++ ++ ++ ++ ++(define_expand "tablejump" ++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))])] ++ "" ++ "" ++) ++ ++(define_insn "*tablejump" ++ [(set (pc) ++ (match_operand:SI 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Comparisons ++;* ++;***************************************************************************** ++;; Flow here is rather complex (based on MIPS): ++;; ++;; 1) The cmp{si,di,sf,df} routine is called. It deposits the ++;; arguments into the branch_cmp array, and the type into ++;; branch_type. No RTL is generated. ++;; ++;; 2) The appropriate branch define_expand is called, which then ++;; creates the appropriate RTL for the comparison and branch. ++;; Different CC modes are used, based on what type of branch is ++;; done, so that we can constrain things appropriately. There ++;; are assumptions in the rest of GCC that break if we fold the ++;; operands into the branchs for integer operations, and use cc0 ++;; for floating point, so we use the fp status register instead. ++;; If needed, an appropriate temporary is created to hold the ++;; of the integer compare. ++ ++(define_expand "cmpsi" ++ [(set (cc0) ++ (compare:CC (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "arith_operand" "")))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++(define_expand "tstsi" ++ [(set (cc0) ++ (match_operand:SI 0 "register_operand" ""))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = const0_rtx; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* setting a register from a comparison ++;* ++;***************************************************************************** ++ ++(define_expand "seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpeq%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpne%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmplt\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpge%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpge\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmplt%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpltu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpgeu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpgeu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpltu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* branches ++;* ++;***************************************************************************** ++ ++(define_insn "*cbranch" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:SI 2 "reg_or_0_operand" "rM") ++ (match_operand:SI 3 "reg_or_0_operand" "rM")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ "b%0\\t%z2, %z3, %l1" ++ [(set_attr "type" "control")]) ++ ++ ++(define_expand "beq" ++ [(set (pc) ++ (if_then_else (eq:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bne" ++ [(set (pc) ++ (if_then_else (ne:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgt" ++ [(set (pc) ++ (if_then_else (gt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bge" ++ [(set (pc) ++ (if_then_else (ge:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "ble" ++ [(set (pc) ++ (if_then_else (le:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "blt" ++ [(set (pc) ++ (if_then_else (lt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgtu" ++ [(set (pc) ++ (if_then_else (gtu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bgeu" ++ [(set (pc) ++ (if_then_else (geu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bleu" ++ [(set (pc) ++ (if_then_else (leu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bltu" ++ [(set (pc) ++ (if_then_else (ltu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* String and Block Operations ++;* ++;***************************************************************************** ++ ++; ??? This is all really a hack to get Dhrystone to work as fast as possible ++; things to be fixed: ++; * let the compiler core handle all of this, for that to work the extra ++; aliasing needs to be addressed. ++; * we use three temporary registers for loading and storing to ensure no ++; ld use stalls, this is excessive, because after the first ld/st only ++; two are needed. Only two would be needed all the way through if ++; we could schedule with other code. Consider: ++; 1 ld $1, 0($src) ++; 2 ld $2, 4($src) ++; 3 ld $3, 8($src) ++; 4 st $1, 0($dest) ++; 5 ld $1, 12($src) ++; 6 st $2, 4($src) ++; 7 etc. ++; The first store has to wait until 4. If it does not there will be one ++; cycle of stalling. However, if any other instruction could be placed ++; between 1 and 4, $3 would not be needed. ++; * In small we probably don't want to ever do this ourself because there ++; is no ld use stall. ++ ++(define_expand "movstrsi" ++ [(parallel [(set (match_operand:BLK 0 "general_operand" "") ++ (match_operand:BLK 1 "general_operand" "")) ++ (use (match_operand:SI 2 "const_int_operand" "")) ++ (use (match_operand:SI 3 "const_int_operand" "")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))])] ++ "TARGET_INLINE_MEMCPY" ++{ ++ rtx ld_addr_reg, st_addr_reg; ++ ++ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr ++ it trys to copy to a register, but does not re-try the predicate. ++ ??? Intead of fixing expr.c, I fix it here. */ ++ if (!const_int_operand (operands[2], SImode)) ++ FAIL; ++ ++ /* ??? there are some magic numbers which need to be sorted out here. ++ the basis for them is not increasing code size hugely or going ++ out of range of offset addressing */ ++ if (INTVAL (operands[3]) < 4) ++ FAIL; ++ if (!optimize ++ || (optimize_size && INTVAL (operands[2]) > 12) ++ || (optimize < 3 && INTVAL (operands[2]) > 100) ++ || INTVAL (operands[2]) > 200) ++ FAIL; ++ ++ st_addr_reg ++ = replace_equiv_address (operands[0], ++ copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); ++ ld_addr_reg ++ = replace_equiv_address (operands[1], ++ copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); ++ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, ++ operands[2], operands[3])); ++ ++ DONE; ++}) ++ ++ ++(define_insn "movstrsi_internal" ++ [(set (match_operand:BLK 0 "memory_operand" "=o") ++ (match_operand:BLK 1 "memory_operand" "o")) ++ (use (match_operand:SI 2 "const_int_operand" "i")) ++ (use (match_operand:SI 3 "const_int_operand" "i")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))] ++ "TARGET_INLINE_MEMCPY" ++{ ++ int ld_offset = INTVAL (operands[2]); ++ int ld_len = INTVAL (operands[2]); ++ int ld_reg = 0; ++ rtx ld_addr_reg = XEXP (operands[1], 0); ++ int st_offset = INTVAL (operands[2]); ++ int st_len = INTVAL (operands[2]); ++ int st_reg = 0; ++ rtx st_addr_reg = XEXP (operands[0], 0); ++ int delay_count = 0; ++ ++ /* ops[0] is the address used by the insn ++ ops[1] is the register being loaded or stored */ ++ rtx ops[2]; ++ ++ if (INTVAL (operands[3]) < 4) ++ abort (); ++ ++ while (ld_offset >= 4) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldw\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 4; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 2) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldh\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 2; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 1) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldb\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 1; ++ delay_count++; ++ } ++ ++ while (st_offset >= 4) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ while (st_offset >= 2) ++ { ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("sth\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 2; ++ } ++ ++ while (st_offset >= 1) ++ { ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stb\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 1; ++ } ++ ++ return ""; ++} ++; ??? lengths are not being used yet, but I will probably forget ++; to update this once I am using lengths, so set it to something ++; definetely big enough to cover it. 400 allows for 200 bytes ++; of motion. ++ [(set_attr "length" "400")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Custom instructions ++;* ++;***************************************************************************** ++ ++(define_constants [ ++ (CUSTOM_N 100) ++ (CUSTOM_NI 101) ++ (CUSTOM_NF 102) ++ (CUSTOM_NP 103) ++ (CUSTOM_NII 104) ++ (CUSTOM_NIF 105) ++ (CUSTOM_NIP 106) ++ (CUSTOM_NFI 107) ++ (CUSTOM_NFF 108) ++ (CUSTOM_NFP 109) ++ (CUSTOM_NPI 110) ++ (CUSTOM_NPF 111) ++ (CUSTOM_NPP 112) ++ (CUSTOM_IN 113) ++ (CUSTOM_INI 114) ++ (CUSTOM_INF 115) ++ (CUSTOM_INP 116) ++ (CUSTOM_INII 117) ++ (CUSTOM_INIF 118) ++ (CUSTOM_INIP 119) ++ (CUSTOM_INFI 120) ++ (CUSTOM_INFF 121) ++ (CUSTOM_INFP 122) ++ (CUSTOM_INPI 123) ++ (CUSTOM_INPF 124) ++ (CUSTOM_INPP 125) ++ (CUSTOM_FN 126) ++ (CUSTOM_FNI 127) ++ (CUSTOM_FNF 128) ++ (CUSTOM_FNP 129) ++ (CUSTOM_FNII 130) ++ (CUSTOM_FNIF 131) ++ (CUSTOM_FNIP 132) ++ (CUSTOM_FNFI 133) ++ (CUSTOM_FNFF 134) ++ (CUSTOM_FNFP 135) ++ (CUSTOM_FNPI 136) ++ (CUSTOM_FNPF 137) ++ (CUSTOM_FNPP 138) ++ (CUSTOM_PN 139) ++ (CUSTOM_PNI 140) ++ (CUSTOM_PNF 141) ++ (CUSTOM_PNP 142) ++ (CUSTOM_PNII 143) ++ (CUSTOM_PNIF 144) ++ (CUSTOM_PNIP 145) ++ (CUSTOM_PNFI 146) ++ (CUSTOM_PNFF 147) ++ (CUSTOM_PNFP 148) ++ (CUSTOM_PNPI 149) ++ (CUSTOM_PNPF 150) ++ (CUSTOM_PNPP 151) ++]) ++ ++ ++(define_insn "custom_n" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] ++ "" ++ "custom\\t%0, zero, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ni" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_np" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nii" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nif" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nip" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nff" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_in" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ini" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++(define_insn "custom_fn" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fni" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnii" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnif" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnip" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnff" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_pn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pni" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Misc ++;* ++;***************************************************************************** ++ ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop\\t" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "sync" ++ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] ++ "" ++ "sync\\t" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "rdctl" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))] ++ "" ++ "rdctl\\t%0, ctl%1" ++ [(set_attr "type" "control")]) ++ ++(define_insn "wrctl" ++ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") ++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_WRCTL)] ++ "" ++ "wrctl\\tctl%0, %1" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Peepholes ++;* ++;***************************************************************************** ++ ++ +--- gcc-3.4.3/gcc/config/nios2/t-nios2 ++++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2 +@@ -0,0 +1,123 @@ ++## ++## Compiler flags to use when compiling libgcc2.c. ++## ++## LIB2FUNCS_EXTRA ++## A list of source file names to be compiled or assembled and inserted into libgcc.a. ++ ++LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ ++ $(srcdir)/config/nios2/lib2-divmod-hi.c \ ++ $(srcdir)/config/nios2/lib2-divtable.c \ ++ $(srcdir)/config/nios2/lib2-mul.c ++ ++## ++## Floating Point Emulation ++## To have GCC include software floating point libraries in libgcc.a define FPBIT ++## and DPBIT along with a few rules as follows: ++## ++## # We want fine grained libraries, so use the new code ++## # to build the floating point emulation libraries. ++FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c ++DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c ++ ++TARGET_LIBGCC2_CFLAGS = -O2 ++ ++# FLOAT_ONLY - no doubles ++# SMALL_MACHINE - QI/HI is faster than SI ++# Actually SMALL_MACHINE uses chars and shorts instead of ints ++# since ints (16-bit ones as they are today) are at least as fast ++# as chars and shorts, don't define SMALL_MACHINE ++# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) ++ ++$(FPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '#define FLOAT' > ${FPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT} ++ ++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '' > ${DPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT} ++ ++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o ++ ++# Assemble startup files. ++$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm ++ ++$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm ++ ++ ++## You may need to provide additional #defines at the beginning of ++## fp-bit.c and dp-bit.c to control target endianness and other options ++## ++## CRTSTUFF_T_CFLAGS ++## Special flags used when compiling crtstuff.c. See Initialization. ++## ++## CRTSTUFF_T_CFLAGS_S ++## Special flags used when compiling crtstuff.c for shared linking. Used ++## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. ++## ++## MULTILIB_OPTIONS ++## For some targets, invoking GCC in different ways produces objects that ++## can not be linked together. For example, for some targets GCC produces ++## both big and little endian code. For these targets, you must arrange ++## for multiple versions of libgcc.a to be compiled, one for each set of ++## incompatible options. When GCC invokes the linker, it arranges to link ++## in the right version of libgcc.a, based on the command line options ++## used. ++## The MULTILIB_OPTIONS macro lists the set of options for which special ++## versions of libgcc.a must be built. Write options that are mutually ++## incompatible side by side, separated by a slash. Write options that may ++## be used together separated by a space. The build procedure will build ++## all combinations of compatible options. ++## ++## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, ++## Makefile will build special versions of libgcc.a using the following ++## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, ++## and -m68020 -msoft-float. ++ ++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx ++ ++## MULTILIB_DIRNAMES ++## If MULTILIB_OPTIONS is used, this variable specifies the directory names ++## that should be used to hold the various libraries. Write one element in ++## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If ++## MULTILIB_DIRNAMES is not used, the default value will be ++## MULTILIB_OPTIONS, with all slashes treated as spaces. ++## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, ++## then the default value of MULTILIB_DIRNAMES is m68000 m68020 ++## msoft-float. You may specify a different value if you desire a ++## different set of directory names. ++ ++# MULTILIB_DIRNAMES = ++ ++## MULTILIB_MATCHES ++## Sometimes the same option may be written in two different ways. If an ++## option is listed in MULTILIB_OPTIONS, GCC needs to know about any ++## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the ++## form option=option to describe all relevant synonyms. For example, ++## m68000=mc68000 m68020=mc68020. ++## ++## MULTILIB_EXCEPTIONS ++## Sometimes when there are multiple sets of MULTILIB_OPTIONS being ++## specified, there are combinations that should not be built. In that ++## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in ++## shell case syntax that should not be built. ++## For example, in the PowerPC embedded ABI support, it is not desirable to ++## build libraries compiled with the -mcall-aix option and either of the ++## -fleading-underscore or -mlittle options at the same time. Therefore ++## MULTILIB_EXCEPTIONS is set to ++## ++## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* ++## ++ ++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* ++ ++## ++## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building ++## multiple versions of libgcc.a certain options should always be passed on ++## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list ++## of options to be used for all builds. ++## ++ +--- gcc-3.4.3/gcc/config.gcc ++++ gcc-3.4.3-nios2/gcc/config.gcc +@@ -1321,6 +1321,10 @@ m32rle-*-linux*) + thread_file='posix' + fi + ;; ++# JBG ++nios2-*-* | nios2-*-*) ++ tm_file="elfos.h ${tm_file}" ++ ;; + # m68hc11 and m68hc12 share the same machine description. + m68hc11-*-*|m6811-*-*) + tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h" +--- gcc-3.4.3/gcc/cse.c ++++ gcc-3.4.3-nios2/gcc/cse.c +@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code + #ifdef FLOAT_STORE_FLAG_VALUE + REAL_VALUE_TYPE fsfv; + #endif ++#ifdef __nios2__ ++ if (p->is_const) ++ break; ++#endif + + /* If the entry isn't valid, skip it. */ + if (! exp_equiv_p (p->exp, p->exp, 1, 0)) +--- gcc-3.4.3/gcc/doc/extend.texi ++++ gcc-3.4.3-nios2/gcc/doc/extend.texi +@@ -5636,12 +5636,118 @@ to those machines. Generally these gene + instructions, but allow the compiler to schedule those calls. + + @menu ++* Altera Nios II Built-in Functions:: + * Alpha Built-in Functions:: + * ARM Built-in Functions:: + * X86 Built-in Functions:: + * PowerPC AltiVec Built-in Functions:: + @end menu + ++@node Altera Nios II Built-in Functions ++@subsection Altera Nios II Built-in Functions ++ ++These built-in functions are available for the Altera Nios II ++family of processors. ++ ++The following built-in functions are always available. They ++all generate the machine instruction that is part of the name. ++ ++@example ++int __builtin_ldbio (volatile const void *) ++int __builtin_ldbuio (volatile const void *) ++int __builtin_ldhio (volatile const void *) ++int __builtin_ldhuio (volatile const void *) ++int __builtin_ldwio (volatile const void *) ++void __builtin_stbio (volatile void *, int) ++void __builtin_sthio (volatile void *, int) ++void __builtin_stwio (volatile void *, int) ++void __builtin_sync (void) ++int __builtin_rdctl (int) ++void __builtin_wrctl (int, int) ++@end example ++ ++The following built-in functions are always available. They ++all generate a Nios II Custom Instruction. The name of the ++function represents the types that the function takes and ++returns. The letter before the @code{n} is the return type ++or void if absent. The @code{n} represnts the first parameter ++to all the custom instructions, the custom instruction number. ++The two letters after the @code{n} represent the up to two ++parameters to the function. ++ ++The letters reprsent the following data types: ++@table @code ++@item ++@code{void} for return type and no parameter for parameter types. ++ ++@item i ++@code{int} for return type and parameter type ++ ++@item f ++@code{float} for return type and parameter type ++ ++@item p ++@code{void *} for return type and parameter type ++ ++@end table ++ ++And the function names are: ++@example ++void __builtin_custom_n (void) ++void __builtin_custom_ni (int) ++void __builtin_custom_nf (float) ++void __builtin_custom_np (void *) ++void __builtin_custom_nii (int, int) ++void __builtin_custom_nif (int, float) ++void __builtin_custom_nip (int, void *) ++void __builtin_custom_nfi (float, int) ++void __builtin_custom_nff (float, float) ++void __builtin_custom_nfp (float, void *) ++void __builtin_custom_npi (void *, int) ++void __builtin_custom_npf (void *, float) ++void __builtin_custom_npp (void *, void *) ++int __builtin_custom_in (void) ++int __builtin_custom_ini (int) ++int __builtin_custom_inf (float) ++int __builtin_custom_inp (void *) ++int __builtin_custom_inii (int, int) ++int __builtin_custom_inif (int, float) ++int __builtin_custom_inip (int, void *) ++int __builtin_custom_infi (float, int) ++int __builtin_custom_inff (float, float) ++int __builtin_custom_infp (float, void *) ++int __builtin_custom_inpi (void *, int) ++int __builtin_custom_inpf (void *, float) ++int __builtin_custom_inpp (void *, void *) ++float __builtin_custom_fn (void) ++float __builtin_custom_fni (int) ++float __builtin_custom_fnf (float) ++float __builtin_custom_fnp (void *) ++float __builtin_custom_fnii (int, int) ++float __builtin_custom_fnif (int, float) ++float __builtin_custom_fnip (int, void *) ++float __builtin_custom_fnfi (float, int) ++float __builtin_custom_fnff (float, float) ++float __builtin_custom_fnfp (float, void *) ++float __builtin_custom_fnpi (void *, int) ++float __builtin_custom_fnpf (void *, float) ++float __builtin_custom_fnpp (void *, void *) ++void * __builtin_custom_pn (void) ++void * __builtin_custom_pni (int) ++void * __builtin_custom_pnf (float) ++void * __builtin_custom_pnp (void *) ++void * __builtin_custom_pnii (int, int) ++void * __builtin_custom_pnif (int, float) ++void * __builtin_custom_pnip (int, void *) ++void * __builtin_custom_pnfi (float, int) ++void * __builtin_custom_pnff (float, float) ++void * __builtin_custom_pnfp (float, void *) ++void * __builtin_custom_pnpi (void *, int) ++void * __builtin_custom_pnpf (void *, float) ++void * __builtin_custom_pnpp (void *, void *) ++@end example ++ ++ + @node Alpha Built-in Functions + @subsection Alpha Built-in Functions + +--- gcc-3.4.3/gcc/doc/invoke.texi ++++ gcc-3.4.3-nios2/gcc/doc/invoke.texi +@@ -337,6 +337,14 @@ in the following sections. + @item Machine Dependent Options + @xref{Submodel Options,,Hardware Models and Configurations}. + ++@emph{Altera Nios II Options} ++@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol ++-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol ++-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol ++-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol ++-mno-hw-div -mhw-div @gol ++-msys-crt0= -msys-lib= -msys=nosys } ++ + @emph{M680x0 Options} + @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol + -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol +@@ -5836,6 +5844,7 @@ machine description. The default for th + that macro, which enables you to change the defaults. + + @menu ++* Altera Nios II Options:: + * M680x0 Options:: + * M68hc1x Options:: + * VAX Options:: +@@ -5871,6 +5880,103 @@ that macro, which enables you to change + * FRV Options:: + @end menu + ++ ++@node Altera Nios II Options ++@subsection Altera Nios II Options ++@cindex Altera Nios II options ++ ++These are the @samp{-m} options defined for the Altera Nios II ++processor. ++ ++@table @gcctabopt ++ ++@item -msmallc ++@opindex msmallc ++ ++Link with a limited version of the C library, -lsmallc. For more ++information see the C Library Documentation. ++ ++ ++@item -mbypass-cache ++@itemx -mno-bypass-cache ++@opindex mno-bypass-cache ++@opindex mbypass-cache ++ ++Force all load and store instructions to always bypass cache by ++using io variants of the instructions. The default is to not ++bypass the cache. ++ ++@item -mno-cache-volatile ++@itemx -mcache-volatile ++@opindex mcache-volatile ++@opindex mno-cache-volatile ++ ++Volatile memory access bypass the cache using the io variants of ++the ld and st instructions. The default is to cache volatile ++accesses. ++ ++-mno-cache-volatile is deprecated and will be deleted in a ++future GCC release. ++ ++ ++@item -mno-inline-memcpy ++@itemx -minline-memcpy ++@opindex mno-inline-memcpy ++@opindex minline-memcpy ++ ++Do not inline memcpy. The default is to inline when -O is on. ++ ++ ++@item -mno-fast-sw-div ++@itemx -mfast-sw-div ++@opindex mno-fast-sw-div ++@opindex mfast-sw-div ++ ++Do no use table based fast divide for small numbers. The default ++is to use the fast divide at -O3 and above. ++ ++ ++@item -mno-hw-mul ++@itemx -mhw-mul ++@itemx -mno-hw-mulx ++@itemx -mhw-mulx ++@itemx -mno-hw-div ++@itemx -mhw-div ++@opindex mno-hw-mul ++@opindex mhw-mul ++@opindex mno-hw-mulx ++@opindex mhw-mulx ++@opindex mno-hw-div ++@opindex mhw-div ++ ++Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of ++instructions by the compiler. The default is to emit @code{mul} ++and not emit @code{div} and @code{mulx}. ++ ++The different combinations of @code{mul} and @code{mulx} instructions ++generate a different multilib options. ++ ++ ++@item -msys-crt0=@var{startfile} ++@opindex msys-crt0 ++ ++@var{startfile} is the file name of the startfile (crt0) to use ++when linking. The default is crt0.o that comes with libgloss ++and is only suitable for use with the instruction set ++simulator. ++ ++@item -msys-lib=@var{systemlib} ++@itemx -msys-lib=nosys ++@opindex msys-lib ++ ++@var{systemlib} is the library name of the library which provides ++the system calls required by the C library, e.g. @code{read}, @code{write} ++etc. The default is to use nosys, this library provides ++stub implementations of the calls and is part of libgloss. ++ ++@end table ++ ++ + @node M680x0 Options + @subsection M680x0 Options + @cindex M680x0 options +--- gcc-3.4.3/gcc/doc/md.texi ++++ gcc-3.4.3-nios2/gcc/doc/md.texi +@@ -1335,6 +1335,49 @@ However, here is a summary of the machin + available on some particular machines. + + @table @emph ++ ++@item Altera Nios II family---@file{nios2.h} ++@table @code ++ ++@item I ++Integer that is valid as an immediate operand in an ++instruction taking a signed 16-bit number. Range ++@minus{}32768 to 32767. ++ ++@item J ++Integer that is valid as an immediate operand in an ++instruction taking an unsigned 16-bit number. Range ++0 to 65535. ++ ++@item K ++Integer that is valid as an immediate operand in an ++instruction taking only the upper 16-bits of a ++32-bit number. Range 32-bit numbers with the lower ++16-bits being 0. ++ ++@item L ++Integer that is valid as an immediate operand for a ++shift instruction. Range 0 to 31. ++ ++ ++@item M ++Integer that is valid as an immediate operand for ++only the value 0. Can be used in conjunction with ++the format modifier @code{z} to use @code{r0} ++instead of @code{0} in the assembly output. ++ ++@item N ++Integer that is valid as an immediate operand for ++a custom instruction opcode. Range 0 to 255. ++ ++@item S ++Matches immediates which are addresses in the small ++data section and therefore can be added to @code{gp} ++as a 16-bit immediate to re-create their 32-bit value. ++ ++@end table ++ ++ + @item ARM family---@file{arm.h} + @table @code + @item f diff --git a/misc/buildroot/toolchain/gcc/3.4.5/arm-softfloat.patch.conditional b/misc/buildroot/toolchain/gcc/3.4.5/arm-softfloat.patch.conditional new file mode 100644 index 000000000..19d1b90da --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.5/arm-softfloat.patch.conditional @@ -0,0 +1,270 @@ +Note... modified my mjn3 to not conflict with the big endian arm patch. +Warning!!! Only the linux target is aware of TARGET_ENDIAN_DEFAULT. +Also changed + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{!mcpu=*:-mcpu=xscale} \ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +to + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +in gcc/config/arm/linux-elf.h. +# +# Submitted: +# +# Dimitry Andric , 2004-05-01 +# +# Description: +# +# Nicholas Pitre released this patch for gcc soft-float support here: +# http://lists.arm.linux.org.uk/pipermail/linux-arm/2003-October/006436.html +# +# This version has been adapted to work with gcc 3.4.0. +# +# The original patch doesn't distinguish between softfpa and softvfp modes +# in the way Nicholas Pitre probably meant. His description is: +# +# "Default is to use APCS-32 mode with soft-vfp. The old Linux default for +# floats can be achieved with -mhard-float or with the configure +# --with-float=hard option. If -msoft-float or --with-float=soft is used then +# software float support will be used just like the default but with the legacy +# big endian word ordering for double float representation instead." +# +# Which means the following: +# +# * If you compile without -mhard-float or -msoft-float, you should get +# software floating point, using the VFP format. The produced object file +# should have these flags in its header: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# * If you compile with -mhard-float, you should get hardware floating point, +# which always uses the FPA format. Object file header flags should be: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# * If you compile with -msoft-float, you should get software floating point, +# using the FPA format. This is done for compatibility reasons with many +# existing distributions. Object file header flags should be: +# +# private flags = 200: [APCS-32] [FPA float format] [software FP] +# +# The original patch from Nicholas Pitre contained the following constructs: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" +# +# However, gcc doesn't accept this ";:" notation, used in the 3rd line. This +# is probably the reason Robert Schwebel modified it to: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa -mfpu=softvfp}}" +# +# But this causes the following behaviour: +# +# * If you compile without -mhard-float or -msoft-float, the compiler generates +# software floating point instructions, but *nothing* is passed to the +# assembler, which results in an object file which has flags: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# This is not correct! +# +# * If you compile with -mhard-float, the compiler generates hardware floating +# point instructions, and passes "-mfpu=fpa" to the assembler, which results +# in an object file which has the same flags as in the previous item, but now +# those *are* correct. +# +# * If you compile with -msoft-float, the compiler generates software floating +# point instructions, and passes "-mfpu=softfpa -mfpu=softvfp" (in that +# order) to the assembler, which results in an object file with flags: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# This is not correct, because the last "-mfpu=" option on the assembler +# command line determines the actual FPU convention used (which should be FPA +# in this case). +# +# Therefore, I modified this patch to get the desired behaviour. Every +# instance of the notation: +# +# %{msoft-float:-mfpu=softfpa -mfpu=softvfp} +# +# was changed to: +# +# %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp} +# +# I also did the following: +# +# * Modified all TARGET_DEFAULT macros I could find to include ARM_FLAG_VFP, to +# be consistent with Nicholas' original patch. +# * Removed any "msoft-float" or "mhard-float" from all MULTILIB_DEFAULTS +# macros I could find. I think that if you compile without any options, you +# would like to get the defaults. :) +# * Removed the extra -lfloat option from LIBGCC_SPEC, since it isn't needed +# anymore. (The required functions are now in libgcc.) + +diff -urN gcc-3.4.1-old/gcc/config/arm/coff.h gcc-3.4.1/gcc/config/arm/coff.h +--- gcc-3.4.1-old/gcc/config/arm/coff.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/coff.h 2004-09-02 21:51:15.000000000 -0500 +@@ -31,11 +31,16 @@ + #define TARGET_VERSION fputs (" (ARM/coff)", stderr) + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork" } + #endif + + /* This is COFF, but prefer stabs. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/elf.h gcc-3.4.1/gcc/config/arm/elf.h +--- gcc-3.4.1-old/gcc/config/arm/elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -46,7 +46,9 @@ + + #ifndef SUBTARGET_ASM_FLOAT_SPEC + #define SUBTARGET_ASM_FLOAT_SPEC "\ +-%{mapcs-float:-mfloat} %{msoft-float:-mfpu=softfpa}" ++%{mapcs-float:-mfloat} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + #endif + + #ifndef ASM_SPEC +@@ -106,12 +108,17 @@ + #endif + + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } + #endif + + #define TARGET_ASM_FILE_START_APP_OFF true +diff -urN gcc-3.4.1-old/gcc/config/arm/linux-elf.h gcc-3.4.1/gcc/config/arm/linux-elf.h +--- gcc-3.4.1-old/gcc/config/arm/linux-elf.h 2004-09-02 21:50:52.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h 2004-09-02 22:00:49.000000000 -0500 +@@ -44,12 +44,26 @@ + #define TARGET_LINKER_EMULATION "armelf_linux" + #endif + +-/* Default is to use APCS-32 mode. */ ++/* ++ * Default is to use APCS-32 mode with soft-vfp. ++ * The old Linux default for floats can be achieved with -mhard-float ++ * or with the configure --with-float=hard option. ++ * If -msoft-float or --with-float=soft is used then software float ++ * support will be used just like the default but with the legacy ++ * big endian word ordering for double float representation instead. ++ */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT \ +- ( ARM_FLAG_APCS_32 | \ +- ARM_FLAG_MMU_TRAPS | \ +- TARGET_ENDIAN_DEFAULT ) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_SOFT_FLOAT \ ++ | TARGET_ENDIAN_DEFAULT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_MMU_TRAPS ) ++ ++#undef SUBTARGET_EXTRA_ASM_SPEC ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +@@ -57,7 +71,7 @@ + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -72,7 +86,7 @@ + %{shared:-lc} \ + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" + +-#define LIBGCC_SPEC "%{msoft-float:-lfloat} -lgcc" ++#define LIBGCC_SPEC "-lgcc" + + /* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add + the GNU/Linux magical crtbegin.o file (see crtstuff.c) which +diff -urN gcc-3.4.1-old/gcc/config/arm/t-linux gcc-3.4.1/gcc/config/arm/t-linux +--- gcc-3.4.1-old/gcc/config/arm/t-linux 2003-09-20 16:09:07.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/t-linux 2004-09-02 21:51:15.000000000 -0500 +@@ -4,7 +4,10 @@ + LIBGCC2_DEBUG_CFLAGS = -g0 + + LIB1ASMSRC = arm/lib1funcs.asm +-LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx ++LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx \ ++ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \ ++ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ ++ _fixsfsi _fixunssfsi + + # MULTILIB_OPTIONS = mhard-float/msoft-float + # MULTILIB_DIRNAMES = hard-float soft-float +diff -urN gcc-3.4.1-old/gcc/config/arm/unknown-elf.h gcc-3.4.1/gcc/config/arm/unknown-elf.h +--- gcc-3.4.1-old/gcc/config/arm/unknown-elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/unknown-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -30,7 +30,12 @@ + + /* Default to using APCS-32 and software floating point. */ + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + /* Now we define the strings used to build the spec file. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/xscale-elf.h gcc-3.4.1/gcc/config/arm/xscale-elf.h +--- gcc-3.4.1-old/gcc/config/arm/xscale-elf.h 2003-07-01 18:26:43.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/xscale-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -49,11 +49,12 @@ + endian, regardless of the endian-ness of the memory + system. */ + +-#define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +- %{mhard-float:-mfpu=fpa} \ +- %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{!mcpu=*:-mcpu=xscale} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "mlittle-endian", "mno-thumb-interwork", "marm", "msoft-float" } ++ { "mlittle-endian", "mno-thumb-interwork", "marm" } + #endif diff --git a/misc/buildroot/toolchain/gcc/3.4.6/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/3.4.6/300-libstdc++-pic.patch new file mode 100644 index 000000000..9f304a4c4 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/300-libstdc++-pic.patch @@ -0,0 +1,47 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -224,6 +224,10 @@ + @OPT_LDFLAGS@ @SECTION_LDFLAGS@ $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCPP_BUILD_DEBUG + all-local: build_debug + +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -585,7 +585,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -618,6 +618,7 @@ + distclean-tags distdir dvi dvi-am info info-am install \ + install-am install-data install-data-am install-data-local \ + install-exec install-exec-am install-info install-info-am \ ++ install-exec-local \ + install-man install-strip install-toolexeclibLTLIBRARIES \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ +@@ -707,6 +708,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/3.4.6/304-index_macro.patch b/misc/buildroot/toolchain/gcc/3.4.6/304-index_macro.patch new file mode 100644 index 000000000..1fac112fa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/304-index_macro.patch @@ -0,0 +1,24 @@ +--- gcc-4.1.0/libstdc++-v3/include/ext/rope.mps 2006-03-24 01:49:51 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/rope 2006-03-24 01:49:37 +0100 +@@ -59,6 +59,9 @@ + #include + #include + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + # ifdef __GC + # define __GC_CONST const + # else +--- gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h.mps 2006-03-24 01:50:04 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h 2006-03-24 01:50:28 +0100 +@@ -53,6 +53,9 @@ + #include // For uninitialized_copy_n + #include // For power + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + namespace __gnu_cxx + { + using std::size_t; diff --git a/misc/buildroot/toolchain/gcc/3.4.6/600-gcc34-arm-ldm-peephole.patch b/misc/buildroot/toolchain/gcc/3.4.6/600-gcc34-arm-ldm-peephole.patch new file mode 100644 index 000000000..0c370502c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/600-gcc34-arm-ldm-peephole.patch @@ -0,0 +1,65 @@ +--- gcc-3.4.0/gcc/config/arm/arm.md.arm-ldm-peephole 2004-01-13 08:24:37.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.md 2004-04-24 18:18:04.000000000 -0400 +@@ -8810,13 +8810,16 @@ + (set_attr "length" "4,8,8")] + ) + ++; Try to convert LDR+LDR+arith into [add+]LDM+arith ++; On XScale, LDM is always slower than two LDRs, so only do this if ++; optimising for size. + (define_insn "*arith_adjacentmem" + [(set (match_operand:SI 0 "s_register_operand" "=r") + (match_operator:SI 1 "shiftable_operator" + [(match_operand:SI 2 "memory_operand" "m") + (match_operand:SI 3 "memory_operand" "m")])) + (clobber (match_scratch:SI 4 "=r"))] +- "TARGET_ARM && adjacent_mem_locations (operands[2], operands[3])" ++ "TARGET_ARM && (!arm_tune_xscale || optimize_size) && adjacent_mem_locations (operands[2], operands[3])" + "* + { + rtx ldm[3]; +@@ -8851,6 +8854,8 @@ + } + if (val1 && val2) + { ++ /* This would be a loss on a Harvard core, but adjacent_mem_locations() ++ will prevent it from happening. */ + rtx ops[3]; + ldm[0] = ops[0] = operands[4]; + ops[1] = XEXP (XEXP (operands[2], 0), 0); +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm-peephole 2004-04-24 18:16:25.000000000 -0400 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:18:04.000000000 -0400 +@@ -4838,6 +4841,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* ldmia */ + +@@ -5064,6 +5072,11 @@ + *load_offset = unsorted_offsets[order[0]]; + } + ++ /* For XScale a two-word LDM is a performance loss, so only do this if ++ size is more important. See comments in arm_gen_load_multiple. */ ++ if (nops == 2 && arm_tune_xscale && !optimize_size) ++ return 0; ++ + if (unsorted_offsets[order[0]] == 0) + return 1; /* stmia */ + +--- gcc-3.4.0/gcc/genpeep.c.arm-ldm-peephole 2003-07-05 01:27:22.000000000 -0400 ++++ gcc-3.4.0/gcc/genpeep.c 2004-04-24 18:18:04.000000000 -0400 +@@ -381,6 +381,7 @@ + printf ("#include \"recog.h\"\n"); + printf ("#include \"except.h\"\n\n"); + printf ("#include \"function.h\"\n\n"); ++ printf ("#include \"flags.h\"\n\n"); + + printf ("#ifdef HAVE_peephole\n"); + printf ("extern rtx peep_operand[];\n\n"); diff --git a/misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm-peephole2.patch b/misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm-peephole2.patch new file mode 100644 index 000000000..27f7c07db --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm-peephole2.patch @@ -0,0 +1,42 @@ +The 30_all_gcc34-arm-ldm-peephole.patch from Debian was conflicting +with the newer 36_all_pr16201-fix.patch, so i cut out the hunk from +it that was causing problems and grabbed an updated version from +upstream cvs. + +Index: gcc/config/arm/arm.c +=================================================================== +RCS file: /cvsroot/gcc/gcc/gcc/config/arm/arm.c,v +retrieving revision 1.432 +retrieving revision 1.433 +diff -u -r1.432 -r1.433 +--- gcc-3.4.4/gcc/config/arm/arm.c 29 Mar 2005 03:00:23 -0000 1.432 ++++ gcc-3.4.4/gcc/config/arm/arm.c 1 Apr 2005 11:02:22 -0000 1.433 +@@ -5139,6 +5139,10 @@ + int + adjacent_mem_locations (rtx a, rtx b) + { ++ /* We don't guarantee to preserve the order of these memory refs. */ ++ if (volatile_refs_p (a) || volatile_refs_p (b)) ++ return 0; ++ + if ((GET_CODE (XEXP (a, 0)) == REG + || (GET_CODE (XEXP (a, 0)) == PLUS + && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT)) +@@ -5178,6 +5182,17 @@ + return 0; + + val_diff = val1 - val0; ++ ++ if (arm_ld_sched) ++ { ++ /* If the target has load delay slots, then there's no benefit ++ to using an ldm instruction unless the offset is zero and ++ we are optimizing for size. */ ++ return (optimize_size && (REGNO (reg0) == REGNO (reg1)) ++ && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4) ++ && (val_diff == 4 || val_diff == -4)); ++ } ++ + return ((REGNO (reg0) == REGNO (reg1)) + && (val_diff == 4 || val_diff == -4)); + } diff --git a/misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm.patch b/misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm.patch new file mode 100644 index 000000000..142052fdf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/601-gcc34-arm-ldm.patch @@ -0,0 +1,119 @@ +--- gcc-3.4.0/gcc/config/arm/arm.c.arm-ldm 2004-02-27 09:51:05.000000000 -0500 ++++ gcc-3.4.0/gcc/config/arm/arm.c 2004-04-24 18:16:25.000000000 -0400 +@@ -8520,6 +8520,26 @@ + return_used_this_function = 0; + } + ++/* Return the number (counting from 0) of ++ the least significant set bit in MASK. */ ++ ++#ifdef __GNUC__ ++inline ++#endif ++static int ++number_of_first_bit_set (mask) ++ int mask; ++{ ++ int bit; ++ ++ for (bit = 0; ++ (mask & (1 << bit)) == 0; ++ ++bit) ++ continue; ++ ++ return bit; ++} ++ + const char * + arm_output_epilogue (rtx sibling) + { +@@ -8753,27 +8773,47 @@ + saved_regs_mask |= (1 << PC_REGNUM); + } + +- /* Load the registers off the stack. If we only have one register +- to load use the LDR instruction - it is faster. */ +- if (saved_regs_mask == (1 << LR_REGNUM)) +- { +- /* The exception handler ignores the LR, so we do +- not really need to load it off the stack. */ +- if (eh_ofs) +- asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); +- else +- asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM); +- } +- else if (saved_regs_mask) ++ if (saved_regs_mask) + { +- if (saved_regs_mask & (1 << SP_REGNUM)) +- /* Note - write back to the stack register is not enabled +- (ie "ldmfd sp!..."). We know that the stack pointer is +- in the list of registers and if we add writeback the +- instruction becomes UNPREDICTABLE. */ +- print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ /* Load the registers off the stack. If we only have one register ++ to load use the LDR instruction - it is faster. */ ++ if (bit_count (saved_regs_mask) == 1) ++ { ++ int reg = number_of_first_bit_set (saved_regs_mask); ++ ++ switch (reg) ++ { ++ case SP_REGNUM: ++ /* Mustn't use base writeback when loading SP. */ ++ asm_fprintf (f, "\tldr\t%r, [%r]\n", SP_REGNUM, SP_REGNUM); ++ break; ++ ++ case LR_REGNUM: ++ if (eh_ofs) ++ { ++ /* The exception handler ignores the LR, so we do ++ not really need to load it off the stack. */ ++ asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM); ++ break; ++ } ++ /* else fall through */ ++ ++ default: ++ asm_fprintf (f, "\tldr\t%r, [%r], #4\n", reg, SP_REGNUM); ++ break; ++ } ++ } + else +- print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ { ++ if (saved_regs_mask & (1 << SP_REGNUM)) ++ /* Note - write back to the stack register is not enabled ++ (ie "ldmfd sp!..."). We know that the stack pointer is ++ in the list of registers and if we add writeback the ++ instruction becomes UNPREDICTABLE. */ ++ print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask); ++ else ++ print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask); ++ } + } + + if (current_function_pretend_args_size) +@@ -11401,22 +11441,6 @@ + } + } + +-/* Return the number (counting from 0) of +- the least significant set bit in MASK. */ +- +-inline static int +-number_of_first_bit_set (int mask) +-{ +- int bit; +- +- for (bit = 0; +- (mask & (1 << bit)) == 0; +- ++bit) +- continue; +- +- return bit; +-} +- + /* Generate code to return from a thumb function. + If 'reg_containing_return_addr' is -1, then the return address is + actually on the stack, at the stack pointer. */ diff --git a/misc/buildroot/toolchain/gcc/3.4.6/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/3.4.6/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..4377c2143 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +--- gcc-3.4.1/libstdc++-v3/libmath/Makefile.am~ 2003-08-27 22:29:42.000000000 +0100 ++++ gcc-3.4.1/libstdc++-v3/libmath/Makefile.am 2004-07-22 16:41:45.152130128 +0100 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC +--- gcc-3.4.1/libstdc++-v3/fragment.am.old 2004-07-22 18:24:58.024083656 +0100 ++++ gcc-3.4.1/libstdc++-v3/fragment.am 2004-07-22 18:24:59.019932264 +0100 +@@ -18,7 +18,7 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + + + diff --git a/misc/buildroot/toolchain/gcc/3.4.6/700-pr15068-fix.patch b/misc/buildroot/toolchain/gcc/3.4.6/700-pr15068-fix.patch new file mode 100644 index 000000000..2977765c5 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/700-pr15068-fix.patch @@ -0,0 +1,44 @@ +See http://gcc.gnu.org/PR15068 + +Fixes error + +../sysdeps/generic/s_fmax.c: In function `__fmax': +../sysdeps/generic/s_fmax.c:28: internal compiler error: in elim_reg_cond, at flow.c:3257 +Please submit a full bug report, +with preprocessed source if appropriate. +See for instructions. +make[2]: *** [/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/build-glibc/math/s_fmax.o] Error 1 +make[2]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822/math' +make[1]: *** [math/others] Error 2 +make[1]: Leaving directory `/home/dank/wk/crosstool-0.28-rc35/build/arm-unknown-linux-gnu/gcc-3.4.1-glibc-20040822/glibc-20040822' +make: *** [all] Error 2 + +[ rediffed against gcc-3.4.1, with elbow grease, ending up with same thing as +http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/flow.c.diff?cvsroot=gcc&only_with_tag=csl-arm-branch&r1=1.563.4.2&r2=1.563.4.3 ] + +--- gcc-3.4.1/gcc/flow.c.old 2004-02-27 19:39:19.000000000 -0800 ++++ gcc-3.4.1/gcc/flow.c 2004-08-26 07:29:46.000000000 -0700 +@@ -1878,6 +1878,7 @@ + rtx set_src = SET_SRC (pc_set (BB_END (bb))); + rtx cond_true = XEXP (set_src, 0); + rtx reg = XEXP (cond_true, 0); ++ enum rtx_code inv_cond; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); +@@ -1886,11 +1887,13 @@ + in the form of a comparison of a register against zero. + If the condition is more complex than that, then it is safe + not to record any information. */ +- if (GET_CODE (reg) == REG ++ inv_cond = reversed_comparison_code (cond_true, BB_END (bb)); ++ if (inv_cond != UNKNOWN ++ && GET_CODE (reg) == REG + && XEXP (cond_true, 1) == const0_rtx) + { + rtx cond_false +- = gen_rtx_fmt_ee (reverse_condition (GET_CODE (cond_true)), ++ = gen_rtx_fmt_ee (inv_cond, + GET_MODE (cond_true), XEXP (cond_true, 0), + XEXP (cond_true, 1)); + if (GET_CODE (XEXP (set_src, 1)) == PC) diff --git a/misc/buildroot/toolchain/gcc/3.4.6/71_all_sh-pr16665-fix.patch b/misc/buildroot/toolchain/gcc/3.4.6/71_all_sh-pr16665-fix.patch new file mode 100644 index 000000000..680bb3978 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/71_all_sh-pr16665-fix.patch @@ -0,0 +1,43 @@ +--- gcc/gcc/config/sh/sh.c ++++ gcc/gcc/config/sh/sh.c +@@ -9106,6 +9106,15 @@ sh_output_mi_thunk (FILE *file, tree thu + } + this = FUNCTION_ARG (cum, Pmode, ptr_type_node, 1); + ++ /* In PIC case, we set PIC register to compute the target address. We ++ can use a scratch register to save and restore the original value ++ except for SHcompact. For SHcompact, use stack. */ ++ if (flag_pic && TARGET_SHCOMPACT) ++ { ++ push (PIC_OFFSET_TABLE_REGNUM); ++ emit_insn (gen_GOTaddr2picreg ()); ++ } ++ + /* For SHcompact, we only have r0 for a scratch register: r1 is the + static chain pointer (even if you can't have nested virtual functions + right now, someone might implement them sometime), and the rest of the +@@ -9188,8 +9197,24 @@ sh_output_mi_thunk (FILE *file, tree thu + assemble_external (function); + TREE_USED (function) = 1; + } ++ /* We can use scratch1 to save and restore the original value of ++ PIC register except for SHcompact. */ ++ if (flag_pic && ! TARGET_SHCOMPACT) ++ { ++ emit_move_insn (scratch1, ++ gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM)); ++ emit_insn (gen_GOTaddr2picreg ()); ++ } + funexp = XEXP (DECL_RTL (function), 0); + emit_move_insn (scratch2, funexp); ++ if (flag_pic) ++ { ++ if (! TARGET_SHCOMPACT) ++ emit_move_insn (gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM), ++ scratch1); ++ else ++ pop (PIC_OFFSET_TABLE_REGNUM); ++ } + funexp = gen_rtx_MEM (FUNCTION_MODE, scratch2); + sibcall = emit_call_insn (gen_sibcall (funexp, const0_rtx, NULL_RTX)); + SIBLING_CALL_P (sibcall) = 1; diff --git a/misc/buildroot/toolchain/gcc/3.4.6/72_all_sh-no-reorder-blocks.patch b/misc/buildroot/toolchain/gcc/3.4.6/72_all_sh-no-reorder-blocks.patch new file mode 100644 index 000000000..8b9826831 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/72_all_sh-no-reorder-blocks.patch @@ -0,0 +1,13 @@ +--- g/gcc/config/sh/sh.h ++++ g/gcc/config/sh/sh.h +@@ -422,6 +422,10 @@ + do { \ + if (LEVEL) \ + flag_omit_frame_pointer = -1; \ ++ if (LEVEL <= 2) \ ++ { \ ++ flag_reorder_blocks = 0; \ ++ } \ + if (SIZE) \ + target_flags |= SPACE_BIT; \ + if (TARGET_SHMEDIA && LEVEL > 1) \ diff --git a/misc/buildroot/toolchain/gcc/3.4.6/73_all_sh-pr20617.patch b/misc/buildroot/toolchain/gcc/3.4.6/73_all_sh-pr20617.patch new file mode 100644 index 000000000..6d8021cc7 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/73_all_sh-pr20617.patch @@ -0,0 +1,28 @@ +2005-03-24 J"orn Rennecke + + Band aid for PR target/20617: + * config/sh/lib1funcs.asm (FUNC, ALIAS): Add .hidden directive. + +--- g/gcc/config/sh/lib1funcs.asm ++++ g/gcc/config/sh/lib1funcs.asm +@@ -37,9 +37,19 @@ Boston, MA 02111-1307, USA. */ + ELF local label prefixes by J"orn Rennecke + amylaar@cygnus.com */ + ++#define ALIAS(X,Y) .global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y) ++ + #ifdef __ELF__ + #define LOCAL(X) .L_##X +-#define FUNC(X) .type X,@function ++ ++#if 1 /* ??? The export list mechanism is broken, everything that is not ++ hidden is exported. */ ++#undef FUNC ++#define FUNC(X) .type X,@function; .hidden X ++#undef ALIAS ++#define ALIAS(X,Y) .global GLOBAL(X); .set GLOBAL(X),GLOBAL(Y); .hidden GLOBAL(X) ++#endif ++ + #define ENDFUNC0(X) .Lfe_##X: .size X,.Lfe_##X-X + #define ENDFUNC(X) ENDFUNC0(X) + #else diff --git a/misc/buildroot/toolchain/gcc/3.4.6/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/3.4.6/800-arm-bigendian.patch new file mode 100644 index 000000000..04e998419 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/800-arm-bigendian.patch @@ -0,0 +1,68 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-3.4.1-dist/gcc/config/arm/linux-elf.h ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h +@@ -30,17 +30,34 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + /* Default is to use APCS-32 mode. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_APCS_32 | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 | \ ++ ARM_FLAG_MMU_TRAPS | \ ++ TARGET_ENDIAN_DEFAULT ) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -101,7 +118,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + #endif + +--- gcc-3.4.1-dist/gcc/config.gcc ++++ gcc-3.4.1/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="t-slibgcc-elf-ver t-linux arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/3.4.6/810-mips-xgot.patch b/misc/buildroot/toolchain/gcc/3.4.6/810-mips-xgot.patch new file mode 100644 index 000000000..14e8d126e --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/810-mips-xgot.patch @@ -0,0 +1,6 @@ +--- gcc.orig/gcc/config/mips/t-linux 1970-01-01 01:00:00.000000000 +0100 ++++ gcc/gcc/config/mips/t-linux 2004-08-26 18:28:12.000000000 +0200 +@@ -0,0 +1,3 @@ ++# Compile crtbegin/end with xgot so it works for both ++# normal and large GOTs. ++CRTSTUFF_T_CFLAGS = -mxgot diff --git a/misc/buildroot/toolchain/gcc/3.4.6/900-nios2.patch b/misc/buildroot/toolchain/gcc/3.4.6/900-nios2.patch new file mode 100644 index 000000000..bfa06a21c --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/900-nios2.patch @@ -0,0 +1,10211 @@ +--- gcc-3.4.3/gcc/Makefile.in ++++ gcc-3.4.3-nios2/gcc/Makefile.in +@@ -3085,7 +3085,7 @@ install-mkheaders: stmp-int-hdrs $(STMP_ + $(INSTALL_DATA) $(srcdir)/README-fixinc \ + $(DESTDIR)$(itoolsdatadir)/include/README ; \ + $(INSTALL_SCRIPT) fixinc.sh $(DESTDIR)$(itoolsdir)/fixinc.sh ; \ +- $(INSTALL_PROGRAM) fixinc/fixincl $(DESTDIR)$(itoolsdir)/fixincl ; \ ++ $(INSTALL_PROGRAM) fixinc/fixincl$(build_exeext) $(DESTDIR)$(itoolsdir)/fixincl$(build_exeext) ; \ + $(INSTALL_DATA) $(srcdir)/gsyslimits.h \ + $(DESTDIR)$(itoolsdatadir)/gsyslimits.h ; \ + else :; fi +--- gcc-3.4.3/gcc/combine.c ++++ gcc-3.4.3-nios2/gcc/combine.c +@@ -4380,6 +4380,14 @@ combine_simplify_rtx (rtx x, enum machin + mode); + } + ++#ifndef __nios2__ ++/* This screws up Nios II in this test case: ++ ++if (x & 1) ++ return 2; ++else ++ return 3; ++*/ + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT + && op1 == const0_rtx +@@ -4391,6 +4399,7 @@ combine_simplify_rtx (rtx x, enum machin + gen_lowpart_for_combine (mode, op0), + const1_rtx); + } ++#endif + + else if (STORE_FLAG_VALUE == 1 + && new_code == EQ && GET_MODE_CLASS (mode) == MODE_INT +--- gcc-3.4.3/gcc/config/nios2/crti.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crti.asm +@@ -0,0 +1,88 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just make a stack frame for the contents of the .fini and ++.init sections. Users may put any desired instructions in those ++sections. ++ ++ ++While technically any code can be put in the init and fini sections ++most stuff will not work other than stuff which obeys the call frame ++and ABI. All the call-preserved registers are saved, the call clobbered ++registers should have been saved by the code calling init and fini. ++ ++See crtstuff.c for an example of code that inserts itself in the ++init and fini sections. ++ ++See crt0.s for the code that calls init and fini. ++*/ ++ ++ .file "crti.asm" ++ ++ .section ".init" ++ .align 2 ++ .global _init ++_init: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ ++ .section ".fini" ++ .align 2 ++ .global _fini ++_fini: ++ addi sp, sp, -48 ++ stw ra, 44(sp) ++ stw r23, 40(sp) ++ stw r22, 36(sp) ++ stw r21, 32(sp) ++ stw r20, 28(sp) ++ stw r19, 24(sp) ++ stw r18, 20(sp) ++ stw r17, 16(sp) ++ stw r16, 12(sp) ++ stw fp, 8(sp) ++ mov fp, sp ++ ++ +--- gcc-3.4.3/gcc/config/nios2/crtn.asm ++++ gcc-3.4.3-nios2/gcc/config/nios2/crtn.asm +@@ -0,0 +1,70 @@ ++/* ++ Copyright (C) 2003 ++ by Jonah Graham (jgraham@altera.com) ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. ++ ++ As a special exception, if you link this library with files ++ compiled with GCC to produce an executable, this does not cause ++ the resulting executable to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. ++ ++ ++This file just makes sure that the .fini and .init sections do in ++fact return. Users may put any desired instructions in those sections. ++This file is the last thing linked into any executable. ++*/ ++ .file "crtn.asm" ++ ++ ++ ++ .section ".init" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ ++ .section ".fini" ++ ldw ra, 44(sp) ++ ldw r23, 40(sp) ++ ldw r22, 36(sp) ++ ldw r21, 32(sp) ++ ldw r20, 28(sp) ++ ldw r19, 24(sp) ++ ldw r18, 20(sp) ++ ldw r17, 16(sp) ++ ldw r16, 12(sp) ++ ldw fp, 8(sp) ++ addi sp, sp, -48 ++ ret ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod-hi.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod-hi.c +@@ -0,0 +1,123 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern HItype __modhi3 (HItype, HItype); ++extern HItype __divhi3 (HItype, HItype); ++extern HItype __umodhi3 (HItype, HItype); ++extern HItype __udivhi3 (HItype, HItype); ++ ++static UHItype udivmodhi4(UHItype, UHItype, word_type); ++ ++static UHItype ++udivmodhi4(UHItype num, UHItype den, word_type modwanted) ++{ ++ UHItype bit = 1; ++ UHItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<15))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++HItype ++__divhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodhi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__modhi3 (HItype a, HItype b) ++{ ++ word_type neg = 0; ++ HItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodhi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++HItype ++__udivhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 0); ++} ++ ++ ++HItype ++__umodhi3 (HItype a, HItype b) ++{ ++ return udivmodhi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divmod.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divmod.c +@@ -0,0 +1,126 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++extern SItype __modsi3 (SItype, SItype); ++extern SItype __divsi3 (SItype, SItype); ++extern SItype __umodsi3 (SItype, SItype); ++extern SItype __udivsi3 (SItype, SItype); ++ ++static USItype udivmodsi4(USItype, USItype, word_type); ++ ++/* 16-bit SI divide and modulo as used in NIOS */ ++ ++ ++static USItype ++udivmodsi4(USItype num, USItype den, word_type modwanted) ++{ ++ USItype bit = 1; ++ USItype res = 0; ++ ++ while (den < num && bit && !(den & (1L<<31))) ++ { ++ den <<=1; ++ bit <<=1; ++ } ++ while (bit) ++ { ++ if (num >= den) ++ { ++ num -= den; ++ res |= bit; ++ } ++ bit >>=1; ++ den >>=1; ++ } ++ if (modwanted) return num; ++ return res; ++} ++ ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = !neg; ++ } ++ ++ if (b < 0) ++ { ++ b = -b; ++ neg = !neg; ++ } ++ ++ res = udivmodsi4 (a, b, 0); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__modsi3 (SItype a, SItype b) ++{ ++ word_type neg = 0; ++ SItype res; ++ ++ if (a < 0) ++ { ++ a = -a; ++ neg = 1; ++ } ++ ++ if (b < 0) ++ b = -b; ++ ++ res = udivmodsi4 (a, b, 1); ++ ++ if (neg) ++ res = -res; ++ ++ return res; ++} ++ ++ ++SItype ++__udivsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 0); ++} ++ ++ ++SItype ++__umodsi3 (SItype a, SItype b) ++{ ++ return udivmodsi4 (a, b, 1); ++} ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-divtable.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-divtable.c +@@ -0,0 +1,46 @@ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++UQItype __divsi3_table[] = ++{ ++ 0, 0/1, 0/2, 0/3, 0/4, 0/5, 0/6, 0/7, 0/8, 0/9, 0/10, 0/11, 0/12, 0/13, 0/14, 0/15, ++ 0, 1/1, 1/2, 1/3, 1/4, 1/5, 1/6, 1/7, 1/8, 1/9, 1/10, 1/11, 1/12, 1/13, 1/14, 1/15, ++ 0, 2/1, 2/2, 2/3, 2/4, 2/5, 2/6, 2/7, 2/8, 2/9, 2/10, 2/11, 2/12, 2/13, 2/14, 2/15, ++ 0, 3/1, 3/2, 3/3, 3/4, 3/5, 3/6, 3/7, 3/8, 3/9, 3/10, 3/11, 3/12, 3/13, 3/14, 3/15, ++ 0, 4/1, 4/2, 4/3, 4/4, 4/5, 4/6, 4/7, 4/8, 4/9, 4/10, 4/11, 4/12, 4/13, 4/14, 4/15, ++ 0, 5/1, 5/2, 5/3, 5/4, 5/5, 5/6, 5/7, 5/8, 5/9, 5/10, 5/11, 5/12, 5/13, 5/14, 5/15, ++ 0, 6/1, 6/2, 6/3, 6/4, 6/5, 6/6, 6/7, 6/8, 6/9, 6/10, 6/11, 6/12, 6/13, 6/14, 6/15, ++ 0, 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, 7/9, 7/10, 7/11, 7/12, 7/13, 7/14, 7/15, ++ 0, 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, 8/9, 8/10, 8/11, 8/12, 8/13, 8/14, 8/15, ++ 0, 9/1, 9/2, 9/3, 9/4, 9/5, 9/6, 9/7, 9/8, 9/9, 9/10, 9/11, 9/12, 9/13, 9/14, 9/15, ++ 0, 10/1, 10/2, 10/3, 10/4, 10/5, 10/6, 10/7, 10/8, 10/9, 10/10, 10/11, 10/12, 10/13, 10/14, 10/15, ++ 0, 11/1, 11/2, 11/3, 11/4, 11/5, 11/6, 11/7, 11/8, 11/9, 11/10, 11/11, 11/12, 11/13, 11/14, 11/15, ++ 0, 12/1, 12/2, 12/3, 12/4, 12/5, 12/6, 12/7, 12/8, 12/9, 12/10, 12/11, 12/12, 12/13, 12/14, 12/15, ++ 0, 13/1, 13/2, 13/3, 13/4, 13/5, 13/6, 13/7, 13/8, 13/9, 13/10, 13/11, 13/12, 13/13, 13/14, 13/15, ++ 0, 14/1, 14/2, 14/3, 14/4, 14/5, 14/6, 14/7, 14/8, 14/9, 14/10, 14/11, 14/12, 14/13, 14/14, 14/15, ++ 0, 15/1, 15/2, 15/3, 15/4, 15/5, 15/6, 15/7, 15/8, 15/9, 15/10, 15/11, 15/12, 15/13, 15/14, 15/15, ++}; ++ +--- gcc-3.4.3/gcc/config/nios2/lib2-mul.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/lib2-mul.c +@@ -0,0 +1,103 @@ ++/* while we are debugging (ie compile outside of gcc build) ++ disable gcc specific headers */ ++#ifndef DEBUG_MULSI3 ++ ++ ++/* We include auto-host.h here to get HAVE_GAS_HIDDEN. This is ++ supposedly valid even though this is a "target" file. */ ++#include "auto-host.h" ++ ++ ++#include "tconfig.h" ++#include "tsystem.h" ++#include "coretypes.h" ++#include "tm.h" ++ ++ ++/* Don't use `fancy_abort' here even if config.h says to use it. */ ++#ifdef abort ++#undef abort ++#endif ++ ++ ++#ifdef HAVE_GAS_HIDDEN ++#define ATTRIBUTE_HIDDEN __attribute__ ((__visibility__ ("hidden"))) ++#else ++#define ATTRIBUTE_HIDDEN ++#endif ++ ++#include "libgcc2.h" ++ ++#else ++#define SItype int ++#define USItype unsigned int ++#endif ++ ++ ++extern SItype __mulsi3 (SItype, SItype); ++ ++SItype ++__mulsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = a; ++ ++ while (cnt) ++ { ++ if (cnt & 1) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt >>= 1; ++ } ++ ++ return res; ++} ++/* ++TODO: Choose best alternative implementation. ++ ++SItype ++__divsi3 (SItype a, SItype b) ++{ ++ SItype res = 0; ++ USItype cnt = 0; ++ ++ while (cnt < 32) ++ { ++ if (a & (1L << cnt)) ++ { ++ res += b; ++ } ++ b <<= 1; ++ cnt++; ++ } ++ ++ return res; ++} ++*/ ++ ++ ++#ifdef DEBUG_MULSI3 ++ ++int ++main () ++{ ++ int i, j; ++ int error = 0; ++ ++ for (i = -1000; i < 1000; i++) ++ for (j = -1000; j < 1000; j++) ++ { ++ int expect = i * j; ++ int actual = A__divsi3 (i, j); ++ if (expect != actual) ++ { ++ printf ("error: %d * %d = %d not %d\n", i, j, expect, actual); ++ error = 1; ++ } ++ } ++ ++ return error; ++} ++#endif +--- gcc-3.4.3/gcc/config/nios2/nios2-dp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-dp-bit.c +@@ -0,0 +1,1652 @@ ++ ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-fp-bit.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-fp-bit.c +@@ -0,0 +1,1652 @@ ++#define FLOAT ++/* This is a software floating point library which can be used ++ for targets without hardware floating point. ++ Copyright (C) 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004 ++ Free Software Foundation, Inc. ++ ++This file is free software; you can redistribute it and/or modify it ++under the terms of the GNU General Public License as published by the ++Free Software Foundation; either version 2, or (at your option) any ++later version. ++ ++In addition to the permissions in the GNU General Public License, the ++Free Software Foundation gives you unlimited permission to link the ++compiled version of this file with other programs, and to distribute ++those programs without any restriction coming from the use of this ++file. (The General Public License restrictions do apply in other ++respects; for example, they cover modification of the file, and ++distribution when not linked into another program.) ++ ++This file is distributed in the hope that it will be useful, but ++WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with this program; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++/* As a special exception, if you link this library with other files, ++ some of which are compiled with GCC, to produce an executable, ++ this library does not by itself cause the resulting executable ++ to be covered by the GNU General Public License. ++ This exception does not however invalidate any other reasons why ++ the executable file might be covered by the GNU General Public License. */ ++ ++/* This implements IEEE 754 format arithmetic, but does not provide a ++ mechanism for setting the rounding mode, or for generating or handling ++ exceptions. ++ ++ The original code by Steve Chamberlain, hacked by Mark Eichin and Jim ++ Wilson, all of Cygnus Support. */ ++ ++/* The intended way to use this file is to make two copies, add `#define FLOAT' ++ to one copy, then compile both copies and add them to libgcc.a. */ ++ ++#include "tconfig.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "config/fp-bit.h" ++ ++/* The following macros can be defined to change the behavior of this file: ++ FLOAT: Implement a `float', aka SFmode, fp library. If this is not ++ defined, then this file implements a `double', aka DFmode, fp library. ++ FLOAT_ONLY: Used with FLOAT, to implement a `float' only library, i.e. ++ don't include float->double conversion which requires the double library. ++ This is useful only for machines which can't support doubles, e.g. some ++ 8-bit processors. ++ CMPtype: Specify the type that floating point compares should return. ++ This defaults to SItype, aka int. ++ US_SOFTWARE_GOFAST: This makes all entry points use the same names as the ++ US Software goFast library. ++ _DEBUG_BITFLOAT: This makes debugging the code a little easier, by adding ++ two integers to the FLO_union_type. ++ NO_DENORMALS: Disable handling of denormals. ++ NO_NANS: Disable nan and infinity handling ++ SMALL_MACHINE: Useful when operations on QIs and HIs are faster ++ than on an SI */ ++ ++/* We don't currently support extended floats (long doubles) on machines ++ without hardware to deal with them. ++ ++ These stubs are just to keep the linker from complaining about unresolved ++ references which can be pulled in from libio & libstdc++, even if the ++ user isn't using long doubles. However, they may generate an unresolved ++ external to abort if abort is not used by the function, and the stubs ++ are referenced from within libc, since libgcc goes before and after the ++ system library. */ ++ ++#ifdef DECLARE_LIBRARY_RENAMES ++ DECLARE_LIBRARY_RENAMES ++#endif ++ ++#ifdef EXTENDED_FLOAT_STUBS ++extern void abort (void); ++void __extendsfxf2 (void) { abort(); } ++void __extenddfxf2 (void) { abort(); } ++void __truncxfdf2 (void) { abort(); } ++void __truncxfsf2 (void) { abort(); } ++void __fixxfsi (void) { abort(); } ++void __floatsixf (void) { abort(); } ++void __addxf3 (void) { abort(); } ++void __subxf3 (void) { abort(); } ++void __mulxf3 (void) { abort(); } ++void __divxf3 (void) { abort(); } ++void __negxf2 (void) { abort(); } ++void __eqxf2 (void) { abort(); } ++void __nexf2 (void) { abort(); } ++void __gtxf2 (void) { abort(); } ++void __gexf2 (void) { abort(); } ++void __lexf2 (void) { abort(); } ++void __ltxf2 (void) { abort(); } ++ ++void __extendsftf2 (void) { abort(); } ++void __extenddftf2 (void) { abort(); } ++void __trunctfdf2 (void) { abort(); } ++void __trunctfsf2 (void) { abort(); } ++void __fixtfsi (void) { abort(); } ++void __floatsitf (void) { abort(); } ++void __addtf3 (void) { abort(); } ++void __subtf3 (void) { abort(); } ++void __multf3 (void) { abort(); } ++void __divtf3 (void) { abort(); } ++void __negtf2 (void) { abort(); } ++void __eqtf2 (void) { abort(); } ++void __netf2 (void) { abort(); } ++void __gttf2 (void) { abort(); } ++void __getf2 (void) { abort(); } ++void __letf2 (void) { abort(); } ++void __lttf2 (void) { abort(); } ++#else /* !EXTENDED_FLOAT_STUBS, rest of file */ ++ ++/* IEEE "special" number predicates */ ++ ++#ifdef NO_NANS ++ ++#define nan() 0 ++#define isnan(x) 0 ++#define isinf(x) 0 ++#else ++ ++#if defined L_thenan_sf ++const fp_number_type __thenan_sf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_df ++const fp_number_type __thenan_df = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined L_thenan_tf ++const fp_number_type __thenan_tf = { CLASS_SNAN, 0, 0, {(fractype) 0} }; ++#elif defined TFLOAT ++extern const fp_number_type __thenan_tf; ++#elif defined FLOAT ++extern const fp_number_type __thenan_sf; ++#else ++extern const fp_number_type __thenan_df; ++#endif ++ ++INLINE ++static fp_number_type * ++nan (void) ++{ ++ /* Discard the const qualifier... */ ++#ifdef TFLOAT ++ return (fp_number_type *) (& __thenan_tf); ++#elif defined FLOAT ++ return (fp_number_type *) (& __thenan_sf); ++#else ++ return (fp_number_type *) (& __thenan_df); ++#endif ++} ++ ++INLINE ++static int ++isnan ( fp_number_type * x) ++{ ++ return x->class == CLASS_SNAN || x->class == CLASS_QNAN; ++} ++ ++INLINE ++static int ++isinf ( fp_number_type * x) ++{ ++ return x->class == CLASS_INFINITY; ++} ++ ++#endif /* NO_NANS */ ++ ++INLINE ++static int ++iszero ( fp_number_type * x) ++{ ++ return x->class == CLASS_ZERO; ++} ++ ++INLINE ++static void ++flip_sign ( fp_number_type * x) ++{ ++ x->sign = !x->sign; ++} ++ ++extern FLO_type pack_d ( fp_number_type * ); ++ ++#if defined(L_pack_df) || defined(L_pack_sf) || defined(L_pack_tf) ++FLO_type ++pack_d ( fp_number_type * src) ++{ ++ FLO_union_type dst; ++ fractype fraction = src->fraction.ll; /* wasn't unsigned before? */ ++ int sign = src->sign; ++ int exp = 0; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && (isnan (src) || isinf (src))) ++ { ++ /* We can't represent these values accurately. By using the ++ largest possible magnitude, we guarantee that the conversion ++ of infinity is at least as big as any finite number. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ else if (isnan (src)) ++ { ++ exp = EXPMAX; ++ if (src->class == CLASS_QNAN || 1) ++ { ++#ifdef QUIET_NAN_NEGATED ++ fraction |= QUIET_NAN - 1; ++#else ++ fraction |= QUIET_NAN; ++#endif ++ } ++ } ++ else if (isinf (src)) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else if (iszero (src)) ++ { ++ exp = 0; ++ fraction = 0; ++ } ++ else if (fraction == 0) ++ { ++ exp = 0; ++ } ++ else ++ { ++ if (src->normal_exp < NORMAL_EXPMIN) ++ { ++#ifdef NO_DENORMALS ++ /* Go straight to a zero representation if denormals are not ++ supported. The denormal handling would be harmless but ++ isn't unnecessary. */ ++ exp = 0; ++ fraction = 0; ++#else /* NO_DENORMALS */ ++ /* This number's exponent is too low to fit into the bits ++ available in the number, so we'll store 0 in the exponent and ++ shift the fraction to the right to make up for it. */ ++ ++ int shift = NORMAL_EXPMIN - src->normal_exp; ++ ++ exp = 0; ++ ++ if (shift > FRAC_NBITS - NGARDS) ++ { ++ /* No point shifting, since it's more that 64 out. */ ++ fraction = 0; ++ } ++ else ++ { ++ int lowbit = (fraction & (((fractype)1 << shift) - 1)) ? 1 : 0; ++ fraction = (fraction >> shift) | lowbit; ++ } ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if ((fraction & (1 << NGARDS))) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add to the guards to round up. */ ++ fraction += GARDROUND; ++ } ++ /* Perhaps the rounding means we now need to change the ++ exponent, because the fraction is no longer denormal. */ ++ if (fraction >= IMPLICIT_1) ++ { ++ exp += 1; ++ } ++ fraction >>= NGARDS; ++#endif /* NO_DENORMALS */ ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) ++ && src->normal_exp > EXPBIAS) ++ { ++ exp = EXPMAX; ++ fraction = 0; ++ } ++ else ++ { ++ exp = src->normal_exp + EXPBIAS; ++ if (!ROUND_TOWARDS_ZERO) ++ { ++ /* IF the gard bits are the all zero, but the first, then we're ++ half way between two numbers, choose the one which makes the ++ lsb of the answer 0. */ ++ if ((fraction & GARDMASK) == GARDMSB) ++ { ++ if (fraction & (1 << NGARDS)) ++ fraction += GARDROUND + 1; ++ } ++ else ++ { ++ /* Add a one to the guards to round up */ ++ fraction += GARDROUND; ++ } ++ if (fraction >= IMPLICIT_2) ++ { ++ fraction >>= 1; ++ exp += 1; ++ } ++ } ++ fraction >>= NGARDS; ++ ++ if (LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp > EXPMAX) ++ { ++ /* Saturate on overflow. */ ++ exp = EXPMAX; ++ fraction = ((fractype) 1 << FRACBITS) - 1; ++ } ++ } ++ } ++ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ dst.bits.fraction = fraction; ++ dst.bits.exp = exp; ++ dst.bits.sign = sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low, unity; ++ int lowsign, lowexp; ++ ++ unity = (halffractype) 1 << HALFFRACBITS; ++ ++ /* Set HIGH to the high double's significand, masking out the implicit 1. ++ Set LOW to the low double's full significand. */ ++ high = (fraction >> (FRACBITS - HALFFRACBITS)) & (unity - 1); ++ low = fraction & (unity * 2 - 1); ++ ++ /* Get the initial sign and exponent of the low double. */ ++ lowexp = exp - HALFFRACBITS - 1; ++ lowsign = sign; ++ ++ /* HIGH should be rounded like a normal double, making |LOW| <= ++ 0.5 ULP of HIGH. Assume round-to-nearest. */ ++ if (exp < EXPMAX) ++ if (low > unity || (low == unity && (high & 1) == 1)) ++ { ++ /* Round HIGH up and adjust LOW to match. */ ++ high++; ++ if (high == unity) ++ { ++ /* May make it infinite, but that's OK. */ ++ high = 0; ++ exp++; ++ } ++ low = unity * 2 - low; ++ lowsign ^= 1; ++ } ++ ++ high |= (halffractype) exp << HALFFRACBITS; ++ high |= (halffractype) sign << (HALFFRACBITS + EXPBITS); ++ ++ if (exp == EXPMAX || exp == 0 || low == 0) ++ low = 0; ++ else ++ { ++ while (lowexp > 0 && low < unity) ++ { ++ low <<= 1; ++ lowexp--; ++ } ++ ++ if (lowexp <= 0) ++ { ++ halffractype roundmsb, round; ++ int shift; ++ ++ shift = 1 - lowexp; ++ roundmsb = (1 << (shift - 1)); ++ round = low & ((roundmsb << 1) - 1); ++ ++ low >>= shift; ++ lowexp = 0; ++ ++ if (round > roundmsb || (round == roundmsb && (low & 1) == 1)) ++ { ++ low++; ++ if (low == unity) ++ /* LOW rounds up to the smallest normal number. */ ++ lowexp++; ++ } ++ } ++ ++ low &= unity - 1; ++ low |= (halffractype) lowexp << HALFFRACBITS; ++ low |= (halffractype) lowsign << (HALFFRACBITS + EXPBITS); ++ } ++ dst.value_raw = ((fractype) high << HALFSHIFT) | low; ++ } ++# else ++ dst.value_raw = fraction & ((((fractype)1) << FRACBITS) - (fractype)1); ++ dst.value_raw |= ((fractype) (exp & ((1 << EXPBITS) - 1))) << FRACBITS; ++ dst.value_raw |= ((fractype) (sign & 1)) << (FRACBITS | EXPBITS); ++# endif ++#endif ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++#ifdef TFLOAT ++ { ++ qrtrfractype tmp1 = dst.words[0]; ++ qrtrfractype tmp2 = dst.words[1]; ++ dst.words[0] = dst.words[3]; ++ dst.words[1] = dst.words[2]; ++ dst.words[2] = tmp2; ++ dst.words[3] = tmp1; ++ } ++#else ++ { ++ halffractype tmp = dst.words[0]; ++ dst.words[0] = dst.words[1]; ++ dst.words[1] = tmp; ++ } ++#endif ++#endif ++ ++ return dst.value; ++} ++#endif ++ ++#if defined(L_unpack_df) || defined(L_unpack_sf) || defined(L_unpack_tf) ++void ++unpack_d (FLO_union_type * src, fp_number_type * dst) ++{ ++ /* We previously used bitfields to store the number, but this doesn't ++ handle little/big endian systems conveniently, so use shifts and ++ masks */ ++ fractype fraction; ++ int exp; ++ int sign; ++ ++#if defined(FLOAT_WORD_ORDER_MISMATCH) && !defined(FLOAT) ++ FLO_union_type swapped; ++ ++#ifdef TFLOAT ++ swapped.words[0] = src->words[3]; ++ swapped.words[1] = src->words[2]; ++ swapped.words[2] = src->words[1]; ++ swapped.words[3] = src->words[0]; ++#else ++ swapped.words[0] = src->words[1]; ++ swapped.words[1] = src->words[0]; ++#endif ++ src = &swapped; ++#endif ++ ++#ifdef FLOAT_BIT_ORDER_MISMATCH ++ fraction = src->bits.fraction; ++ exp = src->bits.exp; ++ sign = src->bits.sign; ++#else ++# if defined TFLOAT && defined HALFFRACBITS ++ { ++ halffractype high, low; ++ ++ high = src->value_raw >> HALFSHIFT; ++ low = src->value_raw & (((fractype)1 << HALFSHIFT) - 1); ++ ++ fraction = high & ((((fractype)1) << HALFFRACBITS) - 1); ++ fraction <<= FRACBITS - HALFFRACBITS; ++ exp = ((int)(high >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(high >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ ++ if (exp != EXPMAX && exp != 0 && low != 0) ++ { ++ int lowexp = ((int)(low >> HALFFRACBITS)) & ((1 << EXPBITS) - 1); ++ int lowsign = ((int)(low >> (((HALFFRACBITS + EXPBITS))))) & 1; ++ int shift; ++ fractype xlow; ++ ++ xlow = low & ((((fractype)1) << HALFFRACBITS) - 1); ++ if (lowexp) ++ xlow |= (((halffractype)1) << HALFFRACBITS); ++ else ++ lowexp = 1; ++ shift = (FRACBITS - HALFFRACBITS) - (exp - lowexp); ++ if (shift > 0) ++ xlow <<= shift; ++ else if (shift < 0) ++ xlow >>= -shift; ++ if (sign == lowsign) ++ fraction += xlow; ++ else if (fraction >= xlow) ++ fraction -= xlow; ++ else ++ { ++ /* The high part is a power of two but the full number is lower. ++ This code will leave the implicit 1 in FRACTION, but we'd ++ have added that below anyway. */ ++ fraction = (((fractype) 1 << FRACBITS) - xlow) << 1; ++ exp--; ++ } ++ } ++ } ++# else ++ fraction = src->value_raw & ((((fractype)1) << FRACBITS) - 1); ++ exp = ((int)(src->value_raw >> FRACBITS)) & ((1 << EXPBITS) - 1); ++ sign = ((int)(src->value_raw >> (FRACBITS + EXPBITS))) & 1; ++# endif ++#endif ++ ++ dst->sign = sign; ++ if (exp == 0) ++ { ++ /* Hmm. Looks like 0 */ ++ if (fraction == 0 ++#ifdef NO_DENORMALS ++ || 1 ++#endif ++ ) ++ { ++ /* tastes like zero */ ++ dst->class = CLASS_ZERO; ++ } ++ else ++ { ++ /* Zero exponent with nonzero fraction - it's denormalized, ++ so there isn't a leading implicit one - we'll shift it so ++ it gets one. */ ++ dst->normal_exp = exp - EXPBIAS + 1; ++ fraction <<= NGARDS; ++ ++ dst->class = CLASS_NUMBER; ++#if 1 ++ while (fraction < IMPLICIT_1) ++ { ++ fraction <<= 1; ++ dst->normal_exp--; ++ } ++#endif ++ dst->fraction.ll = fraction; ++ } ++ } ++ else if (!LARGEST_EXPONENT_IS_NORMAL (FRAC_NBITS) && exp == EXPMAX) ++ { ++ /* Huge exponent*/ ++ if (fraction == 0) ++ { ++ /* Attached to a zero fraction - means infinity */ ++ dst->class = CLASS_INFINITY; ++ } ++ else ++ { ++ /* Nonzero fraction, means nan */ ++#ifdef QUIET_NAN_NEGATED ++ if ((fraction & QUIET_NAN) == 0) ++#else ++ if (fraction & QUIET_NAN) ++#endif ++ { ++ dst->class = CLASS_QNAN; ++ } ++ else ++ { ++ dst->class = CLASS_SNAN; ++ } ++ /* Keep the fraction part as the nan number */ ++ dst->fraction.ll = fraction; ++ } ++ } ++ else ++ { ++ /* Nothing strange about this number */ ++ dst->normal_exp = exp - EXPBIAS; ++ dst->class = CLASS_NUMBER; ++ dst->fraction.ll = (fraction << NGARDS) | IMPLICIT_1; ++ } ++} ++#endif /* L_unpack_df || L_unpack_sf */ ++ ++#if defined(L_addsub_sf) || defined(L_addsub_df) || defined(L_addsub_tf) ++static fp_number_type * ++_fpadd_parts (fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ intfrac tfraction; ++ ++ /* Put commonly used fields in local variables. */ ++ int a_normal_exp; ++ int b_normal_exp; ++ fractype a_fraction; ++ fractype b_fraction; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ if (isinf (a)) ++ { ++ /* Adding infinities with opposite signs yields a NaN. */ ++ if (isinf (b) && a->sign != b->sign) ++ return nan (); ++ return a; ++ } ++ if (isinf (b)) ++ { ++ return b; ++ } ++ if (iszero (b)) ++ { ++ if (iszero (a)) ++ { ++ *tmp = *a; ++ tmp->sign = a->sign & b->sign; ++ return tmp; ++ } ++ return a; ++ } ++ if (iszero (a)) ++ { ++ return b; ++ } ++ ++ /* Got two numbers. shift the smaller and increment the exponent till ++ they're the same */ ++ { ++ int diff; ++ ++ a_normal_exp = a->normal_exp; ++ b_normal_exp = b->normal_exp; ++ a_fraction = a->fraction.ll; ++ b_fraction = b->fraction.ll; ++ ++ diff = a_normal_exp - b_normal_exp; ++ ++ if (diff < 0) ++ diff = -diff; ++ if (diff < FRAC_NBITS) ++ { ++ /* ??? This does shifts one bit at a time. Optimize. */ ++ while (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp++; ++ LSHIFT (b_fraction); ++ } ++ while (b_normal_exp > a_normal_exp) ++ { ++ a_normal_exp++; ++ LSHIFT (a_fraction); ++ } ++ } ++ else ++ { ++ /* Somethings's up.. choose the biggest */ ++ if (a_normal_exp > b_normal_exp) ++ { ++ b_normal_exp = a_normal_exp; ++ b_fraction = 0; ++ } ++ else ++ { ++ a_normal_exp = b_normal_exp; ++ a_fraction = 0; ++ } ++ } ++ } ++ ++ if (a->sign != b->sign) ++ { ++ if (a->sign) ++ { ++ tfraction = -a_fraction + b_fraction; ++ } ++ else ++ { ++ tfraction = a_fraction - b_fraction; ++ } ++ if (tfraction >= 0) ++ { ++ tmp->sign = 0; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = tfraction; ++ } ++ else ++ { ++ tmp->sign = 1; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = -tfraction; ++ } ++ /* and renormalize it */ ++ ++ while (tmp->fraction.ll < IMPLICIT_1 && tmp->fraction.ll) ++ { ++ tmp->fraction.ll <<= 1; ++ tmp->normal_exp--; ++ } ++ } ++ else ++ { ++ tmp->sign = a->sign; ++ tmp->normal_exp = a_normal_exp; ++ tmp->fraction.ll = a_fraction + b_fraction; ++ } ++ tmp->class = CLASS_NUMBER; ++ /* Now the fraction is added, we have to shift down to renormalize the ++ number */ ++ ++ if (tmp->fraction.ll >= IMPLICIT_2) ++ { ++ LSHIFT (tmp->fraction.ll); ++ tmp->normal_exp++; ++ } ++ return tmp; ++ ++} ++ ++FLO_type ++add (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++ ++FLO_type ++sub (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ b.sign ^= 1; ++ ++ res = _fpadd_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_addsub_sf || L_addsub_df */ ++ ++#if defined(L_mul_sf) || defined(L_mul_df) || defined(L_mul_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpmul_parts ( fp_number_type * a, ++ fp_number_type * b, ++ fp_number_type * tmp) ++{ ++ fractype low = 0; ++ fractype high = 0; ++ ++ if (isnan (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isnan (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (isinf (a)) ++ { ++ if (iszero (b)) ++ return nan (); ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (isinf (b)) ++ { ++ if (iszero (a)) ++ { ++ return nan (); ++ } ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ if (iszero (a)) ++ { ++ a->sign = a->sign != b->sign; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ b->sign = a->sign != b->sign; ++ return b; ++ } ++ ++ /* Calculate the mantissa by multiplying both numbers to get a ++ twice-as-wide number. */ ++ { ++#if defined(NO_DI_MODE) || defined(TFLOAT) ++ { ++ fractype x = a->fraction.ll; ++ fractype ylow = b->fraction.ll; ++ fractype yhigh = 0; ++ int bit; ++ ++ /* ??? This does multiplies one bit at a time. Optimize. */ ++ for (bit = 0; bit < FRAC_NBITS; bit++) ++ { ++ int carry; ++ ++ if (x & 1) ++ { ++ carry = (low += ylow) < ylow; ++ high += yhigh + carry; ++ } ++ yhigh <<= 1; ++ if (ylow & FRACHIGH) ++ { ++ yhigh |= 1; ++ } ++ ylow <<= 1; ++ x >>= 1; ++ } ++ } ++#elif defined(FLOAT) ++ /* Multiplying two USIs to get a UDI, we're safe. */ ++ { ++ UDItype answer = (UDItype)a->fraction.ll * (UDItype)b->fraction.ll; ++ ++ high = answer >> BITS_PER_SI; ++ low = answer; ++ } ++#else ++ /* fractype is DImode, but we need the result to be twice as wide. ++ Assuming a widening multiply from DImode to TImode is not ++ available, build one by hand. */ ++ { ++ USItype nl = a->fraction.ll; ++ USItype nh = a->fraction.ll >> BITS_PER_SI; ++ USItype ml = b->fraction.ll; ++ USItype mh = b->fraction.ll >> BITS_PER_SI; ++ UDItype pp_ll = (UDItype) ml * nl; ++ UDItype pp_hl = (UDItype) mh * nl; ++ UDItype pp_lh = (UDItype) ml * nh; ++ UDItype pp_hh = (UDItype) mh * nh; ++ UDItype res2 = 0; ++ UDItype res0 = 0; ++ UDItype ps_hh__ = pp_hl + pp_lh; ++ if (ps_hh__ < pp_hl) ++ res2 += (UDItype)1 << BITS_PER_SI; ++ pp_hl = (UDItype)(USItype)ps_hh__ << BITS_PER_SI; ++ res0 = pp_ll + pp_hl; ++ if (res0 < pp_ll) ++ res2++; ++ res2 += (ps_hh__ >> BITS_PER_SI) + pp_hh; ++ high = res2; ++ low = res0; ++ } ++#endif ++ } ++ ++ tmp->normal_exp = a->normal_exp + b->normal_exp ++ + FRAC_NBITS - (FRACBITS + NGARDS); ++ tmp->sign = a->sign != b->sign; ++ while (high >= IMPLICIT_2) ++ { ++ tmp->normal_exp++; ++ if (high & 1) ++ { ++ low >>= 1; ++ low |= FRACHIGH; ++ } ++ high >>= 1; ++ } ++ while (high < IMPLICIT_1) ++ { ++ tmp->normal_exp--; ++ ++ high <<= 1; ++ if (low & FRACHIGH) ++ high |= 1; ++ low <<= 1; ++ } ++ /* rounding is tricky. if we only round if it won't make us round later. */ ++#if 0 ++ if (low & FRACHIGH2) ++ { ++ if (((high & GARDMASK) != GARDMSB) ++ && (((high + 1) & GARDMASK) == GARDMSB)) ++ { ++ /* don't round, it gets done again later. */ ++ } ++ else ++ { ++ high++; ++ } ++ } ++#endif ++ if (!ROUND_TOWARDS_ZERO && (high & GARDMASK) == GARDMSB) ++ { ++ if (high & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ high += GARDROUND + 1; ++ } ++ else if (low) ++ { ++ /* but we really weren't half way */ ++ high += GARDROUND + 1; ++ } ++ } ++ tmp->fraction.ll = high; ++ tmp->class = CLASS_NUMBER; ++ return tmp; ++} ++ ++FLO_type ++multiply (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type tmp; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpmul_parts (&a, &b, &tmp); ++ ++ return pack_d (res); ++} ++#endif /* L_mul_sf || L_mul_df */ ++ ++#if defined(L_div_sf) || defined(L_div_df) || defined(L_div_tf) ++static inline __attribute__ ((__always_inline__)) fp_number_type * ++_fpdiv_parts (fp_number_type * a, ++ fp_number_type * b) ++{ ++ fractype bit; ++ fractype numerator; ++ fractype denominator; ++ fractype quotient; ++ ++ if (isnan (a)) ++ { ++ return a; ++ } ++ if (isnan (b)) ++ { ++ return b; ++ } ++ ++ a->sign = a->sign ^ b->sign; ++ ++ if (isinf (a) || iszero (a)) ++ { ++ if (a->class == b->class) ++ return nan (); ++ return a; ++ } ++ ++ if (isinf (b)) ++ { ++ a->fraction.ll = 0; ++ a->normal_exp = 0; ++ return a; ++ } ++ if (iszero (b)) ++ { ++ a->class = CLASS_INFINITY; ++ return a; ++ } ++ ++ /* Calculate the mantissa by multiplying both 64bit numbers to get a ++ 128 bit number */ ++ { ++ /* quotient = ++ ( numerator / denominator) * 2^(numerator exponent - denominator exponent) ++ */ ++ ++ a->normal_exp = a->normal_exp - b->normal_exp; ++ numerator = a->fraction.ll; ++ denominator = b->fraction.ll; ++ ++ if (numerator < denominator) ++ { ++ /* Fraction will be less than 1.0 */ ++ numerator *= 2; ++ a->normal_exp--; ++ } ++ bit = IMPLICIT_1; ++ quotient = 0; ++ /* ??? Does divide one bit at a time. Optimize. */ ++ while (bit) ++ { ++ if (numerator >= denominator) ++ { ++ quotient |= bit; ++ numerator -= denominator; ++ } ++ bit >>= 1; ++ numerator *= 2; ++ } ++ ++ if (!ROUND_TOWARDS_ZERO && (quotient & GARDMASK) == GARDMSB) ++ { ++ if (quotient & (1 << NGARDS)) ++ { ++ /* half way, so round to even */ ++ quotient += GARDROUND + 1; ++ } ++ else if (numerator) ++ { ++ /* but we really weren't half way, more bits exist */ ++ quotient += GARDROUND + 1; ++ } ++ } ++ ++ a->fraction.ll = quotient; ++ return (a); ++ } ++} ++ ++FLO_type ++divide (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ fp_number_type *res; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ res = _fpdiv_parts (&a, &b); ++ ++ return pack_d (res); ++} ++#endif /* L_div_sf || L_div_df */ ++ ++#if defined(L_fpcmp_parts_sf) || defined(L_fpcmp_parts_df) \ ++ || defined(L_fpcmp_parts_tf) ++/* according to the demo, fpcmp returns a comparison with 0... thus ++ a -1 ++ a==b -> 0 ++ a>b -> +1 ++ */ ++ ++int ++__fpcmp_parts (fp_number_type * a, fp_number_type * b) ++{ ++#if 0 ++ /* either nan -> unordered. Must be checked outside of this routine. */ ++ if (isnan (a) && isnan (b)) ++ { ++ return 1; /* still unordered! */ ++ } ++#endif ++ ++ if (isnan (a) || isnan (b)) ++ { ++ return 1; /* how to indicate unordered compare? */ ++ } ++ if (isinf (a) && isinf (b)) ++ { ++ /* +inf > -inf, but +inf != +inf */ ++ /* b \a| +inf(0)| -inf(1) ++ ______\+--------+-------- ++ +inf(0)| a==b(0)| ab(1) | a==b(0) ++ -------+--------+-------- ++ So since unordered must be nonzero, just line up the columns... ++ */ ++ return b->sign - a->sign; ++ } ++ /* but not both... */ ++ if (isinf (a)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (isinf (b)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (a) && iszero (b)) ++ { ++ return 0; ++ } ++ if (iszero (a)) ++ { ++ return b->sign ? 1 : -1; ++ } ++ if (iszero (b)) ++ { ++ return a->sign ? -1 : 1; ++ } ++ /* now both are "normal". */ ++ if (a->sign != b->sign) ++ { ++ /* opposite signs */ ++ return a->sign ? -1 : 1; ++ } ++ /* same sign; exponents? */ ++ if (a->normal_exp > b->normal_exp) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->normal_exp < b->normal_exp) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* same exponents; check size. */ ++ if (a->fraction.ll > b->fraction.ll) ++ { ++ return a->sign ? -1 : 1; ++ } ++ if (a->fraction.ll < b->fraction.ll) ++ { ++ return a->sign ? 1 : -1; ++ } ++ /* after all that, they're equal. */ ++ return 0; ++} ++#endif ++ ++#if defined(L_compare_sf) || defined(L_compare_df) || defined(L_compoare_tf) ++CMPtype ++compare (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_compare_sf || L_compare_df */ ++ ++#ifndef US_SOFTWARE_GOFAST ++ ++/* These should be optimized for their specific tasks someday. */ ++ ++#if defined(L_eq_sf) || defined(L_eq_df) || defined(L_eq_tf) ++CMPtype ++_eq_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth == 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_eq_sf || L_eq_df */ ++ ++#if defined(L_ne_sf) || defined(L_ne_df) || defined(L_ne_tf) ++CMPtype ++_ne_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* true, truth != 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ne_sf || L_ne_df */ ++ ++#if defined(L_gt_sf) || defined(L_gt_df) || defined(L_gt_tf) ++CMPtype ++_gt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth > 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_gt_sf || L_gt_df */ ++ ++#if defined(L_ge_sf) || defined(L_ge_df) || defined(L_ge_tf) ++CMPtype ++_ge_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return -1; /* false, truth >= 0 */ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_ge_sf || L_ge_df */ ++ ++#if defined(L_lt_sf) || defined(L_lt_df) || defined(L_lt_tf) ++CMPtype ++_lt_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth < 0 */ ++ ++ return __fpcmp_parts (&a, &b); ++} ++#endif /* L_lt_sf || L_lt_df */ ++ ++#if defined(L_le_sf) || defined(L_le_df) || defined(L_le_tf) ++CMPtype ++_le_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ if (isnan (&a) || isnan (&b)) ++ return 1; /* false, truth <= 0 */ ++ ++ return __fpcmp_parts (&a, &b) ; ++} ++#endif /* L_le_sf || L_le_df */ ++ ++#endif /* ! US_SOFTWARE_GOFAST */ ++ ++#if defined(L_unord_sf) || defined(L_unord_df) || defined(L_unord_tf) ++CMPtype ++_unord_f2 (FLO_type arg_a, FLO_type arg_b) ++{ ++ fp_number_type a; ++ fp_number_type b; ++ FLO_union_type au, bu; ++ ++ au.value = arg_a; ++ bu.value = arg_b; ++ ++ unpack_d (&au, &a); ++ unpack_d (&bu, &b); ++ ++ return (isnan (&a) || isnan (&b)); ++} ++#endif /* L_unord_sf || L_unord_df */ ++ ++#if defined(L_si_to_sf) || defined(L_si_to_df) || defined(L_si_to_tf) ++FLO_type ++si_to_float (SItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.class = CLASS_NUMBER; ++ in.sign = arg_a < 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.normal_exp = FRACBITS + NGARDS; ++ if (in.sign) ++ { ++ /* Special case for minint, since there is no +ve integer ++ representation for it */ ++ if (arg_a == (- MAX_SI_INT - 1)) ++ { ++ return (FLO_type)(- MAX_SI_INT - 1); ++ } ++ in.fraction.ll = (-arg_a); ++ } ++ else ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif /* L_si_to_sf || L_si_to_df */ ++ ++#if defined(L_usi_to_sf) || defined(L_usi_to_df) || defined(L_usi_to_tf) ++FLO_type ++usi_to_float (USItype arg_a) ++{ ++ fp_number_type in; ++ ++ in.sign = 0; ++ if (!arg_a) ++ { ++ in.class = CLASS_ZERO; ++ } ++ else ++ { ++ in.class = CLASS_NUMBER; ++ in.normal_exp = FRACBITS + NGARDS; ++ in.fraction.ll = arg_a; ++ ++ while (in.fraction.ll > ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll >>= 1; ++ in.normal_exp += 1; ++ } ++ while (in.fraction.ll < ((fractype)1 << (FRACBITS + NGARDS))) ++ { ++ in.fraction.ll <<= 1; ++ in.normal_exp -= 1; ++ } ++ } ++ return pack_d (&in); ++} ++#endif ++ ++#if defined(L_sf_to_si) || defined(L_df_to_si) || defined(L_tf_to_si) ++SItype ++float_to_si (FLO_type arg_a) ++{ ++ fp_number_type a; ++ SItype tmp; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* get reasonable MAX_SI_INT... */ ++ if (isinf (&a)) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 2) ++ return a.sign ? (-MAX_SI_INT)-1 : MAX_SI_INT; ++ tmp = a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++ return a.sign ? (-tmp) : (tmp); ++} ++#endif /* L_sf_to_si || L_df_to_si */ ++ ++#if defined(L_sf_to_usi) || defined(L_df_to_usi) || defined(L_tf_to_usi) ++#if defined US_SOFTWARE_GOFAST || defined(L_tf_to_usi) ++/* While libgcc2.c defines its own __fixunssfsi and __fixunsdfsi routines, ++ we also define them for GOFAST because the ones in libgcc2.c have the ++ wrong names and I'd rather define these here and keep GOFAST CYG-LOC's ++ out of libgcc2.c. We can't define these here if not GOFAST because then ++ there'd be duplicate copies. */ ++ ++USItype ++float_to_usi (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ if (iszero (&a)) ++ return 0; ++ if (isnan (&a)) ++ return 0; ++ /* it is a negative number */ ++ if (a.sign) ++ return 0; ++ /* get reasonable MAX_USI_INT... */ ++ if (isinf (&a)) ++ return MAX_USI_INT; ++ /* it is a number, but a small one */ ++ if (a.normal_exp < 0) ++ return 0; ++ if (a.normal_exp > BITS_PER_SI - 1) ++ return MAX_USI_INT; ++ else if (a.normal_exp > (FRACBITS + NGARDS)) ++ return a.fraction.ll << (a.normal_exp - (FRACBITS + NGARDS)); ++ else ++ return a.fraction.ll >> ((FRACBITS + NGARDS) - a.normal_exp); ++} ++#endif /* US_SOFTWARE_GOFAST */ ++#endif /* L_sf_to_usi || L_df_to_usi */ ++ ++#if defined(L_negate_sf) || defined(L_negate_df) || defined(L_negate_tf) ++FLO_type ++negate (FLO_type arg_a) ++{ ++ fp_number_type a; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &a); ++ ++ flip_sign (&a); ++ return pack_d (&a); ++} ++#endif /* L_negate_sf || L_negate_df */ ++ ++#ifdef FLOAT ++ ++#if defined(L_make_sf) ++SFtype ++__make_fp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ USItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_sf */ ++ ++#ifndef FLOAT_ONLY ++ ++/* This enables one to build an fp library that supports float but not double. ++ Otherwise, we would get an undefined reference to __make_dp. ++ This is needed for some 8-bit ports that can't handle well values that ++ are 8-bytes in size, so we just don't support double for them at all. */ ++ ++#if defined(L_sf_to_df) ++DFtype ++sf_to_df (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, ++ ((UDItype) in.fraction.ll) << F_D_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#if defined(L_sf_to_tf) && defined(TMODES) ++TFtype ++sf_to_tf (SFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << F_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#endif /* ! FLOAT_ONLY */ ++#endif /* FLOAT */ ++ ++#ifndef FLOAT ++ ++extern SFtype __make_fp (fp_class_type, unsigned int, int, USItype); ++ ++#if defined(L_make_df) ++DFtype ++__make_dp (fp_class_type class, unsigned int sign, int exp, UDItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_df */ ++ ++#if defined(L_df_to_sf) ++SFtype ++df_to_sf (DFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_D_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((USItype) 1 << F_D_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_df_to_sf */ ++ ++#if defined(L_df_to_tf) && defined(TMODES) \ ++ && !defined(FLOAT) && !defined(TFLOAT) ++TFtype ++df_to_tf (DFtype arg_a) ++{ ++ fp_number_type in; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ return __make_tp (in.class, in.sign, in.normal_exp, ++ ((UTItype) in.fraction.ll) << D_T_BITOFF); ++} ++#endif /* L_sf_to_df */ ++ ++#ifdef TFLOAT ++#if defined(L_make_tf) ++TFtype ++__make_tp(fp_class_type class, ++ unsigned int sign, ++ int exp, ++ UTItype frac) ++{ ++ fp_number_type in; ++ ++ in.class = class; ++ in.sign = sign; ++ in.normal_exp = exp; ++ in.fraction.ll = frac; ++ return pack_d (&in); ++} ++#endif /* L_make_tf */ ++ ++#if defined(L_tf_to_df) ++DFtype ++tf_to_df (TFtype arg_a) ++{ ++ fp_number_type in; ++ UDItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> D_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << D_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_dp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_df */ ++ ++#if defined(L_tf_to_sf) ++SFtype ++tf_to_sf (TFtype arg_a) ++{ ++ fp_number_type in; ++ USItype sffrac; ++ FLO_union_type au; ++ ++ au.value = arg_a; ++ unpack_d (&au, &in); ++ ++ sffrac = in.fraction.ll >> F_T_BITOFF; ++ ++ /* We set the lowest guard bit in SFFRAC if we discarded any non ++ zero bits. */ ++ if ((in.fraction.ll & (((UTItype) 1 << F_T_BITOFF) - 1)) != 0) ++ sffrac |= 1; ++ ++ return __make_fp (in.class, in.sign, in.normal_exp, sffrac); ++} ++#endif /* L_tf_to_sf */ ++#endif /* TFLOAT */ ++ ++#endif /* ! FLOAT */ ++#endif /* !EXTENDED_FLOAT_STUBS */ +--- gcc-3.4.3/gcc/config/nios2/nios2-protos.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2-protos.h +@@ -0,0 +1,70 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++extern void dump_frame_size (FILE *); ++extern HOST_WIDE_INT compute_frame_size (void); ++extern int nios2_initial_elimination_offset (int, int); ++extern void override_options (void); ++extern void optimization_options (int, int); ++extern int nios2_can_use_return_insn (void); ++extern void expand_prologue (void); ++extern void expand_epilogue (bool); ++extern void function_profiler (FILE *, int); ++ ++ ++#ifdef RTX_CODE ++extern int nios2_legitimate_address (rtx, enum machine_mode, int); ++extern void nios2_print_operand (FILE *, rtx, int); ++extern void nios2_print_operand_address (FILE *, rtx); ++ ++extern int nios2_emit_move_sequence (rtx *, enum machine_mode); ++extern int nios2_emit_expensive_div (rtx *, enum machine_mode); ++ ++extern void gen_int_relational (enum rtx_code, rtx, rtx, rtx, rtx); ++extern void gen_conditional_move (rtx *, enum machine_mode); ++extern const char *asm_output_opcode (FILE *, const char *); ++ ++/* predicates */ ++extern int arith_operand (rtx, enum machine_mode); ++extern int uns_arith_operand (rtx, enum machine_mode); ++extern int logical_operand (rtx, enum machine_mode); ++extern int shift_operand (rtx, enum machine_mode); ++extern int reg_or_0_operand (rtx, enum machine_mode); ++extern int equality_op (rtx, enum machine_mode); ++extern int custom_insn_opcode (rtx, enum machine_mode); ++extern int rdwrctl_operand (rtx, enum machine_mode); ++ ++# ifdef HAVE_MACHINE_MODES ++# if defined TREE_CODE ++extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern rtx function_arg (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern int function_arg_partial_nregs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, tree, int); ++extern int nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *, enum machine_mode, tree, int); ++ ++# endif /* TREE_CODE */ ++# endif /* HAVE_MACHINE_MODES */ ++#endif ++ ++#ifdef TREE_CODE ++extern int nios2_return_in_memory (tree); ++ ++#endif /* TREE_CODE */ +--- gcc-3.4.3/gcc/config/nios2/nios2.c ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.c +@@ -0,0 +1,2853 @@ ++/* Subroutines for assembler code output for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++#include ++#include "config.h" ++#include "system.h" ++#include "coretypes.h" ++#include "tm.h" ++#include "rtl.h" ++#include "tree.h" ++#include "tm_p.h" ++#include "regs.h" ++#include "hard-reg-set.h" ++#include "real.h" ++#include "insn-config.h" ++#include "conditions.h" ++#include "output.h" ++#include "insn-attr.h" ++#include "flags.h" ++#include "recog.h" ++#include "expr.h" ++#include "toplev.h" ++#include "basic-block.h" ++#include "function.h" ++#include "ggc.h" ++#include "reload.h" ++#include "debug.h" ++#include "optabs.h" ++#include "target.h" ++#include "target-def.h" ++ ++/* local prototypes */ ++static bool nios2_rtx_costs (rtx, int, int, int *); ++ ++static void nios2_asm_function_prologue (FILE *, HOST_WIDE_INT); ++static int nios2_use_dfa_pipeline_interface (void); ++static int nios2_issue_rate (void); ++static struct machine_function *nios2_init_machine_status (void); ++static bool nios2_in_small_data_p (tree); ++static rtx save_reg (int, HOST_WIDE_INT, rtx); ++static rtx restore_reg (int, HOST_WIDE_INT); ++static unsigned int nios2_section_type_flags (tree, const char *, int); ++static void nios2_init_builtins (void); ++static rtx nios2_expand_builtin (tree, rtx, rtx, enum machine_mode, int); ++static bool nios2_function_ok_for_sibcall (tree, tree); ++static void nios2_encode_section_info (tree, rtx, int); ++ ++/* Initialize the GCC target structure. */ ++#undef TARGET_ASM_FUNCTION_PROLOGUE ++#define TARGET_ASM_FUNCTION_PROLOGUE nios2_asm_function_prologue ++ ++#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE ++#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \ ++ nios2_use_dfa_pipeline_interface ++#undef TARGET_SCHED_ISSUE_RATE ++#define TARGET_SCHED_ISSUE_RATE nios2_issue_rate ++#undef TARGET_IN_SMALL_DATA_P ++#define TARGET_IN_SMALL_DATA_P nios2_in_small_data_p ++#undef TARGET_ENCODE_SECTION_INFO ++#define TARGET_ENCODE_SECTION_INFO nios2_encode_section_info ++#undef TARGET_SECTION_TYPE_FLAGS ++#define TARGET_SECTION_TYPE_FLAGS nios2_section_type_flags ++ ++#undef TARGET_INIT_BUILTINS ++#define TARGET_INIT_BUILTINS nios2_init_builtins ++#undef TARGET_EXPAND_BUILTIN ++#define TARGET_EXPAND_BUILTIN nios2_expand_builtin ++ ++#undef TARGET_FUNCTION_OK_FOR_SIBCALL ++#define TARGET_FUNCTION_OK_FOR_SIBCALL nios2_function_ok_for_sibcall ++ ++#undef TARGET_RTX_COSTS ++#define TARGET_RTX_COSTS nios2_rtx_costs ++ ++ ++struct gcc_target targetm = TARGET_INITIALIZER; ++ ++ ++ ++/* Threshold for data being put into the small data/bss area, instead ++ of the normal data area (references to the small data/bss area take ++ 1 instruction, and use the global pointer, references to the normal ++ data area takes 2 instructions). */ ++unsigned HOST_WIDE_INT nios2_section_threshold = NIOS2_DEFAULT_GVALUE; ++ ++ ++/* Structure to be filled in by compute_frame_size with register ++ save masks, and offsets for the current function. */ ++ ++struct nios2_frame_info ++GTY (()) ++{ ++ long total_size; /* # bytes that the entire frame takes up */ ++ long var_size; /* # bytes that variables take up */ ++ long args_size; /* # bytes that outgoing arguments take up */ ++ int save_reg_size; /* # bytes needed to store gp regs */ ++ int save_reg_rounded; /* # bytes needed to store gp regs */ ++ long save_regs_offset; /* offset from new sp to store gp registers */ ++ int initialized; /* != 0 if frame size already calculated */ ++ int num_regs; /* number of gp registers saved */ ++}; ++ ++struct machine_function ++GTY (()) ++{ ++ ++ /* Current frame information, calculated by compute_frame_size. */ ++ struct nios2_frame_info frame; ++}; ++ ++ ++/*************************************** ++ * Section encodings ++ ***************************************/ ++ ++ ++ ++ ++ ++/*************************************** ++ * Stack Layout and Calling Conventions ++ ***************************************/ ++ ++ ++#define TOO_BIG_OFFSET(X) ((X) > ((1 << 15) - 1)) ++#define TEMP_REG_NUM 8 ++ ++static void ++nios2_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) ++{ ++ if (flag_verbose_asm || flag_debug_asm) ++ { ++ compute_frame_size (); ++ dump_frame_size (file); ++ } ++} ++ ++static rtx ++save_reg (int regno, HOST_WIDE_INT offset, rtx cfa_store_reg) ++{ ++ rtx insn, stack_slot; ++ ++ stack_slot = gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ GEN_INT (offset)); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_MEM (SImode, stack_slot), ++ gen_rtx_REG (SImode, regno))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ return insn; ++} ++ ++static rtx ++restore_reg (int regno, HOST_WIDE_INT offset) ++{ ++ rtx insn, stack_slot; ++ ++ if (TOO_BIG_OFFSET (offset)) ++ { ++ stack_slot = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ GEN_INT (offset))); ++ ++ insn = emit_insn (gen_rtx_SET (SImode, ++ stack_slot, ++ gen_rtx_PLUS (SImode, ++ stack_slot, ++ stack_pointer_rtx))); ++ } ++ else ++ { ++ stack_slot = gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (offset)); ++ } ++ ++ stack_slot = gen_rtx_MEM (SImode, stack_slot); ++ ++ insn = emit_move_insn (gen_rtx_REG (SImode, regno), stack_slot); ++ ++ return insn; ++} ++ ++ ++/* There are two possible paths for prologue expansion, ++- the first is if the total frame size is < 2^15-1. In that ++case all the immediates will fit into the 16-bit immediate ++fields. ++- the second is when the frame size is too big, in that ++case an additional temporary register is used, first ++as a cfa_temp to offset the sp, second as the cfa_store ++register. ++ ++See the comment above dwarf2out_frame_debug_expr in ++dwarf2out.c for more explanation of the "rules." ++ ++ ++Case 1: ++Rule # Example Insn Effect ++2 addi sp, sp, -total_frame_size cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++12 stw ra, offset(sp) ++12 stw r16, offset(sp) ++1 mov fp, sp ++ ++Case 2: ++Rule # Example Insn Effect ++6 movi r8, total_frame_size cfa_temp.reg=r8, cfa_temp.offset=total_frame_size ++2 sub sp, sp, r8 cfa.reg=sp, cfa.offset=total_frame_size ++ cfa_store.reg=sp, cfa_store.offset=total_frame_size ++5 add r8, r8, sp cfa_store.reg=r8, cfa_store.offset=0 ++12 stw ra, offset(r8) ++12 stw r16, offset(r8) ++1 mov fp, sp ++ ++*/ ++ ++void ++expand_prologue () ++{ ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int cfa_store_offset; ++ rtx insn; ++ rtx cfa_store_reg = 0; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (total_frame_size) ++ { ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ /* cfa_temp and cfa_store_reg are the same register, ++ cfa_store_reg overwrites cfa_temp */ ++ cfa_store_reg = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ cfa_store_reg, ++ GEN_INT (total_frame_size))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_MINUS (SImode, ++ stack_pointer_rtx, ++ cfa_store_reg)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ ++ /* if there are no registers to save, I don't need to ++ create a cfa_store */ ++ if (cfun->machine->frame.save_reg_size) ++ { ++ insn = gen_rtx_SET (SImode, ++ cfa_store_reg, ++ gen_rtx_PLUS (SImode, ++ cfa_store_reg, ++ stack_pointer_rtx)); ++ ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ cfa_store_offset ++ = total_frame_size ++ - (cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded); ++ } ++ else ++ { ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ GEN_INT (-total_frame_size))); ++ insn = emit_insn (insn); ++ RTX_FRAME_RELATED_P (insn) = 1; ++ ++ cfa_store_reg = stack_pointer_rtx; ++ cfa_store_offset ++ = cfun->machine->frame.save_regs_offset ++ + cfun->machine->frame.save_reg_rounded; ++ } ++ } ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (RA_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ cfa_store_offset -= 4; ++ save_reg (FP_REGNO, cfa_store_offset, cfa_store_reg); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ cfa_store_offset -= 4; ++ save_reg (i, cfa_store_offset, cfa_store_reg); ++ } ++ } ++ ++ if (frame_pointer_needed) ++ { ++ insn = emit_insn (gen_rtx_SET (SImode, ++ gen_rtx_REG (SImode, FP_REGNO), ++ gen_rtx_REG (SImode, SP_REGNO))); ++ ++ RTX_FRAME_RELATED_P (insn) = 1; ++ } ++ ++ /* If we are profiling, make sure no instructions are scheduled before ++ the call to mcount. */ ++ if (current_function_profile) ++ emit_insn (gen_blockage ()); ++} ++ ++void ++expand_epilogue (bool sibcall_p) ++{ ++ rtx insn; ++ int i; ++ HOST_WIDE_INT total_frame_size; ++ int register_store_offset; ++ ++ total_frame_size = compute_frame_size (); ++ ++ if (!sibcall_p && nios2_can_use_return_insn ()) ++ { ++ insn = emit_jump_insn (gen_return ()); ++ return; ++ } ++ ++ emit_insn (gen_blockage ()); ++ ++ register_store_offset = ++ cfun->machine->frame.save_regs_offset + ++ cfun->machine->frame.save_reg_rounded; ++ ++ if (MUST_SAVE_REGISTER (RA_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (RA_REGNO, register_store_offset); ++ } ++ ++ if (MUST_SAVE_REGISTER (FP_REGNO)) ++ { ++ register_store_offset -= 4; ++ restore_reg (FP_REGNO, register_store_offset); ++ } ++ ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) ++ { ++ if (MUST_SAVE_REGISTER (i) && i != FP_REGNO && i != RA_REGNO) ++ { ++ register_store_offset -= 4; ++ restore_reg (i, register_store_offset); ++ } ++ } ++ ++ if (total_frame_size) ++ { ++ rtx sp_adjust; ++ ++ if (TOO_BIG_OFFSET (total_frame_size)) ++ { ++ sp_adjust = gen_rtx_REG (SImode, TEMP_REG_NUM); ++ insn = emit_insn (gen_rtx_SET (SImode, ++ sp_adjust, ++ GEN_INT (total_frame_size))); ++ ++ } ++ else ++ { ++ sp_adjust = GEN_INT (total_frame_size); ++ } ++ ++ insn = gen_rtx_SET (SImode, ++ stack_pointer_rtx, ++ gen_rtx_PLUS (SImode, ++ stack_pointer_rtx, ++ sp_adjust)); ++ insn = emit_insn (insn); ++ } ++ ++ ++ if (!sibcall_p) ++ { ++ insn = emit_jump_insn (gen_return_from_epilogue (gen_rtx (REG, Pmode, ++ RA_REGNO))); ++ } ++} ++ ++ ++bool ++nios2_function_ok_for_sibcall (tree a ATTRIBUTE_UNUSED, tree b ATTRIBUTE_UNUSED) ++{ ++ return true; ++} ++ ++ ++ ++ ++ ++/* ----------------------- * ++ * Profiling ++ * ----------------------- */ ++ ++void ++function_profiler (FILE *file, int labelno) ++{ ++ fprintf (file, "\t%s mcount begin, label: .LP%d\n", ++ ASM_COMMENT_START, labelno); ++ fprintf (file, "\tnextpc\tr8\n"); ++ fprintf (file, "\tmov\tr9, ra\n"); ++ fprintf (file, "\tmovhi\tr10, %%hiadj(.LP%d)\n", labelno); ++ fprintf (file, "\taddi\tr10, r10, %%lo(.LP%d)\n", labelno); ++ fprintf (file, "\tcall\tmcount\n"); ++ fprintf (file, "\tmov\tra, r9\n"); ++ fprintf (file, "\t%s mcount end\n", ASM_COMMENT_START); ++} ++ ++ ++/*************************************** ++ * Stack Layout ++ ***************************************/ ++ ++ ++void ++dump_frame_size (FILE *file) ++{ ++ fprintf (file, "\t%s Current Frame Info\n", ASM_COMMENT_START); ++ ++ fprintf (file, "\t%s total_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.total_size); ++ fprintf (file, "\t%s var_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.var_size); ++ fprintf (file, "\t%s args_size = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.args_size); ++ fprintf (file, "\t%s save_reg_size = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_size); ++ fprintf (file, "\t%s save_reg_rounded = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_reg_rounded); ++ fprintf (file, "\t%s initialized = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.initialized); ++ fprintf (file, "\t%s num_regs = %d\n", ASM_COMMENT_START, ++ cfun->machine->frame.num_regs); ++ fprintf (file, "\t%s save_regs_offset = %ld\n", ASM_COMMENT_START, ++ cfun->machine->frame.save_regs_offset); ++ fprintf (file, "\t%s current_function_is_leaf = %d\n", ASM_COMMENT_START, ++ current_function_is_leaf); ++ fprintf (file, "\t%s frame_pointer_needed = %d\n", ASM_COMMENT_START, ++ frame_pointer_needed); ++ fprintf (file, "\t%s pretend_args_size = %d\n", ASM_COMMENT_START, ++ current_function_pretend_args_size); ++ ++} ++ ++ ++/* Return the bytes needed to compute the frame pointer from the current ++ stack pointer. ++*/ ++ ++HOST_WIDE_INT ++compute_frame_size () ++{ ++ unsigned int regno; ++ HOST_WIDE_INT var_size; /* # of var. bytes allocated */ ++ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up */ ++ HOST_WIDE_INT save_reg_size; /* # bytes needed to store callee save regs */ ++ HOST_WIDE_INT save_reg_rounded; ++ /* # bytes needed to store callee save regs (rounded) */ ++ HOST_WIDE_INT out_args_size; /* # bytes needed for outgoing args */ ++ ++ save_reg_size = 0; ++ var_size = STACK_ALIGN (get_frame_size ()); ++ out_args_size = STACK_ALIGN (current_function_outgoing_args_size); ++ ++ total_size = var_size + out_args_size; ++ ++ /* Calculate space needed for gp registers. */ ++ for (regno = 0; regno <= FIRST_PSEUDO_REGISTER; regno++) ++ { ++ if (MUST_SAVE_REGISTER (regno)) ++ { ++ save_reg_size += 4; ++ } ++ } ++ ++ save_reg_rounded = STACK_ALIGN (save_reg_size); ++ total_size += save_reg_rounded; ++ ++ total_size += STACK_ALIGN (current_function_pretend_args_size); ++ ++ /* Save other computed information. */ ++ cfun->machine->frame.total_size = total_size; ++ cfun->machine->frame.var_size = var_size; ++ cfun->machine->frame.args_size = current_function_outgoing_args_size; ++ cfun->machine->frame.save_reg_size = save_reg_size; ++ cfun->machine->frame.save_reg_rounded = save_reg_rounded; ++ cfun->machine->frame.initialized = reload_completed; ++ cfun->machine->frame.num_regs = save_reg_size / UNITS_PER_WORD; ++ ++ cfun->machine->frame.save_regs_offset ++ = save_reg_rounded ? current_function_outgoing_args_size + var_size : 0; ++ ++ return total_size; ++} ++ ++ ++int ++nios2_initial_elimination_offset (int from, int to ATTRIBUTE_UNUSED) ++{ ++ int offset; ++ ++ /* Set OFFSET to the offset from the stack pointer. */ ++ switch (from) ++ { ++ case FRAME_POINTER_REGNUM: ++ offset = 0; ++ break; ++ ++ case ARG_POINTER_REGNUM: ++ compute_frame_size (); ++ offset = cfun->machine->frame.total_size; ++ offset -= current_function_pretend_args_size; ++ break; ++ ++ case RETURN_ADDRESS_POINTER_REGNUM: ++ compute_frame_size (); ++ /* since the return address is always the first of the ++ saved registers, return the offset to the beginning ++ of the saved registers block */ ++ offset = cfun->machine->frame.save_regs_offset; ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ return offset; ++} ++ ++/* Return nonzero if this function is known to have a null epilogue. ++ This allows the optimizer to omit jumps to jumps if no stack ++ was created. */ ++int ++nios2_can_use_return_insn () ++{ ++ if (!reload_completed) ++ return 0; ++ ++ if (regs_ever_live[RA_REGNO] || current_function_profile) ++ return 0; ++ ++ if (cfun->machine->frame.initialized) ++ return cfun->machine->frame.total_size == 0; ++ ++ return compute_frame_size () == 0; ++} ++ ++ ++ ++ ++ ++/*************************************** ++ * ++ ***************************************/ ++ ++const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++const char *nios2_sys_lib_string; /* for -msys-lib= */ ++const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++void ++override_options () ++{ ++ /* Function to allocate machine-dependent function status. */ ++ init_machine_status = &nios2_init_machine_status; ++ ++ nios2_section_threshold ++ = g_switch_set ? g_switch_value : NIOS2_DEFAULT_GVALUE; ++ ++ if (nios2_sys_nosys_string && *nios2_sys_nosys_string) ++ { ++ error ("invalid option '-msys=nosys%s'", nios2_sys_nosys_string); ++ } ++ ++ /* If we don't have mul, we don't have mulx either! */ ++ if (!TARGET_HAS_MUL && TARGET_HAS_MULX) ++ { ++ target_flags &= ~HAS_MULX_FLAG; ++ } ++ ++} ++ ++void ++optimization_options (int level, int size) ++{ ++ if (level || size) ++ { ++ target_flags |= INLINE_MEMCPY_FLAG; ++ } ++ ++ if (level >= 3 && !size) ++ { ++ target_flags |= FAST_SW_DIV_FLAG; ++ } ++} ++ ++/* Allocate a chunk of memory for per-function machine-dependent data. */ ++static struct machine_function * ++nios2_init_machine_status () ++{ ++ return ((struct machine_function *) ++ ggc_alloc_cleared (sizeof (struct machine_function))); ++} ++ ++ ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++/* Compute a (partial) cost for rtx X. Return true if the complete ++ cost has been computed, and false if subexpressions should be ++ scanned. In either case, *TOTAL contains the cost result. */ ++ ++ ++ ++static bool ++nios2_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total) ++{ ++ switch (code) ++ { ++ case CONST_INT: ++ if (INTVAL (x) == 0) ++ { ++ *total = COSTS_N_INSNS (0); ++ return true; ++ } ++ else if (SMALL_INT (INTVAL (x)) ++ || SMALL_INT_UNSIGNED (INTVAL (x)) ++ || UPPER16_INT (INTVAL (x))) ++ { ++ *total = COSTS_N_INSNS (2); ++ return true; ++ } ++ else ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case LABEL_REF: ++ case SYMBOL_REF: ++ /* ??? gp relative stuff will fit in here */ ++ /* fall through */ ++ case CONST: ++ case CONST_DOUBLE: ++ { ++ *total = COSTS_N_INSNS (4); ++ return true; ++ } ++ ++ case MULT: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ case SIGN_EXTEND: ++ { ++ *total = COSTS_N_INSNS (3); ++ return false; ++ } ++ case ZERO_EXTEND: ++ { ++ *total = COSTS_N_INSNS (1); ++ return false; ++ } ++ ++ default: ++ return false; ++ } ++} ++ ++ ++/*************************************** ++ * INSTRUCTION SUPPORT ++ * ++ * These functions are used within the Machine Description to ++ * handle common or complicated output and expansions from ++ * instructions. ++ ***************************************/ ++ ++int ++nios2_emit_move_sequence (rtx *operands, enum machine_mode mode) ++{ ++ rtx to = operands[0]; ++ rtx from = operands[1]; ++ ++ if (!register_operand (to, mode) && !reg_or_0_operand (from, mode)) ++ { ++ if (no_new_pseudos) ++ internal_error ("Trying to force_reg no_new_pseudos == 1"); ++ from = copy_to_mode_reg (mode, from); ++ } ++ ++ operands[0] = to; ++ operands[1] = from; ++ return 0; ++} ++ ++/* Divide Support */ ++ ++/* ++ If -O3 is used, we want to output a table lookup for ++ divides between small numbers (both num and den >= 0 ++ and < 0x10). The overhead of this method in the worse ++ case is 40 bytes in the text section (10 insns) and ++ 256 bytes in the data section. Additional divides do ++ not incur additional penalties in the data section. ++ ++ Code speed is improved for small divides by about 5x ++ when using this method in the worse case (~9 cycles ++ vs ~45). And in the worse case divides not within the ++ table are penalized by about 10% (~5 cycles vs ~45). ++ However in the typical case the penalty is not as bad ++ because doing the long divide in only 45 cycles is ++ quite optimistic. ++ ++ ??? It would be nice to have some benchmarks other ++ than Dhrystone to back this up. ++ ++ This bit of expansion is to create this instruction ++ sequence as rtl. ++ or $8, $4, $5 ++ slli $9, $4, 4 ++ cmpgeui $3, $8, 16 ++ beq $3, $0, .L3 ++ or $10, $9, $5 ++ add $12, $11, divide_table ++ ldbu $2, 0($12) ++ br .L1 ++.L3: ++ call slow_div ++.L1: ++# continue here with result in $2 ++ ++ ??? Ideally I would like the emit libcall block to contain ++ all of this code, but I don't know how to do that. What it ++ means is that if the divide can be eliminated, it may not ++ completely disappear. ++ ++ ??? The __divsi3_table label should ideally be moved out ++ of this block and into a global. If it is placed into the ++ sdata section we can save even more cycles by doing things ++ gp relative. ++*/ ++int ++nios2_emit_expensive_div (rtx *operands, enum machine_mode mode) ++{ ++ rtx or_result, shift_left_result; ++ rtx lookup_value; ++ rtx lab1, lab3; ++ rtx insns; ++ rtx libfunc; ++ rtx final_result; ++ rtx tmp; ++ ++ /* it may look a little generic, but only SImode ++ is supported for now */ ++ if (mode != SImode) ++ abort (); ++ ++ libfunc = sdiv_optab->handlers[(int) SImode].libfunc; ++ ++ ++ ++ lab1 = gen_label_rtx (); ++ lab3 = gen_label_rtx (); ++ ++ or_result = expand_simple_binop (SImode, IOR, ++ operands[1], operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ emit_cmp_and_jump_insns (or_result, GEN_INT (15), GTU, 0, ++ GET_MODE (or_result), 0, lab3); ++ JUMP_LABEL (get_last_insn ()) = lab3; ++ ++ shift_left_result = expand_simple_binop (SImode, ASHIFT, ++ operands[1], GEN_INT (4), ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ lookup_value = expand_simple_binop (SImode, IOR, ++ shift_left_result, operands[2], ++ 0, 0, OPTAB_LIB_WIDEN); ++ ++ convert_move (operands[0], ++ gen_rtx (MEM, QImode, ++ gen_rtx (PLUS, SImode, ++ lookup_value, ++ gen_rtx_SYMBOL_REF (SImode, "__divsi3_table"))), ++ 1); ++ ++ ++ tmp = emit_jump_insn (gen_jump (lab1)); ++ JUMP_LABEL (tmp) = lab1; ++ emit_barrier (); ++ ++ emit_label (lab3); ++ LABEL_NUSES (lab3) = 1; ++ ++ start_sequence (); ++ final_result = emit_library_call_value (libfunc, NULL_RTX, ++ LCT_CONST, SImode, 2, ++ operands[1], SImode, ++ operands[2], SImode); ++ ++ ++ insns = get_insns (); ++ end_sequence (); ++ emit_libcall_block (insns, operands[0], final_result, ++ gen_rtx (DIV, SImode, operands[1], operands[2])); ++ ++ emit_label (lab1); ++ LABEL_NUSES (lab1) = 1; ++ return 1; ++} ++ ++/* Branches/Compares */ ++ ++/* the way of handling branches/compares ++ in gcc is heavily borrowed from MIPS */ ++ ++enum internal_test ++{ ++ ITEST_EQ, ++ ITEST_NE, ++ ITEST_GT, ++ ITEST_GE, ++ ITEST_LT, ++ ITEST_LE, ++ ITEST_GTU, ++ ITEST_GEU, ++ ITEST_LTU, ++ ITEST_LEU, ++ ITEST_MAX ++}; ++ ++static enum internal_test map_test_to_internal_test (enum rtx_code); ++ ++/* Cached operands, and operator to compare for use in set/branch/trap ++ on condition codes. */ ++rtx branch_cmp[2]; ++enum cmp_type branch_type; ++ ++/* Make normal rtx_code into something we can index from an array */ ++ ++static enum internal_test ++map_test_to_internal_test (enum rtx_code test_code) ++{ ++ enum internal_test test = ITEST_MAX; ++ ++ switch (test_code) ++ { ++ case EQ: ++ test = ITEST_EQ; ++ break; ++ case NE: ++ test = ITEST_NE; ++ break; ++ case GT: ++ test = ITEST_GT; ++ break; ++ case GE: ++ test = ITEST_GE; ++ break; ++ case LT: ++ test = ITEST_LT; ++ break; ++ case LE: ++ test = ITEST_LE; ++ break; ++ case GTU: ++ test = ITEST_GTU; ++ break; ++ case GEU: ++ test = ITEST_GEU; ++ break; ++ case LTU: ++ test = ITEST_LTU; ++ break; ++ case LEU: ++ test = ITEST_LEU; ++ break; ++ default: ++ break; ++ } ++ ++ return test; ++} ++ ++/* Generate the code to compare (and possibly branch) two integer values ++ TEST_CODE is the comparison code we are trying to emulate ++ (or implement directly) ++ RESULT is where to store the result of the comparison, ++ or null to emit a branch ++ CMP0 CMP1 are the two comparison operands ++ DESTINATION is the destination of the branch, or null to only compare ++ */ ++ ++void ++gen_int_relational (enum rtx_code test_code, /* relational test (EQ, etc) */ ++ rtx result, /* result to store comp. or 0 if branch */ ++ rtx cmp0, /* first operand to compare */ ++ rtx cmp1, /* second operand to compare */ ++ rtx destination) /* destination of the branch, or 0 if compare */ ++{ ++ struct cmp_info ++ { ++ /* for register (or 0) compares */ ++ enum rtx_code test_code_reg; /* code to use in instruction (LT vs. LTU) */ ++ int reverse_regs; /* reverse registers in test */ ++ ++ /* for immediate compares */ ++ enum rtx_code test_code_const; ++ /* code to use in instruction (LT vs. LTU) */ ++ int const_low; /* low bound of constant we can accept */ ++ int const_high; /* high bound of constant we can accept */ ++ int const_add; /* constant to add */ ++ ++ /* generic info */ ++ int unsignedp; /* != 0 for unsigned comparisons. */ ++ }; ++ ++ static const struct cmp_info info[(int) ITEST_MAX] = { ++ ++ {EQ, 0, EQ, -32768, 32767, 0, 0}, /* EQ */ ++ {NE, 0, NE, -32768, 32767, 0, 0}, /* NE */ ++ ++ {LT, 1, GE, -32769, 32766, 1, 0}, /* GT */ ++ {GE, 0, GE, -32768, 32767, 0, 0}, /* GE */ ++ {LT, 0, LT, -32768, 32767, 0, 0}, /* LT */ ++ {GE, 1, LT, -32769, 32766, 1, 0}, /* LE */ ++ ++ {LTU, 1, GEU, 0, 65534, 1, 0}, /* GTU */ ++ {GEU, 0, GEU, 0, 65535, 0, 0}, /* GEU */ ++ {LTU, 0, LTU, 0, 65535, 0, 0}, /* LTU */ ++ {GEU, 1, LTU, 0, 65534, 1, 0}, /* LEU */ ++ }; ++ ++ enum internal_test test; ++ enum machine_mode mode; ++ const struct cmp_info *p_info; ++ int branch_p; ++ ++ ++ ++ ++ test = map_test_to_internal_test (test_code); ++ if (test == ITEST_MAX) ++ abort (); ++ ++ p_info = &info[(int) test]; ++ ++ mode = GET_MODE (cmp0); ++ if (mode == VOIDmode) ++ mode = GET_MODE (cmp1); ++ ++ branch_p = (destination != 0); ++ ++ /* We can't, under any circumstances, have const_ints in cmp0 ++ ??? Actually we could have const0 */ ++ if (GET_CODE (cmp0) == CONST_INT) ++ cmp0 = force_reg (mode, cmp0); ++ ++ /* if the comparison is against an int not in legal range ++ move it into a register */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ HOST_WIDE_INT value = INTVAL (cmp1); ++ ++ if (value < p_info->const_low || value > p_info->const_high) ++ cmp1 = force_reg (mode, cmp1); ++ } ++ ++ /* Comparison to constants, may involve adding 1 to change a GT into GE. ++ Comparison between two registers, may involve switching operands. */ ++ if (GET_CODE (cmp1) == CONST_INT) ++ { ++ if (p_info->const_add != 0) ++ { ++ HOST_WIDE_INT new = INTVAL (cmp1) + p_info->const_add; ++ ++ /* If modification of cmp1 caused overflow, ++ we would get the wrong answer if we follow the usual path; ++ thus, x > 0xffffffffU would turn into x > 0U. */ ++ if ((p_info->unsignedp ++ ? (unsigned HOST_WIDE_INT) new > ++ (unsigned HOST_WIDE_INT) INTVAL (cmp1) ++ : new > INTVAL (cmp1)) != (p_info->const_add > 0)) ++ { ++ /* ??? This case can never happen with the current numbers, ++ but I am paranoid and would rather an abort than ++ a bug I will never find */ ++ abort (); ++ } ++ else ++ cmp1 = GEN_INT (new); ++ } ++ } ++ ++ else if (p_info->reverse_regs) ++ { ++ rtx temp = cmp0; ++ cmp0 = cmp1; ++ cmp1 = temp; ++ } ++ ++ ++ ++ if (branch_p) ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ rtx insn; ++ rtx cond = gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1); ++ rtx label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ insn = gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, label, pc_rtx)); ++ emit_jump_insn (insn); ++ } ++ else ++ { ++ rtx cond, label; ++ ++ result = gen_reg_rtx (mode); ++ ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ ++ cond = gen_rtx (NE, mode, result, const0_rtx); ++ label = gen_rtx_LABEL_REF (VOIDmode, destination); ++ ++ emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, ++ gen_rtx_IF_THEN_ELSE (VOIDmode, ++ cond, ++ label, pc_rtx))); ++ } ++ } ++ else ++ { ++ if (register_operand (cmp0, mode) && register_operand (cmp1, mode)) ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_reg, mode, cmp0, cmp1)); ++ } ++ else ++ { ++ emit_move_insn (result, ++ gen_rtx (p_info->test_code_const, mode, cmp0, ++ cmp1)); ++ } ++ } ++ ++} ++ ++ ++/* ??? For now conditional moves are only supported ++ when the mode of the operands being compared are ++ the same as the ones being moved */ ++ ++void ++gen_conditional_move (rtx *operands, enum machine_mode mode) ++{ ++ rtx insn, cond; ++ rtx cmp_reg = gen_reg_rtx (mode); ++ enum rtx_code cmp_code = GET_CODE (operands[1]); ++ enum rtx_code move_code = EQ; ++ ++ /* emit a comparison if it is not "simple". ++ Simple comparisons are X eq 0 and X ne 0 */ ++ if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[1] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[0]; ++ move_code = cmp_code; ++ } ++ else if ((cmp_code == EQ || cmp_code == NE) && branch_cmp[0] == const0_rtx) ++ { ++ cmp_reg = branch_cmp[1]; ++ move_code = cmp_code == EQ ? NE : EQ; ++ } ++ else ++ gen_int_relational (cmp_code, cmp_reg, branch_cmp[0], branch_cmp[1], ++ NULL_RTX); ++ ++ cond = gen_rtx (move_code, VOIDmode, cmp_reg, CONST0_RTX (mode)); ++ insn = gen_rtx_SET (mode, operands[0], ++ gen_rtx_IF_THEN_ELSE (mode, ++ cond, operands[2], operands[3])); ++ emit_insn (insn); ++} ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++int ++nios2_legitimate_address (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int strict) ++{ ++ int ret_val = 0; ++ ++ switch (GET_CODE (operand)) ++ { ++ /* direct. */ ++ case SYMBOL_REF: ++ if (SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (operand)) ++ { ++ ret_val = 1; ++ break; ++ } ++ /* else, fall through */ ++ case LABEL_REF: ++ case CONST_INT: ++ case CONST: ++ case CONST_DOUBLE: ++ /* ??? In here I need to add gp addressing */ ++ ret_val = 0; ++ ++ break; ++ ++ /* Register indirect. */ ++ case REG: ++ ret_val = REG_OK_FOR_BASE_P2 (operand, strict); ++ break; ++ ++ /* Register indirect with displacement */ ++ case PLUS: ++ { ++ rtx op0 = XEXP (operand, 0); ++ rtx op1 = XEXP (operand, 1); ++ ++ if (REG_P (op0) && REG_P (op1)) ++ ret_val = 0; ++ else if (REG_P (op0) && CONSTANT_P (op1)) ++ ret_val = REG_OK_FOR_BASE_P2 (op0, strict) ++ && SMALL_INT (INTVAL (op1)); ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ ret_val = REG_OK_FOR_BASE_P2 (op1, strict) ++ && SMALL_INT (INTVAL (op0)); ++ else ++ ret_val = 0; ++ } ++ break; ++ ++ default: ++ ret_val = 0; ++ break; ++ } ++ ++ return ret_val; ++} ++ ++/* Return true if EXP should be placed in the small data section. */ ++ ++static bool ++nios2_in_small_data_p (tree exp) ++{ ++ /* We want to merge strings, so we never consider them small data. */ ++ if (TREE_CODE (exp) == STRING_CST) ++ return false; ++ ++ if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp)) ++ { ++ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp)); ++ /* ??? these string names need moving into ++ an array in some header file */ ++ if (nios2_section_threshold > 0 ++ && (strcmp (section, ".sbss") == 0 ++ || strncmp (section, ".sbss.", 6) == 0 ++ || strcmp (section, ".sdata") == 0 ++ || strncmp (section, ".sdata.", 7) == 0)) ++ return true; ++ } ++ else if (TREE_CODE (exp) == VAR_DECL) ++ { ++ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp)); ++ ++ /* If this is an incomplete type with size 0, then we can't put it ++ in sdata because it might be too big when completed. */ ++ if (size > 0 && size <= nios2_section_threshold) ++ return true; ++ } ++ ++ return false; ++} ++ ++static void ++nios2_encode_section_info (tree decl, rtx rtl, int first) ++{ ++ ++ rtx symbol; ++ int flags; ++ ++ default_encode_section_info (decl, rtl, first); ++ ++ /* Careful not to prod global register variables. */ ++ if (GET_CODE (rtl) != MEM) ++ return; ++ symbol = XEXP (rtl, 0); ++ if (GET_CODE (symbol) != SYMBOL_REF) ++ return; ++ ++ flags = SYMBOL_REF_FLAGS (symbol); ++ ++ /* We don't want weak variables to be addressed with gp in case they end up with ++ value 0 which is not within 2^15 of $gp */ ++ if (DECL_P (decl) && DECL_WEAK (decl)) ++ flags |= SYMBOL_FLAG_WEAK_DECL; ++ ++ SYMBOL_REF_FLAGS (symbol) = flags; ++} ++ ++ ++static unsigned int ++nios2_section_type_flags (tree decl, const char *name, int reloc) ++{ ++ unsigned int flags; ++ ++ flags = default_section_type_flags (decl, name, reloc); ++ ++ /* ??? these string names need moving into an array in some header file */ ++ if (strcmp (name, ".sbss") == 0 ++ || strncmp (name, ".sbss.", 6) == 0 ++ || strcmp (name, ".sdata") == 0 ++ || strncmp (name, ".sdata.", 7) == 0) ++ flags |= SECTION_SMALL; ++ ++ return flags; ++} ++ ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++ ++/* print the operand OP to file stream ++ FILE modified by LETTER. LETTER ++ can be one of: ++ i: print "i" if OP is an immediate, except 0 ++ o: print "io" if OP is volatile ++ ++ z: for const0_rtx print $0 instead of 0 ++ H: for %hiadj ++ L: for %lo ++ U: for upper half of 32 bit value ++ */ ++ ++void ++nios2_print_operand (FILE *file, rtx op, int letter) ++{ ++ ++ switch (letter) ++ { ++ case 'i': ++ if (CONSTANT_P (op) && (op != const0_rtx)) ++ fprintf (file, "i"); ++ return; ++ ++ case 'o': ++ if (GET_CODE (op) == MEM ++ && ((MEM_VOLATILE_P (op) && !TARGET_CACHE_VOLATILE) ++ || TARGET_BYPASS_CACHE)) ++ fprintf (file, "io"); ++ return; ++ ++ default: ++ break; ++ } ++ ++ if (comparison_operator (op, VOIDmode)) ++ { ++ if (letter == 0) ++ { ++ fprintf (file, "%s", GET_RTX_NAME (GET_CODE (op))); ++ return; ++ } ++ } ++ ++ ++ switch (GET_CODE (op)) ++ { ++ case REG: ++ if (letter == 0 || letter == 'z') ++ { ++ fprintf (file, "%s", reg_names[REGNO (op)]); ++ return; ++ } ++ ++ case CONST_INT: ++ if (INTVAL (op) == 0 && letter == 'z') ++ { ++ fprintf (file, "zero"); ++ return; ++ } ++ else if (letter == 'U') ++ { ++ HOST_WIDE_INT val = INTVAL (op); ++ rtx new_op; ++ val = (val / 65536) & 0xFFFF; ++ new_op = GEN_INT (val); ++ output_addr_const (file, new_op); ++ return; ++ } ++ ++ /* else, fall through */ ++ case CONST: ++ case LABEL_REF: ++ case SYMBOL_REF: ++ case CONST_DOUBLE: ++ if (letter == 0 || letter == 'z') ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ else if (letter == 'H') ++ { ++ fprintf (file, "%%hiadj("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ else if (letter == 'L') ++ { ++ fprintf (file, "%%lo("); ++ output_addr_const (file, op); ++ fprintf (file, ")"); ++ return; ++ } ++ ++ ++ case SUBREG: ++ case MEM: ++ if (letter == 0) ++ { ++ output_address (op); ++ return; ++ } ++ ++ case CODE_LABEL: ++ if (letter == 0) ++ { ++ output_addr_const (file, op); ++ return; ++ } ++ ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print (%c) ", letter); ++ debug_rtx (op); ++ abort (); ++} ++ ++static int gprel_constant (rtx); ++ ++static int ++gprel_constant (rtx op) ++{ ++ if (GET_CODE (op) == SYMBOL_REF ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (op)) ++ { ++ return 1; ++ } ++ else if (GET_CODE (op) == CONST ++ && GET_CODE (XEXP (op, 0)) == PLUS) ++ { ++ return gprel_constant (XEXP (XEXP (op, 0), 0)); ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++void ++nios2_print_operand_address (FILE *file, rtx op) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST: ++ case CONST_INT: ++ case LABEL_REF: ++ case CONST_DOUBLE: ++ case SYMBOL_REF: ++ if (gprel_constant (op)) ++ { ++ fprintf (file, "%%gprel("); ++ output_addr_const (file, op); ++ fprintf (file, ")(%s)", reg_names[GP_REGNO]); ++ return; ++ } ++ ++ break; ++ ++ case PLUS: ++ { ++ rtx op0 = XEXP (op, 0); ++ rtx op1 = XEXP (op, 1); ++ ++ if (REG_P (op0) && CONSTANT_P (op1)) ++ { ++ output_addr_const (file, op1); ++ fprintf (file, "(%s)", reg_names[REGNO (op0)]); ++ return; ++ } ++ else if (REG_P (op1) && CONSTANT_P (op0)) ++ { ++ output_addr_const (file, op0); ++ fprintf (file, "(%s)", reg_names[REGNO (op1)]); ++ return; ++ } ++ } ++ break; ++ ++ case REG: ++ fprintf (file, "0(%s)", reg_names[REGNO (op)]); ++ return; ++ ++ case MEM: ++ { ++ rtx base = XEXP (op, 0); ++ PRINT_OPERAND_ADDRESS (file, base); ++ return; ++ } ++ default: ++ break; ++ } ++ ++ fprintf (stderr, "Missing way to print address\n"); ++ debug_rtx (op); ++ abort (); ++} ++ ++ ++ ++ ++ ++/**************************** ++ * Predicates ++ ****************************/ ++ ++int ++arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++uns_arith_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SMALL_INT_UNSIGNED (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++logical_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT ++ && (SMALL_INT_UNSIGNED (INTVAL (op)) || UPPER16_INT (INTVAL (op)))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++shift_operand (rtx op, enum machine_mode mode) ++{ ++ if (GET_CODE (op) == CONST_INT && SHIFT_INT (INTVAL (op))) ++ return 1; ++ ++ return register_operand (op, mode); ++} ++ ++int ++rdwrctl_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && RDWRCTL_INT (INTVAL (op)); ++} ++ ++/* Return truth value of whether OP is a register or the constant 0. */ ++ ++int ++reg_or_0_operand (rtx op, enum machine_mode mode) ++{ ++ switch (GET_CODE (op)) ++ { ++ case CONST_INT: ++ return INTVAL (op) == 0; ++ ++ case CONST_DOUBLE: ++ return op == CONST0_RTX (mode); ++ ++ default: ++ break; ++ } ++ ++ return register_operand (op, mode); ++} ++ ++ ++int ++equality_op (rtx op, enum machine_mode mode) ++{ ++ if (mode != GET_MODE (op)) ++ return 0; ++ ++ return GET_CODE (op) == EQ || GET_CODE (op) == NE; ++} ++ ++int ++custom_insn_opcode (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) ++{ ++ return GET_CODE (op) == CONST_INT && CUSTOM_INSN_OPCODE (INTVAL (op)); ++} ++ ++ ++ ++ ++ ++ ++ ++/***************************************************************************** ++** ++** instruction scheduler ++** ++*****************************************************************************/ ++static int ++nios2_use_dfa_pipeline_interface () ++{ ++ return 1; ++} ++ ++ ++static int ++nios2_issue_rate () ++{ ++#ifdef MAX_DFA_ISSUE_RATE ++ return MAX_DFA_ISSUE_RATE; ++#else ++ return 1; ++#endif ++} ++ ++ ++const char * ++asm_output_opcode (FILE *file ATTRIBUTE_UNUSED, ++ const char *ptr ATTRIBUTE_UNUSED) ++{ ++ const char *p; ++ ++ p = ptr; ++ return ptr; ++} ++ ++ ++ ++/***************************************************************************** ++** ++** function arguments ++** ++*****************************************************************************/ ++ ++void ++init_cumulative_args (CUMULATIVE_ARGS *cum, ++ tree fntype ATTRIBUTE_UNUSED, ++ rtx libname ATTRIBUTE_UNUSED, ++ tree fndecl ATTRIBUTE_UNUSED, ++ int n_named_args ATTRIBUTE_UNUSED) ++{ ++ cum->regs_used = 0; ++} ++ ++ ++/* Update the data in CUM to advance over an argument ++ of mode MODE and data type TYPE. ++ (TYPE is null for libcalls where that information may not be available.) */ ++ ++void ++function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ cum->regs_used = NUM_ARG_REGS; ++ } ++ else ++ { ++ cum->regs_used += param_size; ++ } ++ ++ return; ++} ++ ++/* Define where to put the arguments to a function. Value is zero to ++ push the argument on the stack, or a hard register in which to ++ store the argument. ++ ++ MODE is the argument's machine mode. ++ TYPE is the data type of the argument (as a tree). ++ This is null for libcalls where that information may ++ not be available. ++ CUM is a variable of type CUMULATIVE_ARGS which gives info about ++ the preceding args and about the function being called. ++ NAMED is nonzero if this argument is a named parameter ++ (otherwise it is an extra parameter matching an ellipsis). */ ++rtx ++function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode, ++ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED) ++{ ++ rtx return_rtx = NULL_RTX; ++ ++ if (cum->regs_used < NUM_ARG_REGS) ++ { ++ return_rtx = gen_rtx_REG (mode, FIRST_ARG_REGNO + cum->regs_used); ++ } ++ ++ return return_rtx; ++} ++ ++int ++function_arg_partial_nregs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int named ATTRIBUTE_UNUSED) ++{ ++ HOST_WIDE_INT param_size; ++ ++ if (mode == BLKmode) ++ { ++ param_size = int_size_in_bytes (type); ++ if (param_size < 0) ++ internal_error ++ ("Do not know how to handle large structs or variable length types"); ++ } ++ else ++ { ++ param_size = GET_MODE_SIZE (mode); ++ } ++ ++ /* convert to words (round up) */ ++ param_size = (3 + param_size) / 4; ++ ++ if (cum->regs_used < NUM_ARG_REGS ++ && cum->regs_used + param_size > NUM_ARG_REGS) ++ { ++ return NUM_ARG_REGS - cum->regs_used; ++ } ++ else ++ { ++ return 0; ++ } ++} ++ ++ ++int ++nios2_return_in_memory (tree type) ++{ ++ int res = ((int_size_in_bytes (type) > (2 * UNITS_PER_WORD)) ++ || (int_size_in_bytes (type) == -1)); ++ ++ return res; ++} ++ ++/* ??? It may be possible to eliminate the copyback and implement ++ my own va_arg type, but that is more work for now. */ ++int ++nios2_setup_incoming_varargs (const CUMULATIVE_ARGS *cum, ++ enum machine_mode mode, tree type, ++ int no_rtl) ++{ ++ CUMULATIVE_ARGS local_cum; ++ int regs_to_push; ++ ++ local_cum = *cum; ++ FUNCTION_ARG_ADVANCE (local_cum, mode, type, 1); ++ ++ regs_to_push = NUM_ARG_REGS - local_cum.regs_used; ++ ++ if (!no_rtl) ++ { ++ if (regs_to_push > 0) ++ { ++ rtx ptr, mem; ++ ++ ptr = virtual_incoming_args_rtx; ++ mem = gen_rtx_MEM (BLKmode, ptr); ++ ++ /* va_arg is an array access in this case, which causes ++ it to get MEM_IN_STRUCT_P set. We must set it here ++ so that the insn scheduler won't assume that these ++ stores can't possibly overlap with the va_arg loads. */ ++ MEM_SET_IN_STRUCT_P (mem, 1); ++ ++ emit_insn (gen_blockage ()); ++ move_block_from_reg (local_cum.regs_used + FIRST_ARG_REGNO, mem, ++ regs_to_push); ++ emit_insn (gen_blockage ()); ++ } ++ } ++ ++ return regs_to_push * UNITS_PER_WORD; ++ ++} ++ ++ ++ ++/***************************************************************************** ++** ++** builtins ++** ++** This method for handling builtins is from CSP where _many_ more types of ++** expanders have already been written. Check there first before writing ++** new ones. ++** ++*****************************************************************************/ ++ ++enum nios2_builtins ++{ ++ NIOS2_BUILTIN_LDBIO, ++ NIOS2_BUILTIN_LDBUIO, ++ NIOS2_BUILTIN_LDHIO, ++ NIOS2_BUILTIN_LDHUIO, ++ NIOS2_BUILTIN_LDWIO, ++ NIOS2_BUILTIN_STBIO, ++ NIOS2_BUILTIN_STHIO, ++ NIOS2_BUILTIN_STWIO, ++ NIOS2_BUILTIN_SYNC, ++ NIOS2_BUILTIN_RDCTL, ++ NIOS2_BUILTIN_WRCTL, ++ ++ NIOS2_BUILTIN_CUSTOM_N, ++ NIOS2_BUILTIN_CUSTOM_NI, ++ NIOS2_BUILTIN_CUSTOM_NF, ++ NIOS2_BUILTIN_CUSTOM_NP, ++ NIOS2_BUILTIN_CUSTOM_NII, ++ NIOS2_BUILTIN_CUSTOM_NIF, ++ NIOS2_BUILTIN_CUSTOM_NIP, ++ NIOS2_BUILTIN_CUSTOM_NFI, ++ NIOS2_BUILTIN_CUSTOM_NFF, ++ NIOS2_BUILTIN_CUSTOM_NFP, ++ NIOS2_BUILTIN_CUSTOM_NPI, ++ NIOS2_BUILTIN_CUSTOM_NPF, ++ NIOS2_BUILTIN_CUSTOM_NPP, ++ NIOS2_BUILTIN_CUSTOM_IN, ++ NIOS2_BUILTIN_CUSTOM_INI, ++ NIOS2_BUILTIN_CUSTOM_INF, ++ NIOS2_BUILTIN_CUSTOM_INP, ++ NIOS2_BUILTIN_CUSTOM_INII, ++ NIOS2_BUILTIN_CUSTOM_INIF, ++ NIOS2_BUILTIN_CUSTOM_INIP, ++ NIOS2_BUILTIN_CUSTOM_INFI, ++ NIOS2_BUILTIN_CUSTOM_INFF, ++ NIOS2_BUILTIN_CUSTOM_INFP, ++ NIOS2_BUILTIN_CUSTOM_INPI, ++ NIOS2_BUILTIN_CUSTOM_INPF, ++ NIOS2_BUILTIN_CUSTOM_INPP, ++ NIOS2_BUILTIN_CUSTOM_FN, ++ NIOS2_BUILTIN_CUSTOM_FNI, ++ NIOS2_BUILTIN_CUSTOM_FNF, ++ NIOS2_BUILTIN_CUSTOM_FNP, ++ NIOS2_BUILTIN_CUSTOM_FNII, ++ NIOS2_BUILTIN_CUSTOM_FNIF, ++ NIOS2_BUILTIN_CUSTOM_FNIP, ++ NIOS2_BUILTIN_CUSTOM_FNFI, ++ NIOS2_BUILTIN_CUSTOM_FNFF, ++ NIOS2_BUILTIN_CUSTOM_FNFP, ++ NIOS2_BUILTIN_CUSTOM_FNPI, ++ NIOS2_BUILTIN_CUSTOM_FNPF, ++ NIOS2_BUILTIN_CUSTOM_FNPP, ++ NIOS2_BUILTIN_CUSTOM_PN, ++ NIOS2_BUILTIN_CUSTOM_PNI, ++ NIOS2_BUILTIN_CUSTOM_PNF, ++ NIOS2_BUILTIN_CUSTOM_PNP, ++ NIOS2_BUILTIN_CUSTOM_PNII, ++ NIOS2_BUILTIN_CUSTOM_PNIF, ++ NIOS2_BUILTIN_CUSTOM_PNIP, ++ NIOS2_BUILTIN_CUSTOM_PNFI, ++ NIOS2_BUILTIN_CUSTOM_PNFF, ++ NIOS2_BUILTIN_CUSTOM_PNFP, ++ NIOS2_BUILTIN_CUSTOM_PNPI, ++ NIOS2_BUILTIN_CUSTOM_PNPF, ++ NIOS2_BUILTIN_CUSTOM_PNPP, ++ ++ ++ LIM_NIOS2_BUILTINS ++}; ++ ++struct builtin_description ++{ ++ const enum insn_code icode; ++ const char *const name; ++ const enum nios2_builtins code; ++ const tree *type; ++ rtx (* expander) PARAMS ((const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int)); ++}; ++ ++static rtx nios2_expand_STXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_LDXIO (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_sync (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_rdctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_wrctl (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static rtx nios2_expand_custom_n (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_Xn (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_nXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++static rtx nios2_expand_custom_XnXX (const struct builtin_description *, ++ tree, rtx, rtx, enum machine_mode, int); ++ ++static tree endlink; ++ ++/* int fn (volatile const void *) ++ */ ++static tree int_ftype_volatile_const_void_p; ++ ++/* int fn (int) ++ */ ++static tree int_ftype_int; ++ ++/* void fn (int, int) ++ */ ++static tree void_ftype_int_int; ++ ++/* void fn (volatile void *, int) ++ */ ++static tree void_ftype_volatile_void_p_int; ++ ++/* void fn (void) ++ */ ++static tree void_ftype_void; ++ ++static tree custom_n; ++static tree custom_ni; ++static tree custom_nf; ++static tree custom_np; ++static tree custom_nii; ++static tree custom_nif; ++static tree custom_nip; ++static tree custom_nfi; ++static tree custom_nff; ++static tree custom_nfp; ++static tree custom_npi; ++static tree custom_npf; ++static tree custom_npp; ++static tree custom_in; ++static tree custom_ini; ++static tree custom_inf; ++static tree custom_inp; ++static tree custom_inii; ++static tree custom_inif; ++static tree custom_inip; ++static tree custom_infi; ++static tree custom_inff; ++static tree custom_infp; ++static tree custom_inpi; ++static tree custom_inpf; ++static tree custom_inpp; ++static tree custom_fn; ++static tree custom_fni; ++static tree custom_fnf; ++static tree custom_fnp; ++static tree custom_fnii; ++static tree custom_fnif; ++static tree custom_fnip; ++static tree custom_fnfi; ++static tree custom_fnff; ++static tree custom_fnfp; ++static tree custom_fnpi; ++static tree custom_fnpf; ++static tree custom_fnpp; ++static tree custom_pn; ++static tree custom_pni; ++static tree custom_pnf; ++static tree custom_pnp; ++static tree custom_pnii; ++static tree custom_pnif; ++static tree custom_pnip; ++static tree custom_pnfi; ++static tree custom_pnff; ++static tree custom_pnfp; ++static tree custom_pnpi; ++static tree custom_pnpf; ++static tree custom_pnpp; ++ ++ ++static const struct builtin_description bdesc[] = { ++ {CODE_FOR_ldbio, "__builtin_ldbio", NIOS2_BUILTIN_LDBIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldbuio, "__builtin_ldbuio", NIOS2_BUILTIN_LDBUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhio, "__builtin_ldhio", NIOS2_BUILTIN_LDHIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldhuio, "__builtin_ldhuio", NIOS2_BUILTIN_LDHUIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ {CODE_FOR_ldwio, "__builtin_ldwio", NIOS2_BUILTIN_LDWIO, &int_ftype_volatile_const_void_p, nios2_expand_LDXIO}, ++ ++ {CODE_FOR_stbio, "__builtin_stbio", NIOS2_BUILTIN_STBIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_sthio, "__builtin_sthio", NIOS2_BUILTIN_STHIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ {CODE_FOR_stwio, "__builtin_stwio", NIOS2_BUILTIN_STWIO, &void_ftype_volatile_void_p_int, nios2_expand_STXIO}, ++ ++ {CODE_FOR_sync, "__builtin_sync", NIOS2_BUILTIN_SYNC, &void_ftype_void, nios2_expand_sync}, ++ {CODE_FOR_rdctl, "__builtin_rdctl", NIOS2_BUILTIN_RDCTL, &int_ftype_int, nios2_expand_rdctl}, ++ {CODE_FOR_wrctl, "__builtin_wrctl", NIOS2_BUILTIN_WRCTL, &void_ftype_int_int, nios2_expand_wrctl}, ++ ++ {CODE_FOR_custom_n, "__builtin_custom_n", NIOS2_BUILTIN_CUSTOM_N, &custom_n, nios2_expand_custom_n}, ++ {CODE_FOR_custom_ni, "__builtin_custom_ni", NIOS2_BUILTIN_CUSTOM_NI, &custom_ni, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nf, "__builtin_custom_nf", NIOS2_BUILTIN_CUSTOM_NF, &custom_nf, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_np, "__builtin_custom_np", NIOS2_BUILTIN_CUSTOM_NP, &custom_np, nios2_expand_custom_nX}, ++ {CODE_FOR_custom_nii, "__builtin_custom_nii", NIOS2_BUILTIN_CUSTOM_NII, &custom_nii, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nif, "__builtin_custom_nif", NIOS2_BUILTIN_CUSTOM_NIF, &custom_nif, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nip, "__builtin_custom_nip", NIOS2_BUILTIN_CUSTOM_NIP, &custom_nip, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfi, "__builtin_custom_nfi", NIOS2_BUILTIN_CUSTOM_NFI, &custom_nfi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nff, "__builtin_custom_nff", NIOS2_BUILTIN_CUSTOM_NFF, &custom_nff, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_nfp, "__builtin_custom_nfp", NIOS2_BUILTIN_CUSTOM_NFP, &custom_nfp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npi, "__builtin_custom_npi", NIOS2_BUILTIN_CUSTOM_NPI, &custom_npi, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npf, "__builtin_custom_npf", NIOS2_BUILTIN_CUSTOM_NPF, &custom_npf, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_npp, "__builtin_custom_npp", NIOS2_BUILTIN_CUSTOM_NPP, &custom_npp, nios2_expand_custom_nXX}, ++ {CODE_FOR_custom_in, "__builtin_custom_in", NIOS2_BUILTIN_CUSTOM_IN, &custom_in, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_ini, "__builtin_custom_ini", NIOS2_BUILTIN_CUSTOM_INI, &custom_ini, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inf, "__builtin_custom_inf", NIOS2_BUILTIN_CUSTOM_INF, &custom_inf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inp, "__builtin_custom_inp", NIOS2_BUILTIN_CUSTOM_INP, &custom_inp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_inii, "__builtin_custom_inii", NIOS2_BUILTIN_CUSTOM_INII, &custom_inii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inif, "__builtin_custom_inif", NIOS2_BUILTIN_CUSTOM_INIF, &custom_inif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inip, "__builtin_custom_inip", NIOS2_BUILTIN_CUSTOM_INIP, &custom_inip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infi, "__builtin_custom_infi", NIOS2_BUILTIN_CUSTOM_INFI, &custom_infi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inff, "__builtin_custom_inff", NIOS2_BUILTIN_CUSTOM_INFF, &custom_inff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_infp, "__builtin_custom_infp", NIOS2_BUILTIN_CUSTOM_INFP, &custom_infp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpi, "__builtin_custom_inpi", NIOS2_BUILTIN_CUSTOM_INPI, &custom_inpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpf, "__builtin_custom_inpf", NIOS2_BUILTIN_CUSTOM_INPF, &custom_inpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_inpp, "__builtin_custom_inpp", NIOS2_BUILTIN_CUSTOM_INPP, &custom_inpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fn, "__builtin_custom_fn", NIOS2_BUILTIN_CUSTOM_FN, &custom_fn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_fni, "__builtin_custom_fni", NIOS2_BUILTIN_CUSTOM_FNI, &custom_fni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnf, "__builtin_custom_fnf", NIOS2_BUILTIN_CUSTOM_FNF, &custom_fnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnp, "__builtin_custom_fnp", NIOS2_BUILTIN_CUSTOM_FNP, &custom_fnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_fnii, "__builtin_custom_fnii", NIOS2_BUILTIN_CUSTOM_FNII, &custom_fnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnif, "__builtin_custom_fnif", NIOS2_BUILTIN_CUSTOM_FNIF, &custom_fnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnip, "__builtin_custom_fnip", NIOS2_BUILTIN_CUSTOM_FNIP, &custom_fnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfi, "__builtin_custom_fnfi", NIOS2_BUILTIN_CUSTOM_FNFI, &custom_fnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnff, "__builtin_custom_fnff", NIOS2_BUILTIN_CUSTOM_FNFF, &custom_fnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnfp, "__builtin_custom_fnfp", NIOS2_BUILTIN_CUSTOM_FNFP, &custom_fnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpi, "__builtin_custom_fnpi", NIOS2_BUILTIN_CUSTOM_FNPI, &custom_fnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpf, "__builtin_custom_fnpf", NIOS2_BUILTIN_CUSTOM_FNPF, &custom_fnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_fnpp, "__builtin_custom_fnpp", NIOS2_BUILTIN_CUSTOM_FNPP, &custom_fnpp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pn, "__builtin_custom_pn", NIOS2_BUILTIN_CUSTOM_PN, &custom_pn, nios2_expand_custom_Xn}, ++ {CODE_FOR_custom_pni, "__builtin_custom_pni", NIOS2_BUILTIN_CUSTOM_PNI, &custom_pni, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnf, "__builtin_custom_pnf", NIOS2_BUILTIN_CUSTOM_PNF, &custom_pnf, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnp, "__builtin_custom_pnp", NIOS2_BUILTIN_CUSTOM_PNP, &custom_pnp, nios2_expand_custom_XnX}, ++ {CODE_FOR_custom_pnii, "__builtin_custom_pnii", NIOS2_BUILTIN_CUSTOM_PNII, &custom_pnii, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnif, "__builtin_custom_pnif", NIOS2_BUILTIN_CUSTOM_PNIF, &custom_pnif, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnip, "__builtin_custom_pnip", NIOS2_BUILTIN_CUSTOM_PNIP, &custom_pnip, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfi, "__builtin_custom_pnfi", NIOS2_BUILTIN_CUSTOM_PNFI, &custom_pnfi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnff, "__builtin_custom_pnff", NIOS2_BUILTIN_CUSTOM_PNFF, &custom_pnff, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnfp, "__builtin_custom_pnfp", NIOS2_BUILTIN_CUSTOM_PNFP, &custom_pnfp, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpi, "__builtin_custom_pnpi", NIOS2_BUILTIN_CUSTOM_PNPI, &custom_pnpi, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpf, "__builtin_custom_pnpf", NIOS2_BUILTIN_CUSTOM_PNPF, &custom_pnpf, nios2_expand_custom_XnXX}, ++ {CODE_FOR_custom_pnpp, "__builtin_custom_pnpp", NIOS2_BUILTIN_CUSTOM_PNPP, &custom_pnpp, nios2_expand_custom_XnXX}, ++ ++ ++ {0, 0, 0, 0, 0}, ++}; ++ ++/* This does not have a closing bracket on purpose (see use) */ ++#define def_param(TYPE) \ ++ tree_cons (NULL_TREE, TYPE, ++ ++static void ++nios2_init_builtins () ++{ ++ const struct builtin_description *d; ++ ++ ++ endlink = void_list_node; ++ ++ /* Special indenting here because one of the brackets is in def_param */ ++ /* *INDENT-OFF* */ ++ ++ /* int fn (volatile const void *) ++ */ ++ int_ftype_volatile_const_void_p ++ = build_function_type (integer_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE)) ++ endlink)); ++ ++ ++ /* void fn (volatile void *, int) ++ */ ++ void_ftype_volatile_void_p_int ++ = build_function_type (void_type_node, ++ def_param (build_qualified_type (ptr_type_node, ++ TYPE_QUAL_VOLATILE)) ++ def_param (integer_type_node) ++ endlink))); ++ ++ /* void fn (void) ++ */ ++ void_ftype_void ++ = build_function_type (void_type_node, ++ endlink); ++ ++ /* int fn (int) ++ */ ++ int_ftype_int ++ = build_function_type (integer_type_node, ++ def_param (integer_type_node) ++ endlink)); ++ ++ /* void fn (int, int) ++ */ ++ void_ftype_int_int ++ = build_function_type (void_type_node, ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink))); ++ ++ ++#define CUSTOM_NUM def_param (integer_type_node) ++ ++ custom_n ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ni ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_nf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_np ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_nii ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nif ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nip ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_nfi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_nff ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_nfp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_npi ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_npf ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_npp ++ = build_function_type (void_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_in ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_ini ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_inf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_inp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_inii ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inif ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inip ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_infi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inff ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_infp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_inpi ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_inpf ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_inpp ++ = build_function_type (integer_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ custom_fn ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_fni ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_fnf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_fnp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_fnii ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnif ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnip ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnfi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnff ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnfp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_fnpi ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_fnpf ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_fnpp ++ = build_function_type (float_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ custom_pn ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ endlink)); ++ custom_pni ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ endlink))); ++ custom_pnf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ endlink))); ++ custom_pnp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ endlink))); ++ custom_pnii ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnif ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnip ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (integer_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnfi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnff ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnfp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (float_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ custom_pnpi ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (integer_type_node) ++ endlink)))); ++ custom_pnpf ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (float_type_node) ++ endlink)))); ++ custom_pnpp ++ = build_function_type (ptr_type_node, ++ CUSTOM_NUM ++ def_param (ptr_type_node) ++ def_param (ptr_type_node) ++ endlink)))); ++ ++ ++ ++ /* *INDENT-ON* */ ++ ++ ++ for (d = bdesc; d->name; d++) ++ { ++ builtin_function (d->name, *d->type, d->code, ++ BUILT_IN_MD, NULL, NULL); ++ } ++} ++ ++/* Expand an expression EXP that calls a built-in function, ++ with result going to TARGET if that's convenient ++ (and in mode MODE if that's convenient). ++ SUBTARGET may be used as the target for computing one of EXP's operands. ++ IGNORE is nonzero if the value is to be ignored. */ ++ ++static rtx ++nios2_expand_builtin (tree exp, rtx target, rtx subtarget, ++ enum machine_mode mode, int ignore) ++{ ++ const struct builtin_description *d; ++ tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0); ++ unsigned int fcode = DECL_FUNCTION_CODE (fndecl); ++ ++ for (d = bdesc; d->name; d++) ++ if (d->code == fcode) ++ return (d->expander) (d, exp, target, subtarget, mode, ignore); ++ ++ /* we should have seen one of the functins we registered */ ++ abort (); ++} ++ ++static rtx nios2_create_target (const struct builtin_description *, rtx); ++ ++ ++static rtx ++nios2_create_target (const struct builtin_description *d, rtx target) ++{ ++ if (!target ++ || !(*insn_data[d->icode].operand[0].predicate) (target, ++ insn_data[d->icode].operand[0].mode)) ++ { ++ target = gen_reg_rtx (insn_data[d->icode].operand[0].mode); ++ } ++ ++ return target; ++} ++ ++ ++static rtx nios2_extract_opcode (const struct builtin_description *, int, tree); ++static rtx nios2_extract_operand (const struct builtin_description *, int, int, tree); ++ ++static rtx ++nios2_extract_opcode (const struct builtin_description *d, int op, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx opcode = expand_expr (arg, NULL_RTX, mode, 0); ++ opcode = protect_from_queue (opcode, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (opcode, mode)) ++ error ("Custom instruction opcode must be compile time constant in the range 0-255 for %s", d->name); ++ ++ return opcode; ++} ++ ++static rtx ++nios2_extract_operand (const struct builtin_description *d, int op, int argnum, tree arglist) ++{ ++ enum machine_mode mode = insn_data[d->icode].operand[op].mode; ++ tree arg = TREE_VALUE (arglist); ++ rtx operand = expand_expr (arg, NULL_RTX, mode, 0); ++ operand = protect_from_queue (operand, 0); ++ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ operand = copy_to_mode_reg (mode, operand); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[d->icode].operand[op].predicate) (operand, mode)) ++ error ("Invalid argument %d to %s", argnum, d->name); ++ ++ return operand; ++} ++ ++ ++static rtx ++nios2_expand_custom_n (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_n should have exactly one operand */ ++ if (insn_data[d->icode].n_operands != 1) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ ++ pat = GEN_FCN (d->icode) (opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_Xn (const struct builtin_description *d, tree exp, ++ rtx target, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ ++ /* custom_Xn should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ pat = GEN_FCN (d->icode) (target, opcode); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nX (const struct builtin_description *d, tree exp, ++ rtx target ATTRIBUTE_UNUSED, rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ ++ /* custom_nX should have exactly two operands */ ++ if (insn_data[d->icode].n_operands != 2) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[1]; ++ int i; ++ ++ /* custom_Xn should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ ++ for (i = 0; i < 1; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_custom_nXX (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_nX should have exactly three operands */ ++ if (insn_data[d->icode].n_operands != 3) ++ abort (); ++ ++ opcode = nios2_extract_opcode (d, 0, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 1, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (opcode, operands[0], operands[1]); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++static rtx ++nios2_expand_custom_XnXX (const struct builtin_description *d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx opcode; ++ rtx operands[2]; ++ int i; ++ ++ ++ /* custom_XnX should have exactly four operands */ ++ if (insn_data[d->icode].n_operands != 4) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ opcode = nios2_extract_opcode (d, 1, arglist); ++ for (i = 0; i < 2; i++) ++ { ++ arglist = TREE_CHAIN (arglist); ++ operands[i] = nios2_extract_operand (d, i + 2, i + 1, arglist); ++ } ++ ++ pat = GEN_FCN (d->icode) (target, opcode, operands[0], operands[1]); ++ ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++ ++static rtx ++nios2_expand_STXIO (const struct builtin_description *d, tree exp, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx store_dest, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ store_dest = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ store_dest = protect_from_queue (store_dest, 0); ++ ++ store_dest = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, store_dest)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[0].predicate) (store_dest, mode)) ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (store_dest, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++static rtx ++nios2_expand_LDXIO (const struct builtin_description * d, tree exp, rtx target, ++ rtx subtarget ATTRIBUTE_UNUSED, enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx ld_src; ++ enum insn_code icode = d->icode; ++ ++ /* loads should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ ld_src = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ ld_src = protect_from_queue (ld_src, 0); ++ ++ ld_src = gen_rtx_MEM (mode, copy_to_mode_reg (Pmode, ld_src)); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (ld_src, mode)) ++ { ++ error ("Invalid argument 1 to %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, ld_src); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++ ++static rtx ++nios2_expand_sync (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ emit_insn (gen_sync ()); ++ return 0; ++} ++ ++static rtx ++nios2_expand_rdctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx rdctl_reg; ++ enum insn_code icode = d->icode; ++ ++ /* rdctl should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ target = nios2_create_target (d, target); ++ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (arglist); ++ rdctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ rdctl_reg = protect_from_queue (rdctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (rdctl_reg, mode)) ++ { ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ } ++ ++ pat = GEN_FCN (d->icode) (target, rdctl_reg); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return target; ++} ++ ++static rtx ++nios2_expand_wrctl (const struct builtin_description * d ATTRIBUTE_UNUSED, ++ tree exp ATTRIBUTE_UNUSED, rtx target ATTRIBUTE_UNUSED, ++ rtx subtarget ATTRIBUTE_UNUSED, ++ enum machine_mode mode ATTRIBUTE_UNUSED, ++ int ignore ATTRIBUTE_UNUSED) ++{ ++ tree arglist = TREE_OPERAND (exp, 1); ++ rtx pat; ++ rtx wrctl_reg, store_val; ++ enum insn_code icode = d->icode; ++ ++ /* stores should have exactly two operands */ ++ if (insn_data[icode].n_operands != 2) ++ abort (); ++ ++ /* process the destination of the store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[0].mode; ++ tree arg = TREE_VALUE (arglist); ++ wrctl_reg = expand_expr (arg, NULL_RTX, VOIDmode, 0); ++ wrctl_reg = protect_from_queue (wrctl_reg, 0); ++ ++ if (!(*insn_data[icode].operand[0].predicate) (wrctl_reg, mode)) ++ error ("Control register number must be in range 0-31 for %s", d->name); ++ } ++ ++ ++ /* process the value to store */ ++ { ++ enum machine_mode mode = insn_data[icode].operand[1].mode; ++ tree arg = TREE_VALUE (TREE_CHAIN (arglist)); ++ store_val = expand_expr (arg, NULL_RTX, mode, 0); ++ store_val = protect_from_queue (store_val, 0); ++ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ store_val = copy_to_mode_reg (mode, store_val); ++ ++ /* ??? Better errors would be nice */ ++ if (!(*insn_data[icode].operand[1].predicate) (store_val, mode)) ++ error ("Invalid argument 2 to %s", d->name); ++ } ++ ++ pat = GEN_FCN (d->icode) (wrctl_reg, store_val); ++ if (!pat) ++ return 0; ++ emit_insn (pat); ++ return 0; ++} ++ ++ ++#include "gt-nios2.h" ++ +--- gcc-3.4.3/gcc/config/nios2/nios2.h ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.h +@@ -0,0 +1,824 @@ ++/* Definitions of target machine for Altera NIOS 2G NIOS2 version. ++ Copyright (C) 2003 Altera ++ Contributed by Jonah Graham (jgraham@altera.com). ++ ++This file is part of GNU CC. ++ ++GNU CC is free software; you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation; either version 2, or (at your option) ++any later version. ++ ++GNU CC is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with GNU CC; see the file COPYING. If not, write to ++the Free Software Foundation, 59 Temple Place - Suite 330, ++Boston, MA 02111-1307, USA. */ ++ ++ ++ ++#define TARGET_CPU_CPP_BUILTINS() \ ++ do \ ++ { \ ++ builtin_define_std ("NIOS2"); \ ++ builtin_define_std ("nios2"); \ ++ builtin_define ("_GNU_SOURCE"); \ ++ } \ ++ while (0) ++#define TARGET_VERSION fprintf (stderr, " (Altera Nios II)") ++ ++ ++ ++ ++ ++/********************************* ++ * Run-time Target Specification ++ *********************************/ ++ ++#define HAS_DIV_FLAG 0x0001 ++#define HAS_MUL_FLAG 0x0002 ++#define HAS_MULX_FLAG 0x0004 ++#define FAST_SW_DIV_FLAG 0x0008 ++#define INLINE_MEMCPY_FLAG 0x00010 ++#define CACHE_VOLATILE_FLAG 0x0020 ++#define BYPASS_CACHE_FLAG 0x0040 ++ ++extern int target_flags; ++#define TARGET_HAS_DIV (target_flags & HAS_DIV_FLAG) ++#define TARGET_HAS_MUL (target_flags & HAS_MUL_FLAG) ++#define TARGET_HAS_MULX (target_flags & HAS_MULX_FLAG) ++#define TARGET_FAST_SW_DIV (target_flags & FAST_SW_DIV_FLAG) ++#define TARGET_INLINE_MEMCPY (target_flags & INLINE_MEMCPY_FLAG) ++#define TARGET_CACHE_VOLATILE (target_flags & CACHE_VOLATILE_FLAG) ++#define TARGET_BYPASS_CACHE (target_flags & BYPASS_CACHE_FLAG) ++ ++#define TARGET_SWITCHES \ ++{ \ ++ { "hw-div", HAS_DIV_FLAG, \ ++ N_("Enable DIV, DIVU") }, \ ++ { "no-hw-div", -HAS_DIV_FLAG, \ ++ N_("Disable DIV, DIVU (default)") }, \ ++ { "hw-mul", HAS_MUL_FLAG, \ ++ N_("Enable MUL instructions (default)") }, \ ++ { "hw-mulx", HAS_MULX_FLAG, \ ++ N_("Enable MULX instructions, assume fast shifter") }, \ ++ { "no-hw-mul", -HAS_MUL_FLAG, \ ++ N_("Disable MUL instructions") }, \ ++ { "no-hw-mulx", -HAS_MULX_FLAG, \ ++ N_("Disable MULX instructions, assume slow shifter (default and implied by -mno-hw-mul)") }, \ ++ { "fast-sw-div", FAST_SW_DIV_FLAG, \ ++ N_("Use table based fast divide (default at -O3)") }, \ ++ { "no-fast-sw-div", -FAST_SW_DIV_FLAG, \ ++ N_("Don't use table based fast divide ever") }, \ ++ { "inline-memcpy", INLINE_MEMCPY_FLAG, \ ++ N_("Inline small memcpy (default when optimizing)") }, \ ++ { "no-inline-memcpy", -INLINE_MEMCPY_FLAG, \ ++ N_("Don't Inline small memcpy") }, \ ++ { "cache-volatile", CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use non-io variants of instructions (default)") }, \ ++ { "no-cache-volatile", -CACHE_VOLATILE_FLAG, \ ++ N_("Volatile accesses use io variants of instructions") }, \ ++ { "bypass-cache", BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins use io variants") }, \ ++ { "no-bypass-cache", -BYPASS_CACHE_FLAG, \ ++ N_("All ld/st instructins do not use io variants (default)") }, \ ++ { "smallc", 0, \ ++ N_("Link with a limited version of the C library") }, \ ++ { "ctors-in-init", 0, \ ++ "" /* undocumented: N_("Link with static constructors and destructors in init") */ }, \ ++ { "", TARGET_DEFAULT, 0 } \ ++} ++ ++ ++extern const char *nios2_sys_nosys_string; /* for -msys=nosys */ ++extern const char *nios2_sys_lib_string; /* for -msys-lib= */ ++extern const char *nios2_sys_crt0_string; /* for -msys-crt0= */ ++ ++#define TARGET_OPTIONS \ ++{ \ ++ { "sys=nosys", &nios2_sys_nosys_string, \ ++ N_("Use stub versions of OS library calls (default)"), 0}, \ ++ { "sys-lib=", &nios2_sys_lib_string, \ ++ N_("Name of System Library to link against. (Converted to a -l option)"), 0}, \ ++ { "sys-crt0=", &nios2_sys_crt0_string, \ ++ N_("Name of the startfile. (default is a crt0 for the ISS only)"), 0}, \ ++} ++ ++ ++/* Default target_flags if no switches specified. */ ++#ifndef TARGET_DEFAULT ++# define TARGET_DEFAULT (HAS_MUL_FLAG | CACHE_VOLATILE_FLAG) ++#endif ++ ++/* Switch Recognition by gcc.c. Add -G xx support */ ++#undef SWITCH_TAKES_ARG ++#define SWITCH_TAKES_ARG(CHAR) \ ++ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G') ++ ++#define OVERRIDE_OPTIONS override_options () ++#define OPTIMIZATION_OPTIONS(LEVEL, SIZE) optimization_options (LEVEL, SIZE) ++#define CAN_DEBUG_WITHOUT_FP ++ ++#define CC1_SPEC "\ ++%{G*}" ++ ++#undef LIB_SPEC ++#define LIB_SPEC \ ++"--start-group %{msmallc: -lsmallc} %{!msmallc: -lc} -lgcc \ ++ %{msys-lib=*: -l%*} \ ++ %{!msys-lib=*: -lc } \ ++ --end-group \ ++ %{msys-lib=: %eYou need a library name for -msys-lib=} \ ++" ++ ++ ++#undef STARTFILE_SPEC ++#define STARTFILE_SPEC \ ++"%{msys-crt0=*: %*} %{!msys-crt0=*: crt1%O%s} \ ++ %{msys-crt0=: %eYou need a C startup file for -msys-crt0=} \ ++ %{mctors-in-init: crti%O%s crtbegin%O%s} \ ++" ++ ++#undef ENDFILE_SPEC ++#define ENDFILE_SPEC \ ++ "%{mctors-in-init: crtend%O%s crtn%O%s}" ++ ++ ++/*********************** ++ * Storage Layout ++ ***********************/ ++ ++#define DEFAULT_SIGNED_CHAR 1 ++#define BITS_BIG_ENDIAN 0 ++#define BYTES_BIG_ENDIAN 0 ++#define WORDS_BIG_ENDIAN 0 ++#define BITS_PER_UNIT 8 ++#define BITS_PER_WORD 32 ++#define UNITS_PER_WORD 4 ++#define POINTER_SIZE 32 ++#define BIGGEST_ALIGNMENT 32 ++#define STRICT_ALIGNMENT 1 ++#define FUNCTION_BOUNDARY 32 ++#define PARM_BOUNDARY 32 ++#define STACK_BOUNDARY 32 ++#define PREFERRED_STACK_BOUNDARY 32 ++#define MAX_FIXED_MODE_SIZE 64 ++ ++#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ ++ ((TREE_CODE (EXP) == STRING_CST) \ ++ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) ++ ++ ++/********************** ++ * Layout of Source Language Data Types ++ **********************/ ++ ++#define INT_TYPE_SIZE 32 ++#define SHORT_TYPE_SIZE 16 ++#define LONG_TYPE_SIZE 32 ++#define LONG_LONG_TYPE_SIZE 64 ++#define FLOAT_TYPE_SIZE 32 ++#define DOUBLE_TYPE_SIZE 64 ++#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE ++ ++ ++/************************* ++ * Condition Code Status ++ ************************/ ++ ++/* comparison type */ ++/* ??? currently only CMP_SI is used */ ++enum cmp_type { ++ CMP_SI, /* compare four byte integers */ ++ CMP_DI, /* compare eight byte integers */ ++ CMP_SF, /* compare single precision floats */ ++ CMP_DF, /* compare double precision floats */ ++ CMP_MAX /* max comparison type */ ++}; ++ ++extern GTY(()) rtx branch_cmp[2]; /* operands for compare */ ++extern enum cmp_type branch_type; /* what type of branch to use */ ++ ++/********************** ++ * Register Usage ++ **********************/ ++ ++/* ---------------------------------- * ++ * Basic Characteristics of Registers ++ * ---------------------------------- */ ++ ++/* ++Register Number ++ Register Name ++ Alternate Name ++ Purpose ++0 r0 zero always zero ++1 r1 at Assembler Temporary ++2-3 r2-r3 Return Location ++4-7 r4-r7 Register Arguments ++8-15 r8-r15 Caller Saved Registers ++16-22 r16-r22 Callee Saved Registers ++23 r23 sc Static Chain (Callee Saved) ++ ??? Does $sc want to be caller or callee ++ saved. If caller, 15, else 23. ++24 r24 Exception Temporary ++25 r25 Breakpoint Temporary ++26 r26 gp Global Pointer ++27 r27 sp Stack Pointer ++28 r28 fp Frame Pointer ++29 r29 ea Exception Return Address ++30 r30 ba Breakpoint Return Address ++31 r31 ra Return Address ++ ++32 ctl0 status ++33 ctl1 estatus STATUS saved by exception ? ++34 ctl2 bstatus STATUS saved by break ? ++35 ctl3 ipri Interrupt Priority Mask ? ++36 ctl4 ecause Exception Cause ? ++ ++37 pc Not an actual register ++ ++38 rap Return address pointer, this does not ++ actually exist and will be eliminated ++ ++39 fake_fp Fake Frame Pointer which will always be eliminated. ++40 fake_ap Fake Argument Pointer which will always be eliminated. ++ ++41 First Pseudo Register ++ ++ ++The definitions for all the hard register numbers ++are located in nios2.md. ++*/ ++ ++#define FIRST_PSEUDO_REGISTER 41 ++#define NUM_ARG_REGS (LAST_ARG_REGNO - FIRST_ARG_REGNO + 1) ++ ++ ++ ++/* also see CONDITIONAL_REGISTER_USAGE */ ++#define FIXED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++/* call used is the same as caller saved ++ + fixed regs + args + ret vals */ ++#define CALL_USED_REGISTERS \ ++ { \ ++/* +0 1 2 3 4 5 6 7 8 9 */ \ ++/* 0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 10 */ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \ ++/* 20 */ 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, \ ++/* 30 */ 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, \ ++/* 40 */ 1, \ ++ } ++ ++#define HARD_REGNO_NREGS(REGNO, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++/* --------------------------- * ++ * How Values Fit in Registers ++ * --------------------------- */ ++ ++#define HARD_REGNO_MODE_OK(REGNO, MODE) 1 ++ ++#define MODES_TIEABLE_P(MODE1, MODE2) 1 ++ ++ ++/************************* ++ * Register Classes ++ *************************/ ++ ++enum reg_class ++{ ++ NO_REGS, ++ ALL_REGS, ++ LIM_REG_CLASSES ++}; ++ ++#define N_REG_CLASSES (int) LIM_REG_CLASSES ++ ++#define REG_CLASS_NAMES \ ++ {"NO_REGS", \ ++ "ALL_REGS"} ++ ++#define GENERAL_REGS ALL_REGS ++ ++#define REG_CLASS_CONTENTS \ ++/* NO_REGS */ {{ 0, 0}, \ ++/* ALL_REGS */ {~0,~0}} \ ++ ++#define REGNO_REG_CLASS(REGNO) ALL_REGS ++ ++#define BASE_REG_CLASS ALL_REGS ++#define INDEX_REG_CLASS ALL_REGS ++ ++/* only one reg class, 'r', is handled automatically */ ++#define REG_CLASS_FROM_LETTER(CHAR) NO_REGS ++ ++#define REGNO_OK_FOR_BASE_P2(REGNO, STRICT) \ ++ ((STRICT) \ ++ ? (REGNO) < FIRST_PSEUDO_REGISTER \ ++ : (REGNO) < FIRST_PSEUDO_REGISTER || (reg_renumber && reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER)) ++ ++#define REGNO_OK_FOR_INDEX_P2(REGNO, STRICT) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, STRICT)) ++ ++#define REGNO_OK_FOR_BASE_P(REGNO) \ ++ (REGNO_OK_FOR_BASE_P2 (REGNO, 1)) ++ ++#define REGNO_OK_FOR_INDEX_P(REGNO) \ ++ (REGNO_OK_FOR_INDEX_P2 (REGNO, 1)) ++ ++#define REG_OK_FOR_BASE_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define REG_OK_FOR_INDEX_P2(X, STRICT) \ ++ (STRICT \ ++ ? REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) \ ++ : REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) || REGNO(X) >= FIRST_PSEUDO_REGISTER) ++ ++#define CLASS_MAX_NREGS(CLASS, MODE) \ ++ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) \ ++ / UNITS_PER_WORD) ++ ++ ++#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) ((X) + 0x8000) < 0x10000) ++#define SMALL_INT_UNSIGNED(X) ((unsigned HOST_WIDE_INT) (X) < 0x10000) ++#define UPPER16_INT(X) (((X) & 0xffff) == 0) ++#define SHIFT_INT(X) ((X) >= 0 && (X) <= 31) ++#define RDWRCTL_INT(X) ((X) >= 0 && (X) <= 31) ++#define CUSTOM_INSN_OPCODE(X) ((X) >= 0 && (X) <= 255) ++ ++#define CONST_OK_FOR_LETTER_P(VALUE, C) \ ++ ( \ ++ (C) == 'I' ? SMALL_INT (VALUE) : \ ++ (C) == 'J' ? SMALL_INT_UNSIGNED (VALUE) : \ ++ (C) == 'K' ? UPPER16_INT (VALUE) : \ ++ (C) == 'L' ? SHIFT_INT (VALUE) : \ ++ (C) == 'M' ? (VALUE) == 0 : \ ++ (C) == 'N' ? CUSTOM_INSN_OPCODE (VALUE) : \ ++ (C) == 'O' ? RDWRCTL_INT (VALUE) : \ ++ 0) ++ ++#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0 ++ ++#define PREFERRED_RELOAD_CLASS(X, CLASS) \ ++ ((CLASS) == NO_REGS ? GENERAL_REGS : (CLASS)) ++ ++/* 'S' matches immediates which are in small data ++ and therefore can be added to gp to create a ++ 32-bit value. */ ++#define EXTRA_CONSTRAINT(VALUE, C) \ ++ ((C) == 'S' \ ++ && (GET_CODE (VALUE) == SYMBOL_REF) \ ++ && SYMBOL_REF_IN_NIOS2_SMALL_DATA_P (VALUE)) ++ ++ ++ ++ ++/* Say that the epilogue uses the return address register. Note that ++ in the case of sibcalls, the values "used by the epilogue" are ++ considered live at the start of the called function. */ ++#define EPILOGUE_USES(REGNO) ((REGNO) == RA_REGNO) ++ ++ ++#define DEFAULT_MAIN_RETURN c_expand_return (integer_zero_node) ++ ++/********************************** ++ * Trampolines for Nested Functions ++ ***********************************/ ++ ++#define TRAMPOLINE_TEMPLATE(FILE) \ ++ error ("trampolines not yet implemented") ++#define TRAMPOLINE_SIZE 20 ++#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \ ++ error ("trampolines not yet implemented") ++ ++/*************************** ++ * Stack Layout and Calling Conventions ++ ***************************/ ++ ++/* ------------------ * ++ * Basic Stack Layout ++ * ------------------ */ ++ ++/* The downward variants are used by the compiler, ++ the upward ones serve as documentation */ ++#define STACK_GROWS_DOWNWARD ++#define FRAME_GROWS_UPWARD ++#define ARGS_GROW_UPWARD ++ ++#define STARTING_FRAME_OFFSET current_function_outgoing_args_size ++#define FIRST_PARM_OFFSET(FUNDECL) 0 ++ ++/* Before the prologue, RA lives in r31. */ ++#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RA_REGNO) ++ ++/* -------------------------------------- * ++ * Registers That Address the Stack Frame ++ * -------------------------------------- */ ++ ++#define STACK_POINTER_REGNUM SP_REGNO ++#define STATIC_CHAIN_REGNUM SC_REGNO ++#define PC_REGNUM PC_REGNO ++#define DWARF_FRAME_RETURN_COLUMN RA_REGNO ++ ++/* Base register for access to local variables of the function. We ++ pretend that the frame pointer is a non-existent hard register, and ++ then eliminate it to HARD_FRAME_POINTER_REGNUM. */ ++#define FRAME_POINTER_REGNUM FAKE_FP_REGNO ++ ++#define HARD_FRAME_POINTER_REGNUM FP_REGNO ++#define RETURN_ADDRESS_POINTER_REGNUM RAP_REGNO ++/* the argumnet pointer needs to always be eliminated ++ so it is set to a fake hard register. */ ++#define ARG_POINTER_REGNUM FAKE_AP_REGNO ++ ++/* ----------------------------------------- * ++ * Eliminating Frame Pointer and Arg Pointer ++ * ----------------------------------------- */ ++ ++#define FRAME_POINTER_REQUIRED 0 ++ ++#define ELIMINABLE_REGS \ ++{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { RETURN_ADDRESS_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \ ++ { FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} ++ ++#define CAN_ELIMINATE(FROM, TO) 1 ++ ++#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ ++ (OFFSET) = nios2_initial_elimination_offset ((FROM), (TO)) ++ ++#define MUST_SAVE_REGISTER(regno) \ ++ ((regs_ever_live[regno] && !call_used_regs[regno]) \ ++ || (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed) \ ++ || (regno == RA_REGNO && regs_ever_live[RA_REGNO])) ++ ++/* Treat LOC as a byte offset from the stack pointer and round it up ++ to the next fully-aligned offset. */ ++#define STACK_ALIGN(LOC) \ ++ (((LOC) + ((PREFERRED_STACK_BOUNDARY / 8) - 1)) & ~((PREFERRED_STACK_BOUNDARY / 8) - 1)) ++ ++ ++/* ------------------------------ * ++ * Passing Arguments in Registers ++ * ------------------------------ */ ++ ++/* see nios2.c */ ++#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ ++ (function_arg (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_partial_nregs (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) 0 ++ ++#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) 0 ++ ++typedef struct nios2_args ++{ ++ int regs_used; ++} CUMULATIVE_ARGS; ++ ++/* This is to initialize the above unused CUM data type */ ++#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \ ++ (init_cumulative_args (&CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS)) ++ ++#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ ++ (function_arg_advance (&CUM, MODE, TYPE, NAMED)) ++ ++#define FUNCTION_ARG_REGNO_P(REGNO) \ ++ ((REGNO) >= FIRST_ARG_REGNO && (REGNO) <= LAST_ARG_REGNO) ++ ++#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL) \ ++ { \ ++ int pret_size = nios2_setup_incoming_varargs (&(CUM), (MODE), \ ++ (TYPE), (NO_RTL)); \ ++ if (pret_size) \ ++ (PRETEND_SIZE) = pret_size; \ ++ } ++ ++/* ----------------------------- * ++ * Generating Code for Profiling ++ * ----------------------------- */ ++ ++#define PROFILE_BEFORE_PROLOGUE ++ ++#define FUNCTION_PROFILER(FILE, LABELNO) \ ++ function_profiler ((FILE), (LABELNO)) ++ ++/* --------------------------------------- * ++ * Passing Function Arguments on the Stack ++ * --------------------------------------- */ ++ ++#define PROMOTE_PROTOTYPES 1 ++ ++#define PUSH_ARGS 0 ++#define ACCUMULATE_OUTGOING_ARGS 1 ++ ++#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, STACKSIZE) 0 ++ ++/* --------------------------------------- * ++ * How Scalar Function Values Are Returned ++ * --------------------------------------- */ ++ ++#define FUNCTION_VALUE(VALTYPE, FUNC) \ ++ gen_rtx(REG, TYPE_MODE(VALTYPE), FIRST_RETVAL_REGNO) ++ ++#define LIBCALL_VALUE(MODE) \ ++ gen_rtx(REG, MODE, FIRST_RETVAL_REGNO) ++ ++#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == FIRST_RETVAL_REGNO) ++ ++/* ----------------------------- * ++ * How Large Values Are Returned ++ * ----------------------------- */ ++ ++ ++#define RETURN_IN_MEMORY(TYPE) \ ++ nios2_return_in_memory (TYPE) ++ ++ ++#define STRUCT_VALUE 0 ++ ++#define DEFAULT_PCC_STRUCT_RETURN 0 ++ ++/******************* ++ * Addressing Modes ++ *******************/ ++ ++ ++#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) ++ ++#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) ++ ++#define MAX_REGS_PER_ADDRESS 1 ++ ++/* Go to ADDR if X is a valid address. */ ++#ifndef REG_OK_STRICT ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 0)) \ ++ goto ADDR; \ ++ } ++#else ++#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR) \ ++ { \ ++ if (nios2_legitimate_address ((X), (MODE), 1)) \ ++ goto ADDR; \ ++ } ++#endif ++ ++#ifndef REG_OK_STRICT ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 0) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 0) ++#else ++#define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P2 (REGNO (X), 1) ++#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P2 (REGNO (X), 1) ++#endif ++ ++#define LEGITIMATE_CONSTANT_P(X) 1 ++ ++/* Nios II has no mode dependent addresses. */ ++#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) ++ ++/* Set if this has a weak declaration */ ++#define SYMBOL_FLAG_WEAK_DECL (1 << SYMBOL_FLAG_MACH_DEP_SHIFT) ++#define SYMBOL_REF_WEAK_DECL_P(RTX) \ ++ ((SYMBOL_REF_FLAGS (RTX) & SYMBOL_FLAG_WEAK_DECL) != 0) ++ ++ ++/* true if a symbol is both small and not weak. In this case, gp ++ relative access can be used */ ++#define SYMBOL_REF_IN_NIOS2_SMALL_DATA_P(RTX) \ ++ (SYMBOL_REF_SMALL_P(RTX) && !SYMBOL_REF_WEAK_DECL_P(RTX)) ++ ++/***************** ++ * Describing Relative Costs of Operations ++ *****************/ ++ ++#define SLOW_BYTE_ACCESS 1 ++ ++/* It is as good to call a constant function address as to call an address ++ kept in a register. ++ ??? Not true anymore really. Now that call cannot address full range ++ of memory callr may need to be used */ ++ ++#define NO_FUNCTION_CSE ++#define NO_RECURSIVE_FUNCTION_CSE ++ ++ ++ ++/***************************************** ++ * Defining the Output Assembler Language ++ *****************************************/ ++ ++/* ------------------------------------------ * ++ * The Overall Framework of an Assembler File ++ * ------------------------------------------ */ ++ ++#define ASM_APP_ON "#APP\n" ++#define ASM_APP_OFF "#NO_APP\n" ++ ++#define ASM_COMMENT_START "# " ++ ++/* ------------------------------- * ++ * Output and Generation of Labels ++ * ------------------------------- */ ++ ++#define GLOBAL_ASM_OP "\t.global\t" ++ ++ ++/* -------------- * ++ * Output of Data ++ * -------------- */ ++ ++#define DWARF2_UNWIND_INFO 0 ++ ++ ++/* -------------------------------- * ++ * Assembler Commands for Alignment ++ * -------------------------------- */ ++ ++#define ASM_OUTPUT_ALIGN(FILE, LOG) \ ++ do { \ ++ fprintf ((FILE), "%s%d\n", ALIGN_ASM_OP, (LOG)); \ ++ } while (0) ++ ++ ++/* -------------------------------- * ++ * Output of Assembler Instructions ++ * -------------------------------- */ ++ ++#define REGISTER_NAMES \ ++{ \ ++ "zero", \ ++ "at", \ ++ "r2", \ ++ "r3", \ ++ "r4", \ ++ "r5", \ ++ "r6", \ ++ "r7", \ ++ "r8", \ ++ "r9", \ ++ "r10", \ ++ "r11", \ ++ "r12", \ ++ "r13", \ ++ "r14", \ ++ "r15", \ ++ "r16", \ ++ "r17", \ ++ "r18", \ ++ "r19", \ ++ "r20", \ ++ "r21", \ ++ "r22", \ ++ "r23", \ ++ "r24", \ ++ "r25", \ ++ "gp", \ ++ "sp", \ ++ "fp", \ ++ "ta", \ ++ "ba", \ ++ "ra", \ ++ "status", \ ++ "estatus", \ ++ "bstatus", \ ++ "ipri", \ ++ "ecause", \ ++ "pc", \ ++ "rap", \ ++ "fake_fp", \ ++ "fake_ap", \ ++} ++ ++#define ASM_OUTPUT_OPCODE(STREAM, PTR)\ ++ (PTR) = asm_output_opcode (STREAM, PTR) ++ ++#define PRINT_OPERAND(STREAM, X, CODE) \ ++ nios2_print_operand (STREAM, X, CODE) ++ ++#define PRINT_OPERAND_ADDRESS(STREAM, X) \ ++ nios2_print_operand_address (STREAM, X) ++ ++#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ ++do { fputs (integer_asm_op (POINTER_SIZE / BITS_PER_UNIT, TRUE), FILE); \ ++ fprintf (FILE, ".L%u\n", (unsigned) (VALUE)); \ ++ } while (0) ++ ++ ++/* ------------ * ++ * Label Output ++ * ------------ */ ++ ++ ++/* ---------------------------------------------------- * ++ * Dividing the Output into Sections (Texts, Data, ...) ++ * ---------------------------------------------------- */ ++ ++/* Output before read-only data. */ ++#define TEXT_SECTION_ASM_OP ("\t.section\t.text") ++ ++/* Output before writable data. */ ++#define DATA_SECTION_ASM_OP ("\t.section\t.data") ++ ++ ++/* Default the definition of "small data" to 8 bytes. */ ++/* ??? How come I can't use HOST_WIDE_INT here? */ ++extern unsigned long nios2_section_threshold; ++#define NIOS2_DEFAULT_GVALUE 8 ++ ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized external linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef COMMON_ASM_OP ++#define COMMON_ASM_OP "\t.comm\t" ++ ++#undef ASM_OUTPUT_ALIGNED_COMMON ++#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ ++do \ ++{ \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ { \ ++ named_section (0, ".sbss", 0); \ ++ (*targetm.asm_out.globalize_label) (FILE, NAME); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++ } \ ++ else \ ++ { \ ++ fprintf ((FILE), "%s", COMMON_ASM_OP); \ ++ assemble_name ((FILE), (NAME)); \ ++ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", (SIZE), (ALIGN) / BITS_PER_UNIT); \ ++ } \ ++} \ ++while (0) ++ ++ ++/* This says how to output assembler code to declare an ++ uninitialized internal linkage data object. Under SVR4, ++ the linker seems to want the alignment of data objects ++ to depend on their types. We do exactly that here. */ ++ ++#undef ASM_OUTPUT_ALIGNED_LOCAL ++#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \ ++do { \ ++ if ((SIZE) <= nios2_section_threshold) \ ++ named_section (0, ".sbss", 0); \ ++ else \ ++ named_section (0, ".bss", 0); \ ++ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \ ++ if (!flag_inhibit_size_directive) \ ++ ASM_OUTPUT_SIZE_DIRECTIVE (FILE, NAME, SIZE); \ ++ ASM_OUTPUT_ALIGN ((FILE), exact_log2((ALIGN) / BITS_PER_UNIT)); \ ++ ASM_OUTPUT_LABEL(FILE, NAME); \ ++ ASM_OUTPUT_SKIP((FILE), (SIZE) ? (SIZE) : 1); \ ++} while (0) ++ ++ ++ ++/*************************** ++ * Miscellaneous Parameters ++ ***************************/ ++ ++#define MOVE_MAX 4 ++ ++#define Pmode SImode ++#define FUNCTION_MODE QImode ++ ++#define CASE_VECTOR_MODE Pmode ++ ++#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 ++ ++#define LOAD_EXTEND_OP(MODE) (ZERO_EXTEND) ++ ++#define WORD_REGISTER_OPERATIONS +--- gcc-3.4.3/gcc/config/nios2/nios2.md ++++ gcc-3.4.3-nios2/gcc/config/nios2/nios2.md +@@ -0,0 +1,2078 @@ ++;; Machine Description for Altera NIOS 2G NIOS2 version. ++;; Copyright (C) 2003 Altera ++;; Contributed by Jonah Graham (jgraham@altera.com). ++;; ++;; This file is part of GNU CC. ++;; ++;; GNU CC is free software; you can redistribute it and/or modify ++;; it under the terms of the GNU General Public License as published by ++;; the Free Software Foundation; either version 2, or (at your option) ++;; any later version. ++;; ++;; GNU CC is distributed in the hope that it will be useful, ++;; but WITHOUT ANY WARRANTY; without even the implied warranty of ++;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++;; GNU General Public License for more details. ++;; ++;; You should have received a copy of the GNU General Public License ++;; along with GNU CC; see the file COPYING. If not, write to ++;; the Free Software Foundation, 59 Temple Place - Suite 330, ++;; Boston, MA 02111-1307, USA. */ ++ ++ ++ ++;***************************************************************************** ++;* ++;* constants ++;* ++;***************************************************************************** ++(define_constants [ ++ (GP_REGNO 26) ++ (SP_REGNO 27) ++ (FP_REGNO 28) ++ (RA_REGNO 31) ++ (RAP_REGNO 38) ++ (FIRST_RETVAL_REGNO 2) ++ (LAST_RETVAL_REGNO 3) ++ (FIRST_ARG_REGNO 4) ++ (LAST_ARG_REGNO 7) ++ (SC_REGNO 23) ++ (PC_REGNO 37) ++ (FAKE_FP_REGNO 39) ++ (FAKE_AP_REGNO 40) ++ ++ ++ (UNSPEC_BLOCKAGE 0) ++ (UNSPEC_LDBIO 1) ++ (UNSPEC_LDBUIO 2) ++ (UNSPEC_LDHIO 3) ++ (UNSPEC_LDHUIO 4) ++ (UNSPEC_LDWIO 5) ++ (UNSPEC_STBIO 6) ++ (UNSPEC_STHIO 7) ++ (UNSPEC_STWIO 8) ++ (UNSPEC_SYNC 9) ++ (UNSPEC_WRCTL 10) ++ (UNSPEC_RDCTL 11) ++ ++]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* instruction scheduler ++;* ++;***************************************************************************** ++ ++; No schedule info is currently available, using an assumption that no ++; instruction can use the results of the previous instruction without ++; incuring a stall. ++ ++; length of an instruction (in bytes) ++(define_attr "length" "" (const_int 4)) ++(define_attr "type" "unknown,complex,control,alu,cond_alu,st,ld,shift,mul,div,custom" (const_string "complex")) ++ ++(define_asm_attributes ++ [(set_attr "length" "4") ++ (set_attr "type" "complex")]) ++ ++(define_automaton "nios2") ++(automata_option "v") ++;(automata_option "no-minimization") ++(automata_option "ndfa") ++ ++; The nios2 pipeline is fairly straightforward for the fast model. ++; Every alu operation is pipelined so that an instruction can ++; be issued every cycle. However, there are still potential ++; stalls which this description tries to deal with. ++ ++(define_cpu_unit "cpu" "nios2") ++ ++(define_insn_reservation "complex" 1 ++ (eq_attr "type" "complex") ++ "cpu") ++ ++(define_insn_reservation "control" 1 ++ (eq_attr "type" "control") ++ "cpu") ++ ++(define_insn_reservation "alu" 1 ++ (eq_attr "type" "alu") ++ "cpu") ++ ++(define_insn_reservation "cond_alu" 1 ++ (eq_attr "type" "cond_alu") ++ "cpu") ++ ++(define_insn_reservation "st" 1 ++ (eq_attr "type" "st") ++ "cpu") ++ ++(define_insn_reservation "custom" 1 ++ (eq_attr "type" "custom") ++ "cpu") ++ ++; shifts, muls and lds have three cycle latency ++(define_insn_reservation "ld" 3 ++ (eq_attr "type" "ld") ++ "cpu") ++ ++(define_insn_reservation "shift" 3 ++ (eq_attr "type" "shift") ++ "cpu") ++ ++(define_insn_reservation "mul" 3 ++ (eq_attr "type" "mul") ++ "cpu") ++ ++(define_insn_reservation "div" 1 ++ (eq_attr "type" "div") ++ "cpu") ++ ++ ++;***************************************************************************** ++;* ++;* MOV Instructions ++;* ++;***************************************************************************** ++ ++(define_expand "movqi" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "") ++ (match_operand:QI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, QImode)) ++ DONE; ++}) ++ ++(define_insn "movqi_internal" ++ [(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r, r") ++ (match_operand:QI 1 "general_operand" "rM,m,rM,I"))] ++ "(register_operand (operands[0], QImode) ++ || register_operand (operands[1], QImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stb%o0\\t%z1, %0 ++ ldbu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu")]) ++ ++(define_insn "ldbio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldbuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDBUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldbuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stbio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STBIO)] ++ "" ++ "stbio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++(define_expand "movhi" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "") ++ (match_operand:HI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, HImode)) ++ DONE; ++}) ++ ++(define_insn "movhi_internal" ++ [(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r, r,r") ++ (match_operand:HI 1 "general_operand" "rM,m,rM,I,J"))] ++ "(register_operand (operands[0], HImode) ++ || register_operand (operands[1], HImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ sth%o0\\t%z1, %0 ++ ldhu%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1" ++ [(set_attr "type" "st,ld,alu,alu,alu")]) ++ ++(define_insn "ldhio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "ldhuio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDHUIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldhuio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "sthio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STHIO)] ++ "" ++ "sthio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++(define_expand "movsi" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "") ++ (match_operand:SI 1 "general_operand" ""))] ++ "" ++{ ++ if (nios2_emit_move_sequence (operands, SImode)) ++ DONE; ++}) ++ ++(define_insn "movsi_internal" ++ [(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r,r,r,r") ++ (match_operand:SI 1 "general_operand" "rM,m,rM,I,J,S,i"))] ++ "(register_operand (operands[0], SImode) ++ || register_operand (operands[1], SImode) ++ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))" ++ "@ ++ stw%o0\\t%z1, %0 ++ ldw%o1\\t%0, %1 ++ mov\\t%0, %z1 ++ movi\\t%0, %1 ++ movui\\t%0, %1 ++ addi\\t%0, gp, %%gprel(%1) ++ movhi\\t%0, %H1\;addi\\t%0, %0, %L1" ++ [(set_attr "type" "st,ld,alu,alu,alu,alu,alu")]) ++ ++(define_insn "ldwio" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_LDWIO)) ++ (use (match_operand:SI 1 "memory_operand" "m"))] ++ "" ++ "ldwio\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_insn "stwio" ++ [(set (match_operand:SI 0 "memory_operand" "=m") ++ (match_operand:SI 1 "register_operand" "r")) ++ (unspec_volatile:SI [(const_int 0)] UNSPEC_STWIO)] ++ "" ++ "stwio\\t%z1, %0" ++ [(set_attr "type" "st")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* zero extension ++;* ++;***************************************************************************** ++ ++ ++(define_insn "zero_extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xffff ++ ldhu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "=r,r") ++ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++(define_insn "zero_extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "r,m")))] ++ "" ++ "@ ++ andi\\t%0, %1, 0xff ++ ldbu%o1\\t%0, %1" ++ [(set_attr "type" "alu,ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* sign extension ++;* ++;***************************************************************************** ++ ++(define_expand "extendhisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (16); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendhisi2_internal" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))] ++ "" ++ "ldh%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++(define_expand "extendqihi2" ++ [(set (match_operand:HI 0 "register_operand" "") ++ (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op0 = gen_lowpart (SImode, operands[0]); ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (op0, temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqihi2_internal" ++ [(set (match_operand:HI 0 "register_operand" "=r") ++ (sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++(define_expand "extendqisi2" ++ [(set (match_operand:SI 0 "register_operand" "") ++ (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))] ++ "" ++{ ++ if (optimize && GET_CODE (operands[1]) == MEM) ++ operands[1] = force_not_mem (operands[1]); ++ ++ if (GET_CODE (operands[1]) != MEM) ++ { ++ rtx op1 = gen_lowpart (SImode, operands[1]); ++ rtx temp = gen_reg_rtx (SImode); ++ rtx shift = GEN_INT (24); ++ ++ emit_insn (gen_ashlsi3 (temp, op1, shift)); ++ emit_insn (gen_ashrsi3 (operands[0], temp, shift)); ++ DONE; ++ } ++}) ++ ++(define_insn "extendqisi2_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))] ++ "" ++ "ldb%o1\\t%0, %1" ++ [(set_attr "type" "ld")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Arithmetic Operations ++;* ++;***************************************************************************** ++ ++(define_insn "addsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (plus:SI (match_operand:SI 1 "register_operand" "%r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "" ++ "add%i2\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "subsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (minus:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++ "sub\\t%0, %z1, %2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "mulsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (mult:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "arith_operand" "r,I")))] ++ "TARGET_HAS_MUL" ++ "mul%i2\\t%0, %1, %z2" ++ [(set_attr "type" "mul")]) ++ ++(define_expand "divsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "" ++{ ++ if (!TARGET_HAS_DIV) ++ { ++ if (!TARGET_FAST_SW_DIV) ++ FAIL; ++ else ++ { ++ if (nios2_emit_expensive_div (operands, SImode)) ++ DONE; ++ } ++ } ++}) ++ ++(define_insn "divsi3_insn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (div:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "div\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "udivsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (udiv:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")))] ++ "TARGET_HAS_DIV" ++ "divu\\t%0, %1, %2" ++ [(set_attr "type" "div")]) ++ ++(define_insn "smulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxss\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++(define_insn "umulsi3_highpart" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (truncate:SI ++ (lshiftrt:DI ++ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r")) ++ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "mulxuu\\t%0, %1, %2" ++ [(set_attr "type" "mul")]) ++ ++ ++(define_expand "mulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) ++ (sign_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++(define_expand "umulsidi3" ++ [(set (subreg:SI (match_operand:DI 0 "register_operand" "") 0) ++ (mult:SI (match_operand:SI 1 "register_operand" "") ++ (match_operand:SI 2 "register_operand" ""))) ++ (set (subreg:SI (match_dup 0) 4) ++ (truncate:SI (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) ++ (zero_extend:DI (match_dup 2))) ++ (const_int 32))))] ++ "TARGET_HAS_MULX" ++ "") ++ ++ ++ ++;***************************************************************************** ++;* ++;* Negate and ones complement ++;* ++;***************************************************************************** ++ ++(define_insn "negsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (neg:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "sub\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++(define_insn "one_cmplsi2" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (not:SI (match_operand:SI 1 "register_operand" "r")))] ++ "" ++{ ++ operands[2] = const0_rtx; ++ return "nor\\t%0, %z2, %1"; ++} ++ [(set_attr "type" "alu")]) ++ ++ ++ ++; Logical Operantions ++ ++(define_insn "andsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (and:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ and\\t%0, %1, %z2 ++ and%i2\\t%0, %1, %2 ++ andh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "iorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (ior:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ or\\t%0, %1, %z2 ++ or%i2\\t%0, %1, %2 ++ orh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "*norsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (and:SI (not:SI (match_operand:SI 1 "register_operand" "%r")) ++ (not:SI (match_operand:SI 2 "reg_or_0_operand" "rM"))))] ++ "" ++ "nor\\t%0, %1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "xorsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r, r,r") ++ (xor:SI (match_operand:SI 1 "register_operand" "%r, r,r") ++ (match_operand:SI 2 "logical_operand" "rM,J,K")))] ++ "" ++ "@ ++ xor\\t%0, %1, %z2 ++ xor%i2\\t%0, %1, %2 ++ xorh%i2\\t%0, %1, %U2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Shifts ++;* ++;***************************************************************************** ++ ++(define_insn "ashlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashift:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sll%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "ashrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (ashiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "sra%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "lshrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "srl%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotlsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotate:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "shift_operand" "r,L")))] ++ "" ++ "rol%i2\\t%0, %1, %z2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "rotrsi3" ++ [(set (match_operand:SI 0 "register_operand" "=r,r") ++ (rotatert:SI (match_operand:SI 1 "register_operand" "r,r") ++ (match_operand:SI 2 "register_operand" "r,r")))] ++ "" ++ "ror\\t%0, %1, %2" ++ [(set_attr "type" "shift")]) ++ ++(define_insn "*shift_mul_constants" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ashift:SI (mult:SI (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "const_int_operand" "I")) ++ (match_operand:SI 3 "const_int_operand" "I")))] ++ "TARGET_HAS_MUL && SMALL_INT (INTVAL (operands[2]) << INTVAL (operands[3]))" ++{ ++ HOST_WIDE_INT mul = INTVAL (operands[2]) << INTVAL (operands[3]); ++ rtx ops[3]; ++ ++ ops[0] = operands[0]; ++ ops[1] = operands[1]; ++ ops[2] = GEN_INT (mul); ++ ++ output_asm_insn ("muli\t%0, %1, %2", ops); ++ return ""; ++} ++ [(set_attr "type" "mul")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Prologue, Epilogue and Return ++;* ++;***************************************************************************** ++ ++(define_expand "prologue" ++ [(const_int 1)] ++ "" ++{ ++ expand_prologue (); ++ DONE; ++}) ++ ++(define_expand "epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (false); ++ DONE; ++}) ++ ++(define_expand "sibcall_epilogue" ++ [(return)] ++ "" ++{ ++ expand_epilogue (true); ++ DONE; ++}) ++ ++(define_insn "return" ++ [(return)] ++ "reload_completed && nios2_can_use_return_insn ()" ++ "ret\\t" ++) ++ ++(define_insn "return_from_epilogue" ++ [(use (match_operand 0 "pmode_register_operand" "")) ++ (return)] ++ "reload_completed" ++ "ret\\t" ++) ++ ++;; Block any insns from being moved before this point, since the ++;; profiling call to mcount can use various registers that aren't ++;; saved or used to pass arguments. ++ ++(define_insn "blockage" ++ [(unspec_volatile [(const_int 0)] UNSPEC_BLOCKAGE)] ++ "" ++ "" ++ [(set_attr "type" "unknown") ++ (set_attr "length" "0")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Jumps and Calls ++;* ++;***************************************************************************** ++ ++(define_insn "indirect_jump" ++ [(set (pc) (match_operand:SI 0 "register_operand" "r"))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "jump" ++ [(set (pc) ++ (label_ref (match_operand 0 "" "")))] ++ "" ++ "br\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "indirect_call" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "indirect_call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))] ++ "" ++ "callr\\t%1" ++) ++ ++(define_expand "call" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_expand "call_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (clobber (reg:SI RA_REGNO))])] ++ "" ++ "") ++ ++(define_insn "*call" ++ [(call (mem:QI (match_operand:SI 0 "immediate_operand" "i")) ++ (match_operand 1 "" "")) ++ (clobber (match_operand:SI 2 "register_operand" "=r"))] ++ "" ++ "call\\t%0" ++ [(set_attr "type" "control")]) ++ ++(define_insn "*call_value" ++ [(set (match_operand 0 "" "") ++ (call (mem:QI (match_operand:SI 1 "immediate_operand" "i")) ++ (match_operand 2 "" ""))) ++ (clobber (match_operand:SI 3 "register_operand" "=r"))] ++ "" ++ "call\\t%1" ++ [(set_attr "type" "control")]) ++ ++(define_expand "sibcall" ++ [(parallel [(call (match_operand 0 "" "") ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))])] ++ "" ++ { ++ XEXP (operands[0], 0) = copy_to_mode_reg (SImode, XEXP (operands[0], 0)); ++ ++ if (operands[2] == NULL_RTX) ++ operands[2] = const0_rtx; ++ } ++) ++ ++(define_expand "sibcall_value" ++ [(parallel [(set (match_operand 0 "" "") ++ (call (match_operand 1 "" "") ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))])] ++ "" ++ { ++ XEXP (operands[1], 0) = copy_to_mode_reg (SImode, XEXP (operands[1], 0)); ++ ++ if (operands[3] == NULL_RTX) ++ operands[3] = const0_rtx; ++ } ++) ++ ++(define_insn "sibcall_insn" ++ [(call (mem:QI (match_operand:SI 0 "register_operand" "r")) ++ (match_operand 1 "" "")) ++ (return) ++ (use (match_operand 2 "" ""))] ++ "" ++ "jmp\\t%0" ++) ++ ++(define_insn "sibcall_value_insn" ++ [(set (match_operand 0 "register_operand" "") ++ (call (mem:QI (match_operand:SI 1 "register_operand" "r")) ++ (match_operand 2 "" ""))) ++ (return) ++ (use (match_operand 3 "" ""))] ++ "" ++ "jmp\\t%1" ++) ++ ++ ++ ++ ++(define_expand "tablejump" ++ [(parallel [(set (pc) (match_operand 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))])] ++ "" ++ "" ++) ++ ++(define_insn "*tablejump" ++ [(set (pc) ++ (match_operand:SI 0 "register_operand" "r")) ++ (use (label_ref (match_operand 1 "" "")))] ++ "" ++ "jmp\\t%0" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Comparisons ++;* ++;***************************************************************************** ++;; Flow here is rather complex (based on MIPS): ++;; ++;; 1) The cmp{si,di,sf,df} routine is called. It deposits the ++;; arguments into the branch_cmp array, and the type into ++;; branch_type. No RTL is generated. ++;; ++;; 2) The appropriate branch define_expand is called, which then ++;; creates the appropriate RTL for the comparison and branch. ++;; Different CC modes are used, based on what type of branch is ++;; done, so that we can constrain things appropriately. There ++;; are assumptions in the rest of GCC that break if we fold the ++;; operands into the branchs for integer operations, and use cc0 ++;; for floating point, so we use the fp status register instead. ++;; If needed, an appropriate temporary is created to hold the ++;; of the integer compare. ++ ++(define_expand "cmpsi" ++ [(set (cc0) ++ (compare:CC (match_operand:SI 0 "register_operand" "") ++ (match_operand:SI 1 "arith_operand" "")))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = operands[1]; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++(define_expand "tstsi" ++ [(set (cc0) ++ (match_operand:SI 0 "register_operand" ""))] ++ "" ++{ ++ branch_cmp[0] = operands[0]; ++ branch_cmp[1] = const0_rtx; ++ branch_type = CMP_SI; ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* setting a register from a comparison ++;* ++;***************************************************************************** ++ ++(define_expand "seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (EQ, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*seq" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (eq:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpeq%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (NE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sne" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ne:SI (match_operand:SI 1 "reg_or_0_operand" "%rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpne%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmplt\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sge" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ge:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmpge%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LE, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sle" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (le:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpge\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LT, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*slt" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (lt:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "arith_operand" "rI")))] ++ "" ++ "cmplt%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgtu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (gtu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpltu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (GEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sgeu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (geu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpgeu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++(define_expand "sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LEU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sleu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (leu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "reg_or_0_operand" "rM")))] ++ "" ++ "cmpgeu\\t%0, %z2, %z1" ++ [(set_attr "type" "alu")]) ++ ++ ++(define_expand "sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_dup 1) ++ (match_dup 2)))] ++ "" ++{ ++ if (branch_type != CMP_SI) ++ FAIL; ++ ++ /* set up operands from compare. */ ++ operands[1] = branch_cmp[0]; ++ operands[2] = branch_cmp[1]; ++ ++ gen_int_relational (LTU, operands[0], operands[1], operands[2], NULL_RTX); ++ DONE; ++}) ++ ++ ++(define_insn "*sltu" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (ltu:SI (match_operand:SI 1 "reg_or_0_operand" "rM") ++ (match_operand:SI 2 "uns_arith_operand" "rJ")))] ++ "" ++ "cmpltu%i2\\t%0, %z1, %z2" ++ [(set_attr "type" "alu")]) ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* branches ++;* ++;***************************************************************************** ++ ++(define_insn "*cbranch" ++ [(set (pc) ++ (if_then_else ++ (match_operator:SI 0 "comparison_operator" ++ [(match_operand:SI 2 "reg_or_0_operand" "rM") ++ (match_operand:SI 3 "reg_or_0_operand" "rM")]) ++ (label_ref (match_operand 1 "" "")) ++ (pc)))] ++ "" ++ "b%0\\t%z2, %z3, %l1" ++ [(set_attr "type" "control")]) ++ ++ ++(define_expand "beq" ++ [(set (pc) ++ (if_then_else (eq:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (EQ, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bne" ++ [(set (pc) ++ (if_then_else (ne:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (NE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgt" ++ [(set (pc) ++ (if_then_else (gt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bge" ++ [(set (pc) ++ (if_then_else (ge:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "ble" ++ [(set (pc) ++ (if_then_else (le:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LE, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "blt" ++ [(set (pc) ++ (if_then_else (lt:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LT, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++(define_expand "bgtu" ++ [(set (pc) ++ (if_then_else (gtu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bgeu" ++ [(set (pc) ++ (if_then_else (geu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (GEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bleu" ++ [(set (pc) ++ (if_then_else (leu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LEU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++(define_expand "bltu" ++ [(set (pc) ++ (if_then_else (ltu:CC (cc0) ++ (const_int 0)) ++ (label_ref (match_operand 0 "" "")) ++ (pc)))] ++ "" ++{ ++ gen_int_relational (LTU, NULL_RTX, branch_cmp[0], branch_cmp[1], operands[0]); ++ DONE; ++}) ++ ++ ++;***************************************************************************** ++;* ++;* String and Block Operations ++;* ++;***************************************************************************** ++ ++; ??? This is all really a hack to get Dhrystone to work as fast as possible ++; things to be fixed: ++; * let the compiler core handle all of this, for that to work the extra ++; aliasing needs to be addressed. ++; * we use three temporary registers for loading and storing to ensure no ++; ld use stalls, this is excessive, because after the first ld/st only ++; two are needed. Only two would be needed all the way through if ++; we could schedule with other code. Consider: ++; 1 ld $1, 0($src) ++; 2 ld $2, 4($src) ++; 3 ld $3, 8($src) ++; 4 st $1, 0($dest) ++; 5 ld $1, 12($src) ++; 6 st $2, 4($src) ++; 7 etc. ++; The first store has to wait until 4. If it does not there will be one ++; cycle of stalling. However, if any other instruction could be placed ++; between 1 and 4, $3 would not be needed. ++; * In small we probably don't want to ever do this ourself because there ++; is no ld use stall. ++ ++(define_expand "movstrsi" ++ [(parallel [(set (match_operand:BLK 0 "general_operand" "") ++ (match_operand:BLK 1 "general_operand" "")) ++ (use (match_operand:SI 2 "const_int_operand" "")) ++ (use (match_operand:SI 3 "const_int_operand" "")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))])] ++ "TARGET_INLINE_MEMCPY" ++{ ++ rtx ld_addr_reg, st_addr_reg; ++ ++ /* If the predicate for op2 fails in expr.c:emit_block_move_via_movstr ++ it trys to copy to a register, but does not re-try the predicate. ++ ??? Intead of fixing expr.c, I fix it here. */ ++ if (!const_int_operand (operands[2], SImode)) ++ FAIL; ++ ++ /* ??? there are some magic numbers which need to be sorted out here. ++ the basis for them is not increasing code size hugely or going ++ out of range of offset addressing */ ++ if (INTVAL (operands[3]) < 4) ++ FAIL; ++ if (!optimize ++ || (optimize_size && INTVAL (operands[2]) > 12) ++ || (optimize < 3 && INTVAL (operands[2]) > 100) ++ || INTVAL (operands[2]) > 200) ++ FAIL; ++ ++ st_addr_reg ++ = replace_equiv_address (operands[0], ++ copy_to_mode_reg (Pmode, XEXP (operands[0], 0))); ++ ld_addr_reg ++ = replace_equiv_address (operands[1], ++ copy_to_mode_reg (Pmode, XEXP (operands[1], 0))); ++ emit_insn (gen_movstrsi_internal (st_addr_reg, ld_addr_reg, ++ operands[2], operands[3])); ++ ++ DONE; ++}) ++ ++ ++(define_insn "movstrsi_internal" ++ [(set (match_operand:BLK 0 "memory_operand" "=o") ++ (match_operand:BLK 1 "memory_operand" "o")) ++ (use (match_operand:SI 2 "const_int_operand" "i")) ++ (use (match_operand:SI 3 "const_int_operand" "i")) ++ (clobber (match_scratch:SI 4 "=&r")) ++ (clobber (match_scratch:SI 5 "=&r")) ++ (clobber (match_scratch:SI 6 "=&r"))] ++ "TARGET_INLINE_MEMCPY" ++{ ++ int ld_offset = INTVAL (operands[2]); ++ int ld_len = INTVAL (operands[2]); ++ int ld_reg = 0; ++ rtx ld_addr_reg = XEXP (operands[1], 0); ++ int st_offset = INTVAL (operands[2]); ++ int st_len = INTVAL (operands[2]); ++ int st_reg = 0; ++ rtx st_addr_reg = XEXP (operands[0], 0); ++ int delay_count = 0; ++ ++ /* ops[0] is the address used by the insn ++ ops[1] is the register being loaded or stored */ ++ rtx ops[2]; ++ ++ if (INTVAL (operands[3]) < 4) ++ abort (); ++ ++ while (ld_offset >= 4) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldw\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 4; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 2) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldh\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 2; ++ delay_count++; ++ } ++ ++ if (ld_offset >= 1) ++ { ++ /* if the load use delay has been met, I can start ++ storing */ ++ if (delay_count >= 3) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (ld_addr_reg, ld_len - ld_offset)); ++ ops[1] = operands[ld_reg + 4]; ++ output_asm_insn ("ldb\t%1, %0", ops); ++ ++ ld_reg = (ld_reg + 1) % 3; ++ ld_offset -= 1; ++ delay_count++; ++ } ++ ++ while (st_offset >= 4) ++ { ++ ops[0] = gen_rtx (MEM, SImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stw\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 4; ++ } ++ ++ while (st_offset >= 2) ++ { ++ ops[0] = gen_rtx (MEM, HImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("sth\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 2; ++ } ++ ++ while (st_offset >= 1) ++ { ++ ops[0] = gen_rtx (MEM, QImode, ++ plus_constant (st_addr_reg, st_len - st_offset)); ++ ops[1] = operands[st_reg + 4]; ++ output_asm_insn ("stb\t%1, %0", ops); ++ ++ st_reg = (st_reg + 1) % 3; ++ st_offset -= 1; ++ } ++ ++ return ""; ++} ++; ??? lengths are not being used yet, but I will probably forget ++; to update this once I am using lengths, so set it to something ++; definetely big enough to cover it. 400 allows for 200 bytes ++; of motion. ++ [(set_attr "length" "400")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Custom instructions ++;* ++;***************************************************************************** ++ ++(define_constants [ ++ (CUSTOM_N 100) ++ (CUSTOM_NI 101) ++ (CUSTOM_NF 102) ++ (CUSTOM_NP 103) ++ (CUSTOM_NII 104) ++ (CUSTOM_NIF 105) ++ (CUSTOM_NIP 106) ++ (CUSTOM_NFI 107) ++ (CUSTOM_NFF 108) ++ (CUSTOM_NFP 109) ++ (CUSTOM_NPI 110) ++ (CUSTOM_NPF 111) ++ (CUSTOM_NPP 112) ++ (CUSTOM_IN 113) ++ (CUSTOM_INI 114) ++ (CUSTOM_INF 115) ++ (CUSTOM_INP 116) ++ (CUSTOM_INII 117) ++ (CUSTOM_INIF 118) ++ (CUSTOM_INIP 119) ++ (CUSTOM_INFI 120) ++ (CUSTOM_INFF 121) ++ (CUSTOM_INFP 122) ++ (CUSTOM_INPI 123) ++ (CUSTOM_INPF 124) ++ (CUSTOM_INPP 125) ++ (CUSTOM_FN 126) ++ (CUSTOM_FNI 127) ++ (CUSTOM_FNF 128) ++ (CUSTOM_FNP 129) ++ (CUSTOM_FNII 130) ++ (CUSTOM_FNIF 131) ++ (CUSTOM_FNIP 132) ++ (CUSTOM_FNFI 133) ++ (CUSTOM_FNFF 134) ++ (CUSTOM_FNFP 135) ++ (CUSTOM_FNPI 136) ++ (CUSTOM_FNPF 137) ++ (CUSTOM_FNPP 138) ++ (CUSTOM_PN 139) ++ (CUSTOM_PNI 140) ++ (CUSTOM_PNF 141) ++ (CUSTOM_PNP 142) ++ (CUSTOM_PNII 143) ++ (CUSTOM_PNIF 144) ++ (CUSTOM_PNIP 145) ++ (CUSTOM_PNFI 146) ++ (CUSTOM_PNFF 147) ++ (CUSTOM_PNFP 148) ++ (CUSTOM_PNPI 149) ++ (CUSTOM_PNPF 150) ++ (CUSTOM_PNPP 151) ++]) ++ ++ ++(define_insn "custom_n" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N")] CUSTOM_N)] ++ "" ++ "custom\\t%0, zero, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ni" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NI)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r")] CUSTOM_NF)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_np" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r")] CUSTOM_NP)] ++ "" ++ "custom\\t%0, zero, %1, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nii" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NII)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nif" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NIF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nip" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NIP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nff" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NFF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_nfp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SF 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NFP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npi" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPI)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npf" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_NPF)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_npp" ++ [(unspec_volatile [(match_operand:SI 0 "custom_insn_opcode" "N") ++ (match_operand:SI 1 "register_operand" "r") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_NPP)] ++ "" ++ "custom\\t%0, zero, %1, %2" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_in" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_IN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_ini" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_INF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_INP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_infp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_INPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_inpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_INPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++(define_insn "custom_fn" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_FN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fni" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_FNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_FNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnii" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnif" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnip" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnff" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnfp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpi" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpf" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_FNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_fnpp" ++ [(set (match_operand:SF 0 "register_operand" "=r") ++ (unspec_volatile:SF [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_FNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++(define_insn "custom_pn" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N")] CUSTOM_PN))] ++ "" ++ "custom\\t%1, %0, zero, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pni" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNI))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r")] CUSTOM_PNF))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r")] CUSTOM_PNP))] ++ "" ++ "custom\\t%1, %0, %2, zero" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnii" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNII))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnif" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNIF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnip" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNIP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnff" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNFF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnfp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SF 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNFP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpi" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPI))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpf" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SF 3 "register_operand" "r")] CUSTOM_PNPF))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++(define_insn "custom_pnpp" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "custom_insn_opcode" "N") ++ (match_operand:SI 2 "register_operand" "r") ++ (match_operand:SI 3 "register_operand" "r")] CUSTOM_PNPP))] ++ "" ++ "custom\\t%1, %0, %2, %3" ++ [(set_attr "type" "custom")]) ++ ++ ++ ++ ++ ++ ++;***************************************************************************** ++;* ++;* Misc ++;* ++;***************************************************************************** ++ ++(define_insn "nop" ++ [(const_int 0)] ++ "" ++ "nop\\t" ++ [(set_attr "type" "alu")]) ++ ++(define_insn "sync" ++ [(unspec_volatile [(const_int 0)] UNSPEC_SYNC)] ++ "" ++ "sync\\t" ++ [(set_attr "type" "control")]) ++ ++ ++(define_insn "rdctl" ++ [(set (match_operand:SI 0 "register_operand" "=r") ++ (unspec_volatile:SI [(match_operand:SI 1 "rdwrctl_operand" "O")] UNSPEC_RDCTL))] ++ "" ++ "rdctl\\t%0, ctl%1" ++ [(set_attr "type" "control")]) ++ ++(define_insn "wrctl" ++ [(unspec_volatile:SI [(match_operand:SI 0 "rdwrctl_operand" "O") ++ (match_operand:SI 1 "register_operand" "r")] UNSPEC_WRCTL)] ++ "" ++ "wrctl\\tctl%0, %1" ++ [(set_attr "type" "control")]) ++ ++ ++ ++;***************************************************************************** ++;* ++;* Peepholes ++;* ++;***************************************************************************** ++ ++ +--- gcc-3.4.3/gcc/config/nios2/t-nios2 ++++ gcc-3.4.3-nios2/gcc/config/nios2/t-nios2 +@@ -0,0 +1,123 @@ ++## ++## Compiler flags to use when compiling libgcc2.c. ++## ++## LIB2FUNCS_EXTRA ++## A list of source file names to be compiled or assembled and inserted into libgcc.a. ++ ++LIB2FUNCS_EXTRA=$(srcdir)/config/nios2/lib2-divmod.c \ ++ $(srcdir)/config/nios2/lib2-divmod-hi.c \ ++ $(srcdir)/config/nios2/lib2-divtable.c \ ++ $(srcdir)/config/nios2/lib2-mul.c ++ ++## ++## Floating Point Emulation ++## To have GCC include software floating point libraries in libgcc.a define FPBIT ++## and DPBIT along with a few rules as follows: ++## ++## # We want fine grained libraries, so use the new code ++## # to build the floating point emulation libraries. ++FPBIT=$(srcdir)/config/nios2/nios2-fp-bit.c ++DPBIT=$(srcdir)/config/nios2/nios2-dp-bit.c ++ ++TARGET_LIBGCC2_CFLAGS = -O2 ++ ++# FLOAT_ONLY - no doubles ++# SMALL_MACHINE - QI/HI is faster than SI ++# Actually SMALL_MACHINE uses chars and shorts instead of ints ++# since ints (16-bit ones as they are today) are at least as fast ++# as chars and shorts, don't define SMALL_MACHINE ++# CMPtype - type returned by FP compare, i.e. INT (hard coded in fp-bit - see code ) ++ ++$(FPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '#define FLOAT' > ${FPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${FPBIT} ++ ++$(DPBIT): $(srcdir)/config/fp-bit.c Makefile ++ echo '' > ${DPBIT} ++ cat $(srcdir)/config/fp-bit.c >> ${DPBIT} ++ ++EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o ++ ++# Assemble startup files. ++$(T)crti.o: $(srcdir)/config/nios2/crti.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/nios2/crti.asm ++ ++$(T)crtn.o: $(srcdir)/config/nios2/crtn.asm $(GCC_PASSES) ++ $(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \ ++ -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/nios2/crtn.asm ++ ++ ++## You may need to provide additional #defines at the beginning of ++## fp-bit.c and dp-bit.c to control target endianness and other options ++## ++## CRTSTUFF_T_CFLAGS ++## Special flags used when compiling crtstuff.c. See Initialization. ++## ++## CRTSTUFF_T_CFLAGS_S ++## Special flags used when compiling crtstuff.c for shared linking. Used ++## if you use crtbeginS.o and crtendS.o in EXTRA-PARTS. See Initialization. ++## ++## MULTILIB_OPTIONS ++## For some targets, invoking GCC in different ways produces objects that ++## can not be linked together. For example, for some targets GCC produces ++## both big and little endian code. For these targets, you must arrange ++## for multiple versions of libgcc.a to be compiled, one for each set of ++## incompatible options. When GCC invokes the linker, it arranges to link ++## in the right version of libgcc.a, based on the command line options ++## used. ++## The MULTILIB_OPTIONS macro lists the set of options for which special ++## versions of libgcc.a must be built. Write options that are mutually ++## incompatible side by side, separated by a slash. Write options that may ++## be used together separated by a space. The build procedure will build ++## all combinations of compatible options. ++## ++## For example, if you set MULTILIB_OPTIONS to m68000/m68020 msoft-float, ++## Makefile will build special versions of libgcc.a using the following ++## sets of options: -m68000, -m68020, -msoft-float, -m68000 -msoft-float, ++## and -m68020 -msoft-float. ++ ++MULTILIB_OPTIONS = mno-hw-mul mhw-mulx ++ ++## MULTILIB_DIRNAMES ++## If MULTILIB_OPTIONS is used, this variable specifies the directory names ++## that should be used to hold the various libraries. Write one element in ++## MULTILIB_DIRNAMES for each element in MULTILIB_OPTIONS. If ++## MULTILIB_DIRNAMES is not used, the default value will be ++## MULTILIB_OPTIONS, with all slashes treated as spaces. ++## For example, if MULTILIB_OPTIONS is set to m68000/m68020 msoft-float, ++## then the default value of MULTILIB_DIRNAMES is m68000 m68020 ++## msoft-float. You may specify a different value if you desire a ++## different set of directory names. ++ ++# MULTILIB_DIRNAMES = ++ ++## MULTILIB_MATCHES ++## Sometimes the same option may be written in two different ways. If an ++## option is listed in MULTILIB_OPTIONS, GCC needs to know about any ++## synonyms. In that case, set MULTILIB_MATCHES to a list of items of the ++## form option=option to describe all relevant synonyms. For example, ++## m68000=mc68000 m68020=mc68020. ++## ++## MULTILIB_EXCEPTIONS ++## Sometimes when there are multiple sets of MULTILIB_OPTIONS being ++## specified, there are combinations that should not be built. In that ++## case, set MULTILIB_EXCEPTIONS to be all of the switch exceptions in ++## shell case syntax that should not be built. ++## For example, in the PowerPC embedded ABI support, it is not desirable to ++## build libraries compiled with the -mcall-aix option and either of the ++## -fleading-underscore or -mlittle options at the same time. Therefore ++## MULTILIB_EXCEPTIONS is set to ++## ++## *mcall-aix/*fleading-underscore* *mlittle/*mcall-aix* ++## ++ ++MULTILIB_EXCEPTIONS = *mno-hw-mul/*mhw-mulx* ++ ++## ++## MULTILIB_EXTRA_OPTS Sometimes it is desirable that when building ++## multiple versions of libgcc.a certain options should always be passed on ++## to the compiler. In that case, set MULTILIB_EXTRA_OPTS to be the list ++## of options to be used for all builds. ++## ++ +--- gcc-3.4.3/gcc/config.gcc ++++ gcc-3.4.3-nios2/gcc/config.gcc +@@ -1321,6 +1321,10 @@ m32rle-*-linux*) + thread_file='posix' + fi + ;; ++# JBG ++nios2-*-* | nios2-*-*) ++ tm_file="elfos.h ${tm_file}" ++ ;; + # m68hc11 and m68hc12 share the same machine description. + m68hc11-*-*|m6811-*-*) + tm_file="dbxelf.h elfos.h m68hc11/m68hc11.h" +--- gcc-3.4.3/gcc/cse.c ++++ gcc-3.4.3-nios2/gcc/cse.c +@@ -3134,6 +3134,10 @@ find_comparison_args (enum rtx_code code + #ifdef FLOAT_STORE_FLAG_VALUE + REAL_VALUE_TYPE fsfv; + #endif ++#ifdef __nios2__ ++ if (p->is_const) ++ break; ++#endif + + /* If the entry isn't valid, skip it. */ + if (! exp_equiv_p (p->exp, p->exp, 1, 0)) +--- gcc-3.4.3/gcc/doc/extend.texi ++++ gcc-3.4.3-nios2/gcc/doc/extend.texi +@@ -5636,12 +5636,118 @@ to those machines. Generally these gene + instructions, but allow the compiler to schedule those calls. + + @menu ++* Altera Nios II Built-in Functions:: + * Alpha Built-in Functions:: + * ARM Built-in Functions:: + * X86 Built-in Functions:: + * PowerPC AltiVec Built-in Functions:: + @end menu + ++@node Altera Nios II Built-in Functions ++@subsection Altera Nios II Built-in Functions ++ ++These built-in functions are available for the Altera Nios II ++family of processors. ++ ++The following built-in functions are always available. They ++all generate the machine instruction that is part of the name. ++ ++@example ++int __builtin_ldbio (volatile const void *) ++int __builtin_ldbuio (volatile const void *) ++int __builtin_ldhio (volatile const void *) ++int __builtin_ldhuio (volatile const void *) ++int __builtin_ldwio (volatile const void *) ++void __builtin_stbio (volatile void *, int) ++void __builtin_sthio (volatile void *, int) ++void __builtin_stwio (volatile void *, int) ++void __builtin_sync (void) ++int __builtin_rdctl (int) ++void __builtin_wrctl (int, int) ++@end example ++ ++The following built-in functions are always available. They ++all generate a Nios II Custom Instruction. The name of the ++function represents the types that the function takes and ++returns. The letter before the @code{n} is the return type ++or void if absent. The @code{n} represnts the first parameter ++to all the custom instructions, the custom instruction number. ++The two letters after the @code{n} represent the up to two ++parameters to the function. ++ ++The letters reprsent the following data types: ++@table @code ++@item ++@code{void} for return type and no parameter for parameter types. ++ ++@item i ++@code{int} for return type and parameter type ++ ++@item f ++@code{float} for return type and parameter type ++ ++@item p ++@code{void *} for return type and parameter type ++ ++@end table ++ ++And the function names are: ++@example ++void __builtin_custom_n (void) ++void __builtin_custom_ni (int) ++void __builtin_custom_nf (float) ++void __builtin_custom_np (void *) ++void __builtin_custom_nii (int, int) ++void __builtin_custom_nif (int, float) ++void __builtin_custom_nip (int, void *) ++void __builtin_custom_nfi (float, int) ++void __builtin_custom_nff (float, float) ++void __builtin_custom_nfp (float, void *) ++void __builtin_custom_npi (void *, int) ++void __builtin_custom_npf (void *, float) ++void __builtin_custom_npp (void *, void *) ++int __builtin_custom_in (void) ++int __builtin_custom_ini (int) ++int __builtin_custom_inf (float) ++int __builtin_custom_inp (void *) ++int __builtin_custom_inii (int, int) ++int __builtin_custom_inif (int, float) ++int __builtin_custom_inip (int, void *) ++int __builtin_custom_infi (float, int) ++int __builtin_custom_inff (float, float) ++int __builtin_custom_infp (float, void *) ++int __builtin_custom_inpi (void *, int) ++int __builtin_custom_inpf (void *, float) ++int __builtin_custom_inpp (void *, void *) ++float __builtin_custom_fn (void) ++float __builtin_custom_fni (int) ++float __builtin_custom_fnf (float) ++float __builtin_custom_fnp (void *) ++float __builtin_custom_fnii (int, int) ++float __builtin_custom_fnif (int, float) ++float __builtin_custom_fnip (int, void *) ++float __builtin_custom_fnfi (float, int) ++float __builtin_custom_fnff (float, float) ++float __builtin_custom_fnfp (float, void *) ++float __builtin_custom_fnpi (void *, int) ++float __builtin_custom_fnpf (void *, float) ++float __builtin_custom_fnpp (void *, void *) ++void * __builtin_custom_pn (void) ++void * __builtin_custom_pni (int) ++void * __builtin_custom_pnf (float) ++void * __builtin_custom_pnp (void *) ++void * __builtin_custom_pnii (int, int) ++void * __builtin_custom_pnif (int, float) ++void * __builtin_custom_pnip (int, void *) ++void * __builtin_custom_pnfi (float, int) ++void * __builtin_custom_pnff (float, float) ++void * __builtin_custom_pnfp (float, void *) ++void * __builtin_custom_pnpi (void *, int) ++void * __builtin_custom_pnpf (void *, float) ++void * __builtin_custom_pnpp (void *, void *) ++@end example ++ ++ + @node Alpha Built-in Functions + @subsection Alpha Built-in Functions + +--- gcc-3.4.3/gcc/doc/invoke.texi ++++ gcc-3.4.3-nios2/gcc/doc/invoke.texi +@@ -337,6 +337,14 @@ in the following sections. + @item Machine Dependent Options + @xref{Submodel Options,,Hardware Models and Configurations}. + ++@emph{Altera Nios II Options} ++@gccoptlist{-msmallc -mno-bypass-cache -mbypass-cache @gol ++-mno-cache-volatile -mcache-volatile -mno-inline-memcpy @gol ++-minline-memcpy -mno-fast-sw-div -mfast-sw-div @gol ++-mhw-mul -mno-hw-mul -mhw-mulx -mno-hw-mulx @gol ++-mno-hw-div -mhw-div @gol ++-msys-crt0= -msys-lib= -msys=nosys } ++ + @emph{M680x0 Options} + @gccoptlist{-m68000 -m68020 -m68020-40 -m68020-60 -m68030 -m68040 @gol + -m68060 -mcpu32 -m5200 -m68881 -mbitfield -mc68000 -mc68020 @gol +@@ -5836,6 +5844,7 @@ machine description. The default for th + that macro, which enables you to change the defaults. + + @menu ++* Altera Nios II Options:: + * M680x0 Options:: + * M68hc1x Options:: + * VAX Options:: +@@ -5871,6 +5880,103 @@ that macro, which enables you to change + * FRV Options:: + @end menu + ++ ++@node Altera Nios II Options ++@subsection Altera Nios II Options ++@cindex Altera Nios II options ++ ++These are the @samp{-m} options defined for the Altera Nios II ++processor. ++ ++@table @gcctabopt ++ ++@item -msmallc ++@opindex msmallc ++ ++Link with a limited version of the C library, -lsmallc. For more ++information see the C Library Documentation. ++ ++ ++@item -mbypass-cache ++@itemx -mno-bypass-cache ++@opindex mno-bypass-cache ++@opindex mbypass-cache ++ ++Force all load and store instructions to always bypass cache by ++using io variants of the instructions. The default is to not ++bypass the cache. ++ ++@item -mno-cache-volatile ++@itemx -mcache-volatile ++@opindex mcache-volatile ++@opindex mno-cache-volatile ++ ++Volatile memory access bypass the cache using the io variants of ++the ld and st instructions. The default is to cache volatile ++accesses. ++ ++-mno-cache-volatile is deprecated and will be deleted in a ++future GCC release. ++ ++ ++@item -mno-inline-memcpy ++@itemx -minline-memcpy ++@opindex mno-inline-memcpy ++@opindex minline-memcpy ++ ++Do not inline memcpy. The default is to inline when -O is on. ++ ++ ++@item -mno-fast-sw-div ++@itemx -mfast-sw-div ++@opindex mno-fast-sw-div ++@opindex mfast-sw-div ++ ++Do no use table based fast divide for small numbers. The default ++is to use the fast divide at -O3 and above. ++ ++ ++@item -mno-hw-mul ++@itemx -mhw-mul ++@itemx -mno-hw-mulx ++@itemx -mhw-mulx ++@itemx -mno-hw-div ++@itemx -mhw-div ++@opindex mno-hw-mul ++@opindex mhw-mul ++@opindex mno-hw-mulx ++@opindex mhw-mulx ++@opindex mno-hw-div ++@opindex mhw-div ++ ++Enable or disable emitting @code{mul}, @code{mulx} and @code{div} family of ++instructions by the compiler. The default is to emit @code{mul} ++and not emit @code{div} and @code{mulx}. ++ ++The different combinations of @code{mul} and @code{mulx} instructions ++generate a different multilib options. ++ ++ ++@item -msys-crt0=@var{startfile} ++@opindex msys-crt0 ++ ++@var{startfile} is the file name of the startfile (crt0) to use ++when linking. The default is crt0.o that comes with libgloss ++and is only suitable for use with the instruction set ++simulator. ++ ++@item -msys-lib=@var{systemlib} ++@itemx -msys-lib=nosys ++@opindex msys-lib ++ ++@var{systemlib} is the library name of the library which provides ++the system calls required by the C library, e.g. @code{read}, @code{write} ++etc. The default is to use nosys, this library provides ++stub implementations of the calls and is part of libgloss. ++ ++@end table ++ ++ + @node M680x0 Options + @subsection M680x0 Options + @cindex M680x0 options +--- gcc-3.4.3/gcc/doc/md.texi ++++ gcc-3.4.3-nios2/gcc/doc/md.texi +@@ -1335,6 +1335,49 @@ However, here is a summary of the machin + available on some particular machines. + + @table @emph ++ ++@item Altera Nios II family---@file{nios2.h} ++@table @code ++ ++@item I ++Integer that is valid as an immediate operand in an ++instruction taking a signed 16-bit number. Range ++@minus{}32768 to 32767. ++ ++@item J ++Integer that is valid as an immediate operand in an ++instruction taking an unsigned 16-bit number. Range ++0 to 65535. ++ ++@item K ++Integer that is valid as an immediate operand in an ++instruction taking only the upper 16-bits of a ++32-bit number. Range 32-bit numbers with the lower ++16-bits being 0. ++ ++@item L ++Integer that is valid as an immediate operand for a ++shift instruction. Range 0 to 31. ++ ++ ++@item M ++Integer that is valid as an immediate operand for ++only the value 0. Can be used in conjunction with ++the format modifier @code{z} to use @code{r0} ++instead of @code{0} in the assembly output. ++ ++@item N ++Integer that is valid as an immediate operand for ++a custom instruction opcode. Range 0 to 255. ++ ++@item S ++Matches immediates which are addresses in the small ++data section and therefore can be added to @code{gp} ++as a 16-bit immediate to re-create their 32-bit value. ++ ++@end table ++ ++ + @item ARM family---@file{arm.h} + @table @code + @item f diff --git a/misc/buildroot/toolchain/gcc/3.4.6/arm-softfloat.patch.conditional b/misc/buildroot/toolchain/gcc/3.4.6/arm-softfloat.patch.conditional new file mode 100644 index 000000000..19d1b90da --- /dev/null +++ b/misc/buildroot/toolchain/gcc/3.4.6/arm-softfloat.patch.conditional @@ -0,0 +1,270 @@ +Note... modified my mjn3 to not conflict with the big endian arm patch. +Warning!!! Only the linux target is aware of TARGET_ENDIAN_DEFAULT. +Also changed + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{!mcpu=*:-mcpu=xscale} \ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +to + #define SUBTARGET_EXTRA_ASM_SPEC "\ + %{mhard-float:-mfpu=fpa} \ + %{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" +in gcc/config/arm/linux-elf.h. +# +# Submitted: +# +# Dimitry Andric , 2004-05-01 +# +# Description: +# +# Nicholas Pitre released this patch for gcc soft-float support here: +# http://lists.arm.linux.org.uk/pipermail/linux-arm/2003-October/006436.html +# +# This version has been adapted to work with gcc 3.4.0. +# +# The original patch doesn't distinguish between softfpa and softvfp modes +# in the way Nicholas Pitre probably meant. His description is: +# +# "Default is to use APCS-32 mode with soft-vfp. The old Linux default for +# floats can be achieved with -mhard-float or with the configure +# --with-float=hard option. If -msoft-float or --with-float=soft is used then +# software float support will be used just like the default but with the legacy +# big endian word ordering for double float representation instead." +# +# Which means the following: +# +# * If you compile without -mhard-float or -msoft-float, you should get +# software floating point, using the VFP format. The produced object file +# should have these flags in its header: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# * If you compile with -mhard-float, you should get hardware floating point, +# which always uses the FPA format. Object file header flags should be: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# * If you compile with -msoft-float, you should get software floating point, +# using the FPA format. This is done for compatibility reasons with many +# existing distributions. Object file header flags should be: +# +# private flags = 200: [APCS-32] [FPA float format] [software FP] +# +# The original patch from Nicholas Pitre contained the following constructs: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" +# +# However, gcc doesn't accept this ";:" notation, used in the 3rd line. This +# is probably the reason Robert Schwebel modified it to: +# +# #define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +# %{mhard-float:-mfpu=fpa} \ +# %{!mhard-float: %{msoft-float:-mfpu=softfpa -mfpu=softvfp}}" +# +# But this causes the following behaviour: +# +# * If you compile without -mhard-float or -msoft-float, the compiler generates +# software floating point instructions, but *nothing* is passed to the +# assembler, which results in an object file which has flags: +# +# private flags = 0: [APCS-32] [FPA float format] +# +# This is not correct! +# +# * If you compile with -mhard-float, the compiler generates hardware floating +# point instructions, and passes "-mfpu=fpa" to the assembler, which results +# in an object file which has the same flags as in the previous item, but now +# those *are* correct. +# +# * If you compile with -msoft-float, the compiler generates software floating +# point instructions, and passes "-mfpu=softfpa -mfpu=softvfp" (in that +# order) to the assembler, which results in an object file with flags: +# +# private flags = 600: [APCS-32] [VFP float format] [software FP] +# +# This is not correct, because the last "-mfpu=" option on the assembler +# command line determines the actual FPU convention used (which should be FPA +# in this case). +# +# Therefore, I modified this patch to get the desired behaviour. Every +# instance of the notation: +# +# %{msoft-float:-mfpu=softfpa -mfpu=softvfp} +# +# was changed to: +# +# %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp} +# +# I also did the following: +# +# * Modified all TARGET_DEFAULT macros I could find to include ARM_FLAG_VFP, to +# be consistent with Nicholas' original patch. +# * Removed any "msoft-float" or "mhard-float" from all MULTILIB_DEFAULTS +# macros I could find. I think that if you compile without any options, you +# would like to get the defaults. :) +# * Removed the extra -lfloat option from LIBGCC_SPEC, since it isn't needed +# anymore. (The required functions are now in libgcc.) + +diff -urN gcc-3.4.1-old/gcc/config/arm/coff.h gcc-3.4.1/gcc/config/arm/coff.h +--- gcc-3.4.1-old/gcc/config/arm/coff.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/coff.h 2004-09-02 21:51:15.000000000 -0500 +@@ -31,11 +31,16 @@ + #define TARGET_VERSION fputs (" (ARM/coff)", stderr) + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork" } + #endif + + /* This is COFF, but prefer stabs. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/elf.h gcc-3.4.1/gcc/config/arm/elf.h +--- gcc-3.4.1-old/gcc/config/arm/elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -46,7 +46,9 @@ + + #ifndef SUBTARGET_ASM_FLOAT_SPEC + #define SUBTARGET_ASM_FLOAT_SPEC "\ +-%{mapcs-float:-mfloat} %{msoft-float:-mfpu=softfpa}" ++%{mapcs-float:-mfloat} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + #endif + + #ifndef ASM_SPEC +@@ -106,12 +108,17 @@ + #endif + + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "msoft-float", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } ++ { "marm", "mlittle-endian", "mapcs-32", "mno-thumb-interwork", "fno-leading-underscore" } + #endif + + #define TARGET_ASM_FILE_START_APP_OFF true +diff -urN gcc-3.4.1-old/gcc/config/arm/linux-elf.h gcc-3.4.1/gcc/config/arm/linux-elf.h +--- gcc-3.4.1-old/gcc/config/arm/linux-elf.h 2004-09-02 21:50:52.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/linux-elf.h 2004-09-02 22:00:49.000000000 -0500 +@@ -44,12 +44,26 @@ + #define TARGET_LINKER_EMULATION "armelf_linux" + #endif + +-/* Default is to use APCS-32 mode. */ ++/* ++ * Default is to use APCS-32 mode with soft-vfp. ++ * The old Linux default for floats can be achieved with -mhard-float ++ * or with the configure --with-float=hard option. ++ * If -msoft-float or --with-float=soft is used then software float ++ * support will be used just like the default but with the legacy ++ * big endian word ordering for double float representation instead. ++ */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT \ +- ( ARM_FLAG_APCS_32 | \ +- ARM_FLAG_MMU_TRAPS | \ +- TARGET_ENDIAN_DEFAULT ) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_SOFT_FLOAT \ ++ | TARGET_ENDIAN_DEFAULT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_MMU_TRAPS ) ++ ++#undef SUBTARGET_EXTRA_ASM_SPEC ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +@@ -57,7 +71,7 @@ + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mapcs-32", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mapcs-32", "mno-thumb-interwork" } + + #define CPP_APCS_PC_DEFAULT_SPEC "-D__APCS_32__" + +@@ -72,7 +86,7 @@ + %{shared:-lc} \ + %{!shared:%{profile:-lc_p}%{!profile:-lc}}" + +-#define LIBGCC_SPEC "%{msoft-float:-lfloat} -lgcc" ++#define LIBGCC_SPEC "-lgcc" + + /* Provide a STARTFILE_SPEC appropriate for GNU/Linux. Here we add + the GNU/Linux magical crtbegin.o file (see crtstuff.c) which +diff -urN gcc-3.4.1-old/gcc/config/arm/t-linux gcc-3.4.1/gcc/config/arm/t-linux +--- gcc-3.4.1-old/gcc/config/arm/t-linux 2003-09-20 16:09:07.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/t-linux 2004-09-02 21:51:15.000000000 -0500 +@@ -4,7 +4,10 @@ + LIBGCC2_DEBUG_CFLAGS = -g0 + + LIB1ASMSRC = arm/lib1funcs.asm +-LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx ++LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3 _dvmd_lnx \ ++ _negdf2 _addsubdf3 _muldivdf3 _cmpdf2 _unorddf2 _fixdfsi _fixunsdfsi \ ++ _truncdfsf2 _negsf2 _addsubsf3 _muldivsf3 _cmpsf2 _unordsf2 \ ++ _fixsfsi _fixunssfsi + + # MULTILIB_OPTIONS = mhard-float/msoft-float + # MULTILIB_DIRNAMES = hard-float soft-float +diff -urN gcc-3.4.1-old/gcc/config/arm/unknown-elf.h gcc-3.4.1/gcc/config/arm/unknown-elf.h +--- gcc-3.4.1-old/gcc/config/arm/unknown-elf.h 2004-02-24 08:25:22.000000000 -0600 ++++ gcc-3.4.1/gcc/config/arm/unknown-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -30,7 +30,12 @@ + + /* Default to using APCS-32 and software floating point. */ + #ifndef TARGET_DEFAULT +-#define TARGET_DEFAULT (ARM_FLAG_SOFT_FLOAT | ARM_FLAG_APCS_32 | ARM_FLAG_APCS_FRAME | ARM_FLAG_MMU_TRAPS) ++#define TARGET_DEFAULT \ ++ ( ARM_FLAG_SOFT_FLOAT \ ++ | ARM_FLAG_VFP \ ++ | ARM_FLAG_APCS_32 \ ++ | ARM_FLAG_APCS_FRAME \ ++ | ARM_FLAG_MMU_TRAPS ) + #endif + + /* Now we define the strings used to build the spec file. */ +diff -urN gcc-3.4.1-old/gcc/config/arm/xscale-elf.h gcc-3.4.1/gcc/config/arm/xscale-elf.h +--- gcc-3.4.1-old/gcc/config/arm/xscale-elf.h 2003-07-01 18:26:43.000000000 -0500 ++++ gcc-3.4.1/gcc/config/arm/xscale-elf.h 2004-09-02 21:51:15.000000000 -0500 +@@ -49,11 +49,12 @@ + endian, regardless of the endian-ness of the memory + system. */ + +-#define SUBTARGET_EXTRA_ASM_SPEC "%{!mcpu=*:-mcpu=xscale} \ +- %{mhard-float:-mfpu=fpa} \ +- %{!mhard-float: %{msoft-float:-mfpu=softfpa;:-mfpu=softvfp}}" ++#define SUBTARGET_EXTRA_ASM_SPEC "\ ++%{!mcpu=*:-mcpu=xscale} \ ++%{mhard-float:-mfpu=fpa} \ ++%{!mhard-float: %{msoft-float:-mfpu=softfpa} %{!msoft-float:-mfpu=softvfp}}" + + #ifndef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "mlittle-endian", "mno-thumb-interwork", "marm", "msoft-float" } ++ { "mlittle-endian", "mno-thumb-interwork", "marm" } + #endif diff --git a/misc/buildroot/toolchain/gcc/4.0.0/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.0.0/300-libstdc++-pic.patch new file mode 100644 index 000000000..a9d6e7185 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.0/300-libstdc++-pic.patch @@ -0,0 +1,45 @@ +--- gcc-4.0.0/libstdc++-v3/src/Makefile.am ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,10 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc-4.0.0/libstdc++-v3/src/Makefile.in ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.in +@@ -625,7 +625,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -664,7 +664,7 @@ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ +- uninstall-toolexeclibLTLIBRARIES ++ uninstall-toolexeclibLTLIBRARIES install-exec-local + + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@libstdc++-symbol.ver: ${glibcxx_srcdir}/$(SYMVER_MAP) + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@ cp ${glibcxx_srcdir}/$(SYMVER_MAP) ./libstdc++-symbol.ver +@@ -743,6 +743,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.0.0/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.0.0/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.0/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.0.0/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.0.0/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.0/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.0.0/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.0.0/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.0/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.0.0/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/4.0.0/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..c7676ae6a --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.0/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +diff -urN gcc-4.0.0-100/libstdc++-v3/fragment.am gcc-4.0.0/libstdc++-v3/fragment.am +--- gcc-4.0.0-100/libstdc++-v3/fragment.am 2004-10-25 15:32:40.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/fragment.am 2005-04-28 21:48:43.000000000 -0500 +@@ -18,5 +18,5 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + +diff -urN gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am gcc-4.0.0/libstdc++-v3/libmath/Makefile.am +--- gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am 2003-08-27 16:29:42.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/libmath/Makefile.am 2005-04-28 21:48:43.000000000 -0500 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC diff --git a/misc/buildroot/toolchain/gcc/4.0.0/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.0.0/800-arm-bigendian.patch new file mode 100644 index 000000000..307aea3ea --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.0/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.0.3/gcc/config/arm/linux-elf.h ++++ gcc-4.0.3/gcc/config/arm/linux-elf.h +@@ -31,19 +31,33 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* The GNU C++ standard library requires that these macros be defined. */ + #undef CPLUSPLUS_CPP_SPEC +@@ -90,7 +104,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #define TARGET_OS_CPP_BUILTINS() \ +--- gcc-4.0.3/gcc/config.gcc ++++ gcc-4.0.3/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="${tmake_file} arm/t-arm arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/4.0.0/830-gcc-bug-num-22167.patch b/misc/buildroot/toolchain/gcc/4.0.0/830-gcc-bug-num-22167.patch new file mode 100644 index 000000000..c7419af90 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.0/830-gcc-bug-num-22167.patch @@ -0,0 +1,16 @@ +Index: gcc/gcse.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gcse.c,v +retrieving revision 1.288.2.9 +diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.288.2.9 gcse.c +--- gcc/gcc/gcse.c 30 Oct 2004 18:02:53 -0000 1.288.2.9 ++++ gcc/gcc/gcse.c 14 Jul 2005 13:19:57 -0000 +@@ -6445,7 +6445,7 @@ hoist_code (void) + insn_inserted_p = 0; + + /* These tests should be the same as the tests above. */ +- if (TEST_BIT (hoist_vbeout[bb->index], i)) ++ if (TEST_BIT (hoist_exprs[bb->index], i)) + { + /* We've found a potentially hoistable expression, now + we look at every block BB dominates to see if it diff --git a/misc/buildroot/toolchain/gcc/4.0.1/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.0.1/300-libstdc++-pic.patch new file mode 100644 index 000000000..a9d6e7185 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.1/300-libstdc++-pic.patch @@ -0,0 +1,45 @@ +--- gcc-4.0.0/libstdc++-v3/src/Makefile.am ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,10 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc-4.0.0/libstdc++-v3/src/Makefile.in ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.in +@@ -625,7 +625,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -664,7 +664,7 @@ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ +- uninstall-toolexeclibLTLIBRARIES ++ uninstall-toolexeclibLTLIBRARIES install-exec-local + + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@libstdc++-symbol.ver: ${glibcxx_srcdir}/$(SYMVER_MAP) + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@ cp ${glibcxx_srcdir}/$(SYMVER_MAP) ./libstdc++-symbol.ver +@@ -743,6 +743,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.0.1/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.0.1/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.1/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.0.1/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.0.1/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.1/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.0.1/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.0.1/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.1/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.0.1/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/4.0.1/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..c7676ae6a --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.1/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +diff -urN gcc-4.0.0-100/libstdc++-v3/fragment.am gcc-4.0.0/libstdc++-v3/fragment.am +--- gcc-4.0.0-100/libstdc++-v3/fragment.am 2004-10-25 15:32:40.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/fragment.am 2005-04-28 21:48:43.000000000 -0500 +@@ -18,5 +18,5 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + +diff -urN gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am gcc-4.0.0/libstdc++-v3/libmath/Makefile.am +--- gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am 2003-08-27 16:29:42.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/libmath/Makefile.am 2005-04-28 21:48:43.000000000 -0500 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC diff --git a/misc/buildroot/toolchain/gcc/4.0.1/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.0.1/800-arm-bigendian.patch new file mode 100644 index 000000000..307aea3ea --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.1/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.0.3/gcc/config/arm/linux-elf.h ++++ gcc-4.0.3/gcc/config/arm/linux-elf.h +@@ -31,19 +31,33 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* The GNU C++ standard library requires that these macros be defined. */ + #undef CPLUSPLUS_CPP_SPEC +@@ -90,7 +104,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #define TARGET_OS_CPP_BUILTINS() \ +--- gcc-4.0.3/gcc/config.gcc ++++ gcc-4.0.3/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="${tmake_file} arm/t-arm arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/4.0.1/830-gcc-bug-num-22167.patch b/misc/buildroot/toolchain/gcc/4.0.1/830-gcc-bug-num-22167.patch new file mode 100644 index 000000000..c7419af90 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.1/830-gcc-bug-num-22167.patch @@ -0,0 +1,16 @@ +Index: gcc/gcse.c +=================================================================== +RCS file: /cvs/gcc/gcc/gcc/gcse.c,v +retrieving revision 1.288.2.9 +diff -u -p -F^\([(a-zA-Z0-9_]\|#define\) -r1.288.2.9 gcse.c +--- gcc/gcc/gcse.c 30 Oct 2004 18:02:53 -0000 1.288.2.9 ++++ gcc/gcc/gcse.c 14 Jul 2005 13:19:57 -0000 +@@ -6445,7 +6445,7 @@ hoist_code (void) + insn_inserted_p = 0; + + /* These tests should be the same as the tests above. */ +- if (TEST_BIT (hoist_vbeout[bb->index], i)) ++ if (TEST_BIT (hoist_exprs[bb->index], i)) + { + /* We've found a potentially hoistable expression, now + we look at every block BB dominates to see if it diff --git a/misc/buildroot/toolchain/gcc/4.0.2/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.0.2/300-libstdc++-pic.patch new file mode 100644 index 000000000..a9d6e7185 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.2/300-libstdc++-pic.patch @@ -0,0 +1,45 @@ +--- gcc-4.0.0/libstdc++-v3/src/Makefile.am ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,10 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc-4.0.0/libstdc++-v3/src/Makefile.in ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.in +@@ -625,7 +625,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -664,7 +664,7 @@ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ +- uninstall-toolexeclibLTLIBRARIES ++ uninstall-toolexeclibLTLIBRARIES install-exec-local + + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@libstdc++-symbol.ver: ${glibcxx_srcdir}/$(SYMVER_MAP) + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@ cp ${glibcxx_srcdir}/$(SYMVER_MAP) ./libstdc++-symbol.ver +@@ -743,6 +743,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.0.2/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.0.2/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.2/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.0.2/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.0.2/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.2/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.0.2/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.0.2/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.2/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.0.2/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/4.0.2/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..c7676ae6a --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.2/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +diff -urN gcc-4.0.0-100/libstdc++-v3/fragment.am gcc-4.0.0/libstdc++-v3/fragment.am +--- gcc-4.0.0-100/libstdc++-v3/fragment.am 2004-10-25 15:32:40.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/fragment.am 2005-04-28 21:48:43.000000000 -0500 +@@ -18,5 +18,5 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + +diff -urN gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am gcc-4.0.0/libstdc++-v3/libmath/Makefile.am +--- gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am 2003-08-27 16:29:42.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/libmath/Makefile.am 2005-04-28 21:48:43.000000000 -0500 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC diff --git a/misc/buildroot/toolchain/gcc/4.0.2/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.0.2/800-arm-bigendian.patch new file mode 100644 index 000000000..307aea3ea --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.2/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.0.3/gcc/config/arm/linux-elf.h ++++ gcc-4.0.3/gcc/config/arm/linux-elf.h +@@ -31,19 +31,33 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* The GNU C++ standard library requires that these macros be defined. */ + #undef CPLUSPLUS_CPP_SPEC +@@ -90,7 +104,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #define TARGET_OS_CPP_BUILTINS() \ +--- gcc-4.0.3/gcc/config.gcc ++++ gcc-4.0.3/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="${tmake_file} arm/t-arm arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/4.0.3/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.0.3/300-libstdc++-pic.patch new file mode 100644 index 000000000..a9d6e7185 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.3/300-libstdc++-pic.patch @@ -0,0 +1,45 @@ +--- gcc-4.0.0/libstdc++-v3/src/Makefile.am ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,10 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc-4.0.0/libstdc++-v3/src/Makefile.in ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.in +@@ -625,7 +625,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -664,7 +664,7 @@ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ +- uninstall-toolexeclibLTLIBRARIES ++ uninstall-toolexeclibLTLIBRARIES install-exec-local + + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@libstdc++-symbol.ver: ${glibcxx_srcdir}/$(SYMVER_MAP) + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@ cp ${glibcxx_srcdir}/$(SYMVER_MAP) ./libstdc++-symbol.ver +@@ -743,6 +743,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.0.3/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.0.3/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.3/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.0.3/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.0.3/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.3/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.0.3/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.0.3/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.3/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.0.3/304-index_macro.patch b/misc/buildroot/toolchain/gcc/4.0.3/304-index_macro.patch new file mode 100644 index 000000000..1fac112fa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.3/304-index_macro.patch @@ -0,0 +1,24 @@ +--- gcc-4.1.0/libstdc++-v3/include/ext/rope.mps 2006-03-24 01:49:51 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/rope 2006-03-24 01:49:37 +0100 +@@ -59,6 +59,9 @@ + #include + #include + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + # ifdef __GC + # define __GC_CONST const + # else +--- gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h.mps 2006-03-24 01:50:04 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h 2006-03-24 01:50:28 +0100 +@@ -53,6 +53,9 @@ + #include // For uninitialized_copy_n + #include // For power + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + namespace __gnu_cxx + { + using std::size_t; diff --git a/misc/buildroot/toolchain/gcc/4.0.3/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/4.0.3/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..c7676ae6a --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.3/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +diff -urN gcc-4.0.0-100/libstdc++-v3/fragment.am gcc-4.0.0/libstdc++-v3/fragment.am +--- gcc-4.0.0-100/libstdc++-v3/fragment.am 2004-10-25 15:32:40.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/fragment.am 2005-04-28 21:48:43.000000000 -0500 +@@ -18,5 +18,5 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + +diff -urN gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am gcc-4.0.0/libstdc++-v3/libmath/Makefile.am +--- gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am 2003-08-27 16:29:42.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/libmath/Makefile.am 2005-04-28 21:48:43.000000000 -0500 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC diff --git a/misc/buildroot/toolchain/gcc/4.0.3/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.0.3/800-arm-bigendian.patch new file mode 100644 index 000000000..307aea3ea --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.3/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.0.3/gcc/config/arm/linux-elf.h ++++ gcc-4.0.3/gcc/config/arm/linux-elf.h +@@ -31,19 +31,33 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* The GNU C++ standard library requires that these macros be defined. */ + #undef CPLUSPLUS_CPP_SPEC +@@ -90,7 +104,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #define TARGET_OS_CPP_BUILTINS() \ +--- gcc-4.0.3/gcc/config.gcc ++++ gcc-4.0.3/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="${tmake_file} arm/t-arm arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/4.0.4/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.0.4/300-libstdc++-pic.patch new file mode 100644 index 000000000..a9d6e7185 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/300-libstdc++-pic.patch @@ -0,0 +1,45 @@ +--- gcc-4.0.0/libstdc++-v3/src/Makefile.am ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,10 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc-4.0.0/libstdc++-v3/src/Makefile.in ++++ gcc-4.0.0/libstdc++-v3/src/Makefile.in +@@ -625,7 +625,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -664,7 +664,7 @@ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-info-am \ +- uninstall-toolexeclibLTLIBRARIES ++ uninstall-toolexeclibLTLIBRARIES install-exec-local + + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@libstdc++-symbol.ver: ${glibcxx_srcdir}/$(SYMVER_MAP) + @GLIBCXX_BUILD_VERSIONED_SHLIB_TRUE@ cp ${glibcxx_srcdir}/$(SYMVER_MAP) ./libstdc++-symbol.ver +@@ -743,6 +743,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.0.4/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.0.4/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.0.4/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.0.4/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.0.4/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.0.4/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.0.4/304-index_macro.patch b/misc/buildroot/toolchain/gcc/4.0.4/304-index_macro.patch new file mode 100644 index 000000000..1fac112fa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/304-index_macro.patch @@ -0,0 +1,24 @@ +--- gcc-4.1.0/libstdc++-v3/include/ext/rope.mps 2006-03-24 01:49:51 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/rope 2006-03-24 01:49:37 +0100 +@@ -59,6 +59,9 @@ + #include + #include + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + # ifdef __GC + # define __GC_CONST const + # else +--- gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h.mps 2006-03-24 01:50:04 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h 2006-03-24 01:50:28 +0100 +@@ -53,6 +53,9 @@ + #include // For uninitialized_copy_n + #include // For power + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + namespace __gnu_cxx + { + using std::size_t; diff --git a/misc/buildroot/toolchain/gcc/4.0.4/305-libmudflap-susv3-legacy.patch b/misc/buildroot/toolchain/gcc/4.0.4/305-libmudflap-susv3-legacy.patch new file mode 100644 index 000000000..374b1f865 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/305-libmudflap-susv3-legacy.patch @@ -0,0 +1,49 @@ +Index: gcc-4.2/libmudflap/mf-hooks2.c +=================================================================== +--- gcc-4.2/libmudflap/mf-hooks2.c (revision 119834) ++++ gcc-4.2/libmudflap/mf-hooks2.c (working copy) +@@ -427,7 +427,7 @@ + { + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, n, __MF_CHECK_WRITE, "bzero region"); +- bzero (s, n); ++ memset (s, 0, n); + } + + +@@ -437,7 +437,7 @@ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, n, __MF_CHECK_READ, "bcopy src"); + MF_VALIDATE_EXTENT(dest, n, __MF_CHECK_WRITE, "bcopy dest"); +- bcopy (src, dest, n); ++ memmove (dest, src, n); + } + + +@@ -447,7 +447,7 @@ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s1, n, __MF_CHECK_READ, "bcmp 1st arg"); + MF_VALIDATE_EXTENT(s2, n, __MF_CHECK_READ, "bcmp 2nd arg"); +- return bcmp (s1, s2, n); ++ return n == 0 ? 0 : memcmp (s1, s2, n); + } + + +@@ -456,7 +456,7 @@ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "index region"); +- return index (s, c); ++ return strchr (s, c); + } + + +@@ -465,7 +465,7 @@ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "rindex region"); +- return rindex (s, c); ++ return strrchr (s, c); + } + + /* XXX: stpcpy, memccpy */ diff --git a/misc/buildroot/toolchain/gcc/4.0.4/402-libbackend_dep_gcov-iov.h.patch b/misc/buildroot/toolchain/gcc/4.0.4/402-libbackend_dep_gcov-iov.h.patch new file mode 100644 index 000000000..89196d9fa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/402-libbackend_dep_gcov-iov.h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.4.orig/gcc/Makefile.in 2007-02-12 11:35:43.000000000 +0100 ++++ gcc-4.0.4/gcc/Makefile.in 2007-02-12 11:38:04.000000000 +0100 +@@ -2202,7 +2202,7 @@ mips-tdump.o : mips-tdump.c $(CONFIG_H) + # FIXME: writing proper dependencies for this is a *LOT* of work. + libbackend.o : $(OBJS-common:.o=.c) $(out_file) \ + insn-config.h insn-flags.h insn-codes.h insn-constants.h \ +- insn-attr.h ++ insn-attr.h gcov-iov.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + -DTARGET_NAME=\"$(target_noncanonical)\" \ + -DLOCALEDIR=\"$(localedir)\" \ diff --git a/misc/buildroot/toolchain/gcc/4.0.4/602-sdk-libstdc++-includes.patch b/misc/buildroot/toolchain/gcc/4.0.4/602-sdk-libstdc++-includes.patch new file mode 100644 index 000000000..c7676ae6a --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/602-sdk-libstdc++-includes.patch @@ -0,0 +1,22 @@ +diff -urN gcc-4.0.0-100/libstdc++-v3/fragment.am gcc-4.0.0/libstdc++-v3/fragment.am +--- gcc-4.0.0-100/libstdc++-v3/fragment.am 2004-10-25 15:32:40.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/fragment.am 2005-04-28 21:48:43.000000000 -0500 +@@ -18,5 +18,5 @@ + $(WARN_FLAGS) $(WERROR) -fdiagnostics-show-location=once + + # -I/-D flags to pass when compiling. +-AM_CPPFLAGS = $(GLIBCXX_INCLUDES) ++AM_CPPFLAGS = $(GLIBCXX_INCLUDES) -I$(toplevel_srcdir)/include + +diff -urN gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am gcc-4.0.0/libstdc++-v3/libmath/Makefile.am +--- gcc-4.0.0-100/libstdc++-v3/libmath/Makefile.am 2003-08-27 16:29:42.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/libmath/Makefile.am 2005-04-28 21:48:43.000000000 -0500 +@@ -32,7 +32,7 @@ + + libmath_la_SOURCES = stubs.c + +-AM_CPPFLAGS = $(CANADIAN_INCLUDES) ++AM_CPPFLAGS = $(CANADIAN_INCLUDES) -I$(toplevel_srcdir)/include + + # Only compiling "C" sources in this directory. + LIBTOOL = @LIBTOOL@ --tag CC diff --git a/misc/buildroot/toolchain/gcc/4.0.4/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.0.4/800-arm-bigendian.patch new file mode 100644 index 000000000..307aea3ea --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.0.4/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.0.3/gcc/config/arm/linux-elf.h ++++ gcc-4.0.3/gcc/config/arm/linux-elf.h +@@ -31,19 +31,33 @@ + /* Do not assume anything about header files. */ + #define NO_IMPLICIT_EXTERN_C + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT ARM_FLAG_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* The GNU C++ standard library requires that these macros be defined. */ + #undef CPLUSPLUS_CPP_SPEC +@@ -90,7 +104,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker /lib/ld-linux.so.2} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #define TARGET_OS_CPP_BUILTINS() \ +--- gcc-4.0.3/gcc/config.gcc ++++ gcc-4.0.3/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h arm/aout.h arm/arm.h" ++ case $target in ++ arm*b-*) ++ tm_defines="TARGET_BIG_ENDIAN_DEFAULT=1 $tm_defines" ++ ;; ++ esac + tmake_file="${tmake_file} arm/t-arm arm/t-linux" + extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o" + gnu_ld=yes diff --git a/misc/buildroot/toolchain/gcc/4.1.0/110-arm-eabi.patch b/misc/buildroot/toolchain/gcc/4.1.0/110-arm-eabi.patch new file mode 100644 index 000000000..acebe5308 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/110-arm-eabi.patch @@ -0,0 +1,27 @@ +--- gcc-2005q3-1.orig/gcc/config.gcc 2005-10-31 19:02:54.000000000 +0300 ++++ gcc-2005q3-1/gcc/config.gcc 2006-01-27 01:09:09.000000000 +0300 +@@ -674,7 +674,7 @@ + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" + tmake_file="t-slibgcc-elf-ver t-linux arm/t-arm" + case ${target} in +- arm*-*-linux-gnueabi) ++ arm*-*-linux-gnueabi | arm*-*-linux-uclibcgnueabi) + tm_file="$tm_file arm/bpabi.h arm/linux-eabi.h" + tmake_file="$tmake_file arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi" + # The BPABI long long divmod functions return a 128-bit value in + +diff -urN gcc-2005q3-2/gcc/config/arm/linux-eabi.h gcc-2005q3-2.new/gcc/config/arm/linux-eabi.h +--- gcc-2005q3-2/gcc/config/arm/linux-eabi.h 2005-12-07 23:14:16.000000000 +0300 ++++ gcc-2005q3-2.new/gcc/config/arm/linux-eabi.h 2006-03-29 19:02:34.000000000 +0400 +@@ -53,7 +53,11 @@ + /* Use ld-linux.so.3 so that it will be possible to run "classic" + GNU/Linux binaries on an EABI system. */ + #undef LINUX_TARGET_INTERPRETER ++#ifdef USE_UCLIBC ++#define LINUX_TARGET_INTERPRETER "/lib/ld-uClibc.so.0" ++#else + #define LINUX_TARGET_INTERPRETER "/lib/ld-linux.so.3" ++#endif + + /* At this point, bpabi.h will have clobbered LINK_SPEC. We want to + use the GNU/Linux version, not the generic BPABI version. */ diff --git a/misc/buildroot/toolchain/gcc/4.1.0/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.1.0/300-libstdc++-pic.patch new file mode 100644 index 000000000..7b93855eb --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/300-libstdc++-pic.patch @@ -0,0 +1,46 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc-4.1.0/libstdc++-v3/src/Makefile.am ++++ gcc-4.1.0/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,10 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc-4.1.0/libstdc++-v3/src/Makefile.in ++++ gcc-4.1.0/libstdc++-v3/src/Makefile.in +@@ -627,7 +627,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -660,6 +660,7 @@ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-data-local install-exec \ ++ install-exec-local \ + install-exec-am install-info install-info-am install-man \ + install-strip install-toolexeclibLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ +@@ -745,6 +746,11 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.1.0/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.1.0/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.1.0/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.1.0/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.1.0/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.1.0/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.1.0/304-index_macro.patch b/misc/buildroot/toolchain/gcc/4.1.0/304-index_macro.patch new file mode 100644 index 000000000..1fac112fa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/304-index_macro.patch @@ -0,0 +1,24 @@ +--- gcc-4.1.0/libstdc++-v3/include/ext/rope.mps 2006-03-24 01:49:51 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/rope 2006-03-24 01:49:37 +0100 +@@ -59,6 +59,9 @@ + #include + #include + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + # ifdef __GC + # define __GC_CONST const + # else +--- gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h.mps 2006-03-24 01:50:04 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h 2006-03-24 01:50:28 +0100 +@@ -53,6 +53,9 @@ + #include // For uninitialized_copy_n + #include // For power + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + namespace __gnu_cxx + { + using std::size_t; diff --git a/misc/buildroot/toolchain/gcc/4.1.0/740-sh-pr24836.patch b/misc/buildroot/toolchain/gcc/4.1.0/740-sh-pr24836.patch new file mode 100644 index 000000000..7992282cf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/740-sh-pr24836.patch @@ -0,0 +1,25 @@ +http://sourceforge.net/mailarchive/forum.php?thread_id=8959304&forum_id=5348 +http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24836 + +--- gcc/gcc/configure.ac (revision 106699) ++++ gcc/gcc/configure.ac (working copy) +@@ -2446,7 +2446,7 @@ + tls_first_minor=14 + tls_as_opt="-m64 -Aesame --fatal-warnings" + ;; +- sh-*-* | sh[34]-*-*) ++ sh-*-* | sh[34]*-*-*) + conftest_s=' + .section ".tdata","awT",@progbits + foo: .long 25 +--- gcc/gcc/configure ++++ gcc/gcc/configure +@@ -14846,7 +14846,7 @@ + tls_first_minor=14 + tls_as_opt="-m64 -Aesame --fatal-warnings" + ;; +- sh-*-* | sh[34]-*-*) ++ sh-*-* | sh[34]*-*-*) + conftest_s=' + .section ".tdata","awT",@progbits + foo: .long 25 diff --git a/misc/buildroot/toolchain/gcc/4.1.0/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.1.0/800-arm-bigendian.patch new file mode 100644 index 000000000..1fa5ae1cd --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.0/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.1.0/gcc/config/arm/linux-elf.h ++++ gcc-4.1.0/gcc/config/arm/linux-elf.h +@@ -28,19 +28,33 @@ + #undef TARGET_VERSION + #define TARGET_VERSION fputs (" (ARM GNU/Linux with ELF)", stderr); + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT MASK_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* Now we define the strings used to build the spec file. */ + #undef LIB_SPEC +@@ -61,7 +75,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker " LINUX_TARGET_INTERPRETER "} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #undef LINK_SPEC +--- gcc-4.1.0/gcc/config.gcc ++++ gcc-4.1.0/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" ++ case $target in ++ arm*b-*) ++ tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" ++ ;; ++ esac + tmake_file="${tmake_file} t-linux arm/t-arm" + case ${target} in + arm*-*-linux-gnueabi) diff --git a/misc/buildroot/toolchain/gcc/4.1.1/110-arm-eabi.patch b/misc/buildroot/toolchain/gcc/4.1.1/110-arm-eabi.patch new file mode 100644 index 000000000..acebe5308 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/110-arm-eabi.patch @@ -0,0 +1,27 @@ +--- gcc-2005q3-1.orig/gcc/config.gcc 2005-10-31 19:02:54.000000000 +0300 ++++ gcc-2005q3-1/gcc/config.gcc 2006-01-27 01:09:09.000000000 +0300 +@@ -674,7 +674,7 @@ + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" + tmake_file="t-slibgcc-elf-ver t-linux arm/t-arm" + case ${target} in +- arm*-*-linux-gnueabi) ++ arm*-*-linux-gnueabi | arm*-*-linux-uclibcgnueabi) + tm_file="$tm_file arm/bpabi.h arm/linux-eabi.h" + tmake_file="$tmake_file arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi" + # The BPABI long long divmod functions return a 128-bit value in + +diff -urN gcc-2005q3-2/gcc/config/arm/linux-eabi.h gcc-2005q3-2.new/gcc/config/arm/linux-eabi.h +--- gcc-2005q3-2/gcc/config/arm/linux-eabi.h 2005-12-07 23:14:16.000000000 +0300 ++++ gcc-2005q3-2.new/gcc/config/arm/linux-eabi.h 2006-03-29 19:02:34.000000000 +0400 +@@ -53,7 +53,11 @@ + /* Use ld-linux.so.3 so that it will be possible to run "classic" + GNU/Linux binaries on an EABI system. */ + #undef LINUX_TARGET_INTERPRETER ++#ifdef USE_UCLIBC ++#define LINUX_TARGET_INTERPRETER "/lib/ld-uClibc.so.0" ++#else + #define LINUX_TARGET_INTERPRETER "/lib/ld-linux.so.3" ++#endif + + /* At this point, bpabi.h will have clobbered LINK_SPEC. We want to + use the GNU/Linux version, not the generic BPABI version. */ diff --git a/misc/buildroot/toolchain/gcc/4.1.1/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.1.1/300-libstdc++-pic.patch new file mode 100644 index 000000000..560bcb237 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/300-libstdc++-pic.patch @@ -0,0 +1,50 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,12 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ifeq ($(enable_shared),yes) ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++endif ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -627,7 +627,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -660,6 +660,7 @@ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-data-local install-exec \ ++ install-exec-local \ + install-exec-am install-info install-info-am install-man \ + install-strip install-toolexeclibLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ +@@ -743,6 +743,13 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ifeq ($(enable_shared),yes) ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++endif ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.1.1/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.1.1/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.1.1/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.1.1/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.1.1/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.1.1/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.1.1/304-index_macro.patch b/misc/buildroot/toolchain/gcc/4.1.1/304-index_macro.patch new file mode 100644 index 000000000..1fac112fa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/304-index_macro.patch @@ -0,0 +1,24 @@ +--- gcc-4.1.0/libstdc++-v3/include/ext/rope.mps 2006-03-24 01:49:51 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/rope 2006-03-24 01:49:37 +0100 +@@ -59,6 +59,9 @@ + #include + #include + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + # ifdef __GC + # define __GC_CONST const + # else +--- gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h.mps 2006-03-24 01:50:04 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h 2006-03-24 01:50:28 +0100 +@@ -53,6 +53,9 @@ + #include // For uninitialized_copy_n + #include // For power + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + namespace __gnu_cxx + { + using std::size_t; diff --git a/misc/buildroot/toolchain/gcc/4.1.1/740-sh-pr24836.patch b/misc/buildroot/toolchain/gcc/4.1.1/740-sh-pr24836.patch new file mode 100644 index 000000000..7992282cf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/740-sh-pr24836.patch @@ -0,0 +1,25 @@ +http://sourceforge.net/mailarchive/forum.php?thread_id=8959304&forum_id=5348 +http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24836 + +--- gcc/gcc/configure.ac (revision 106699) ++++ gcc/gcc/configure.ac (working copy) +@@ -2446,7 +2446,7 @@ + tls_first_minor=14 + tls_as_opt="-m64 -Aesame --fatal-warnings" + ;; +- sh-*-* | sh[34]-*-*) ++ sh-*-* | sh[34]*-*-*) + conftest_s=' + .section ".tdata","awT",@progbits + foo: .long 25 +--- gcc/gcc/configure ++++ gcc/gcc/configure +@@ -14846,7 +14846,7 @@ + tls_first_minor=14 + tls_as_opt="-m64 -Aesame --fatal-warnings" + ;; +- sh-*-* | sh[34]-*-*) ++ sh-*-* | sh[34]*-*-*) + conftest_s=' + .section ".tdata","awT",@progbits + foo: .long 25 diff --git a/misc/buildroot/toolchain/gcc/4.1.1/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.1.1/800-arm-bigendian.patch new file mode 100644 index 000000000..1fa5ae1cd --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.1/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.1.0/gcc/config/arm/linux-elf.h ++++ gcc-4.1.0/gcc/config/arm/linux-elf.h +@@ -28,19 +28,33 @@ + #undef TARGET_VERSION + #define TARGET_VERSION fputs (" (ARM GNU/Linux with ELF)", stderr); + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT MASK_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* Now we define the strings used to build the spec file. */ + #undef LIB_SPEC +@@ -61,7 +75,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker " LINUX_TARGET_INTERPRETER "} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #undef LINK_SPEC +--- gcc-4.1.0/gcc/config.gcc ++++ gcc-4.1.0/gcc/config.gcc +@@ -672,6 +672,11 @@ + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" ++ case $target in ++ arm*b-*) ++ tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" ++ ;; ++ esac + tmake_file="${tmake_file} t-linux arm/t-arm" + case ${target} in + arm*-*-linux-gnueabi) diff --git a/misc/buildroot/toolchain/gcc/4.1.2/110-arm-eabi.patch b/misc/buildroot/toolchain/gcc/4.1.2/110-arm-eabi.patch new file mode 100644 index 000000000..acebe5308 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/110-arm-eabi.patch @@ -0,0 +1,27 @@ +--- gcc-2005q3-1.orig/gcc/config.gcc 2005-10-31 19:02:54.000000000 +0300 ++++ gcc-2005q3-1/gcc/config.gcc 2006-01-27 01:09:09.000000000 +0300 +@@ -674,7 +674,7 @@ + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" + tmake_file="t-slibgcc-elf-ver t-linux arm/t-arm" + case ${target} in +- arm*-*-linux-gnueabi) ++ arm*-*-linux-gnueabi | arm*-*-linux-uclibcgnueabi) + tm_file="$tm_file arm/bpabi.h arm/linux-eabi.h" + tmake_file="$tmake_file arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi" + # The BPABI long long divmod functions return a 128-bit value in + +diff -urN gcc-2005q3-2/gcc/config/arm/linux-eabi.h gcc-2005q3-2.new/gcc/config/arm/linux-eabi.h +--- gcc-2005q3-2/gcc/config/arm/linux-eabi.h 2005-12-07 23:14:16.000000000 +0300 ++++ gcc-2005q3-2.new/gcc/config/arm/linux-eabi.h 2006-03-29 19:02:34.000000000 +0400 +@@ -53,7 +53,11 @@ + /* Use ld-linux.so.3 so that it will be possible to run "classic" + GNU/Linux binaries on an EABI system. */ + #undef LINUX_TARGET_INTERPRETER ++#ifdef USE_UCLIBC ++#define LINUX_TARGET_INTERPRETER "/lib/ld-uClibc.so.0" ++#else + #define LINUX_TARGET_INTERPRETER "/lib/ld-linux.so.3" ++#endif + + /* At this point, bpabi.h will have clobbered LINK_SPEC. We want to + use the GNU/Linux version, not the generic BPABI version. */ diff --git a/misc/buildroot/toolchain/gcc/4.1.2/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.1.2/300-libstdc++-pic.patch new file mode 100644 index 000000000..560bcb237 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/300-libstdc++-pic.patch @@ -0,0 +1,50 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,12 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ifeq ($(enable_shared),yes) ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++endif ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -627,7 +627,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -660,6 +660,7 @@ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-data-local install-exec \ ++ install-exec-local \ + install-exec-am install-info install-info-am install-man \ + install-strip install-toolexeclibLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ +@@ -743,6 +743,13 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ifeq ($(enable_shared),yes) ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++endif ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.1.2/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.1.2/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.1.2/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.1.2/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.1.2/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.1.2/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.1.2/304-index_macro.patch b/misc/buildroot/toolchain/gcc/4.1.2/304-index_macro.patch new file mode 100644 index 000000000..1fac112fa --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/304-index_macro.patch @@ -0,0 +1,24 @@ +--- gcc-4.1.0/libstdc++-v3/include/ext/rope.mps 2006-03-24 01:49:51 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/rope 2006-03-24 01:49:37 +0100 +@@ -59,6 +59,9 @@ + #include + #include + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + # ifdef __GC + # define __GC_CONST const + # else +--- gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h.mps 2006-03-24 01:50:04 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h 2006-03-24 01:50:28 +0100 +@@ -53,6 +53,9 @@ + #include // For uninitialized_copy_n + #include // For power + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + namespace __gnu_cxx + { + using std::size_t; diff --git a/misc/buildroot/toolchain/gcc/4.1.2/402-libbackend_dep_gcov-iov.h.patch b/misc/buildroot/toolchain/gcc/4.1.2/402-libbackend_dep_gcov-iov.h.patch new file mode 100644 index 000000000..b7d9bb993 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/402-libbackend_dep_gcov-iov.h.patch @@ -0,0 +1,12 @@ +# gcc.gnu.org/PR30620 +--- gcc-4.1.2-20070208.orig/gcc/Makefile.in 2006-11-01 15:40:44.000000000 +0100 ++++ gcc-4.1.2-20070208/gcc/Makefile.in 2007-02-13 19:23:31.000000000 +0100 +@@ -2522,7 +2522,7 @@ + # FIXME: writing proper dependencies for this is a *LOT* of work. + libbackend.o : $(OBJS-common:.o=.c) $(out_file) \ + insn-config.h insn-flags.h insn-codes.h insn-constants.h \ +- insn-attr.h $(DATESTAMP) $(BASEVER) $(DEVPHASE) ++ insn-attr.h $(DATESTAMP) $(BASEVER) $(DEVPHASE) gcov-iov.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + -DTARGET_NAME=\"$(target_noncanonical)\" \ + -DLOCALEDIR=\"$(localedir)\" \ diff --git a/misc/buildroot/toolchain/gcc/4.1.2/740-sh-pr24836.patch b/misc/buildroot/toolchain/gcc/4.1.2/740-sh-pr24836.patch new file mode 100644 index 000000000..7992282cf --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/740-sh-pr24836.patch @@ -0,0 +1,25 @@ +http://sourceforge.net/mailarchive/forum.php?thread_id=8959304&forum_id=5348 +http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24836 + +--- gcc/gcc/configure.ac (revision 106699) ++++ gcc/gcc/configure.ac (working copy) +@@ -2446,7 +2446,7 @@ + tls_first_minor=14 + tls_as_opt="-m64 -Aesame --fatal-warnings" + ;; +- sh-*-* | sh[34]-*-*) ++ sh-*-* | sh[34]*-*-*) + conftest_s=' + .section ".tdata","awT",@progbits + foo: .long 25 +--- gcc/gcc/configure ++++ gcc/gcc/configure +@@ -14846,7 +14846,7 @@ + tls_first_minor=14 + tls_as_opt="-m64 -Aesame --fatal-warnings" + ;; +- sh-*-* | sh[34]-*-*) ++ sh-*-* | sh[34]*-*-*) + conftest_s=' + .section ".tdata","awT",@progbits + foo: .long 25 diff --git a/misc/buildroot/toolchain/gcc/4.1.2/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.1.2/800-arm-bigendian.patch new file mode 100644 index 000000000..0a9417419 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.1.2/800-arm-bigendian.patch @@ -0,0 +1,127 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +Index: gcc-4.1.1/gcc/config/arm/linux-elf.h +=================================================================== +--- gcc-4.1.1.orig/gcc/config/arm/linux-elf.h ++++ gcc-4.1.1/gcc/config/arm/linux-elf.h +@@ -28,19 +28,33 @@ + #undef TARGET_VERSION + #define TARGET_VERSION fputs (" (ARM GNU/Linux with ELF)", stderr); + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT MASK_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* Now we define the strings used to build the spec file. */ + #undef LIB_SPEC +@@ -61,7 +75,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker " LINUX_TARGET_INTERPRETER "} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #undef LINK_SPEC +Index: gcc-4.1.1/gcc/config.gcc +=================================================================== +--- gcc-4.1.1.orig/gcc/config.gcc ++++ gcc-4.1.1/gcc/config.gcc +@@ -672,6 +672,11 @@ arm*-*-netbsd*) + ;; + arm*-*-linux*) # ARM GNU/Linux with ELF + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" ++ case $target in ++ arm*b-*) ++ tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" ++ ;; ++ esac + tmake_file="${tmake_file} t-linux arm/t-arm" + case ${target} in + arm*-*-linux-gnueabi) +Index: gcc-4.1.1/gcc/config/arm/linux-eabi.h +=================================================================== +--- gcc-4.1.1.orig/gcc/config/arm/linux-eabi.h ++++ gcc-4.1.1/gcc/config/arm/linux-eabi.h +@@ -20,6 +20,17 @@ + the Free Software Foundation, 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. */ + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#undef TARGET_LINKER_EMULATION ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_LINKER_EMULATION "armelfb_linux_eabi" ++#else ++#define TARGET_LINKER_EMULATION "armelf_linux_eabi" ++#endif ++ + /* On EABI GNU/Linux, we want both the BPABI builtins and the + GNU/Linux builtins. */ + #undef TARGET_OS_CPP_BUILTINS +@@ -48,7 +59,7 @@ + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm10tdmi + + #undef SUBTARGET_EXTRA_LINK_SPEC +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux_eabi" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION + + /* Use ld-linux.so.3 so that it will be possible to run "classic" + GNU/Linux binaries on an EABI system. */ +Index: gcc-4.1.1/gcc/config/arm/bpabi.h +=================================================================== +--- gcc-4.1.1.orig/gcc/config/arm/bpabi.h ++++ gcc-4.1.1/gcc/config/arm/bpabi.h +@@ -33,9 +33,19 @@ + #undef FPUTYPE_DEFAULT + #define FPUTYPE_DEFAULT FPUTYPE_VFP + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT MASK_BIG_END ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#endif ++ + /* EABI targets should enable interworking by default. */ + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT MASK_INTERWORK ++#define TARGET_DEFAULT (MASK_INTERWORK | TARGET_ENDIAN_DEFAULT) + + /* The ARM BPABI functions return a boolean; they use no special + calling convention. */ diff --git a/misc/buildroot/toolchain/gcc/4.2/300-libstdc++-pic.patch b/misc/buildroot/toolchain/gcc/4.2/300-libstdc++-pic.patch new file mode 100644 index 000000000..560bcb237 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/300-libstdc++-pic.patch @@ -0,0 +1,50 @@ +# DP: Build and install libstdc++_pic.a library. + +--- gcc/libstdc++-v3/src/Makefile.am ++++ gcc/libstdc++-v3/src/Makefile.am +@@ -214,6 +214,12 @@ + $(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LDFLAGS) -o $@ + + ++install-exec-local: ++ifeq ($(enable_shared),yes) ++ $(AR) cru libstdc++_pic.a .libs/*.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++endif ++ + # Added bits to build debug library. + if GLIBCXX_BUILD_DEBUG + all-local: build_debug +--- gcc/libstdc++-v3/src/Makefile.in ++++ gcc/libstdc++-v3/src/Makefile.in +@@ -627,7 +627,7 @@ + + install-data-am: install-data-local + +-install-exec-am: install-toolexeclibLTLIBRARIES ++install-exec-am: install-toolexeclibLTLIBRARIES install-exec-local + + install-info: install-info-am + +@@ -660,6 +660,7 @@ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-data-local install-exec \ ++ install-exec-local \ + install-exec-am install-info install-info-am install-man \ + install-strip install-toolexeclibLTLIBRARIES installcheck \ + installcheck-am installdirs maintainer-clean \ +@@ -743,6 +743,13 @@ + install_debug: + (cd ${debugdir} && $(MAKE) \ + toolexeclibdir=$(glibcxx_toolexeclibdir)/debug install) ++ ++install-exec-local: ++ifeq ($(enable_shared),yes) ++ $(AR) cru libstdc++_pic.a *.o $(top_builddir)/libsupc++/*.o ++ $(INSTALL_DATA) libstdc++_pic.a $(DESTDIR)$(toolexeclibdir) ++endif ++ + # Tell versions [3.59,3.63) of GNU make to not export all variables. + # Otherwise a system limit (for SysV at least) may be exceeded. + .NOEXPORT: diff --git a/misc/buildroot/toolchain/gcc/4.2/301-missing-execinfo_h.patch b/misc/buildroot/toolchain/gcc/4.2/301-missing-execinfo_h.patch new file mode 100644 index 000000000..0e2092f3f --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/301-missing-execinfo_h.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/boehm-gc/include/gc.h-orig 2005-04-28 22:28:57.000000000 -0500 ++++ gcc-4.0.0/boehm-gc/include/gc.h 2005-04-28 22:30:38.000000000 -0500 +@@ -500,7 +500,7 @@ + #ifdef __linux__ + # include + # if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \ +- && !defined(__ia64__) ++ && !defined(__ia64__) && !defined(__UCLIBC__) + # ifndef GC_HAVE_BUILTIN_BACKTRACE + # define GC_HAVE_BUILTIN_BACKTRACE + # endif diff --git a/misc/buildroot/toolchain/gcc/4.2/302-c99-snprintf.patch b/misc/buildroot/toolchain/gcc/4.2/302-c99-snprintf.patch new file mode 100644 index 000000000..dfb22d681 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/302-c99-snprintf.patch @@ -0,0 +1,11 @@ +--- gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h-orig 2005-04-29 00:08:41.000000000 -0500 ++++ gcc-4.0.0/libstdc++-v3/include/c_std/std_cstdio.h 2005-04-29 00:08:45.000000000 -0500 +@@ -142,7 +142,7 @@ + using ::vsprintf; + } + +-#if _GLIBCXX_USE_C99 ++#if _GLIBCXX_USE_C99 || defined(__UCLIBC__) + + #undef snprintf + #undef vfscanf diff --git a/misc/buildroot/toolchain/gcc/4.2/303-c99-complex-ugly-hack.patch b/misc/buildroot/toolchain/gcc/4.2/303-c99-complex-ugly-hack.patch new file mode 100644 index 000000000..2ccc80d9b --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/303-c99-complex-ugly-hack.patch @@ -0,0 +1,12 @@ +--- gcc-4.0.0/libstdc++-v3/configure-old 2005-04-30 22:04:48.061603912 -0500 ++++ gcc-4.0.0/libstdc++-v3/configure 2005-04-30 22:06:13.678588152 -0500 +@@ -7194,6 +7194,9 @@ + cat >>conftest.$ac_ext <<_ACEOF + /* end confdefs.h. */ + #include ++#ifdef __UCLIBC__ ++#error ugly hack to make sure configure test fails here for cross until uClibc supports the complex funcs ++#endif + int + main () + { diff --git a/misc/buildroot/toolchain/gcc/4.2/304-index_macro.patch b/misc/buildroot/toolchain/gcc/4.2/304-index_macro.patch new file mode 100644 index 000000000..d8e476555 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/304-index_macro.patch @@ -0,0 +1,24 @@ +--- gcc-4.1.0/libstdc++-v3/include/ext/rope.mps 2006-03-24 01:49:51 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/rope 2006-03-24 01:49:37 +0100 +@@ -59,6 +59,9 @@ + #include + #include + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + # ifdef __GC + # define __GC_CONST const + # else +--- gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h.mps 2006-03-24 01:50:04 +0100 ++++ gcc-4.1.0/libstdc++-v3/include/ext/ropeimpl.h 2006-03-24 01:50:28 +0100 +@@ -53,6 +53,9 @@ + #include // For uninitialized_copy_n + #include // For power + ++/* cope w/ index defined as macro, SuSv3 proposal */ ++#undef index ++ + _GLIBCXX_BEGIN_NAMESPACE(__gnu_cxx) + + using std::size_t; diff --git a/misc/buildroot/toolchain/gcc/4.2/305-libmudflap-susv3-legacy.patch b/misc/buildroot/toolchain/gcc/4.2/305-libmudflap-susv3-legacy.patch new file mode 100644 index 000000000..374b1f865 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/305-libmudflap-susv3-legacy.patch @@ -0,0 +1,49 @@ +Index: gcc-4.2/libmudflap/mf-hooks2.c +=================================================================== +--- gcc-4.2/libmudflap/mf-hooks2.c (revision 119834) ++++ gcc-4.2/libmudflap/mf-hooks2.c (working copy) +@@ -427,7 +427,7 @@ + { + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, n, __MF_CHECK_WRITE, "bzero region"); +- bzero (s, n); ++ memset (s, 0, n); + } + + +@@ -437,7 +437,7 @@ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(src, n, __MF_CHECK_READ, "bcopy src"); + MF_VALIDATE_EXTENT(dest, n, __MF_CHECK_WRITE, "bcopy dest"); +- bcopy (src, dest, n); ++ memmove (dest, src, n); + } + + +@@ -447,7 +447,7 @@ + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s1, n, __MF_CHECK_READ, "bcmp 1st arg"); + MF_VALIDATE_EXTENT(s2, n, __MF_CHECK_READ, "bcmp 2nd arg"); +- return bcmp (s1, s2, n); ++ return n == 0 ? 0 : memcmp (s1, s2, n); + } + + +@@ -456,7 +456,7 @@ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "index region"); +- return index (s, c); ++ return strchr (s, c); + } + + +@@ -465,7 +465,7 @@ + size_t n = strlen (s); + TRACE ("%s\n", __PRETTY_FUNCTION__); + MF_VALIDATE_EXTENT(s, CLAMPADD(n, 1), __MF_CHECK_READ, "rindex region"); +- return rindex (s, c); ++ return strrchr (s, c); + } + + /* XXX: stpcpy, memccpy */ diff --git a/misc/buildroot/toolchain/gcc/4.2/306-libstdc++-namespace.patch b/misc/buildroot/toolchain/gcc/4.2/306-libstdc++-namespace.patch new file mode 100644 index 000000000..69587ca63 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/306-libstdc++-namespace.patch @@ -0,0 +1,36 @@ +diff -rup gcc-4.2.orig/libstdc++-v3/config/locale/uclibc/messages_members.h gcc-4.2/libstdc++-v3/config/locale/uclibc/messages_members.h +--- gcc-4.2.orig/libstdc++-v3/config/locale/uclibc/messages_members.h 2006-12-22 13:06:56.000000000 +0100 ++++ gcc-4.2/libstdc++-v3/config/locale/uclibc/messages_members.h 2006-12-22 15:23:41.000000000 +0100 +@@ -32,7 +32,8 @@ + // + + // Written by Benjamin Kosnik +- ++namespace std ++{ + #ifdef __UCLIBC_MJN3_ONLY__ + #warning fix prototypes for *textdomain funcs + #endif +@@ -115,3 +116,4 @@ + this->_S_create_c_locale(this->_M_c_locale_messages, __s); + } + } ++} +diff -rup gcc-4.2.orig/libstdc++-v3/config/locale/uclibc/time_members.h gcc-4.2/libstdc++-v3/config/locale/uclibc/time_members.h +--- gcc-4.2.orig/libstdc++-v3/config/locale/uclibc/time_members.h 2006-12-22 13:06:56.000000000 +0100 ++++ gcc-4.2/libstdc++-v3/config/locale/uclibc/time_members.h 2006-12-22 15:20:31.000000000 +0100 +@@ -33,7 +33,8 @@ + // + + // Written by Benjamin Kosnik +- ++namespace std ++{ + template + __timepunct<_CharT>::__timepunct(size_t __refs) + : facet(__refs), _M_data(NULL), _M_c_locale_timepunct(NULL), +@@ -74,3 +75,4 @@ + delete _M_data; + _S_destroy_c_locale(_M_c_locale_timepunct); + } ++} diff --git a/misc/buildroot/toolchain/gcc/4.2/402-libbackend_dep_gcov-iov.h.patch b/misc/buildroot/toolchain/gcc/4.2/402-libbackend_dep_gcov-iov.h.patch new file mode 100644 index 000000000..0bf115c45 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/402-libbackend_dep_gcov-iov.h.patch @@ -0,0 +1,13 @@ +Index: gcc-4.2/gcc/Makefile.in +=================================================================== +--- gcc-4.2/gcc/Makefile.in (revision 121758) ++++ gcc-4.2/gcc/Makefile.in (working copy) +@@ -2658,7 +2658,7 @@ mips-tdump.o : mips-tdump.c $(CONFIG_H) + # FIXME: writing proper dependencies for this is a *LOT* of work. + libbackend.o : $(OBJS-common:.o=.c) $(out_file) \ + insn-config.h insn-flags.h insn-codes.h insn-constants.h \ +- insn-attr.h $(DATESTAMP) $(BASEVER) $(DEVPHASE) ++ insn-attr.h $(DATESTAMP) $(BASEVER) $(DEVPHASE) gcov-iov.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + -DTARGET_NAME=\"$(target_noncanonical)\" \ + -DLOCALEDIR=\"$(localedir)\" \ diff --git a/misc/buildroot/toolchain/gcc/4.2/800-arm-bigendian.patch b/misc/buildroot/toolchain/gcc/4.2/800-arm-bigendian.patch new file mode 100644 index 000000000..07c609337 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/4.2/800-arm-bigendian.patch @@ -0,0 +1,67 @@ +By Lennert Buytenhek +Adds support for arm*b-linux* big-endian ARM targets + +See http://gcc.gnu.org/PR16350 + +--- gcc-4.2.0/gcc/config/arm/linux-elf.h ++++ gcc-4.2.0/gcc/config/arm/linux-elf.h +@@ -28,19 +28,33 @@ + #undef TARGET_VERSION + #define TARGET_VERSION fputs (" (ARM GNU/Linux with ELF)", stderr); + ++/* ++ * 'config.gcc' defines TARGET_BIG_ENDIAN_DEFAULT as 1 for arm*b-* ++ * (big endian) configurations. ++ */ ++#if TARGET_BIG_ENDIAN_DEFAULT ++#define TARGET_ENDIAN_DEFAULT MASK_BIG_END ++#define TARGET_ENDIAN_OPTION "mbig-endian" ++#define TARGET_LINKER_EMULATION "armelfb_linux" ++#else ++#define TARGET_ENDIAN_DEFAULT 0 ++#define TARGET_ENDIAN_OPTION "mlittle-endian" ++#define TARGET_LINKER_EMULATION "armelf_linux" ++#endif ++ + #undef TARGET_DEFAULT_FLOAT_ABI + #define TARGET_DEFAULT_FLOAT_ABI ARM_FLOAT_ABI_HARD + + #undef TARGET_DEFAULT +-#define TARGET_DEFAULT (0) ++#define TARGET_DEFAULT (TARGET_ENDIAN_DEFAULT) + + #define SUBTARGET_CPU_DEFAULT TARGET_CPU_arm6 + +-#define SUBTARGET_EXTRA_LINK_SPEC " -m armelf_linux -p" ++#define SUBTARGET_EXTRA_LINK_SPEC " -m " TARGET_LINKER_EMULATION " -p" + + #undef MULTILIB_DEFAULTS + #define MULTILIB_DEFAULTS \ +- { "marm", "mlittle-endian", "mhard-float", "mno-thumb-interwork" } ++ { "marm", TARGET_ENDIAN_OPTION, "mhard-float", "mno-thumb-interwork" } + + /* Now we define the strings used to build the spec file. */ + #undef LIB_SPEC +@@ -61,7 +75,7 @@ + %{rdynamic:-export-dynamic} \ + %{!dynamic-linker:-dynamic-linker " LINUX_DYNAMIC_LINKER "} \ + -X \ +- %{mbig-endian:-EB}" \ ++ %{mbig-endian:-EB} %{mlittle-endian:-EL}" \ + SUBTARGET_EXTRA_LINK_SPEC + + #undef LINK_SPEC +--- gcc-4.2.0/gcc/config.gcc.orig 2006-09-22 14:53:41.000000000 +0200 ++++ gcc-4.2.0/gcc/config.gcc 2006-09-25 10:45:21.000000000 +0200 +@@ -696,6 +696,11 @@ + tm_file="dbxelf.h elfos.h linux.h arm/elf.h arm/linux-gas.h arm/linux-elf.h" + tmake_file="${tmake_file} t-linux arm/t-arm" + case ${target} in ++ arm*b-*) ++ tm_defines="${tm_defines} TARGET_BIG_ENDIAN_DEFAULT=1" ++ ;; ++ esac ++ case ${target} in + arm*-*-linux-*eabi) + tm_file="$tm_file arm/bpabi.h arm/linux-eabi.h" + tmake_file="$tmake_file arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi" diff --git a/misc/buildroot/toolchain/gcc/Config.in b/misc/buildroot/toolchain/gcc/Config.in new file mode 100644 index 000000000..898638fce --- /dev/null +++ b/misc/buildroot/toolchain/gcc/Config.in @@ -0,0 +1,153 @@ +# Choose gcc version. + +comment "Gcc Options" + +choice + prompt "GCC compiler Version" + default BR2_GCC_VERSION_3_4_6 + help + Select the version of gcc you wish to use. + + config BR2_GCC_VERSION_3_3_5 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 3.3.5" + + config BR2_GCC_VERSION_3_3_6 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 3.3.6" + + config BR2_GCC_VERSION_3_4_2 + depends BR2_DEPRECATED + bool "gcc 3.4.2" + + config BR2_GCC_VERSION_3_4_3 + depends BR2_DEPRECATED + bool "gcc 3.4.3" + + config BR2_GCC_VERSION_3_4_4 + depends BR2_DEPRECATED + bool "gcc 3.4.4" + + config BR2_GCC_VERSION_3_4_5 + depends BR2_DEPRECATED + bool "gcc 3.4.5" + + config BR2_GCC_VERSION_3_4_6 + bool "gcc 3.4.6" + + config BR2_GCC_VERSION_4_0_0 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 4.0.0" + + config BR2_GCC_VERSION_4_0_1 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 4.0.1" + + config BR2_GCC_VERSION_4_0_2 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 4.0.2" + + config BR2_GCC_VERSION_4_0_3 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 4.0.3" + + config BR2_GCC_VERSION_4_0_4 + depends !BR2_nios2 + bool "gcc 4.0.4" + + config BR2_GCC_VERSION_4_1_0 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 4.1.0" + + config BR2_GCC_VERSION_4_1_1 + depends !BR2_nios2 && BR2_DEPRECATED + bool "gcc 4.1.1" + + config BR2_GCC_VERSION_4_1_2 + depends !BR2_nios2 + bool "gcc 4.1.2" + + config BR2_GCC_VERSION_4_2 + depends !BR2_nios2 + select BR2_GCC_IS_SNAP + bool "gcc 4.2" + +endchoice + +config BR2_GCC_IS_SNAP + bool + default n + +config BR2_GCC_SNAP_DATE + string "GCC snapshot date" + default "20061121" + depends BR2_GCC_IS_SNAP + help + Enter snapshot date to use for gcc. Format is: + YYYYMMDD + +config BR2_GCC_VERSION + string + default "3.3.5" if BR2_GCC_VERSION_3_3_5 + default "3.3.6" if BR2_GCC_VERSION_3_3_6 + default "3.4.2" if BR2_GCC_VERSION_3_4_2 + default "3.4.3" if BR2_GCC_VERSION_3_4_3 + default "3.4.4" if BR2_GCC_VERSION_3_4_4 + default "3.4.5" if BR2_GCC_VERSION_3_4_5 + default "3.4.6" if BR2_GCC_VERSION_3_4_6 + default "4.0.0" if BR2_GCC_VERSION_4_0_0 + default "4.0.1" if BR2_GCC_VERSION_4_0_1 + default "4.0.2" if BR2_GCC_VERSION_4_0_2 + default "4.0.3" if BR2_GCC_VERSION_4_0_3 + default "4.0.4" if BR2_GCC_VERSION_4_0_4 + default "4.1.0" if BR2_GCC_VERSION_4_1_0 + default "4.1.1" if BR2_GCC_VERSION_4_1_1 + default "4.1.2" if BR2_GCC_VERSION_4_1_2 + default "4.2" if BR2_GCC_VERSION_4_2 + + +config BR2_GCC_USE_SJLJ_EXCEPTIONS + bool "Enable setjmp/longjmp exceptions?" + default n + help + For some platforms, proper stack unwinding works perfectly, + while other platforms must use setjmp/longjmp exceptions for + proper stack unwinding during exception handling. Most people + can leave this set to n. + +config BR2_EXTRA_GCC_CONFIG_OPTIONS + string "Additional gcc options" + default "" + help + Any additional gcc configure options you may want to include.... + +config BR2_INSTALL_LIBSTDCPP + bool "Build/install c++ compiler and libstdc++?" + default n + # huh? why so? select BR2_LARGEFILE + select BR2_LARGEFILE if !BR2_GCC_VERSION_4_2 + help + Build/install c++ compiler and libstdc++? + +config BR2_INSTALL_LIBGCJ + bool "Build/install java compiler and libgcj?" + default n + depends on BR2_INSTALL_LIBSTDCPP + help + Build/install java compiler and libgcj? + +config BR2_INSTALL_OBJC + bool "Build/install Objective-C compiler and runtime?" + default n + help + Build/install Objective-C compiler and runtime? + +config BR2_INSTALL_FORTRAN + bool "Build/install Fortran compiler and runtime?" + default n + select BR2_PACKAGE_LIBMPFR + help + Build/install Fortran compiler and runtime? + Note that it is highly recommended NOT to use gfortran + from gcc older than 4.2.0 + diff --git a/misc/buildroot/toolchain/gcc/Config.in.2 b/misc/buildroot/toolchain/gcc/Config.in.2 new file mode 100644 index 000000000..bb97286c1 --- /dev/null +++ b/misc/buildroot/toolchain/gcc/Config.in.2 @@ -0,0 +1,14 @@ +config BR2_PACKAGE_GCC_TARGET + bool "native toolchain in the target filesystem" + default n + help + If you want the target system to be able to run + binutils/gcc and compile native code, say Y here. + +config BR2_EXTRA_TARGET_GCC_CONFIG_OPTIONS + string "Additional target gcc options" + default "" + help + Any additional target gcc options you may want to include.... + Including, but not limited to --disable-checking etc. + Refer to */configure in your gcc sources. diff --git a/misc/buildroot/toolchain/gcc/Makefile.in b/misc/buildroot/toolchain/gcc/Makefile.in new file mode 100644 index 000000000..51685679e --- /dev/null +++ b/misc/buildroot/toolchain/gcc/Makefile.in @@ -0,0 +1,66 @@ +# + +GCC_VERSION:=$(strip $(subst ",, $(BR2_GCC_VERSION))) +#")) +TARGET_OPTIMIZATION:=$(strip $(subst ",, $(BR2_TARGET_OPTIMIZATION))) +#")) +EXTRA_GCC_CONFIG_OPTIONS:=$(strip $(subst ",, $(BR2_EXTRA_GCC_CONFIG_OPTIONS))) +#")) +ifeq ($(strip $(subst ",, $(BR2_GCC_IS_SNAP))),y) +#")) +GCC_SNAP_DATE:=$(strip $(subst ",, $(BR2_GCC_SNAP_DATE))) +#")) +else +GCC_SNAP_DATE:= +endif +#"))) + +ifeq ($(strip $(BR2_GCC_USE_SJLJ_EXCEPTIONS)),y) +GCC_USE_SJLJ_EXCEPTIONS:=--enable-sjlj-exceptions +endif + +ifeq ($(BR2_SOFT_FLOAT),y) +# gcc 3.4.x soft float configuration is different than previous versions. +ifeq ($(findstring 3.4.,$(GCC_VERSION)),3.4.) +SOFT_FLOAT_CONFIG_OPTION:=--with-float=soft +else +SOFT_FLOAT_CONFIG_OPTION:=--without-float +endif + +# again... there must be a better way +ifeq ($(findstring 4.,$(GCC_VERSION)),4.) +SOFT_FLOAT_CONFIG_OPTION:=--with-float=soft +ifeq ($(BR2_SOFT_FLOAT_FP),y) +TARGET_SOFT_FLOAT:=-mfloat-abi=softfp +else # no fp at all +TARGET_SOFT_FLOAT:=-mfloat-abi=soft +endif +else # not gcc-4.x +TARGET_SOFT_FLOAT:=-msoft-float +endif +ARCH_FPU_SUFFIX:=_nofpu +else # no softfloat support +SOFT_FLOAT_CONFIG_OPTION:= +TARGET_SOFT_FLOAT:= +ARCH_FPU_SUFFIX:= +endif + +TARGET_GCC_FLAGS= CFLAGS_FOR_TARGET="$(TARGET_CFLAGS) $(TARGET_SOFT_FLOAT)" \ + CXXFLAGS_FOR_TARGET="$(TARGET_CFLAGS) $(TARGET_SOFT_FLOAT)" \ + CFLAGS="$(TARGET_CFLAGS) $(TARGET_SOFT_FLOAT)" \ + BOOT_CFLAGS="$(TARGET_CFLAGS) $(TARGET_SOFT_FLOAT)" + +ifeq ($(strip $(BR2_PACKAGE_GCC_TARGET)),y) +# pull in config opts from the user +EXTRA_TARGET_GCC_CONFIG_OPTIONS:=$(strip $(subst ",, $(BR2_EXTRA_TARGET_GCC_CONFIG_OPTIONS))) +#")) + +ifeq ($(BR2_PREFER_IMA),y) +# >= 4.x +ifneq ($(findstring 3.,$(GCC_VERSION)),3.) +EXTRA_TARGET_GCC_CONFIG_OPTIONS+=--enable-intermodule +endif +endif # BR2_PREFER_IMA=y + +TARGETS+=gcc_target +endif diff --git a/misc/buildroot/toolchain/gcc/gcc-nuttx-3.x.mk b/misc/buildroot/toolchain/gcc/gcc-nuttx-3.x.mk new file mode 100644 index 000000000..a5d09e50d --- /dev/null +++ b/misc/buildroot/toolchain/gcc/gcc-nuttx-3.x.mk @@ -0,0 +1,435 @@ +# Makefile for to build a gcc/nuttx toolchain +# +# Copyright (C) 2002-2003 Erik Andersen +# Copyright (C) 2004 Manuel Novoa III +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +ifeq ($(GCC_SNAP_DATE),) +GCC_OFFICIAL_VER:=$(GCC_VERSION) +GCC_SITE:=http://ftp.gnu.org/gnu/gcc/gcc-$(GCC_VERSION) +#GCC_SITE:=ftp://ftp.ibiblio.org/pub/mirrors/gnu/ftp/gnu/gcc/gcc-$(GCC_OFFICIAL_VER) +else +GCC_OFFICIAL_VER:=$(GCC_VERSION)-$(GCC_SNAP_DATE) +GCC_SITE:=ftp://sources.redhat.com/pub/gcc/snapshots/$(GCC_OFFICIAL_VER) +endif + +GCC_SOURCE:=gcc-$(GCC_OFFICIAL_VER).tar.bz2 +GCC_DIR:=$(TOOL_BUILD_DIR)/gcc-$(GCC_OFFICIAL_VER) +GCC_CAT:=$(BZCAT) +GCC_STRIP_HOST_BINARIES:=true + + +ifeq ($(findstring 3.,$(GCC_VERSION)),3.) +GCC_NO_MPFR:=y +endif +ifeq ($(findstring 4.0.,$(GCC_VERSION)),4.0.) +GCC_NO_MPFR:=y +endif +#ifeq ($(findstring 4.1.,$(GCC_VERSION)),4.1.) +#GCC_NO_MPFR:=y +#endif + +############################################################# +# +# Setup some initial stuff +# +############################################################# + +GCC_TARGET_LANGUAGES:=c + +ifeq ($(BR2_INSTALL_LIBSTDCPP),y) +GCC_TARGET_LANGUAGES:=$(GCC_TARGET_LANGUAGES),c++ +endif + +ifeq ($(BR2_INSTALL_LIBGCJ),y) +GCC_TARGET_LANGUAGES:=$(GCC_TARGET_LANGUAGES),java +endif + +ifeq ($(BR2_INSTALL_OBJC),y) +GCC_TARGET_LANGUAGES:=$(GCC_TARGET_LANGUAGES),objc +endif + +GCC_TARGET_PREREQ = +GCC_STAGING_PREREQ= + +ifndef GCC_NO_MPFR +GCC_WITH_HOST_GMP=--with-gmp=$(GMP_HOST_DIR) +GCC_WITH_HOST_MPFR=--with-mpfr=$(MPFR_HOST_DIR) + +ifeq ($(BR2_INSTALL_FORTRAN),y) +GCC_TARGET_LANGUAGES:=$(GCC_TARGET_LANGUAGES),fortran +#GCC_TARGET_PREREQ += $(TARGET_DIR)/lib/libmpfr.so $(TARGET_DIR)/lib/libgmp.so +#GCC_STAGING_PREREQ+= $(TOOL_BUILD_DIR)/mpfr/lib/libmpfr.so +GCC_WITH_TARGET_GMP=--with-gmp="$(GMP_TARGET_DIR)" +GCC_WITH_TARGET_MPFR=--with-mpfr="$(MPFR_TARGET_DIR)" +endif +endif # ifndef GCC_NO_MPFR + +GCC_SHARED_LIBGCC:=--disable-shared + +ifneq ($(BR2_ENABLE_LOCALE),y) +GCC_ENABLE_CLOCALE:=--disable-clocale +endif + + +############################################################# +# +# build the first pass gcc compiler +# +############################################################# +GCC_BUILD_DIR1:=$(TOOL_BUILD_DIR)/gcc-$(GCC_VERSION)-initial + +$(DL_DIR)/$(GCC_SOURCE): + mkdir -p $(DL_DIR) + $(WGET) -P $(DL_DIR) $(GCC_SITE)/$(GCC_SOURCE) + +gcc-unpacked: $(GCC_DIR)/.unpacked +$(GCC_DIR)/.unpacked: $(DL_DIR)/$(GCC_SOURCE) + mkdir -p $(TOOL_BUILD_DIR) + $(GCC_CAT) $(DL_DIR)/$(GCC_SOURCE) | tar -C $(TOOL_BUILD_DIR) $(TAR_OPTIONS) - + $(CONFIG_UPDATE) $(GCC_DIR) + touch $@ + +gcc-patched: $(GCC_DIR)/.patched +$(GCC_DIR)/.patched: $(GCC_DIR)/.unpacked + # Apply any files named gcc-*.patch from the source directory to gcc +ifeq ($(GCC_SNAP_DATE),) + toolchain/patch-kernel.sh $(GCC_DIR) toolchain/gcc/$(GCC_VERSION) \*.patch +else +ifneq ($(wildcard toolchain/gcc/$(GCC_OFFICIAL_VER)),) + toolchain/patch-kernel.sh $(GCC_DIR) toolchain/gcc/$(GCC_OFFICIAL_VER) \*.patch +else + toolchain/patch-kernel.sh $(GCC_DIR) toolchain/gcc/$(GCC_VERSION) \*.patch +endif +endif + + # Note: The soft float situation has improved considerably with gcc 3.4.x. + # We can dispense with the custom spec files, as well as libfloat for the arm case. + # However, we still need a patch for arm. There's a similar patch for gcc 3.3.x + # which needs to be integrated so we can kill of libfloat for good, except for + # anyone (?) who might still be using gcc 2.95. mjn3 +ifeq ($(BR2_SOFT_FLOAT),y) +ifeq ("$(strip $(ARCH))","arm") + toolchain/patch-kernel.sh $(GCC_DIR) toolchain/gcc/$(GCC_VERSION) arm-softfloat.patch.conditional +endif +ifeq ("$(strip $(ARCH))","armeb") + toolchain/patch-kernel.sh $(GCC_DIR) toolchain/gcc/$(GCC_VERSION) arm-softfloat.patch.conditional +endif + # Not yet updated to 3.4.1. + #ifeq ("$(strip $(ARCH))","i386") + #toolchain/patch-kernel.sh $(GCC_DIR) toolchain/gcc i386-gcc-soft-float.patch + #endif +endif + touch $@ + +# The --without-headers option stopped working with gcc 3.0 and has never been +# fixed, so we need to actually have working C library header files prior to +# the step or libgcc will not build... + +$(GCC_BUILD_DIR1)/.configured: $(GCC_DIR)/.patched + mkdir -p $(GCC_BUILD_DIR1) + (cd $(GCC_BUILD_DIR1); PATH=$(TARGET_PATH) \ + CC="$(HOSTCC)" \ + $(GCC_DIR)/configure \ + --prefix=$(STAGING_DIR) \ + --build=$(GNU_HOST_NAME) \ + --host=$(GNU_HOST_NAME) \ + --target=$(REAL_GNU_TARGET_NAME) \ + --enable-languages=c \ + --disable-__cxa_atexit \ + --enable-target-optspace \ + --with-gnu-ld \ + --disable-shared \ + $(GCC_WITH_HOST_GMP) \ + $(GCC_WITH_HOST_MPFR) \ + $(DISABLE_NLS) \ + $(THREADS) \ + $(MULTILIB) \ + $(SOFT_FLOAT_CONFIG_OPTION) \ + $(GCC_WITH_CPU) $(GCC_WITH_ARCH) $(GCC_WITH_TUNE) \ + $(EXTRA_GCC_CONFIG_OPTIONS)); + touch $@ + +$(GCC_BUILD_DIR1)/.compiled: $(GCC_BUILD_DIR1)/.configured + PATH=$(TARGET_PATH) $(MAKE) -C $(GCC_BUILD_DIR1) all-gcc + touch $@ + +$(STAGING_DIR)/bin/$(REAL_GNU_TARGET_NAME)-gcc: $(GCC_BUILD_DIR1)/.compiled + PATH=$(TARGET_PATH) $(MAKE) -C $(GCC_BUILD_DIR1) install-gcc + #rm -f $(STAGING_DIR)/bin/gccbug $(STAGING_DIR)/bin/gcov + #rm -rf $(STAGING_DIR)/info $(STAGING_DIR)/man $(STAGING_DIR)/share/doc $(STAGING_DIR)/share/locale + +gcc_initial: binutils $(STAGING_DIR)/bin/$(REAL_GNU_TARGET_NAME)-gcc + +gcc_initial-clean: + rm -rf $(GCC_BUILD_DIR1) + +gcc_initial-dirclean: + rm -rf $(GCC_BUILD_DIR1) $(GCC_DIR) + +############################################################# +# +# second pass compiler build. Build the compiler targeting +# the newly built shared library. +# +############################################################# +# +# Sigh... I had to rework things because using --with-gxx-include-dir +# causes issues with include dir search order for g++. This seems to +# have something to do with "path translations" and possibly doesn't +# affect gcc-target. However, I haven't tested gcc-target yet so no +# guarantees. mjn3 + +GCC_BUILD_DIR2:=$(TOOL_BUILD_DIR)/gcc-$(GCC_VERSION)-final +$(GCC_BUILD_DIR2)/.configured: $(GCC_DIR)/.patched $(GCC_STAGING_PREREQ) + mkdir -p $(GCC_BUILD_DIR2) + # Important! Required for limits.h to be fixed. + ln -snf ../include $(STAGING_DIR)/$(REAL_GNU_TARGET_NAME)/sys-include + (cd $(GCC_BUILD_DIR2); PATH=$(TARGET_PATH) \ + CC="$(HOSTCC)" \ + $(GCC_DIR)/configure \ + --prefix=$(STAGING_DIR) \ + --build=$(GNU_HOST_NAME) \ + --host=$(GNU_HOST_NAME) \ + --target=$(REAL_GNU_TARGET_NAME) \ + --enable-languages=$(GCC_TARGET_LANGUAGES) \ + --disable-__cxa_atexit \ + --enable-target-optspace \ + --with-gnu-ld \ + $(GCC_WITH_HOST_GMP) \ + $(GCC_WITH_HOST_MPFR) \ + $(GCC_SHARED_LIBGCC) \ + $(DISABLE_NLS) \ + $(THREADS) \ + $(MULTILIB) \ + $(SOFT_FLOAT_CONFIG_OPTION) \ + $(GCC_WITH_CPU) $(GCC_WITH_ARCH) $(GCC_WITH_TUNE) \ + $(GCC_USE_SJLJ_EXCEPTIONS) \ + $(DISABLE_LARGEFILE) \ + $(EXTRA_GCC_CONFIG_OPTIONS)); + touch $@ + +$(GCC_BUILD_DIR2)/.compiled: $(GCC_BUILD_DIR2)/.configured + PATH=$(TARGET_PATH) $(MAKE) -C $(GCC_BUILD_DIR2) all + touch $@ + +$(GCC_BUILD_DIR2)/.installed: $(GCC_BUILD_DIR2)/.compiled + PATH=$(TARGET_PATH) $(MAKE) -C $(GCC_BUILD_DIR2) install + if [ -d "$(STAGING_DIR)/lib64" ] ; then \ + if [ ! -e "$(STAGING_DIR)/lib" ] ; then \ + mkdir "$(STAGING_DIR)/lib" ; \ + fi ; \ + mv "$(STAGING_DIR)/lib64/"* "$(STAGING_DIR)/lib/" ; \ + rmdir "$(STAGING_DIR)/lib64" ; \ + fi + # Strip the host binaries +ifeq ($(GCC_STRIP_HOST_BINARIES),true) + -strip --strip-all -R .note -R .comment $(STAGING_DIR)/bin/* +endif + # Make sure we have 'cc'. + if [ ! -e $(STAGING_DIR)/bin/$(REAL_GNU_TARGET_NAME)-cc ] ; then \ + ln -snf $(REAL_GNU_TARGET_NAME)-gcc \ + $(STAGING_DIR)/bin/$(REAL_GNU_TARGET_NAME)-cc ; \ + fi; + if [ ! -e $(STAGING_DIR)/$(REAL_GNU_TARGET_NAME)/bin/cc ] ; then \ + ln -snf gcc $(STAGING_DIR)/$(REAL_GNU_TARGET_NAME)/bin/cc ; \ + fi; + # Set up the symlinks to enable lying about target name. + set -e; \ + (cd $(STAGING_DIR); \ + ln -snf $(REAL_GNU_TARGET_NAME) $(GNU_TARGET_NAME); \ + cd bin; \ + for app in $(REAL_GNU_TARGET_NAME)-* ; do \ + ln -snf $${app} \ + $(GNU_TARGET_NAME)$${app##$(REAL_GNU_TARGET_NAME)}; \ + done; \ + ); + # + # Now for the ugly 3.3.x soft float hack... + # +ifeq ($(BR2_SOFT_FLOAT),y) +ifeq ($(findstring 3.3.,$(GCC_VERSION)),3.3.) + # Make sure we have a soft float specs file for this arch + if [ ! -f toolchain/gcc/$(GCC_VERSION)/specs-$(ARCH)-soft-float ] ; then \ + echo soft float configured but no specs file for this arch ; \ + /bin/false ; \ + fi; + # Replace specs file with one that defaults to soft float mode. + if [ ! -f $(STAGING_DIR)/lib/gcc-lib/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION)/specs ] ; then \ + echo staging dir specs file is missing ; \ + /bin/false ; \ + fi; + cp toolchain/gcc/$(GCC_VERSION)/specs-$(ARCH)-soft-float $(STAGING_DIR)/lib/gcc-lib/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION)/specs +endif +endif + # + # Ok... that's enough of that. + # + touch $@ + +$(GCC_BUILD_DIR2)/.libs_installed: $(GCC_BUILD_DIR2)/.installed +ifeq ($(BR2_INSTALL_LIBSTDCPP),y) + -cp -dpf $(STAGING_DIR)/lib/libstdc++.so* $(TARGET_DIR)/lib/ +endif +ifeq ($(BR2_INSTALL_LIBGCJ),y) + -cp -dpf $(STAGING_DIR)/lib/libgcj.so* $(TARGET_DIR)/lib/ + -cp -dpf $(STAGING_DIR)/lib/lib-org-w3c-dom.so* $(TARGET_DIR)/lib/ + -cp -dpf $(STAGING_DIR)/lib/lib-org-xml-sax.so* $(TARGET_DIR)/lib/ + -mkdir -p $(TARGET_DIR)/usr/lib/security + -cp -dpf $(STAGING_DIR)/usr/lib/security/libgcj.security $(TARGET_DIR)/usr/lib/security/ + -cp -dpf $(STAGING_DIR)/usr/lib/security/classpath.security $(TARGET_DIR)/usr/lib/security/ +endif + touch $@ + +gcc: binutils gcc_initial $(LIBFLOAT_TARGET) \ + $(GCC_BUILD_DIR2)/.installed $(GCC_BUILD_DIR2)/.libs_installed \ + $(GCC_TARGETS) + +gcc-source: $(DL_DIR)/$(GCC_SOURCE) + +gcc-clean: + rm -rf $(GCC_BUILD_DIR2) + for prog in cpp gcc gcc-[0-9]* protoize unprotoize gcov gccbug cc; do \ + rm -f $(STAGING_DIR)/bin/$(REAL_GNU_TARGET_NAME)-$$prog \ + rm -f $(STAGING_DIR)/bin/$(GNU_TARGET_NAME)-$$prog; \ + done + +gcc-dirclean: gcc_initial-dirclean + rm -rf $(GCC_BUILD_DIR2) + +############################################################# +# +# Next build target gcc compiler +# +############################################################# +GCC_BUILD_DIR3:=$(BUILD_DIR)/gcc-$(GCC_VERSION)-target + +$(GCC_BUILD_DIR3)/.prepared: $(GCC_BUILD_DIR2)/.libs_installed $(GCC_TARGET_PREREQ) + mkdir -p $(GCC_BUILD_DIR3) + touch $@ + +$(GCC_BUILD_DIR3)/.configured: $(GCC_BUILD_DIR3)/.prepared + (cd $(GCC_BUILD_DIR3); rm -rf config.cache ; \ + PATH=$(TARGET_PATH) \ + CC_FOR_BUILD="$(HOSTCC)" \ + CFLAGS_FOR_BUILD="-g -O2" \ + $(TARGET_GCC_FLAGS) \ + $(GCC_DIR)/configure \ + --prefix=/usr \ + --build=$(GNU_HOST_NAME) \ + --host=$(REAL_GNU_TARGET_NAME) \ + --target=$(REAL_GNU_TARGET_NAME) \ + --enable-languages=$(GCC_TARGET_LANGUAGES) \ + --with-gxx-include-dir=/usr/include/c++ \ + --disable-__cxa_atexit \ + --with-gnu-ld \ + $(GCC_SHARED_LIBGCC) \ + $(GCC_WITH_TARGET_GMP) \ + $(GCC_WITH_TARGET_MPFR) \ + $(DISABLE_NLS) \ + $(THREADS) \ + $(MULTILIB) \ + $(SOFT_FLOAT_CONFIG_OPTION) \ + $(GCC_WITH_CPU) $(GCC_WITH_ARCH) $(GCC_WITH_TUNE) \ + $(GCC_USE_SJLJ_EXCEPTIONS) \ + $(DISABLE_LARGEFILE) \ + $(EXTRA_GCC_CONFIG_OPTIONS) \ + $(EXTRA_TARGET_GCC_CONFIG_OPTIONS)); + touch $@ + +$(GCC_BUILD_DIR3)/.compiled: $(GCC_BUILD_DIR3)/.configured + PATH=$(TARGET_PATH) \ + $(MAKE) -C $(GCC_BUILD_DIR3) all + touch $@ + +# +# gcc-lib dir changes names to gcc with 3.4.mumble +# +ifeq ($(findstring 3.4.,$(GCC_VERSION)),3.4.) +GCC_LIB_SUBDIR=lib/gcc/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION) +else +GCC_LIB_SUBDIR=lib/gcc-lib/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION) +endif +# sigh... we need to find a better way +ifeq ($(findstring 4.0.,$(GCC_VERSION)),4.0.) +GCC_LIB_SUBDIR=lib/gcc/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION) +endif +ifeq ($(findstring 4.1.,$(GCC_VERSION)),4.1.) +GCC_LIB_SUBDIR=lib/gcc/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION) +endif +ifeq ($(findstring 4.2,$(GCC_VERSION)),4.2) +ifneq ($(findstring 4.2.,$(GCC_VERSION)),4.2.) +REAL_GCC_VERSION=$(shell cat $(GCC_DIR)/gcc/BASE-VER) +GCC_LIB_SUBDIR=lib/gcc/$(REAL_GNU_TARGET_NAME)/$(REAL_GCC_VERSION) +else +GCC_LIB_SUBDIR=lib/gcc/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION) +endif +#XXX: FIXME: cleanup BR2_ARCH selection and establish BR2_CPU +#GCC_WITH_ARCH=--with-arch=$(BR2_ARCH) +#GCC_WITH_TUNE=--with-tune=$(BR2_ARCH) +#GCC_WITH_CPU=--with-cpu=$(BR2_ARCH) +endif + +$(TARGET_DIR)/usr/bin/gcc: $(GCC_BUILD_DIR3)/.compiled + PATH=$(TARGET_PATH) \ + $(MAKE) DESTDIR=$(TARGET_DIR) -C $(GCC_BUILD_DIR3) install + # Remove broken specs file (cross compile flag is set). + rm -f $(TARGET_DIR)/usr/$(GCC_LIB_SUBDIR)/specs + # + # Now for the ugly 3.3.x soft float hack... + # +ifeq ($(BR2_SOFT_FLOAT),y) +ifeq ($(findstring 3.3.,$(GCC_VERSION)),3.3.) + # Add a specs file that defaults to soft float mode. + cp toolchain/gcc/$(GCC_VERSION)/specs-$(ARCH)-soft-float $(TARGET_DIR)/usr/lib/gcc-lib/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION)/specs + # Make sure gcc does not think we are cross compiling + $(SED) "s/^1/0/;" $(TARGET_DIR)/usr/lib/gcc-lib/$(REAL_GNU_TARGET_NAME)/$(GCC_VERSION)/specs +endif +endif + # + # Ok... that's enough of that. + # + -(cd $(TARGET_DIR)/bin; find -type f | xargs $(STRIP) > /dev/null 2>&1) + -(cd $(TARGET_DIR)/usr/bin; find -type f | xargs $(STRIP) > /dev/null 2>&1) + -(cd $(TARGET_DIR)/usr/$(GCC_LIB_SUBDIR); $(STRIP) cc1 cc1plus collect2 > /dev/null 2>&1) + -(cd $(TARGET_DIR)/usr/lib; $(STRIP) libstdc++.so.*.*.* > /dev/null 2>&1) + -(cd $(TARGET_DIR)/lib; $(STRIP) libgcc_s*.so.*.*.* > /dev/null 2>&1) + # + rm -f $(TARGET_DIR)/usr/lib/*.la* + #rm -rf $(TARGET_DIR)/share/locale $(TARGET_DIR)/usr/info \ + # $(TARGET_DIR)/usr/man $(TARGET_DIR)/usr/share/doc + # Work around problem of missing syslimits.h + if [ ! -f $(TARGET_DIR)/usr/$(GCC_LIB_SUBDIR)/include/syslimits.h ] ; then \ + echo "warning: working around missing syslimits.h" ; \ + cp -f $(STAGING_DIR)/$(GCC_LIB_SUBDIR)/include/syslimits.h \ + $(TARGET_DIR)/usr/$(GCC_LIB_SUBDIR)/include/ ; \ + fi + # Make sure we have 'cc'. + if [ ! -e $(TARGET_DIR)/usr/bin/cc ] ; then \ + ln -snf gcc $(TARGET_DIR)/usr/bin/cc ; \ + fi; + # These are in /lib, so... + #rm -rf $(TARGET_DIR)/usr/lib/libgcc_s*.so* + #touch -c $(TARGET_DIR)/usr/bin/gcc + +gcc_target: binutils_target $(TARGET_DIR)/usr/bin/gcc + +gcc_target-clean: + rm -rf $(GCC_BUILD_DIR3) + rm -f $(TARGET_DIR)/usr/bin/$(REAL_GNU_TARGET_NAME)* + +gcc_target-dirclean: + rm -rf $(GCC_BUILD_DIR3) diff --git a/misc/buildroot/toolchain/gcc/i386-gcc-soft-float.patch b/misc/buildroot/toolchain/gcc/i386-gcc-soft-float.patch new file mode 100644 index 000000000..97501087e --- /dev/null +++ b/misc/buildroot/toolchain/gcc/i386-gcc-soft-float.patch @@ -0,0 +1,61 @@ +diff -urN gcc-3.3.2-orig/gcc/config/i386/i386.h gcc-3.3.2/gcc/config/i386/i386.h +--- gcc-3.3.2-orig/gcc/config/i386/i386.h 2003-06-25 16:18:31.000000000 -0500 ++++ gcc-3.3.2/gcc/config/i386/i386.h 2003-10-22 01:46:57.000000000 -0500 +@@ -653,6 +653,7 @@ + /* Define for XFmode or TFmode extended real floating point support. + The XFmode is specified by i386 ABI, while TFmode may be faster + due to alignment and simplifications in the address calculations. */ ++#if 0 + #define LONG_DOUBLE_TYPE_SIZE (TARGET_128BIT_LONG_DOUBLE ? 128 : 96) + #define MAX_LONG_DOUBLE_TYPE_SIZE 128 + #ifdef __x86_64__ +@@ -660,6 +661,17 @@ + #else + #define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 96 + #endif ++#else ++ /* Set up for x86 soft float with 64-bit long doubles, since that's ++ * all the soft float emulation supports. */ ++#define LONG_DOUBLE_TYPE_SIZE (TARGET_128BIT_LONG_DOUBLE ? 128 : (TARGET_80387 ? 96 : 64)) ++#define MAX_LONG_DOUBLE_TYPE_SIZE 128 ++#ifdef __x86_64__ ++#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 128 ++#else ++#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE (TARGET_80387 ? 96 : 64) ++#endif ++#endif + + /* Set the value of FLT_EVAL_METHOD in float.h. When using only the + FPU, assume that the fpcw is set to extended precision; when using +diff -urN gcc-3.3.2-orig/gcc/config/t-linux gcc-3.3.2/gcc/config/t-linux +--- gcc-3.3.2-orig/gcc/config/t-linux-uclibc 2003-06-04 11:56:11.000000000 -0500 ++++ gcc-3.3.2/gcc/config/t-linux-uclibc 2003-10-22 01:46:39.000000000 -0500 +@@ -21,3 +21,28 @@ + LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde.c \ + $(srcdir)/unwind-sjlj.c $(srcdir)/unwind-c.c + LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h ++ ++############################################## ++# We want fine grained libraries, so use the new code to build the ++# floating point emulation libraries. ++FPBIT = fp-bit.c ++DPBIT = dp-bit.c ++ ++#LIB2FUNCS_EXTRA = xp-bit.c ++ ++dp-bit.c: $(srcdir)/config/fp-bit.c ++ echo '#ifdef __LITTLE_ENDIAN__' > dp-bit.c ++ echo '#define FLOAT_BIT_ORDER_MISMATCH' >>dp-bit.c ++ echo '#endif' >> dp-bit.c ++ cat $(srcdir)/config/fp-bit.c >> dp-bit.c ++ ++fp-bit.c: $(srcdir)/config/fp-bit.c ++ echo '#define FLOAT' > fp-bit.c ++ echo '#ifdef __LITTLE_ENDIAN__' >> fp-bit.c ++ echo '#define FLOAT_BIT_ORDER_MISMATCH' >>fp-bit.c ++ echo '#endif' >> fp-bit.c ++ cat $(srcdir)/config/fp-bit.c >> fp-bit.c ++ ++#MULTILIB_OPTIONS = msoft-float ++#MULTILIB_DIRNAMES = soft-float ++ -- cgit v1.2.3