X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fconfig%2Frs6000%2Frs6000.md;h=a5cae5ed1af28f3736c22ee7d186406b5e06e818;hb=4747587880166b33e57209e8dd2bb6cbbb1865a3;hp=abb6043fb0d19d098dee5325782cb7742770e1bc;hpb=50310931b0a67edeee23bf37081b3d2647c4523e;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index abb6043fb0d..a5cae5ed1af 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -23,7 +23,7 @@ ;; Define an insn type attribute. This is used in function unit delay ;; computations. -(define_attr "type" "integer,load,fpload,imul,idiv,branch,compare,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg" +(define_attr "type" "integer,load,store,fpload,fpstore,imul,idiv,branch,compare,delayed_compare,fpcompare,mtjmpr,fp,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg" (const_string "integer")) ;; Length (in bytes). @@ -40,45 +40,74 @@ ;; Processor type -- this attribute must exactly match the processor_type ;; enumeration in rs6000.h. -(define_attr "cpu" "rios1,rios2,mpccore,ppc403,ppc601,ppc602,ppc603,ppc604,ppc620" +(define_attr "cpu" "rios1,rios2,mpccore,ppc403,ppc601,ppc603,ppc604,ppc620" (const (symbol_ref "rs6000_cpu_attr"))) ; (define_function_unit NAME MULTIPLICITY SIMULTANEITY ; TEST READY-DELAY ISSUE-DELAY [CONFLICT-LIST]) -; Load/Store Unit -- POWER/2 and pure PowerPC only +; Load/Store Unit -- pure PowerPC only ; (POWER and 601 use Integer Unit) (define_function_unit "lsu" 1 0 (and (eq_attr "type" "load") - (eq_attr "cpu" "mpccore,ppc602,ppc603,ppc604,ppc620")) + (eq_attr "cpu" "mpccore,ppc603,ppc604,ppc620")) 2 1) (define_function_unit "lsu" 1 0 - (and (eq_attr "type" "fpload") - (eq_attr "cpu" "ppc604,ppc620")) - 3 1) + (and (eq_attr "type" "store,fpstore") + (eq_attr "cpu" "mpccore,ppc603,ppc604,ppc620")) + 1 1) (define_function_unit "lsu" 1 0 (and (eq_attr "type" "fpload") - (eq_attr "cpu" "mpccore,ppc602,ppc603")) + (eq_attr "cpu" "mpccore,ppc603")) 2 1) +(define_function_unit "lsu" 1 0 + (and (eq_attr "type" "fpload") + (eq_attr "cpu" "ppc604,ppc620")) + 3 1) + (define_function_unit "iu" 1 0 (and (eq_attr "type" "load") - (eq_attr "cpu" "rios1,ppc601,ppc403")) + (eq_attr "cpu" "rios1,ppc403,ppc601")) 2 1) (define_function_unit "iu" 1 0 - (and (eq_attr "type" "fpload") + (and (eq_attr "type" "store,fpstore") + (eq_attr "cpu" "rios1,ppc403,ppc601")) + 1 1) + +(define_function_unit "fpu" 1 0 + (and (eq_attr "type" "fpstore") (eq_attr "cpu" "rios1,ppc601")) - 2 0) + 0 1) -; Integer Unit (RIOS1, PPC601, PPC603) -; Trivial operations take one cycle which need not be listed here. (define_function_unit "iu" 1 0 - (and (eq_attr "type" "imul") + (and (eq_attr "type" "fpload") (eq_attr "cpu" "rios1")) - 3 3) + 2 1) + +(define_function_unit "iu" 1 0 + (and (eq_attr "type" "fpload") + (eq_attr "cpu" "ppc601")) + 3 1) + +(define_function_unit "iu2" 2 0 + (and (eq_attr "type" "load,fpload") + (eq_attr "cpu" "rios2")) + 2 1) + +(define_function_unit "iu2" 2 0 + (and (eq_attr "type" "store,fpstore") + (eq_attr "cpu" "rios2")) + 1 1) + +; Integer Unit (RIOS1, PPC601, PPC603) +(define_function_unit "iu" 1 0 + (and (eq_attr "type" "integer") + (eq_attr "cpu" "rios1,mpccore,ppc403,ppc601,ppc603")) + 1 1) (define_function_unit "iu" 1 0 (and (eq_attr "type" "imul") @@ -87,7 +116,7 @@ (define_function_unit "iu" 1 0 (and (eq_attr "type" "imul") - (eq_attr "cpu" "ppc601,ppc602,ppc603")) + (eq_attr "cpu" "rios1,ppc601,ppc603")) 5 5) (define_function_unit "iu" 1 0 @@ -97,17 +126,17 @@ (define_function_unit "iu" 1 0 (and (eq_attr "type" "idiv") - (eq_attr "cpu" "ppc601")) - 36 36) + (eq_attr "cpu" "ppc403")) + 33 33) (define_function_unit "iu" 1 0 (and (eq_attr "type" "idiv") - (eq_attr "cpu" "ppc403")) - 33 33) + (eq_attr "cpu" "ppc601")) + 36 36) (define_function_unit "iu" 1 0 (and (eq_attr "type" "idiv") - (eq_attr "cpu" "ppc602,ppc603")) + (eq_attr "cpu" "ppc603")) 37 36) ; RIOS2 has two integer units: a primary one which can perform all @@ -118,7 +147,7 @@ (define_function_unit "iu2" 2 0 (and (eq_attr "type" "integer") (eq_attr "cpu" "rios2")) - 1 0) + 1 1) (define_function_unit "iu2" 2 0 (and (eq_attr "type" "imul") @@ -135,7 +164,6 @@ (eq_attr "cpu" "rios2")) 2 2) - (define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (eq_attr "cpu" "rios2")) @@ -159,59 +187,50 @@ (define_function_unit "iu2" 2 0 (and (eq_attr "type" "integer") (eq_attr "cpu" "ppc604,ppc620")) - 1 1 - [(eq_attr "type" "imul,idiv")]) + 1 1) (define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "imul") (eq_attr "cpu" "ppc604,ppc620")) - 4 2 - [(eq_attr "type" "integer")]) + 4 2) (define_function_unit "imuldiv" 1 0 (and (eq_attr "type" "idiv") (eq_attr "cpu" "ppc604,ppc620")) - 20 19 - [(eq_attr "type" "integer")]) + 20 19) ; compare is done on integer unit, but feeds insns which -; execute on the branch unit. Ready-delay of the compare -; on the branch unit is large (3-5 cycles). On the iu/fpu -; it is 1. One drawback is that the compare will also be -; assigned to the bpu, but this inaccuracy is worth for being -; able to fill the compare-branch delay, with insns on iu/fpu. +; execute on the branch unit. (define_function_unit "iu" 1 0 (and (eq_attr "type" "compare") - (eq_attr "cpu" "rios1,mpccore,ppc601")) - 1 1) + (eq_attr "cpu" "rios1")) + 4 1) + +(define_function_unit "iu" 1 0 + (and (eq_attr "type" "delayed_compare") + (eq_attr "cpu" "rios1")) + 5 1) + +(define_function_unit "iu" 1 0 + (and (eq_attr "type" "compare,delayed_compare") + (eq_attr "cpu" "mpccore,ppc403,ppc601,ppc603,ppc604,ppc620")) + 3 1) (define_function_unit "iu2" 2 0 - (and (eq_attr "type" "compare") + (and (eq_attr "type" "compare,delayed_compare") (eq_attr "cpu" "rios2")) - 1 1) - -(define_function_unit "bpu" 1 0 - (and (eq_attr "type" "compare") - (eq_attr "cpu" "rios1,rios2,ppc403,mpccore,ppc601,ppc603,ppc604,ppc620")) - 4 1) + 3 1) -; different machines have different compare timings -; in ppc604, compare is done on the one of the two -; main integer units. (define_function_unit "iu2" 2 0 - (and (eq_attr "type" "compare") + (and (eq_attr "type" "compare,delayed_compare") (eq_attr "cpu" "ppc604,ppc620")) 1 1) -(define_function_unit "bpu" 1 0 - (eq_attr "type" "delayed_compare") - 5 0) - ; fp compare uses fp unit (define_function_unit "fpu" 1 0 (and (eq_attr "type" "fpcompare") (eq_attr "cpu" "rios1")) - 8 1) + 9 1) ; rios1 and rios2 have different fpcompare delays (define_function_unit "fpu2" 2 0 @@ -222,16 +241,16 @@ ; on ppc601 and ppc603, fpcompare takes also 2 cycles from ; the integer unit ; here we do not define delays, just occupy the unit. The dependencies -; will be signed by the fpcompare definition in the fpu. +; will be assigned by the fpcompare definition in the fpu. (define_function_unit "iu" 1 0 (and (eq_attr "type" "fpcompare") - (eq_attr "cpu" "ppc601,ppc602,ppc603")) + (eq_attr "cpu" "ppc601,ppc603")) 0 2) ; fp compare uses fp unit (define_function_unit "fpu" 1 0 (and (eq_attr "type" "fpcompare") - (eq_attr "cpu" "ppc601,ppc602,ppc603,ppc604,ppc620")) + (eq_attr "cpu" "ppc601,ppc603,ppc604,ppc620")) 5 1) (define_function_unit "fpu" 1 0 @@ -242,27 +261,27 @@ (define_function_unit "bpu" 1 0 (and (eq_attr "type" "mtjmpr") (eq_attr "cpu" "rios1,rios2")) - 5 0) + 5 1) (define_function_unit "bpu" 1 0 (and (eq_attr "type" "mtjmpr") - (eq_attr "cpu" "ppc403,mpccore,ppc601,ppc602,ppc603,ppc604,ppc620")) - 4 0) + (eq_attr "cpu" "mpccore,ppc403,ppc601,ppc603,ppc604,ppc620")) + 4 1) ; all jumps/branches are executing on the bpu, in 1 cycle, for all machines. (define_function_unit "bpu" 1 0 (eq_attr "type" "jmpreg") - 1 0) + 1 1) (define_function_unit "bpu" 1 0 (eq_attr "type" "branch") - 1 0) + 1 1) ; Floating Point Unit (define_function_unit "fpu" 1 0 (and (eq_attr "type" "fp,dmul") (eq_attr "cpu" "rios1")) - 2 0) + 2 1) (define_function_unit "fpu" 1 0 (and (eq_attr "type" "fp") @@ -272,11 +291,11 @@ (define_function_unit "fpu" 1 0 (and (eq_attr "type" "fp") (eq_attr "cpu" "ppc601")) - 4 0) + 4 1) (define_function_unit "fpu" 1 0 (and (eq_attr "type" "fp") - (eq_attr "cpu" "ppc602,ppc603,ppc604,ppc620")) + (eq_attr "cpu" "ppc603,ppc604,ppc620")) 3 1) (define_function_unit "fpu" 1 0 @@ -292,7 +311,7 @@ ; is this true? (define_function_unit "fpu" 1 0 (and (eq_attr "type" "dmul") - (eq_attr "cpu" "ppc602,ppc603")) + (eq_attr "cpu" "ppc603")) 4 2) (define_function_unit "fpu" 1 0 @@ -317,7 +336,7 @@ (define_function_unit "fpu" 1 0 (and (eq_attr "type" "sdiv") - (eq_attr "cpu" "ppc602,ppc603,ppc604,ppc620")) + (eq_attr "cpu" "ppc603,ppc604,ppc620")) 18 18) (define_function_unit "fpu" 1 0 @@ -332,7 +351,7 @@ (define_function_unit "fpu" 1 0 (and (eq_attr "type" "ddiv") - (eq_attr "cpu" "ppc602,ppc603")) + (eq_attr "cpu" "ppc603")) 33 33) (define_function_unit "fpu" 1 0 @@ -349,12 +368,12 @@ (define_function_unit "fpu2" 2 0 (and (eq_attr "type" "fp") (eq_attr "cpu" "rios2")) - 2 0) + 2 1) (define_function_unit "fpu2" 2 0 (and (eq_attr "type" "dmul") (eq_attr "cpu" "rios2")) - 2 0) + 2 1) (define_function_unit "fpu2" 2 0 (and (eq_attr "type" "sdiv,ddiv") @@ -848,7 +867,7 @@ {cax|add} %0,%1,%2 {cal %0,%2(%1)|addi %0,%1,%2} {ai|addic} %0,%1,%2 - {cau|addis} %0,%1,%u2") + {cau|addis} %0,%1,%v2") (define_insn "" [(set (match_operand:CC 0 "cc_reg_operand" "=x,x") @@ -888,14 +907,14 @@ (set (match_dup 0) (plus:SI (match_dup 0) (match_dup 4)))] " { - int low = INTVAL (operands[2]) & 0xffff; - int high = (unsigned) INTVAL (operands[2]) >> 16; + HOST_WIDE_INT low = INTVAL (operands[2]) & 0xffff; + HOST_WIDE_INT high = INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff); if (low & 0x8000) - high++, low |= 0xffff0000; + high += 0x10000, low |= ((HOST_WIDE_INT) -1) << 16; - operands[3] = gen_rtx (CONST_INT, VOIDmode, high << 16); - operands[4] = gen_rtx (CONST_INT, VOIDmode, low); + operands[3] = GEN_INT (high); + operands[4] = GEN_INT (low); }") (define_insn "one_cmplsi2" @@ -920,7 +939,7 @@ (set (match_operand:SI 0 "gpc_reg_operand" "=r") (not:SI (match_dup 1)))] "" - "nor. %0,%2,%1" + "nor. %0,%1,%1" [(set_attr "type" "compare")]) (define_insn "" @@ -1570,7 +1589,8 @@ (const_int 32)))) (clobber (match_scratch:SI 0 "=l"))] "! TARGET_POWER && ! TARGET_POWERPC" - "bla __mulh") + "bla __mulh" + [(set_attr "type" "imul")]) (define_insn "mull_call" [(set (reg:DI 3) @@ -1579,7 +1599,8 @@ (clobber (match_scratch:SI 0 "=l")) (clobber (reg:SI 0))] "! TARGET_POWER && ! TARGET_POWERPC" - "bla __mull") + "bla __mull" + [(set_attr "type" "imul")]) (define_insn "divss_call" [(set (reg:SI 3) @@ -1589,7 +1610,8 @@ (clobber (match_scratch:SI 0 "=l")) (clobber (reg:SI 0))] "! TARGET_POWER && ! TARGET_POWERPC" - "bla __divss") + "bla __divss" + [(set_attr "type" "idiv")]) (define_insn "divus_call" [(set (reg:SI 3) @@ -1601,14 +1623,16 @@ (clobber (match_scratch:CC 1 "=x")) (clobber (reg:CC 69))] "! TARGET_POWER && ! TARGET_POWERPC" - "bla __divus") + "bla __divus" + [(set_attr "type" "idiv")]) (define_insn "quoss_call" [(set (reg:SI 3) (div:SI (reg:SI 3) (reg:SI 4))) (clobber (match_scratch:SI 0 "=l"))] "! TARGET_POWER && ! TARGET_POWERPC" - "bla __quoss") + "bla __quoss" + [(set_attr "type" "idiv")]) (define_insn "quous_call" [(set (reg:SI 3) @@ -1618,7 +1642,8 @@ (clobber (match_scratch:CC 1 "=x")) (clobber (reg:CC 69))] "! TARGET_POWER && ! TARGET_POWERPC" - "bla __quous") + "bla __quous" + [(set_attr "type" "idiv")]) (define_insn "andsi3" [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") @@ -2068,7 +2093,7 @@ operands[4] = gen_rtx (CONST_INT, VOIDmode, 32 - start - size); operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1); - return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\"; + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; }") (define_insn "" @@ -2084,9 +2109,9 @@ int start = INTVAL (operands[2]) & 31; int size = INTVAL (operands[1]) & 31; - operands[4] = gen_rtx (CONST_INT, VOIDmode, (shift - start - size) & 31); + operands[4] = gen_rtx (CONST_INT, VOIDmode, shift - start - size); operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1); - return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\"; + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; }") (define_insn "" @@ -2102,9 +2127,9 @@ int start = INTVAL (operands[2]) & 31; int size = INTVAL (operands[1]) & 31; - operands[4] = gen_rtx (CONST_INT, VOIDmode, (32 - shift - start - size) & 31); + operands[4] = gen_rtx (CONST_INT, VOIDmode, 32 - shift - start - size); operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1); - return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\"; + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; }") (define_insn "" @@ -2120,9 +2145,9 @@ int start = INTVAL (operands[2]) & 31; int size = INTVAL (operands[1]) & 31; - operands[4] = gen_rtx (CONST_INT, VOIDmode, (32 - shift - start - size) & 31); + operands[4] = gen_rtx (CONST_INT, VOIDmode, 32 - shift - start - size); operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1); - return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\"; + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; }") (define_insn "" @@ -2142,9 +2167,24 @@ /* Align extract field with insert field */ operands[5] = gen_rtx (CONST_INT, VOIDmode, - (extract_start + extract_size - insert_start - insert_size) & 31); + extract_start + extract_size - insert_start - insert_size); operands[1] = gen_rtx (CONST_INT, VOIDmode, insert_start + insert_size - 1); - return \"{rlimi|rlwimi} %0,%3,%5,%h2,%h1\"; + return \"{rlimi|rlwimi} %0,%3,%h5,%h2,%h1\"; +}") + +(define_insn "" + [(set (zero_extract:DI (match_operand:DI 0 "gpc_reg_operand" "+r") + (match_operand:DI 1 "const_int_operand" "i") + (match_operand:DI 2 "const_int_operand" "i")) + (match_operand:DI 3 "gpc_reg_operand" "r"))] + "TARGET_POWERPC64" + "* +{ + int start = INTVAL (operands[2]) & 63; + int size = INTVAL (operands[1]) & 63; + + operands[2] = gen_rtx (CONST_INT, VOIDmode, 64 - start - size); + return \"rldimi %0,%3,%H2,%H1\"; }") (define_expand "extzv" @@ -2247,6 +2287,68 @@ }" [(set_attr "type" "delayed_compare")]) +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:DI 2 "const_int_operand" "i") + (match_operand:DI 3 "const_int_operand" "i")))] + "TARGET_POWERPC64" + "* +{ + int start = INTVAL (operands[3]) & 63; + int size = INTVAL (operands[2]) & 63; + + if (start + size >= 64) + operands[3] = const0_rtx; + else + operands[3] = gen_rtx (CONST_INT, VOIDmode, start + size); + operands[2] = gen_rtx (CONST_INT, VOIDmode, 64 - size); + return \"rldicl %0,%1,%3,%2\"; +}") + +(define_insn "" + [(set (match_operand:CC 0 "gpc_reg_operand" "=x") + (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:DI 2 "const_int_operand" "i") + (match_operand:DI 3 "const_int_operand" "i")) + (const_int 0))) + (clobber (match_scratch:DI 4 "=r"))] + "TARGET_POWERPC64" + "* +{ + int start = INTVAL (operands[3]) & 63; + int size = INTVAL (operands[2]) & 63; + + if (start + size >= 64) + operands[3] = const0_rtx; + else + operands[3] = gen_rtx (CONST_INT, VOIDmode, start + size); + operands[2] = gen_rtx (CONST_INT, VOIDmode, 64 - size); + return \"rldicl. %4,%1,%3,%2\"; +}") + +(define_insn "" + [(set (match_operand:CC 4 "gpc_reg_operand" "=x") + (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:DI 2 "const_int_operand" "i") + (match_operand:DI 3 "const_int_operand" "i")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r") + (zero_extract:DI (match_dup 1) (match_dup 2) (match_dup 3)))] + "TARGET_POWERPC64" + "* +{ + int start = INTVAL (operands[3]) & 63; + int size = INTVAL (operands[2]) & 63; + + if (start + size >= 64) + operands[3] = const0_rtx; + else + operands[3] = gen_rtx (CONST_INT, VOIDmode, start + size); + operands[2] = gen_rtx (CONST_INT, VOIDmode, 64 - size); + return \"rldicl. %0,%1,%3,%2\"; +}") + (define_insn "rotlsi3" [(set (match_operand:SI 0 "gpc_reg_operand" "=r") (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r") @@ -2510,68 +2612,77 @@ }") (define_insn "lshrsi3_power" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") - (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") - (match_operand:SI 2 "reg_or_cint_operand" "r,i"))) - (clobber (match_scratch:SI 3 "=q,X"))] + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,O,i"))) + (clobber (match_scratch:SI 3 "=q,X,X"))] "TARGET_POWER" "@ sre %0,%1,%2 + mr %0,%1 {s%A2i|s%A2wi} %0,%1,%h2") (define_insn "lshrsi3_no_power" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r") - (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r") - (match_operand:SI 2 "reg_or_cint_operand" "ri")))] + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "O,ri")))] "! TARGET_POWER" - "{sr|srw}%I2 %0,%1,%h2") + "@ + mr %0,%1 + {sr|srw}%I2 %0,%1,%h2") (define_insn "" - [(set (match_operand:CC 0 "cc_reg_operand" "=x,x") - (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") - (match_operand:SI 2 "reg_or_cint_operand" "r,i")) + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,O,i")) (const_int 0))) - (clobber (match_scratch:SI 3 "=r,r")) - (clobber (match_scratch:SI 4 "=q,X"))] + (clobber (match_scratch:SI 3 "=r,X,r")) + (clobber (match_scratch:SI 4 "=q,X,X"))] "TARGET_POWER" "@ sre. %3,%1,%2 + mr. %1,%1 {s%A2i.|s%A2wi.} %3,%1,%h2" [(set_attr "type" "delayed_compare")]) (define_insn "" - [(set (match_operand:CC 0 "cc_reg_operand" "=x") - (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r") - (match_operand:SI 2 "reg_or_cint_operand" "ri")) + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "O,ri")) (const_int 0))) - (clobber (match_scratch:SI 3 "=r"))] + (clobber (match_scratch:SI 3 "=X,r"))] "! TARGET_POWER" - "{sr|srw}%I2. %3,%1,%h2" + "@ + mr. %1,%1 + {sr|srw}%I2. %3,%1,%h2" [(set_attr "type" "delayed_compare")]) (define_insn "" - [(set (match_operand:CC 3 "cc_reg_operand" "=x,x") - (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") - (match_operand:SI 2 "reg_or_cint_operand" "r,i")) + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,O,i")) (const_int 0))) - (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r") (lshiftrt:SI (match_dup 1) (match_dup 2))) - (clobber (match_scratch:SI 4 "=q,X"))] + (clobber (match_scratch:SI 4 "=q,X,X"))] "TARGET_POWER" "@ sre. %0,%1,%2 + mr. %0,%1 {s%A2i.|s%A2wi.} %0,%1,%h2" [(set_attr "type" "delayed_compare")]) (define_insn "" - [(set (match_operand:CC 3 "cc_reg_operand" "=x") - (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r") - (match_operand:SI 2 "reg_or_cint_operand" "ri")) + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "O,ri")) (const_int 0))) - (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") (lshiftrt:SI (match_dup 1) (match_dup 2)))] "! TARGET_POWER" - "{sr|srw}%I2. %0,%1,%h2" + "@ + mr. %0,%1 + {sr|srw}%I2. %0,%1,%h2" [(set_attr "type" "delayed_compare")]) (define_insn "" @@ -3432,137 +3543,342 @@ [(set_attr "type" "fp")]) ;; Conversions to and from floating-point. + (define_expand "floatsidf2" - [(set (match_operand:DF 0 "gpc_reg_operand" "") - (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))] + [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "") + (float:DF (match_operand:SI 1 "gpc_reg_operand" ""))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_dup 5)) + (clobber (reg:DF 76))])] "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" " { - if (operands[0]) - { /* prevent unused warning messages */ - rtx high = force_reg (SImode, GEN_INT (0x43300000)); - rtx low = gen_reg_rtx (SImode); - rtx df = gen_reg_rtx (DFmode); - rtx adjust = force_reg (DFmode, rs6000_float_const (\"4503601774854144\", DFmode)); - - emit_insn (gen_xorsi3 (low, operands[1], GEN_INT (0x80000000))); - emit_insn (gen_move_to_float (df, low, high)); - emit_insn (gen_subdf3 (operands[0], df, adjust)); - DONE; - } + operands[2] = force_reg (SImode, GEN_INT (0x43300000)); + operands[3] = force_reg (DFmode, rs6000_float_const (\"4503601774854144\", DFmode)); + operands[4] = gen_reg_rtx (SImode); + operands[5] = gen_reg_rtx (Pmode); }") -(define_expand "floatunssidf2" +(define_insn "*floatsidf2_internal" + [(set (match_operand:DF 0 "gpc_reg_operand" "=&f") + (float:DF (match_operand:SI 1 "gpc_reg_operand" "r"))) + (use (match_operand:SI 2 "gpc_reg_operand" "r")) + (use (match_operand:DF 3 "gpc_reg_operand" "f")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=r")) + (clobber (match_operand:SI 5 "gpc_reg_operand" "=b")) + (clobber (reg:DF 76))] + "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" + "#" + [(set_attr "length" "24")]) + +(define_split [(set (match_operand:DF 0 "gpc_reg_operand" "") - (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))] + (float:DF (match_operand:SI 1 "gpc_reg_operand" ""))) + (use (match_operand:SI 2 "gpc_reg_operand" "")) + (use (match_operand:DF 3 "gpc_reg_operand" "")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "")) + (clobber (match_operand:SI 5 "gpc_reg_operand" "")) + (clobber (reg:DF 76))] "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" + [(set (match_dup 4) + (xor:SI (match_dup 1) + (match_dup 6))) + (set (match_dup 5) + (unspec [(const_int 0)] 11)) + (set (match_dup 7) + (unspec [(match_dup 4) + (match_dup 5)] 12)) ;; low word + (set (match_dup 7) + (unspec [(match_dup 2) + (match_dup 5) + (match_dup 7)] 13)) ;; high word + (set (match_dup 0) + (unspec [(match_dup 7) + (match_dup 5)] 14)) + (set (match_dup 0) + (minus:DF (match_dup 0) + (match_dup 3)))] " { - if (operands[0]) - { /* prevent unused warning messages */ - rtx high = force_reg (SImode, GEN_INT (0x43300000)); - rtx df = gen_reg_rtx (DFmode); - rtx adjust = force_reg (DFmode, rs6000_float_const (\"4503599627370496\", DFmode)); - - emit_insn (gen_move_to_float (df, operands[1], high)); - emit_insn (gen_subdf3 (operands[0], df, adjust)); - DONE; - } + operands[6] = GEN_INT (0x80000000); + operands[7] = gen_rtx (REG, DFmode, FPMEM_REGNUM); }") -(define_expand "move_to_float" - [(set (match_operand:DF 0 "gpc_reg_operand" "") - (unspec [(match_operand:SI 1 "gpc_reg_operand" "") - (match_operand:SI 2 "gpc_reg_operand" "") - (match_dup 3)] 2))] +(define_expand "floatunssidf2" + [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "") + (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" ""))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 4)) + (clobber (reg:DF 76))])] "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" " { - operands[3] = XEXP (rs6000_stack_temp (DFmode, 8, 1), 0); + operands[2] = force_reg (SImode, GEN_INT (0x43300000)); + operands[3] = force_reg (DFmode, rs6000_float_const (\"4503599627370496\", DFmode)); + operands[4] = gen_reg_rtx (Pmode); }") +(define_insn "*floatunssidf2_internal" + [(set (match_operand:DF 0 "gpc_reg_operand" "=&f") + (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r"))) + (use (match_operand:SI 2 "gpc_reg_operand" "r")) + (use (match_operand:DF 3 "gpc_reg_operand" "f")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=b")) + (clobber (reg:DF 76))] + "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" + "#" + [(set_attr "length" "20")]) + (define_split [(set (match_operand:DF 0 "gpc_reg_operand" "") - (unspec [(match_operand:SI 1 "gpc_reg_operand" "") - (match_operand:SI 2 "gpc_reg_operand" "") - (match_operand:SI 3 "offsettable_addr_operand" "")] 2))] - "reload_completed" - [(set (match_dup 4) (match_dup 1)) - (set (match_dup 5) (match_dup 2)) - (set (match_dup 0) (mem:DF (match_dup 3)))] - " + (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" ""))) + (use (match_operand:SI 2 "gpc_reg_operand" "")) + (use (match_operand:DF 3 "gpc_reg_operand" "")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=b")) + (clobber (reg:DF 76))] + "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" + [(set (match_dup 4) + (unspec [(const_int 0)] 11)) + (set (match_dup 5) + (unspec [(match_dup 1) + (match_dup 4)] 12)) ;; low word + (set (match_dup 5) + (unspec [(match_dup 2) + (match_dup 4) + (match_dup 5)] 13)) ;; high word + (set (match_dup 0) + (unspec [(match_dup 5) + (reg:SI 1)] 14)) + (set (match_dup 0) + (minus:DF (match_dup 0) + (match_dup 3)))] + "operands[5] = gen_rtx (REG, DFmode, FPMEM_REGNUM);") + +;; Load up scratch register with base address + offset if needed +(define_insn "*floatsidf2_loadaddr" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b") + (unspec [(const_int 0)] 11))] + "TARGET_HARD_FLOAT" + "* { - rtx word1 = gen_rtx (MEM, SImode, operands[3]); - rtx word2 = gen_rtx (MEM, SImode, plus_constant (operands[3], 4)); - - MEM_IN_STRUCT_P (word1) = 1; - MEM_IN_STRUCT_P (word2) = 1; - - if (WORDS_BIG_ENDIAN) + if (rs6000_fpmem_offset > 32760) { - operands[4] = word2; - operands[5] = word1; + rtx xop[3]; + + xop[0] = operands[0]; + xop[1] = (frame_pointer_needed) ? frame_pointer_rtx : stack_pointer_rtx; + xop[2] = GEN_INT ((rs6000_fpmem_offset >> 16) + ((rs6000_fpmem_offset & 0x8000) >> 15)); + output_asm_insn (\"{cau %0,%2(%1)|addis %0,%1,%2}\", xop); } + else if (rs6000_fpmem_offset < 0) + abort (); + + return \"\"; +}" + [(set_attr "length" "4")]) + +(define_insn "*floatsidf2_store1" + [(set (reg:DF 76) + (unspec [(match_operand:SI 0 "gpc_reg_operand" "r") + (match_operand:SI 1 "gpc_reg_operand" "r")] 12))] + "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" + "* +{ + rtx indx; + + if (rs6000_fpmem_offset > 32760) + indx = operands[1]; + else if (frame_pointer_needed) + indx = frame_pointer_rtx; else - { - operands[4] = word1; - operands[5] = word2; - } -}") + indx = stack_pointer_rtx; -(define_insn "" + operands[2] = gen_rtx (MEM, SImode, + gen_rtx (PLUS, Pmode, + indx, + GEN_INT ((((rs6000_fpmem_offset & 0xffff) ^ 0x8000) - 0x8000) + + ((WORDS_BIG_ENDIAN != 0) * 4)))); + + return \"{st|stw} %0,%2\"; +}" + [(set_attr "type" "store")]) + +(define_insn "*floatsidf2_store2" + [(set (reg:DF 76) + (unspec [(match_operand:SI 0 "gpc_reg_operand" "r") + (match_operand:SI 1 "gpc_reg_operand" "r") + (reg:DF 76)] 13))] + "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" + "* +{ + rtx indx; + + if (rs6000_fpmem_offset > 32760) + indx = operands[1]; + else if (frame_pointer_needed) + indx = frame_pointer_rtx; + else + indx = stack_pointer_rtx; + + operands[2] = gen_rtx (MEM, SImode, + gen_rtx (PLUS, Pmode, + indx, + GEN_INT ((((rs6000_fpmem_offset & 0xffff) ^ 0x8000) - 0x8000) + + ((WORDS_BIG_ENDIAN == 0) * 4)))); + + return \"{st|stw} %0,%2\"; +}" + [(set_attr "type" "store")]) + +(define_insn "*floatsidf2_load" [(set (match_operand:DF 0 "gpc_reg_operand" "=f") - (unspec [(match_operand:SI 1 "gpc_reg_operand" "r") - (match_operand:SI 2 "gpc_reg_operand" "r") - (match_operand:SI 3 "offsettable_addr_operand" "p")] 2))] + (unspec [(reg:DF 76) + (match_operand:SI 1 "gpc_reg_operand" "b")] 14))] "! TARGET_POWERPC64 && TARGET_HARD_FLOAT" - "#" - [(set_attr "length" "12")]) + "* +{ + rtx indx; + HOST_WIDE_INT offset = rs6000_fpmem_offset; + + if (rs6000_fpmem_offset > 32760) + { + indx = operands[1]; + offset = (((offset & 0xffff) ^ 0x8000) - 0x8000); + } + else if (frame_pointer_needed) + indx = frame_pointer_rtx; + else + indx = stack_pointer_rtx; + + operands[2] = gen_rtx (MEM, SImode, + gen_rtx (PLUS, Pmode, indx, GEN_INT (offset))); + + return \"lfd %0,%2\"; +}" + [(set_attr "type" "fpload")]) (define_expand "fix_truncdfsi2" - [(set (match_operand:SI 0 "gpc_reg_operand" "") - (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))] + [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "") + (fix:SI (match_operand:DF 1 "gpc_reg_operand" ""))) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4))])] "TARGET_HARD_FLOAT" " { - if (TARGET_POWER2 || TARGET_POWERPC) - { - int endian = (WORDS_BIG_ENDIAN == 0); - rtx stack_slot = rs6000_stack_temp (DImode, 8, 1); - rtx temp = gen_reg_rtx (DImode); - - emit_insn (gen_fpcvtsi (temp, operands[1])); - emit_move_insn (stack_slot, temp); - emit_move_insn (operands[0], - operand_subword (stack_slot, 1 - endian, 0, DImode)); - DONE; - } - else + if (!TARGET_POWER2 && !TARGET_POWERPC) { emit_insn (gen_trunc_call (operands[0], operands[1], gen_rtx (SYMBOL_REF, Pmode, RS6000_ITRUNC))); DONE; } + + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_reg_rtx (Pmode); + operands[4] = gen_rtx (REG, DImode, FPMEM_REGNUM); }") -(define_insn "fpcvtsi" +(define_insn "*fix_truncdfsi2_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))) + (clobber (match_operand:DI 2 "gpc_reg_operand" "=f")) + (clobber (match_operand:SI 3 "gpc_reg_operand" "=b")) + (clobber (reg:DI 76))] + "TARGET_HARD_FLOAT" + "#" + [(set_attr "length" "12")]) + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))) + (clobber (match_operand:DI 2 "gpc_reg_operand" "")) + (clobber (match_operand:SI 3 "gpc_reg_operand" "")) + (clobber (reg:DI 76))] + "TARGET_HARD_FLOAT" + [(set (match_dup 2) + (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))) + (set (match_dup 3) + (unspec [(const_int 0)] 11)) + (set (match_dup 4) + (unspec [(match_dup 2) + (match_dup 3)] 15)) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (unspec [(match_dup 4) + (match_dup 3)] 16))] + "operands[4] = gen_rtx (REG, DImode, FPMEM_REGNUM);") + +(define_insn "*fctiwz" [(set (match_operand:DI 0 "gpc_reg_operand" "=f") - (sign_extend:DI - (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))] + (sign_extend:DI (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))] "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT" "{fcirz|fctiwz} %0,%1" [(set_attr "type" "fp")]) -(define_expand "fixuns_truncdfsi2" - [(set (match_operand:SI 0 "gpc_reg_operand" "") - (unsigned_fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))] - "! TARGET_POWER2 && ! TARGET_POWERPC && TARGET_HARD_FLOAT" - " +(define_insn "*fix_truncdfsi2_store" + [(set (reg:DI 76) + (unspec [(match_operand:DI 0 "gpc_reg_operand" "f") + (match_operand:SI 1 "gpc_reg_operand" "b")] 15))] + "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT" + "* { - emit_insn (gen_trunc_call (operands[0], operands[1], - gen_rtx (SYMBOL_REF, Pmode, RS6000_UITRUNC))); - DONE; -}") + rtx indx; + + if (rs6000_fpmem_offset > 32760) + indx = operands[1]; + else if (frame_pointer_needed) + indx = frame_pointer_rtx; + else + indx = stack_pointer_rtx; + + operands[2] = gen_rtx (MEM, DFmode, + gen_rtx (PLUS, Pmode, + indx, + GEN_INT ((((rs6000_fpmem_offset & 0xffff) + ^ 0x8000) - 0x8000)))); + + return \"stfd %0,%w2\"; +}" + [(set_attr "type" "fpstore")]) + +(define_insn "*fix_truncdfsi2_load" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec [(reg:DI 76) + (match_operand:SI 1 "gpc_reg_operand" "b")] 16))] + "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT" + "* +{ + rtx indx; + + if (rs6000_fpmem_offset > 32760) + indx = operands[1]; + else if (frame_pointer_needed) + indx = frame_pointer_rtx; + else + indx = stack_pointer_rtx; + + operands[2] = gen_rtx (MEM, DFmode, + gen_rtx (PLUS, Pmode, + indx, + GEN_INT ((((rs6000_fpmem_offset & 0xffff) ^ 0x8000) - 0x8000) + + ((WORDS_BIG_ENDIAN) ? 4 : 0)))); + + return \"{l|lwz} %0,%2\"; +}" + [(set_attr "type" "load")]) + +(define_expand "fixuns_truncdfsi2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (unsigned_fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))] + "! TARGET_POWER2 && ! TARGET_POWERPC && TARGET_HARD_FLOAT" + " +{ + emit_insn (gen_trunc_call (operands[0], operands[1], + gen_rtx (SYMBOL_REF, Pmode, RS6000_UITRUNC))); + DONE; +}") (define_expand "trunc_call" [(parallel [(set (match_operand:SI 0 "" "") @@ -3904,7 +4220,7 @@ add %0,%1,%2 addi %0,%1,%2 addic %0,%1,%2 - addis %0,%1,%u2") + addis %0,%1,%v2") (define_insn "" [(set (match_operand:CC 0 "cc_reg_operand" "=x,x") @@ -3944,14 +4260,14 @@ (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))] " { - int low = INTVAL (operands[2]) & 0xffff; - int high = (unsigned) INTVAL (operands[2]) >> 16; + HOST_WIDE_INT low = INTVAL (operands[2]) & 0xffff; + HOST_WIDE_INT high = INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff); if (low & 0x8000) - high++, low |= 0xffff0000; + high+=0x10000, low |= ((HOST_WIDE_INT) -1) << 16; - operands[3] = gen_rtx (CONST_INT, VOIDmode, high << 16); - operands[4] = gen_rtx (CONST_INT, VOIDmode, low); + operands[3] = GEN_INT (high); + operands[4] = GEN_INT (low); }") (define_insn "one_cmpldi2" @@ -3976,7 +4292,7 @@ (set (match_operand:DI 0 "gpc_reg_operand" "=r") (not:DI (match_dup 1)))] "TARGET_POWERPC64" - "nor. %0,%2,%1" + "nor. %0,%1,%1" [(set_attr "type" "compare")]) (define_insn "" @@ -4219,7 +4535,7 @@ (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r") (match_operand:DI 2 "reg_or_cint_operand" "ri")))] "TARGET_POWERPC64" - "rld%I2cl %0,%1,%h2,0") + "rld%I2cl %0,%1,%H2,0") (define_insn "" [(set (match_operand:CC 0 "cc_reg_operand" "=x") @@ -4228,7 +4544,7 @@ (const_int 0))) (clobber (match_scratch:DI 3 "=r"))] "TARGET_POWERPC64" - "rld%I2cl. %3,%1,%h2,0" + "rld%I2cl. %3,%1,%H2,0" [(set_attr "type" "delayed_compare")]) (define_insn "" @@ -4239,7 +4555,7 @@ (set (match_operand:DI 0 "gpc_reg_operand" "=r") (rotate:DI (match_dup 1) (match_dup 2)))] "TARGET_POWERPC64" - "rld%I2cl. %0,%1,%h2,0" + "rld%I2cl. %0,%1,%H2,0" [(set_attr "type" "delayed_compare")]) (define_expand "ashldi3" @@ -4265,7 +4581,7 @@ (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r") (match_operand:SI 2 "reg_or_cint_operand" "ri")))] "TARGET_POWERPC64" - "sld%I2 %0,%1,%2" + "sld%I2 %0,%1,%H2" [(set_attr "length" "8")]) (define_insn "" @@ -4275,7 +4591,7 @@ (const_int 0))) (clobber (match_scratch:DI 3 "=r"))] "TARGET_POWERPC64" - "sld%I2. %3,%1,%2" + "sld%I2. %3,%1,%H2" [(set_attr "type" "delayed_compare")]) (define_insn "" @@ -4286,7 +4602,7 @@ (set (match_operand:DI 0 "gpc_reg_operand" "=r") (ashift:DI (match_dup 1) (match_dup 2)))] "TARGET_POWERPC64" - "sld%I2. %0,%1,%2" + "sld%I2. %0,%1,%H2" [(set_attr "type" "delayed_compare")]) (define_expand "lshrdi3" @@ -4312,7 +4628,7 @@ (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r") (match_operand:SI 2 "reg_or_cint_operand" "ri")))] "TARGET_POWERPC64" - "srd%I2 %0,%1,%2") + "srd%I2 %0,%1,%H2") (define_insn "" [(set (match_operand:CC 0 "cc_reg_operand" "=x") @@ -4321,7 +4637,7 @@ (const_int 0))) (clobber (match_scratch:DI 3 "=r"))] "TARGET_POWERPC64" - "srd%I2. %3,%1,%2" + "srd%I2. %3,%1,%H2" [(set_attr "type" "delayed_compare")]) (define_insn "" @@ -4332,7 +4648,7 @@ (set (match_operand:DI 0 "gpc_reg_operand" "=r") (lshiftrt:DI (match_dup 1) (match_dup 2)))] "TARGET_POWERPC64" - "srd%I2. %0,%1,%2" + "srd%I2. %0,%1,%H2" [(set_attr "type" "delayed_compare")]) (define_expand "ashrdi3" @@ -4358,7 +4674,7 @@ (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r") (match_operand:SI 2 "reg_or_cint_operand" "ri")))] "TARGET_POWERPC64" - "srad%I2 %0,%1,%2") + "srad%I2 %0,%1,%H2") (define_insn "" [(set (match_operand:CC 0 "cc_reg_operand" "=x") @@ -4367,7 +4683,7 @@ (const_int 0))) (clobber (match_scratch:DI 3 "=r"))] "TARGET_POWERPC64" - "srad%I2. %3,%1,%2" + "srad%I2. %3,%1,%H2" [(set_attr "type" "delayed_compare")]) (define_insn "" @@ -4378,7 +4694,7 @@ (set (match_operand:DI 0 "gpc_reg_operand" "=r") (ashiftrt:DI (match_dup 1) (match_dup 2)))] "TARGET_POWERPC64" - "srad%I2. %0,%1,%2" + "srad%I2. %0,%1,%H2" [(set_attr "type" "delayed_compare")]) (define_insn "anddi3" @@ -4503,7 +4819,7 @@ " { operands[3] = gen_rtx (CONST_INT, VOIDmode, - INTVAL (operands[2]) & 0xffff0000); + INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff)); operands[4] = gen_rtx (CONST_INT, VOIDmode, INTVAL (operands[2]) & 0xffff); }") @@ -4714,6 +5030,26 @@ "TARGET_ELF && !TARGET_64BIT" "{cal %0,%a2@l(%1)|addi %0,%1,%2@l}") +;; Set up a register with a value from the GOT table + +(define_expand "movsi_got" + [(set (match_operand:SI 0 "register_operand" "") + (unspec [(match_operand:SI 1 "got_operand" "") + (match_dup 2)] 8))] + "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && flag_pic == 1" + " +{ + operands[2] = rs6000_got_register (operands[1]); +}") + +(define_insn "*movsi_got_internal" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec [(match_operand:SI 1 "got_operand" "") + (match_operand:SI 2 "register_operand" "b")] 8))] + "(DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && flag_pic == 1" + "{l|lwz} %0,%a1@got(%2)" + [(set_attr "type" "load")]) + ;; For SI, we special-case integers that can't be loaded in one insn. We ;; do the load 16-bits at a time. We could do this by loading from memory, ;; and this is even supposed to be faster, but it is simpler not to get @@ -4733,7 +5069,7 @@ /* Use default pattern for address of ELF small data */ if (TARGET_ELF - && DEFAULT_ABI == ABI_V4 + && (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) && (GET_CODE (operands[1]) == SYMBOL_REF || GET_CODE (operands[1]) == CONST) && small_data_operand (operands[1], SImode)) { @@ -4741,7 +5077,15 @@ DONE; } + if ((DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && flag_pic == 1 && got_operand (operands[1], SImode)) + { + emit_insn (gen_movsi_got (operands[0], operands[1])); + DONE; + } + if (TARGET_ELF && TARGET_NO_TOC && !TARGET_64BIT + && !flag_pic && CONSTANT_P (operands[1]) && GET_CODE (operands[1]) != HIGH && GET_CODE (operands[1]) != CONST_INT) @@ -4854,18 +5198,18 @@ mr %0,%1 {l|lwz} %0,[toc]%1(2) {l|lwz} %0,[toc]%l1(2) - {cal|la} %0,%1 + {cal|la} %0,%a1 {l%U1%X1|lwz%U1%X1} %0,%1 {st%U0%X0|stw%U0%X0} %1,%0 {lil|li} %0,%1 - {liu|lis} %0,%u1 + {liu|lis} %0,%v1 # {cal|la} %0,%1(%*) mf%1 %0 mt%0 %1 mt%0 %1 cror 0,0,0" - [(set_attr "type" "*,load,load,*,load,*,*,*,*,*,*,*,mtjmpr,*") + [(set_attr "type" "*,load,load,*,load,store,*,*,*,*,*,*,mtjmpr,*") (set_attr "length" "4,4,4,4,4,4,4,4,8,4,4,4,4,4")]) ;; Split a load of a large constant into the appropriate two-insn @@ -4930,7 +5274,7 @@ mt%0 %1 mt%0 %1 cror 0,0,0" - [(set_attr "type" "*,load,*,*,*,*,mtjmpr,*")]) + [(set_attr "type" "*,load,store,*,*,*,mtjmpr,*")]) (define_expand "movqi" [(set (match_operand:QI 0 "general_operand" "") @@ -4965,7 +5309,7 @@ mt%0 %1 mt%0 %1 cror 0,0,0" - [(set_attr "type" "*,load,*,*,*,*,mtjmpr,*")]) + [(set_attr "type" "*,load,store,*,*,*,mtjmpr,*")]) ;; Here is how to move condition codes around. When we store CC data in ;; an integer register or memory, we store just the high-order 4 bits. @@ -4990,7 +5334,7 @@ mr %0,%1 {l%U1%X1|lwz%U1%X1} %0,%1 {st%U0%U1|stw%U0%U1} %1,%0" - [(set_attr "type" "*,*,*,compare,*,*,load,*") + [(set_attr "type" "*,*,*,compare,*,*,load,store") (set_attr "length" "*,*,12,*,8,*,*,*")]) ;; For floating-point, we normally deal with the floating-point registers @@ -5089,7 +5433,7 @@ } } - if (CONSTANT_P (operands[1])) + if (CONSTANT_P (operands[1]) && TARGET_HARD_FLOAT) { operands[1] = force_const_mem (SFmode, operands[1]); if (! memory_address_p (SFmode, XEXP (operands[1], 0)) @@ -5101,27 +5445,57 @@ (define_split [(set (match_operand:SF 0 "gpc_reg_operand" "") - (match_operand:SF 1 "easy_fp_constant" ""))] - "reload_completed && REGNO (operands[0]) <= 31" + (match_operand:SF 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], SFmode) <= 1 && REGNO (operands[0]) <= 31" [(set (match_dup 2) (match_dup 3))] " -{ operands[2] = operand_subword (operands[0], 0, 0, SFmode); - operands[3] = operand_subword (operands[1], 0, 0, SFmode); }") +{ + long l; + REAL_VALUE_TYPE rv; -(define_insn "" - [(set (match_operand:SF 0 "fp_reg_or_mem_operand" "=f,f,m") - (match_operand:SF 1 "input_operand" "f,m,f"))] + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + operands[2] = gen_rtx (SUBREG, SImode, operands[0], 0); + operands[3] = GEN_INT(l); +}") + +(define_split + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (match_operand:SF 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], SFmode) == 2 && REGNO (operands[0]) <= 31" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 4)))] + " +{ + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + operands[2] = gen_rtx (SUBREG, SImode, operands[0], 0); + operands[3] = GEN_INT(l & 0xffff0000); + operands[4] = GEN_INT(l & 0x0000ffff); +}") + +(define_insn "*movsf_hardfloat" + [(set (match_operand:SF 0 "fp_reg_or_mem_operand" "=f,f,m,!r,!r") + (match_operand:SF 1 "input_operand" "f,m,f,G,Fn"))] "(gpc_reg_operand (operands[0], SFmode) || gpc_reg_operand (operands[1], SFmode)) && TARGET_HARD_FLOAT" "@ fmr %0,%1 lfs%U1%X1 %0,%1 - stfs%U0%X0 %1,%0" - [(set_attr "type" "fp,fpload,*")]) + stfs%U0%X0 %1,%0 + # + #" + [(set_attr "type" "fp,fpload,fpstore,*,*") + (set_attr "length" "4,4,4,4,8")]) -(define_insn "" - [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,r,r,r") - (match_operand:SF 1 "input_operand" "r,m,r,I,J,R"))] +(define_insn "*movsf_softfloat" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,r") + (match_operand:SF 1 "input_operand" "r,m,r,I,J,R,G,Fn"))] "(gpc_reg_operand (operands[0], SFmode) || gpc_reg_operand (operands[1], SFmode)) && TARGET_SOFT_FLOAT" "@ @@ -5129,9 +5503,12 @@ {l%U1%X1|lwz%U1%X1} %0,%1 {st%U0%X0|stw%U0%X0} %1,%0 {lil|li} %0,%1 - {liu|lis} %0,%u1 - {cal|la} %0,%1(%*)" - [(set_attr "type" "*,load,*,*,*,*")]) + {liu|lis} %0,%v1 + {cal|la} %0,%1(%*) + # + #" + [(set_attr "type" "*,load,store,*,*,*,*,*") + (set_attr "length" "4,4,4,4,4,4,4,8")]) (define_expand "movdf" @@ -5143,6 +5520,23 @@ if (GET_CODE (operands[0]) != REG) operands[1] = force_reg (DFmode, operands[1]); + /* Stores between FPR and any non-FPR registers must go through a + temporary stack slot. */ + + if (TARGET_POWERPC64 + && GET_CODE (operands[0]) == REG && GET_CODE (operands[1]) == REG + && ((FP_REGNO_P (REGNO (operands[0])) + && ! FP_REGNO_P (REGNO (operands[1]))) + || (FP_REGNO_P (REGNO (operands[1])) + && ! FP_REGNO_P (REGNO (operands[0]))))) + { + rtx stack_slot = assign_stack_temp (DFmode, 8, 0); + + emit_move_insn (stack_slot, operands[1]); + emit_move_insn (operands[0], stack_slot); + DONE; + } + if (CONSTANT_P (operands[1]) && ! easy_fp_constant (operands[1], DFmode)) { operands[1] = force_const_mem (DFmode, operands[1]); @@ -5155,15 +5549,122 @@ (define_split [(set (match_operand:DF 0 "gpc_reg_operand" "") - (match_operand:DF 1 "easy_fp_constant" ""))] - "reload_completed && REGNO (operands[0]) <= 31" - [(set (match_dup 2) (match_dup 3)) - (set (match_dup 4) (match_dup 5))] + (match_operand:DF 1 "const_int_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DFmode) <= 1 && REGNO (operands[0]) <= 31" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 1))] " -{ operands[2] = operand_subword (operands[0], 0, 0, DFmode); - operands[3] = operand_subword (operands[1], 0, 0, DFmode); - operands[4] = operand_subword (operands[0], 1, 0, DFmode); - operands[5] = operand_subword (operands[1], 1, 0, DFmode); }") +{ + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx; +}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "const_int_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DFmode) >= 2 && REGNO (operands[0]) <= 31" + [(set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 6)))] + " +{ + HOST_WIDE_INT value = INTVAL (operands[1]); + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx; + operands[5] = GEN_INT (value & 0xffff0000); + operands[6] = GEN_INT (value & 0x0000ffff); +}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DFmode) <= 2 && REGNO (operands[0]) <= 31" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + +#ifdef HOST_WORDS_BIG_ENDIAN + operands[4] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + operands[5] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); +#else + operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + operands[5] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); +#endif +}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DFmode) == 3 && REGNO (operands[0]) <= 31" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6)))] + " +{ + HOST_WIDE_INT high; + HOST_WIDE_INT low; + rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + rtx low_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + +#ifdef HOST_WORDS_BIG_ENDIAN + high = CONST_DOUBLE_LOW (operands[1]); + low = CONST_DOUBLE_HIGH (operands[1]); +#else + high = CONST_DOUBLE_HIGH (operands[1]); + low = CONST_DOUBLE_LOW (operands[1]); +#endif + + if (((unsigned HOST_WIDE_INT) (low + 0x8000) < 0x10000) + || (low & 0xffff) == 0) + { + operands[2] = high_reg; + operands[3] = low_reg; + operands[4] = GEN_INT (high & 0xffff0000); + operands[5] = GEN_INT (low); + operands[6] = GEN_INT (high & 0x0000ffff); + } + else + { + operands[2] = low_reg; + operands[3] = high_reg; + operands[4] = GEN_INT (low & 0xffff0000); + operands[5] = GEN_INT (high); + operands[6] = GEN_INT (low & 0x0000ffff); + } +}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DFmode) >= 4 && REGNO (operands[0]) <= 31" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6))) + (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 7)))] + " +{ + HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]); + HOST_WIDE_INT low = CONST_DOUBLE_LOW (operands[1]); + + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = GEN_INT (high & 0xffff0000); + operands[5] = GEN_INT (low & 0xffff0000); + operands[6] = GEN_INT (high & 0x0000ffff); + operands[7] = GEN_INT (low & 0x0000ffff); +}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "easy_fp_constant" ""))] + "TARGET_64BIT && reload_completed && REGNO (operands[0]) <= 31" + [(set (subreg:DI (match_dup 0) 0) (subreg:DI (match_dup 1) 0))] + "") ;; Don't have reload use general registers to load a constant. First, ;; it might not work if the output operand has is the equivalent of @@ -5171,9 +5672,9 @@ ;; the constant into an FP register, since it will probably be used there. ;; The "??" is a kludge until we can figure out a more reasonable way ;; of handling these non-offsettable values. -(define_insn "" - [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,o,!r,f,f,m") - (match_operand:DF 1 "input_operand" "r,o,r,G,f,m,f"))] +(define_insn "*movdf_hardfloat32" + [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,o,!r,!r,!r,f,f,m") + (match_operand:DF 1 "input_operand" "r,o,r,G,H,F,f,m,f"))] "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" @@ -5202,21 +5703,23 @@ case 2: return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\"; case 3: - return \"#\"; case 4: - return \"fmr %0,%1\"; case 5: - return \"lfd%U1%X1 %0,%1\"; + return \"#\"; case 6: + return \"fmr %0,%1\"; + case 7: + return \"lfd%U1%X1 %0,%1\"; + case 8: return \"stfd%U0%X0 %1,%0\"; } }" - [(set_attr "type" "*,load,*,*,fp,fpload,*") - (set_attr "length" "8,8,8,8,*,*,*")]) + [(set_attr "type" "*,load,store,*,*,*,fp,fpload,fpstore") + (set_attr "length" "8,8,8,8,12,16,*,*,*")]) -(define_insn "" - [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r") - (match_operand:DF 1 "input_operand" "r,o,r,G"))] +(define_insn "*movdf_softfloat32" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r,r,r") + (match_operand:DF 1 "input_operand" "r,o,r,G,H,F"))] "! TARGET_POWERPC64 && TARGET_SOFT_FLOAT && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" @@ -5245,54 +5748,63 @@ case 2: return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\"; case 3: + case 4: + case 5: return \"#\"; } }" - [(set_attr "type" "*,load,*,*") - (set_attr "length" "8,8,8,8")]) + [(set_attr "type" "*,load,store,*,*,*") + (set_attr "length" "8,8,8,8,12,16")]) -(define_insn "" - [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,o,!r,f,f,m") - (match_operand:DF 1 "input_operand" "r,o,r,G,f,m,f"))] +(define_insn "*movdf_hardfloat64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,o,!r,!r,!r,f,f,m") + (match_operand:DF 1 "input_operand" "r,o,r,G,H,F,f,m,f"))] "TARGET_POWERPC64 && TARGET_HARD_FLOAT && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" "@ mr %0,%1 ld%U1%X1 %0,%1 - sd%U0%X0 %1,%0 + std%U0%X0 %1,%0 + # + # # fmr %0,%1 lfd%U1%X1 %0,%1 stfd%U0%X0 %1,%0" - [(set_attr "type" "*,load,*,*,fp,fpload,*")]) + [(set_attr "type" "*,load,store,*,*,*,fp,fpload,fpstore") + (set_attr "length" "4,4,4,8,12,16,4,4,4")]) -(define_insn "" - [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r") - (match_operand:DF 1 "input_operand" "r,o,r,G"))] +(define_insn "*movdf_softfloat64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r,r,r") + (match_operand:DF 1 "input_operand" "r,o,r,G,H,F"))] "TARGET_POWERPC64 && TARGET_SOFT_FLOAT && (register_operand (operands[0], DFmode) || register_operand (operands[1], DFmode))" "@ mr %0,%1 ld%U1%X1 %0,%1 - sd%U0%X0 %1,%0 + std%U0%X0 %1,%0 + # + # #" - [(set_attr "type" "*,load,*,*")]) + [(set_attr "type" "*,load,store,*,*,*") + (set_attr "length" "*,*,*,8,12,16")]) ;; Next come the multi-word integer load and store and the load and store ;; multiple insns. (define_expand "movdi" [(set (match_operand:DI 0 "general_operand" "") - (match_operand:DI 1 "general_operand" ""))] + (match_operand:DI 1 "any_operand" ""))] "" " { - if (GET_CODE (operands[0]) == MEM) + if (GET_CODE (operands[0]) != REG) operands[1] = force_reg (DImode, operands[1]); - if (GET_CODE (operands[1]) == CONST_DOUBLE - || GET_CODE (operands[1]) == CONST_INT) + if (TARGET_64BIT + && (GET_CODE (operands[1]) == CONST_DOUBLE + || GET_CODE (operands[1]) == CONST_INT)) { HOST_WIDE_INT low; HOST_WIDE_INT high; @@ -5303,17 +5815,35 @@ high = CONST_DOUBLE_HIGH (operands[1]); } else +#if HOST_BITS_PER_WIDE_INT == 32 { low = INTVAL (operands[1]); high = (low < 0) ? ~0 : 0; } +#else + { + low = INTVAL (operands[1]) & 0xffffffff; + high = (HOST_WIDE_INT) INTVAL (operands[1]) >> 32; + } +#endif - emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN), - GEN_INT (low)); - - emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], !WORDS_BIG_ENDIAN), - GEN_INT (high)); - DONE; + if (high) + { + emit_move_insn (operands[0], GEN_INT (high)); + emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32))); + if (low) + { + HOST_WIDE_INT low_low = low & 0xffff; + HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff); + if (low_high) + emit_insn (gen_iordi3 (operands[0], operands[0], + GEN_INT (low_high))); + if (low_low) + emit_insn (gen_iordi3 (operands[0], operands[0], + GEN_INT (low_low))); + } + DONE; + } } /* Stores between FPR and any non-FPR registers must go through a @@ -5333,11 +5863,12 @@ } }") -(define_insn "" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m") - (match_operand:DI 1 "input_operand" "r,m,r,f,m,f"))] - "! TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode) - || gpc_reg_operand (operands[1], DImode))" +(define_insn "*movdi_32" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m,r,r,r,r,r") + (match_operand:DI 1 "input_operand" "r,m,r,f,m,f,IJK,n,G,H,F"))] + "TARGET_32BIT + && (gpc_reg_operand (operands[0], DImode) + || gpc_reg_operand (operands[1], DImode))" "* { switch (which_alternative) @@ -5368,29 +5899,201 @@ return \"lfd%U1%X1 %0,%1\"; case 5: return \"stfd%U0%X0 %1,%0\"; + case 6: + case 7: + case 8: + case 9: + case 10: + return \"#\"; } }" - [(set_attr "type" "*,load,*,fp,fpload,*") - (set_attr "length" "8,8,8,*,*,*")]) + [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*") + (set_attr "length" "8,8,8,*,*,*,8,12,8,12,16")]) -(define_insn "" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,f,f,m,r,*h") - (match_operand:DI 1 "input_operand" "r,m,r,I,J,R,f,m,f,*h,r"))] - "TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode) - || gpc_reg_operand (operands[1], DImode))" +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 1" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 1))] + " +{ + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx; +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 2" + [(set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 6)))] + " +{ + HOST_WIDE_INT value = INTVAL (operands[1]); + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx; + operands[5] = GEN_INT (value & 0xffff0000); + operands[6] = GEN_INT (value & 0x0000ffff); +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 2" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + operands[5] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) == 3" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6)))] + " +{ + HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]); + HOST_WIDE_INT low = CONST_DOUBLE_LOW (operands[1]); + rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + rtx low_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + + if (((unsigned HOST_WIDE_INT) (low + 0x8000) < 0x10000) + || (low & 0xffff) == 0) + { + operands[2] = high_reg; + operands[3] = low_reg; + operands[4] = GEN_INT (high & 0xffff0000); + operands[5] = GEN_INT (low); + operands[6] = GEN_INT (high & 0x0000ffff); + } + else + { + operands[2] = low_reg; + operands[3] = high_reg; + operands[4] = GEN_INT (low & 0xffff0000); + operands[5] = GEN_INT (high); + operands[6] = GEN_INT (low & 0x0000ffff); + } +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 4" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5)) + (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6))) + (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 7)))] + " +{ + HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]); + HOST_WIDE_INT low = CONST_DOUBLE_LOW (operands[1]); + + operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0); + operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0); + operands[4] = GEN_INT (high & 0xffff0000); + operands[5] = GEN_INT (low & 0xffff0000); + operands[6] = GEN_INT (high & 0x0000ffff); + operands[7] = GEN_INT (low & 0x0000ffff); +}") + +(define_insn "*movdi_64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,f,f,m,r,*h,*h") + (match_operand:DI 1 "input_operand" "r,m,r,I,J,nF,R,f,m,f,*h,r,0"))] + "TARGET_64BIT + && (gpc_reg_operand (operands[0], DImode) + || gpc_reg_operand (operands[1], DImode))" "@ mr %0,%1 ld%U1%X1 %0,%1 - sd%U0%X0 %1,%0 + std%U0%X0 %1,%0 li %0,%1 - lis %0,%u1 + lis %0,%v1 + # {cal|la} %0,%1(%*) fmr %0,%1 lfd%U1%X1 %0,%1 stfd%U0%X0 %1,%0 mf%1 %0 - mt%0 %1" - [(set_attr "type" "*,load,*,*,*,*,fp,fpload,*,*,mtjmpr")]) + mt%0 %1 + cror 0,0,0" + [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,*,mtjmpr,*") + (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4")]) + +;; Split a load of a large constant into the appropriate five-instruction +;; sequence. The expansion in movdi tries to perform the minimum number of +;; steps, but here we have to handle anything in a constant number of insns. + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_64BIT && num_insns_constant (operands[1], DImode) > 1" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (ior:DI (match_dup 0) + (match_dup 3))) + (set (match_dup 0) + (ashift:DI (match_dup 0) + (const_int 32))) + (set (match_dup 0) + (ior:DI (match_dup 0) + (match_dup 4))) + (set (match_dup 0) + (ior:DI (match_dup 0) + (match_dup 5)))] + " +{ + HOST_WIDE_INT low; + HOST_WIDE_INT high; + + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + low = CONST_DOUBLE_LOW (operands[1]); + high = CONST_DOUBLE_HIGH (operands[1]); + } + else +#if HOST_BITS_PER_WIDE_INT == 32 + { + low = INTVAL (operands[1]); + high = (low < 0) ? ~0 : 0; + } +#else + { + low = INTVAL (operands[1]) & 0xffffffff; + high = (HOST_WIDE_INT) INTVAL (operands[1]) >> 32; + } +#endif + + if ((high + 0x8000) < 0x10000 + && ((low & 0xffff) == 0 || (low & (~ (HOST_WIDE_INT) 0xffff)) == 0)) + FAIL; + + operands[2] = GEN_INT (high & (~ (HOST_WIDE_INT) 0xffff)); + operands[3] = GEN_INT (high & 0xffff); + operands[4] = GEN_INT (low & (~ (HOST_WIDE_INT) 0xffff)); + operands[5] = GEN_INT (low & 0xffff); +}") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x") + (compare:CC (match_operand:DI 1 "gpc_reg_operand" "r") + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r") (match_dup 1))] + "TARGET_POWERPC64" + "mr. %0,%1" + [(set_attr "type" "compare")]) ;; TImode is similar, except that we usually want to compute the address into ;; a register and use lsi/stsi (the exception is during reload). MQ is also @@ -5474,7 +6177,7 @@ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\"; } }" - [(set_attr "type" "*,load,load,*,*") + [(set_attr "type" "store,store,*,load,load") (set_attr "length" "*,16,16,*,16")]) (define_insn "" @@ -5519,7 +6222,7 @@ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\"; } }" - [(set_attr "type" "load,*,*") + [(set_attr "type" "store,*,load") (set_attr "length" "16,16,16")]) (define_insn "" @@ -5553,7 +6256,7 @@ return \"std%U0 %1,%0\;std %L1,%L0\"; } }" - [(set_attr "type" "*,load,*") + [(set_attr "type" "*,load,store") (set_attr "length" "8,8,8")]) (define_expand "load_multiple" @@ -5648,8 +6351,8 @@ }" [(set_attr "type" "load") (set_attr "length" "32")]) - + (define_expand "store_multiple" [(match_par_dup 3 [(set (match_operand:SI 0 "" "") (match_operand:SI 1 "" "")) @@ -5698,7 +6401,8 @@ (match_operand:SI 2 "gpc_reg_operand" "r")) (clobber (match_scratch:SI 3 "=q"))])] "TARGET_STRING && TARGET_POWER" - "{stsi|stswi} %2,%P1,%O0") + "{stsi|stswi} %2,%P1,%O0" + [(set_attr "type" "store")]) (define_insn "" [(match_parallel 0 "store_multiple_operation" @@ -5706,7 +6410,8 @@ (match_operand:SI 2 "gpc_reg_operand" "r")) (clobber (match_scratch:SI 3 "X"))])] "TARGET_STRING && !TARGET_POWER" - "{stsi|stswi} %2,%1,%O0") + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store")]) ;; String/block move insn. @@ -5768,7 +6473,8 @@ && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12) && REGNO (operands[4]) == 5" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) (define_insn "" [(set (mem:BLK (match_operand:SI 0 "register_operand" "b")) @@ -5790,7 +6496,8 @@ && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12) && REGNO (operands[4]) == 5" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) ;; Move up to 24 bytes at a time. The fixed registers are needed because the ;; register allocator doesn't have a clue about allocating 6 word registers @@ -5827,7 +6534,8 @@ && (REGNO (operands[1]) < 7 || REGNO (operands[1]) > 12) && REGNO (operands[4]) == 7" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) (define_insn "" [(set (mem:BLK (match_operand:SI 0 "register_operand" "b")) @@ -5847,7 +6555,8 @@ && (REGNO (operands[1]) < 7 || REGNO (operands[1]) > 12) && REGNO (operands[4]) == 7" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) ;; Move up to 16 bytes at a time, using 4 fixed registers to avoid spill problems ;; with TImode @@ -5880,7 +6589,8 @@ && (REGNO (operands[1]) < 9 || REGNO (operands[1]) > 12) && REGNO (operands[4]) == 9" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) (define_insn "" [(set (mem:BLK (match_operand:SI 0 "register_operand" "b")) @@ -5898,7 +6608,8 @@ && (REGNO (operands[1]) < 9 || REGNO (operands[1]) > 12) && REGNO (operands[4]) == 9" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) ;; Move up to 8 bytes at a time. (define_expand "movstrsi_2reg" @@ -5921,7 +6632,8 @@ "TARGET_STRING && TARGET_POWER && !TARGET_64BIT && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) (define_insn "" [(set (mem:BLK (match_operand:SI 0 "register_operand" "b")) @@ -5933,7 +6645,8 @@ "TARGET_STRING && !TARGET_POWER && !TARGET_64BIT && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) ;; Move up to 4 bytes at a time. (define_expand "movstrsi_1reg" @@ -5956,7 +6669,8 @@ "TARGET_STRING && TARGET_POWER && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) (define_insn "" [(set (mem:BLK (match_operand:SI 0 "register_operand" "b")) @@ -5968,7 +6682,8 @@ "TARGET_STRING && !TARGET_POWER && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4" "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" - [(set_attr "length" "8")]) + [(set_attr "type" "load") + (set_attr "length" "8")]) ;; Define insns that do load or store with update. Some of these we can @@ -6012,7 +6727,8 @@ "TARGET_POWERPC64" "@ stdux %3,%0,%2 - stdu %3,%2(%0)") + stdu %3,%2(%0)" + [(set_attr "type" "store")]) (define_insn "" [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r") @@ -6035,7 +6751,8 @@ "" "@ {stux|stwux} %3,%0,%2 - {stu|stwu} %3,%2(%0)") + {stu|stwu} %3,%2(%0)" + [(set_attr "type" "store")]) (define_insn "" [(set (match_operand:HI 3 "gpc_reg_operand" "=r,r") @@ -6084,7 +6801,8 @@ "" "@ sthux %3,%0,%2 - sthu %3,%2(%0)") + sthu %3,%2(%0)" + [(set_attr "type" "store")]) (define_insn "" [(set (match_operand:QI 3 "gpc_reg_operand" "=r,r") @@ -6120,7 +6838,8 @@ "" "@ stbux %3,%0,%2 - stbu %3,%2(%0)") + stbu %3,%2(%0)" + [(set_attr "type" "store")]) (define_insn "" [(set (match_operand:SF 3 "gpc_reg_operand" "=f,f") @@ -6143,7 +6862,8 @@ "TARGET_HARD_FLOAT" "@ stfsux %3,%0,%2 - stfsu %3,%2(%0)") + stfsu %3,%2(%0)" + [(set_attr "type" "fpstore")]) (define_insn "" [(set (match_operand:DF 3 "gpc_reg_operand" "=f,f") @@ -6166,7 +6886,8 @@ "TARGET_HARD_FLOAT" "@ stfdux %3,%0,%2 - stfdu %3,%2(%0)") + stfdu %3,%2(%0)" + [(set_attr "type" "fpstore")]) ;; Peephole to convert two consecutive FP loads or stores into lfq/stfq. @@ -6210,27 +6931,50 @@ emit_move_insn (chain, stack_bot); + /* Under Windows NT, we need to add stack probes for large/variable allocations, + so do it via a call to the external function alloca, instead of doing it + inline. */ + if (DEFAULT_ABI == ABI_NT + && (GET_CODE (operands[0]) != CONST_INT || INTVAL (operands[0]) > 4096)) + { + rtx tmp = gen_reg_rtx (SImode); + emit_library_call_value (gen_rtx (SYMBOL_REF, Pmode, \"__allocate_stack\"), + tmp, 0, SImode, 1, operands[0], Pmode); + emit_insn (gen_set_sp (tmp)); + DONE; + } + if (GET_CODE (operands[0]) != CONST_INT || INTVAL (operands[0]) < -32767 || INTVAL (operands[0]) > 32768) { neg_op0 = gen_reg_rtx (Pmode); - if (TARGET_POWERPC64) - emit_insn (gen_negdi2 (neg_op0, operands[0])); - else + if (TARGET_32BIT) emit_insn (gen_negsi2 (neg_op0, operands[0])); + else + emit_insn (gen_negdi2 (neg_op0, operands[0])); } else neg_op0 = GEN_INT (- INTVAL (operands[0])); - if (TARGET_POWERPC64) - emit_insn (gen_movdi_update (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain)); - else + if (TARGET_32BIT) emit_insn (gen_movsi_update (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain)); + else + emit_insn (gen_movdi_update (stack_pointer_rtx, stack_pointer_rtx, neg_op0, chain)); DONE; }") +;; Marker to indicate that the stack pointer was changed under NT in +;; ways not known to the compiler + +(define_insn "set_sp" + [(set (reg:SI 1) + (unspec [(match_operand:SI 0 "register_operand" "r")] 7))] + "" + "" + [(set_attr "length" "0")]) + ;; These patterns say how to save and restore the stack pointer. We need not ;; save the stack pointer at function level since we are careful to ;; preserve the backchain. At block level, we have to restore the backchain @@ -6287,8 +7031,8 @@ emit_move_insn (gen_rtx (MEM, SImode, operands[0]), temp); DONE; }") - + ;; A function pointer under AIX is a pointer to a data area whose first word ;; contains the actual address of the function, whose second word contains a ;; pointer to its TOC, and whose third word contains a value to place in the @@ -6308,29 +7052,33 @@ (define_insn "call_indirect_aix" [(call (mem:SI (match_operand:SI 0 "register_operand" "b")) (match_operand 1 "const_int_operand" "n")) - (use (match_operand 2 "const_int_operand" "O")) + (use (match_operand 2 "const_int_operand" "n")) (use (match_operand 3 "offsettable_addr_operand" "p")) (use (match_operand 4 "register_operand" "r")) (clobber (match_operand 5 "register_operand" "=r")) (clobber (match_scratch:SI 6 "=&r")) (clobber (match_scratch:SI 7 "=l"))] - "DEFAULT_ABI == ABI_AIX" - "{st|stw} %4,%a3\;{l|lwz} %6,0(%0)\;{l|lwz} %4,4(%0);\;mt%7 %6\;{l|lwz} %5,8(%0)\;{brl|blrl}\;{l|lwz} %4,%a3" - [(set_attr "length" "28")]) + "DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)" + "{st|stw} %4,%a3\;{l|lwz} %6,0(%0)\;{l|lwz} %4,4(%0)\;mt%7 %6\;{l|lwz} %5,8(%0)\;{brl|blrl}\;{l|lwz} %4,%a3" + [(set_attr "type" "load") + (set_attr "length" "28")]) (define_insn "call_value_indirect_aix" [(set (match_operand 0 "register_operand" "fg") (call (mem:SI (match_operand:SI 1 "register_operand" "b")) (match_operand 2 "const_int_operand" "n"))) - (use (match_operand 3 "const_int_operand" "O")) + (use (match_operand 3 "const_int_operand" "n")) (use (match_operand 4 "offsettable_addr_operand" "p")) (use (match_operand 5 "register_operand" "r")) (clobber (match_operand 6 "register_operand" "=r")) (clobber (match_scratch:SI 7 "=&r")) (clobber (match_scratch:SI 8 "=l"))] - "DEFAULT_ABI == ABI_AIX" + "DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)" "{st|stw} %5,%a4\;{l|lwz} %7,0(%1)\;{l|lwz} %5,4(%1);\;mt%8 %7\;{l|lwz} %6,8(%1)\;{brl|blrl}\;{l|lwz} %5,%a4" - [(set_attr "length" "28")]) + [(set_attr "type" "load") + (set_attr "length" "28")]) ;; A function pointer undef NT is a pointer to a data area whose first word ;; contains the actual address of the function, whose second word contains a @@ -6349,27 +7097,31 @@ (define_insn "call_indirect_nt" [(call (mem:SI (match_operand:SI 0 "register_operand" "b")) (match_operand 1 "const_int_operand" "n")) - (use (match_operand 2 "const_int_operand" "O")) + (use (match_operand 2 "const_int_operand" "n")) (use (match_operand 3 "offsettable_addr_operand" "p")) (use (match_operand 4 "register_operand" "r")) (clobber (match_scratch:SI 5 "=&r")) (clobber (match_scratch:SI 6 "=l"))] - "DEFAULT_ABI == ABI_NT" + "DEFAULT_ABI == ABI_NT + && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)" "{st|stw} %4,%a3\;{l|lwz} %5,0(%0)\;{l|lwz} %4,4(%0)\;mt%6 %5\;{brl|blrl}\;{l|lwz} %4,%a3" - [(set_attr "length" "24")]) + [(set_attr "type" "load") + (set_attr "length" "24")]) (define_insn "call_value_indirect_nt" [(set (match_operand 0 "register_operand" "fg") (call (mem:SI (match_operand:SI 1 "register_operand" "b")) (match_operand 2 "const_int_operand" "n"))) - (use (match_operand 3 "const_int_operand" "O")) + (use (match_operand 3 "const_int_operand" "n")) (use (match_operand 4 "offsettable_addr_operand" "p")) (use (match_operand 5 "register_operand" "r")) (clobber (match_scratch:SI 6 "=&r")) (clobber (match_scratch:SI 7 "=l"))] - "DEFAULT_ABI == ABI_NT" + "DEFAULT_ABI == ABI_NT + && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)" "{st|stw} %5,%a4\;{l|lwz} %6,0(%1)\;{l|lwz} %5,4(%1)\;mt%7 %6\;{brl|blrl}\;{l|lwz} %5,%a4" - [(set_attr "length" "24")]) + [(set_attr "type" "load") + (set_attr "length" "24")]) ;; A function pointer under System V is just a normal pointer ;; operands[0] is the function pointer @@ -6381,18 +7133,19 @@ (match_operand 1 "const_int_operand" "n,n")) (use (match_operand 2 "const_int_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] - "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC" + "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS || DEFAULT_ABI == ABI_AIX_NODESC" "* { - if (INTVAL (operands[2]) > 0) - return \"creqv 6,6,6\;{brl|blrl}\"; + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); - else if (INTVAL (operands[2]) < 0) - return \"crxor 6,6,6\;{brl|blrl}\"; + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); return \"{brl|blrl}\"; }" - [(set_attr "length" "4,8")]) + [(set_attr "type" "jmpreg") + (set_attr "length" "4,8")]) (define_insn "call_value_indirect_sysv" [(set (match_operand 0 "register_operand" "=fg,fg") @@ -6400,18 +7153,19 @@ (match_operand 2 "const_int_operand" "n,n"))) (use (match_operand 3 "const_int_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] - "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC" + "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS || DEFAULT_ABI == ABI_AIX_NODESC" "* { - if (INTVAL (operands[3]) > 0) - return \"creqv 6,6,6\;{brl|blrl}\"; + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); - else if (INTVAL (operands[3]) < 0) - return \"crxor 6,6,6\;{brl|blrl}\"; + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); return \"{brl|blrl}\"; }" - [(set_attr "length" "4,8")]) + [(set_attr "type" "jmpreg") + (set_attr "length" "4,8")]) ;; Now the definitions for the call and call_value insns (define_expand "call" @@ -6429,15 +7183,19 @@ /* Convert NT DLL imports into an indirect call. */ if (GET_CODE (operands[0]) == SYMBOL_REF - && INTVAL (operands[2]) == (int)CALL_NT_DLLIMPORT) + && (INTVAL (operands[2]) & CALL_NT_DLLIMPORT) != 0) { operands[0] = rs6000_dll_import_ref (operands[0]); operands[2] = GEN_INT ((int)CALL_NORMAL); } - if (GET_CODE (operands[0]) != SYMBOL_REF) + if (GET_CODE (operands[0]) != SYMBOL_REF + || (INTVAL (operands[2]) & CALL_LONG) != 0) { - if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC) + if (INTVAL (operands[2]) & CALL_LONG) + operands[0] = rs6000_longcall_ref (operands[0]); + + if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS) emit_call_insn (gen_call_indirect_sysv (force_reg (Pmode, operands[0]), operands[1], operands[2])); else @@ -6456,7 +7214,6 @@ else if (DEFAULT_ABI == ABI_NT) { /* NT function pointers are really pointers to a two word area */ - rs6000_save_toc_p = 1; emit_call_insn (gen_call_indirect_nt (force_reg (Pmode, operands[0]), operands[1], operands[2], toc_addr, toc_reg)); @@ -6484,15 +7241,19 @@ /* Convert NT DLL imports into an indirect call. */ if (GET_CODE (operands[1]) == SYMBOL_REF - && INTVAL (operands[3]) == (int)CALL_NT_DLLIMPORT) + && (INTVAL (operands[3]) & CALL_NT_DLLIMPORT) != 0) { operands[1] = rs6000_dll_import_ref (operands[1]); operands[3] = GEN_INT ((int)CALL_NORMAL); } - if (GET_CODE (operands[1]) != SYMBOL_REF) + if (GET_CODE (operands[1]) != SYMBOL_REF + || (INTVAL (operands[3]) & CALL_LONG) != 0) { - if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC) + if (INTVAL (operands[2]) & CALL_LONG) + operands[1] = rs6000_longcall_ref (operands[1]); + + if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_SOLARIS) emit_call_insn (gen_call_value_indirect_sysv (operands[0], operands[1], operands[2], operands[3])); else @@ -6512,7 +7273,6 @@ else if (DEFAULT_ABI == ABI_NT) { /* NT function pointers are really pointers to a two word area */ - rs6000_save_toc_p = 1; emit_call_insn (gen_call_value_indirect_nt (operands[0], force_reg (Pmode, operands[1]), operands[2], operands[3], @@ -6536,18 +7296,19 @@ (match_operand 1 "" "g,g")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] - "" + "(INTVAL (operands[2]) & CALL_LONG) == 0" "* { - switch ((enum rs6000_call_cookie)INTVAL (operands[2])) - { - case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break; - case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break; - } + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); return \"bl %z0\"; }" - [(set_attr "length" "4,8")]) + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) ;; Call to function which may be in another module. Restore the TOC ;; pointer (r2) after the call unless this is System V. @@ -6561,44 +7322,48 @@ (match_operand 1 "" "fg,fg")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] - "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT" + "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT) + && (INTVAL (operands[2]) & CALL_LONG) == 0" "* { /* Indirect calls should go through call_indirect */ if (GET_CODE (operands[0]) == REG) abort (); - switch ((enum rs6000_call_cookie)INTVAL (operands[2])) - { - case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break; - case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break; - } + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); return (TARGET_WINDOWS_NT) ? \"bl %z0\;.znop %z0\" : \"bl %z0\;%.\"; }" - [(set_attr "length" "8,12")]) + [(set_attr "type" "branch") + (set_attr "length" "8,12")]) (define_insn "" [(call (mem:SI (match_operand:SI 0 "call_operand" "s,s")) (match_operand 1 "" "fg,fg")) (use (match_operand:SI 2 "immediate_operand" "O,n")) (clobber (match_scratch:SI 3 "=l,l"))] - "DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4" + "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && (INTVAL (operands[2]) & CALL_LONG) == 0" "* { /* Indirect calls should go through call_indirect */ if (GET_CODE (operands[0]) == REG) abort (); - switch ((enum rs6000_call_cookie)INTVAL (operands[2])) - { - case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break; - case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break; - } + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); - return \"bl %z0\"; + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (flag_pic == 1) ? \"bl %z0@plt\" : \"bl %z0\"; }" - [(set_attr "length" "4,8")]) + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) (define_insn "" [(set (match_operand 0 "" "=fg,fg") @@ -6606,18 +7371,19 @@ (match_operand 2 "" "g,g"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] - "" + "(INTVAL (operands[3]) & CALL_LONG) == 0" "* { - switch ((enum rs6000_call_cookie)INTVAL (operands[3])) - { - case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break; - case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break; - } + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); return \"bl %z1\"; }" - [(set_attr "length" "4,8")]) + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) (define_insn "" [(set (match_operand 0 "" "=fg,fg") @@ -6625,22 +7391,24 @@ (match_operand 2 "" "fg,fg"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] - "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT" + "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT) + && (INTVAL (operands[3]) & CALL_LONG) == 0" "* { /* This should be handled by call_value_indirect */ if (GET_CODE (operands[1]) == REG) abort (); - switch ((enum rs6000_call_cookie)INTVAL (operands[3])) - { - case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break; - case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break; - } + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); return (TARGET_WINDOWS_NT) ? \"bl %z1\;.znop %z1\" : \"bl %z1\;%.\"; }" - [(set_attr "length" "8,12")]) + [(set_attr "type" "branch") + (set_attr "length" "8,12")]) (define_insn "" [(set (match_operand 0 "" "=fg,fg") @@ -6648,26 +7416,26 @@ (match_operand 2 "" "fg,fg"))) (use (match_operand:SI 3 "immediate_operand" "O,n")) (clobber (match_scratch:SI 4 "=l,l"))] - "DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4" + "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS) + && (INTVAL (operands[3]) & CALL_LONG) == 0" "* { /* This should be handled by call_value_indirect */ if (GET_CODE (operands[1]) == REG) abort (); - switch ((enum rs6000_call_cookie)INTVAL (operands[3])) - { - case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break; - case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break; - } + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); - return \"bl %z1\"; -}" - [(set_attr "length" "4,8")]) + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + return (flag_pic == 1) ? \"bl %z1@plt\" : \"bl %z1\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) ;; Call subroutine returning any type. - (define_expand "untyped_call" [(parallel [(call (match_operand 0 "" "") (const_int 0)) @@ -6703,32 +7471,15 @@ "" "") -;; Synchronize instructions/data caches for V.4 trampolines -;; The extra memory_operand is to prevent the optimizer from -;; deleting insns with "no" effect. -(define_insn "icbi" - [(unspec [(match_operand 0 "memory_operand" "=m") - (match_operand 1 "register_operand" "b") - (match_operand 2 "register_operand" "r")] 3)] - "TARGET_POWERPC" - "icbi %1,%2") - -(define_insn "dcbst" - [(unspec [(match_operand 0 "memory_operand" "=m") - (match_operand 1 "register_operand" "b") - (match_operand 2 "register_operand" "r")] 4)] - "TARGET_POWERPC" - "dcbst %1,%2") - -(define_insn "sync" - [(unspec [(match_operand 0 "memory_operand" "=m")] 5)] - "" - "{dcs|sync}") +;; V.4 specific code to initialize the PIC register -(define_insn "isync" - [(unspec [(match_operand 0 "memory_operand" "=m")] 6)] - "" - "{ics|isync}") +(define_insn "init_v4_pic" + [(set (match_operand:SI 0 "register_operand" "=l") + (unspec [(const_int 0)] 7))] + "DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_SOLARIS" + "bl _GLOBAL_OFFSET_TABLE_@local-4" + [(set_attr "type" "branch") + (set_attr "length" "4")]) ;; Compare insns are next. Note that the RS/6000 has two types of compares, @@ -8327,7 +9078,8 @@ if (get_attr_length (insn) == 8) return \"%C1bc %t1,%j1,%l0\"; else - return \"%C1bc %T1,%j1,$+8\;b %l0\"; + return \"%C1bc %T1,%j1,%$+8\;b %l0\"; + }" [(set_attr "type" "branch")]) @@ -8341,7 +9093,8 @@ (pc)))] "direct_return ()" "{%C0bcr|%C0bclr} %t0,%j0" - [(set_attr "length" "8")]) + [(set_attr "type" "branch") + (set_attr "length" "8")]) (define_insn "" [(set (pc) @@ -8357,7 +9110,7 @@ if (get_attr_length (insn) == 8) return \"%C1bc %T1,%j1,%l0\"; else - return \"%C1bc %t1,%j1,$+8\;b %l0\"; + return \"%C1bc %t1,%j1,%$+8\;b %l0\"; }" [(set_attr "type" "branch")]) @@ -8371,7 +9124,8 @@ (return)))] "direct_return ()" "{%C0bcr|%C0bclr} %T0,%j0" - [(set_attr "length" "8")]) + [(set_attr "type" "branch") + (set_attr "length" "8")]) ;; Unconditional branch and return. @@ -8379,7 +9133,8 @@ [(set (pc) (label_ref (match_operand 0 "" "")))] "" - "b %l0") + "b %l0" + [(set_attr "type" "branch")]) (define_insn "return" [(return)] @@ -8405,6 +9160,19 @@ ;; Table jump for switch statements: (define_expand "tablejump" + [(use (match_operand 0 "" "")) + (use (label_ref (match_operand 1 "" "")))] + "" + " +{ + if (TARGET_32BIT) + emit_jump_insn (gen_tablejumpsi (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejumpdi (operands[0], operands[1])); + DONE; +}") + +(define_expand "tablejumpsi" [(set (match_dup 3) (plus:SI (match_operand:SI 0 "" "") (match_dup 2))) @@ -8417,6 +9185,19 @@ operands[3] = gen_reg_rtx (SImode); }") +(define_expand "tablejumpdi" + [(set (match_dup 3) + (plus:DI (match_operand:DI 0 "" "") + (match_dup 2))) + (parallel [(set (pc) (match_dup 3)) + (use (label_ref (match_operand 1 "" "")))])] + "" + " +{ operands[0] = force_reg (DImode, operands[0]); + operands[2] = force_reg (DImode, gen_rtx (LABEL_REF, VOIDmode, operands[1])); + operands[3] = gen_reg_rtx (DImode); +}") + (define_insn "" [(set (pc) (match_operand:SI 0 "register_operand" "c,l")) @@ -8483,7 +9264,7 @@ else if (get_attr_length (insn) == 8) return \"{bdn|bdnz} %l0\"; else - return \"bdz $+8\;b %l0\"; + return \"bdz %$+8\;b %l0\"; }" [(set_attr "type" "branch") (set_attr "length" "*,12,16")]) @@ -8507,7 +9288,7 @@ else if (get_attr_length (insn) == 8) return \"bdz %l0\"; else - return \"{bdn|bdnz} $+8\;b %l0\"; + return \"{bdn|bdnz} %$+8\;b %l0\"; }" [(set_attr "type" "branch") (set_attr "length" "*,12,16")]) @@ -8532,7 +9313,7 @@ else if (get_attr_length (insn) == 8) return \"{bdn|bdnz} %l0\"; else - return \"bdz $+8\;b %l0\"; + return \"bdz %$+8\;b %l0\"; }" [(set_attr "type" "branch") (set_attr "length" "*,12,16")]) @@ -8556,7 +9337,7 @@ else if (get_attr_length (insn) == 8) return \"bdz %l0\"; else - return \"{bdn|bdnz} $+8\;b %l0\"; + return \"{bdn|bdnz} %$+8\;b %l0\"; }" [(set_attr "type" "branch") (set_attr "length" "*,12,16")]) @@ -8580,7 +9361,7 @@ else if (get_attr_length (insn) == 8) return \"bdz %l0\"; else - return \"{bdn|bdnz} $+8\;b %l0\"; + return \"{bdn|bdnz} %$+8\;b %l0\"; }" [(set_attr "type" "branch") (set_attr "length" "*,12,16")]) @@ -8604,7 +9385,7 @@ else if (get_attr_length (insn) == 8) return \"{bdn|bdnz} %l0\"; else - return \"bdz $+8\;b %l0\"; + return \"bdz %$+8\;b %l0\"; }" [(set_attr "type" "branch") (set_attr "length" "*,12,16")])