* MicroBlaze port
@ 2010-09-29 9:07 Michael Eager
2010-09-29 13:16 ` Joseph S. Myers
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Michael Eager @ 2010-09-29 9:07 UTC (permalink / raw)
To: gcc-patches
[-- Attachment #1: Type: text/plain, Size: 654 bytes --]
Hi --
Attached are the final patches to the GCC trunk
and htdocs to add support for the Xilinx MicroBlaze
processor. These patches have been updated to the
current head but are otherwise identical to the
patches which were previously approved.
The wwwdocs patches were approved by Gerald Pfeifer
off-list.
Rather than repost each patch individually with its
ChangeLog, the attached patch contains the ChangeLogs.
The ChangeLogs are the same as previously posted.
Please let me know ASAP if you see any problems
with checking these patches into GCC mainline.
--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mb-head-10-09-27.patch --]
[-- Type: text/x-patch; name="mb-head-10-09-27.patch", Size: 319225 bytes --]
Index: configure
===================================================================
--- configure (revision 164569)
+++ configure (working copy)
@@ -3650,7 +3650,7 @@
noconfigdirs="$noconfigdirs ld binutils gprof target-libgloss ${libgcj}"
;;
microblaze*)
- noconfigdirs="$noconfigdirs gprof ${libgcj}"
+ noconfigdirs="$noconfigdirs gprof target-libssp ${libgcj}"
;;
mips*-sde-elf*)
skipdirs="$skipdirs target-libiberty"
Index: libgcc/config.host
===================================================================
--- libgcc/config.host (revision 164569)
+++ libgcc/config.host (working copy)
@@ -107,6 +107,9 @@
;;
mep*-*-*)
;;
+microblaze*-*-*)
+ cpu_type=microblaze
+ ;;
mips*-*-*)
cpu_type=mips
;;
@@ -399,6 +402,9 @@
;;
mcore-*-pe*)
;;
+microblaze*-*-*)
+ tmake_file="microblaze/t-microblaze"
+ ;;
mips-sgi-irix[56]*)
;;
mips*-*-netbsd*) # NetBSD/mips, either endian.
Index: libgcc/config/microblaze/divsi3.asm
===================================================================
--- libgcc/config/microblaze/divsi3.asm (revision 0)
+++ libgcc/config/microblaze/divsi3.asm (revision 0)
@@ -0,0 +1,96 @@
+###################################-
+#
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# divsi3.asm
+#
+# Divide operation for 32 bit integers.
+# Input : Dividend in Reg r5
+# Divisor in Reg r6
+# Output: Result in Reg r3
+#
+#######################################
+
+ .globl __divsi3
+ .ent __divsi3
+ .type __divsi3,@function
+__divsi3:
+ .frame r1,0,r15
+
+ ADDIK r1,r1,-16
+ SWI r28,r1,0
+ SWI r29,r1,4
+ SWI r30,r1,8
+ SWI r31,r1,12
+
+ BEQI r6,$LaDiv_By_Zero # Div_by_Zero # Division Error
+ BEQI r5,$LaResult_Is_Zero # Result is Zero
+ BGEID r5,$LaR5_Pos
+ XOR r28,r5,r6 # Get the sign of the result
+ RSUBI r5,r5,0 # Make r5 positive
+$LaR5_Pos:
+ BGEI r6,$LaR6_Pos
+ RSUBI r6,r6,0 # Make r6 positive
+$LaR6_Pos:
+ ADDIK r30,r0,0 # Clear mod
+ ADDIK r3,r0,0 # clear div
+ ADDIK r29,r0,32 # Initialize the loop count
+
+ # First part try to find the first '1' in the r5
+$LaDIV0:
+ BLTI r5,$LaDIV2 # This traps r5 == 0x80000000
+$LaDIV1:
+ ADD r5,r5,r5 # left shift logical r5
+ BGTID r5,$LaDIV1
+ ADDIK r29,r29,-1
+$LaDIV2:
+ ADD r5,r5,r5 # left shift logical r5 get the '1' into the Carry
+ ADDC r30,r30,r30 # Move that bit into the Mod register
+ RSUB r31,r6,r30 # Try to subtract (r30 a r6)
+ BLTI r31,$LaMOD_TOO_SMALL
+ OR r30,r0,r31 # Move the r31 to mod since the result was positive
+ ADDIK r3,r3,1
+$LaMOD_TOO_SMALL:
+ ADDIK r29,r29,-1
+ BEQi r29,$LaLOOP_END
+ ADD r3,r3,r3 # Shift in the '1' into div
+ BRI $LaDIV2 # Div2
+$LaLOOP_END:
+ BGEI r28,$LaRETURN_HERE
+ BRID $LaRETURN_HERE
+ RSUBI r3,r3,0 # Negate the result
+$LaDiv_By_Zero:
+$LaResult_Is_Zero:
+ OR r3,r0,r0 # set result to 0
+$LaRETURN_HERE:
+# Restore values of CSRs and that of r3 and the divisor and the dividend
+ LWI r28,r1,0
+ LWI r29,r1,4
+ LWI r30,r1,8
+ LWI r31,r1,12
+ RTSD r15,8
+ ADDIK r1,r1,16
+.end __divsi3
+ .size __divsi3, . - __divsi3
+
Index: libgcc/config/microblaze/stack_overflow_exit.asm
===================================================================
--- libgcc/config/microblaze/stack_overflow_exit.asm (revision 0)
+++ libgcc/config/microblaze/stack_overflow_exit.asm (revision 0)
@@ -0,0 +1,61 @@
+###################################-*-asm*-
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# stack_overflow_exit.asm
+#
+# Checks for stack overflows and sets the global variable
+# stack_overflow_error with the value of current stack pointer
+#
+# This routine exits from the program
+#
+#######################################
+
+ .globl _stack_overflow_error
+ .data
+ .align 2
+ .type _stack_overflow_error,@object
+ .size _stack_overflow_error,4
+_stack_overflow_error:
+ .data32 0
+
+ .text
+ .globl _stack_overflow_exit
+ .ent _stack_overflow_exit
+ .type _stack_overflow_exit,@function
+
+_stack_overflow_exit:
+#ifdef __PIC__
+ mfs r20,rpc
+ addik r20,r20,_GLOBAL_OFFSET_TABLE_+8
+ swi r1,r20,_stack_overflow_error@GOTOFF
+ bri exit@PLT
+#else
+ swi r1,r0,_stack_overflow_error
+ bri exit
+#endif
+
+ .end _stack_overflow_exit
+ .size _stack_overflow_exit,. - _stack_overflow_exit
Index: libgcc/config/microblaze/umodsi3.asm
===================================================================
--- libgcc/config/microblaze/umodsi3.asm (revision 0)
+++ libgcc/config/microblaze/umodsi3.asm (revision 0)
@@ -0,0 +1,106 @@
+###################################
+#
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# umodsi3.asm
+#
+# Unsigned modulo operation for 32 bit integers.
+# Input : op1 in Reg r5
+# op2 in Reg r6
+# Output: op1 mod op2 in Reg r3
+#
+#######################################
+
+ .globl __umodsi3
+ .ent __umodsi3
+ .type __umodsi3,@function
+__umodsi3:
+ .frame r1,0,r15
+
+ addik r1,r1,-12
+ swi r29,r1,0
+ swi r30,r1,4
+ swi r31,r1,8
+
+ BEQI r6,$LaDiv_By_Zero # Div_by_Zero # Division Error
+ BEQId r5,$LaResult_Is_Zero # Result is Zero
+ ADDIK r3,r0,0 # Clear div
+ ADDIK r30,r0,0 # clear mod
+ ADDIK r29,r0,32 # Initialize the loop count
+
+# Check if r6 and r5 are equal # if yes, return 0
+ rsub r18,r5,r6
+ beqi r18,$LaRETURN_HERE
+
+# Check if (uns)r6 is greater than (uns)r5. In that case, just return r5
+ xor r18,r5,r6
+ bgeid r18,16
+ addik r3,r5,0
+ blti r6,$LaRETURN_HERE
+ bri $LCheckr6
+ rsub r18,r5,r6 # MICROBLAZEcmp
+ bgti r18,$LaRETURN_HERE
+
+# If r6 [bit 31] is set, then return result as r5-r6
+$LCheckr6:
+ bgtid r6,$LaDIV0
+ addik r3,r0,0
+ addik r18,r0,0x7fffffff
+ and r5,r5,r18
+ and r6,r6,r18
+ brid $LaRETURN_HERE
+ rsub r3,r6,r5
+# First part: try to find the first '1' in the r5
+$LaDIV0:
+ BLTI r5,$LaDIV2
+$LaDIV1:
+ ADD r5,r5,r5 # left shift logical r5
+ BGEID r5,$LaDIV1 #
+ ADDIK r29,r29,-1
+$LaDIV2:
+ ADD r5,r5,r5 # left shift logical r5 get the '1' into the Carry
+ ADDC r3,r3,r3 # Move that bit into the Mod register
+ rSUB r31,r6,r3 # Try to subtract (r3 a r6)
+ BLTi r31,$LaMOD_TOO_SMALL
+ OR r3,r0,r31 # Move the r31 to mod since the result was positive
+ ADDIK r30,r30,1
+$LaMOD_TOO_SMALL:
+ ADDIK r29,r29,-1
+ BEQi r29,$LaLOOP_END
+ ADD r30,r30,r30 # Shift in the '1' into div
+ BRI $LaDIV2 # Div2
+$LaLOOP_END:
+ BRI $LaRETURN_HERE
+$LaDiv_By_Zero:
+$LaResult_Is_Zero:
+ or r3,r0,r0 # set result to 0
+$LaRETURN_HERE:
+# Restore values of CSRs and that of r3 and the divisor and the dividend
+ lwi r29,r1,0
+ lwi r30,r1,4
+ lwi r31,r1,8
+ rtsd r15,8
+ addik r1,r1,12
+.end __umodsi3
+ .size __umodsi3, . - __umodsi3
Index: libgcc/config/microblaze/udivsi3.asm
===================================================================
--- libgcc/config/microblaze/udivsi3.asm (revision 0)
+++ libgcc/config/microblaze/udivsi3.asm (revision 0)
@@ -0,0 +1,103 @@
+###################################-
+#
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# udivsi3.asm
+#
+# Unsigned divide operation.
+# Input : Divisor in Reg r5
+# Dividend in Reg r6
+# Output: Result in Reg r3
+#
+#######################################
+
+ .globl __udivsi3
+ .ent __udivsi3
+ .type __udivsi3,@function
+__udivsi3:
+ .frame r1,0,r15
+
+ ADDIK r1,r1,-12
+ SWI r29,r1,0
+ SWI r30,r1,4
+ SWI r31,r1,8
+
+ BEQI r6,$LaDiv_By_Zero # Div_by_Zero # Division Error
+ BEQID r5,$LaResult_Is_Zero # Result is Zero
+ ADDIK r30,r0,0 # Clear mod
+ ADDIK r29,r0,32 # Initialize the loop count
+
+ # Check if r6 and r5 are equal # if yes, return 1
+ RSUB r18,r5,r6
+ BEQID r18,$LaRETURN_HERE
+ ADDIK r3,r0,1
+
+ # Check if (uns)r6 is greater than (uns)r5. In that case, just return 0
+ XOR r18,r5,r6
+ BGEID r18,16
+ ADD r3,r0,r0 # We would anyways clear r3
+ BLTI r6,$LaRETURN_HERE # r6[bit 31 = 1] hence is greater
+ BRI $LCheckr6
+ RSUB r18,r6,r5 # MICROBLAZEcmp
+ BLTI r18,$LaRETURN_HERE
+
+ # If r6 [bit 31] is set, then return result as 1
+$LCheckr6:
+ BGTI r6,$LaDIV0
+ BRID $LaRETURN_HERE
+ ADDIK r3,r0,1
+
+ # First part try to find the first '1' in the r5
+$LaDIV0:
+ BLTI r5,$LaDIV2
+$LaDIV1:
+ ADD r5,r5,r5 # left shift logical r5
+ BGTID r5,$LaDIV1
+ ADDIK r29,r29,-1
+$LaDIV2:
+ ADD r5,r5,r5 # left shift logical r5 get the '1' into the Carry
+ ADDC r30,r30,r30 # Move that bit into the Mod register
+ RSUB r31,r6,r30 # Try to subtract (r30 a r6)
+ BLTI r31,$LaMOD_TOO_SMALL
+ OR r30,r0,r31 # Move the r31 to mod since the result was positive
+ ADDIK r3,r3,1
+$LaMOD_TOO_SMALL:
+ ADDIK r29,r29,-1
+ BEQi r29,$LaLOOP_END
+ ADD r3,r3,r3 # Shift in the '1' into div
+ BRI $LaDIV2 # Div2
+$LaLOOP_END:
+ BRI $LaRETURN_HERE
+$LaDiv_By_Zero:
+$LaResult_Is_Zero:
+ OR r3,r0,r0 # set result to 0
+$LaRETURN_HERE:
+ # Restore values of CSRs and that of r3 and the divisor and the dividend
+ LWI r29,r1,0
+ LWI r30,r1,4
+ LWI r31,r1,8
+ RTSD r15,8
+ ADDIK r1,r1,12
+ .end __udivsi3
+ .size __udivsi3, . - __udivsi3
Index: libgcc/config/microblaze/t-microblaze
===================================================================
--- libgcc/config/microblaze/t-microblaze (revision 0)
+++ libgcc/config/microblaze/t-microblaze (revision 0)
@@ -0,0 +1,12 @@
+LIB2ADD += \
+ $(srcdir)/config/microblaze/divsi3.asm \
+ $(srcdir)/config/microblaze/moddi3.asm \
+ $(srcdir)/config/microblaze/modsi3.asm \
+ $(srcdir)/config/microblaze/muldi3_hard.asm \
+ $(srcdir)/config/microblaze/mulsi3.asm \
+ $(srcdir)/config/microblaze/stack_overflow_exit.asm \
+ $(srcdir)/config/microblaze/udivsi3.asm \
+ $(srcdir)/config/microblaze/umodsi3.asm \
+ $(srcdir)/config/microblaze/divsi3_table.c
+
+MULTILIB_OPTIONS = mxl-barrel-shift mno-xl-soft-mul mxl-multiply-high
Index: libgcc/config/microblaze/divsi3_table.c
===================================================================
--- libgcc/config/microblaze/divsi3_table.c (revision 0)
+++ libgcc/config/microblaze/divsi3_table.c (revision 0)
@@ -0,0 +1,62 @@
+/* Table for software lookup divide for Xilinx MicroBlaze.
+
+ Copyright 2009, 2010 Free Software Foundation, Inc.
+
+ Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+ later version.
+
+ GCC 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+
+unsigned char _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,
+};
+
Index: libgcc/config/microblaze/muldi3_hard.asm
===================================================================
--- libgcc/config/microblaze/muldi3_hard.asm (revision 0)
+++ libgcc/config/microblaze/muldi3_hard.asm (revision 0)
@@ -0,0 +1,144 @@
+###################################-
+#
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# muldi3_hard.asm
+#
+# Multiply operation for 64 bit integers, for devices with hard multiply
+# Input : Operand1[H] in Reg r5
+# Operand1[L] in Reg r6
+# Operand2[H] in Reg r7
+# Operand2[L] in Reg r8
+# Output: Result[H] in Reg r3
+# Result[L] in Reg r4
+#
+# Explaination:
+#
+# Both the input numbers are divided into 16 bit number as follows
+# op1 = A B C D
+# op2 = E F G H
+# result = D * H
+# + (C * H + D * G) << 16
+# + (B * H + C * G + D * F) << 32
+# + (A * H + B * G + C * F + D * E) << 48
+#
+# Only 64 bits of the output are considered
+#
+#######################################
+
+ .globl muldi3_hardproc
+ .ent muldi3_hardproc
+muldi3_hardproc:
+ addi r1,r1,-40
+
+# Save the input operands on the caller's stack
+ swi r5,r1,44
+ swi r6,r1,48
+ swi r7,r1,52
+ swi r8,r1,56
+
+# Store all the callee saved registers
+ sw r20,r1,r0
+ swi r21,r1,4
+ swi r22,r1,8
+ swi r23,r1,12
+ swi r24,r1,16
+ swi r25,r1,20
+ swi r26,r1,24
+ swi r27,r1,28
+
+# Load all the 16 bit values for A thru H
+ lhui r20,r1,44 # A
+ lhui r21,r1,46 # B
+ lhui r22,r1,48 # C
+ lhui r23,r1,50 # D
+ lhui r24,r1,52 # E
+ lhui r25,r1,54 # F
+ lhui r26,r1,56 # G
+ lhui r27,r1,58 # H
+
+# D * H ==> LSB of the result on stack ==> Store1
+ mul r9,r23,r27
+ swi r9,r1,36 # Pos2 and Pos3
+
+# Hi (Store1) + C * H + D * G ==> Store2 ==> Pos1 and Pos2
+# Store the carry generated in position 2 for Pos 3
+ lhui r11,r1,36 # Pos2
+ mul r9,r22,r27 # C * H
+ mul r10,r23,r26 # D * G
+ add r9,r9,r10
+ addc r12,r0,r0
+ add r9,r9,r11
+ addc r12,r12,r0 # Store the Carry
+ shi r9,r1,36 # Store Pos2
+ swi r9,r1,32
+ lhui r11,r1,32
+ shi r11,r1,34 # Store Pos1
+
+# Hi (Store2) + B * H + C * G + D * F ==> Store3 ==> Pos0 and Pos1
+ mul r9,r21,r27 # B * H
+ mul r10,r22,r26 # C * G
+ mul r7,r23,r25 # D * F
+ add r9,r9,r11
+ add r9,r9,r10
+ add r9,r9,r7
+ swi r9,r1,32 # Pos0 and Pos1
+
+# Hi (Store3) + A * H + B * G + C * F + D * E ==> Store3 ==> Pos0
+ lhui r11,r1,32 # Pos0
+ mul r9,r20,r27 # A * H
+ mul r10,r21,r26 # B * G
+ mul r7,r22,r25 # C * F
+ mul r8,r23,r24 # D * E
+ add r9,r9,r11
+ add r9,r9,r10
+ add r9,r9,r7
+ add r9,r9,r8
+ sext16 r9,r9 # Sign extend the MSB
+ shi r9,r1,32
+
+# Move results to r3 and r4
+ lhui r3,r1,32
+ add r3,r3,r12
+ shi r3,r1,32
+ lwi r3,r1,32 # Hi Part
+ lwi r4,r1,36 # Lo Part
+
+# Restore Callee saved registers
+ lw r20,r1,r0
+ lwi r21,r1,4
+ lwi r22,r1,8
+ lwi r23,r1,12
+ lwi r24,r1,16
+ lwi r25,r1,20
+ lwi r26,r1,24
+ lwi r27,r1,28
+
+# Restore Frame and return
+ rtsd r15,8
+ addi r1,r1,40
+
+.end muldi3_hardproc
+
+
Index: libgcc/config/microblaze/mulsi3.asm
===================================================================
--- libgcc/config/microblaze/mulsi3.asm (revision 0)
+++ libgcc/config/microblaze/mulsi3.asm (revision 0)
@@ -0,0 +1,69 @@
+###################################-*-asm*-
+#
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# mulsi3.asm
+#
+# Multiply operation for 32 bit integers.
+# Input : Operand1 in Reg r5
+# Operand2 in Reg r6
+# Output: Result [op1 * op2] in Reg r3
+#
+#######################################
+
+ .globl __mulsi3
+ .ent __mulsi3
+ .type __mulsi3,@function
+__mulsi3:
+ .frame r1,0,r15
+ add r3,r0,r0
+ BEQI r5,$L_Result_Is_Zero # Multiply by Zero
+ BEQI r6,$L_Result_Is_Zero # Multiply by Zero
+ BGEId r5,$L_R5_Pos
+ XOR r4,r5,r6 # Get the sign of the result
+ RSUBI r5,r5,0 # Make r5 positive
+$L_R5_Pos:
+ BGEI r6,$L_R6_Pos
+ RSUBI r6,r6,0 # Make r6 positive
+$L_R6_Pos:
+ bri $L1
+$L2:
+ add r5,r5,r5
+$L1:
+ srl r6,r6
+ addc r7,r0,r0
+ beqi r7,$L2
+ bneid r6,$L2
+ add r3,r3,r5
+ blti r4,$L_NegateResult
+ rtsd r15,8
+ nop
+$L_NegateResult:
+ rtsd r15,8
+ rsub r3,r3,r0
+$L_Result_Is_Zero:
+ rtsd r15,8
+ addi r3,r0,0
+ .end __mulsi3
+ .size __mulsi3, . - __mulsi3
Index: libgcc/config/microblaze/modsi3.asm
===================================================================
--- libgcc/config/microblaze/modsi3.asm (revision 0)
+++ libgcc/config/microblaze/modsi3.asm (revision 0)
@@ -0,0 +1,93 @@
+###################################
+#
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# modsi3.asm
+#
+# modulo operation for 32 bit integers.
+# Input : op1 in Reg r5
+# op2 in Reg r6
+# Output: op1 mod op2 in Reg r3
+#
+#######################################
+
+ .globl __modsi3
+ .ent __modsi3
+ .type __modsi3,@function
+__modsi3:
+ .frame r1,0,r15
+
+ addik r1,r1,-16
+ swi r28,r1,0
+ swi r29,r1,4
+ swi r30,r1,8
+ swi r31,r1,12
+
+ BEQI r6,$LaDiv_By_Zero # Div_by_Zero # Division Error
+ BEQI r5,$LaResult_Is_Zero # Result is Zero
+ BGEId r5,$LaR5_Pos
+ ADD r28,r5,r0 # Get the sign of the result [ Depends only on the first arg]
+ RSUBI r5,r5,0 # Make r5 positive
+$LaR5_Pos:
+ BGEI r6,$LaR6_Pos
+ RSUBI r6,r6,0 # Make r6 positive
+$LaR6_Pos:
+ ADDIK r3,r0,0 # Clear mod
+ ADDIK r30,r0,0 # clear div
+ ADDIK r29,r0,32 # Initialize the loop count
+ # First part try to find the first '1' in the r5
+$LaDIV1:
+ ADD r5,r5,r5 # left shift logical r5
+ BGEID r5,$LaDIV1 #
+ ADDIK r29,r29,-1
+$LaDIV2:
+ ADD r5,r5,r5 # left shift logical r5 get the '1' into the Carry
+ ADDC r3,r3,r3 # Move that bit into the Mod register
+ rSUB r31,r6,r3 # Try to subtract (r30 a r6)
+ BLTi r31,$LaMOD_TOO_SMALL
+ OR r3,r0,r31 # Move the r31 to mod since the result was positive
+ ADDIK r30,r30,1
+$LaMOD_TOO_SMALL:
+ ADDIK r29,r29,-1
+ BEQi r29,$LaLOOP_END
+ ADD r30,r30,r30 # Shift in the '1' into div
+ BRI $LaDIV2 # Div2
+$LaLOOP_END:
+ BGEI r28,$LaRETURN_HERE
+ BRId $LaRETURN_HERE
+ rsubi r3,r3,0 # Negate the result
+$LaDiv_By_Zero:
+$LaResult_Is_Zero:
+ or r3,r0,r0 # set result to 0 [Both mod as well as div are 0]
+$LaRETURN_HERE:
+# Restore values of CSRs and that of r3 and the divisor and the dividend
+ lwi r28,r1,0
+ lwi r29,r1,4
+ lwi r30,r1,8
+ lwi r31,r1,12
+ rtsd r15,8
+ addik r1,r1,16
+ .end __modsi3
+ .size __modsi3, . - __modsi3
+
Index: libgcc/config/microblaze/moddi3.asm
===================================================================
--- libgcc/config/microblaze/moddi3.asm (revision 0)
+++ libgcc/config/microblaze/moddi3.asm (revision 0)
@@ -0,0 +1,115 @@
+###################################
+#
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+#
+# Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+# later version.
+#
+# GCC 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# a copy of the GCC Runtime Library Exception along with this program;
+# see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+# <http://www.gnu.org/licenses/>.
+#
+# modsi3.asm
+#
+# modulo operation for 64 bit integers.
+#
+#######################################
+
+
+ .globl __moddi3
+ .ent __moddi3
+__moddi3:
+ .frame r1,0,r15
+
+#Change the stack pointer value and Save callee saved regs
+ addik r1,r1,-24
+ swi r25,r1,0
+ swi r26,r1,4
+ swi r27,r1,8 # used for sign
+ swi r28,r1,12 # used for loop count
+ swi r29,r1,16 # Used for div value High
+ swi r30,r1,20 # Used for div value Low
+
+#Check for Zero Value in the divisor/dividend
+ OR r9,r5,r6 # Check for the op1 being zero
+ BEQID r9,$LaResult_Is_Zero # Result is zero
+ OR r9,r7,r8 # Check for the dividend being zero
+ BEQI r9,$LaDiv_By_Zero # Div_by_Zero # Division Error
+ BGEId r5,$La1_Pos
+ XOR r27,r5,r7 # Get the sign of the result
+ RSUBI r6,r6,0 # Make dividend positive
+ RSUBIC r5,r5,0 # Make dividend positive
+$La1_Pos:
+ BGEI r7,$La2_Pos
+ RSUBI r8,r8,0 # Make Divisor Positive
+ RSUBIC r9,r9,0 # Make Divisor Positive
+$La2_Pos:
+ ADDIK r4,r0,0 # Clear mod low
+ ADDIK r3,r0,0 # Clear mod high
+ ADDIK r29,r0,0 # clear div high
+ ADDIK r30,r0,0 # clear div low
+ ADDIK r28,r0,64 # Initialize the loop count
+ # First part try to find the first '1' in the r5/r6
+$LaDIV1:
+ ADD r6,r6,r6
+ ADDC r5,r5,r5 # left shift logical r5
+ BGEID r5,$LaDIV1
+ ADDIK r28,r28,-1
+$LaDIV2:
+ ADD r6,r6,r6
+ ADDC r5,r5,r5 # left shift logical r5/r6 get the '1' into the Carry
+ ADDC r4,r4,r4 # Move that bit into the Mod register
+ ADDC r3,r3,r3 # Move carry into high mod register
+ rsub r18,r7,r3 # Compare the High Parts of Mod and Divisor
+ bnei r18,$L_High_EQ
+ rsub r18,r6,r4 # Compare Low Parts only if Mod[h] == Divisor[h]
+$L_High_EQ:
+ rSUB r26,r8,r4 # Subtract divisor[L] from Mod[L]
+ rsubc r25,r7,r3 # Subtract divisor[H] from Mod[H]
+ BLTi r25,$LaMOD_TOO_SMALL
+ OR r3,r0,r25 # move r25 to mod [h]
+ OR r4,r0,r26 # move r26 to mod [l]
+ ADDI r30,r30,1
+ ADDC r29,r29,r0
+$LaMOD_TOO_SMALL:
+ ADDIK r28,r28,-1
+ BEQi r28,$LaLOOP_END
+ ADD r30,r30,r30 # Shift in the '1' into div [low]
+ ADDC r29,r29,r29 # Move the carry generated into high
+ BRI $LaDIV2 # Div2
+$LaLOOP_END:
+ BGEI r27,$LaRETURN_HERE
+ rsubi r30,r30,0
+ rsubc r29,r29,r0
+ BRI $LaRETURN_HERE
+$LaDiv_By_Zero:
+$LaResult_Is_Zero:
+ or r29,r0,r0 # set result to 0 [High]
+ or r30,r0,r0 # set result to 0 [Low]
+$LaRETURN_HERE:
+# Restore values of CSRs and that of r29 and the divisor and the dividend
+
+ lwi r25,r1,0
+ lwi r26,r1,4
+ lwi r27,r1,8
+ lwi r28,r1,12
+ lwi r29,r1,16
+ lwi r30,r1,20
+ rtsd r15,8
+ addik r1,r1,24
+ .end __moddi3
+
Index: libgcc/ChangeLog
===================================================================
--- libgcc/ChangeLog (revision 164569)
+++ libgcc/ChangeLog (working copy)
@@ -1,3 +1,10 @@
+2010-09-28 Michael Eager <eager@eagercon.com>
+
+ * config.host: Add microblaze*-*-*.
+ * config/microblaze/{divsi3.asm,divsi3_table.c,moddi3.asm,modsi3.asm,
+ muldi3_hard.asm,mulsi3.asm,stack_overflow_exit.asm,t-microblaze,
+ udivsi3.asm,umodsi3.asm}: New.
+
2010-09-21 Iain Sandoe <iains@gcc.gnu.org>
* Makefile.in (libgcc-extra-parts): Check for static archives and
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi (revision 164569)
+++ gcc/doc/extend.texi (working copy)
@@ -2533,8 +2533,8 @@
sequences suitable for use in an interrupt handler when this attribute
is present.
-Note, interrupt handlers for the Blackfin, H8/300, H8/300H, H8S, and
-SH processors can be specified via the @code{interrupt_handler} attribute.
+Note, interrupt handlers for the Blackfin, H8/300, H8/300H, H8S, MicroBlaze,
+and SH processors can be specified via the @code{interrupt_handler} attribute.
Note, on the AVR, interrupts will be enabled inside the function.
@@ -3100,6 +3100,14 @@
all registers except the stack pointer should be saved in the prologue
regardless of whether they are used or not.
+@item save_volatiles
+@cindex save volatile registers on the MicroBlaze
+Use this attribute on the MicroBlaze to indicate that the function is
+an interrupt handler. All volatile registers (in addition to non-volatile
+registers) will be saved in the function prologue. If the function is a leaf
+function, only volatiles used by the function are saved. A normal function
+return is generated instead of a return from interrupt.
+
@item section ("@var{section-name}")
@cindex @code{section} function attribute
Normally, the compiler places the code it generates in the @code{text} section.
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi (revision 164569)
+++ gcc/doc/invoke.texi (working copy)
@@ -682,6 +682,13 @@
-mmult -mno-opts -mrepeat -ms -msatur -msdram -msim -msimnovec -mtf @gol
-mtiny=@var{n}}
+@emph{MicroBlaze Options}
+@gccoptlist{-msoft-float -mhard-float -msmall-divides -mcpu=@var{cpu} @gol
+-mmemcpy -mxl-soft-mul -mxl-soft-div -mxl-barrel-shift @gol
+-mxl-pattern-compare -mxl-stack-check -mxl-gp-opt -mno-clearbss @gol
+-mxl-multiply-high -mxl-float-convert -mxl-float-sqrt @gol
+-mxl-mode-@var{app-model}}
+
@emph{MIPS Options}
@gccoptlist{-EL -EB -march=@var{arch} -mtune=@var{arch} @gol
-mips1 -mips2 -mips3 -mips4 -mips32 -mips32r2 @gol
@@ -9904,6 +9911,7 @@
* M68hc1x Options::
* MCore Options::
* MeP Options::
+* MicroBlaze Options::
* MIPS Options::
* MMIX Options::
* MN10300 Options::
@@ -13877,6 +13885,104 @@
@end table
+@node MicroBlaze Options
+@subsection MicroBlaze Options
+@cindex MicroBlaze Options
+
+@table @gcctabopt
+
+@item -msoft-float
+@opindex msoft-float
+Use software emulation for floating point (default).
+
+@item -mhard-float
+@opindex mhard-float
+Use hardware floating point instructions.
+
+@item -mmemcpy
+@opindex mmemcpy
+Do not optimize block moves, use @code{memcpy}.
+
+@item -mno-clearbss
+@opindex mno-clearbss
+This option is deprecated. Use @option{-fno-zero-initialized-in-bss} instead.
+
+@item -mcpu=@var{cpu-type}
+@opindex mcpu=
+Use features of and schedule code for given CPU.
+Supported values are in the format @var{vX.YY.Z}, where X is a major version, YY
+is the minor version, and Z is compatiblity code. Example values are
+@samp{v3.00.a}, @samp{v4.00.b}, @samp{v5.00.a}, @samp{v5.00.b},
+@samp{v5.00.b}, @samp{v6.00.a}.
+
+@item -mxl-soft-mul
+@opindex mxl-soft-mul
+Use software multiply emulation (default).
+
+@item -mxl-soft-div
+@opindex mxl-soft-div
+Use software emulation for divides (default).
+
+@item -mxl-barrel-shift
+@opindex mxl-barrel-shift
+Use the hardware barrel shifter.
+
+@item -mxl-pattern-compare
+@opindex mxl-pattern-compare
+Use pattern compare instructions.
+
+@item -msmall-divides
+@opindex msmall-divides
+Use table lookup optimization for small signed integer divisions.
+
+@item -mxl-stack-check
+@opindex mxl-stack-check
+This option is deprecated. Use -fstack-check instead.
+
+@item -mxl-gp-opt
+@opindex mxl-gp-opt
+Use GP relative sdata/sbss sections.
+
+@item -mxl-multiply-high
+@opindex mxl-multiply-high
+Use multiply high instructions for high part of 32x32 multiply.
+
+@item -mxl-float-convert
+@opindex mxl-float-convert
+Use hardware floating point converstion instructions.
+
+@item -mxl-float-sqrt
+@opindex mxl-float-sqrt
+Use hardware floating point square root instruction.
+
+@item -mxl-mode-@var{app-model}
+Select application model @var{app-model}. Valid models are
+@table @samp
+@item executable
+normal executable (default), uses startup code @file{crt0.o}.
+
+@item xmdstub
+for use with Xilinx Microprocessor Debugger (XMD) based
+software intrusive debug agent called xmdstub. This uses startup file
+@file{crt1.o} and sets the start address of the program to be 0x800.
+
+@item bootstrap
+for applications that are loaded using a bootloader.
+This model uses startup file @file{crt2.o} which does not contain a processor
+reset vector handler. This is suitable for transferring control on a
+processor reset to the bootloader rather than the application.
+
+@item novectors
+for applications that do not require any of the
+MicroBlaze vectors. This option may be useful for applications running
+within a monitoring application. This model uses @file{crt3.o} as a startup file.
+@end table
+
+Option @option{-xl-mode-@var{app-model}} is a deprecated alias for
+@option{-mxl-mode-@var{app-model}}.
+
+@end table
+
@node MIPS Options
@subsection MIPS Options
@cindex MIPS options
Index: gcc/doc/contrib.texi
===================================================================
--- gcc/doc/contrib.texi (revision 164569)
+++ gcc/doc/contrib.texi (working copy)
@@ -239,6 +239,9 @@
Zdenek Dvorak for a new loop unroller and various fixes.
@item
+Michael Eager for his work on the Xilinx MicroBlaze port.
+
+@item
Richard Earnshaw for his ongoing work with the ARM@.
@item
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi (revision 164569)
+++ gcc/doc/md.texi (working copy)
@@ -2677,8 +2677,16 @@
@item Z
Symbolic references to the control bus.
+@end table
+@item MicroBlaze---@file{config/microblaze/constraints.md}
+@table @code
+@item d
+A general register (@code{r0} to @code{r31}).
+@item z
+A status register (@code{rmsr}, @code{$fcc1} to @code{$fcc7}).
+
@end table
@item MIPS---@file{config/mips/constraints.md}
Index: gcc/doc/install.texi
===================================================================
--- gcc/doc/install.texi (revision 164569)
+++ gcc/doc/install.texi (working copy)
@@ -2928,6 +2928,8 @@
@item
@uref{#mep-x-elf,,mep-*-elf}
@item
+@uref{#microblaze-x-elf,,microblaze-*-elf}
+@item
@uref{#mips-x-x,,mips-*-*}
@item
@uref{#mips-sgi-irix5,,mips-sgi-irix5}
@@ -3798,6 +3800,13 @@
@html
<hr />
@end html
+@heading @anchor{microblaze-x-elf}microblaze-*-elf
+Xilinx MicroBlaze processor.
+This configuration is intended for embedded systems.
+
+@html
+<hr />
+@end html
@heading @anchor{mips-x-x}mips-*-*
If on a MIPS system you get an error message saying ``does not have gp
sections for all it's [sic] sectons [sic]'', don't worry about it. This
Index: gcc/configure
===================================================================
--- gcc/configure (revision 164569)
+++ gcc/configure (working copy)
@@ -24515,7 +24515,7 @@
i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* \
| x86_64*-*-* | hppa*-*-* | arm*-*-* \
| xstormy16*-*-* | cris-*-* | crisv32-*-* | xtensa*-*-* | bfin-*-* | score*-*-* \
- | spu-*-* | fido*-*-* | m32c-*-*)
+ | spu-*-* | fido*-*-* | m32c-*-* | microblaze-*-*)
insn="nop"
;;
ia64*-*-* | s390*-*-*)
Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog (revision 164569)
+++ gcc/ChangeLog (working copy)
@@ -1,3 +1,27 @@
+2010-09-28 Michael Eager <eager@eagercon.com>
+
+ * extend.texi (interrupt_handler): Add MicroBlaze to list.
+ (save_volatiles): Describe option for MicroBlaze.
+ * invoke.texi: Add MicroBlaze Options.
+ * contrib.texi: Add acknowledgment.
+ * md.texi: Add MicroBlaze d and z constraints.
+ * install.texi: Add microblaze-*-elf.
+ * configure.ac: Add microblaze-*-* to target list.
+ * configure: Regenerate.
+ * config.gcc: Add microblaze*-*-*, microblaze*-linux*.
+ * config/microblaze/microblaze-protos.h: New.
+ * config/microblaze/crti.s: New.
+ * config/microblaze/predicates.md: New.
+ * config/microblaze/linux.h: New.
+ * config/microblaze/microblaze.md: New.
+ * config/microblaze/constraints.md: New.
+ * config/microblaze/crtn.s: New.
+ * config/microblaze/microblaze.opt: New.
+ * config/microblaze/microblaze-c.c: New.
+ * config/microblaze/t-microblaze: New.
+ * config/microblaze/microblaze.c: New.
+ * config/microblaze/microblaze.h: New.
+
2010-09-23 Anatoly Sokolov <aesok@post.ru>
* config/arm/arm.h (OUTPUT_ADDR_CONST_EXTRA): Remove.
Index: gcc/testsuite/gcc.c-torture/execute/cmpsi-2.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/cmpsi-2.c (revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/cmpsi-2.c (revision 0)
@@ -0,0 +1,199 @@
+#define F 140
+#define T 13
+
+feq (long x, long y)
+{
+ if (x == y)
+ return T;
+ else
+ return F;
+}
+
+fne (long x, long y)
+{
+ if (x != y)
+ return T;
+ else
+ return F;
+}
+
+flt (long x, long y)
+{
+ if (x < y)
+ return T;
+ else
+ return F;
+}
+
+fge (long x, long y)
+{
+ if (x >= y)
+ return T;
+ else
+ return F;
+}
+
+fgt (long x, long y)
+{
+ if (x > y)
+ return T;
+ else
+ return F;
+}
+
+fle (long x, long y)
+{
+ if (x <= y)
+ return T;
+ else
+ return F;
+}
+
+fltu (long x, long y)
+{
+ if (x < y)
+ return T;
+ else
+ return F;
+}
+
+fgeu (long x, long y)
+{
+ if (x >= y)
+ return T;
+ else
+ return F;
+}
+
+fgtu (long x, long y)
+{
+ if (x > y)
+ return T;
+ else
+ return F;
+}
+
+fleu (long x, long y)
+{
+ if (x <= y)
+ return T;
+ else
+ return F;
+}
+
+long args[] =
+{
+ 0L,
+ 1L,
+ -1L,
+ 0x7fffffffL,
+ 0x80000000L,
+ 0x80000001L,
+ 0x1A3F2373L,
+ 0x93850E92L
+};
+
+int correct_results[] =
+{
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, T, F, F, T,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T
+};
+
+int
+main (void)
+{
+ int i, j, *res = correct_results;
+
+ for (i = 0; i < 8; i++)
+ {
+ long arg0 = args[i];
+ for (j = 0; j < 8; j++)
+ {
+ long arg1 = args[j];
+
+ if (feq (arg0, arg1) != *res++)
+ abort ();
+ if (fne (arg0, arg1) != *res++)
+ abort ();
+ if (flt (arg0, arg1) != *res++)
+ abort ();
+ if (fge (arg0, arg1) != *res++)
+ abort ();
+ if (fgt (arg0, arg1) != *res++)
+ abort ();
+ if (fle (arg0, arg1) != *res++)
+ abort ();
+ if (fltu (arg0, arg1) != *res++)
+ abort ();
+ if (fgeu (arg0, arg1) != *res++)
+ abort ();
+ if (fgtu (arg0, arg1) != *res++)
+ abort ();
+ if (fleu (arg0, arg1) != *res++)
+ abort ();
+ }
+ }
+ exit (0);
+}
Index: gcc/testsuite/gcc.c-torture/execute/cmpsf-1.c
===================================================================
--- gcc/testsuite/gcc.c-torture/execute/cmpsf-1.c (revision 0)
+++ gcc/testsuite/gcc.c-torture/execute/cmpsf-1.c (revision 0)
@@ -0,0 +1,169 @@
+#include <limits.h>
+
+#define F 140
+#define T 13
+
+feq (float x, float y)
+{
+ if (x == y)
+ return T;
+ else
+ return F;
+}
+
+fne (float x, float y)
+{
+ if (x != y)
+ return T;
+ else
+ return F;
+}
+
+flt (float x, float y)
+{
+ if (x < y)
+ return T;
+ else
+ return F;
+}
+
+fge (float x, float y)
+{
+ if (x >= y)
+ return T;
+ else
+ return F;
+}
+
+fgt (float x, float y)
+{
+ if (x > y)
+ return T;
+ else
+ return F;
+}
+
+fle (float x, float y)
+{
+ if (x <= y)
+ return T;
+ else
+ return F;
+}
+
+float args[] =
+{
+ 0.0F,
+ 1.0F,
+ -1.0F,
+ FLOAT_MAX,
+ FLOAT_MIN,
+ 0.0000000000001F,
+ 123456789.0F,
+ -987654321.0F
+};
+
+int correct_results[] =
+{
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, T, F, F, T,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ T, F, F, T, F, T, F, T, F, T,
+ F, T, F, T, T, F, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, T, F, F, T, T, F, F, T,
+ F, T, T, F, F, T, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, F, T, T, F, F, T, T, F,
+ F, T, T, F, F, T, F, T, T, F,
+ T, F, F, T, F, T, F, T, F, T
+};
+
+int
+main (void)
+{
+ int i, j, *res = correct_results;
+
+ for (i = 0; i < 8; i++)
+ {
+ long arg0 = args[i];
+ for (j = 0; j < 8; j++)
+ {
+ long arg1 = args[j];
+
+ if (feq (arg0, arg1) != *res++)
+ abort ();
+ if (fne (arg0, arg1) != *res++)
+ abort ();
+ if (flt (arg0, arg1) != *res++)
+ abort ();
+ if (fge (arg0, arg1) != *res++)
+ abort ();
+ if (fgt (arg0, arg1) != *res++)
+ abort ();
+ if (fle (arg0, arg1) != *res++)
+ abort ();
+ if (fltu (arg0, arg1) != *res++)
+ abort ();
+ if (fgeu (arg0, arg1) != *res++)
+ abort ();
+ if (fgtu (arg0, arg1) != *res++)
+ abort ();
+ if (fleu (arg0, arg1) != *res++)
+ abort ();
+ }
+ }
+ exit (0);
+}
Index: gcc/testsuite/gcc.target/microblaze/microblaze.exp
===================================================================
--- gcc/testsuite/gcc.target/microblaze/microblaze.exp (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/microblaze.exp (revision 0)
@@ -0,0 +1,62 @@
+# Copyright 2009, 2010 Free Software Foundation, Inc.
+
+# 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 3 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 GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+
+# MicroBlaze test driver that uses the `dg.exp' driver.
+
+# Exit immediately if this isn't a MicroBlaze target.
+if { ![istarget microblaze*-*-*] } then {
+ return
+}
+
+# Don't execute when we are testing some configuration of GCC or G++.
+# This we figure out by looking at target_config_cflags which needs to be "" for microblaze.exp
+if { $target_config_cflags != "" } {
+ return
+}
+
+global TORTURE_OPTIONS
+set TORTURE_OPTIONS [list \
+ { -O0 } \
+ { -O1 } \
+ { -O2 } \
+ { -O3 } \
+ { -Os } ]
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CFLAGS
+if ![info exists DEFAULT_CFLAGS] then {
+ set DEFAULT_CFLAGS " -ansi -pedantic-errors"
+}
+
+# Load support procs.
+load_lib gcc-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+set default_c_flags ""
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/isa/*.\[cSi\]]] \
+${default_c_flags} ""
+
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/others/*.\[cSi\]]] \
+ "-mcpu=v6.00.a"
+
+
+# All done.
+dg-finish
Index: gcc/testsuite/gcc.target/microblaze/others/string_cst1.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/string_cst1.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/string_cst1.c (revision 0)
@@ -0,0 +1,12 @@
+#include <string.h>
+
+/* { dg-final { scan-assembler "\.rodata*" } } */
+/* { dg-final { scan-assembler "\.data*" } } */
+
+char *string1 = "string1";
+
+int testfunc (char *cptr)
+{
+/* { dg-final { scan-assembler-not "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ strcpy (string1, cptr);
+}
Index: gcc/testsuite/gcc.target/microblaze/others/string_cst2.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/string_cst2.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/string_cst2.c (revision 0)
@@ -0,0 +1,13 @@
+#include <string.h>
+
+/* { dg-final { scan-assembler "\.rodata*" } } */
+/* { dg-final { scan-assembler "\.data*" } } */
+const char *string1 = "string1";
+
+char* testfunc (char *cptr)
+{
+/* { dg-final { scan-assembler-not "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ strcpy (cptr, string1);
+
+ return cptr;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/data_var1.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/data_var1.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/data_var1.c (revision 0)
@@ -0,0 +1,8 @@
+/* { dg-final { scan-assembler "\.bss*" } } */
+int global;
+
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r0" } } */
+ return global;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/data_var2.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/data_var2.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/data_var2.c (revision 0)
@@ -0,0 +1,8 @@
+/* { dg-final { scan-assembler "\.data*" } } */
+int global = 10;
+
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r0" } } */
+ return global;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/data_var3.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/data_var3.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/data_var3.c (revision 0)
@@ -0,0 +1,7 @@
+/* { dg-final { scan-assembler "\.rodata*" } } */
+const int global = 10;
+
+int testfunc ()
+{
+ return global;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/string_cst1_gpopt.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/string_cst1_gpopt.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/string_cst1_gpopt.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-options "-mxl-gp-opt" } */
+
+#include <string.h>
+
+/* { dg-final { scan-assembler "\.rodata*" } } */
+/* { dg-final { scan-assembler "\.sdata\[^2]+" } } */
+char *string1 = "string1";
+
+int testfunc (char *cptr)
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ strcpy (string1, cptr);
+}
Index: gcc/testsuite/gcc.target/microblaze/others/strings1.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/strings1.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/strings1.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-options "-O3" } */
+
+#include <string.h>
+
+/* { dg-final { scan-assembler "\.rodata*" } } */
+extern void somefunc (char *);
+int testfunc ()
+{
+ char string2[80];
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r0,.LC*" } } */
+ strcpy (string2, "hello");
+ somefunc (string2);
+}
Index: gcc/testsuite/gcc.target/microblaze/others/string_cst2_gpopt.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/string_cst2_gpopt.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/string_cst2_gpopt.c (revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "-mxl-gp-opt" } */
+
+#include <string.h>
+
+/* { dg-final { scan-assembler "\.rodata*" } } */
+/* { dg-final { scan-assembler "\.sdata\[^2]+" } } */
+const char *string1 = "string1";
+
+char* testfunc (char *cptr)
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ strcpy (cptr, string1);
+
+ return cptr;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/interrupt_handler_leaf.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/interrupt_handler_leaf.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/interrupt_handler_leaf.c (revision 0)
@@ -0,0 +1,10 @@
+int leaf_func () __attribute__ ((interrupt_handler));
+volatile int intr_occurred;
+
+int leaf_func ()
+{
+
+ /* { dg-final { scan-assembler "rtid\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),0" } } */
+ /* { dg-final { scan-assembler-not "rtsd" } } */
+ intr_occurred += 1;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/sdata_var1.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/sdata_var1.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/sdata_var1.c (revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "-mxl-gp-opt" } */
+
+/* { dg-final { scan-assembler "\.sbss\[^2]+" } } */
+typedef int Boolean;
+volatile Boolean global = 0;
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ return global;
+}
+
+int main ()
+{
+
+}
Index: gcc/testsuite/gcc.target/microblaze/others/sdata_var2.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/sdata_var2.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/sdata_var2.c (revision 0)
@@ -0,0 +1,10 @@
+/* { dg-options "-mxl-gp-opt" } */
+
+/* { dg-final { scan-assembler "\.sdata\[^2]+" } } */
+int global = 10;
+
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ return global;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/sdata_var3.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/sdata_var3.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/sdata_var3.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-options "-mxl-gp-opt" } */
+
+extern int a;
+
+/* { dg-final { scan-assembler "\.sdata2" } } */
+const int global1 = 10;
+extern const int global2;
+
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r2" } } */
+ return global2 + global1;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/sdata_var4.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/sdata_var4.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/sdata_var4.c (revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "-mxl-gp-opt -G 16" } */
+
+/* { dg-final { scan-assembler "\.sbss\[^2]+" } } */
+struct test_s {
+ int a;
+ int b;
+ int c;
+ int d;
+} global;
+
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ return global.a;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/sdata_var5.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/sdata_var5.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/sdata_var5.c (revision 0)
@@ -0,0 +1,15 @@
+/* { dg-options "-mxl-gp-opt -G 16" } */
+
+/* { dg-final { scan-assembler "\.sdata\[^2]+" } } */
+struct test_s {
+ int a;
+ int b;
+ int c;
+ int d;
+} global = { 1, 2, 3, 4 };
+
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r13" } } */
+ return global.a;
+}
Index: gcc/testsuite/gcc.target/microblaze/others/sdata_var6.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/others/sdata_var6.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/others/sdata_var6.c (revision 0)
@@ -0,0 +1,18 @@
+/* { dg-options "-mxl-gp-opt -G 16" } */
+
+struct test_s {
+ int a;
+ int b;
+ int c;
+ int d;
+};
+
+/* { dg-final { scan-assembler "\.sdata2" } } */
+const struct test_s global1 = { 1, 2, 3, 4};
+extern const struct test_s global2;
+
+int testfunc ()
+{
+/* { dg-final { scan-assembler "\lwi\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r2" } } */
+ return global2.a + global1.a;
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/fsqrt.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/fsqrt.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/fsqrt.c (revision 0)
@@ -0,0 +1,10 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mhard-float -mxl-float-sqrt" } */
+#include <math.h>
+
+float sqrt_func (float f)
+{
+ /* { dg-final { scan-assembler "fsqrt\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ return sqrtf (f);
+}
+
+
Index: gcc/testsuite/gcc.target/microblaze/isa/pcmp.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/pcmp.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/pcmp.c (revision 0)
@@ -0,0 +1,52 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mxl-pattern-compare" } */
+
+volatile int m1, m2, m3;
+volatile long l1, l2;
+volatile long long llp;
+volatile unsigned int u1, u2, u3;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler-not "mul\tr" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler-not "muli" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler-not "mulh" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler-not "mulhu" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler-not "mulhsu" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler-not "bslli" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler-not "bsll" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler-not "bsrai" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler-not "bsra" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler "pcmpne" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler "pcmpeq" } } */
+ return (m1 == m2);
+}
+
Index: gcc/testsuite/gcc.target/microblaze/isa/nofloat.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/nofloat.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/nofloat.c (revision 0)
@@ -0,0 +1,19 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -msoft-float" } */
+
+volatile float f1, f2, f3;
+
+void float_func ()
+{
+ /* { dg-final { scan-assembler-not "fmul" } } */
+ f1 = f2 * f3;
+
+ /* { dg-final { scan-assembler-not "fadd" } } */
+ f1 = f2 + f3;
+
+ /* { dg-final { scan-assembler-not "frsub" } } */
+ f1 = f2 - f3;
+
+ /* { dg-final { scan-assembler-not "fdiv" } } */
+ f1 = f2 / f3;
+
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/fcvt.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/fcvt.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/fcvt.c (revision 0)
@@ -0,0 +1,21 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mhard-float -mxl-float-convert" } */
+
+int float_func (float f)
+{
+ /* { dg-final { scan-assembler "flt\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ return f;
+}
+
+
+float int_func (int i)
+{
+ /* { dg-final { scan-assembler "fint\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ return i;
+}
+
+
+float uint_func (unsigned int i)
+{
+ /* { dg-final { scan-assembler "fint\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ return i;
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/float.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/float.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/float.c (revision 0)
@@ -0,0 +1,18 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mhard-float" } */
+
+volatile float f1, f2, f3;
+
+void float_func ()
+{
+ /* { dg-final { scan-assembler "fmul\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ f1 = f2 * f3;
+
+ /* { dg-final { scan-assembler "fadd\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ f1 = f2 + f3;
+
+ /* { dg-final { scan-assembler "frsub\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ f1 = f2 - f3;
+
+ /* { dg-final { scan-assembler "fdiv\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ f1 = f2 / f3;
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/mulh.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/mulh.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/mulh.c (revision 0)
@@ -0,0 +1,53 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mno-xl-soft-mul -mxl-multiply-high" } */
+
+volatile int m1, m2, m3;
+volatile unsigned int u1, u2, u3;
+volatile long l1, l2;
+volatile long long llp;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler "mul\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler "muli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),(0x\[0-9a-fA-F]+|\[+-]*\[0-9]+)" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler "mulh\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler "mulhu\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler "mulhsu\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler-not "bslli" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler-not "bsll" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler-not "bsrai" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler-not "bsra" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler-not "pcmpne" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler-not "pcmpeq" } } */
+ return (m1 == m2);
+
+}
+
Index: gcc/testsuite/gcc.target/microblaze/isa/fcmp1.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/fcmp1.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/fcmp1.c (revision 0)
@@ -0,0 +1,10 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mhard-float" } */
+
+volatile float f1, f2, f3;
+
+void float_func ()
+{
+ /* { dg-final { scan-assembler "fcmp\.(le|gt)\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ if (f2 <= f3)
+ print ("le");
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/mul-bshift-pcmp.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/mul-bshift-pcmp.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/mul-bshift-pcmp.c (revision 0)
@@ -0,0 +1,53 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mxl-barrel-shift -mno-xl-soft-mul -mxl-pattern-compare" } */
+
+volatile int m1, m2, m3;
+volatile unsigned int u1, u2, u3;
+volatile long l1, l2;
+volatile long long llp;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler "mul\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler "muli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),(0x\[0-9a-fA-F]+|\[+-]*\[0-9]+)" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler-not "mulh" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler-not "mulhu" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler-not "mulhsu" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler "bslli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler "bsll\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler "bsrai\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler "bsra\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler "pcmpne\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler "pcmpeq\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ return (m1 == m2);
+
+}
+
Index: gcc/testsuite/gcc.target/microblaze/isa/fcmp2.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/fcmp2.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/fcmp2.c (revision 0)
@@ -0,0 +1,10 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mhard-float" } */
+
+volatile float f1, f2, f3;
+
+void float_func ()
+{
+ /* { dg-final { scan-assembler "fcmp\.(lt|ge)\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ if (f2 < f3)
+ print ("lt");
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/fcmp3.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/fcmp3.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/fcmp3.c (revision 0)
@@ -0,0 +1,10 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mhard-float" } */
+
+volatile float f1, f2, f3;
+
+void float_func ()
+{
+ /* { dg-final { scan-assembler "fcmp\.(eq|ne)\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ if (f2 == f3)
+ print ("eq");
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/mul-bshift.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/mul-bshift.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/mul-bshift.c (revision 0)
@@ -0,0 +1,53 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mxl-barrel-shift -mno-xl-soft-mul" } */
+
+volatile int m1, m2, m3;
+volatile unsigned int u1, u2, u3;
+volatile long l1, l2;
+volatile long long llp;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler "mul\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler "muli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),(0x\[0-9a-fA-F]+|\[+-]*\[0-9]+)" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler-not "mulh" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler-not "mulhu" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler-not "mulhsu" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler "bslli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler "bsll\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler "bsrai\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler "bsra\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler-not "pcmpne" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler-not "pcmpeq" } } */
+ return (m1 == m2);
+
+}
+
Index: gcc/testsuite/gcc.target/microblaze/isa/mulh-bshift-pcmp.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/mulh-bshift-pcmp.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/mulh-bshift-pcmp.c (revision 0)
@@ -0,0 +1,53 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mxl-barrel-shift -mno-xl-soft-mul -mxl-pattern-compare -mxl-multiply-high" } */
+
+volatile int m1, m2, m3;
+volatile unsigned int u1, u2, u3;
+volatile long l1, l2;
+volatile long long llp;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler "mul\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler "muli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),(0x\[0-9a-fA-F]+|\[+-]*\[0-9]+)" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler "mulh\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ llp = (long long)l1 * l2;
+
+ /* { dg-final { scan-assembler "mulhu\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ ullp = (unsigned long long)ul1 * ul2;
+
+ /* { dg-final { scan-assembler "mulhsu\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ llp = (long long)l1 * ul2;
+
+ /* { dg-final { scan-assembler "bslli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler "bsll\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler "bsrai\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler "bsra\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler "pcmpne\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler "pcmpeq\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ return (m1 == m2);
+
+}
+
Index: gcc/testsuite/gcc.target/microblaze/isa/bshift.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/bshift.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/bshift.c (revision 0)
@@ -0,0 +1,53 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mxl-barrel-shift" } */
+
+volatile int m1, m2, m3;
+volatile unsigned int u1, u2, u3;
+volatile long l1, l2;
+volatile long long llp;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler-not "mul\tr" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler-not "muli" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler-not "mulh" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler-not "mulhu" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler-not "mulhsu" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler "bslli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler "bsll\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler "bsrai\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),25" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler "bsra\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler-not "pcmpne" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler-not "pcmpeq" } } */
+ return (m1 == m2);
+
+}
+
Index: gcc/testsuite/gcc.target/microblaze/isa/nofcmp.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/nofcmp.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/nofcmp.c (revision 0)
@@ -0,0 +1,21 @@
+/* { dg-options "-O3 -mcpu=v6.00.a " } */
+
+volatile float f1, f2, f3;
+
+void float_func ()
+{
+ /* { dg-final { scan-assembler-not "fcmp" } } */
+ if (f2 <= f3)
+ print ("le");
+ else if (f2 == f3)
+ print ("eq");
+ else if (f2 < f3)
+ print ("lt");
+ else if (f2 > f3)
+ print ("gt");
+ else if (f2 >= f3)
+ print ("ge");
+ else if (f2 != f3)
+ print ("ne");
+
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/div.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/div.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/div.c (revision 0)
@@ -0,0 +1,52 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mno-xl-soft-div" } */
+
+volatile int m1, m2, m3;
+volatile long l1, l2;
+volatile long long llp;
+volatile unsigned int u1, u2, u3;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler-not "mul\tr" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler-not "muli" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler-not "mulh" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler-not "mulhu" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler-not "mulhsu" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler-not "bslli" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler-not "bsll" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler-not "bsrai" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler-not "bsra" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler-not "pcmpne" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler-not "pcmpeq" } } */
+ return (m1 == m2);
+}
+
Index: gcc/testsuite/gcc.target/microblaze/isa/vanilla.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/vanilla.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/vanilla.c (revision 0)
@@ -0,0 +1,89 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mcpu=v6.00.a" } */
+
+volatile int m1, m2, m3;
+volatile long l1, l2;
+volatile long long llp;
+volatile unsigned int u1, u2, u3;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler-not "mul\tr" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler-not "muli" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler-not "mulh" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler-not "mulhu" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler-not "mulhsu" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler-not "bslli" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler-not "bsll" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler-not "bsrai" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler-not "bsra" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler-not "pcmpne" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler-not "pcmpeq" } } */
+ return (m1 == m2);
+}
+
+
+
+volatile float f1, f2, f3;
+
+void float_func ()
+{
+ /* { dg-final { scan-assembler-not "fmul" } } */
+ f1 = f2 * f3;
+
+ /* { dg-final { scan-assembler-not "fadd" } } */
+ f1 = f2 + f3;
+
+ /* { dg-final { scan-assembler-not "frsub" } } */
+ f1 = f2 - f3;
+
+ /* { dg-final { scan-assembler-not "fdiv" } } */
+ f1 = f2 / f3;
+
+}
+
+void float_cmp_func ()
+{
+ /* { dg-final { scan-assembler-not "fcmp" } } */
+ if (f2 <= f3)
+ print ("le");
+ else if (f2 == f3)
+ print ("eq");
+ else if (f2 < f3)
+ print ("lt");
+ else if (f2 > f3)
+ print ("gt");
+ else if (f2 >= f3)
+ print ("ge");
+ else if (f2 != f3)
+ print ("ne");
+
+}
Index: gcc/testsuite/gcc.target/microblaze/isa/mul.c
===================================================================
--- gcc/testsuite/gcc.target/microblaze/isa/mul.c (revision 0)
+++ gcc/testsuite/gcc.target/microblaze/isa/mul.c (revision 0)
@@ -0,0 +1,52 @@
+/* { dg-options "-O3 -mcpu=v6.00.a -mno-xl-soft-mul" } */
+
+volatile int m1, m2, m3;
+volatile long l1, l2;
+volatile long long llp;
+volatile unsigned int u1, u2, u3;
+
+volatile unsigned long ul1, ul2;
+volatile unsigned long long ullp;
+
+int test_mul () {
+
+ /* { dg-final { scan-assembler "mul\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1])\[^0-9]" } } */
+ m1 = m2 * m3 ;
+
+ /* { dg-final { scan-assembler "muli\tr(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),r(\[0-9]\|\[1-2]\[0-9]\|3\[0-1]),(0x\[0-9a-fA-F]+|\[+-]*\[0-9]+)" } } */
+ m3 = m1 * 1234 ;
+
+ /* { dg-final { scan-assembler-not "mulh" } } */
+ llp = ((long long)l1 * l2);
+
+ /* { dg-final { scan-assembler-not "mulhu" } } */
+ ullp = ((unsigned long long)ul1 * ul2);
+
+ /* { dg-final { scan-assembler-not "mulhsu" } } */
+ llp = ((long long)l1 * ul2);
+
+ /* { dg-final { scan-assembler-not "bslli" } } */
+ m3 = m2 << 25;
+
+ /* { dg-final { scan-assembler-not "bsll" } } */
+ m2 = m1 << m3;
+
+ /* { dg-final { scan-assembler-not "bsrai" } } */
+ m3 = m2 >> 25;
+
+ /* { dg-final { scan-assembler-not "bsra" } } */
+ m2 = m1 >> m3;
+
+ /* { dg-final { scan-assembler-not "idiv" } } */
+ m1 = m2 / m1;
+
+ /* { dg-final { scan-assembler-not "idivu" } } */
+ u1 = u2 / u3;
+
+ /* { dg-final { scan-assembler-not "pcmpne" } } */
+ m3 = (m3 != m1);
+
+ /* { dg-final { scan-assembler-not "pcmpeq" } } */
+ return (m1 == m2);
+}
+
Index: gcc/testsuite/ChangeLog
===================================================================
--- gcc/testsuite/ChangeLog (revision 164569)
+++ gcc/testsuite/ChangeLog (working copy)
@@ -1,3 +1,42 @@
+2010-09-28 Michael Eager <eager@eagercon.com>
+
+ * gcc.c-torture/execute/cmpsi-2.c: New testcase.
+ * gcc.c-torture/execute/cmpsf-1.c: Ditto.
+ * gcc.target/microblaze/microblaze.exp: Ditto.
+ * gcc.target/microblaze/others/string_cst1.c: Ditto.
+ * gcc.target/microblaze/others/string_cst2.c: Ditto.
+ * gcc.target/microblaze/others/data_var1.c: Ditto.
+ * gcc.target/microblaze/others/data_var2.c: Ditto.
+ * gcc.target/microblaze/others/data_var3.c: Ditto.
+ * gcc.target/microblaze/others/string_cst1_gpopt.c:: Ditto.
+ * gcc.target/microblaze/others/strings1.c:: Ditto.
+ * gcc.target/microblaze/others/string_cst2_gpopt.c: Ditto.
+ * gcc.target/microblaze/others/interrupt_handler_leaf.c: Ditto.
+ * gcc.target/microblaze/others/sdata_var1.c: Ditto.
+ * gcc.target/microblaze/others/sdata_var2.c: Ditto.
+ * gcc.target/microblaze/others/sdata_var3.c: Ditto.
+ * gcc.target/microblaze/others/sdata_var4.c: Ditto.
+ * gcc.target/microblaze/others/sdata_var5.c: Ditto.
+ * gcc.target/microblaze/others/sdata_var6.c: Ditto.
+ * gcc.target/microblaze/isa/fsqrt.c: Ditto.
+ * gcc.target/microblaze/isa/pcmp.c: Ditto.
+ * gcc.target/microblaze/isa/nofloat.c: Ditto.
+ * gcc.target/microblaze/isa/fcvt.c: Ditto.
+ * gcc.target/microblaze/isa/float.c: Ditto.
+ * gcc.target/microblaze/isa/mulh.c: Ditto.
+ * gcc.target/microblaze/isa/fcmp1.c: Ditto.
+ * gcc.target/microblaze/isa/mul-bshift-pcmp.c: Ditto.
+ * gcc.target/microblaze/isa/fcmp2.c: Ditto.
+ * gcc.target/microblaze/isa/fcmp3.c: Ditto.
+ * gcc.target/microblaze/isa/mul-bshift.c: Ditto.
+ * gcc.target/microblaze/isa/mulh-bshift-pcmp.c: Ditto.
+ * gcc.target/microblaze/isa/bshift.c: Ditto.
+ * gcc.target/microblaze/isa/nofcmp.c: Ditto.
+ * gcc.target/microblaze/isa/div.c: Ditto.
+ * gcc.target/microblaze/isa/vanilla.c: Ditto.
+ * gcc.target/microblaze/isa/mul.c: Ditto.
+
+
2010-09-23 Uros Bizjak <ubizjak@gmail.com>
* gcc.target/i386/pad-1.c: Remove -S from dg-options.
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac (revision 164569)
+++ gcc/configure.ac (working copy)
@@ -3748,7 +3748,7 @@
i?86*-*-* | mips*-*-* | alpha*-*-* | powerpc*-*-* | sparc*-*-* | m68*-*-* \
| x86_64*-*-* | hppa*-*-* | arm*-*-* \
| xstormy16*-*-* | cris-*-* | crisv32-*-* | xtensa*-*-* | bfin-*-* | score*-*-* \
- | spu-*-* | fido*-*-* | m32c-*-*)
+ | spu-*-* | fido*-*-* | m32c-*-* | microblaze-*-*)
insn="nop"
;;
ia64*-*-* | s390*-*-*)
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc (revision 164569)
+++ gcc/config.gcc (working copy)
@@ -339,6 +339,9 @@
m68k-*-*)
extra_headers=math-68881.h
;;
+microblaze*-*-*)
+ cpu_type=microblaze
+ ;;
mips*-*-*)
cpu_type=mips
need_64bit_hwint=yes
@@ -1742,6 +1745,19 @@
fi
use_gcc_stdint=wrap
;;
+microblaze*-linux*)
+ tm_file="${tm_file} dbxelf.h linux.h microblaze/linux.h"
+ c_target_objs="${c_target_objs} microblaze-c.o"
+ cxx_target_objs="${cxx_target_objs} microblaze-c.o"
+ tmake_file="${tmake_file} t-slibgcc-elf-ver t-slibgcc-nolc-override t-linux microblaze/t-microblaze"
+ extra_parts="crtbegin.o crtbeginS.o crtend.o crtendS.o crtbeginT.o"
+ ;;
+microblaze*-*-*)
+ tm_file="${tm_file} dbxelf.h"
+ c_target_objs="${c_target_objs} microblaze-c.o"
+ cxx_target_objs="${cxx_target_objs} microblaze-c.o"
+ tmake_file="${tmake_file} microblaze/t-microblaze"
+ ;;
mips-sgi-irix6.5*)
tm_file="elfos.h ${tm_file} mips/iris6.h"
tmake_file="mips/t-iris mips/t-iris6 mips/t-slibgcc-irix"
Index: gcc/config/microblaze/microblaze-protos.h
===================================================================
--- gcc/config/microblaze/microblaze-protos.h (revision 0)
+++ gcc/config/microblaze/microblaze-protos.h (revision 0)
@@ -0,0 +1,64 @@
+/* Definitions of target machine for GNU compiler, for Xilinx MicroBlaze.
+ Copyright 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ Contributed by Michael Eager <eager@eagercon.com>.
+
+ GCC 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 3, or (at your
+ option) any later version.
+
+ GCC 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 GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_MICROBLAZE_PROTOS_H
+#define GCC_MICROBLAZE_PROTOS_H
+
+#ifdef RTX_CODE
+extern int pic_address_needs_scratch (rtx);
+extern void expand_block_move (rtx *);
+extern void microblaze_expand_prologue (void);
+extern void microblaze_expand_epilogue (void);
+extern void override_options (void);
+extern int microblaze_expand_shift (rtx *);
+extern bool microblaze_expand_move (enum machine_mode, rtx *);
+extern bool microblaze_expand_block_move (rtx, rtx, rtx, rtx);
+extern void microblaze_expand_divide (rtx *);
+extern void microblaze_expand_conditional_branch (enum machine_mode, rtx *);
+extern void microblaze_expand_conditional_branch_sf (rtx *);
+extern int microblaze_can_use_return_insn (void);
+extern int microblaze_const_double_ok (rtx, enum machine_mode);
+extern void print_operand (FILE *, rtx, int);
+extern void print_operand_address (FILE *, rtx);
+extern void init_cumulative_args (CUMULATIVE_ARGS *,tree, rtx);
+extern bool microblaze_legitimate_address_p (enum machine_mode, rtx, bool);
+extern int microblaze_is_interrupt_handler (void);
+extern rtx microblaze_return_addr (int, rtx);
+extern int simple_memory_operand (rtx, enum machine_mode);
+extern int double_memory_operand (rtx, enum machine_mode);
+
+extern int microblaze_regno_ok_for_base_p (int, int);
+extern HOST_WIDE_INT microblaze_initial_elimination_offset (int, int);
+extern void microblaze_declare_object (FILE *, const char *, const char *,
+ const char *, int);
+extern void microblaze_asm_output_ident (FILE *, const char *);
+#endif /* RTX_CODE */
+
+#ifdef TREE_CODE
+extern void function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, int);
+extern rtx function_arg (CUMULATIVE_ARGS *, enum machine_mode, tree, int);
+#endif /* TREE_CODE */
+
+/* Declare functions in microblaze-c.c. */
+extern void microblaze_cpp_define (struct cpp_reader *);
+
+#endif /* GCC_MICROBLAZE_PROTOS_H */
Index: gcc/config/microblaze/crti.s
===================================================================
--- gcc/config/microblaze/crti.s (revision 0)
+++ gcc/config/microblaze/crti.s (revision 0)
@@ -0,0 +1,39 @@
+/* crti.s for __init, __fini
+ This file supplies the prologue for __init and __fini routines
+
+ Copyright 2009, 2010 Free Software Foundation, Inc.
+
+ Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+ later version.
+
+ GCC 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+ .section .init, "ax"
+ .global __init
+ .align 2
+__init:
+ addik r1, r1, -8
+ sw r15, r0, r1
+
+ .section .fini, "ax"
+ .global __fini
+ .align 2
+__fini:
+ addik r1, r1, -8
+ sw r15, r0, r1
Index: gcc/config/microblaze/predicates.md
===================================================================
--- gcc/config/microblaze/predicates.md (revision 0)
+++ gcc/config/microblaze/predicates.md (revision 0)
@@ -0,0 +1,64 @@
+;; Predicate definitions for Xilinx MicroBlaze
+;; Copyright 2009, 2010 Free Software Foundation, Inc.
+;;
+;; Contributed by Michael Eager <eager@eagercon.com>.
+;;
+;; This file is part of GCC.
+;;
+;; GCC 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 3, or (at your option)
+;; any later version.
+;;
+;; GCC 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 GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+
+;; Return whether OP can be used as an operands in arithmetic.
+(define_predicate "arith_operand"
+ (ior (match_code "const_int,const_double")
+ (match_operand 0 "register_operand")))
+
+(define_predicate "arith_operand32"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_int,const_double")
+ (match_test "LARGE_INT (op)"))))
+
+(define_predicate "const_0_operand"
+ (and (match_code "const_int,const_double")
+ (match_test "op == CONST0_RTX (GET_MODE (op))")))
+
+;; Return whether OP is a register or the constant 0.
+(define_predicate "reg_or_0_operand"
+ (ior (match_operand 0 "const_0_operand")
+ (match_operand 0 "register_operand")))
+
+;; Return if the operand is either the PC or a label_ref.
+(define_special_predicate "pc_or_label_operand"
+ (ior (match_code "pc,label_ref")
+ (and (match_code "symbol_ref")
+ (match_test "!(strcmp ((XSTR (op, 0)), \"_stack_overflow_exit\"))"))))
+
+;; Test for valid call operand
+(define_predicate "call_insn_operand"
+ (match_test "CALL_INSN_OP (op)"))
+
+;; Return if OPERAND is valid as a source operand for a move instruction.
+(define_predicate "move_operand"
+ (and (
+ not (
+ and (match_code "plus")
+ (not (match_test "(GET_CODE (XEXP (op, 0)) == REG) ^ (GET_CODE (XEXP (op,1)) == REG)"))
+ )
+ )
+ (match_operand 0 "general_operand")))
+
+;; Test for valid PIC call operand
+(define_predicate "call_insn_plt_operand"
+ (match_test "PLT_ADDR_P (op)"))
Index: gcc/config/microblaze/linux.h
===================================================================
--- gcc/config/microblaze/linux.h (revision 0)
+++ gcc/config/microblaze/linux.h (revision 0)
@@ -0,0 +1,35 @@
+/* Definitions for MicroBlaze running Linux.
+ Copyright 2009, 2010 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ Contributed by Michael Eager <eager@eagercon.com>.
+
+ GCC 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 3, or (at your option)
+ any later version.
+
+ GCC 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 GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+
+#define DYNAMIC_LINKER "/lib/ld.so.1"
+#undef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS \
+ { "dynamic_linker", DYNAMIC_LINKER }
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{shared:-shared} \
+ %{!shared: \
+ %{!static: \
+ %{rdynamic:-export-dynamic} \
+ %{!dynamic-linker:-dynamic-linker %(dynamic_linker)}} \
+ %{static:-static}}"
+
Index: gcc/config/microblaze/microblaze.md
===================================================================
--- gcc/config/microblaze/microblaze.md (revision 0)
+++ gcc/config/microblaze/microblaze.md (revision 0)
@@ -0,0 +1,2231 @@
+;; microblaze.md -- Machine description for Xilinx MicroBlaze processors.
+;; Copyright 2009, 2010 Free Software Foundation, Inc.
+
+;; Contributed by Michael Eager <eager@eagercon.com>.
+
+;; This file is part of GCC.
+
+;; GCC 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 3, or (at your option)
+;; any later version.
+
+;; GCC 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 GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>. */
+
+(include "constraints.md")
+(include "predicates.md")
+
+;;----------------------------------------------------
+;; Constants
+;;----------------------------------------------------
+(define_constants [
+ (R_SP 1) ;; Stack pointer reg
+ (R_SR 15) ;; Sub-routine return addr reg
+ (R_IR 14) ;; Interrupt return addr reg
+ (R_DR 16) ;; Debug trap return addr reg
+ (R_ER 17) ;; Exception return addr reg
+ (R_TMP 18) ;; Assembler temporary reg
+ (R_GOT 20) ;; GOT ptr reg
+ (MB_PIPE_3 0) ;; Microblaze 3-stage pipeline
+ (MB_PIPE_5 1) ;; Microblaze 5-stage pipeline
+ (UNSPEC_SET_GOT 101) ;;
+ (UNSPEC_GOTOFF 102) ;; GOT offset
+ (UNSPEC_PLT 103) ;; jump table
+ (UNSPEC_CMP 104) ;; signed compare
+ (UNSPEC_CMPU 105) ;; unsigned compare
+])
+
+
+;;----------------------------------------------------
+;; Instruction Attributes
+;;----------------------------------------------------
+
+;; Classification of each insn.
+;; branch conditional branch
+;; jump unconditional jump
+;; call unconditional call
+;; load load instruction(s)
+;; store store instruction(s)
+;; move data movement within same register set
+;; arith integer arithmetic instruction
+;; darith double precision integer arithmetic instructions
+;; imul integer multiply
+;; idiv integer divide
+;; icmp integer compare
+;; Xfadd floating point add/subtract
+;; Xfmul floating point multiply
+;; Xfmadd floating point multiply-add
+;; Xfdiv floating point divide
+;; Xfabs floating point absolute value
+;; Xfneg floating point negation
+;; Xfcmp floating point compare
+;; Xfcvt floating point convert
+;; Xfsqrt floating point square root
+;; multi multiword sequence (or user asm statements)
+;; nop no operation
+;; bshift Shift operations
+
+(define_attr "type"
+ "unknown,branch,jump,call,load,store,move,arith,darith,imul,idiv,icmp,multi,nop,no_delay_arith,no_delay_load,no_delay_store,no_delay_imul,no_delay_move,bshift,fadd,frsub,fmul,fdiv,fcmp,fsl,fsqrt,fcvt"
+ (const_string "unknown"))
+
+;; Main data type used by the insn
+(define_attr "mode" "unknown,none,QI,HI,SI,DI,SF,DF" (const_string "unknown"))
+
+;; # instructions (4 bytes each)
+(define_attr "length" "" (const_int 4))
+
+;;----------------------------------------------------
+;; Attribute describing the processor.
+;;----------------------------------------------------
+
+;; Describe a user's asm statement.
+(define_asm_attributes
+ [(set_attr "type" "multi")])
+
+;; whether or not generating calls to position independent functions
+(define_attr "abicalls" "no,yes"
+ (const (symbol_ref "microblaze_abicalls_attr")))
+
+;;----------------------------------------------------------------
+;; Microblaze DFA Pipeline description
+;;----------------------------------------------------------------
+
+;;-----------------------------------------------------------------
+/*
+ This is description of pipeline hazards based on DFA. The
+ following constructions can be used for this:
+
+ o define_cpu_unit string [string]) describes a cpu functional unit
+ (separated by comma).
+
+ 1st operand: Names of cpu function units.
+ 2nd operand: Name of automaton (see comments for
+ DEFINE_AUTOMATON).
+
+ All define_reservations and define_cpu_units should have unique
+ names which can not be "nothing".
+
+ o (exclusion_set string string) means that each CPU function unit
+ in the first string can not be reserved simultaneously with each
+ unit whose name is in the second string and vise versa. CPU
+ units in the string are separated by commas. For example, it is
+ useful for description CPU with fully pipelined floating point
+ functional unit which can execute simultaneously only single
+ floating point insns or only double floating point insns.
+
+ o (presence_set string string) means that each CPU function unit in
+ the first string can not be reserved unless at least one of units
+ whose names are in the second string is reserved. This is an
+ asymmetric relation. CPU units in the string are separated by
+ commas. For example, it is useful for description that slot1 is
+ reserved after slot0 reservation for a VLIW processor.
+
+ o (absence_set string string) means that each CPU function unit in
+ the first string can not be reserved only if each unit whose name
+ is in the second string is not reserved. This is an asymmetric
+ relation (actually exclusion set is analogous to this one but it
+ is symmetric). CPU units in the string are separated by commas.
+ For example, it is useful for description that slot0 can not be
+ reserved after slot1 or slot2 reservation for a VLIW processor.
+
+ o (define_bypass number out_insn_names in_insn_names) names bypass with
+ given latency (the first number) from insns given by the first
+ string (see define_insn_reservation) into insns given by the
+ second string. Insn names in the strings are separated by
+ commas.
+
+ o (define_automaton string) describes names of an automaton
+ generated and used for pipeline hazards recognition. The names
+ are separated by comma. Actually it is possibly to generate the
+ single automaton but unfortunately it can be very large. If we
+ use more one automata, the summary size of the automata usually
+ is less than the single one. The automaton name is used in
+ define_cpu_unit. All automata should have unique names.
+
+ o (define_reservation string string) names reservation (the first
+ string) of cpu functional units (the 2nd string). Sometimes unit
+ reservations for different insns contain common parts. In such
+ case, you describe common part and use one its name (the 1st
+ parameter) in regular expression in define_insn_reservation. All
+ define_reservations, define results and define_cpu_units should
+ have unique names which can not be "nothing".
+
+ o (define_insn_reservation name default_latency condition regexpr)
+ describes reservation of cpu functional units (the 3nd operand)
+ for instruction which is selected by the condition (the 2nd
+ parameter). The first parameter is used for output of debugging
+ information. The reservations are described by a regular
+ expression according the following syntax:
+
+ regexp = regexp "," oneof
+ | oneof
+
+ oneof = oneof "|" allof
+ | allof
+
+ allof = allof "+" repeat
+ | repeat
+
+ repeat = element "*" number
+ | element
+
+ element = cpu_function_name
+ | reservation_name
+ | result_name
+ | "nothing"
+ | "(" regexp ")"
+
+ 1. "," is used for describing start of the next cycle in
+ reservation.
+
+ 2. "|" is used for describing the reservation described by the
+ first regular expression *or* the reservation described by
+ the second regular expression *or* etc.
+
+ 3. "+" is used for describing the reservation described by the
+ first regular expression *and* the reservation described by
+ the second regular expression *and* etc.
+
+ 4. "*" is used for convenience and simply means sequence in
+ which the regular expression are repeated NUMBER times with
+ cycle advancing (see ",").
+
+ 5. cpu function unit name which means reservation.
+
+ 6. reservation name -- see define_reservation.
+
+ 7. string "nothing" means no units reservation.
+
+*/
+;;-----------------------------------------------------------------
+
+
+;;----------------------------------------------------------------
+;; Microblaze 5-stage pipeline description (v5.00.a and later)
+;;----------------------------------------------------------------
+
+(define_automaton "mbpipe_5")
+(define_cpu_unit "mb_issue,mb_iu,mb_wb,mb_fpu,mb_fpu_2,mb_mul,mb_mul_2,mb_div,mb_div_2,mb_bs,mb_bs_2" "mbpipe_5")
+
+(define_insn_reservation "mb-integer" 1
+ (and (eq_attr "type" "branch,jump,call,arith,darith,icmp,nop,no_delay_arith")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_iu,mb_wb")
+
+(define_insn_reservation "mb-special-move" 2
+ (and (eq_attr "type" "move")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_iu*2,mb_wb")
+
+(define_insn_reservation "mb-mem-load" 3
+ (and (eq_attr "type" "load,no_delay_load")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_iu,mb_wb")
+
+(define_insn_reservation "mb-mem-store" 1
+ (and (eq_attr "type" "store,no_delay_store")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_iu,mb_wb")
+
+(define_insn_reservation "mb-mul" 3
+ (and (eq_attr "type" "imul,no_delay_imul")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_mul,mb_mul_2*2,mb_wb")
+
+(define_insn_reservation "mb-div" 34
+ (and (eq_attr "type" "idiv")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_div,mb_div_2*33,mb_wb")
+
+(define_insn_reservation "mb-bs" 2
+ (and (eq_attr "type" "bshift")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_bs,mb_bs_2,mb_wb")
+
+(define_insn_reservation "mb-fpu-add-sub-mul" 6
+ (and (eq_attr "type" "fadd,frsub,fmul")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_fpu,mb_fpu_2*5,mb_wb")
+
+(define_insn_reservation "mb-fpu-fcmp" 3
+ (and (eq_attr "type" "fcmp")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_fpu,mb_fpu*2,mb_wb")
+
+(define_insn_reservation "mb-fpu-div" 30
+ (and (eq_attr "type" "fdiv")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_fpu,mb_fpu_2*29,mb_wb")
+
+(define_insn_reservation "mb-fpu-sqrt" 30
+ (and (eq_attr "type" "fsqrt")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_fpu,mb_fpu_2*29,mb_wb")
+
+(define_insn_reservation "mb-fpu-fcvt" 4
+ (and (eq_attr "type" "fcvt")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_5)))
+ "mb_issue,mb_fpu,mb_fpu_2*3,mb_wb")
+
+;;----------------------------------------------------------------
+;; Microblaze 3-stage pipeline description (for v4.00.a and earlier)
+;;----------------------------------------------------------------
+
+(define_automaton "mbpipe_3")
+(define_cpu_unit "mb3_iu" "mbpipe_3")
+
+(define_insn_reservation "mb3-integer" 1
+ (and (eq_attr "type" "branch,jump,call,arith,darith,icmp,nop,no_delay_arith")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-special-move" 2
+ (and (eq_attr "type" "move")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu*2")
+
+(define_insn_reservation "mb3-mem-load" 2
+ (and (eq_attr "type" "load,no_delay_load")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-mem-store" 1
+ (and (eq_attr "type" "store,no_delay_store")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-mul" 3
+ (and (eq_attr "type" "imul,no_delay_imul")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-div" 34
+ (and (eq_attr "type" "idiv")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-bs" 2
+ (and (eq_attr "type" "bshift")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-fpu-add-sub-mul" 6
+ (and (eq_attr "type" "fadd,frsub,fmul")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-fpu-fcmp" 3
+ (and (eq_attr "type" "fcmp")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-fpu-div" 30
+ (and (eq_attr "type" "fdiv")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-fpu-sqrt" 30
+ (and (eq_attr "type" "fsqrt")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(define_insn_reservation "mb3-fpu-fcvt" 4
+ (and (eq_attr "type" "fcvt")
+ (eq (symbol_ref "microblaze_pipe") (const_int MB_PIPE_3)))
+ "mb3_iu")
+
+(automata_option "v")
+(automata_option "time")
+(automata_option "progress")
+
+;;----------------------------------------------------------------
+;; Microblaze delay slot description
+;;----------------------------------------------------------------
+(define_delay (eq_attr "type" "branch,call,jump")
+ [(and (eq_attr "type" "!branch,call,jump,icmp,multi,no_delay_arith,no_delay_load,no_delay_store,no_delay_imul,no_delay_move,darith")
+ (ior (eq (symbol_ref "microblaze_no_unsafe_delay") (const_int 0))
+ (eq_attr "type" "!fadd,frsub,fmul,fdiv,fcmp,store,load")
+ ))
+ (nil) (nil)])
+
+
+;;----------------------------------------------------------------
+;; Microblaze FPU
+;;----------------------------------------------------------------
+
+(define_insn "addsf3"
+ [(set (match_operand:SF 0 "register_operand" "=d")
+ (plus:SF (match_operand:SF 1 "register_operand" "d")
+ (match_operand:SF 2 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT"
+ "fadd\t%0,%1,%2"
+ [(set_attr "type" "fadd")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+(define_insn "subsf3"
+ [(set (match_operand:SF 0 "register_operand" "=d")
+ (minus:SF (match_operand:SF 1 "register_operand" "d")
+ (match_operand:SF 2 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT"
+ "frsub\t%0,%2,%1"
+ [(set_attr "type" "frsub")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+(define_insn "mulsf3"
+ [(set (match_operand:SF 0 "register_operand" "=d")
+ (mult:SF (match_operand:SF 1 "register_operand" "d")
+ (match_operand:SF 2 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT"
+ "fmul\t%0,%1,%2"
+ [(set_attr "type" "fmul")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+
+(define_insn "divsf3"
+ [(set (match_operand:SF 0 "register_operand" "=d")
+ (div:SF (match_operand:SF 1 "register_operand" "d")
+ (match_operand:SF 2 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT"
+ "fdiv\t%0,%2,%1"
+ [(set_attr "type" "fdiv")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+(define_insn "sqrtsf2"
+ [(set (match_operand:SF 0 "register_operand" "=d")
+ (sqrt:SF (match_operand:SF 1 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT && TARGET_FLOAT_SQRT"
+ "fsqrt\t%0,%1"
+ [(set_attr "type" "fsqrt")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+(define_insn "floatsisf2"
+ [(set (match_operand:SF 0 "register_operand" "=d")
+ (float:SF (match_operand:SI 1 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT && TARGET_FLOAT_CONVERT"
+ "flt\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+(define_insn "fix_truncsfsi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (fix:SI (match_operand:SF 1 "register_operand" "d")))]
+ "TARGET_HARD_FLOAT && TARGET_FLOAT_CONVERT"
+ "fint\t%0,%1"
+ [(set_attr "type" "fcvt")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")])
+
+;;----------------------------------------------------------------
+;; Add
+;;----------------------------------------------------------------
+
+;; Add 2 SImode integers [ src1 = reg ; src2 = arith ; dest = reg ]
+;; Leave carry as is
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (plus:SI (match_operand:SI 1 "reg_or_0_operand" "%dJ,dJ,dJ")
+ (match_operand:SI 2 "arith_operand" "d,I,i")))]
+ ""
+ "@
+ addk\t%0,%z1,%2
+ addik\t%0,%z1,%2
+ addik\t%0,%z1,%2"
+ [(set_attr "type" "arith,arith,no_delay_arith")
+ (set_attr "mode" "SI,SI,SI")
+ (set_attr "length" "4,4,8")])
+
+;;----------------------------------------------------------------
+;; Double Precision Additions
+;;----------------------------------------------------------------
+
+;; reg_DI_dest = reg_DI_src1 + DI_src2
+
+;; Adding 2 DI operands in register or reg/imm
+
+(define_insn "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "=d,d,d")
+ (plus:DI (match_operand:DI 1 "register_operand" "%d,d,d")
+ (match_operand:DI 2 "arith_operand32" "d,P,N")))]
+ ""
+ "@
+ add\t%L0,%L1,%L2\;addc\t%M0,%M1,%M2
+ addi\t%L0,%L1,%2\;addc\t%M0,%M1,r0
+ addi\t%L0,%L1,%2\;addc\t%M0,%M1,r0\;addi\t%M0,%M0,-1"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8,8,12")])
+
+;;----------------------------------------------------------------
+;; Subtraction
+;;----------------------------------------------------------------
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (minus:SI (match_operand:SI 1 "arith_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "d,n")))]
+ ""
+ "@
+ rsubk\t%0,%2,%z1
+ addik\t%0,%z1,-%2"
+ [(set_attr "type" "arith,no_delay_arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4,8")])
+
+
+;;----------------------------------------------------------------
+;; Double Precision Subtraction
+;;----------------------------------------------------------------
+
+(define_insn "subdi3"
+ [(set (match_operand:DI 0 "register_operand" "=&d")
+ (minus:DI (match_operand:DI 1 "register_operand" "d")
+ (match_operand:DI 2 "arith_operand32" "d")))]
+ ""
+ "@
+ rsub\t%L0,%L2,%L1\;rsubc\t%M0,%M2,%M1"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+
+;;----------------------------------------------------------------
+;; Multiplication
+;;----------------------------------------------------------------
+
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (mult:SI (match_operand:SI 1 "register_operand" "d,d,d")
+ (match_operand:SI 2 "arith_operand" "d,I,i")))]
+ "!TARGET_SOFT_MUL"
+ "@
+ mul\t%0,%1,%2
+ muli\t%0,%1,%2
+ muli\t%0,%1,%2"
+ [(set_attr "type" "imul,imul,no_delay_imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4,4,8")])
+
+(define_insn "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=&d")
+ (mult:DI
+ (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
+ "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
+ "mul\t%L0,%1,%2\;mulh\t%M0,%1,%2"
+ [(set_attr "type" "no_delay_arith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=&d")
+ (mult:DI
+ (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
+ "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
+ "mul\t%L0,%1,%2\;mulhu\t%M0,%1,%2"
+ [(set_attr "type" "no_delay_arith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+(define_insn "usmulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=&d")
+ (mult:DI
+ (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))))]
+ "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
+ "mul\t%L0,%1,%2\;mulhsu\t%M0,%2,%1"
+ [(set_attr "type" "no_delay_arith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+(define_insn "*smulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "d")))
+ (const_int 32))))]
+ "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
+ "mulh\t%0,%1,%2"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "*umulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "d"))
+)
+ (const_int 32))))]
+ "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
+ "mulhu\t%0,%1,%2"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "*usmulsi3_highpart"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (truncate:SI
+ (lshiftrt:DI
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "d"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "d"))
+)
+ (const_int 32))))]
+ "!TARGET_SOFT_MUL && TARGET_MULTIPLY_HIGH"
+ "mulhsu\t%0,%2,%1"
+ [(set_attr "type" "imul")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+
+;;----------------------------------------------------------------
+;; Division and remainder
+;;----------------------------------------------------------------
+(define_expand "divsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (div:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ ]
+ "(!TARGET_SOFT_DIV) || (TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)"
+ {
+ if (TARGET_SOFT_DIV && TARGET_BARREL_SHIFT && TARGET_SMALL_DIVIDES)
+ {
+ microblaze_expand_divide (operands);
+ DONE;
+ }
+ else if (!TARGET_SOFT_DIV)
+ {
+ emit_insn (gen_divsi3_internal (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+ }
+)
+
+
+(define_insn "divsi3_internal"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (div:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ ]
+ "!TARGET_SOFT_DIV"
+ "idiv\t%0,%2,%1"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")]
+)
+
+(define_insn "udivsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (udiv:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))
+ ]
+ "!TARGET_SOFT_DIV"
+ "idivu\t%0,%2,%1"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+
+;;----------------------------------------------------------------
+;; Negation and one's complement
+;;----------------------------------------------------------------
+
+(define_insn "negsi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (neg:SI (match_operand:SI 1 "register_operand" "d")))]
+ ""
+ "rsubk\t%0,%1,r0"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "negdi2"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (neg:DI (match_operand:DI 1 "register_operand" "d")))]
+ ""
+ "rsub\t%L0,%L1,r0\;rsubc\t%M0,%M1,r0"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+
+(define_insn "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (not:SI (match_operand:SI 1 "register_operand" "d")))]
+ ""
+ "xori\t%0,%1,-1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "*one_cmpldi2"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (not:DI (match_operand:DI 1 "register_operand" "d")))]
+ ""
+ "nor\t%M0,r0,%M1\;nor\t%L0,r0,%L1"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")]
+)
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (not:DI (match_operand:DI 1 "register_operand" "")))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))"
+
+ [(set (subreg:SI (match_dup 0) 0) (not:SI (subreg:SI (match_dup 1) 0)))
+ (set (subreg:SI (match_dup 0) 4) (not:SI (subreg:SI (match_dup 1) 4)))]
+ "")
+
+
+;;----------------------------------------------------------------
+;; Logical
+;;----------------------------------------------------------------
+
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
+ (and:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
+ (match_operand:SI 2 "arith_operand" "d,I,i,M")))]
+ ""
+ "@
+ and\t%0,%1,%2
+ andi\t%0,%1,%2 #and1
+ andi\t%0,%1,%2 #and2
+ andi\t%0,%1,%2 #and3"
+ [(set_attr "type" "arith,arith,no_delay_arith,no_delay_arith")
+ (set_attr "mode" "SI,SI,SI,SI")
+ (set_attr "length" "4,8,8,8")])
+
+
+(define_insn "anddi3"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (and:DI (match_operand:DI 1 "register_operand" "d")
+ (match_operand:DI 2 "register_operand" "d")))]
+ ""
+ "and\t%M0,%M1,%M2\;and\t%L0,%L1,%L2"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")])
+
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (and:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
+ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
+
+ [(set (subreg:SI (match_dup 0) 0) (and:SI (subreg:SI (match_dup 1) 0)
+ (subreg:SI (match_dup 2) 0)))
+ (set (subreg:SI (match_dup 0) 4) (and:SI (subreg:SI (match_dup 1) 4)
+ (subreg:SI (match_dup 2) 4)))]
+ "")
+
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d,d")
+ (ior:SI (match_operand:SI 1 "arith_operand" "%d,d,d,d")
+ (match_operand:SI 2 "arith_operand" "d,I,M,i")))]
+ ""
+ "@
+ or\t%0,%1,%2
+ ori\t%0,%1,%2
+ ori\t%0,%1,%2
+ ori\t%0,%1,%2"
+ [(set_attr "type" "arith,no_delay_arith,no_delay_arith,no_delay_arith")
+ (set_attr "mode" "SI,SI,SI,SI")
+ (set_attr "length" "4,8,8,8")])
+
+
+(define_insn "iordi3"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (ior:DI (match_operand:DI 1 "register_operand" "d")
+ (match_operand:DI 2 "register_operand" "d")))]
+ ""
+ "or\t%M0,%M1,%M2\;or\t%L0,%L1,%L2"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")]
+)
+
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (ior:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
+ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
+
+ [(set (subreg:SI (match_dup 0) 0) (ior:SI (subreg:SI (match_dup 1) 0)
+ (subreg:SI (match_dup 2) 0)))
+ (set (subreg:SI (match_dup 0) 4) (ior:SI (subreg:SI (match_dup 1) 4)
+ (subreg:SI (match_dup 2) 4)))]
+ "")
+
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (xor:SI (match_operand:SI 1 "arith_operand" "%d,d,d")
+ (match_operand:SI 2 "arith_operand" "d,I,i")))]
+ ""
+ "@
+ xor\t%0,%1,%2
+ xori\t%0,%1,%2
+ xori\t%0,%1,%2"
+ [(set_attr "type" "arith,arith,no_delay_arith")
+ (set_attr "mode" "SI,SI,SI")
+ (set_attr "length" "4,8,8")])
+
+(define_insn "xordi3"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (xor:DI (match_operand:DI 1 "register_operand" "d")
+ (match_operand:DI 2 "register_operand" "d")))]
+ ""
+ "xor\t%M0,%M1,%M2\;xor\t%L0,%L1,%L2"
+ [(set_attr "type" "darith")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8")]
+)
+
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (xor:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "register_operand" "")))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
+ && GET_CODE (operands[2]) == REG && GP_REG_P (REGNO (operands[2]))"
+
+ [(set (subreg:SI (match_dup 0) 0) (xor:SI (subreg:SI (match_dup 1) 0)
+ (subreg:SI (match_dup 2) 0)))
+ (set (subreg:SI (match_dup 0) 4) (xor:SI (subreg:SI (match_dup 1) 4)
+ (subreg:SI (match_dup 2) 4)))]
+ "")
+
+;;----------------------------------------------------------------
+;; Zero extension
+;;----------------------------------------------------------------
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "d,R,m")))]
+ ""
+ "@
+ andi\t%0,%1,0xffff
+ lhu%i1\t%0,%1
+ lhu%i1\t%0,%1"
+ [(set_attr "type" "no_delay_arith,load,no_delay_load")
+ (set_attr "mode" "SI,SI,SI")
+ (set_attr "length" "8,4,8")])
+
+(define_insn "zero_extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=d,d,d")
+ (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
+ ""
+ "@
+ andi\t%0,%1,0x00ff
+ lbu%i1\t%0,%1
+ lbu%i1\t%0,%1"
+ [(set_attr "type" "arith,load,no_delay_load")
+ (set_attr "mode" "HI")
+ (set_attr "length" "4,4,8")])
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,d")
+ (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "d,R,m")))]
+ ""
+ "@
+ andi\t%0,%1,0x00ff
+ lbu%i1\t%0,%1
+ lbu%i1\t%0,%1"
+ [(set_attr "type" "arith,load,no_delay_load")
+ (set_attr "mode" "SI,SI,SI")
+ (set_attr "length" "4,4,8")])
+
+;;----------------------------------------------------------------
+;; Sign extension
+;;----------------------------------------------------------------
+
+;; basic Sign Extend Operations
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "d")))]
+ ""
+ "sext8\t%0,%1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "d")))]
+ ""
+ "sext16\t%0,%1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+;; Those for integer source operand are ordered
+;; widest source type first.
+
+(define_insn "extendsidi2"
+ [(set (match_operand:DI 0 "register_operand" "=d,d,d")
+ (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,R,m")))]
+ ""
+ {
+ if (which_alternative == 0)
+ output_asm_insn ("addk\t%D0,r0,%1", operands);
+ else
+ output_asm_insn ("lw%i1\t%D0,%1", operands);
+
+ output_asm_insn ("add\t%0,%D0,%D0", operands);
+ output_asm_insn ("addc\t%0,r0,r0", operands);
+ output_asm_insn ("beqi\t%0,.+8", operands);
+ return "addi\t%0,r0,0xffffffff";
+ }
+ [(set_attr "type" "multi,multi,multi")
+ (set_attr "mode" "DI")
+ (set_attr "length" "20,20,20")])
+
+;;----------------------------------------------------------------
+;; Data movement
+;;----------------------------------------------------------------
+
+;; 64-bit integer moves
+
+;; Unlike most other insns, the move insns can't be split with
+;; different predicates, because register spilling and other parts of
+;; the compiler, have memoized the insn number already.
+
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ {
+ /* If operands[1] is a constant address illegal for pic, then we need to
+ handle it just like microblaze_legitimize_address does. */
+ if (flag_pic && pic_address_needs_scratch (operands[1]))
+ {
+ rtx temp = force_reg (DImode, XEXP (XEXP (operands[1], 0), 0));
+ rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
+ emit_move_insn (operands[0], gen_rtx_PLUS (DImode, temp, temp2));
+ DONE;
+ }
+
+
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], DImode)
+ && !register_operand (operands[1], DImode)
+ && (((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (DImode))))
+ {
+
+ rtx temp = force_reg (DImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+ }
+)
+
+
+
+(define_insn "*movdi_internal"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
+ (match_operand:DI 1 "general_operand" " d,i,J,R,m,d,d"))]
+ ""
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ return "addk\t%0,%1\n\taddk\t%D0,%d1";
+ case 1:
+ return "addik\t%0,r0,%h1\n\taddik\t%D0,r0,%j1 #li => la";
+ case 2:
+ return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
+ case 3:
+ case 4:
+ if (reg_mentioned_p (operands[0], operands[1]))
+ return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
+ else
+ return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
+ case 5:
+ case 6:
+ return "swi\t%1,%0\n\tswi\t%D1,%o0";
+ }
+ return "unreachable";
+ }
+ [(set_attr "type" "no_delay_move,no_delay_arith,no_delay_arith,no_delay_load,no_delay_load,no_delay_store,no_delay_store")
+ (set_attr "mode" "DI")
+ (set_attr "length" "8,8,8,8,12,8,12")])
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "register_operand" ""))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
+ && (REGNO(operands[0]) == (REGNO(operands[1]) + 1))"
+
+ [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
+ (set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
+ "")
+
+(define_split
+ [(set (match_operand:DI 0 "register_operand" "")
+ (match_operand:DI 1 "register_operand" ""))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
+ && (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
+
+ [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
+ (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
+ "")
+
+;; Unlike most other insns, the move insns can't be split with
+;; different predicates, because register spilling and other parts of
+;; the compiler, have memoized the insn number already.
+
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ {
+ if (microblaze_expand_move (SImode, operands)) DONE;
+ }
+)
+
+;; Added for status resgisters
+(define_insn "movsi_status"
+ [(set (match_operand:SI 0 "register_operand" "=d,d,z")
+ (match_operand:SI 1 "register_operand" "z,d,d"))]
+ "interrupt_handler"
+ "@
+ mfs\t%0,%1 #mfs
+ addk\t%0,%1,r0 #add movsi
+ mts\t%0,%1 #mts"
+ [(set_attr "type" "move")
+ (set_attr "mode" "SI")
+ (set_attr "length" "12")])
+
+;; This move will be not be moved to delay slot.
+(define_insn "*movsi_internal3"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d")
+ (match_operand:SI 1 "immediate_operand" "J,I,Mnis"))]
+ "(register_operand (operands[0], SImode) &&
+ (GET_CODE (operands[1]) == CONST_INT &&
+ (INTVAL (operands[1]) <= 32767 && INTVAL (operands[1]) >= -32768)))"
+ "@
+ addk\t%0,r0,r0
+ addik\t%0,r0,%1\t# %X1
+ addik\t%0,r0,%1\t# %X1"
+ [(set_attr "type" "arith,arith,no_delay_arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+;; This move may be used for PLT label operand
+(define_insn "*movsi_internal5_pltop"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (match_operand:SI 1 "call_insn_operand" ""))]
+ "(register_operand (operands[0], Pmode) &&
+ PLT_ADDR_P (operands[1]))"
+ {
+ gcc_unreachable ();
+ }
+ [(set_attr "type" "load")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "*movsi_internal2"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,d, d,d,R, T")
+ (match_operand:SI 1 "move_operand" " d,I,Mnis,R,m,dJ,dJ"))]
+ "(register_operand (operands[0], SImode)
+ || register_operand (operands[1], SImode)
+ || (GET_CODE (operands[1]) == CONST_INT && INTVAL (operands[1]) == 0))
+ && (flag_pic != 2 || (GET_CODE (operands[1]) != SYMBOL_REF
+ && GET_CODE (operands[1]) != LABEL_REF))"
+ "@
+ addk\t%0,%1,r0
+ addik\t%0,r0,%1\t# %X1
+ addik\t%0,%a1
+ lw%i1\t%0,%1
+ lw%i1\t%0,%1
+ sw%i0\t%z1,%0
+ sw%i0\t%z1,%0"
+ [(set_attr "type" "load,load,no_delay_load,load,no_delay_load,store,no_delay_store")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4,4,8,4,8,4,8")])
+
+
+;; 16-bit Integer moves
+
+;; Unlike most other insns, the move insns can't be split with
+;; different predicates, because register spilling and other parts of
+;; the compiler, have memoized the insn number already.
+;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ {
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], HImode)
+ && !register_operand (operands[1], HImode)
+ && ((GET_CODE (operands[1]) != CONST_INT
+ || INTVAL (operands[1]) != 0)))
+ {
+ rtx temp = force_reg (HImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+ }
+)
+
+(define_insn "*movhi_internal2"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,d,R,m")
+ (match_operand:HI 1 "general_operand" "I,d,R,m,dJ,dJ"))]
+ ""
+ "@
+ addik\t%0,r0,%1\t# %X1
+ addk\t%0,%1,r0
+ lhui\t%0,%1
+ lhui\t%0,%1
+ sh%i0\t%z1,%0
+ sh%i0\t%z1,%0"
+ [(set_attr "type" "arith,move,load,no_delay_load,store,no_delay_store")
+ (set_attr "mode" "HI")
+ (set_attr "length" "4,4,4,8,8,8")])
+
+;; 8-bit Integer moves
+
+;; Unlike most other insns, the move insns can't be split with
+;; different predicates, because register spilling and other parts of
+;; the compiler, have memoized the insn number already.
+;; Unsigned loads are used because BYTE_LOADS_ZERO_EXTEND is defined
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ {
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], QImode)
+ && !register_operand (operands[1], QImode)
+ && ((GET_CODE (operands[1]) != CONST_INT
+ || INTVAL (operands[1]) != 0)))
+ {
+ rtx temp = force_reg (QImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+ }
+)
+
+(define_insn "*movqi_internal2"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
+ (match_operand:QI 1 "general_operand" "J,I,d,R,m,dJ,dJ"))]
+ ""
+ "@
+ addk\t%0,r0,%z1
+ addik\t%0,r0,%1\t# %X1
+ addk\t%0,%1,r0
+ lbu%i1\t%0,%1
+ lbu%i1\t%0,%1
+ sb%i0\t%z1,%0
+ sbi\t%z1,%0"
+ [(set_attr "type" "arith,arith,move,load,no_delay_load,store,no_delay_store")
+ (set_attr "mode" "QI")
+ (set_attr "length" "4,4,8,4,8,4,8")])
+
+;; Block moves, see microblaze.c for more details.
+;; Argument 0 is the destination
+;; Argument 1 is the source
+;; Argument 2 is the length
+;; Argument 3 is the alignment
+
+(define_expand "movmemsi"
+ [(parallel [(set (match_operand:BLK 0 "general_operand")
+ (match_operand:BLK 1 "general_operand"))
+ (use (match_operand:SI 2 ""))
+ (use (match_operand:SI 3 "const_int_operand"))])]
+ ""
+ {
+ if (microblaze_expand_block_move (operands[0], operands[1],
+ operands[2], operands[3]))
+ DONE;
+ else
+ FAIL;
+ }
+)
+
+;; 32-bit floating point moves
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ {
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], SFmode)
+ && !register_operand (operands[1], SFmode)
+ && ( ((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (SFmode))))
+ {
+ rtx temp = force_reg (SFmode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+ }
+)
+
+;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
+;;
+(define_insn "*movsf_internal"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=d,d,d,d,d,R,m")
+ (match_operand:SF 1 "general_operand" "G,d,R,F,m,d,d"))]
+ "(register_operand (operands[0], SFmode)
+ || register_operand (operands[1], SFmode)
+ || operands[1] == CONST0_RTX (SFmode))"
+ "@
+ addk\t%0,r0,r0
+ addk\t%0,%1,r0
+ lw%i1\t%0,%1
+ addik\t%0,r0,%F1
+ lw%i1\t%0,%1
+ sw%i0\t%z1,%0
+ swi\t%z1,%0"
+ [(set_attr "type" "move,no_delay_load,load,no_delay_load,no_delay_load,store,no_delay_store")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4,4,4,4,4,4,4")])
+
+;; 64-bit floating point moves
+(define_expand "movdf"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (match_operand:DF 1 "general_operand" ""))]
+ ""
+ {
+ if (flag_pic == 2) {
+ if (GET_CODE (operands[1]) == MEM
+ && !microblaze_legitimate_address_p (DFmode, XEXP (operands[1],0), 0))
+ {
+ rtx ptr_reg;
+ rtx result;
+ ptr_reg = force_reg (Pmode, XEXP (operands[1],0));
+ result = gen_rtx_MEM (DFmode, ptr_reg);
+ emit_move_insn (operands[0], result);
+ DONE;
+ }
+ }
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], DFmode)
+ && !register_operand (operands[1], DFmode)
+ && (((GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0)
+ && operands[1] != CONST0_RTX (DFmode))))
+ {
+ rtx temp = force_reg (DFmode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ DONE;
+ }
+ }
+)
+
+;; movdf_internal
+;; Applies to both TARGET_SOFT_FLOAT and TARGET_HARD_FLOAT
+;;
+(define_insn "*movdf_internal"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=d,d,d,d,To")
+ (match_operand:DF 1 "general_operand" "dG,o,F,T,d"))]
+ ""
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ return "addk\t%0,r0,r0\n\taddk\t%D0,r0,r0";
+ case 1:
+ case 3:
+ if (reg_mentioned_p (operands[0], operands[1]))
+ return "lwi\t%D0,%o1\n\tlwi\t%0,%1";
+ else
+ return "lwi\t%0,%1\n\tlwi\t%D0,%o1";
+ case 2:
+ {
+ return "addik\t%0,r0,%h1 \n\taddik\t%D0,r0,%j1 #Xfer Lo";
+ }
+ case 4:
+ return "swi\t%1,%0\n\tswi\t%D1,%o0";
+ }
+ gcc_unreachable ();
+ }
+ [(set_attr "type" "no_delay_move,no_delay_load,no_delay_load,no_delay_load,no_delay_store")
+ (set_attr "mode" "DF")
+ (set_attr "length" "4,8,8,16,8")])
+
+(define_split
+ [(set (match_operand:DF 0 "register_operand" "")
+ (match_operand:DF 1 "register_operand" ""))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
+ && (REGNO (operands[0]) == (REGNO (operands[1]) + 1))"
+ [(set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))
+ (set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))]
+ "")
+
+(define_split
+ [(set (match_operand:DF 0 "register_operand" "")
+ (match_operand:DF 1 "register_operand" ""))]
+ "reload_completed
+ && GET_CODE (operands[0]) == REG && GP_REG_P (REGNO (operands[0]))
+ && GET_CODE (operands[1]) == REG && GP_REG_P (REGNO (operands[1]))
+ && (REGNO (operands[0]) != (REGNO (operands[1]) + 1))"
+ [(set (subreg:SI (match_dup 0) 0) (subreg:SI (match_dup 1) 0))
+ (set (subreg:SI (match_dup 0) 4) (subreg:SI (match_dup 1) 4))]
+ "")
+
+;;----------------------------------------------------------------
+;; Shifts
+;;----------------------------------------------------------------
+
+;;----------------------------------------------------------------
+;; 32-bit left shifts
+;;----------------------------------------------------------------
+(define_expand "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "arith_operand" "")))]
+ ""
+ {
+ /* Avoid recursion for trivial cases. */
+ if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
+ if (microblaze_expand_shift (operands))
+ DONE;
+ }
+)
+
+;; Irrespective of if we have a barrel-shifter or not, we want to match
+;; shifts by 1 with a special pattern. When a barrel shifter is present,
+;; saves a cycle. If not, allows us to annotate the instruction for delay
+;; slot optimization
+(define_insn "*ashlsi3_byone"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "arith_operand" "I")))]
+ "(INTVAL (operands[2]) == 1)"
+ "addk\t%0,%1,%1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")]
+)
+
+;; Barrel shift left
+(define_insn "ashlsi3_bshift"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "I,d")))]
+ "TARGET_BARREL_SHIFT"
+ "@
+ bslli\t%0,%1,%2
+ bsll\t%0,%1,%2"
+ [(set_attr "type" "bshift,bshift")
+ (set_attr "mode" "SI,SI")
+ (set_attr "length" "4,4")]
+)
+
+;; The following patterns apply when there is no barrel shifter present
+
+(define_insn "*ashlsi3_with_mul_delay"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ "!TARGET_SOFT_MUL
+ && ((1 << INTVAL (operands[2])) <= 32767 && (1 << INTVAL (operands[2])) >= -32768)"
+ "muli\t%0,%1,%m2"
+ ;; This MUL will not generate an imm. Can go into a delay slot.
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")]
+)
+
+(define_insn "*ashlsi3_with_mul_nodelay"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ "!TARGET_SOFT_MUL"
+ "muli\t%0,%1,%m2"
+ ;; This MUL will generate an IMM. Cannot go into a delay slot
+ [(set_attr "type" "no_delay_arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "8")]
+)
+
+(define_insn "*ashlsi3_with_size_opt"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ "(INTVAL (operands[2]) > 5 && optimize_size)"
+ {
+ operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
+
+ output_asm_insn ("ori\t%3,r0,%2", operands);
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ output_asm_insn ("addk\t%0,%1,r0", operands);
+
+ output_asm_insn ("addik\t%3,%3,-1", operands);
+ output_asm_insn ("bneid\t%3,.-4", operands);
+ return "addk\t%0,%0,%0";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "20")]
+)
+
+(define_insn "*ashlsi3_with_rotate"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ "(INTVAL (operands[2]) > 17 && !optimize_size)"
+ {
+ int i, nshift;
+
+ nshift = INTVAL (operands[2]);
+ operands[3] = gen_int_mode (0xFFFFFFFF << nshift, SImode);
+
+ /* We do one extra shift so that the first bit (carry) coming into the MSB
+ will be masked out */
+ output_asm_insn ("src\t%0,%1", operands);
+ for (i = 0; i < (32 - nshift); i++)
+ output_asm_insn ("src\t%0,%0", operands);
+
+ return "andi\t%0,%0,%3";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "80")]
+)
+
+(define_insn "*ashlsi_inline"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ ""
+ {
+ int i;
+ int nshift = INTVAL (operands[2]);
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ output_asm_insn ("addk\t%0,r0,%1", operands);
+ output_asm_insn ("addk\t%0,%1,%1", operands);
+ for (i = 0; i < (nshift - 2); i++)
+ output_asm_insn ("addk\t%0,%0,%0", operands);
+ return "addk\t%0,%0,%0";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "124")]
+)
+
+(define_insn "*ashlsi_reg"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashift:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ ""
+ {
+ operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
+ output_asm_insn ("andi\t%3,%2,31", operands);
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ output_asm_insn ("addk\t%0,r0,%1", operands);
+ /* Exit the loop if zero shift. */
+ output_asm_insn ("beqid\t%3,.+20", operands);
+ /* Emit the loop. */
+ output_asm_insn ("addk\t%0,%0,r0", operands);
+ output_asm_insn ("addik\t%3,%3,-1", operands);
+ output_asm_insn ("bneid\t%3,.-4", operands);
+ return "addk\t%0,%0,%0";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "28")]
+)
+
+
+;;----------------------------------------------------------------
+;; 32-bit right shifts
+;;----------------------------------------------------------------
+(define_expand "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "arith_operand" "")))]
+ ""
+ {
+ /* Avoid recursion for trivial cases. */
+ if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
+ if (microblaze_expand_shift (operands))
+ DONE;
+ }
+)
+
+;; Irrespective of if we have a barrel-shifter or not, we want to match
+;; shifts by 1 with a special pattern. When a barrel shifter is present,
+;; saves a cycle. If not, allows us to annotate the instruction for delay
+;; slot optimization
+(define_insn "*ashrsi3_byone"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "arith_operand" "I")))]
+ "(INTVAL (operands[2]) == 1)"
+ "sra\t%0,%1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")]
+)
+
+;; Barrel shift right logical
+(define_insn "*ashrsi3_bshift"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "I,d")))]
+ "TARGET_BARREL_SHIFT"
+ "@
+ bsrai\t%0,%1,%2
+ bsra\t%0,%1,%2"
+ [(set_attr "type" "bshift,bshift")
+ (set_attr "mode" "SI,SI")
+ (set_attr "length" "4,4")]
+)
+
+(define_insn "*ashrsi_inline"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ ""
+ {
+ int i;
+ int nshift = INTVAL (operands[2]);
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ output_asm_insn ("addk\t%0,r0,%1", operands);
+ output_asm_insn ("sra\t%0,%1", operands);
+ for (i = 0; i < (nshift - 2); i++)
+ output_asm_insn ("sra\t%0,%0", operands);
+ return "sra\t%0,%0";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "124")]
+)
+
+(define_insn "*ashlri_reg"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ ""
+ {
+ operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
+ output_asm_insn ("andi\t%3,%2,31", operands);
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ output_asm_insn ("addk\t%0,r0,%1", operands);
+ /* Exit the loop if zero shift. */
+ output_asm_insn ("beqid\t%3,.+20", operands);
+ /* Emit the loop. */
+ output_asm_insn ("addk\t%0,%0,r0", operands);
+ output_asm_insn ("addik\t%3,%3,-1", operands);
+ output_asm_insn ("bneid\t%3,.-4", operands);
+ return "sra\t%0,%0";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "28")]
+)
+
+;;----------------------------------------------------------------
+;; 32-bit right shifts (logical)
+;;----------------------------------------------------------------
+
+(define_expand "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "arith_operand" "")))]
+ ""
+ {
+ /* Avoid recursion for trivial cases. */
+ if (!((GET_CODE (operands [2]) == CONST_INT) && (INTVAL (operands[2]) == 1)))
+ if (microblaze_expand_shift (operands))
+ DONE;
+ }
+)
+
+;; Irrespective of if we have a barrel-shifter or not, we want to match
+;; shifts by 1 with a special pattern. When a barrel shifter is present,
+;; saves a cycle. If not, allows us to annotate the instruction for delay
+;; slot optimization
+(define_insn "*lshrsi3_byone"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "arith_operand" "I")))]
+ "(INTVAL (operands[2]) == 1)"
+ "srl\t%0,%1"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")]
+)
+
+;; Barrel shift right logical
+(define_insn "*lshrsi3_bshift"
+ [(set (match_operand:SI 0 "register_operand" "=d,d")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "d,d")
+ (match_operand:SI 2 "arith_operand" "I,d")))]
+ "TARGET_BARREL_SHIFT"
+ "@
+ bsrli\t%0,%1,%2
+ bsrl\t%0,%1,%2"
+ [(set_attr "type" "bshift,bshift")
+ (set_attr "mode" "SI,SI")
+ (set_attr "length" "4,4")]
+)
+
+(define_insn "*lshrsi_inline"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "immediate_operand" "I")))]
+ ""
+ {
+ int i;
+ int nshift = INTVAL (operands[2]);
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ output_asm_insn ("addk\t%0,r0,%1", operands);
+ output_asm_insn ("srl\t%0,%1", operands);
+ for (i = 0; i < (nshift - 2); i++)
+ output_asm_insn ("srl\t%0,%0", operands);
+ return "srl\t%0,%0";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "124")]
+)
+
+(define_insn "*lshlri_reg"
+ [(set (match_operand:SI 0 "register_operand" "=&d")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ ""
+ {
+ operands[3] = gen_rtx_REG (SImode, MB_ABI_ASM_TEMP_REGNUM);
+ output_asm_insn ("andi\t%3,%2,31", operands);
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ output_asm_insn ("addk\t%0,r0,%1", operands);
+ /* Exit the loop if zero shift. */
+ output_asm_insn ("beqid\t%3,.+20", operands);
+ /* Emit the loop. */
+ output_asm_insn ("addk\t%0,%0,r0", operands);
+ output_asm_insn ("addik\t%3,%3,-1", operands);
+ output_asm_insn ("bneid\t%3,.-4", operands);
+ return "srl\t%0,%0";
+ }
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")
+ (set_attr "length" "28")]
+)
+
+;;----------------------------------------------------------------
+;; Setting a register from an integer comparison.
+;;----------------------------------------------------------------
+(define_expand "cstoresi4"
+ [(set (match_operand:SI 0 "register_operand")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:SI 2 "register_operand")
+ (match_operand:SI 3 "register_operand")]))]
+ "TARGET_PATTERN_COMPARE"
+ "if (GET_CODE (operand1) != EQ && GET_CODE (operand1) != NE)
+ FAIL;
+ "
+)
+
+(define_insn "seq_internal_pat"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (eq:SI
+ (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ "TARGET_PATTERN_COMPARE"
+ "pcmpeq\t%0,%1,%2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")]
+)
+
+(define_insn "sne_internal_pat"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (ne:SI
+ (match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")))]
+ "TARGET_PATTERN_COMPARE"
+ "pcmpne\t%0,%1,%2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")]
+)
+
+(define_insn "signed_compare"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (unspec
+ [(match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")] UNSPEC_CMP))]
+ ""
+ "cmp\t%0,%1,%2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+(define_insn "unsigned_compare"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (unspec
+ [(match_operand:SI 1 "register_operand" "d")
+ (match_operand:SI 2 "register_operand" "d")] UNSPEC_CMPU))]
+ ""
+ "cmpu\t%0,%1,%2"
+ [(set_attr "type" "arith")
+ (set_attr "mode" "SI")
+ (set_attr "length" "4")])
+
+;;----------------------------------------------------------------
+;; Setting a register from an floating point comparison.
+;;----------------------------------------------------------------
+(define_insn "cstoresf4"
+ [(set (match_operand:SI 0 "register_operand")
+ (match_operator:SI 1 "ordered_comparison_operator"
+ [(match_operand:SF 2 "register_operand")
+ (match_operand:SF 3 "register_operand")]))]
+ "TARGET_HARD_FLOAT"
+ "fcmp.%C1\t%0,%3,%2"
+ [(set_attr "type" "fcmp")
+ (set_attr "mode" "SF")
+ (set_attr "length" "4")]
+)
+
+;;----------------------------------------------------------------
+;; Conditional branches
+;;----------------------------------------------------------------
+
+(define_expand "cbranchsi4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:SI 1 "register_operand")
+ (match_operand:SI 2 "arith_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ ""
+{
+ microblaze_expand_conditional_branch (SImode, operands);
+ DONE;
+})
+
+(define_expand "cbranchsf4"
+ [(set (pc)
+ (if_then_else (match_operator:SI 0 "ordered_comparison_operator"
+ [(match_operand:SF 1 "register_operand")
+ (match_operand:SF 2 "register_operand")])
+ (label_ref (match_operand 3 ""))
+ (pc)))]
+ "TARGET_HARD_FLOAT"
+{
+ microblaze_expand_conditional_branch_sf (operands);
+ DONE;
+
+})
+
+;; Used to implement comparison instructions
+(define_expand "condjump"
+ [(set (pc)
+ (if_then_else (match_operand 0)
+ (label_ref (match_operand 1))
+ (pc)))])
+
+(define_insn "branch_zero"
+ [(set (pc)
+ (if_then_else (match_operator:SI 0 "ordered_comparison_operator"
+ [(match_operand:SI 1 "register_operand" "d")
+ (const_int 0)])
+ (match_operand:SI 2 "pc_or_label_operand" "")
+ (match_operand:SI 3 "pc_or_label_operand" "")))
+ ]
+ ""
+ {
+ if (operands[3] == pc_rtx)
+ return "b%C0i%?\t%z1,%2";
+ else
+ return "b%N0i%?\t%z1,%3";
+ }
+ [(set_attr "type" "branch")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")]
+)
+
+;;----------------------------------------------------------------
+;; Unconditional branches
+;;----------------------------------------------------------------
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ {
+ if (GET_CODE (operands[0]) == REG)
+ return "br%?\t%0";
+ else
+ return "bri%?\t%l0";
+ }
+ [(set_attr "type" "jump")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+(define_expand "indirect_jump"
+ [(set (pc) (match_operand 0 "register_operand" "d"))]
+ ""
+ {
+ rtx dest = operands[0];
+ if (GET_CODE (dest) != REG || GET_MODE (dest) != Pmode)
+ operands[0] = copy_to_mode_reg (Pmode, dest);
+
+ emit_jump_insn (gen_indirect_jump_internal1 (operands[0]));
+ DONE;
+ }
+)
+
+;; Indirect jumps. Jump to register values. Assuming absolute jumps
+
+(define_insn "indirect_jump_internal1"
+ [(set (pc) (match_operand:SI 0 "register_operand" "d"))]
+ ""
+ "bra%?\t%0"
+ [(set_attr "type" "jump")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+(define_expand "tablejump"
+ [(set (pc)
+ (match_operand 0 "register_operand" "d"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ {
+ gcc_assert (GET_MODE (operands[0]) == Pmode);
+
+ if (!flag_pic)
+ emit_jump_insn (gen_tablejump_internal1 (operands[0], operands[1]));
+ else
+ emit_jump_insn (gen_tablejump_internal3 (operands[0], operands[1]));
+ DONE;
+ }
+)
+
+(define_insn "tablejump_internal1"
+ [(set (pc)
+ (match_operand:SI 0 "register_operand" "d"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "bra%?\t%0 "
+ [(set_attr "type" "jump")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+(define_expand "tablejump_internal3"
+ [(parallel [(set (pc)
+ (plus:SI (match_operand:SI 0 "register_operand" "d")
+ (label_ref:SI (match_operand:SI 1 "" ""))))
+ (use (label_ref:SI (match_dup 1)))])]
+ ""
+ ""
+)
+
+;; need to change for MicroBlaze PIC
+(define_insn ""
+ [(set (pc)
+ (plus:SI (match_operand:SI 0 "register_operand" "d")
+ (label_ref:SI (match_operand 1 "" ""))))
+ (use (label_ref:SI (match_dup 1)))]
+ "next_active_insn (insn) != 0
+ && GET_CODE (PATTERN (next_active_insn (insn))) == ADDR_DIFF_VEC
+ && PREV_INSN (next_active_insn (insn)) == operands[1]
+ && flag_pic"
+ {
+ output_asm_insn ("addk\t%0,%0,r20",operands);
+ return "bra%?\t%0";
+}
+ [(set_attr "type" "jump")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+(define_expand "tablejump_internal4"
+ [(parallel [(set (pc)
+ (plus:DI (match_operand:DI 0 "register_operand" "d")
+ (label_ref:DI (match_operand:SI 1 "" ""))))
+ (use (label_ref:DI (match_dup 1)))])]
+ ""
+ ""
+)
+
+;;----------------------------------------------------------------
+;; Function prologue/epilogue and stack allocation
+;;----------------------------------------------------------------
+(define_expand "prologue"
+ [(const_int 1)]
+ ""
+ {
+ microblaze_expand_prologue ();
+ DONE;
+ }
+)
+
+(define_expand "epilogue"
+ [(use (const_int 0))]
+ ""
+ {
+ microblaze_expand_epilogue ();
+ DONE;
+ }
+)
+
+;; An insn to allocate new stack space for dynamic use (e.g., alloca).
+;; We copy the return address, decrement the stack pointer and save the
+;; return address again at the new stack top
+
+(define_expand "allocate_stack"
+ [(set (match_operand 0 "register_operand" "=r")
+ (minus (reg 1) (match_operand 1 "register_operand" "")))
+ (set (reg 1)
+ (minus (reg 1) (match_dup 1)))]
+ ""
+ {
+ rtx retaddr = gen_rtx_MEM (Pmode, stack_pointer_rtx);
+ rtx rtmp = gen_rtx_REG (SImode, R_TMP);
+ rtx neg_op0;
+
+ emit_move_insn (rtmp, retaddr);
+ if (GET_CODE (operands[1]) != CONST_INT)
+ {
+ neg_op0 = gen_reg_rtx (Pmode);
+ emit_insn (gen_negsi2 (neg_op0, operands[1]));
+ } else
+ neg_op0 = GEN_INT (- INTVAL (operands[1]));
+
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, neg_op0));
+ emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), rtmp);
+ emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
+ emit_insn (gen_rtx_CLOBBER (SImode, rtmp));
+ DONE;
+ }
+)
+
+;; Trivial return. Make it look like a normal return insn as that
+;; allows jump optimizations to work better .
+(define_insn "return"
+ [(return)]
+ "microblaze_can_use_return_insn ()"
+ {
+ if (microblaze_is_interrupt_handler ())
+ return "rtid\tr14, 0\;%#";
+ else
+ return "rtsd\tr15, 8\;%#";
+ }
+ [(set_attr "type" "jump")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+;; Normal return.
+;; We match any mode for the return address, so that this will work with
+;; both 32 bit and 64 bit targets.
+
+(define_insn "return_internal"
+ [(parallel [(use (match_operand:SI 0 "register_operand" ""))
+ (return)])]
+ ""
+ {
+ if (microblaze_is_interrupt_handler ())
+ return "rtid\tr14,0 \;%#";
+ else
+ return "rtsd\tr15,8 \;%#";
+ }
+ [(set_attr "type" "jump")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+
+;; Block any insns from across this point
+;; Useful to group sequences together.
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] 0)]
+ ""
+ ""
+ [(set_attr "type" "unknown")
+ (set_attr "mode" "none")
+ (set_attr "length" "0")])
+
+
+;;----------------------------------------------------------------
+;; Function calls
+;;----------------------------------------------------------------
+
+(define_expand "call"
+ [(parallel [(call (match_operand 0 "memory_operand" "m")
+ (match_operand 1 "" "i"))
+ (clobber (reg:SI R_SR))
+ (use (match_operand 2 "" ""))
+ (use (match_operand 3 "" ""))])]
+ ""
+ {
+ rtx addr = XEXP (operands[0], 0);
+
+ if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
+ && !SYMBOL_REF_LOCAL_P (addr))
+ {
+ rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
+ XEXP (operands[0], 0) = temp;
+ }
+
+ if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
+ || !call_insn_operand (addr, VOIDmode))
+ XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, addr);
+
+ if (GET_CODE (XEXP (operands[0], 0)) == UNSPEC)
+ emit_call_insn (gen_call_internal_plt0 (operands[0], operands[1],
+ gen_rtx_REG (SImode,
+ GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
+ pic_offset_table_rtx));
+ else
+ emit_call_insn (gen_call_internal0 (operands[0], operands[1],
+ gen_rtx_REG (SImode,
+ GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
+
+ DONE;
+ }
+)
+
+(define_expand "call_internal0"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (clobber (match_operand:SI 2 "" ""))])]
+ ""
+ {
+ }
+)
+
+(define_expand "call_internal_plt0"
+ [(parallel [(call (match_operand 0 "" "")
+ (match_operand 1 "" ""))
+ (clobber (match_operand:SI 2 "" ""))
+ (use (match_operand:SI 3 "" ""))])]
+ ""
+ {
+ }
+)
+
+(define_insn "call_internal_plt"
+ [(call (mem (match_operand:SI 0 "call_insn_plt_operand" ""))
+ (match_operand:SI 1 "" "i"))
+ (clobber (reg:SI R_SR))
+ (use (reg:SI R_GOT))]
+ "flag_pic"
+ {
+ register rtx target2 = gen_rtx_REG (Pmode,
+ GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
+ gen_rtx_CLOBBER (VOIDmode, target2);
+ return "brlid\tr15,%0\;%#";
+ }
+ [(set_attr "type" "call")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+(define_insn "call_internal1"
+ [(call (mem (match_operand:SI 0 "call_insn_operand" "ri"))
+ (match_operand:SI 1 "" "i"))
+ (clobber (reg:SI R_SR))]
+ ""
+ {
+ register rtx target = operands[0];
+ register rtx target2 = gen_rtx_REG (Pmode,
+ GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
+ if (GET_CODE (target) == SYMBOL_REF) {
+ gen_rtx_CLOBBER (VOIDmode, target2);
+ return "brlid\tr15,%0\;%#";
+ } else if (GET_CODE (target) == CONST_INT)
+ return "la\t%@,r0,%0\;brald\tr15,%@\;%#";
+ else if (GET_CODE (target) == REG)
+ return "brald\tr15,%0\;%#";
+ else {
+ fprintf (stderr,"Unsupported call insn\n");
+ return NULL;
+ }
+ }
+ [(set_attr "type" "call")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+;; calls.c now passes a fourth argument, make saber happy
+
+(define_expand "call_value"
+ [(parallel [(set (match_operand 0 "register_operand" "=d")
+ (call (match_operand 1 "memory_operand" "m")
+ (match_operand 2 "" "i")))
+ (clobber (reg:SI R_SR))
+ (use (match_operand 3 "" ""))])] ;; next_arg_reg
+ ""
+ {
+ rtx addr = XEXP (operands[1], 0);
+
+ if (flag_pic == 2 && GET_CODE (addr) == SYMBOL_REF
+ && !SYMBOL_REF_LOCAL_P (addr))
+ {
+ rtx temp = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_PLT);
+ XEXP (operands[1], 0) = temp;
+ }
+
+ if ((GET_CODE (addr) != REG && !CONSTANT_ADDRESS_P (addr))
+ || !call_insn_operand (addr, VOIDmode))
+ XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, addr);
+
+ if (GET_CODE (XEXP (operands[1], 0)) == UNSPEC)
+ emit_call_insn (gen_call_value_intern_plt0 (operands[0], operands[1],
+ operands[2],
+ gen_rtx_REG (SImode,
+ GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM),
+ pic_offset_table_rtx));
+ else
+ emit_call_insn (gen_call_value_internal (operands[0], operands[1],
+ operands[2],
+ gen_rtx_REG (SImode,
+ GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)));
+
+ DONE;
+ }
+)
+
+
+(define_expand "call_value_internal"
+ [(parallel [(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (clobber (match_operand:SI 3 "" ""))
+ ])]
+ ""
+ {}
+)
+
+(define_expand "call_value_intern_plt0"
+ [(parallel[(set (match_operand 0 "" "")
+ (call (match_operand 1 "" "")
+ (match_operand 2 "" "")))
+ (clobber (match_operand:SI 3 "" ""))
+ (use (match_operand:SI 4 "" ""))])]
+ "flag_pic"
+ {}
+)
+
+(define_insn "call_value_intern_plt"
+ [(set (match_operand:VOID 0 "register_operand" "=d")
+ (call (mem (match_operand:SI 1 "call_insn_plt_operand" ""))
+ (match_operand:SI 2 "" "i")))
+ (clobber (match_operand:SI 3 "register_operand" "=d"))
+ (use (match_operand:SI 4 "register_operand"))]
+ "flag_pic"
+ {
+ register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
+
+ gen_rtx_CLOBBER (VOIDmode,target2);
+ return "brlid\tr15,%1\;%#";
+ }
+ [(set_attr "type" "call")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+(define_insn "call_value_intern"
+ [(set (match_operand:VOID 0 "register_operand" "=d")
+ (call (mem (match_operand:VOID 1 "call_insn_operand" "ri"))
+ (match_operand:SI 2 "" "i")))
+ (clobber (match_operand:SI 3 "register_operand" "=d"))]
+ ""
+ {
+ register rtx target = operands[1];
+ register rtx target2=gen_rtx_REG (Pmode,GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM);
+
+ if (GET_CODE (target) == SYMBOL_REF){
+ gen_rtx_CLOBBER (VOIDmode,target2);
+ return "brlid\tr15,%1\;%#";
+ }
+ else if (GET_CODE (target) == CONST_INT)
+ return "la\t%@,r0,%1\;brald\tr15,%@\;%#";
+ else if (GET_CODE (target) == REG)
+ return "brald\tr15,%1\;%#";
+ else
+ return "Unsupported call insn\n";
+ }
+ [(set_attr "type" "call")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+
+;; Call subroutine returning any type.
+(define_expand "untyped_call"
+ [(parallel [(call (match_operand 0 "" "")
+ (const_int 0))
+ (match_operand 1 "" "")
+ (match_operand 2 "" "")])]
+ ""
+ {
+ if (operands[0]) /* silence statement not reached warnings */
+ {
+ int i;
+
+ emit_call_insn (gen_call (operands[0], const0_rtx, NULL, const0_rtx));
+
+ for (i = 0; i < XVECLEN (operands[2], 0); i++)
+ {
+ rtx set = XVECEXP (operands[2], 0, i);
+ emit_move_insn (SET_DEST (set), SET_SRC (set));
+ }
+
+ emit_insn (gen_blockage ());
+ DONE;
+ }
+ }
+)
+
+;;----------------------------------------------------------------
+;; Misc.
+;;----------------------------------------------------------------
+
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+ [(set_attr "type" "nop")
+ (set_attr "mode" "none")
+ (set_attr "length" "4")])
+
+;; The insn to set GOT. The hardcoded number "8" accounts for $pc difference
+;; between "mfs" and "addik" instructions.
+(define_insn "set_got"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))]
+ ""
+ "mfs\t%0,rpc\n\taddik\t%0,%0,_GLOBAL_OFFSET_TABLE_+8"
+ [(set_attr "type" "multi")
+ (set_attr "length" "12")])
+
Index: gcc/config/microblaze/constraints.md
===================================================================
--- gcc/config/microblaze/constraints.md (revision 0)
+++ gcc/config/microblaze/constraints.md (revision 0)
@@ -0,0 +1,72 @@
+;; Constraint definitions for Xilinx MicroBlaze processors.
+;; Copyright 2010 Free Software Foundation, Inc.
+
+;; Contributed by Michael Eager <eager@eagercon.com>.
+
+;; This file is part of GCC.
+
+;; GCC 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 3, or (at your option)
+;; any later version.
+
+;; GCC 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 GCC; see the file COPYING3. If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_register_constraint "d" "GR_REGS"
+ "A general register.")
+
+(define_register_constraint "z" "ST_REGS"
+ "A status register.")
+
+;; Define integer constraints
+
+(define_constraint "I"
+ "A signed 16-bit constant."
+ (and (match_code "const_int")
+ (match_test "SMALL_OPERAND (ival)")))
+
+(define_constraint "J"
+ "Integer zero."
+ (and (match_code "const_int")
+ (match_test "ival == 0")))
+
+(define_constraint "M"
+ "A constant which needs two instructions to load."
+ (and (match_code "const_int")
+ (match_test "LARGE_OPERAND (ival)")))
+
+(define_constraint "N"
+ "A constant in the range -65535 to -1 (inclusive)."
+ (and (match_code "const_int")
+ (match_test "(unsigned HOST_WIDE_INT) (ival + 0xffff) < 0xffff")))
+
+(define_constraint "P"
+ "A constant in the range 1 to 65535 (inclusive)."
+ (and (match_code "const_int")
+ (match_test "ival > 0 && ival < 0x10000")))
+
+;; Define floating point constraints
+
+(define_constraint "G"
+ "Floating-point zero."
+ (and (match_code "const_double")
+ (match_test "op == CONST0_RTX (mode)")))
+
+;; Define memory constraints
+
+(define_memory_constraint "R"
+ "Memory operand which fits in single instruction."
+ (and (match_code "mem")
+ (match_test "simple_memory_operand (op, GET_MODE (op))")))
+
+(define_memory_constraint "T"
+ "Double word operand."
+ (and (match_code "mem")
+ (match_test "double_memory_operand (op, GET_MODE (op))")))
Index: gcc/config/microblaze/crtn.s
===================================================================
--- gcc/config/microblaze/crtn.s (revision 0)
+++ gcc/config/microblaze/crtn.s (revision 0)
@@ -0,0 +1,35 @@
+/* crtn.s for __init, __fini
+ This file supplies the epilogue for __init and __fini routines
+
+ Copyright 2009, 2010 Free Software Foundation, Inc.
+
+ Contributed by Michael Eager <eager@eagercon.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 3, or (at your option) any
+ later version.
+
+ GCC 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+ .section .init, "ax"
+ lw r15, r0, r1
+ rtsd r15, 8
+ addik r1, r1, 8
+
+ .section .fini, "ax"
+ lw r15, r0, r1
+ rtsd r15, 8
+ addik r1, r1, 8
Index: gcc/config/microblaze/microblaze.opt
===================================================================
--- gcc/config/microblaze/microblaze.opt (revision 0)
+++ gcc/config/microblaze/microblaze.opt (revision 0)
@@ -0,0 +1,97 @@
+; Options for the MicroBlaze port of the compiler
+;
+; Copyright 2009, 2010 Free Software Foundation, Inc.
+;
+; Contributed by Michael Eager <eager@eagercon.com>.
+;
+; This file is part of GCC.
+;
+; GCC 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 3, or (at your option) any later
+; version.
+;
+; GCC 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 GCC; see the file COPYING3. If not see
+; <http://www.gnu.org/licenses/>. */
+
+msoft-float
+Target Report RejectNegative Mask(SOFT_FLOAT)
+Use software emulation for floating point (default)
+
+mhard-float
+Target Report RejectNegative InverseMask(SOFT_FLOAT, HARD_FLOAT)
+Use hardware floating point instructions
+
+msmall-divides
+Target Mask(SMALL_DIVIDES)
+Use table lookup optimization for small signed integer divisions
+
+mcpu=
+Target RejectNegative Joined Var(microblaze_select_cpu)
+-mcpu=PROCESSOR Use features of and schedule code for given CPU
+
+mmemcpy
+Target Mask(MEMCPY)
+Don't optimize block moves, use memcpy
+
+mxl-soft-mul
+Target Mask(SOFT_MUL)
+Use the soft multiply emulation (default)
+
+mxl-soft-div
+Target Mask(SOFT_DIV)
+Use the software emulation for divides (default)
+
+mxl-barrel-shift
+Target Mask(BARREL_SHIFT)
+Use the hardware barrel shifter instead of emulation
+
+mxl-pattern-compare
+Target Mask(PATTERN_COMPARE)
+Use pattern compare instructions
+
+mxl-stack-check
+Target Mask(STACK_CHECK)
+Check for stack overflow at runtime
+
+mxl-gp-opt
+Target Mask(XLGPOPT)
+Use GP relative sdata/sbss sections
+
+mno-clearbss
+Target RejectNegative
+Clear the BSS to zero and place zero initialized in BSS
+
+mxl-multiply-high
+Target Mask(MULTIPLY_HIGH)
+Use multiply high instructions for high part of 32x32 multiply
+
+mxl-float-convert
+Target Mask(FLOAT_CONVERT)
+Use hardware floating point converstion instructions
+
+mxl-float-sqrt
+Target Mask(FLOAT_SQRT)
+Use hardware floating point square root instruction
+
+mxl-mode-executable
+Target Mask(XL_MODE_EXECUTABLE)
+Description for mxl-mode-executable
+
+mxl-mode-xmdstub
+Target Mask(XL_MODE_XMDSTUB)
+Description for mxl-mode-xmdstub
+
+mxl-mode-bootstrap
+Target Mask(XL_MODE_BOOTSTRAP)
+Description for mxl-mode-bootstrap
+
+mxl-mode-novectors
+Target Mask(XL_MODE_NOVECTORS)
+Description for mxl-mode-novectors
Index: gcc/config/microblaze/microblaze-c.c
===================================================================
--- gcc/config/microblaze/microblaze-c.c (revision 0)
+++ gcc/config/microblaze/microblaze-c.c (revision 0)
@@ -0,0 +1,93 @@
+/* Subroutines used for the C front end for Xilinx MicroBlaze.
+ Copyright 2010 Free Software Foundation, Inc.
+
+ Contributed by Michael Eager <eager@eagercon.com>.
+
+ This file is part of GCC.
+
+ GCC 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 3, or (at your
+ option) any later version.
+
+ GCC 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 GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "c-family/c-common.h"
+#include "toplev.h"
+#include "tm_p.h"
+#include "target.h"
+
+#define builtin_define(TXT) cpp_define (pfile, TXT)
+#define builtin_assert(TXT) cpp_assert (pfile, TXT)
+
+/* Define preprocessor symbols for MicroBlaze.
+ Symbols which do not start with __ are deprecated. */
+
+void
+microblaze_cpp_define (cpp_reader *pfile)
+{
+ builtin_assert ("cpu=microblaze");
+ builtin_assert ("machine=microblaze");
+ builtin_define ("__MICROBLAZE__");
+ if (!TARGET_SOFT_MUL)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_MUL");
+ builtin_define ("__HAVE_HW_MUL__");
+ }
+ if (TARGET_MULTIPLY_HIGH)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_MUL_HIGH");
+ builtin_define ("__HAVE_HW_MUL_HIGH__");
+ }
+ if (!TARGET_SOFT_DIV)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_DIV");
+ builtin_define ("__HAVE_HW_DIV__");
+ }
+ if (TARGET_BARREL_SHIFT)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_BSHIFT");
+ builtin_define ("__HAVE_HW_BSHIFT__");
+ }
+ if (TARGET_PATTERN_COMPARE)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_PCMP");
+ builtin_define ("__HAVE_HW_PCMP__");
+ }
+ if (TARGET_HARD_FLOAT)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_FPU");
+ builtin_define ("__HAVE_HW_FPU__");
+ }
+ if (TARGET_FLOAT_CONVERT)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_FPU_CONVERT");
+ builtin_define ("__HAVE_HW_FPU_CONVERT__");
+ }
+ if (TARGET_FLOAT_SQRT)
+ {
+ if (!flag_iso)
+ builtin_define ("HAVE_HW_FPU_SQRT");
+ builtin_define ("__HAVE_HW_FPU_SQRT__");
+ }
+}
Index: gcc/config/microblaze/t-microblaze
===================================================================
--- gcc/config/microblaze/t-microblaze (revision 0)
+++ gcc/config/microblaze/t-microblaze (revision 0)
@@ -0,0 +1,33 @@
+# For C++ crtstuff
+EXTRA_MULTILIB_PARTS = crtbegin$(objext) crtend$(objext)
+
+EXTRA_PARTS += crti$(objext) crtn$(objext)
+
+MULTILIB_OPTIONS = mxl-barrel-shift mno-xl-soft-mul mxl-multiply-high
+MULTILIB_DIRNAMES = bs m mh
+MULTILIB_EXCEPTIONS = *mxl-barrel-shift/mxl-multiply-high mxl-multiply-high
+
+# Extra files
+microblaze-c.o: $(srcdir)/config/microblaze/microblaze-c.c \
+ $(srcdir)/config/microblaze/microblaze-protos.h \
+ $(CONFIG_H) $(SYSTEM_H) $(CPPLIB_H) $(TM_P_H) $(TREE_H) errors.h $(TM_H)
+ $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+ $(srcdir)/config/microblaze/microblaze-c.c
+
+# Build soft FP routines.
+FPBIT = fp-bit.c
+DPBIT = dp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+# Assemble startup files
+$(T)crti$(objext): $(srcdir)/config/microblaze/crti.s
+ $(GCC_FOR_TARGET) -c $(srcdir)/config/microblaze/crti.s -o $(T)crti$(objext)
+
+$(T)crtn$(objext): $(srcdir)/config/microblaze/crtn.s
+ $(GCC_FOR_TARGET) -c $(srcdir)/config/microblaze/crtn.s -o $(T)crtn$(objext)
Index: gcc/config/microblaze/microblaze.c
===================================================================
--- gcc/config/microblaze/microblaze.c (revision 0)
+++ gcc/config/microblaze/microblaze.c (revision 0)
@@ -0,0 +1,3032 @@
+/* Subroutines used for code generation on Xilinx MicroBlaze.
+ Copyright 2009, 2010 Free Software Foundation, Inc.
+
+ Contributed by Michael Eager <eager@eagercon.com>.
+
+ This file is part of GCC.
+
+ GCC 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 3, or (at your
+ option) any later version.
+
+ GCC 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 GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include <signal.h>
+#include "tm.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "real.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-flags.h"
+#include "insn-attr.h"
+#include "integrate.h"
+#include "recog.h"
+#include "toplev.h"
+#include "tree.h"
+#include "function.h"
+#include "expr.h"
+#include "flags.h"
+#include "reload.h"
+#include "output.h"
+#include "ggc.h"
+#include "hashtab.h"
+#include "target.h"
+#include "target-def.h"
+#include "tm_p.h"
+#include "gstab.h"
+#include "df.h"
+#include "optabs.h"
+#include "diagnostic-core.h"
+
+#define MICROBLAZE_VERSION_COMPARE(VA,VB) strcasecmp (VA, VB)
+
+/* Classifies an address.
+
+ADDRESS_INVALID
+An invalid address.
+
+ADDRESS_REG
+
+A natural register or a register + const_int offset address.
+The register satisfies microblaze_valid_base_register_p and the
+offset is a const_arith_operand.
+
+ADDRESS_REG_INDEX
+
+A natural register offset by the index contained in an index register. The base
+register satisfies microblaze_valid_base_register_p and the index register
+satisfies microblaze_valid_index_register_p
+
+ADDRESS_CONST_INT
+
+A signed 16/32-bit constant address.
+
+ADDRESS_SYMBOLIC:
+
+A constant symbolic address or a (register + symbol). */
+
+enum microblaze_address_type
+{
+ ADDRESS_INVALID,
+ ADDRESS_REG,
+ ADDRESS_REG_INDEX,
+ ADDRESS_CONST_INT,
+ ADDRESS_SYMBOLIC,
+ ADDRESS_GOTOFF,
+ ADDRESS_PLT
+};
+
+/* Classifies symbols
+
+SYMBOL_TYPE_GENERAL
+
+A general symbol. */
+enum microblaze_symbol_type
+{
+ SYMBOL_TYPE_INVALID,
+ SYMBOL_TYPE_GENERAL
+};
+
+/* Classification of a MicroBlaze address. */
+struct microblaze_address_info
+{
+ enum microblaze_address_type type;
+ rtx regA; /* Contains valid values on ADDRESS_REG, ADDRESS_REG_INDEX,
+ ADDRESS_SYMBOLIC. */
+ rtx regB; /* Contains valid values on ADDRESS_REG_INDEX. */
+ rtx offset; /* Contains valid values on ADDRESS_CONST_INT and ADDRESS_REG. */
+ rtx symbol; /* Contains valid values on ADDRESS_SYMBOLIC. */
+ enum microblaze_symbol_type symbol_type;
+};
+
+/* Structure to be filled in by compute_frame_size with register
+ save masks, and offsets for the current function. */
+
+struct GTY(()) microblaze_frame_info {
+ 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 link_debug_size; /* # bytes for the link reg and back pointer. */
+ int gp_reg_size; /* # bytes needed to store gp regs. */
+ long gp_offset; /* offset from new sp to store gp registers. */
+ long mask; /* mask of saved gp registers. */
+ int initialized; /* != 0 if frame size already calculated. */
+ int num_gp; /* number of gp registers saved. */
+ long insns_len; /* length of insns. */
+ int alloc_stack; /* Flag to indicate if the current function
+ must not create stack space. (As an optimization). */
+};
+
+/* Global variables for machine-dependent things. */
+
+/* Toggle which pipleline interface to use. */
+static GTY(()) int microblaze_sched_use_dfa = 0;
+
+/* 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). */
+int microblaze_section_threshold = -1;
+
+/* Prevent scheduling potentially exception causing instructions in
+ delay slots. -mcpu=v3.00.a or v4.00.a turns this on. */
+int microblaze_no_unsafe_delay;
+
+/* Which CPU pipeline do we use. We haven't really standardized on a CPU
+ version having only a particular type of pipeline. There can still be
+ options on the CPU to scale pipeline features up or down. :(
+ Bad Presentation (??), so we let the MD file rely on the value of
+ this variable instead Making PIPE_5 the default. It should be backward
+ optimal with PIPE_3 MicroBlazes. */
+enum pipeline_type microblaze_pipe = MICROBLAZE_PIPE_5;
+
+/* High and low marks for floating point values which we will accept
+ as legitimate constants for LEGITIMATE_CONSTANT_P. These are
+ initialized in override_options. */
+REAL_VALUE_TYPE dfhigh, dflow, sfhigh, sflow;
+
+/* Array giving truth value on whether or not a given hard register
+ can support a given mode. */
+char microblaze_hard_regno_mode_ok[(int)MAX_MACHINE_MODE]
+ [FIRST_PSEUDO_REGISTER];
+
+/* Current frame information calculated by compute_frame_size. */
+struct microblaze_frame_info current_frame_info;
+
+/* Zero structure to initialize current_frame_info. */
+struct microblaze_frame_info zero_frame_info;
+
+/* List of all MICROBLAZE punctuation characters used by print_operand. */
+char microblaze_print_operand_punct[256];
+
+/* Map GCC register number to debugger register number. */
+int microblaze_dbx_regno[FIRST_PSEUDO_REGISTER];
+
+/* Map hard register number to register class. */
+enum reg_class microblaze_regno_to_class[] =
+{
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ GR_REGS, GR_REGS, GR_REGS, GR_REGS,
+ ST_REGS, GR_REGS, GR_REGS, GR_REGS
+};
+
+/* MicroBlaze specific machine attributes.
+ interrupt_handler - Interrupt handler attribute to add interrupt prologue
+ and epilogue and use appropriate interrupt return.
+ save_volatiles - Similiar to interrupt handler, but use normal return. */
+int interrupt_handler;
+int save_volatiles;
+
+const struct attribute_spec microblaze_attribute_table[] = {
+ /* name min_len, max_len, decl_req, type_req, fn_type, req_handler */
+ {"interrupt_handler", 0, 0, true, false, false, NULL},
+ {"save_volatiles" , 0, 0, true, false, false, NULL},
+ { NULL, 0, 0, false, false, false, NULL}
+};
+
+static int microblaze_interrupt_function_p (tree);
+
+section *sdata2_section;
+
+/* Return truth value if a CONST_DOUBLE is ok to be a legitimate constant. */
+int
+microblaze_const_double_ok (rtx op, enum machine_mode mode)
+{
+ REAL_VALUE_TYPE d;
+
+ if (GET_CODE (op) != CONST_DOUBLE)
+ return 0;
+
+ if (mode == VOIDmode)
+ return 1;
+
+ if (mode != SFmode && mode != DFmode)
+ return 0;
+
+ if (op == CONST0_RTX (mode))
+ return 1;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (d, op);
+
+ if (REAL_VALUE_ISNAN (d))
+ return FALSE;
+
+ if (REAL_VALUE_NEGATIVE (d))
+ d = real_value_negate (&d);
+
+ if (mode == DFmode)
+ {
+ if (REAL_VALUES_LESS (d, dfhigh) && REAL_VALUES_LESS (dflow, d))
+ return 1;
+ }
+ else
+ {
+ if (REAL_VALUES_LESS (d, sfhigh) && REAL_VALUES_LESS (sflow, d))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return truth value if a memory operand fits in a single instruction
+ (ie, register + small offset) or (register + register). */
+
+int
+simple_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ rtx addr, plus0, plus1;
+
+ /* Eliminate non-memory operations. */
+ if (GET_CODE (op) != MEM)
+ return 0;
+
+ /* dword operations really put out 2 instructions, so eliminate them. */
+ /* ??? This isn't strictly correct. It is OK to accept multiword modes
+ here, since the length attributes are being set correctly, but only
+ if the address is offsettable. */
+ if (GET_MODE_SIZE (GET_MODE (op)) > UNITS_PER_WORD)
+ return 0;
+
+
+ /* Decode the address now. */
+ addr = XEXP (op, 0);
+ switch (GET_CODE (addr))
+
+ {
+ case REG:
+ return 1;
+
+ case PLUS:
+ plus0 = XEXP (addr, 0);
+ plus1 = XEXP (addr, 1);
+
+ if (GET_CODE (plus0) == REG && GET_CODE (plus1) == CONST_INT
+ && SMALL_INT (plus1))
+ {
+ return 1;
+ }
+ else if (GET_CODE (plus1) == REG && GET_CODE (plus0) == CONST_INT)
+ {
+ return 1;
+ }
+ else if (GET_CODE (plus0) == REG && GET_CODE (plus1) == REG)
+ {
+ return 1;
+ }
+ else
+ return 0;
+
+ case SYMBOL_REF:
+ return 0;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Return nonzero for a memory address that can be used to load or store
+ a doubleword. */
+
+int
+double_memory_operand (rtx op, enum machine_mode mode)
+{
+ rtx addr;
+
+ if (GET_CODE (op) != MEM || !memory_operand (op, mode))
+ {
+ /* During reload, we accept a pseudo register if it has an
+ appropriate memory address. If we don't do this, we will
+ wind up reloading into a register, and then reloading that
+ register from memory, when we could just reload directly from
+ memory. */
+ if (reload_in_progress
+ && GET_CODE (op) == REG
+ && REGNO (op) >= FIRST_PSEUDO_REGISTER
+ && reg_renumber[REGNO (op)] < 0
+ && reg_equiv_mem[REGNO (op)] != 0
+ && double_memory_operand (reg_equiv_mem[REGNO (op)], mode))
+ return 1;
+ return 0;
+ }
+
+ /* Make sure that 4 added to the address is a valid memory address.
+ This essentially just checks for overflow in an added constant. */
+
+ addr = XEXP (op, 0);
+
+ if (CONSTANT_ADDRESS_P (addr))
+ return 1;
+
+ return memory_address_p ((GET_MODE_CLASS (mode) == MODE_INT
+ ? SImode : SFmode), plus_constant (addr, 4));
+}
+
+/* Implement REG_OK_FOR_BASE_P -and- REG_OK_FOR_INDEX_P. */
+int
+microblaze_regno_ok_for_base_p (int regno, int strict)
+{
+ if (regno >= FIRST_PSEUDO_REGISTER)
+ {
+ if (!strict)
+ return true;
+ regno = reg_renumber[regno];
+ }
+
+ /* These fake registers will be eliminated to either the stack or
+ hard frame pointer, both of which are usually valid base registers.
+ Reload deals with the cases where the eliminated form isn't valid. */
+ if (regno == ARG_POINTER_REGNUM || regno == FRAME_POINTER_REGNUM)
+ return true;
+
+ return GP_REG_P (regno);
+}
+
+/* Return true if X is a valid base register for the given mode.
+ Allow only hard registers if STRICT. */
+
+static bool
+microblaze_valid_base_register_p (rtx x,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int strict)
+{
+ if (!strict && GET_CODE (x) == SUBREG)
+ x = SUBREG_REG (x);
+
+ return (GET_CODE (x) == REG
+ && microblaze_regno_ok_for_base_p (REGNO (x), strict));
+}
+
+static bool
+microblaze_classify_unspec (struct microblaze_address_info *info, rtx x)
+{
+ info->symbol_type = SYMBOL_TYPE_GENERAL;
+ info->symbol = XVECEXP (x, 0, 0);
+
+ if (XINT (x, 1) == UNSPEC_GOTOFF)
+ {
+ info->regA = gen_rtx_REG (SImode, PIC_OFFSET_TABLE_REGNUM);
+ info->type = ADDRESS_GOTOFF;
+ }
+ else if (XINT (x, 1) == UNSPEC_PLT)
+ {
+ info->type = ADDRESS_PLT;
+ }
+ else
+ {
+ return false;
+ }
+ return true;
+}
+
+
+/* Return true if X is a valid index register for the given mode.
+ Allow only hard registers if STRICT. */
+
+static bool
+microblaze_valid_index_register_p (rtx x,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int strict)
+{
+ if (!strict && GET_CODE (x) == SUBREG)
+ x = SUBREG_REG (x);
+
+ return (GET_CODE (x) == REG
+ /* A base register is good enough to be an index register on MicroBlaze. */
+ && microblaze_regno_ok_for_base_p (REGNO (x), strict));
+}
+
+/* Get the base register for accessing a value from the memory or
+ Symbol ref. Used for MicroBlaze Small Data Area Pointer Optimization. */
+static int
+get_base_reg (rtx x)
+{
+ tree decl;
+ int base_reg = (flag_pic ? MB_ABI_PIC_ADDR_REGNUM : MB_ABI_BASE_REGNUM);
+
+ if (TARGET_XLGPOPT
+ && GET_CODE (x) == SYMBOL_REF
+ && SYMBOL_REF_SMALL_P (x) && (decl = SYMBOL_REF_DECL (x)) != NULL)
+ {
+ if (TREE_READONLY (decl))
+ base_reg = MB_ABI_GPRO_REGNUM;
+ else
+ base_reg = MB_ABI_GPRW_REGNUM;
+ }
+
+ return base_reg;
+}
+
+/* Return true if X is a valid address for machine mode MODE. If it is,
+ fill in INFO appropriately. STRICT is true if we should only accept
+ hard base registers.
+
+ type regA regB offset symbol
+
+ ADDRESS_INVALID NULL NULL NULL NULL
+
+ ADDRESS_REG %0 NULL const_0 / NULL
+ const_int
+ ADDRESS_REG_INDEX %0 %1 NULL NULL
+
+ ADDRESS_SYMBOLIC r0 / NULL NULL symbol
+ sda_base_reg
+
+ ADDRESS_CONST_INT r0 NULL const NULL
+
+ For modes spanning multiple registers (DFmode in 32-bit GPRs,
+ DImode, TImode), indexed addressing cannot be used because
+ adjacent memory cells are accessed by adding word-sized offsets
+ during assembly output. */
+
+static bool
+microblaze_classify_address (struct microblaze_address_info *info, rtx x,
+ enum machine_mode mode, int strict)
+{
+ rtx xplus0;
+ rtx xplus1;
+
+ info->type = ADDRESS_INVALID;
+ info->regA = NULL;
+ info->regB = NULL;
+ info->offset = NULL;
+ info->symbol = NULL;
+ info->symbol_type = SYMBOL_TYPE_INVALID;
+
+ switch (GET_CODE (x))
+ {
+ case REG:
+ case SUBREG:
+ {
+ info->type = ADDRESS_REG;
+ info->regA = x;
+ info->offset = const0_rtx;
+ return microblaze_valid_base_register_p (info->regA, mode, strict);
+ }
+ case PLUS:
+ {
+ xplus0 = XEXP (x, 0);
+ xplus1 = XEXP (x, 1);
+
+ if (microblaze_valid_base_register_p (xplus0, mode, strict))
+ {
+ info->type = ADDRESS_REG;
+ info->regA = xplus0;
+
+ if (GET_CODE (xplus1) == CONST_INT)
+ {
+ info->offset = xplus1;
+ return true;
+ }
+ else if (GET_CODE (xplus1) == UNSPEC)
+ {
+ return microblaze_classify_unspec (info, xplus1);
+ }
+ else if ((GET_CODE (xplus1) == SYMBOL_REF ||
+ GET_CODE (xplus1) == LABEL_REF) && flag_pic == 2)
+ {
+ return false;
+ }
+ else if (GET_CODE (xplus1) == SYMBOL_REF ||
+ GET_CODE (xplus1) == LABEL_REF ||
+ GET_CODE (xplus1) == CONST)
+ {
+ if (GET_CODE (XEXP (xplus1, 0)) == UNSPEC)
+ return microblaze_classify_unspec (info, XEXP (xplus1, 0));
+ else if (flag_pic == 2)
+ {
+ return false;
+ }
+ info->type = ADDRESS_SYMBOLIC;
+ info->symbol = xplus1;
+ info->symbol_type = SYMBOL_TYPE_GENERAL;
+ return true;
+ }
+ else if (GET_CODE (xplus1) == REG
+ && microblaze_valid_index_register_p (xplus1, mode,
+ strict)
+ && (GET_MODE_SIZE (mode) <= UNITS_PER_WORD))
+ {
+ /* Restrict larger than word-width modes from using an index register. */
+ info->type = ADDRESS_REG_INDEX;
+ info->regB = xplus1;
+ return true;
+ }
+ }
+ break;
+ }
+ case CONST_INT:
+ {
+ info->regA = gen_rtx_raw_REG (mode, 0);
+ info->type = ADDRESS_CONST_INT;
+ info->offset = x;
+ return true;
+ }
+ case CONST:
+ case LABEL_REF:
+ case SYMBOL_REF:
+ {
+ info->type = ADDRESS_SYMBOLIC;
+ info->symbol_type = SYMBOL_TYPE_GENERAL;
+ info->symbol = x;
+ info->regA = gen_rtx_raw_REG (mode, get_base_reg (x));
+
+ if (GET_CODE (x) == CONST)
+ {
+ return !(flag_pic && pic_address_needs_scratch (x));
+ }
+ else if (flag_pic == 2)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ case UNSPEC:
+ {
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ return microblaze_classify_unspec (info, x);
+ }
+
+ default:
+ return false;
+ }
+
+ return false;
+}
+
+/* This function is used to implement GO_IF_LEGITIMATE_ADDRESS. It
+ returns a nonzero value if X is a legitimate address for a memory
+ operand of the indicated MODE. STRICT is nonzero if this function
+ is called during reload. */
+
+bool
+microblaze_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
+{
+ struct microblaze_address_info addr;
+
+ return microblaze_classify_address (&addr, x, mode, strict);
+}
+
+
+/* Try machine-dependent ways of modifying an illegitimate address
+ to be legitimate. If we find one, return the new, valid address.
+ This is used from only one place: `memory_address' in explow.c.
+
+ OLDX is the address as it was before break_out_memory_refs was
+ called. In some cases it is useful to look at this to decide what
+ needs to be done.
+
+ It is always safe for this function to do nothing. It exists to
+ recognize opportunities to optimize the output.
+
+ For the MicroBlaze, transform:
+
+ memory(X + <large int>)
+
+ into:
+
+ Y = <large int> & ~0x7fff;
+ Z = X + Y
+ memory (Z + (<large int> & 0x7fff));
+
+ This is for CSE to find several similar references, and only use one Z.
+
+ When PIC, convert addresses of the form memory (symbol+large int) to
+ memory (reg+large int). */
+
+static rtx
+microblaze_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ register rtx xinsn = x, result;
+
+ if (GET_CODE (xinsn) == CONST
+ && flag_pic && pic_address_needs_scratch (xinsn))
+ {
+ rtx ptr_reg = gen_reg_rtx (Pmode);
+ rtx constant = XEXP (XEXP (xinsn, 0), 1);
+
+ emit_move_insn (ptr_reg, XEXP (XEXP (xinsn, 0), 0));
+
+ result = gen_rtx_PLUS (Pmode, ptr_reg, constant);
+ if (SMALL_INT (constant))
+ return result;
+ /* Otherwise we fall through so the code below will fix the
+ constant. */
+ xinsn = result;
+ }
+
+ if (GET_CODE (xinsn) == PLUS)
+ {
+ register rtx xplus0 = XEXP (xinsn, 0);
+ register rtx xplus1 = XEXP (xinsn, 1);
+ register enum rtx_code code0 = GET_CODE (xplus0);
+ register enum rtx_code code1 = GET_CODE (xplus1);
+
+ if (code0 != REG && code1 == REG)
+ {
+ xplus0 = XEXP (xinsn, 1);
+ xplus1 = XEXP (xinsn, 0);
+ code0 = GET_CODE (xplus0);
+ code1 = GET_CODE (xplus1);
+ }
+
+ if (code0 == REG && REG_OK_FOR_BASE_P (xplus0)
+ && code1 == CONST_INT && !SMALL_INT (xplus1))
+ {
+ rtx int_reg = gen_reg_rtx (Pmode);
+ rtx ptr_reg = gen_reg_rtx (Pmode);
+
+ emit_move_insn (int_reg, GEN_INT (INTVAL (xplus1) & ~0x7fff));
+
+ emit_insn (gen_rtx_SET (VOIDmode,
+ ptr_reg,
+ gen_rtx_PLUS (Pmode, xplus0, int_reg)));
+
+ result = gen_rtx_PLUS (Pmode, ptr_reg,
+ GEN_INT (INTVAL (xplus1) & 0x7fff));
+ return result;
+ }
+
+ if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) && flag_pic == 2)
+ {
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ if (code1 == CONST)
+ {
+ xplus1 = XEXP (xplus1, 0);
+ code1 = GET_CODE (xplus1);
+ }
+ if (code1 == SYMBOL_REF)
+ {
+ result =
+ gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xplus1), UNSPEC_GOTOFF);
+ result = gen_rtx_CONST (Pmode, result);
+ result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
+ result = gen_const_mem (Pmode, result);
+ result = gen_rtx_PLUS (Pmode, xplus0, result);
+ return result;
+ }
+ }
+ }
+
+ if (GET_CODE (xinsn) == SYMBOL_REF)
+ {
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, xinsn), UNSPEC_GOTOFF);
+ result = gen_rtx_CONST (Pmode, result);
+ result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
+ result = gen_const_mem (Pmode, result);
+ return result;
+ }
+
+ return x;
+}
+
+/* Block Moves. */
+
+#define MAX_MOVE_REGS 8
+#define MAX_MOVE_BYTES (MAX_MOVE_REGS * UNITS_PER_WORD)
+
+/* Emit straight-line code to move LENGTH bytes from SRC to DEST.
+ Assume that the areas do not overlap. */
+
+static void
+microblaze_block_move_straight (rtx dest, rtx src, HOST_WIDE_INT length)
+{
+ HOST_WIDE_INT offset, delta;
+ unsigned HOST_WIDE_INT bits;
+ int i;
+ enum machine_mode mode;
+ rtx *regs;
+
+ bits = BITS_PER_WORD;
+ mode = mode_for_size (bits, MODE_INT, 0);
+ delta = bits / BITS_PER_UNIT;
+
+ /* Allocate a buffer for the temporary registers. */
+ regs = alloca (sizeof (rtx) * length / delta);
+
+ /* Load as many BITS-sized chunks as possible. Use a normal load if
+ the source has enough alignment, otherwise use left/right pairs. */
+ for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
+ {
+ regs[i] = gen_reg_rtx (mode);
+ emit_move_insn (regs[i], adjust_address (src, mode, offset));
+ }
+
+ /* Copy the chunks to the destination. */
+ for (offset = 0, i = 0; offset + delta <= length; offset += delta, i++)
+ emit_move_insn (adjust_address (dest, mode, offset), regs[i]);
+
+ /* Mop up any left-over bytes. */
+ if (offset < length)
+ {
+ src = adjust_address (src, BLKmode, offset);
+ dest = adjust_address (dest, BLKmode, offset);
+ move_by_pieces (dest, src, length - offset,
+ MIN (MEM_ALIGN (src), MEM_ALIGN (dest)), 0);
+ }
+}
+
+/* Helper function for doing a loop-based block operation on memory
+ reference MEM. Each iteration of the loop will operate on LENGTH
+ bytes of MEM.
+
+ Create a new base register for use within the loop and point it to
+ the start of MEM. Create a new memory reference that uses this
+ register. Store them in *LOOP_REG and *LOOP_MEM respectively. */
+
+static void
+microblaze_adjust_block_mem (rtx mem, HOST_WIDE_INT length,
+ rtx * loop_reg, rtx * loop_mem)
+{
+ *loop_reg = copy_addr_to_reg (XEXP (mem, 0));
+
+ /* Although the new mem does not refer to a known location,
+ it does keep up to LENGTH bytes of alignment. */
+ *loop_mem = change_address (mem, BLKmode, *loop_reg);
+ set_mem_align (*loop_mem,
+ MIN ((HOST_WIDE_INT) MEM_ALIGN (mem),
+ length * BITS_PER_UNIT));
+}
+
+
+/* Move LENGTH bytes from SRC to DEST using a loop that moves MAX_MOVE_BYTES
+ per iteration. LENGTH must be at least MAX_MOVE_BYTES. Assume that the
+ memory regions do not overlap. */
+
+static void
+microblaze_block_move_loop (rtx dest, rtx src, HOST_WIDE_INT length)
+{
+ rtx label, src_reg, dest_reg, final_src;
+ HOST_WIDE_INT leftover;
+
+ leftover = length % MAX_MOVE_BYTES;
+ length -= leftover;
+
+ /* Create registers and memory references for use within the loop. */
+ microblaze_adjust_block_mem (src, MAX_MOVE_BYTES, &src_reg, &src);
+ microblaze_adjust_block_mem (dest, MAX_MOVE_BYTES, &dest_reg, &dest);
+
+ /* Calculate the value that SRC_REG should have after the last iteration
+ of the loop. */
+ final_src = expand_simple_binop (Pmode, PLUS, src_reg, GEN_INT (length),
+ 0, 0, OPTAB_WIDEN);
+
+ /* Emit the start of the loop. */
+ label = gen_label_rtx ();
+ emit_label (label);
+
+ /* Emit the loop body. */
+ microblaze_block_move_straight (dest, src, MAX_MOVE_BYTES);
+
+ /* Move on to the next block. */
+ emit_move_insn (src_reg, plus_constant (src_reg, MAX_MOVE_BYTES));
+ emit_move_insn (dest_reg, plus_constant (dest_reg, MAX_MOVE_BYTES));
+
+ /* Emit the test & branch. */
+ emit_insn (gen_cbranchsi4 (gen_rtx_NE (SImode, src_reg, final_src),
+ src_reg, final_src, label));
+
+ /* Mop up any left-over bytes. */
+ if (leftover)
+ microblaze_block_move_straight (dest, src, leftover);
+}
+
+/* Expand a movmemsi instruction. */
+
+bool
+microblaze_expand_block_move (rtx dest, rtx src, rtx length, rtx align_rtx)
+{
+
+ if (GET_CODE (length) == CONST_INT)
+ {
+ HOST_WIDE_INT bytes = INTVAL (length);
+ int align = INTVAL (align_rtx);
+
+ if (align > UNITS_PER_WORD)
+ {
+ align = UNITS_PER_WORD; /* We can't do any better. */
+ }
+ else if (align < UNITS_PER_WORD)
+ {
+ if (INTVAL (length) <= MAX_MOVE_BYTES)
+ {
+ move_by_pieces (dest, src, bytes, align, 0);
+ return true;
+ }
+ else
+ return false;
+ }
+
+ if (INTVAL (length) <= 2 * MAX_MOVE_BYTES)
+ {
+ microblaze_block_move_straight (dest, src, INTVAL (length));
+ return true;
+ }
+ else if (optimize)
+ {
+ microblaze_block_move_loop (dest, src, INTVAL (length));
+ return true;
+ }
+ }
+ return false;
+}
+
+static bool
+microblaze_rtx_costs (rtx x, int code, int outer_code ATTRIBUTE_UNUSED, int *total,
+ bool speed ATTRIBUTE_UNUSED)
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ switch (code)
+ {
+ case MEM:
+ {
+ int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
+ if (simple_memory_operand (x, mode))
+ *total = COSTS_N_INSNS (2 * num_words);
+ else
+ *total = COSTS_N_INSNS (2 * (2 * num_words));
+
+ return true;
+ }
+ case NOT:
+ {
+ if (mode == DImode)
+ {
+ *total = COSTS_N_INSNS (2);
+ }
+ else
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+ case AND:
+ case IOR:
+ case XOR:
+ {
+ if (mode == DImode)
+ {
+ *total = COSTS_N_INSNS (2);
+ }
+ else
+ *total = COSTS_N_INSNS (1);
+
+ return false;
+ }
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ {
+ if (TARGET_BARREL_SHIFT)
+ {
+ if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
+ >= 0)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ }
+ else if (!TARGET_SOFT_MUL)
+ *total = COSTS_N_INSNS (1);
+ else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ /* Add 1 to make shift slightly more expensive than add. */
+ *total = COSTS_N_INSNS (INTVAL (XEXP (x, 1))) + 1;
+ /* Reduce shift costs for for special circumstances. */
+ if (optimize_size && INTVAL (XEXP (x, 1)) > 5)
+ *total -= 2;
+ if (!optimize_size && INTVAL (XEXP (x, 1)) > 17)
+ *total -= 2;
+ }
+ else
+ /* Double the worst cost of shifts when there is no barrel shifter and
+ the shift amount is in a reg. */
+ *total = COSTS_N_INSNS (32 * 4);
+ return true;
+ }
+ case PLUS:
+ case MINUS:
+ {
+ if (mode == SFmode || mode == DFmode)
+ {
+ if (TARGET_HARD_FLOAT)
+ *total = COSTS_N_INSNS (6);
+ return true;
+ }
+ else if (mode == DImode)
+ {
+ *total = COSTS_N_INSNS (4);
+ return true;
+ }
+ else
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+
+ return false;
+ }
+ case NEG:
+ {
+ if (mode == DImode)
+ *total = COSTS_N_INSNS (4);
+
+ return false;
+ }
+ case MULT:
+ {
+ if (mode == SFmode)
+ {
+ if (TARGET_HARD_FLOAT)
+ *total = COSTS_N_INSNS (6);
+ }
+ else if (!TARGET_SOFT_MUL)
+ {
+ if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a")
+ >= 0)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (3);
+ }
+ else
+ *total = COSTS_N_INSNS (10);
+ return true;
+ }
+ case DIV:
+ case UDIV:
+ {
+ if (mode == SFmode)
+ {
+ if (TARGET_HARD_FLOAT)
+ *total = COSTS_N_INSNS (23);
+ }
+ return false;
+ }
+ case SIGN_EXTEND:
+ {
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+ case ZERO_EXTEND:
+ {
+ *total = COSTS_N_INSNS (1);
+ return false;
+ }
+ }
+
+ return false;
+}
+
+/* Return the number of instructions needed to load or store a value
+ of mode MODE at X. Return 0 if X isn't valid for MODE. */
+
+static int
+microblaze_address_insns (rtx x, enum machine_mode mode)
+{
+ struct microblaze_address_info addr;
+
+ if (microblaze_classify_address (&addr, x, mode, false))
+ {
+ switch (addr.type)
+ {
+ case ADDRESS_REG:
+ if (SMALL_INT (addr.offset))
+ return 1;
+ else
+ return 2;
+ case ADDRESS_CONST_INT:
+ if (SMALL_INT (x))
+ return 1;
+ else
+ return 2;
+ case ADDRESS_REG_INDEX:
+ case ADDRESS_SYMBOLIC:
+ return 1;
+ case ADDRESS_GOTOFF:
+ return 2;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+/* Provide the costs of an addressing mode that contains ADDR.
+ If ADDR is not a valid address, its cost is irrelevant. */
+static int
+microblaze_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
+{
+ return COSTS_N_INSNS (microblaze_address_insns (addr, GET_MODE (addr)));
+}
+
+/* Return nonzero if X is an address which needs a temporary register when
+ reloaded while generating PIC code. */
+
+int
+pic_address_needs_scratch (rtx x)
+{
+ /* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
+ if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
+ && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+ && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+ && (flag_pic == 2 || !SMALL_INT (XEXP (XEXP (x, 0), 1))))
+ return 1;
+
+ return 0;
+}
+
+/* Argument support functions. */
+/* Initialize CUMULATIVE_ARGS for a function. */
+
+void
+init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
+ rtx libname ATTRIBUTE_UNUSED)
+{
+ static CUMULATIVE_ARGS zero_cum;
+ tree param, next_param;
+
+ *cum = zero_cum;
+
+ /* Determine if this function has variable arguments. This is
+ indicated by the last argument being 'void_type_mode' if there
+ are no variable arguments. The standard MicroBlaze calling sequence
+ passes all arguments in the general purpose registers in this case. */
+
+ for (param = fntype ? TYPE_ARG_TYPES (fntype) : 0;
+ param != 0; param = next_param)
+ {
+ next_param = TREE_CHAIN (param);
+ if (next_param == 0 && TREE_VALUE (param) != void_type_node)
+ cum->gp_reg_found = 1;
+ }
+}
+
+/* Advance the argument to the next argument position. */
+
+void
+function_arg_advance (CUMULATIVE_ARGS * cum, enum machine_mode mode,
+ tree type, int named ATTRIBUTE_UNUSED)
+{
+ cum->arg_number++;
+ switch (mode)
+ {
+ case VOIDmode:
+ break;
+
+ default:
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
+ || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
+
+ cum->gp_reg_found = 1;
+ cum->arg_words += ((GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1)
+ / UNITS_PER_WORD);
+ break;
+
+ case BLKmode:
+ cum->gp_reg_found = 1;
+ cum->arg_words += ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
+ / UNITS_PER_WORD);
+ break;
+
+ case SFmode:
+ cum->arg_words++;
+ if (!cum->gp_reg_found && cum->arg_number <= 2)
+ cum->fp_code += 1 << ((cum->arg_number - 1) * 2);
+ break;
+
+ case DFmode:
+ cum->arg_words += 2;
+ if (!cum->gp_reg_found && cum->arg_number <= 2)
+ cum->fp_code += 2 << ((cum->arg_number - 1) * 2);
+ break;
+
+ case DImode:
+ cum->gp_reg_found = 1;
+ cum->arg_words += 2;
+ break;
+
+ case QImode:
+ case HImode:
+ case SImode:
+ case TImode:
+ cum->gp_reg_found = 1;
+ cum->arg_words++;
+ break;
+ }
+}
+
+/* Return an RTL expression containing the register for the given mode,
+ or 0 if the argument is to be passed on the stack. */
+
+rtx
+function_arg (CUMULATIVE_ARGS * cum, enum machine_mode mode,
+ tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
+{
+ rtx ret;
+ int regbase = -1;
+ int *arg_words = &cum->arg_words;
+
+ cum->last_arg_fp = 0;
+ switch (mode)
+ {
+ case SFmode:
+ case DFmode:
+ case VOIDmode:
+ case QImode:
+ case HImode:
+ case SImode:
+ case DImode:
+ case TImode:
+ regbase = GP_ARG_FIRST;
+ break;
+ default:
+ gcc_assert (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
+ || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT);
+ /* Drops through. */
+ case BLKmode:
+ regbase = GP_ARG_FIRST;
+ break;
+ }
+
+ if (*arg_words >= MAX_ARGS_IN_REGISTERS)
+ ret = 0;
+ else
+ {
+ gcc_assert (regbase != -1);
+
+ ret = gen_rtx_REG (mode, regbase + *arg_words);
+ }
+
+ if (mode == VOIDmode)
+ {
+ if (cum->num_adjusts > 0)
+ ret = gen_rtx_PARALLEL ((enum machine_mode) cum->fp_code,
+ gen_rtvec_v (cum->num_adjusts, cum->adjust));
+ }
+
+ return ret;
+}
+
+/* Return number of bytes of argument to put in registers. */
+static int
+function_arg_partial_bytes (CUMULATIVE_ARGS * cum, enum machine_mode mode,
+ tree type, bool named ATTRIBUTE_UNUSED)
+{
+ if ((mode == BLKmode
+ || GET_MODE_CLASS (mode) != MODE_COMPLEX_INT
+ || GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT)
+ && cum->arg_words < MAX_ARGS_IN_REGISTERS)
+ {
+ int words;
+ if (mode == BLKmode)
+ words = ((int_size_in_bytes (type) + UNITS_PER_WORD - 1)
+ / UNITS_PER_WORD);
+ else
+ words = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+
+ if (words + cum->arg_words <= MAX_ARGS_IN_REGISTERS)
+ return 0; /* structure fits in registers */
+
+ return (MAX_ARGS_IN_REGISTERS - cum->arg_words) * UNITS_PER_WORD;
+ }
+
+ else if (mode == DImode && cum->arg_words == MAX_ARGS_IN_REGISTERS - 1)
+ return UNITS_PER_WORD;
+
+ return 0;
+}
+
+/* Convert a version number of the form "vX.YY.Z" to an integer encoding
+ for easier range comparison. */
+static int
+microblaze_version_to_int (const char *version)
+{
+ const char *p, *v;
+ const char *tmpl = "vX.YY.Z";
+ int iver = 0;
+
+ p = version;
+ v = tmpl;
+
+ while (*v)
+ {
+ if (*v == 'X')
+ { /* Looking for major */
+ if (!(*p >= '0' && *p <= '9'))
+ return -1;
+ iver += (int) (*p - '0');
+ iver *= 10;
+ }
+ else if (*v == 'Y')
+ { /* Looking for minor */
+ if (!(*p >= '0' && *p <= '9'))
+ return -1;
+ iver += (int) (*p - '0');
+ iver *= 10;
+ }
+ else if (*v == 'Z')
+ { /* Looking for compat */
+ if (!(*p >= 'a' && *p <= 'z'))
+ return -1;
+ iver *= 10;
+ iver += (int) (*p - 'a');
+ }
+ else
+ {
+ if (*p != *v)
+ return -1;
+ }
+
+ v++;
+ p++;
+ }
+
+ if (*p)
+ return -1;
+
+ return iver;
+}
+
+static bool
+microblaze_handle_option (size_t code,
+ const char *arg ATTRIBUTE_UNUSED,
+ int value ATTRIBUTE_UNUSED)
+{
+ switch (code)
+ {
+ case OPT_mno_clearbss:
+ flag_zero_initialized_in_bss = 0;
+ warning (0, "-mno-clearbss is deprecated; use -fno-zero-initialized-in-bss");
+ break;
+ case OPT_mxl_stack_check:
+ warning (0, "-mxl_stack_check is deprecated; use -fstack-check.");
+ break;
+ }
+ return true;
+}
+
+
+static void
+microblaze_option_override (void)
+{
+ register int i, start;
+ register int regno;
+ register enum machine_mode mode;
+ int ver;
+
+ microblaze_section_threshold =
+ g_switch_set ? g_switch_value : MICROBLAZE_DEFAULT_GVALUE;
+
+ /* Check the MicroBlaze CPU version for any special action to be done. */
+ if (microblaze_select_cpu == NULL)
+ microblaze_select_cpu = MICROBLAZE_DEFAULT_CPU;
+ ver = microblaze_version_to_int (microblaze_select_cpu);
+ if (ver == -1)
+ {
+ error ("%qs is an invalid argument to -mcpu=", microblaze_select_cpu);
+ }
+
+ ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v3.00.a");
+ if (ver < 0)
+ {
+ /* No hardware exceptions in earlier versions. So no worries. */
+ // microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
+ microblaze_no_unsafe_delay = 0;
+ microblaze_pipe = MICROBLAZE_PIPE_3;
+ }
+ else if (ver == 0
+ || (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v4.00.b")
+ == 0))
+ {
+ // microblaze_select_flags |= (MICROBLAZE_MASK_NO_UNSAFE_DELAY);
+ microblaze_no_unsafe_delay = 1;
+ microblaze_pipe = MICROBLAZE_PIPE_3;
+ }
+ else
+ {
+ /* We agree to use 5 pipe-stage model even on area optimized 3
+ pipe-stage variants. */
+ // microblaze_select_flags &= ~(MICROBLAZE_MASK_NO_UNSAFE_DELAY);
+ microblaze_no_unsafe_delay = 0;
+ microblaze_pipe = MICROBLAZE_PIPE_5;
+ if (MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v5.00.a") == 0
+ || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
+ "v5.00.b") == 0
+ || MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu,
+ "v5.00.c") == 0)
+ {
+ /* Pattern compares are to be turned on by default only when
+ compiling for MB v5.00.'z'. */
+ target_flags |= MASK_PATTERN_COMPARE;
+ }
+ }
+
+ ver = MICROBLAZE_VERSION_COMPARE (microblaze_select_cpu, "v6.00.a");
+ if (ver < 0)
+ {
+ if (TARGET_MULTIPLY_HIGH)
+ warning (0,
+ "-mxl-multiply-high can be used only with -mcpu=v6.00.a or greater");
+ }
+
+ if (TARGET_MULTIPLY_HIGH && TARGET_SOFT_MUL)
+ error ("-mxl-multiply-high requires -mno-xl-soft-mul");
+
+ /* Always use DFA scheduler. */
+ microblaze_sched_use_dfa = 1;
+
+ // microblaze_abicalls = MICROBLAZE_ABICALLS_NO;
+
+ /* Initialize the high, low values for legit floating point constants. */
+ real_maxval (&dfhigh, 0, DFmode);
+ real_maxval (&dflow, 1, DFmode);
+ real_maxval (&sfhigh, 0, SFmode);
+ real_maxval (&sflow, 1, SFmode);
+
+ microblaze_print_operand_punct['?'] = 1;
+ microblaze_print_operand_punct['#'] = 1;
+ microblaze_print_operand_punct['&'] = 1;
+ microblaze_print_operand_punct['!'] = 1;
+ microblaze_print_operand_punct['*'] = 1;
+ microblaze_print_operand_punct['@'] = 1;
+ microblaze_print_operand_punct['.'] = 1;
+ microblaze_print_operand_punct['('] = 1;
+ microblaze_print_operand_punct[')'] = 1;
+ microblaze_print_operand_punct['['] = 1;
+ microblaze_print_operand_punct[']'] = 1;
+ microblaze_print_operand_punct['<'] = 1;
+ microblaze_print_operand_punct['>'] = 1;
+ microblaze_print_operand_punct['{'] = 1;
+ microblaze_print_operand_punct['}'] = 1;
+ microblaze_print_operand_punct['^'] = 1;
+ microblaze_print_operand_punct['$'] = 1;
+ microblaze_print_operand_punct['+'] = 1;
+
+ /* Set up array to map GCC register number to debug register number.
+ Ignore the special purpose register numbers. */
+
+ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+ microblaze_dbx_regno[i] = -1;
+
+ start = GP_DBX_FIRST - GP_REG_FIRST;
+ for (i = GP_REG_FIRST; i <= GP_REG_LAST; i++)
+ microblaze_dbx_regno[i] = i + start;
+
+ /* Set up array giving whether a given register can hold a given mode. */
+
+ for (mode = VOIDmode;
+ mode != MAX_MACHINE_MODE; mode = (enum machine_mode) ((int) mode + 1))
+ {
+ register int size = GET_MODE_SIZE (mode);
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ register int ok;
+
+ if (mode == CCmode)
+ {
+ ok = (ST_REG_P (regno) || GP_REG_P (regno));
+ }
+ else if (GP_REG_P (regno))
+ ok = ((regno & 1) == 0 || size <= UNITS_PER_WORD);
+ else
+ ok = 0;
+
+ microblaze_hard_regno_mode_ok[(int) mode][regno] = ok;
+ }
+ }
+}
+
+/* Return true if FUNC is an interrupt function as specified
+ by the "interrupt_handler" attribute. */
+
+static int
+microblaze_interrupt_function_p (tree func)
+{
+ tree a;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ a = lookup_attribute ("interrupt_handler", DECL_ATTRIBUTES (func));
+ return a != NULL_TREE;
+}
+
+/* Return true if FUNC is an interrupt function which uses
+ normal return, indicated by the "save_volatiles" attribute. */
+
+static int
+microblaze_save_volatiles (tree func)
+{
+ tree a;
+
+ if (TREE_CODE (func) != FUNCTION_DECL)
+ return 0;
+
+ a = lookup_attribute ("save_volatiles", DECL_ATTRIBUTES (func));
+ return a != NULL_TREE;
+}
+
+/* Return whether function is tagged with 'interrupt_handler'
+ attribute. Return true if function should use return from
+ interrupt rather than normal function return. */
+int
+microblaze_is_interrupt_handler (void)
+{
+ return interrupt_handler;
+}
+
+/* Determine of register must be saved/restored in call. */
+static int
+microblaze_must_save_register (int regno)
+{
+ if (pic_offset_table_rtx &&
+ (regno == MB_ABI_PIC_ADDR_REGNUM) && df_regs_ever_live_p (regno))
+ return 1;
+
+ if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
+ return 1;
+
+ if (frame_pointer_needed && (regno == HARD_FRAME_POINTER_REGNUM))
+ return 1;
+
+ if (!current_function_is_leaf)
+ {
+ if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
+ return 1;
+ if ((interrupt_handler || save_volatiles) &&
+ (regno >= 3 && regno <= 12))
+ return 1;
+ }
+
+ if (interrupt_handler)
+ {
+ if (df_regs_ever_live_p (regno)
+ || regno == MB_ABI_MSR_SAVE_REG
+ || regno == MB_ABI_ASM_TEMP_REGNUM
+ || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
+ return 1;
+ }
+
+ if (save_volatiles)
+ {
+ if (df_regs_ever_live_p (regno)
+ || regno == MB_ABI_ASM_TEMP_REGNUM
+ || regno == MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM)
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return the bytes needed to compute the frame pointer from the current
+ stack pointer.
+
+ MicroBlaze stack frames look like:
+
+
+
+ Before call After call
+ +-----------------------+ +-----------------------+
+ high | | | |
+ mem. | local variables, | | local variables, |
+ | callee saved and | | callee saved and |
+ | temps | | temps |
+ +-----------------------+ +-----------------------+
+ | arguments for called | | arguments for called |
+ | subroutines | | subroutines |
+ | (optional) | | (optional) |
+ +-----------------------+ +-----------------------+
+ | Link register | | Link register |
+ SP->| | | |
+ +-----------------------+ +-----------------------+
+ | |
+ | local variables, |
+ | callee saved and |
+ | temps |
+ +-----------------------+
+ | MSR (optional if, |
+ | interrupt handler) |
+ +-----------------------+
+ | |
+ | alloca allocations |
+ | |
+ +-----------------------+
+ | |
+ | arguments for called |
+ | subroutines |
+ | (optional) |
+ | |
+ +-----------------------+
+ | Link register |
+ low FP,SP->| |
+ memory +-----------------------+
+
+*/
+
+static HOST_WIDE_INT
+compute_frame_size (HOST_WIDE_INT size)
+{
+ int regno;
+ HOST_WIDE_INT total_size; /* # bytes that the entire frame takes up. */
+ HOST_WIDE_INT var_size; /* # bytes that local variables take up. */
+ HOST_WIDE_INT args_size; /* # bytes that outgoing arguments take up. */
+ int link_debug_size; /* # bytes for link register. */
+ HOST_WIDE_INT gp_reg_size; /* # bytes needed to store calle-saved gp regs. */
+ long mask; /* mask of saved gp registers. */
+
+ interrupt_handler =
+ microblaze_interrupt_function_p (current_function_decl);
+ save_volatiles = microblaze_save_volatiles (current_function_decl);
+
+ gp_reg_size = 0;
+ mask = 0;
+ var_size = size;
+ args_size = crtl->outgoing_args_size;
+
+ if ((args_size == 0) && cfun->calls_alloca)
+ args_size = NUM_OF_ARGS * UNITS_PER_WORD;
+
+ total_size = var_size + args_size;
+
+ if (flag_pic == 2)
+ /* force setting GOT. */
+ df_set_regs_ever_live (MB_ABI_PIC_ADDR_REGNUM, true);
+
+ /* Calculate space needed for gp registers. */
+ for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+ {
+ if (microblaze_must_save_register (regno))
+ {
+
+ if (regno != MB_ABI_SUB_RETURN_ADDR_REGNUM)
+ /* Don't account for link register. It is accounted specially below. */
+ gp_reg_size += GET_MODE_SIZE (SImode);
+
+ mask |= (1L << (regno - GP_REG_FIRST));
+ }
+ }
+
+ total_size += gp_reg_size;
+
+ /* Add 4 bytes for MSR. */
+ if (interrupt_handler)
+ total_size += 4;
+
+ /* No space to be allocated for link register in leaf functions with no other
+ stack requirements. */
+ if (total_size == 0 && current_function_is_leaf)
+ link_debug_size = 0;
+ else
+ link_debug_size = UNITS_PER_WORD;
+
+ total_size += link_debug_size;
+
+ /* Save other computed information. */
+ current_frame_info.total_size = total_size;
+ current_frame_info.var_size = var_size;
+ current_frame_info.args_size = args_size;
+ current_frame_info.gp_reg_size = gp_reg_size;
+ current_frame_info.mask = mask;
+ current_frame_info.initialized = reload_completed;
+ current_frame_info.num_gp = gp_reg_size / UNITS_PER_WORD;
+ current_frame_info.link_debug_size = link_debug_size;
+
+ if (mask)
+ /* Offset from which to callee-save GP regs. */
+ current_frame_info.gp_offset = (total_size - gp_reg_size);
+ else
+ current_frame_info.gp_offset = 0;
+
+ /* Ok, we're done. */
+ return total_size;
+}
+
+/* Make sure that we're not trying to eliminate to the wrong hard frame
+ pointer. */
+
+static bool
+microblaze_can_eliminate (const int from, const int to)
+{
+ return ((from == RETURN_ADDRESS_POINTER_REGNUM && !leaf_function_p())
+ || (to == MB_ABI_SUB_RETURN_ADDR_REGNUM && leaf_function_p())
+ || (from != RETURN_ADDRESS_POINTER_REGNUM
+ && (to == HARD_FRAME_POINTER_REGNUM
+ || (to == STACK_POINTER_REGNUM && !frame_pointer_needed))));
+}
+
+/* Implement INITIAL_ELIMINATION_OFFSET. FROM is either the frame
+ pointer or argument pointer or the return address pointer. TO is either
+ the stack pointer or hard frame pointer. */
+
+HOST_WIDE_INT
+microblaze_initial_elimination_offset (int from, int to)
+{
+ HOST_WIDE_INT offset;
+
+ switch (from)
+ {
+ case FRAME_POINTER_REGNUM:
+ offset = 0;
+ break;
+ case ARG_POINTER_REGNUM:
+ if (to == STACK_POINTER_REGNUM || to == HARD_FRAME_POINTER_REGNUM)
+ offset = compute_frame_size (get_frame_size ());
+ else
+ gcc_unreachable ();
+ break;
+ case RETURN_ADDRESS_POINTER_REGNUM:
+ if (current_function_is_leaf)
+ offset = 0;
+ else
+ offset = current_frame_info.gp_offset +
+ ((UNITS_PER_WORD - (POINTER_SIZE / BITS_PER_UNIT)));
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ return offset;
+}
+
+/* Print operands using format code.
+
+ The MicroBlaze specific codes are:
+
+ 'X' X is CONST_INT, prints 32 bits in hexadecimal format = "0x%08x",
+ 'x' X is CONST_INT, prints 16 bits in hexadecimal format = "0x%04x",
+ 'F' op is CONST_DOUBLE, print 32 bits in hex,
+ 'd' output integer constant in decimal,
+ 'z' if the operand is 0, use $0 instead of normal operand.
+ 'D' print second register of double-word register operand.
+ 'L' print low-order register of double-word register operand.
+ 'M' print high-order register of double-word register operand.
+ 'C' print part of opcode for a branch condition.
+ 'N' print part of opcode for a branch condition, inverted.
+ 'S' X is CODE_LABEL, print with prefix of "LS" (for embedded switch).
+ 'B' print 'z' for EQ, 'n' for NE
+ 'b' print 'n' for EQ, 'z' for NE
+ 'T' print 'f' for EQ, 't' for NE
+ 't' print 't' for EQ, 'f' for NE
+ 'm' Print 1<<operand.
+ 'i' Print 'i' if MEM operand has immediate value
+ 'o' Print operand address+4
+ '?' Print 'd' if we use a branch with delay slot instead of normal branch.
+ 'h' Print high word of const_double (int or float) value as hex
+ 'j' Print low word of const_double (int or float) value as hex
+ 's' Print -1 if operand is negative, 0 if positive (sign extend)
+ '@' Print the name of the temporary register (rMB_ABI_ASM_TEMP_REGNUM).
+ '#' Print nop if the delay slot of a branch is not filled.
+*/
+
+void
+print_operand (FILE * file, rtx op, int letter)
+{
+ register enum rtx_code code;
+
+ if (PRINT_OPERAND_PUNCT_VALID_P (letter))
+ {
+ switch (letter)
+ {
+ case '?':
+ /* Conditionally add a 'd' to indicate filled delay slot. */
+ if (final_sequence != NULL)
+ fputs ("d", file);
+ break;
+
+ case '#':
+ /* Conditionally add a nop in unfilled delay slot. */
+ if (final_sequence == NULL)
+ fputs ("nop\t\t# Unfilled delay slot\n", file);
+ break;
+
+ case '@':
+ fputs (reg_names[GP_REG_FIRST + MB_ABI_ASM_TEMP_REGNUM], file);
+ break;
+
+ default:
+ output_operand_lossage ("unknown punctuation '%c'", letter);
+ break;
+ }
+
+ return;
+ }
+
+ if (!op)
+ {
+ output_operand_lossage ("null pointer");
+ return;
+ }
+
+ code = GET_CODE (op);
+
+ if (code == SIGN_EXTEND)
+ op = XEXP (op, 0), code = GET_CODE (op);
+
+ if (letter == 'C')
+ switch (code)
+ {
+ case EQ:
+ fputs ("eq", file);
+ break;
+ case NE:
+ fputs ("ne", file);
+ break;
+ case GT:
+ case GTU:
+ fputs ("gt", file);
+ break;
+ case GE:
+ case GEU:
+ fputs ("ge", file);
+ break;
+ case LT:
+ case LTU:
+ fputs ("lt", file);
+ break;
+ case LE:
+ case LEU:
+ fputs ("le", file);
+ break;
+ default:
+ fatal_insn ("PRINT_OPERAND, invalid insn for %%C", op);
+ }
+
+ else if (letter == 'N')
+ switch (code)
+ {
+ case EQ:
+ fputs ("ne", file);
+ break;
+ case NE:
+ fputs ("eq", file);
+ break;
+ case GT:
+ case GTU:
+ fputs ("le", file);
+ break;
+ case GE:
+ case GEU:
+ fputs ("lt", file);
+ break;
+ case LT:
+ case LTU:
+ fputs ("ge", file);
+ break;
+ case LE:
+ case LEU:
+ fputs ("gt", file);
+ break;
+ default:
+ fatal_insn ("PRINT_OPERAND, invalid insn for %%N", op);
+ }
+
+ else if (letter == 'S')
+ {
+ char buffer[100];
+
+ ASM_GENERATE_INTERNAL_LABEL (buffer, "LS", CODE_LABEL_NUMBER (op));
+ assemble_name (file, buffer);
+ }
+
+ /* Print 'i' for memory operands which have immediate values. */
+ else if (letter == 'i')
+ {
+ if (code == MEM)
+ {
+ struct microblaze_address_info info;
+
+ if (!microblaze_classify_address
+ (&info, XEXP (op, 0), GET_MODE (op), 1))
+ fatal_insn ("insn contains an invalid address !", op);
+
+ switch (info.type)
+ {
+ case ADDRESS_REG:
+ case ADDRESS_CONST_INT:
+ case ADDRESS_SYMBOLIC:
+ case ADDRESS_GOTOFF:
+ fputs ("i", file);
+ break;
+ case ADDRESS_REG_INDEX:
+ break;
+ case ADDRESS_INVALID:
+ case ADDRESS_PLT:
+ fatal_insn ("Invalid address", op);
+ }
+ }
+ }
+
+ else if (code == REG || code == SUBREG)
+ {
+ register int regnum;
+
+ if (code == REG)
+ regnum = REGNO (op);
+ else
+ regnum = true_regnum (op);
+
+ if ((letter == 'M' && !WORDS_BIG_ENDIAN)
+ || (letter == 'L' && WORDS_BIG_ENDIAN) || letter == 'D')
+ regnum++;
+
+ fprintf (file, "%s", reg_names[regnum]);
+ }
+
+ else if (code == MEM)
+ if (letter == 'o')
+ {
+ rtx op4 = adjust_address (op, GET_MODE (op), 4);
+ output_address (XEXP (op4, 0));
+ }
+ else
+ output_address (XEXP (op, 0));
+
+ else if (letter == 'h' || letter == 'j')
+ {
+ long val[2];
+ if (code == CONST_DOUBLE)
+ {
+ if (GET_MODE (op) == DFmode)
+ {
+ REAL_VALUE_TYPE value;
+ REAL_VALUE_FROM_CONST_DOUBLE (value, op);
+ REAL_VALUE_TO_TARGET_DOUBLE (value, val);
+ }
+ else
+ {
+ val[0] = CONST_DOUBLE_HIGH (op);
+ val[1] = CONST_DOUBLE_LOW (op);
+ }
+ }
+ else if (code == CONST_INT)
+ {
+ val[0] = (INTVAL (op) & 0xffffffff00000000LL) >> 32;
+ val[1] = INTVAL (op) & 0x00000000ffffffffLL;
+ if (val[0] == 0 && val[1] < 0)
+ val[0] = -1;
+
+ }
+ fprintf (file, "0x%8.8lx", (letter == 'h') ? val[0] : val[1]);
+ }
+ else if (code == CONST_DOUBLE)
+ {
+ if (letter == 'F')
+ {
+ unsigned long value_long;
+ REAL_VALUE_TYPE value;
+ REAL_VALUE_FROM_CONST_DOUBLE (value, op);
+ REAL_VALUE_TO_TARGET_SINGLE (value, value_long);
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, value_long);
+ }
+ else
+ {
+ char s[60];
+ real_to_decimal (s, CONST_DOUBLE_REAL_VALUE (op), sizeof (s), 0, 1);
+ fputs (s, file);
+ }
+ }
+
+ else if (code == UNSPEC)
+ {
+ print_operand_address (file, op);
+ }
+
+ else if (letter == 'x' && GET_CODE (op) == CONST_INT)
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, 0xffff & INTVAL (op));
+
+ else if (letter == 'X' && GET_CODE (op) == CONST_INT)
+ fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (op));
+
+ else if (letter == 'd' && GET_CODE (op) == CONST_INT)
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, (INTVAL (op)));
+
+ else if (letter == 'z' && GET_CODE (op) == CONST_INT && INTVAL (op) == 0)
+ fputs (reg_names[GP_REG_FIRST], file);
+
+ else if (letter == 's' && GET_CODE (op) == CONST_INT)
+ if (INTVAL (op) < 0)
+ fputs ("-1", file);
+ else
+ fputs ("0", file);
+
+ else if (letter == 'd' || letter == 'x' || letter == 'X' || letter == 's')
+ output_operand_lossage ("letter %c was found & insn was not CONST_INT", letter);
+
+ else if (letter == 'B')
+ fputs (code == EQ ? "z" : "n", file);
+ else if (letter == 'b')
+ fputs (code == EQ ? "n" : "z", file);
+ else if (letter == 'T')
+ fputs (code == EQ ? "f" : "t", file);
+ else if (letter == 't')
+ fputs (code == EQ ? "t" : "f", file);
+
+ else if (code == CONST && GET_CODE (XEXP (op, 0)) == REG)
+ {
+ print_operand (file, XEXP (op, 0), letter);
+ }
+ else if (letter == 'm')
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, (1L << INTVAL (op)));
+ else
+ output_addr_const (file, op);
+}
+
+/* A C compound statement to output to stdio stream STREAM the
+ assembler syntax for an instruction operand that is a memory
+ reference whose address is ADDR. ADDR is an RTL expression.
+
+ Possible address classifications and output formats are,
+
+ ADDRESS_REG "%0, r0"
+
+ ADDRESS_REG with non-zero "%0, <addr_const>"
+ offset
+
+ ADDRESS_REG_INDEX "rA, RB"
+ (if rA is r0, rA and rB are swapped)
+
+ ADDRESS_CONST_INT "r0, <addr_const>"
+
+ ADDRESS_SYMBOLIC "rBase, <addr_const>"
+ (rBase is a base register suitable for the
+ symbol's type)
+*/
+
+void
+print_operand_address (FILE * file, rtx addr)
+{
+ struct microblaze_address_info info;
+ enum microblaze_address_type type;
+ if (!microblaze_classify_address (&info, addr, GET_MODE (addr), 1))
+ fatal_insn ("insn contains an invalid address !", addr);
+
+ type = info.type;
+ switch (info.type)
+ {
+ case ADDRESS_REG:
+ fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
+ output_addr_const (file, info.offset);
+ break;
+ case ADDRESS_REG_INDEX:
+ if (REGNO (info.regA) == 0)
+ /* Make rB == r0 instead of rA == r0. This helps reduce read port
+ congestion. */
+ fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
+ reg_names[REGNO (info.regA)]);
+ else if (REGNO (info.regB) != 0)
+ /* This is a silly swap to help Dhrystone. */
+ fprintf (file, "%s,%s", reg_names[REGNO (info.regB)],
+ reg_names[REGNO (info.regA)]);
+ break;
+ case ADDRESS_CONST_INT:
+ fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
+ output_addr_const (file, info.offset);
+ break;
+ case ADDRESS_SYMBOLIC:
+ case ADDRESS_GOTOFF:
+ case ADDRESS_PLT:
+ if (info.regA)
+ fprintf (file, "%s,", reg_names[REGNO (info.regA)]);
+ output_addr_const (file, info.symbol);
+ if (type == ADDRESS_GOTOFF)
+ {
+ fputs ("@GOT", file);
+ }
+ else if (type == ADDRESS_PLT)
+ {
+ fputs ("@PLT", file);
+ }
+ break;
+ case ADDRESS_INVALID:
+ fatal_insn ("invalid address", addr);
+ break;
+ }
+}
+
+/* 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
+ microblaze_asm_file_end. */
+
+void
+microblaze_declare_object (FILE * stream, const char *name,
+ const char *section, const char *fmt, int size)
+{
+
+ fputs (section, stream);
+ assemble_name (stream, name);
+ fprintf (stream, fmt, size);
+}
+
+/* Common code to emit the insns (or to write the instructions to a file)
+ to save/restore registers.
+
+ Other parts of the code assume that MICROBLAZE_TEMP1_REGNUM (aka large_reg)
+ is not modified within save_restore_insns. */
+
+#define BITSET_P(VALUE,BIT) (((VALUE) & (1L << (BIT))) != 0)
+
+/* Save or restore instructions based on whether this is the prologue or
+ epilogue. prologue is 1 for the prologue. */
+static void
+save_restore_insns (int prologue)
+{
+ rtx base_reg_rtx, reg_rtx, mem_rtx, /* msr_rtx, */ isr_reg_rtx =
+ 0, isr_mem_rtx = 0;
+ rtx isr_msr_rtx = 0, insn;
+ long mask = current_frame_info.mask;
+ HOST_WIDE_INT base_offset, gp_offset;
+ int regno;
+
+ if (frame_pointer_needed
+ && !BITSET_P (mask, HARD_FRAME_POINTER_REGNUM - GP_REG_FIRST))
+ gcc_unreachable ();
+
+ if (mask == 0)
+ return;
+
+ /* Save registers starting from high to low. The debuggers prefer at least
+ the return register be stored at func+4, and also it allows us not to
+ need a nop in the epilog if at least one register is reloaded in
+ addition to return address. */
+
+ /* Pick which pointer to use as a base register. For small frames, just
+ use the stack pointer. Otherwise, use a temporary register. Save 2
+ cycles if the save area is near the end of a large frame, by reusing
+ the constant created in the prologue/epilogue to adjust the stack
+ frame. */
+
+ gp_offset = current_frame_info.gp_offset;
+
+ gcc_assert (gp_offset > 0);
+
+ base_reg_rtx = stack_pointer_rtx;
+ base_offset = 0;
+
+ /* For interrupt_handlers, need to save/restore the MSR. */
+ if (interrupt_handler)
+ {
+ isr_mem_rtx = gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (Pmode, base_reg_rtx,
+ GEN_INT (current_frame_info.
+ gp_offset -
+ UNITS_PER_WORD)));
+
+ /* Do not optimize in flow analysis. */
+ MEM_VOLATILE_P (isr_mem_rtx) = 1;
+ isr_reg_rtx = gen_rtx_REG (SImode, MB_ABI_MSR_SAVE_REG);
+ isr_msr_rtx = gen_rtx_REG (SImode, ST_REG);
+ }
+
+ if (interrupt_handler && !prologue)
+ {
+ emit_move_insn (isr_reg_rtx, isr_mem_rtx);
+ emit_move_insn (isr_msr_rtx, isr_reg_rtx);
+ /* Do not optimize in flow analysis. */
+ emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
+ emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
+ }
+
+ for (regno = GP_REG_FIRST; regno <= GP_REG_LAST; regno++)
+ {
+ if (BITSET_P (mask, regno - GP_REG_FIRST))
+ {
+ if (regno == MB_ABI_SUB_RETURN_ADDR_REGNUM)
+ /* Don't handle here. Already handled as the first register. */
+ continue;
+
+ reg_rtx = gen_rtx_REG (SImode, regno);
+ insn = gen_rtx_PLUS (Pmode, base_reg_rtx, GEN_INT (gp_offset));
+ mem_rtx = gen_rtx_MEM (SImode, insn);
+ if (interrupt_handler || save_volatiles)
+ /* Do not optimize in flow analysis. */
+ MEM_VOLATILE_P (mem_rtx) = 1;
+
+ if (prologue)
+ {
+ insn = emit_move_insn (mem_rtx, reg_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else
+ {
+ insn = emit_move_insn (reg_rtx, mem_rtx);
+ }
+
+ gp_offset += GET_MODE_SIZE (SImode);
+ }
+ }
+
+ if (interrupt_handler && prologue)
+ {
+ emit_move_insn (isr_reg_rtx, isr_msr_rtx);
+ emit_move_insn (isr_mem_rtx, isr_reg_rtx);
+
+ /* Do not optimize in flow analysis. */
+ emit_insn (gen_rtx_USE (SImode, isr_reg_rtx));
+ emit_insn (gen_rtx_USE (SImode, isr_msr_rtx));
+ }
+
+ /* Done saving and restoring */
+}
+
+
+/* Set up the stack and frame (if desired) for the function. */
+static void
+microblaze_function_prologue (FILE * file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ const char *fnname;
+ long fsiz = current_frame_info.total_size;
+
+ /* Get the function name the same way that toplev.c does before calling
+ assemble_start_function. This is needed so that the name used here
+ exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
+ fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+ if (!flag_inhibit_size_directive)
+ {
+ fputs ("\t.ent\t", file);
+ if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
+ fputs ("_interrupt_handler", file);
+ else
+ assemble_name (file, fnname);
+ fputs ("\n", file);
+ if (!interrupt_handler)
+ ASM_OUTPUT_TYPE_DIRECTIVE (file, fnname, "function");
+ }
+
+ assemble_name (file, fnname);
+ fputs (":\n", file);
+
+ if (interrupt_handler && strcmp (INTERRUPT_HANDLER_NAME, fnname))
+ fputs ("_interrupt_handler:\n", file);
+
+ if (!flag_inhibit_size_directive)
+ {
+ /* .frame FRAMEREG, FRAMESIZE, RETREG. */
+ fprintf (file,
+ "\t.frame\t%s,%ld,%s\t\t# vars= %ld, regs= %d, args= %d\n",
+ (reg_names[(frame_pointer_needed)
+ ? HARD_FRAME_POINTER_REGNUM :
+ STACK_POINTER_REGNUM]), fsiz,
+ reg_names[MB_ABI_SUB_RETURN_ADDR_REGNUM + GP_REG_FIRST],
+ current_frame_info.var_size, current_frame_info.num_gp,
+ crtl->outgoing_args_size);
+ fprintf (file, "\t.mask\t0x%08lx\n", current_frame_info.mask);
+ }
+}
+
+/* Output extra assembler code at the end of a prologue. */
+static void
+microblaze_function_end_prologue (FILE * file)
+{
+ if (TARGET_STACK_CHECK)
+ {
+ fprintf (file, "\t# Stack Check Stub -- Start.\n\t");
+ fprintf (file, "ori\tr18,r0,_stack_end\n\t");
+ fprintf (file, "cmpu\tr18,r1,r18\n\t");
+ fprintf (file, "bgei\tr18,_stack_overflow_exit\n\t");
+ fprintf (file, "# Stack Check Stub -- End.\n");
+ }
+}
+
+/* Expand the prologue into a bunch of separate insns. */
+
+void
+microblaze_expand_prologue (void)
+{
+ int regno;
+ HOST_WIDE_INT fsiz;
+ const char *arg_name = 0;
+ tree fndecl = current_function_decl;
+ tree fntype = TREE_TYPE (fndecl);
+ tree fnargs = DECL_ARGUMENTS (fndecl);
+ rtx next_arg_reg;
+ int i;
+ tree next_arg;
+ tree cur_arg;
+ CUMULATIVE_ARGS args_so_far;
+ rtx mem_rtx, reg_rtx;
+
+ /* If struct value address is treated as the first argument, make it so. */
+ if (aggregate_value_p (DECL_RESULT (fndecl), fntype)
+ && !cfun->returns_pcc_struct)
+ {
+ tree type = build_pointer_type (fntype);
+ tree function_result_decl = build_decl (BUILTINS_LOCATION, PARM_DECL,
+ NULL_TREE, type);
+
+ DECL_ARG_TYPE (function_result_decl) = type;
+ TREE_CHAIN (function_result_decl) = fnargs;
+ fnargs = function_result_decl;
+ }
+
+ /* Determine the last argument, and get its name. */
+
+ INIT_CUMULATIVE_ARGS (args_so_far, fntype, NULL_RTX, 0, 0);
+ regno = GP_ARG_FIRST;
+
+ for (cur_arg = fnargs; cur_arg != 0; cur_arg = next_arg)
+ {
+ tree passed_type = DECL_ARG_TYPE (cur_arg);
+ enum machine_mode passed_mode = TYPE_MODE (passed_type);
+ rtx entry_parm;
+
+ if (TREE_ADDRESSABLE (passed_type))
+ {
+ passed_type = build_pointer_type (passed_type);
+ passed_mode = Pmode;
+ }
+
+ entry_parm = FUNCTION_ARG (args_so_far, passed_mode, passed_type, 1);
+
+ if (entry_parm)
+ {
+ int words;
+
+ /* passed in a register, so will get homed automatically. */
+ if (GET_MODE (entry_parm) == BLKmode)
+ words = (int_size_in_bytes (passed_type) + 3) / 4;
+ else
+ words = (GET_MODE_SIZE (GET_MODE (entry_parm)) + 3) / 4;
+
+ regno = REGNO (entry_parm) + words - 1;
+ }
+ else
+ {
+ regno = GP_ARG_LAST + 1;
+ break;
+ }
+
+ FUNCTION_ARG_ADVANCE (args_so_far, passed_mode, passed_type, 1);
+
+ next_arg = TREE_CHAIN (cur_arg);
+ if (next_arg == 0)
+ {
+ if (DECL_NAME (cur_arg))
+ arg_name = IDENTIFIER_POINTER (DECL_NAME (cur_arg));
+
+ break;
+ }
+ }
+
+ /* Split parallel insn into a sequence of insns. */
+
+ next_arg_reg = FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1);
+ if (next_arg_reg != 0 && GET_CODE (next_arg_reg) == PARALLEL)
+ {
+ rtvec adjust = XVEC (next_arg_reg, 0);
+ int num = GET_NUM_ELEM (adjust);
+
+ for (i = 0; i < num; i++)
+ {
+ rtx pattern = RTVEC_ELT (adjust, i);
+ emit_insn (pattern);
+ }
+ }
+
+ fsiz = compute_frame_size (get_frame_size ());
+
+ /* If this function is a varargs function, store any registers that
+ would normally hold arguments ($5 - $10) on the stack. */
+ if (((TYPE_ARG_TYPES (fntype) != 0
+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+ != void_type_node))
+ || (arg_name != 0
+ && ((arg_name[0] == '_'
+ && strcmp (arg_name, "__builtin_va_alist") == 0)
+ || (arg_name[0] == 'v'
+ && strcmp (arg_name, "va_alist") == 0)))))
+ {
+ int offset = (regno - GP_ARG_FIRST + 1) * UNITS_PER_WORD;
+ rtx ptr = stack_pointer_rtx;
+
+ /* If we are doing svr4-abi, sp has already been decremented by fsiz. */
+ for (; regno <= GP_ARG_LAST; regno++)
+ {
+ if (offset != 0)
+ ptr = gen_rtx_PLUS (Pmode, stack_pointer_rtx, GEN_INT (offset));
+ emit_move_insn (gen_rtx_MEM (SImode, ptr),
+ gen_rtx_REG (SImode, regno));
+
+ offset += GET_MODE_SIZE (SImode);
+ }
+
+ }
+
+ if (fsiz > 0)
+ {
+ rtx fsiz_rtx = GEN_INT (fsiz);
+
+ rtx insn = NULL;
+ insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ fsiz_rtx));
+ if (insn)
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ /* Handle SUB_RETURN_ADDR_REGNUM specially at first. */
+ if (!current_function_is_leaf || interrupt_handler)
+ {
+ mem_rtx = gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ const0_rtx));
+
+ if (interrupt_handler)
+ /* Do not optimize in flow analysis. */
+ MEM_VOLATILE_P (mem_rtx) = 1;
+
+ reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
+ insn = emit_move_insn (mem_rtx, reg_rtx);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* _save_ registers for prologue. */
+ save_restore_insns (1);
+
+ if (frame_pointer_needed)
+ {
+ rtx insn = 0;
+
+ insn = emit_insn (gen_movsi (hard_frame_pointer_rtx,
+ stack_pointer_rtx));
+
+ if (insn)
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ if (flag_pic == 2 && df_regs_ever_live_p (MB_ABI_PIC_ADDR_REGNUM))
+ {
+ rtx insn;
+ SET_REGNO (pic_offset_table_rtx, MB_ABI_PIC_ADDR_REGNUM);
+ insn = emit_insn (gen_set_got (pic_offset_table_rtx)); /* setting GOT. */
+ }
+
+ /* If we are profiling, make sure no instructions are scheduled before
+ the call to mcount. */
+
+ if (profile_flag)
+ emit_insn (gen_blockage ());
+}
+
+/* Do necessary cleanup after a function to restore stack, frame, and regs. */
+
+#define RA_MASK ((long) 0x80000000) /* 1 << 31 */
+#define PIC_OFFSET_TABLE_MASK (1 << (PIC_OFFSET_TABLE_REGNUM - GP_REG_FIRST))
+
+static void
+microblaze_function_epilogue (FILE * file ATTRIBUTE_UNUSED,
+ HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+{
+ const char *fnname;
+
+ /* Get the function name the same way that toplev.c does before calling
+ assemble_start_function. This is needed so that the name used here
+ exactly matches the name used in ASM_DECLARE_FUNCTION_NAME. */
+ fnname = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
+
+ if (!flag_inhibit_size_directive)
+ {
+ fputs ("\t.end\t", file);
+ if (interrupt_handler)
+ fputs ("_interrupt_handler", file);
+ else
+ assemble_name (file, fnname);
+ fputs ("\n", file);
+ }
+
+ /* Reset state info for each function. */
+ current_frame_info = zero_frame_info;
+
+ /* Restore the output file if optimizing the GP (optimizing the GP causes
+ the text to be diverted to a tempfile, so that data decls come before
+ references to the data). */
+}
+
+/* Expand the epilogue into a bunch of separate insns. */
+
+void
+microblaze_expand_epilogue (void)
+{
+ HOST_WIDE_INT fsiz = current_frame_info.total_size;
+ rtx fsiz_rtx = GEN_INT (fsiz);
+ rtx reg_rtx;
+ rtx mem_rtx;
+
+ /* In case of interrupt handlers use addki instead of addi for changing the
+ stack pointer value. */
+
+ if (microblaze_can_use_return_insn ())
+ {
+ emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode,
+ GP_REG_FIRST +
+ MB_ABI_SUB_RETURN_ADDR_REGNUM)));
+ return;
+ }
+
+ if (fsiz > 0)
+ {
+ /* Restore SUB_RETURN_ADDR_REGNUM at first. This is to prevent the
+ sequence of load-followed by a use (in rtsd) in every prologue. Saves
+ a load-use stall cycle :) This is also important to handle alloca.
+ (See comments for if (frame_pointer_needed) below. */
+
+ if (!current_function_is_leaf || interrupt_handler)
+ {
+ mem_rtx =
+ gen_rtx_MEM (SImode,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx, const0_rtx));
+ if (interrupt_handler)
+ /* Do not optimize in flow analysis. */
+ MEM_VOLATILE_P (mem_rtx) = 1;
+ reg_rtx = gen_rtx_REG (SImode, MB_ABI_SUB_RETURN_ADDR_REGNUM);
+ emit_move_insn (reg_rtx, mem_rtx);
+ }
+
+ /* It is important that this is done after we restore the return address
+ register (above). When alloca is used, we want to restore the
+ sub-routine return address only from the current stack top and not
+ from the frame pointer (which we restore below). (frame_pointer + 0)
+ might have been over-written since alloca allocates memory on the
+ current stack. */
+ if (frame_pointer_needed)
+ emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
+
+ /* _restore_ registers for epilogue. */
+ save_restore_insns (0);
+ emit_insn (gen_blockage ());
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, fsiz_rtx));
+ }
+
+ emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, GP_REG_FIRST +
+ MB_ABI_SUB_RETURN_ADDR_REGNUM)));
+}
+
+
+/* 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
+microblaze_can_use_return_insn (void)
+{
+ if (!reload_completed)
+ return 0;
+
+ if (df_regs_ever_live_p (MB_ABI_SUB_RETURN_ADDR_REGNUM) || profile_flag)
+ return 0;
+
+ if (current_frame_info.initialized)
+ return current_frame_info.total_size == 0;
+
+ return compute_frame_size (get_frame_size ()) == 0;
+}
+
+/* Implement TARGET_SECONDARY_RELOAD. */
+
+static enum reg_class
+microblaze_secondary_reload (bool in_p ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED,
+ enum reg_class rclass, enum machine_mode mode ATTRIBUTE_UNUSED,
+ secondary_reload_info *sri ATTRIBUTE_UNUSED)
+{
+ if (rclass == ST_REGS)
+ return GR_REGS;
+
+ return NO_REGS;
+}
+
+static void
+microblaze_globalize_label (FILE * stream, const char *name)
+{
+ fputs ("\t.globl\t", stream);
+ if (interrupt_handler && strcmp (name, INTERRUPT_HANDLER_NAME))
+ {
+ fputs (INTERRUPT_HANDLER_NAME, stream);
+ fputs ("\n\t.globl\t", stream);
+ }
+ assemble_name (stream, name);
+ fputs ("\n", stream);
+}
+
+/* Returns true if decl should be placed into a "small data" section. */
+static bool
+microblaze_elf_in_small_data_p (const_tree decl)
+{
+ if (!TARGET_XLGPOPT)
+ return false;
+
+ /* We want to merge strings, so we never consider them small data. */
+ if (TREE_CODE (decl) == STRING_CST)
+ return false;
+
+ /* Functions are never in the small data area. */
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ return false;
+
+ if (TREE_CODE (decl) == VAR_DECL && DECL_SECTION_NAME (decl))
+ {
+ const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+ if (strcmp (section, ".sdata") == 0
+ || strcmp (section, ".sdata2") == 0
+ || strcmp (section, ".sbss") == 0
+ || strcmp (section, ".sbss2") == 0)
+ return true;
+ }
+
+ HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
+ return (size > 0 && size <= microblaze_section_threshold);
+}
+
+
+static section *
+microblaze_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align)
+{
+ switch (categorize_decl_for_section (decl, reloc))
+ {
+ case SECCAT_RODATA_MERGE_STR:
+ case SECCAT_RODATA_MERGE_STR_INIT:
+ /* MB binutils have various issues with mergeable string sections and
+ relaxation/relocation. Currently, turning mergeable sections
+ into regular readonly sections. */
+
+ return readonly_data_section;
+ default:
+ return default_elf_select_section (decl, reloc, align);
+ }
+}
+
+/*
+ Encode info about sections into the RTL based on a symbol's declaration.
+ The default definition of this hook, default_encode_section_info in
+ `varasm.c', sets a number of commonly-useful bits in SYMBOL_REF_FLAGS. */
+
+static void
+microblaze_encode_section_info (tree decl, rtx rtl, int first)
+{
+ default_encode_section_info (decl, rtl, first);
+}
+
+static rtx
+expand_pic_symbol_ref (enum machine_mode mode ATTRIBUTE_UNUSED, rtx op)
+{
+ rtx result;
+ result = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op), UNSPEC_GOTOFF);
+ result = gen_rtx_CONST (Pmode, result);
+ result = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, result);
+ result = gen_const_mem (Pmode, result);
+ return result;
+}
+
+bool
+microblaze_expand_move (enum machine_mode mode, rtx operands[])
+{
+ /* If operands[1] is a constant address invalid for pic, then we need to
+ handle it just like LEGITIMIZE_ADDRESS does. */
+ if (flag_pic)
+ {
+ if (GET_CODE (operands[0]) == MEM)
+ {
+ rtx addr = XEXP (operands[0], 0);
+ if (GET_CODE (addr) == SYMBOL_REF)
+ {
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+
+ rtx ptr_reg, result;
+
+ addr = expand_pic_symbol_ref (mode, addr);
+ ptr_reg = gen_reg_rtx (Pmode);
+ emit_move_insn (ptr_reg, addr);
+ result = gen_rtx_MEM (mode, ptr_reg);
+ operands[0] = result;
+ }
+ }
+ if (GET_CODE (operands[1]) == SYMBOL_REF
+ || GET_CODE (operands[1]) == LABEL_REF)
+ {
+ rtx result;
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ result = expand_pic_symbol_ref (mode, operands[1]);
+ if (GET_CODE (operands[0]) != REG)
+ {
+ rtx ptr_reg = gen_reg_rtx (Pmode);
+ emit_move_insn (ptr_reg, result);
+ emit_move_insn (operands[0], ptr_reg);
+ }
+ else
+ {
+ emit_move_insn (operands[0], result);
+ }
+ return true;
+ }
+ else if (GET_CODE (operands[1]) == MEM &&
+ GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+ {
+ rtx result;
+ rtx ptr_reg;
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ result = expand_pic_symbol_ref (mode, XEXP (operands[1], 0));
+
+ ptr_reg = gen_reg_rtx (Pmode);
+
+ emit_move_insn (ptr_reg, result);
+ result = gen_rtx_MEM (mode, ptr_reg);
+ emit_move_insn (operands[0], result);
+ return true;
+ }
+ else if (pic_address_needs_scratch (operands[1]))
+ {
+ rtx temp = force_reg (SImode, XEXP (XEXP (operands[1], 0), 0));
+ rtx temp2 = XEXP (XEXP (operands[1], 0), 1);
+
+ if (reload_in_progress)
+ df_set_regs_ever_live (PIC_OFFSET_TABLE_REGNUM, true);
+ emit_move_insn (operands[0], gen_rtx_PLUS (SImode, temp, temp2));
+ return true;
+ }
+ }
+
+ if ((reload_in_progress | reload_completed) == 0
+ && !register_operand (operands[0], SImode)
+ && !register_operand (operands[1], SImode)
+ && (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 0))
+ {
+ rtx temp = force_reg (SImode, operands[1]);
+ emit_move_insn (operands[0], temp);
+ return true;
+ }
+ return false;
+}
+
+/* Expand shift operations. */
+int
+microblaze_expand_shift (rtx operands[])
+{
+ gcc_assert ((GET_CODE (operands[2]) == CONST_INT)
+ || (GET_CODE (operands[2]) == REG)
+ || (GET_CODE (operands[2]) == SUBREG));
+
+ /* Shift by one -- generate pattern. */
+ if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 1))
+ return 0;
+
+ /* Have barrel shifter and shift > 1: use it. */
+ if (TARGET_BARREL_SHIFT)
+ return 0;
+
+ gcc_assert ((GET_CODE (operands[0]) == REG)
+ || (GET_CODE (operands[0]) == SUBREG)
+ || (GET_CODE (operands[1]) == REG)
+ || (GET_CODE (operands[1]) == SUBREG));
+
+ /* Shift by zero -- copy regs if necessary. */
+ if ((GET_CODE (operands[2]) == CONST_INT) && (INTVAL (operands[2]) == 0))
+ {
+ if (REGNO (operands[0]) != REGNO (operands[1]))
+ emit_insn (gen_movsi (operands[0], operands[1]));
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Return an RTX indicating where the return address to the
+ calling function can be found. */
+rtx
+microblaze_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
+{
+ if (count != 0)
+ return NULL_RTX;
+
+ return gen_rtx_PLUS (Pmode,
+ get_hard_reg_initial_val (Pmode,
+ MB_ABI_SUB_RETURN_ADDR_REGNUM),
+ GEN_INT (8));
+}
+
+/* Put string into .sdata2 if below threashold. */
+void
+microblaze_asm_output_ident (FILE *file ATTRIBUTE_UNUSED, const char *string)
+{
+ int size = strlen (string) + 1;
+ if (size <= microblaze_section_threshold)
+ switch_to_section (sdata2_section);
+ else
+ switch_to_section (readonly_data_section);
+ assemble_string (string, size);
+}
+
+static void
+microblaze_elf_asm_init_sections (void)
+{
+ sdata2_section
+ = get_unnamed_section (SECTION_WRITE, output_section_asm_op,
+ SDATA2_SECTION_ASM_OP);
+}
+
+/* Generate assembler code for constant parts of a trampoline. */
+
+static void
+microblaze_asm_trampoline_template (FILE *f)
+{
+ fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n");
+ fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n");
+ fprintf (f, "\t.word\t0x00000000\t\t# nop\n");
+ fprintf (f, "\t.word\t0x8fe30014\t\t# lw $3,20($31)\n");
+ fprintf (f, "\t.word\t0x8fe20018\t\t# lw $2,24($31)\n");
+ fprintf (f, "\t.word\t0x0060c821\t\t# move $25,$3 (abicalls)\n");
+ fprintf (f, "\t.word\t0x00600008\t\t# jr $3\n");
+ fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n");
+ /* fprintf (f, "\t.word\t0x00000000\t\t# <function address>\n"); */
+ /* fprintf (f, "\t.word\t0x00000000\t\t# <static chain value>\n"); */
+}
+
+/* Implement TARGET_TRAMPOLINE_INIT. */
+
+static void
+microblaze_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+ rtx mem;
+
+ emit_block_move (m_tramp, assemble_trampoline_template (),
+ GEN_INT (8*UNITS_PER_WORD), BLOCK_OP_NORMAL);
+
+ mem = adjust_address (m_tramp, SImode, 8);
+ emit_move_insn (mem, chain_value);
+ mem = adjust_address (m_tramp, SImode, 12);
+ emit_move_insn (mem, fnaddr);
+}
+\f
+/* Emit instruction to perform compare.
+ cmp is (compare_op op0 op1). */
+static rtx
+microblaze_emit_compare (enum machine_mode mode, rtx cmp, enum rtx_code *cmp_code)
+{
+ rtx cmp_op0 = XEXP (cmp, 0);
+ rtx cmp_op1 = XEXP (cmp, 1);
+ rtx comp_reg = gen_reg_rtx (SImode);
+ enum rtx_code code = *cmp_code;
+
+ gcc_assert ((GET_CODE (cmp_op0) == REG) || (GET_CODE (cmp_op0) == SUBREG));
+
+ /* If comparing against zero, just test source reg. */
+ if (cmp_op1 == const0_rtx)
+ return cmp_op0;
+
+ if (code == EQ || code == NE)
+ {
+ if (TARGET_PATTERN_COMPARE && GET_CODE(cmp_op1) == REG)
+ {
+ if (code == EQ)
+ emit_insn (gen_seq_internal_pat (comp_reg, cmp_op0, cmp_op1));
+ else
+ {
+ emit_insn (gen_sne_internal_pat (comp_reg, cmp_op0, cmp_op1));
+ *cmp_code = EQ;
+ }
+ }
+ else
+ /* Use xor for equal/not-equal comparison. */
+ emit_insn (gen_xorsi3 (comp_reg, cmp_op0, cmp_op1));
+ }
+ else if (code == GT || code == GTU || code == LE || code == LEU)
+ {
+ /* MicroBlaze compare is not symmetrical. */
+ /* Swap argument order. */
+ cmp_op1 = force_reg (mode, cmp_op1);
+ if (code == GT || code == LE)
+ emit_insn (gen_signed_compare (comp_reg, cmp_op0, cmp_op1));
+ else
+ emit_insn (gen_unsigned_compare (comp_reg, cmp_op0, cmp_op1));
+ /* Translate test condition. */
+ *cmp_code = swap_condition (code);
+ }
+ else /* if (code == GE || code == GEU || code == LT || code == LTU) */
+ {
+ cmp_op1 = force_reg (mode, cmp_op1);
+ if (code == GE || code == LT)
+ emit_insn (gen_signed_compare (comp_reg, cmp_op1, cmp_op0));
+ else
+ emit_insn (gen_unsigned_compare (comp_reg, cmp_op1, cmp_op0));
+ }
+
+ return comp_reg;
+}
+
+/* Generate conditional branch -- first, generate test condition,
+ second, generate correct branch instruction. */
+
+void
+microblaze_expand_conditional_branch (enum machine_mode mode, rtx operands[])
+{
+ enum rtx_code code = GET_CODE (operands[0]);
+ rtx comp;
+ rtx condition;
+
+ comp = microblaze_emit_compare (mode, operands[0], &code);
+ condition = gen_rtx_fmt_ee (signed_condition (code), SImode, comp, const0_rtx);
+ emit_jump_insn (gen_condjump (condition, operands[3]));
+}
+
+void
+microblaze_expand_conditional_branch_sf (rtx operands[])
+{
+ rtx condition;
+ rtx cmp_op0 = XEXP (operands[0], 0);
+ rtx cmp_op1 = XEXP (operands[0], 1);
+ rtx comp_reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_cstoresf4 (comp_reg, operands[0], cmp_op0, cmp_op1));
+ condition = gen_rtx_NE (SImode, comp_reg, const0_rtx);
+ emit_jump_insn (gen_condjump (condition, operands[3]));
+}
+
+/* Implement TARGET_FRAME_POINTER_REQUIRED. */
+
+static bool
+microblaze_frame_pointer_required (void)
+{
+ /* If the function contains dynamic stack allocations, we need to
+ use the frame pointer to access the static parts of the frame. */
+ if (cfun->calls_alloca)
+ return true;
+ return false;
+}
+
+void
+microblaze_expand_divide (rtx operands[])
+{
+ /* Table lookup software divides. Works for all (nr/dr) where (0 <= nr,dr <= 15). */
+
+ rtx regt1 = gen_reg_rtx (SImode);
+ rtx reg18 = gen_rtx_REG (SImode, R_TMP);
+ rtx regqi = gen_reg_rtx (QImode);
+ rtx div_label = gen_label_rtx ();
+ rtx div_end_label = gen_label_rtx ();
+ rtx div_table_rtx = gen_rtx_SYMBOL_REF (QImode,"_divsi3_table");
+ rtx mem_rtx;
+ rtx ret;
+ rtx jump, cjump, insn;
+
+ insn = emit_insn (gen_iorsi3 (regt1, operands[1], operands[2]));
+ cjump = emit_jump_insn_after (gen_cbranchsi4 (
+ gen_rtx_GTU (SImode, regt1, GEN_INT (15)),
+ regt1, GEN_INT (15), div_label), insn);
+ LABEL_NUSES (div_label) = 1;
+ JUMP_LABEL (cjump) = div_label;
+ emit_insn (gen_rtx_CLOBBER (SImode, reg18));
+
+ emit_insn (gen_ashlsi3_bshift (regt1, operands[1], GEN_INT(4)));
+ emit_insn (gen_addsi3 (regt1, regt1, operands[2]));
+ mem_rtx = gen_rtx_MEM (QImode,
+ gen_rtx_PLUS (Pmode, regt1, div_table_rtx));
+
+ insn = emit_insn (gen_movqi (regqi, mem_rtx));
+ insn = emit_insn (gen_movsi (operands[0], gen_rtx_SUBREG (SImode, regqi, 0)));
+ jump = emit_jump_insn_after (gen_jump (div_end_label), insn);
+ JUMP_LABEL (jump) = div_end_label;
+ LABEL_NUSES (div_end_label) = 1;
+ emit_barrier ();
+
+ emit_label (div_label);
+ ret = emit_library_call_value (gen_rtx_SYMBOL_REF (Pmode, "__divsi3"),
+ operands[0], LCT_NORMAL,
+ GET_MODE (operands[0]), 2, operands[1],
+ GET_MODE (operands[1]), operands[2],
+ GET_MODE (operands[2]));
+ if (ret != operands[0])
+ emit_move_insn (operands[0], ret);
+
+ emit_label (div_end_label);
+ emit_insn (gen_blockage ());
+}
+
+/* Implement TARGET_FUNCTION_VALUE. */
+static rtx
+microblaze_function_value (const_tree valtype,
+ const_tree func ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ return LIBCALL_VALUE (TYPE_MODE (valtype));
+}
+
+/* Implement TARGET_SCHED_ADJUST_COST. */
+static int
+microblaze_adjust_cost (rtx insn ATTRIBUTE_UNUSED, rtx link,
+ rtx dep ATTRIBUTE_UNUSED, int cost)
+{
+ if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
+ return cost;
+ if (REG_NOTE_KIND (link) != 0)
+ return 0;
+ return cost;
+}
+\f
+#undef TARGET_ENCODE_SECTION_INFO
+#define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
+
+#undef TARGET_ASM_GLOBALIZE_LABEL
+#define TARGET_ASM_GLOBALIZE_LABEL microblaze_globalize_label
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE microblaze_function_prologue
+
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE microblaze_function_epilogue
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS microblaze_rtx_costs
+
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST microblaze_address_cost
+
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE microblaze_attribute_table
+
+#undef TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P microblaze_elf_in_small_data_p
+
+#undef TARGET_ASM_SELECT_SECTION
+#define TARGET_ASM_SELECT_SECTION microblaze_select_section
+
+#undef TARGET_HAVE_SRODATA_SECTION
+#define TARGET_HAVE_SRODATA_SECTION true
+
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE \
+ microblaze_function_end_prologue
+
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION microblaze_handle_option
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
+
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES function_arg_partial_bytes
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE microblaze_can_eliminate
+
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS microblaze_legitimize_address
+
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P microblaze_legitimate_address_p
+
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED microblaze_frame_pointer_required
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE microblaze_asm_trampoline_template
+
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT microblaze_trampoline_init
+
+#undef TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE default_promote_function_mode_always_promote
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE microblaze_function_value
+
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD microblaze_secondary_reload
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST microblaze_adjust_cost
+
+#undef TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS microblaze_elf_asm_init_sections
+
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE microblaze_option_override
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
+#include "gt-microblaze.h"
Index: gcc/config/microblaze/microblaze.h
===================================================================
--- gcc/config/microblaze/microblaze.h (revision 0)
+++ gcc/config/microblaze/microblaze.h (revision 0)
@@ -0,0 +1,972 @@
+/* Definitions of target machine for GNU compiler for Xilinx MicroBlaze.
+ Copyright 2009, 2010 Free Software Foundation, Inc.
+
+ Contributed by Michael Eager <eager@eagercon.com>.
+
+ This file is part of GCC.
+
+ GCC 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 3, or (at your
+ option) any later version.
+
+ GCC 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 GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+/* Standard GCC variables that we reference. */
+
+/* MicroBlaze external variables defined in microblaze.c. */
+
+/* Which pipeline to schedule for. */
+enum pipeline_type
+{
+ MICROBLAZE_PIPE_3 = 0,
+ MICROBLAZE_PIPE_5 = 1
+};
+
+#define MICROBLAZE_MASK_NO_UNSAFE_DELAY 0x00000001
+
+/* print_operand punctuation chars */
+extern char microblaze_print_operand_punct[];
+
+/* # bytes of data/sdata cutoff */
+extern int microblaze_section_threshold;
+
+/* Map register # to debug register # */
+extern int microblaze_dbx_regno[];
+
+extern char call_used_regs[];
+extern int target_flags;
+extern int microblaze_no_unsafe_delay;
+extern enum pipeline_type microblaze_pipe;
+
+#define OBJECT_FORMAT_ELF
+
+/* This table translates options whose names would interfere
+ with normal driver options and adds a 'Z' so that they can get to
+ specs processing without interference.
+
+ The -xl-* options are deprecated and should be replace with their
+ corresponding equivalent:
+ -xl-mode-executable ==> -mxl-mode-executable
+ -xl-mode-xmdstub ==> -mxl-mode-xmdstub
+ -xl-mode-bootstrap ==> -mxl-mode-bootstrap
+ -xl-mode-novectors ==> -mxl-mode-novectors
+*/
+
+#define TARGET_OPTION_TRANSLATE_TABLE \
+ { "-xl-mode-executable", "-Zxl-mode-executable" }, \
+ { "-xl-mode-xmdstub", "-Zxl-mode-xmdstub" }, \
+ { "-xl-mode-bootstrap", "-Zxl-mode-bootstrap" }, \
+ { "-xl-mode-novectors", "-Zxl-mode-novectors" }
+
+/* Default target_flags if no switches are specified */
+#define TARGET_DEFAULT (MASK_SOFT_MUL | MASK_SOFT_DIV | MASK_SOFT_FLOAT)
+
+/* What is the default setting for -mcpu= . We set it to v4.00.a even though
+ we are actually ahead. This is safest version that has generate code
+ compatible for the original ISA */
+#define MICROBLAZE_DEFAULT_CPU "v4.00.a"
+
+/* Macros to decide whether certain features are available or not,
+ depending on the instruction set architecture level. */
+
+#undef SWITCH_TAKES_ARG
+#define SWITCH_TAKES_ARG(CHAR) \
+ (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
+
+/* We can debug without having a frame pointer. */
+#define CAN_DEBUG_WITHOUT_FP
+
+#define DRIVER_SELF_SPECS \
+ "%{mxl-soft-mul:%<mno-xl-soft-mul}", \
+ "%{mno-xl-barrel-shift:%<mxl-barrel-shift}", \
+ "%{mno-xl-pattern-compare:%<mxl-pattern-compare}", \
+ "%{mxl-soft-div:%<mno-xl-soft-div}", \
+ "%{msoft-float:%<mhard-float}"
+
+/* Tell collect what flags to pass to nm. */
+#ifndef NM_FLAGS
+#define NM_FLAGS "-Bn"
+#endif
+
+/* Names to predefine in the preprocessor for this target machine. */
+#define TARGET_CPU_CPP_BUILTINS() microblaze_cpp_define (pfile)
+
+/* Assembler specs. */
+
+#define TARGET_ASM_SPEC "%{v}"
+
+#define ASM_SPEC "\
+%{microblaze1} \
+%(target_asm_spec)"
+
+/* Extra switches sometimes passed to the linker. */
+/* -xl-mode-xmdstub translated to -Zxl-mode-xmdstub -- deprecated. */
+
+#define LINK_SPEC "%{shared:-shared} -N -relax \
+ %{Zxl-mode-xmdstub:-defsym _TEXT_START_ADDR=0x800} \
+ %{mxl-mode-xmdstub:-defsym _TEXT_START_ADDR=0x800} \
+ %{mxl-gp-opt:%{G*}} %{!mxl-gp-opt: -G 0} \
+ %{!Wl,-T*: %{!T*: -dT xilinx.ld%s}}"
+
+/* Specs for the compiler proper */
+
+#ifndef CC1_SPEC
+#define CC1_SPEC " \
+%{G*} %{gline:%{!g:%{!g0:%{!g1:%{!g2: -g1}}}}} \
+%{save-temps: } \
+%(subtarget_cc1_spec) \
+%{mxl-multiply-high:-mcpu=v6.00.a} \
+"
+#endif
+
+#define EXTRA_SPECS \
+ { "target_asm_spec", TARGET_ASM_SPEC }, \
+ SUBTARGET_EXTRA_SPECS
+
+/* Print subsidiary information on the compiler version in use. */
+#define MICROBLAZE_VERSION MICROBLAZE_DEFAULT_CPU
+
+#ifndef MACHINE_TYPE
+#define MACHINE_TYPE "MicroBlaze/ELF"
+#endif
+
+#ifndef TARGET_VERSION_INTERNAL
+#define TARGET_VERSION_INTERNAL(STREAM) \
+ fprintf (STREAM, " %s %s", MACHINE_TYPE, MICROBLAZE_VERSION)
+#endif
+
+#ifndef TARGET_VERSION
+#define TARGET_VERSION TARGET_VERSION_INTERNAL (stderr)
+#endif
+
+/* Local compiler-generated symbols must have a prefix that the assembler
+ understands. */
+
+#ifndef LOCAL_LABEL_PREFIX
+#define LOCAL_LABEL_PREFIX "$"
+#endif
+
+/* fixed registers. */
+#define MB_ABI_BASE_REGNUM 0
+#define MB_ABI_STACK_POINTER_REGNUM 1
+#define MB_ABI_GPRO_REGNUM 2
+#define MB_ABI_GPRW_REGNUM 13
+#define MB_ABI_INTR_RETURN_ADDR_REGNUM 14
+#define MB_ABI_SUB_RETURN_ADDR_REGNUM 15
+#define MB_ABI_DEBUG_RETURN_ADDR_REGNUM 16
+#define MB_ABI_EXCEPTION_RETURN_ADDR_REGNUM 17
+#define MB_ABI_ASM_TEMP_REGNUM 18
+/* This is our temp register. */
+#define MB_ABI_FRAME_POINTER_REGNUM 19
+#define MB_ABI_PIC_ADDR_REGNUM 20
+#define MB_ABI_PIC_FUNC_REGNUM 21
+/* Volatile registers. */
+#define MB_ABI_INT_RETURN_VAL_REGNUM 3
+#define MB_ABI_INT_RETURN_VAL2_REGNUM 4
+#define MB_ABI_FIRST_ARG_REGNUM 5
+#define MB_ABI_LAST_ARG_REGNUM 10
+#define MB_ABI_MAX_ARG_REGS (MB_ABI_LAST_ARG_REGNUM \
+ - MB_ABI_FIRST_ARG_REGNUM + 1)
+#define MB_ABI_STATIC_CHAIN_REGNUM 3
+#define MB_ABI_TEMP1_REGNUM 11
+#define MB_ABI_TEMP2_REGNUM 12
+#define MB_ABI_MSR_SAVE_REG 11
+/* Volatile register used to save MSR in interrupt handlers. */
+
+
+/* Debug stuff. */
+
+/* How to renumber registers for dbx and gdb. */
+#define DBX_REGISTER_NUMBER(REGNO) microblaze_dbx_regno[(REGNO)]
+
+/* Generate DWARF exception handling info. */
+#define DWARF2_UNWIND_INFO 1
+
+/* Don't generate .loc operations. */
+#define DWARF2_ASM_LINE_DEBUG_INFO 0
+
+/* The DWARF 2 CFA column which tracks the return address. */
+#define DWARF_FRAME_RETURN_COLUMN \
+ (GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
+
+/* Initial state of return address on entry to func = R15.
+ Actually, the RA is at R15+8, but gcc doesn't know how
+ to generate this.
+ NOTE: GDB has a workaround and expects this incorrect value.
+ If this is fixed, a corresponding fix to GDB is needed. */
+#define INCOMING_RETURN_ADDR_RTX \
+ gen_rtx_REG (VOIDmode, GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM)
+
+/* Use DWARF 2 debugging information by default. */
+#define DWARF2_DEBUGGING_INFO
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+/* Target machine storage layout */
+
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN 1
+#define WORDS_BIG_ENDIAN 1
+#define BITS_PER_UNIT 8
+#define BITS_PER_WORD 32
+#define UNITS_PER_WORD 4
+#define MIN_UNITS_PER_WORD 4
+#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 64
+#define POINTER_SIZE 32
+#define PARM_BOUNDARY 32
+#define FUNCTION_BOUNDARY 32
+#define EMPTY_FIELD_BOUNDARY 32
+#define STRUCTURE_SIZE_BOUNDARY 8
+#define BIGGEST_ALIGNMENT 32
+#define STRICT_ALIGNMENT 1
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ ((TREE_CODE (EXP) == STRING_CST || TREE_CODE (EXP) == CONSTRUCTOR) \
+ && (ALIGN) < BITS_PER_WORD \
+ ? BITS_PER_WORD \
+ : (ALIGN))
+
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ ((((ALIGN) < BITS_PER_WORD) \
+ && (TREE_CODE (TYPE) == ARRAY_TYPE \
+ || TREE_CODE (TYPE) == UNION_TYPE \
+ || TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
+
+#define LOCAL_ALIGNMENT(TYPE, ALIGN) \
+ (((TREE_CODE (TYPE) == ARRAY_TYPE \
+ && TYPE_MODE (TREE_TYPE (TYPE)) == QImode) \
+ && (ALIGN) < BITS_PER_WORD) ? BITS_PER_WORD : (ALIGN))
+
+#define WORD_REGISTER_OPERATIONS
+
+#define LOAD_EXTEND_OP(MODE) ZERO_EXTEND
+
+#define PROMOTE_MODE(MODE, UNSIGNEDP, TYPE) \
+ if (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < 4) \
+ (MODE) = SImode;
+
+/* Standard register usage. */
+
+/* On the MicroBlaze, we have 32 integer registers */
+
+#define FIRST_PSEUDO_REGISTER 36
+
+#define FIXED_REGISTERS \
+{ \
+ 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, \
+ 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 1, 1, 1, 1 \
+}
+
+#define CALL_USED_REGISTERS \
+{ \
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
+ 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ 1, 1, 1, 1 \
+}
+
+#define GP_REG_FIRST 0
+#define GP_REG_LAST 31
+#define GP_REG_NUM (GP_REG_LAST - GP_REG_FIRST + 1)
+#define GP_DBX_FIRST 0
+
+#define ST_REG 32
+#define AP_REG_NUM 33
+#define RAP_REG_NUM 34
+#define FRP_REG_NUM 35
+
+#define GP_REG_P(REGNO) ((unsigned) ((REGNO) - GP_REG_FIRST) < GP_REG_NUM)
+#define ST_REG_P(REGNO) ((REGNO) == ST_REG)
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Value is 1 if hard register REGNO can hold a value of machine-mode
+ MODE. In 32 bit mode, require that DImode and DFmode be in even
+ registers. For DImode, this makes some of the insns easier to
+ write, since you don't have to worry about a DImode value in
+ registers 3 & 4, producing a result in 4 & 5.
+
+ To make the code simpler HARD_REGNO_MODE_OK now just references an
+ array built in override_options. Because machmodes.h is not yet
+ included before this file is processed, the MODE bound can't be
+ expressed here. */
+extern char microblaze_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
+#define HARD_REGNO_MODE_OK(REGNO, MODE) \
+ microblaze_hard_regno_mode_ok[ (int)(MODE) ][ (REGNO)]
+
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ ((GET_MODE_CLASS (MODE1) == MODE_FLOAT || \
+ GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \
+ == (GET_MODE_CLASS (MODE2) == MODE_FLOAT || \
+ GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT))
+
+#define STACK_POINTER_REGNUM (GP_REG_FIRST + MB_ABI_STACK_POINTER_REGNUM)
+
+#define STACK_POINTER_OFFSET FIRST_PARM_OFFSET(FNDECL)
+
+/* Base register for access to local variables of the function. We
+ pretend that the frame pointer is
+ MB_ABI_INTR_RETURN_ADDR_REGNUM, and then eliminate it
+ to HARD_FRAME_POINTER_REGNUM. We can get away with this because
+ rMB_ABI_INTR_RETUREN_ADDR_REGNUM is a fixed
+ register(return address for interrupt), and will not be used for
+ anything else. */
+
+#define FRAME_POINTER_REGNUM FRP_REG_NUM
+#define HARD_FRAME_POINTER_REGNUM \
+ (GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM)
+#define ARG_POINTER_REGNUM AP_REG_NUM
+#define RETURN_ADDRESS_POINTER_REGNUM RAP_REG_NUM
+#define STATIC_CHAIN_REGNUM \
+ (GP_REG_FIRST + MB_ABI_STATIC_CHAIN_REGNUM)
+
+/* registers used in prologue/epilogue code when the stack frame
+ is larger than 32K bytes. These registers must come from the
+ scratch register set, and not used for passing and returning
+ arguments and any other information used in the calling sequence
+ (such as pic). */
+
+#define MICROBLAZE_TEMP1_REGNUM \
+ (GP_REG_FIRST + MB_ABI_TEMP1_REGNUM)
+
+#define MICROBLAZE_TEMP2_REGNUM \
+ (GP_REG_FIRST + MB_ABI_TEMP2_REGNUM)
+
+#define NO_FUNCTION_CSE 1
+
+#define PIC_OFFSET_TABLE_REGNUM \
+ (flag_pic ? (GP_REG_FIRST + MB_ABI_PIC_ADDR_REGNUM) : \
+ INVALID_REGNUM)
+
+enum reg_class
+{
+ NO_REGS, /* no registers in set. */
+ GR_REGS, /* integer registers. */
+ ST_REGS, /* status register. */
+ ALL_REGS, /* all registers. */
+ LIM_REG_CLASSES /* max value + 1. */
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define GENERAL_REGS GR_REGS
+
+#define REG_CLASS_NAMES \
+{ \
+ "NO_REGS", \
+ "GR_REGS", \
+ "ST_REGS", \
+ "ALL_REGS" \
+}
+
+#define REG_CLASS_CONTENTS \
+{ \
+ { 0x00000000, 0x00000000 }, /* no registers. */ \
+ { 0xffffffff, 0x00000000 }, /* integer registers. */ \
+ { 0x00000000, 0x00000001 }, /* status registers. */ \
+ { 0xffffffff, 0x0000000f } /* all registers. */ \
+}
+
+extern enum reg_class microblaze_regno_to_class[];
+
+#define REGNO_REG_CLASS(REGNO) microblaze_regno_to_class[ (REGNO) ]
+
+#define BASE_REG_CLASS GR_REGS
+
+#define INDEX_REG_CLASS GR_REGS
+
+#define GR_REG_CLASS_P(CLASS) ((CLASS) == GR_REGS)
+
+/* REGISTER AND CONSTANT CLASSES */
+
+#define SMALL_INT(X) ((unsigned HOST_WIDE_INT) (INTVAL (X) + 0x8000) < 0x10000)
+#define LARGE_INT(X) (INTVAL (X) >= 0x80000000 && INTVAL (X) <= 0xffffffff)
+#define PLT_ADDR_P(X) (GET_CODE (X) == UNSPEC && XINT (X,1) == UNSPEC_PLT)
+/* Test for a valid operand for a call instruction.
+ Don't allow the arg pointer register or virtual regs
+ since they may change into reg + const, which the patterns
+ can't handle yet. */
+#define CALL_INSN_OP(X) (CONSTANT_ADDRESS_P (X) \
+ || (GET_CODE (X) == REG && X != arg_pointer_rtx\
+ && ! (REGNO (X) >= FIRST_PSEUDO_REGISTER \
+ && REGNO (X) <= LAST_VIRTUAL_REGISTER)))
+
+/* True if VALUE is a signed 16-bit number. */
+#define SMALL_OPERAND(VALUE) \
+ ((unsigned HOST_WIDE_INT) (VALUE) + 0x8000 < 0x10000)
+
+/* Constant which cannot be loaded in one instruction. */
+#define LARGE_OPERAND(VALUE) \
+ ((((VALUE) & ~0x0000ffff) != 0) \
+ && (((VALUE) & ~0x0000ffff) != ~0x0000ffff) \
+ && (((VALUE) & 0x0000ffff) != 0 \
+ || (((VALUE) & ~2147483647) != 0 \
+ && ((VALUE) & ~2147483647) != ~2147483647)))
+
+#define PREFERRED_RELOAD_CLASS(X,CLASS) \
+ ((CLASS) != ALL_REGS \
+ ? (CLASS) \
+ : ((GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \
+ || GET_MODE_CLASS (GET_MODE (X)) == MODE_COMPLEX_FLOAT) \
+ ? (GR_REGS) \
+ : ((GET_MODE_CLASS (GET_MODE (X)) == MODE_INT \
+ || GET_MODE (X) == VOIDmode) \
+ ? (GR_REGS) : (CLASS))))
+
+#define SECONDARY_MEMORY_NEEDED(CLASS1, CLASS2, MODE) \
+ (GET_MODE_CLASS (MODE) == MODE_INT)
+
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ ((GET_MODE_SIZE (MODE) + (UNITS_PER_WORD) - 1) / (UNITS_PER_WORD))
+
+/* Stack layout; function entry, exit and calling. */
+
+#define STACK_GROWS_DOWNWARD
+
+/* Changed the starting frame offset to including the new link stuff */
+#define STARTING_FRAME_OFFSET \
+ (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL))
+
+/* The return address for the current frame is in r31 if this is a leaf
+ function. Otherwise, it is on the stack. It is at a variable offset
+ from sp/fp/ap, so we define a fake hard register rap which is a
+ poiner to the return address on the stack. This always gets eliminated
+ during reload to be either the frame pointer or the stack pointer plus
+ an offset. */
+
+#define RETURN_ADDR_RTX(count, frame) \
+ microblaze_return_addr(count,frame)
+
+extern struct microblaze_frame_info current_frame_info;
+
+#define ELIMINABLE_REGS \
+{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM}, \
+ { RETURN_ADDRESS_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { RETURN_ADDRESS_POINTER_REGNUM, \
+ GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM}, \
+ { RETURN_ADDRESS_POINTER_REGNUM, \
+ GP_REG_FIRST + MB_ABI_SUB_RETURN_ADDR_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, GP_REG_FIRST + MB_ABI_FRAME_POINTER_REGNUM}}
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET) = microblaze_initial_elimination_offset ((FROM), (TO))
+
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+#define FIRST_PARM_OFFSET(FNDECL) (UNITS_PER_WORD)
+
+#define ARG_POINTER_CFA_OFFSET(FNDECL) 0
+
+#define REG_PARM_STACK_SPACE(FNDECL) (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD)
+
+#define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) 1
+
+#define STACK_BOUNDARY 32
+
+#define NUM_OF_ARGS 6
+
+#define GP_RETURN (GP_REG_FIRST + MB_ABI_INT_RETURN_VAL_REGNUM)
+
+#define GP_ARG_FIRST (GP_REG_FIRST + MB_ABI_FIRST_ARG_REGNUM)
+#define GP_ARG_LAST (GP_REG_FIRST + MB_ABI_LAST_ARG_REGNUM)
+
+#define MAX_ARGS_IN_REGISTERS MB_ABI_MAX_ARG_REGS
+
+#define LIBCALL_VALUE(MODE) \
+ gen_rtx_REG ( \
+ ((GET_MODE_CLASS (MODE) != MODE_INT \
+ || GET_MODE_SIZE (MODE) >= 4) \
+ ? (MODE) \
+ : SImode), GP_RETURN)
+
+/* 1 if N is a possible register number for a function value.
+ On the MicroBlaze, R2 R3 are the only register thus used.
+ Currently, R2 are only implemented here (C has no complex type) */
+
+#define FUNCTION_VALUE_REGNO_P(N) ((N) == GP_RETURN)
+
+#define FUNCTION_ARG_REGNO_P(N) (((N) >= GP_ARG_FIRST && (N) <= GP_ARG_LAST))
+
+typedef struct microblaze_args
+{
+ int gp_reg_found; /* whether a gp register was found yet */
+ int arg_number; /* argument number */
+ int arg_words; /* # total words the arguments take */
+ int fp_arg_words; /* # words for FP args */
+ int last_arg_fp; /* nonzero if last arg was FP (EABI only) */
+ int fp_code; /* Mode of FP arguments */
+ int num_adjusts; /* number of adjustments made */
+ /* Adjustments made to args pass in regs. */
+ /* ??? The size is doubled to work around a bug in the code that sets the
+ adjustments in function_arg. */
+ struct rtx_def *adjust[MAX_ARGS_IN_REGISTERS * 2];
+} CUMULATIVE_ARGS;
+
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,FNDECL,N_NAMED_ARGS) \
+ init_cumulative_args (&CUM, FNTYPE, LIBNAME)
+
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
+ function_arg_advance (&CUM, MODE, TYPE, NAMED)
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+ function_arg( &CUM, MODE, TYPE, NAMED)
+
+#define NO_PROFILE_COUNTERS 1
+
+#define FUNCTION_PROFILER(FILE, LABELNO) { \
+ { \
+ fprintf (FILE, "\tbrki\tr16,_mcount\n"); \
+ } \
+ }
+
+#define EXIT_IGNORE_STACK 1
+
+#define TRAMPOLINE_SIZE (32 + 8)
+
+#define TRAMPOLINE_ALIGNMENT 32
+
+#define REGNO_OK_FOR_BASE_P(regno) microblaze_regno_ok_for_base_p ((regno), 1)
+
+#define REGNO_OK_FOR_INDEX_P(regno) microblaze_regno_ok_for_base_p ((regno), 1)
+
+#ifndef REG_OK_STRICT
+#define REG_STRICT_FLAG 0
+#else
+#define REG_STRICT_FLAG 1
+#endif
+
+#define REG_OK_FOR_BASE_P(X) \
+ microblaze_regno_ok_for_base_p (REGNO (X), REG_STRICT_FLAG)
+
+#define REG_OK_FOR_INDEX_P(X) \
+ microblaze_regno_ok_for_base_p (REGNO (X), REG_STRICT_FLAG)
+
+#define MAX_REGS_PER_ADDRESS 2
+
+
+/* Identify valid constant addresses. Exclude if PIC addr which
+ needs scratch register. */
+#define CONSTANT_ADDRESS_P(X) \
+ (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == CONST_INT \
+ || (GET_CODE (X) == CONST \
+ && ! (flag_pic && pic_address_needs_scratch (X))))
+
+/* Define this, so that when PIC, reload won't try to reload invalid
+ addresses which require two reload registers. */
+#define LEGITIMATE_PIC_OPERAND_P(X) (!pic_address_needs_scratch (X))
+
+/* At present, GAS doesn't understand li.[sd], so don't allow it
+ to be generated at present. */
+#define LEGITIMATE_CONSTANT_P(X) \
+ (GET_CODE (X) != CONST_DOUBLE \
+ || microblaze_const_double_ok (X, GET_MODE (X)))
+
+#define CASE_VECTOR_MODE (SImode)
+
+#ifndef DEFAULT_SIGNED_CHAR
+#define DEFAULT_SIGNED_CHAR 1
+#endif
+
+#define MOVE_MAX 4
+#define MAX_MOVE_MAX 8
+
+#define SLOW_BYTE_ACCESS 1
+
+/* sCOND operations return 1. */
+#define STORE_FLAG_VALUE 1
+
+#define SHIFT_COUNT_TRUNCATED 1
+
+/* This results in inefficient code for 64 bit to 32 conversions.
+ Something needs to be done about this. Perhaps not use any 32 bit
+ instructions? Perhaps use PROMOTE_MODE? */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define Pmode SImode
+
+#define FUNCTION_MODE SImode
+
+/* Mode should alwasy be SImode */
+#define REGISTER_MOVE_COST(MODE, FROM, TO) \
+ ( GR_REG_CLASS_P (FROM) && GR_REG_CLASS_P (TO) ? 2 \
+ : (FROM) == ST_REGS && GR_REG_CLASS_P (TO) ? 4 \
+ : 12)
+
+#define MEMORY_MOVE_COST(MODE,CLASS,TO_P) \
+ (4 + memory_move_secondary_cost ((MODE), (CLASS), (TO_P)))
+
+#define BRANCH_COST(speed_p, predictable_p) 2
+
+/* Control the assembler format that we output. */
+#define ASM_APP_ON " #APP\n"
+#define ASM_APP_OFF " #NO_APP\n"
+
+#define REGISTER_NAMES { \
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
+ "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", \
+ "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", \
+ "rmsr", "$ap", "$rap", "$frp" }
+
+#define ADDITIONAL_REGISTER_NAMES \
+{ \
+ { "r0", 0 + GP_REG_FIRST }, \
+ { "r1", 1 + GP_REG_FIRST }, \
+ { "r2", 2 + GP_REG_FIRST }, \
+ { "r3", 3 + GP_REG_FIRST }, \
+ { "r4", 4 + GP_REG_FIRST }, \
+ { "r5", 5 + GP_REG_FIRST }, \
+ { "r6", 6 + GP_REG_FIRST }, \
+ { "r7", 7 + GP_REG_FIRST }, \
+ { "r8", 8 + GP_REG_FIRST }, \
+ { "r9", 9 + GP_REG_FIRST }, \
+ { "r10", 10 + GP_REG_FIRST }, \
+ { "r11", 11 + GP_REG_FIRST }, \
+ { "r12", 12 + GP_REG_FIRST }, \
+ { "r13", 13 + GP_REG_FIRST }, \
+ { "r14", 14 + GP_REG_FIRST }, \
+ { "r15", 15 + GP_REG_FIRST }, \
+ { "r16", 16 + GP_REG_FIRST }, \
+ { "r17", 17 + GP_REG_FIRST }, \
+ { "r18", 18 + GP_REG_FIRST }, \
+ { "r19", 19 + GP_REG_FIRST }, \
+ { "r20", 20 + GP_REG_FIRST }, \
+ { "r21", 21 + GP_REG_FIRST }, \
+ { "r22", 22 + GP_REG_FIRST }, \
+ { "r23", 23 + GP_REG_FIRST }, \
+ { "r24", 24 + GP_REG_FIRST }, \
+ { "r25", 25 + GP_REG_FIRST }, \
+ { "r26", 26 + GP_REG_FIRST }, \
+ { "r27", 27 + GP_REG_FIRST }, \
+ { "r28", 28 + GP_REG_FIRST }, \
+ { "r29", 29 + GP_REG_FIRST }, \
+ { "r30", 30 + GP_REG_FIRST }, \
+ { "r31", 31 + GP_REG_FIRST }, \
+ { "rmsr", ST_REG} \
+}
+
+#define PRINT_OPERAND(FILE, X, CODE) print_operand (FILE, X, CODE)
+
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) microblaze_print_operand_punct[CODE]
+
+#define PRINT_OPERAND_ADDRESS(FILE, ADDR) print_operand_address (FILE, ADDR)
+
+/* ASM_OUTPUT_ALIGNED_COMMON and ASM_OUTPUT_ALIGNED_LOCAL
+
+ Unfortunately, we still need to set the section explicitly. Somehow,
+ our binutils assign .comm and .lcomm variables to the "current" section
+ in the assembly file, rather than where they implicitly belong. We need to
+ remove this explicit setting in GCC when binutils can understand sections
+ better. */
+#undef ASM_OUTPUT_ALIGNED_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \
+do { \
+ if (SIZE > 0 && SIZE <= microblaze_section_threshold \
+ && TARGET_XLGPOPT) \
+ { \
+ switch_to_section (sbss_section); \
+ } \
+ else \
+ { \
+ switch_to_section (bss_section); \
+ } \
+ fprintf (FILE, "%s", COMMON_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \
+ (SIZE), (ALIGN) / BITS_PER_UNIT); \
+ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
+} while (0)
+
+#undef ASM_OUTPUT_ALIGNED_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+do { \
+ if (SIZE > 0 && SIZE <= microblaze_section_threshold \
+ && TARGET_XLGPOPT) \
+ { \
+ switch_to_section (sbss_section); \
+ } \
+ else \
+ { \
+ switch_to_section (bss_section); \
+ } \
+ fprintf (FILE, "%s", LCOMMON_ASM_OP); \
+ assemble_name ((FILE), (NAME)); \
+ fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \
+ (SIZE), (ALIGN) / BITS_PER_UNIT); \
+ ASM_OUTPUT_TYPE_DIRECTIVE (FILE, NAME, "object"); \
+} while (0)
+
+#define ASM_OUTPUT_ALIGNED_BSS(FILE, DECL, NAME, SIZE, ALIGN) \
+do { \
+ ASM_OUTPUT_ALIGNED_LOCAL (FILE, NAME, SIZE, ALIGN); \
+} while (0)
+
+#define ASM_DECLARE_FUNCTION_NAME(STREAM,NAME,DECL) \
+{ \
+}
+
+#define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \
+ sprintf ((LABEL), "*%s%s%ld", (LOCAL_LABEL_PREFIX), (PREFIX), (long)(NUM))
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
+ fprintf (STREAM, "\t%s\t%sL%d\n", \
+ ".gpword", \
+ LOCAL_LABEL_PREFIX, VALUE)
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \
+do { \
+ if (flag_pic == 2) \
+ fprintf (STREAM, "\t%s\t%sL%d@GOTOFF\n", \
+ ".gpword", \
+ LOCAL_LABEL_PREFIX, VALUE); \
+ else \
+ fprintf (STREAM, "\t%s\t%sL%d\n", \
+ ".gpword", \
+ LOCAL_LABEL_PREFIX, VALUE); \
+} while (0)
+
+#define ASM_OUTPUT_ALIGN(STREAM,LOG) \
+ fprintf (STREAM, "\t.align\t%d\n", (LOG))
+
+#define ASM_OUTPUT_SKIP(STREAM,SIZE) \
+ fprintf (STREAM, "\t.space\t%lu\n", (SIZE))
+
+#define ASCII_DATA_ASM_OP "\t.ascii\t"
+#define STRING_ASM_OP "\t.asciz\t"
+
+#define ASM_OUTPUT_IDENT(FILE, STRING) \
+ microblaze_asm_output_ident (FILE, STRING)
+
+/* Default to -G 8 */
+#ifndef MICROBLAZE_DEFAULT_GVALUE
+#define MICROBLAZE_DEFAULT_GVALUE 8
+#endif
+
+/* Given a decl node or constant node, choose the section to output it in
+ and select that section. */
+
+/* Store in OUTPUT a string (made with alloca) containing
+ an assembler-name for a local static variable named NAME.
+ LABELNO is an integer which is different for each call. */
+#define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+( (OUTPUT) = (char *) alloca (strlen ((NAME)) + 10), \
+ sprintf ((OUTPUT), "%s.%d", (NAME), (LABELNO)))
+
+/* How to start an assembler comment.
+ The leading space is important (the microblaze assembler requires it). */
+#ifndef ASM_COMMENT_START
+#define ASM_COMMENT_START " #"
+#endif
+
+#define BSS_VAR 1
+#define SBSS_VAR 2
+#define DATA_VAR 4
+#define SDATA_VAR 5
+#define RODATA_VAR 6
+#define SDATA2_VAR 7
+
+/* These definitions are used in with the shift_type flag in the rtl. */
+#define SHIFT_CONST 1
+#define SHIFT_REG 2
+#define USE_ADDK 3
+
+/* Handle interrupt attribute. */
+extern int interrupt_handler;
+extern int save_volatiles;
+
+#define INTERRUPT_HANDLER_NAME "_interrupt_handler"
+
+/* These #define added for C++. */
+#define UNALIGNED_SHORT_ASM_OP ".data16"
+#define UNALIGNED_INT_ASM_OP ".data32"
+#define UNALIGNED_DOUBLE_INT_ASM_OP ".data8"
+
+#define ASM_BYTE_OP ".data8"
+
+/* The following #defines are used in the headers files. Always retain these. */
+
+/* Added for declaring size at the end of the function. */
+#undef ASM_DECLARE_FUNCTION_SIZE
+#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
+ do { \
+ if (!flag_inhibit_size_directive) \
+ { \
+ char label[256]; \
+ static int labelno; \
+ labelno++; \
+ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \
+ (*targetm.asm_out.internal_label) (FILE, "Lfe", labelno); \
+ fprintf (FILE, "%s", SIZE_ASM_OP); \
+ assemble_name (FILE, (FNAME)); \
+ fprintf (FILE, ","); \
+ assemble_name (FILE, label); \
+ fprintf (FILE, "-"); \
+ assemble_name (FILE, (FNAME)); \
+ putc ('\n', FILE); \
+ } \
+ } while (0)
+
+#define GLOBAL_ASM_OP "\t.globl\t"
+#define TYPE_ASM_OP "\t.type\t"
+#define SIZE_ASM_OP "\t.size\t"
+#define COMMON_ASM_OP "\t.comm\t"
+#define LCOMMON_ASM_OP "\t.lcomm\t"
+
+#define MAX_OFILE_ALIGNMENT (32768*8)
+
+#define TYPE_OPERAND_FMT "@%s"
+
+/* Write the extra assembler code needed to declare an object properly. */
+#undef ASM_DECLARE_OBJECT_NAME
+#define ASM_DECLARE_OBJECT_NAME(FILE, NAME, DECL) \
+ do { \
+ fprintf (FILE, "%s", TYPE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ putc (',', FILE); \
+ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \
+ putc ('\n', FILE); \
+ size_directive_output = 0; \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL)) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "%s", SIZE_ASM_OP); \
+ assemble_name (FILE, NAME); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ microblaze_declare_object (FILE, NAME, "", ":\n", 0); \
+ } while (0)
+
+#undef ASM_FINISH_DECLARE_OBJECT
+#define ASM_FINISH_DECLARE_OBJECT(FILE, DECL, TOP_LEVEL, AT_END) \
+do { \
+ char *name = XSTR (XEXP (DECL_RTL (DECL), 0), 0); \
+ if (!flag_inhibit_size_directive && DECL_SIZE (DECL) \
+ && ! AT_END && TOP_LEVEL \
+ && DECL_INITIAL (DECL) == error_mark_node \
+ && !size_directive_output) \
+ { \
+ size_directive_output = 1; \
+ fprintf (FILE, "%s", SIZE_ASM_OP); \
+ assemble_name (FILE, name); \
+ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (DECL))); \
+ } \
+ } while (0)
+
+#define ASM_OUTPUT_DEF(FILE,LABEL1,LABEL2) \
+ do { fputc ( '\t', FILE); \
+ assemble_name (FILE, LABEL1); \
+ fputs ( " = ", FILE); \
+ assemble_name (FILE, LABEL2); \
+ fputc ( '\n', FILE); \
+ } while (0)
+
+#define ASM_WEAKEN_LABEL(FILE,NAME) \
+ do { fputs ("\t.weakext\t", FILE); \
+ assemble_name (FILE, NAME); \
+ fputc ('\n', FILE); \
+ } while (0)
+
+#define MAKE_DECL_ONE_ONLY(DECL) (DECL_WEAK (DECL) = 1)
+#undef UNIQUE_SECTION_P
+#define UNIQUE_SECTION_P(DECL) (DECL_ONE_ONLY (DECL))
+
+#undef TARGET_ASM_NAMED_SECTION
+#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section
+
+/* Define the strings to put out for each section in the object file.
+
+ Note: For ctors/dtors, we want to give these sections the SHF_WRITE
+ attribute to allow shared libraries to patch/resolve addresses into
+ these locations. On Microblaze, there is no concept of shared libraries
+ yet, so this is for future use. */
+#define TEXT_SECTION_ASM_OP "\t.text"
+#define DATA_SECTION_ASM_OP "\t.data"
+#define READONLY_DATA_SECTION_ASM_OP \
+ "\t.rodata"
+#define BSS_SECTION_ASM_OP "\t.bss"
+#define CTORS_SECTION_ASM_OP "\t.section\t.ctors,\"aw\""
+#define DTORS_SECTION_ASM_OP "\t.section\t.dtors,\"aw\""
+#define INIT_SECTION_ASM_OP "\t.section\t.init,\"ax\""
+#define FINI_SECTION_ASM_OP "\t.section\t.fini,\"ax\""
+
+#define SDATA_SECTION_ASM_OP "\t.sdata" /* Small RW initialized data */
+#define SDATA2_SECTION_ASM_OP "\t.sdata2" /* Small RO initialized data */
+#define SBSS_SECTION_ASM_OP "\t.sbss" /* Small RW uninitialized data */
+#define SBSS2_SECTION_ASM_OP "\t.sbss2" /* Small RO uninitialized data */
+
+#define HOT_TEXT_SECTION_NAME ".text.hot"
+#define UNLIKELY_EXECUTED_TEXT_SECTION_NAME \
+ ".text.unlikely"
+
+/* We do this to save a few 10s of code space that would be taken up
+ by the call_FUNC () wrappers, used by the generic CRT_CALL_STATIC_FUNCTION
+ definition in crtstuff.c. */
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \
+ asm ( SECTION_OP "\n" \
+ "\tbrlid r15, " #FUNC "\n\t nop\n" \
+ TEXT_SECTION_ASM_OP);
+
+/* We need to group -lm as well, since some Newlib math functions
+ reference __errno! */
+#undef LIB_SPEC
+#define LIB_SPEC \
+"%{!nostdlib: \
+%{pg:-start-group -lxilprofile -lgloss -lxil -lc -lm -end-group } \
+%{!pg:-start-group -lgloss -lxil -lc -lm -end-group }} "
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+#define STARTFILE_EXECUTABLE_SPEC "crt0.o%s crti.o%s crtbegin.o%s"
+#define STARTFILE_XMDSTUB_SPEC "crt1.o%s crti.o%s crtbegin.o%s"
+#define STARTFILE_BOOTSTRAP_SPEC "crt2.o%s crti.o%s crtbegin.o%s"
+#define STARTFILE_NOVECTORS_SPEC "crt3.o%s crti.o%s crtbegin.o%s"
+#define STARTFILE_CRTINIT_SPEC "%{!pg: %{!mno-clearbss: crtinit.o%s} \
+%{mno-clearbss: sim-crtinit.o%s}} \
+%{pg: %{!mno-clearbss: pgcrtinit.o%s} %{mno-clearbss: sim-pgcrtinit.o%s}}"
+
+#define STARTFILE_DEFAULT_SPEC STARTFILE_EXECUTABLE_SPEC
+
+#undef SUBTARGET_EXTRA_SPECS
+#define SUBTARGET_EXTRA_SPECS \
+ { "startfile_executable", STARTFILE_EXECUTABLE_SPEC }, \
+ { "startfile_xmdstub", STARTFILE_XMDSTUB_SPEC }, \
+ { "startfile_bootstrap", STARTFILE_BOOTSTRAP_SPEC }, \
+ { "startfile_novectors", STARTFILE_NOVECTORS_SPEC }, \
+ { "startfile_crtinit", STARTFILE_CRTINIT_SPEC }, \
+ { "startfile_default", STARTFILE_DEFAULT_SPEC },
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "\
+%{Zxl-mode-executable : %(startfile_executable) ; \
+ mxl-mode-executable : %(startfile_executable) ; \
+ Zxl-mode-xmdstub : %(startfile_xmdstub) ; \
+ mxl-mode-xmdstub : %(startfile_xmdstub) ; \
+ Zxl-mode-bootstrap : %(startfile_bootstrap) ; \
+ mxl-mode-bootstrap : %(startfile_bootstrap) ; \
+ Zxl-mode-novectors : %(startfile_novectors) ; \
+ mxl-mode-novectors : %(startfile_novectors) ; \
+ Zxl-mode-xilkernel : %(startfile_xilkernel) ; \
+ mxl-mode-xilkernel : %(startfile_xilkernel) ; \
+ : %(startfile_default) \
+} \
+%(startfile_crtinit)"
Index: libstdc++-v3/ChangeLog
===================================================================
--- libstdc++-v3/ChangeLog (revision 164569)
+++ libstdc++-v3/ChangeLog (working copy)
@@ -1,3 +1,8 @@
+2010-09-28 Michael Eager <eager@eagercon.com>
+
+ * config/cpu/microblaze/cpu_defines.h: New. Define
+ _GLIBCXX_NO_VERBOSE_TERMINATE for MicroBlaze.
+
2010-09-22 David Krauss <potswa@mac.com>
PR libstdc++/45628
Index: libstdc++-v3/config/cpu/microblaze/cpu_defines.h
===================================================================
--- libstdc++-v3/config/cpu/microblaze/cpu_defines.h (revision 0)
+++ libstdc++-v3/config/cpu/microblaze/cpu_defines.h (revision 0)
@@ -0,0 +1,34 @@
+// Specific definitions for Xilinx MicroBlaze platforms -*- C++ -*-
+
+// Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+//
+// Contributed by Michael Eager <eager@eagercon.com>.
+//
+// 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
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library 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.
+
+// Under Section 7 of GPL version 3, you are granted additional
+// permissions described in the GCC Runtime Library Exception, version
+// 3.1, as published by the Free Software Foundation.
+
+// You should have received a copy of the GNU General Public License and
+// a copy of the GCC Runtime Library Exception along with this program;
+// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_CPU_DEFINES
+#define _GLIBCXX_CPU_DEFINES 1
+
+// Optimize memory size for embedded systems
+// -- Use abort for eh terminate
+#define _GLIBCXX_NO_VERBOSE_TERMINATE 1
+
+#endif
Index: configure.ac
===================================================================
--- configure.ac (revision 164569)
+++ configure.ac (working copy)
@@ -887,7 +887,7 @@
noconfigdirs="$noconfigdirs ld binutils gprof target-libgloss ${libgcj}"
;;
microblaze*)
- noconfigdirs="$noconfigdirs gprof ${libgcj}"
+ noconfigdirs="$noconfigdirs gprof target-libssp ${libgcj}"
;;
mips*-sde-elf*)
skipdirs="$skipdirs target-libiberty"
Index: ChangeLog
===================================================================
--- ChangeLog (revision 164569)
+++ ChangeLog (working copy)
@@ -1,3 +1,8 @@
+2010-09-28 Michael Eager <eager@eagercon.com>
+
+ * configure.ac (microblaze): Add target-libssp to noconfigdirs.
+ * configure: Regenerate.
+
2010-09-21 Iain Sandoe <iains@gcc.gnu.org>
* configure.ac (enable-lto): Add Darwin to the list of supported lto
[-- Attachment #3: mb-htdocs-10-09-27.patch --]
[-- Type: text/x-patch, Size: 2767 bytes --]
Index: backends.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/backends.html,v
retrieving revision 1.36
diff -u -p -r1.36 backends.html
--- backends.html 29 Jun 2009 23:13:12 -0000 1.36
+++ backends.html 27 Sep 2010 22:56:40 -0000
@@ -85,6 +85,7 @@ m68hc11 | L FI l c s
m68k | ? c a
mcore | ? FI gm d s
mep | F C p g d t s
+microblaze CB bd s
mips | Q CB qr p bda s
mmix | HM Q C q p b a e
mn10300 | ?? c g s
Index: index.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/index.html,v
retrieving revision 1.751
diff -u -p -r1.751 index.html
--- index.html 7 Aug 2010 17:50:57 -0000 1.751
+++ index.html 27 Sep 2010 22:56:40 -0000
@@ -51,6 +51,11 @@ mission statement</a>.</p>
<dl class="news">
+<dt>September 28, 2010</dt>
+<dd>Support has been added for the
+<a href="gcc-4.6/changes.html#microblaze">Xilinx MicroBlaze softcore processor</a>
+target by Michael Eager, Eager Consulting.</dd>
+
<dt>July 31, 2010</dt>
<dd><a href="gcc-4.5/">GCC 4.5.1</a> has been released.</dd>
Index: readings.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/readings.html,v
retrieving revision 1.198
diff -u -p -r1.198 readings.html
--- readings.html 2 May 2010 19:42:24 -0000 1.198
+++ readings.html 27 Sep 2010 22:56:40 -0000
@@ -172,6 +172,13 @@ Intel®64 and IA-32 Architectures Sof
<br />SID includes a MeP simulator.
</li>
+ <li>MicroBlace
+ <br />Manufacturer: Xilinx
+ <br /><a href="http://www.xilinx.com/support/documentation/sw_manuals/xilinx11/mb_ref_guide.pdf">
+ MicroBlaze Processor Reference Guide</a>
+ <br />GDB includes a simulator for an earlier version of the processor.
+ </li>
+
<li>mips (mipsel, mips64, mips64el)
<br />The *el variants are little-endian configurations.
</li>
Index: gcc-4.6/changes.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/gcc-4.6/changes.html,v
retrieving revision 1.44
diff -u -p -r1.44 changes.html
--- gcc-4.6/changes.html 25 Sep 2010 07:08:58 -0000 1.44
+++ gcc-4.6/changes.html 27 Sep 2010 22:56:42 -0000
@@ -265,6 +265,12 @@
the <code>--enable-frame-pointer</code> configure option.</li>
</ul>
+<h3 id="microblaze">MicroBlaze</h3>
+
+<p>Support has been added for the Xilinx MicroBlaze softcore Processor
+(microblaze-elf) embedded target. This configurable processor is
+supported on several Xilinx Spartan and Virtex FPGAs. </p>
+
<h3>MIPS</h3>
<h3 id="picochip">picochip</h3>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: MicroBlaze port
2010-09-29 9:07 MicroBlaze port Michael Eager
@ 2010-09-29 13:16 ` Joseph S. Myers
2010-09-29 22:20 ` Michael Eager
2010-09-30 23:18 ` Michael Eager
2010-10-01 10:31 ` H.J. Lu
2 siblings, 1 reply; 9+ messages in thread
From: Joseph S. Myers @ 2010-09-29 13:16 UTC (permalink / raw)
To: Michael Eager; +Cc: gcc-patches
On Tue, 28 Sep 2010, Michael Eager wrote:
> +extern char call_used_regs[];
Does this actually work now that call_used_regs is a macro in
hard-reg-set.h?
> +extern int target_flags;
This will break when my patch
<http://gcc.gnu.org/ml/gcc-patches/2010-09/msg02171.html> is in. Don't
explicitly declare any variables from .opt files.
> +/* This table translates options whose names would interfere
> + with normal driver options and adds a 'Z' so that they can get to
> + specs processing without interference.
> +
> + The -xl-* options are deprecated and should be replace with their
> + corresponding equivalent:
> + -xl-mode-executable ==> -mxl-mode-executable
> + -xl-mode-xmdstub ==> -mxl-mode-xmdstub
> + -xl-mode-bootstrap ==> -mxl-mode-bootstrap
> + -xl-mode-novectors ==> -mxl-mode-novectors
> +*/
> +
> +#define TARGET_OPTION_TRANSLATE_TABLE \
> + { "-xl-mode-executable", "-Zxl-mode-executable" }, \
> + { "-xl-mode-xmdstub", "-Zxl-mode-xmdstub" }, \
> + { "-xl-mode-bootstrap", "-Zxl-mode-bootstrap" }, \
> + { "-xl-mode-novectors", "-Zxl-mode-novectors" }
Is it possible for you to use the .opt alias facility instead of
TARGET_OPTION_TRANSLATE_TABLE? If you make something an alias then you
don't need to handle it in specs - you could alias these options directly
to the -m versions, I'd have thought. I'd like to get rid of
TARGET_OPTION_TRANSLATE_TABLE.
> +#undef SWITCH_TAKES_ARG
> +#define SWITCH_TAKES_ARG(CHAR) \
> + (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
You're missing two other pieces of -G support: handling it in the
handle_option hook, and use of g.opt in config.gcc. See
<http://gcc.gnu.org/ml/gcc-patches/2010-07/msg02340.html> and
<http://gcc.gnu.org/ml/gcc-patches/2010-08/msg00066.html>.
--
Joseph S. Myers
joseph@codesourcery.com
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: MicroBlaze port
2010-09-29 13:16 ` Joseph S. Myers
@ 2010-09-29 22:20 ` Michael Eager
0 siblings, 0 replies; 9+ messages in thread
From: Michael Eager @ 2010-09-29 22:20 UTC (permalink / raw)
To: Joseph S. Myers; +Cc: gcc-patches
Thanks for noticing these issues.
Joseph S. Myers wrote:
> On Tue, 28 Sep 2010, Michael Eager wrote:
>
>> +extern char call_used_regs[];
>
> Does this actually work now that call_used_regs is a macro in
> hard-reg-set.h?
The macro silently rewrites references to call_used_regs.
I've removed the extern.
>
>> +extern int target_flags;
>
> This will break when my patch
> <http://gcc.gnu.org/ml/gcc-patches/2010-09/msg02171.html> is in. Don't
> explicitly declare any variables from .opt files.
Removed extern.
>> +/* This table translates options whose names would interfere
>> + with normal driver options and adds a 'Z' so that they can get to
>> + specs processing without interference.
>> +
>> + The -xl-* options are deprecated and should be replace with their
>> + corresponding equivalent:
>> + -xl-mode-executable ==> -mxl-mode-executable
>> + -xl-mode-xmdstub ==> -mxl-mode-xmdstub
>> + -xl-mode-bootstrap ==> -mxl-mode-bootstrap
>> + -xl-mode-novectors ==> -mxl-mode-novectors
>> +*/
>> +
>> +#define TARGET_OPTION_TRANSLATE_TABLE \
>> + { "-xl-mode-executable", "-Zxl-mode-executable" }, \
>> + { "-xl-mode-xmdstub", "-Zxl-mode-xmdstub" }, \
>> + { "-xl-mode-bootstrap", "-Zxl-mode-bootstrap" }, \
>> + { "-xl-mode-novectors", "-Zxl-mode-novectors" }
>
> Is it possible for you to use the .opt alias facility instead of
> TARGET_OPTION_TRANSLATE_TABLE? If you make something an alias then you
> don't need to handle it in specs - you could alias these options directly
> to the -m versions, I'd have thought. I'd like to get rid of
> TARGET_OPTION_TRANSLATE_TABLE.
This is for deprecated options; I've removed it.
>> +#undef SWITCH_TAKES_ARG
>> +#define SWITCH_TAKES_ARG(CHAR) \
>> + (DEFAULT_SWITCH_TAKES_ARG (CHAR) || (CHAR) == 'G')
>
> You're missing two other pieces of -G support: handling it in the
> handle_option hook, and use of g.opt in config.gcc. See
> <http://gcc.gnu.org/ml/gcc-patches/2010-07/msg02340.html> and
> <http://gcc.gnu.org/ml/gcc-patches/2010-08/msg00066.html>.
Fixed:
--- config.gcc-orig 2010-09-29 09:27:56.000000000 -0700
+++ config.gcc 2010-09-29 09:28:22.000000000 -0700
@@ -341,6 +341,7 @@ m68k-*-*)
;;
microblaze*-*-*)
cpu_type=microblaze
+ extra_options="${extra_options} g.opt"
;;
mips*-*-*)
cpu_type=mips
--- orig/microblaze.c 2010-09-29 08:39:06.000000000 -0700
+++ microblaze.c 2010-09-29 09:27:39.000000000 -0700
@@ -1279,6 +1279,11 @@ microblaze_handle_option (size_t code,
{
switch (code)
{
+ case OPT_G:
+ g_switch_value = value;
+ g_switch_set = true;
+ return true;
+
case OPT_mno_clearbss:
flag_zero_initialized_in_bss = 0;
warning (0, "-mno-clearbss is deprecated; use -fno-zero-initialized-in-bss");
--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: MicroBlaze port
2010-09-29 9:07 MicroBlaze port Michael Eager
2010-09-29 13:16 ` Joseph S. Myers
@ 2010-09-30 23:18 ` Michael Eager
2010-10-01 10:31 ` H.J. Lu
2 siblings, 0 replies; 9+ messages in thread
From: Michael Eager @ 2010-09-30 23:18 UTC (permalink / raw)
To: gcc-patches
Michael Eager wrote:
> Hi --
>
> Attached are the final patches to the GCC trunk
> and htdocs to add support for the Xilinx MicroBlaze
> processor. These patches have been updated to the
> current head but are otherwise identical to the
> patches which were previously approved.
>
> The wwwdocs patches were approved by Gerald Pfeifer
> off-list.
>
> Rather than repost each patch individually with its
> ChangeLog, the attached patch contains the ChangeLogs.
> The ChangeLogs are the same as previously posted.
>
> Please let me know ASAP if you see any problems
> with checking these patches into GCC mainline.
Patches to support MicroBlaze have been checked in.
--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: MicroBlaze port
2010-09-29 9:07 MicroBlaze port Michael Eager
2010-09-29 13:16 ` Joseph S. Myers
2010-09-30 23:18 ` Michael Eager
@ 2010-10-01 10:31 ` H.J. Lu
2010-10-06 19:52 ` Michael Eager
2 siblings, 1 reply; 9+ messages in thread
From: H.J. Lu @ 2010-10-01 10:31 UTC (permalink / raw)
To: Michael Eager; +Cc: gcc-patches
On Tue, Sep 28, 2010 at 11:52 AM, Michael Eager <eager@eagerm.com> wrote:
> Hi --
>
> Attached are the final patches to the GCC trunk
> and htdocs to add support for the Xilinx MicroBlaze
> processor. These patches have been updated to the
> current head but are otherwise identical to the
> patches which were previously approved.
>
> The wwwdocs patches were approved by Gerald Pfeifer
> off-list.
>
> Rather than repost each patch individually with its
> ChangeLog, the attached patch contains the ChangeLogs.
> The ChangeLogs are the same as previously posted.
>
> Please let me know ASAP if you see any problems
> with checking these patches into GCC mainline.
>
It caused:
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45856
--
H.J.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: MicroBlaze port
2010-10-01 10:31 ` H.J. Lu
@ 2010-10-06 19:52 ` Michael Eager
0 siblings, 0 replies; 9+ messages in thread
From: Michael Eager @ 2010-10-06 19:52 UTC (permalink / raw)
To: H.J. Lu; +Cc: gcc-patches
H.J. Lu wrote:
>
> It caused:
>
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45856
I've updated the bug report with patches for the
test cases. Tested on x86 and x86-64.
--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Microblaze port
2010-09-29 9:47 ` Joel Sherrill
@ 2010-09-29 12:19 ` Michael Eager
0 siblings, 0 replies; 9+ messages in thread
From: Michael Eager @ 2010-09-29 12:19 UTC (permalink / raw)
To: Joel Sherrill; +Cc: David Edelsohn, gcc, gcc-patches
Joel Sherrill wrote:
> On 09/28/2010 01:56 PM, Michael Eager wrote:
>> David Edelsohn wrote:
>>> I am pleased to announce that the GCC Steering Committee has
>>> accepted the Microblaze port for inclusion in GCC and appointed
>>> Michael Eager as port maintainer.
>> Thanks!
>>
> Congratulations!
>
> Does your current source include the microblaze-*-rtems* target
> configure magic? I don't remember where it got left.
No, it doesn't.
After the basic MicroBlaze support is checked in, please post patches
for rtems to gcc-patches.
--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Microblaze port
2010-09-29 9:20 ` Microblaze port Michael Eager
@ 2010-09-29 9:47 ` Joel Sherrill
2010-09-29 12:19 ` Michael Eager
0 siblings, 1 reply; 9+ messages in thread
From: Joel Sherrill @ 2010-09-29 9:47 UTC (permalink / raw)
To: Michael Eager; +Cc: David Edelsohn, gcc, gcc-patches
On 09/28/2010 01:56 PM, Michael Eager wrote:
> David Edelsohn wrote:
>> I am pleased to announce that the GCC Steering Committee has
>> accepted the Microblaze port for inclusion in GCC and appointed
>> Michael Eager as port maintainer.
> Thanks!
>
Congratulations!
Does your current source include the microblaze-*-rtems* target
configure magic? I don't remember where it got left.
--joel
> Adding myself to maintainer list.
>
> Index: MAINTAINERS
> ===================================================================
> --- MAINTAINERS (revision 164696)
> +++ MAINTAINERS (working copy)
> @@ -72,6 +72,7 @@
> m68k-motorola-sysv port Philippe De Muyter phdm@macqel.be
> mcore port Nick Clifton nickc@redhat.com
> mep port DJ Delorie dj@redhat.com
> +microblaze Michael Eager eager@eagercon.com
> mips port Eric Christopher echristo@apple.com
> mips port Richard Sandiford rdsandiford@googlemail.com
> mmix port Hans-Peter Nilsson hp@bitrange.com
>
>
--
Joel Sherrill, Ph.D. Director of Research& Development
joel.sherrill@OARcorp.com On-Line Applications Research
Ask me about RTEMS: a free RTOS Huntsville AL 35805
Support Available (256) 722-9985
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Microblaze port
[not found] <E1P0eoH-0008DY-Nz@fencepost.gnu.org>
@ 2010-09-29 9:20 ` Michael Eager
2010-09-29 9:47 ` Joel Sherrill
0 siblings, 1 reply; 9+ messages in thread
From: Michael Eager @ 2010-09-29 9:20 UTC (permalink / raw)
To: David Edelsohn; +Cc: gcc, gcc-patches
David Edelsohn wrote:
> I am pleased to announce that the GCC Steering Committee has
> accepted the Microblaze port for inclusion in GCC and appointed
> Michael Eager as port maintainer.
Thanks!
Adding myself to maintainer list.
Index: MAINTAINERS
===================================================================
--- MAINTAINERS (revision 164696)
+++ MAINTAINERS (working copy)
@@ -72,6 +72,7 @@
m68k-motorola-sysv port Philippe De Muyter phdm@macqel.be
mcore port Nick Clifton nickc@redhat.com
mep port DJ Delorie dj@redhat.com
+microblaze Michael Eager eager@eagercon.com
mips port Eric Christopher echristo@apple.com
mips port Richard Sandiford rdsandiford@googlemail.com
mmix port Hans-Peter Nilsson hp@bitrange.com
--
Michael Eager eager@eagercon.com
1960 Park Blvd., Palo Alto, CA 94306 650-325-8077
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2010-10-06 19:52 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-29 9:07 MicroBlaze port Michael Eager
2010-09-29 13:16 ` Joseph S. Myers
2010-09-29 22:20 ` Michael Eager
2010-09-30 23:18 ` Michael Eager
2010-10-01 10:31 ` H.J. Lu
2010-10-06 19:52 ` Michael Eager
[not found] <E1P0eoH-0008DY-Nz@fencepost.gnu.org>
2010-09-29 9:20 ` Microblaze port Michael Eager
2010-09-29 9:47 ` Joel Sherrill
2010-09-29 12:19 ` Michael Eager
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).