;; Processor type -- this attribute must exactly match the processor_type
;; enumeration in rs6000.h.
-(define_attr "cpu" "rios1,rios2,ppc601,ppc603,ppc604,ppc620"
+(define_attr "cpu" "rios1,rios2,ppc403,ppc601,ppc603,ppc604,ppc620"
(const (symbol_ref "rs6000_cpu_attr")))
; (define_function_unit NAME MULTIPLICITY SIMULTANEITY
(define_function_unit "iu" 1 0
(and (eq_attr "type" "load")
- (eq_attr "cpu" "rios1,ppc601"))
+ (eq_attr "cpu" "rios1,ppc403,ppc601"))
2 0)
(define_function_unit "iu" 1 0
(define_function_unit "iu" 1 0
(and (eq_attr "type" "imul")
+ (eq_attr "cpu" "ppc403"))
+ 4 4)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "imul")
(eq_attr "cpu" "ppc601,ppc603"))
5 5)
(define_function_unit "iu" 1 0
(and (eq_attr "type" "idiv")
+ (eq_attr "cpu" "ppc403"))
+ 33 33)
+
+(define_function_unit "iu" 1 0
+ (and (eq_attr "type" "idiv")
(eq_attr "cpu" "ppc601"))
36 36)
(define_function_unit "bpu" 1 0
(and (eq_attr "type" "mtjmpr")
- (eq_attr "cpu" "ppc601,ppc603,ppc604,ppc620"))
+ (eq_attr "cpu" "ppc403,ppc601,ppc603,ppc604,ppc620"))
4 0)
; Floating Point Unit (RIOS1, PPC601, PPC603, PPC604).
(define_expand "uminsi3"
[(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
- (const_int -2147483648)))
+ (match_dup 5)))
(set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "")
- (const_int -2147483648)))
+ (match_dup 5)))
(set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4))
(const_int 0)
(minus:SI (match_dup 4) (match_dup 3))))
(minus:SI (match_dup 2) (match_dup 3)))]
"TARGET_POWER"
"
-{ operands[3] = gen_reg_rtx (SImode); operands[4] = gen_reg_rtx (SImode); }")
+{
+ operands[3] = gen_reg_rtx (SImode);
+ operands[4] = gen_reg_rtx (SImode);
+ operands[5] = GEN_INT (-2147483647 - 1);
+}")
(define_expand "umaxsi3"
[(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
- (const_int -2147483648)))
+ (match_dup 5)))
(set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "")
- (const_int -2147483648)))
+ (match_dup 5)))
(set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4))
(const_int 0)
(minus:SI (match_dup 4) (match_dup 3))))
(plus:SI (match_dup 3) (match_dup 1)))]
"TARGET_POWER"
"
-{ operands[3] = gen_reg_rtx (SImode); operands[4] = gen_reg_rtx (SImode); }")
+{
+ operands[3] = gen_reg_rtx (SImode);
+ operands[4] = gen_reg_rtx (SImode);
+ operands[5] = GEN_INT (-2147483647 - 1);
+}")
(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
;; We don't need abs with condition code because such comparisons should
;; never be done.
-(define_insn "abssi2"
+(define_expand "abssi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (abs:SI (match_operand:SI 1 "gpc_reg_operand" "")))]
+ ""
+ "
+{
+ if (!TARGET_POWER)
+ {
+ emit_insn (gen_abssi2_nopower (operands[0], operands[1]));
+ DONE;
+ }
+}")
+
+(define_insn "abssi2_power"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
"TARGET_POWER"
"abs %0,%1")
+(define_insn "abssi2_nopower"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0")))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER"
+ "*
+{
+ return (TARGET_POWERPC)
+ ? \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;subf %0,%2,%0\"
+ : \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;{sf|subfc} %0,%2,%0\";
+}"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0")))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER && reload_completed"
+ [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31)))
+ (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1)))
+ (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 0)))]
+ "")
+
(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r"))))]
"TARGET_POWER"
"nabs %0,%1")
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0"))))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER"
+ "*
+{
+ return (TARGET_POWERPC)
+ ? \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;subf %0,%0,%2\"
+ : \"{srai|srawi} %2,%1,31\;xor %0,%2,%1\;{sf|subfc} %0,%0,%2\";
+}"
+ [(set_attr "length" "12")])
+
+(define_split
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r")
+ (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0"))))
+ (clobber (match_scratch:SI 2 "=&r,&r"))]
+ "!TARGET_POWER && reload_completed"
+ [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31)))
+ (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1)))
+ (set (match_dup 0) (minus:SI (match_dup 0) (match_dup 2)))]
+ "")
+
(define_insn "negsi2"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(neg:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
[(set_attr "type" "compare")])
(define_insn "ffssi2"
- [(set (match_operand:SI 0 "register_operand" "=&r")
- (ffs:SI (match_operand:SI 1 "register_operand" "r")))]
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
+ (ffs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))]
""
"neg %0,%1\;and %0,%0,%1\;{cntlz|cntlzw} %0,%0\;{sfi|subfic} %0,%0,32"
[(set_attr "length" "16")])
;; AIX architecture-independent common-mode multiply (DImode),
;; divide/modulus, and quotient subroutine calls. Input operands in R3 and
-;; R4; results in R3 and somtimes R4; link register always clobbered by bla
+;; R4; results in R3 and sometimes R4; link register always clobbered by bla
;; instruction; R0 sometimes clobbered; also, MQ sometimes clobbered but
;; assumed unused if generating common-mode, so ignore.
(define_insn "mulh_call"
"maskir %0,%3,%2")
(define_insn ""
- [(set (match_operand:SI 0 "register_operand" "=r")
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))
(match_operand:SI 1 "gpc_reg_operand" "0"))
(and:SI (match_operand:SI 3 "gpc_reg_operand" "r")
(and:SI (match_operand:SI 3 "gpc_reg_operand" "r")
(match_dup 2)))
(const_int 0)))
- (set (match_operand:SI 0 "register_operand" "=r")
+ (set (match_operand:SI 0 "gpc_reg_operand" "=r")
(ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1))
(and:SI (match_dup 3) (match_dup 2))))]
"TARGET_POWER"
return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
}")
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (ashift:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")))]
+ ""
+ "*
+{
+ int shift = INTVAL (operands[4]) & 31;
+ int start = INTVAL (operands[2]) & 31;
+ int size = INTVAL (operands[1]) & 31;
+
+ operands[4] = gen_rtx (CONST_INT, VOIDmode, (shift - start - size) & 31);
+ operands[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (ashiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")))]
+ ""
+ "*
+{
+ int shift = INTVAL (operands[4]) & 31;
+ 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[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (lshiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")))]
+ ""
+ "*
+{
+ int shift = INTVAL (operands[4]) & 31;
+ 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[1] = gen_rtx (CONST_INT, VOIDmode, start + size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%4,%h2,%h1\";
+}")
+
+(define_insn ""
+ [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r")
+ (match_operand:SI 1 "const_int_operand" "i")
+ (match_operand:SI 2 "const_int_operand" "i"))
+ (zero_extract:SI (match_operand:SI 3 "gpc_reg_operand" "r")
+ (match_operand:SI 4 "const_int_operand" "i")
+ (match_operand:SI 5 "const_int_operand" "i")))]
+ "INTVAL (operands[4]) >= INTVAL (operands[1])"
+ "*
+{
+ int extract_start = INTVAL (operands[5]) & 31;
+ int extract_size = INTVAL (operands[4]) & 31;
+ int insert_start = INTVAL (operands[2]) & 31;
+ int insert_size = INTVAL (operands[1]) & 31;
+
+/* Align extract field with insert field */
+ operands[5] = gen_rtx (CONST_INT, VOIDmode,
+ (extract_start + extract_size - insert_start - insert_size) & 31);
+ operands[1] = gen_rtx (CONST_INT, VOIDmode, insert_start + insert_size - 1);
+ return \"{rlimi|rlwimi} %0,%3,%5,%h2,%h1\";
+}")
+
(define_insn "extzv"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand:SI 2 "const_int_operand" "i"))
(match_operand:SI 3 "mask_operand" "L")))]
"includes_lshift_p (operands[2], operands[3])"
- "{rlinm|rlwinm} %0,%h1,%h2,%m3,%M3")
+ "{rlinm|rlwinm} %0,%1,%h2,%m3,%M3")
(define_insn ""
[(set (match_operand:CC 0 "cc_reg_operand" "=x")
(const_int 0)))
(clobber (match_scratch:SI 4 "=r"))]
"includes_lshift_p (operands[2], operands[3])"
- "{rlinm.|rlwinm.} %4,%h1,%h2,%m3,%M3"
+ "{rlinm.|rlwinm.} %4,%1,%h2,%m3,%M3"
[(set_attr "type" "delayed_compare")])
(define_insn ""
(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(and:SI (ashift:SI (match_dup 1) (match_dup 2)) (match_dup 3)))]
"includes_lshift_p (operands[2], operands[3])"
- "{rlinm.|rlwinm.} %0,%h1,%h2,%m3,%M3"
+ "{rlinm.|rlwinm.} %0,%1,%h2,%m3,%M3"
[(set_attr "type" "delayed_compare")])
;; The AIX assembler mis-handles "sri x,x,0", so write that case as
(define_insn "extendsfdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(float_extend:DF (match_operand:SF 1 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"*
{
if (REGNO (operands[0]) == REGNO (operands[1]))
(define_insn "truncdfsf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"frsp %0,%1"
[(set_attr "type" "fp")])
(define_insn "negsf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(neg:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"fneg %0,%1"
[(set_attr "type" "fp")])
(define_insn "abssf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(abs:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"fabs %0,%1"
[(set_attr "type" "fp")])
(define_insn ""
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(neg:SF (abs:SF (match_operand:SF 1 "gpc_reg_operand" "f"))))]
- ""
+ "TARGET_HARD_FLOAT"
"fnabs %0,%1"
[(set_attr "type" "fp")])
[(set (match_operand:SF 0 "gpc_reg_operand" "")
(plus:SF (match_operand:SF 1 "gpc_reg_operand" "")
(match_operand:SF 2 "gpc_reg_operand" "")))]
- ""
+ "TARGET_HARD_FLOAT"
"")
(define_insn ""
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fadds %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fa|fadd} %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:SF 0 "gpc_reg_operand" "")
(minus:SF (match_operand:SF 1 "gpc_reg_operand" "")
(match_operand:SF 2 "gpc_reg_operand" "")))]
- ""
+ "TARGET_HARD_FLOAT"
"")
(define_insn ""
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(minus:SF (match_operand:SF 1 "gpc_reg_operand" "f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fsubs %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(minus:SF (match_operand:SF 1 "gpc_reg_operand" "f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fs|fsub} %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:SF 0 "gpc_reg_operand" "")
(mult:SF (match_operand:SF 1 "gpc_reg_operand" "")
(match_operand:SF 2 "gpc_reg_operand" "")))]
- ""
+ "TARGET_HARD_FLOAT"
"")
(define_insn ""
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fmuls %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fm|fmul} %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:SF 0 "gpc_reg_operand" "")
(div:SF (match_operand:SF 1 "gpc_reg_operand" "")
(match_operand:SF 2 "gpc_reg_operand" "")))]
- ""
+ "TARGET_HARD_FLOAT"
"")
(define_insn ""
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(div:SF (match_operand:SF 1 "gpc_reg_operand" "f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fdivs %0,%1,%2"
[(set_attr "type" "sdiv")])
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(div:SF (match_operand:SF 1 "gpc_reg_operand" "f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fd|fdiv} %0,%1,%2"
[(set_attr "type" "sdiv")])
(plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fmadds %0,%1,%2,%3"
[(set_attr "type" "fp")])
(plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f")))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fma|fmadd} %0,%1,%2,%3"
[(set_attr "type" "fp")])
(minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fmsubs %0,%1,%2,%3"
[(set_attr "type" "fp")])
(minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f")))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fms|fmsub} %0,%1,%2,%3"
[(set_attr "type" "fp")])
(neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f"))))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fnmadds %0,%1,%2,%3"
[(set_attr "type" "fp")])
(neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f"))))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fnma|fnmadd} %0,%1,%2,%3"
[(set_attr "type" "fp")])
(neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f"))))]
- "TARGET_POWERPC"
+ "TARGET_POWERPC && TARGET_HARD_FLOAT"
"fnmsubs %0,%1,%2,%3"
[(set_attr "type" "fp")])
(neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
(match_operand:SF 2 "gpc_reg_operand" "f"))
(match_operand:SF 3 "gpc_reg_operand" "f"))))]
- "! TARGET_POWERPC"
+ "! TARGET_POWERPC && TARGET_HARD_FLOAT"
"{fnms|fnmsub} %0,%1,%2,%3"
[(set_attr "type" "fp")])
(define_expand "sqrtsf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "")
(sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "")))]
- "TARGET_PPC_GPOPT || TARGET_POWER2"
+ "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT"
"")
(define_insn ""
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
- "TARGET_PPC_GPOPT"
+ "TARGET_PPC_GPOPT && TARGET_HARD_FLOAT"
"fsqrts %0,%1"
[(set_attr "type" "ssqrt")])
(define_insn ""
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))]
- "TARGET_POWER2"
+ "TARGET_POWER2 && TARGET_HARD_FLOAT"
"fsqrt %0,%1"
[(set_attr "type" "dsqrt")])
-;; For SMIN, SMAX, UMIN, and UMAX, we use DEFINE_EXPAND's that involve a fsel
-;; instruction and some auxiliary computations. Then we just have a single
-;; DEFINE_INSN for fsel and the define_splits to make them if made by
+;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a
+;; fsel instruction and some auxiliary computations. Then we just have a
+;; single DEFINE_INSN for fsel and the define_splits to make them if made by
;; combine.
(define_expand "maxsf3"
[(set (match_dup 3)
(const_int 0))
(match_dup 1)
(match_dup 2)))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"
{ operands[3] = gen_reg_rtx (SFmode); }")
(smax:SF (match_operand:SF 1 "gpc_reg_operand" "")
(match_operand:SF 2 "gpc_reg_operand" "")))
(clobber (match_operand:SF 3 "gpc_reg_operand" ""))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
[(set (match_dup 3)
(minus:SF (match_dup 1) (match_dup 2)))
(set (match_dup 0)
(const_int 0))
(match_dup 1)
(match_dup 2)))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"
{ operands[3] = gen_reg_rtx (SFmode); }")
(smin:SF (match_operand:SF 1 "gpc_reg_operand" "")
(match_operand:SF 2 "gpc_reg_operand" "")))
(clobber (match_operand:SF 3 "gpc_reg_operand" ""))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
[(set (match_dup 3)
(minus:SF (match_dup 2) (match_dup 1)))
(set (match_dup 0)
(match_dup 2)))]
"")
-(define_insn ""
+(define_expand "movsfcc"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (if_then_else:SF (match_operand 1 "comparison_operator" "")
+ (match_operand:SF 2 "gpc_reg_operand" "f")
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{
+ rtx temp, op0, op1;
+ enum rtx_code code = GET_CODE (operands[1]);
+ if (! rs6000_compare_fp_p)
+ FAIL;
+ switch (code)
+ {
+ case GE: case EQ: case NE:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ break;
+ case GT:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ case LE:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ break;
+ case LT:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ default:
+ FAIL;
+ }
+ if (GET_MODE (rs6000_compare_op0) == DFmode)
+ {
+ temp = gen_reg_rtx (DFmode);
+ emit_insn (gen_subdf3 (temp, op0, op1));
+ emit_insn (gen_fseldfsf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfsf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfsf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ else
+ {
+ temp = gen_reg_rtx (SFmode);
+ emit_insn (gen_subsf3 (temp, op0, op1));
+ emit_insn (gen_fselsfsf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfsf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfsf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ DONE;
+}")
+
+(define_insn "fselsfsf4"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
(const_int 0))
(match_operand:SF 2 "gpc_reg_operand" "f")
(match_operand:SF 3 "gpc_reg_operand" "f")))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn "fseldfsf4"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (if_then_else:SF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
+ (const_int 0))
+ (match_operand:SF 2 "gpc_reg_operand" "f")
+ (match_operand:SF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"fsel %0,%1,%2,%3"
[(set_attr "type" "fp")])
(define_insn "negdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(neg:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"fneg %0,%1"
[(set_attr "type" "fp")])
(define_insn "absdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(abs:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"fabs %0,%1"
[(set_attr "type" "fp")])
(define_insn ""
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(neg:DF (abs:DF (match_operand:DF 1 "gpc_reg_operand" "f"))))]
- ""
+ "TARGET_HARD_FLOAT"
"fnabs %0,%1"
[(set_attr "type" "fp")])
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(plus:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
(match_operand:DF 2 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"{fa|fadd} %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(minus:DF (match_operand:DF 1 "gpc_reg_operand" "f")
(match_operand:DF 2 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"{fs|fsub} %0,%1,%2"
[(set_attr "type" "fp")])
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
(match_operand:DF 2 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"{fm|fmul} %0,%1,%2"
[(set_attr "type" "dmul")])
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(div:DF (match_operand:DF 1 "gpc_reg_operand" "f")
(match_operand:DF 2 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"{fd|fdiv} %0,%1,%2"
[(set_attr "type" "ddiv")])
(plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
(match_operand:DF 2 "gpc_reg_operand" "f"))
(match_operand:DF 3 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"{fma|fmadd} %0,%1,%2,%3"
[(set_attr "type" "dmul")])
(minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
(match_operand:DF 2 "gpc_reg_operand" "f"))
(match_operand:DF 3 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"{fms|fmsub} %0,%1,%2,%3"
[(set_attr "type" "dmul")])
(neg:DF (plus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
(match_operand:DF 2 "gpc_reg_operand" "f"))
(match_operand:DF 3 "gpc_reg_operand" "f"))))]
- ""
+ "TARGET_HARD_FLOAT"
"{fnma|fnmadd} %0,%1,%2,%3"
[(set_attr "type" "dmul")])
(neg:DF (minus:DF (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%f")
(match_operand:DF 2 "gpc_reg_operand" "f"))
(match_operand:DF 3 "gpc_reg_operand" "f"))))]
- ""
+ "TARGET_HARD_FLOAT"
"{fnms|fnmsub} %0,%1,%2,%3"
[(set_attr "type" "dmul")])
(define_insn "sqrtdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "f")))]
- "TARGET_PPC_GPOPT || TARGET_POWER2"
+ "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT"
"fsqrt %0,%1"
[(set_attr "type" "dsqrt")])
-;; For SMIN, SMAX, UMIN, and UMAX, we use DEFINE_EXPAND's that involve a fsel
-;; instruction and some auxiliary computations. Then we just have a single
-;; DEFINE_INSN for fsel and the define_splits to make them if made by
+;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a
+;; fsel instruction and some auxiliary computations. Then we just have a
+;; single DEFINE_INSN for fsel and the define_splits to make them if made by
;; combine.
(define_expand "maxdf3"
(const_int 0))
(match_dup 1)
(match_dup 2)))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"
{ operands[3] = gen_reg_rtx (DFmode); }")
(smax:DF (match_operand:DF 1 "gpc_reg_operand" "")
(match_operand:DF 2 "gpc_reg_operand" "")))
(clobber (match_operand:DF 3 "gpc_reg_operand" ""))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
[(set (match_dup 3)
(minus:DF (match_dup 1) (match_dup 2)))
(set (match_dup 0)
(const_int 0))
(match_dup 1)
(match_dup 2)))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
"
{ operands[3] = gen_reg_rtx (DFmode); }")
(smin:DF (match_operand:DF 1 "gpc_reg_operand" "")
(match_operand:DF 2 "gpc_reg_operand" "")))
(clobber (match_operand:DF 3 "gpc_reg_operand" ""))]
- "TARGET_PPC_GFXOPT"
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
[(set (match_dup 3)
(minus:DF (match_dup 2) (match_dup 1)))
(set (match_dup 0)
(match_dup 2)))]
"")
-(define_insn ""
+(define_expand "movdfcc"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (if_then_else:DF (match_operand 1 "comparison_operator" "")
+ (match_operand:DF 2 "gpc_reg_operand" "f")
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "
+{
+ rtx temp, op0, op1;
+ enum rtx_code code = GET_CODE (operands[1]);
+ if (! rs6000_compare_fp_p)
+ FAIL;
+ switch (code)
+ {
+ case GE: case EQ: case NE:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ break;
+ case GT:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ case LE:
+ op0 = rs6000_compare_op1;
+ op1 = rs6000_compare_op0;
+ break;
+ case LT:
+ op0 = rs6000_compare_op0;
+ op1 = rs6000_compare_op1;
+ temp = operands[2]; operands[2] = operands[3]; operands[3] = temp;
+ break;
+ default:
+ FAIL;
+ }
+ if (GET_MODE (rs6000_compare_op0) == DFmode)
+ {
+ temp = gen_reg_rtx (DFmode);
+ emit_insn (gen_subdf3 (temp, op0, op1));
+ emit_insn (gen_fseldfdf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfdf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negdf2 (temp, temp));
+ emit_insn (gen_fseldfdf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ else
+ {
+ temp = gen_reg_rtx (SFmode);
+ emit_insn (gen_subsf3 (temp, op0, op1));
+ emit_insn (gen_fselsfdf4 (operands[0], temp, operands[2], operands[3]));
+ if (code == EQ)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfdf4 (operands[0], temp, operands[0], operands[3]));
+ }
+ if (code == NE)
+ {
+ emit_insn (gen_negsf2 (temp, temp));
+ emit_insn (gen_fselsfdf4 (operands[0], temp, operands[3], operands[0]));
+ }
+ }
+ DONE;
+}")
+
+(define_insn "fseldfdf4"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "f")
(const_int 0))
(match_operand:DF 2 "gpc_reg_operand" "f")
(match_operand:DF 3 "gpc_reg_operand" "f")))]
+ "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT"
+ "fsel %0,%1,%2,%3"
+ [(set_attr "type" "fp")])
+
+(define_insn "fselsfdf4"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=f")
+ (if_then_else:DF (ge (match_operand:SF 1 "gpc_reg_operand" "f")
+ (const_int 0))
+ (match_operand:DF 2 "gpc_reg_operand" "f")
+ (match_operand:DF 3 "gpc_reg_operand" "f")))]
"TARGET_PPC_GFXOPT"
"fsel %0,%1,%2,%3"
[(set_attr "type" "fp")])
(set (match_operand:DF 0 "gpc_reg_operand" "")
(minus:DF (subreg:DF (match_dup 2) 0)
(match_dup 5)))]
- "! TARGET_POWERPC64 && HOST_BITS_PER_INT == BITS_PER_WORD"
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"
{
operands[2] = gen_reg_rtx (DImode);
operands[3] = gen_rtx (CONST_INT, VOIDmode, 0x80000000);
- operands[4] = immed_double_const (0, 0x43300000, DImode);
- operands[5] = force_reg (DFmode, immed_double_const (0x43300000,
- 0x80000000, DFmode));
+ operands[4] = rs6000_immed_double_const (0, 0x43300000, DImode);
+ operands[5] = force_reg (DFmode, rs6000_immed_double_const (0x43300000,
+ 0x80000000,
+ DFmode));
}")
(define_expand "floatunssidf2"
(set (match_operand:DF 0 "gpc_reg_operand" "")
(minus:DF (subreg:DF (match_dup 2) 0)
(match_dup 4)))]
- "! TARGET_POWERPC64 && HOST_BITS_PER_INT == BITS_PER_WORD"
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"
{
operands[2] = gen_reg_rtx (DImode);
- operands[3] = immed_double_const (0, 0x43300000, DImode);
- operands[4] = force_reg (DFmode, immed_double_const (0x43300000, 0, DFmode));
+ operands[3] = rs6000_immed_double_const (0, 0x43300000, DImode);
+ operands[4] = force_reg (DFmode, rs6000_immed_double_const (0x43300000, 0, DFmode));
}")
;; For the above two cases, we always split.
(plus:DI (zero_extend:DI
(xor:SI (match_operand:SI 1 "gpc_reg_operand" "")
(match_operand:SI 2 "logical_operand" "")))
- (match_operand:DI 3 "immediate_operand" "")))]
- "reload_completed && HOST_BITS_PER_INT == BITS_PER_WORD
- && GET_CODE (operands[3]) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (operands[3]) == 0"
+ (match_operand:DI 3 "low_32_bit_operand" "")))]
+ "reload_completed"
[(set (match_dup 6) (xor:SI (match_dup 1) (match_dup 2)))
(set (match_dup 4) (match_dup 5))]
"
(plus:DI (zero_extend:DI
(xor:SI (match_operand:SI 1 "gpc_reg_operand" "%r")
(match_operand:SI 2 "logical_operand" "rKJ")))
- (match_operand:DI 3 "immediate_operand" "n")))]
- "HOST_BITS_PER_INT == BITS_PER_WORD
- && GET_CODE (operands[3]) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (operands[3]) == 0"
+ (match_operand:DI 3 "low_32_bit_operand" "n")))]
+ ""
"#"
[(set_attr "length" "8")])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "=")
(plus:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
- (match_operand:DI 2 "immediate_operand" "")))]
- "reload_completed && HOST_BITS_PER_INT == BITS_PER_WORD
- && GET_CODE (operands[2]) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (operands[2]) == 0"
+ (match_operand:DI 2 "low_32_bit_operand" "")))]
+ "reload_completed"
[(set (match_dup 3) (match_dup 4))
(set (match_dup 5) (match_dup 1))]
"
(define_insn ""
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(plus:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r"))
- (match_operand:DI 2 "immediate_operand" "n")))]
- "HOST_BITS_PER_INT == BITS_PER_WORD
- && GET_CODE (operands[2]) == CONST_DOUBLE
- && CONST_DOUBLE_LOW (operands[2]) == 0"
+ (match_operand:DI 2 "low_32_bit_operand" "n")))]
+ ""
"#"
[(set_attr "length" "8")])
(define_expand "fix_truncdfsi2"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
- ""
+ "TARGET_HARD_FLOAT"
"
{
if (TARGET_POWER2 || TARGET_POWERPC)
[(set (match_operand:DI 0 "gpc_reg_operand" "=f")
(sign_extend:DI
(fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
- "TARGET_POWER2 || TARGET_POWERPC"
+ "(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_POWER2 && ! TARGET_POWERPC && TARGET_HARD_FLOAT"
"
{
emit_insn (gen_trunc_call (operands[0], operands[1],
[(parallel [(set (match_operand:SI 0 "" "")
(fix:SI (match_operand:DF 1 "" "")))
(use (match_operand:SI 2 "" ""))])]
- ""
+ "TARGET_HARD_FLOAT"
"
{
rtx insns = gen_trunc_call_rtl (operands[0], operands[1], operands[2]);
(clobber (scratch:SI))])
(set (match_operand:SI 0 "gpc_reg_operand" "")
(reg:SI 3))]
- ""
+ "TARGET_HARD_FLOAT"
"
{
rs6000_trunc_used = 1;
(define_insn "floatdidf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
(float:DF (match_operand:DI 1 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC64"
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"fcfid %0,%1"
[(set_attr "type" "fp")])
(define_insn "fix_truncdfdi2"
[(set (match_operand:DI 0 "gpc_reg_operand" "=f")
(fix:DI (match_operand:DF 1 "gpc_reg_operand" "f")))]
- "TARGET_POWERPC64"
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT"
"fctidz %0,%1"
[(set_attr "type" "fp")])
\f
;; PowerPC64 DImode operations.
(define_insn "ffsdi2"
- [(set (match_operand:DI 0 "register_operand" "=&r")
- (ffs:DI (match_operand:DI 1 "register_operand" "r")))]
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
+ (ffs:DI (match_operand:DI 1 "gpc_reg_operand" "r")))]
"TARGET_POWERPC64"
"neg %0,%1\;and %0,%0,%1\;cntlzd %0,%0\;subfic %0,%0,64"
[(set_attr "length" "16")])
[(set_attr "type" "*,*,*,compare,*,*,load,*")
(set_attr "length" "*,*,12,*,8,*,*,*")])
\f
-;; For floating-point, we normally deal with the floating-point registers.
-;; The sole exception is that parameter passing can produce floating-point
-;; values in fixed-point registers. Unless the value is a simple constant
-;; or already in memory, we deal with this by allocating memory and copying
-;; the value explicitly via that memory location.
+;; For floating-point, we normally deal with the floating-point registers
+;; unless -msoft-float is used. The sole exception is that parameter passing
+;; can produce floating-point values in fixed-point registers. Unless the
+;; value is a simple constant or already in memory, we deal with this by
+;; allocating memory and copying the value explicitly via that memory location.
(define_expand "movsf"
[(set (match_operand:SF 0 "nonimmediate_operand" "")
(match_operand:SF 1 "any_operand" ""))]
&& REGNO (SUBREG_REG (operands[1])) < FIRST_PSEUDO_REGISTER)
operands[1] = alter_subreg (operands[1]);
- if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32)
+ if (TARGET_SOFT_FLOAT && GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (SFmode, operands[1]);
+
+ else if (TARGET_HARD_FLOAT)
{
- /* If this is a store to memory or another integer register do the
- move directly. Otherwise store to a temporary stack slot and
- load from there into a floating point register. */
-
- if (GET_CODE (operands[0]) == MEM
- || (GET_CODE (operands[0]) == REG
- && (REGNO (operands[0]) < 32
- || (reload_in_progress
- && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))))
- {
- emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
- operand_subword (operands[1], 0, 0, SFmode));
- DONE;
- }
- else
+ if (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32)
{
- rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
-
- emit_move_insn (stack_slot, operands[1]);
- emit_move_insn (operands[0], stack_slot);
- DONE;
+ /* If this is a store to memory or another integer register do the
+ move directly. Otherwise store to a temporary stack slot and
+ load from there into a floating point register. */
+
+ if (GET_CODE (operands[0]) == MEM
+ || (GET_CODE (operands[0]) == REG
+ && (REGNO (operands[0]) < 32
+ || (reload_in_progress
+ && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))))
+ {
+ emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
+ operand_subword (operands[1], 0, 0, SFmode));
+ DONE;
+ }
+ else
+ {
+ rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
+
+ emit_move_insn (stack_slot, operands[1]);
+ emit_move_insn (operands[0], stack_slot);
+ DONE;
+ }
}
- }
- if (GET_CODE (operands[0]) == MEM)
- {
- /* If operands[1] is a register, it may have double-precision data
- in it, so truncate it to single precision. We need not do
- this for POWERPC. */
- if (! TARGET_POWERPC && GET_CODE (operands[1]) == REG)
+ if (GET_CODE (operands[0]) == MEM)
{
- rtx newreg = reload_in_progress ? operands[1] : gen_reg_rtx (SFmode);
- emit_insn (gen_truncdfsf2 (newreg,
- gen_rtx (SUBREG, DFmode, operands[1], 0)));
- operands[1] = newreg;
+ /* If operands[1] is a register, it may have double-precision data
+ in it, so truncate it to single precision. We need not do
+ this for POWERPC. */
+ if (! TARGET_POWERPC && GET_CODE (operands[1]) == REG)
+ {
+ rtx newreg = reload_in_progress ? operands[1] : gen_reg_rtx (SFmode);
+ emit_insn (gen_truncdfsf2 (newreg,
+ gen_rtx (SUBREG, DFmode, operands[1], 0)));
+ operands[1] = newreg;
+ }
+
+ operands[1] = force_reg (SFmode, operands[1]);
}
- operands[1] = force_reg (SFmode, operands[1]);
- }
-
- if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) < 32)
- {
- if (GET_CODE (operands[1]) == MEM
+ if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) < 32)
+ {
+ if (GET_CODE (operands[1]) == MEM
#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && ! defined(REAL_IS_NOT_DOUBLE)
- || GET_CODE (operands[1]) == CONST_DOUBLE
+ || GET_CODE (operands[1]) == CONST_DOUBLE
#endif
- || (GET_CODE (operands[1]) == REG
- && (REGNO (operands[1]) < 32
- || (reload_in_progress
- && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))))
- {
- emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
- operand_subword (operands[1], 0, 0, SFmode));
- DONE;
- }
- else
- {
- rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
-
- emit_move_insn (stack_slot, operands[1]);
- emit_move_insn (operands[0], stack_slot);
- DONE;
+ || (GET_CODE (operands[1]) == REG
+ && (REGNO (operands[1]) < 32
+ || (reload_in_progress
+ && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))))
+ {
+ emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
+ operand_subword (operands[1], 0, 0, SFmode));
+ DONE;
+ }
+ else
+ {
+ rtx stack_slot = assign_stack_temp (SFmode, 4, 0);
+
+ emit_move_insn (stack_slot, operands[1]);
+ emit_move_insn (operands[0], stack_slot);
+ DONE;
+ }
}
}
(define_insn ""
[(set (match_operand:SF 0 "fp_reg_or_mem_operand" "=f,f,m")
(match_operand:SF 1 "input_operand" "f,m,f"))]
- "gpc_reg_operand (operands[0], SFmode)
- || gpc_reg_operand (operands[1], SFmode)"
+ "(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,*")])
+
+(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"))]
+ "(gpc_reg_operand (operands[0], SFmode)
+ || gpc_reg_operand (operands[1], SFmode)) && TARGET_SOFT_FLOAT"
+ "@
+ mr %0,%1
+ {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,*,*,*,*")])
+
\f
(define_expand "movdf"
[(set (match_operand:DF 0 "nonimmediate_operand" "")
(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"))]
- "! TARGET_POWERPC64 && (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode))"
+ "! TARGET_POWERPC64 && TARGET_HARD_FLOAT
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
"*
{
switch (which_alternative)
(set_attr "length" "8,8,8,8,*,*,*")])
(define_insn ""
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r")
+ (match_operand:DF 1 "input_operand" "r,o,r,G"))]
+ "! TARGET_POWERPC64 && TARGET_SOFT_FLOAT
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ /* We normally copy the low-numbered register first. However, if
+ the first register operand 0 is the same as the second register of
+ operand 1, we must copy in the opposite order. */
+ if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
+ return \"mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\";
+ case 1:
+ /* If the low-address word is used in the address, we must load it
+ last. Otherwise, load it first. Note that we cannot have
+ auto-increment in that case since the address register is known to be
+ dead. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands [1], 0))
+ return \"{l|lwz} %L0,%L1\;{l|lwz} %0,%1\";
+ else
+ return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
+ case 2:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
+ case 3:
+ return \"#\";
+ }
+}"
+ [(set_attr "type" "*,load,*,*")
+ (set_attr "length" "8,8,8,8")])
+
+(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"))]
- "TARGET_POWERPC64 && (register_operand (operands[0], DFmode)
- || register_operand (operands[1], DFmode))"
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT
+ && (register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DFmode))"
"@
mr %0,%1
ld%U1%X1 %0,%1
lfd%U1%X1 %0,%1
stfd%U0%X0 %1,%0"
[(set_attr "type" "*,load,*,*,fp,fpload,*")])
+
+(define_insn ""
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,o,r")
+ (match_operand:DF 1 "input_operand" "r,o,r,G"))]
+ "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
+ #"
+ [(set_attr "type" "*,load,*,*")])
\f
;; Next come the multi-word integer load and store and the load and store
;; multiple insns.
[(parallel [(set (match_operand:TI 0 "general_operand" "")
(match_operand:TI 1 "general_operand" ""))
(clobber (scratch:SI))])]
- "TARGET_POWER || TARGET_POWERPC64"
+ "TARGET_MULTIPLE || TARGET_POWERPC64"
"
{
if (GET_CODE (operands[0]) == MEM)
[(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
(match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
(clobber (match_scratch:SI 2 "=q,q#X,X,X,X"))]
- "TARGET_POWER && ! TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
- || gpc_reg_operand (operands[1], TImode))"
+ "TARGET_MULTIPLE && TARGET_POWER && ! TARGET_POWERPC64
+ && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
"*
{
switch (which_alternative)
{
+ default:
+ abort ();
+
case 0:
return \"{stsi|stswi} %1,%P0,16\";
(set_attr "length" "*,16,16,*,16")])
(define_insn ""
+ [(set (match_operand:TI 0 "reg_or_mem_operand" "=m,????r,????r")
+ (match_operand:TI 1 "reg_or_mem_operand" "r,r,m"))
+ (clobber (match_scratch:SI 2 "=X,X,X"))]
+ "TARGET_MULTIPLE && !TARGET_POWER && ! TARGET_POWERPC64
+ && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
+ "*
+{
+ switch (which_alternative)
+ {
+ default:
+ abort ();
+
+ case 0:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
+
+ case 1:
+ /* Normally copy registers with lowest numbered register copied first.
+ But copy in the other order if the first register of the output
+ is the second, third, or fourth register in the input. */
+ if (REGNO (operands[0]) >= REGNO (operands[1]) + 1
+ && REGNO (operands[0]) <= REGNO (operands[1]) + 3)
+ return \"mr %Z0,%Z1\;mr %Y0,%Y1\;mr %L0,%L1\;mr %0,%1\";
+ else
+ return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
+ case 2:
+ /* If the address register is the same as the register for the lowest-
+ addressed word, load it last. Similarly for the next two words.
+ Otherwise load lowest address to highest. */
+ if (refers_to_regno_p (REGNO (operands[0]), REGNO (operands[0]) + 1,
+ operands[1], 0))
+ return \"{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %0,%1\";
+ else if (refers_to_regno_p (REGNO (operands[0]) + 1,
+ REGNO (operands[0]) + 2, operands[1], 0))
+ return \"{l|lwz} %0,%1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\;{l|lwz} %L0,%L1\";
+ else if (refers_to_regno_p (REGNO (operands[0]) + 2,
+ REGNO (operands[0]) + 3, operands[1], 0))
+ return \"{l|lwz} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Z0,%Z1\;{l|lwz} %Y0,%Y1\";
+ else
+ 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 "length" "16,16,16")])
+
+(define_insn ""
[(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
(match_operand:TI 1 "input_operand" "r,m,r"))]
"TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode)
[(set (match_operand:SI 1 "indirect_operand" "=Q")
(match_operand:SI 2 "gpc_reg_operand" "r"))
(clobber (match_scratch:SI 3 "=q"))])]
- "TARGET_POWER"
+ "TARGET_MULTIPLE && TARGET_POWER"
+ "{stsi|stswi} %2,%P1,%O0")
+
+(define_insn ""
+ [(match_parallel 0 "store_multiple_operation"
+ [(set (match_operand:SI 1 "indirect_operand" "=Q")
+ (match_operand:SI 2 "gpc_reg_operand" "r"))
+ (clobber (match_scratch:SI 3 "X"))])]
+ "TARGET_MULTIPLE && !TARGET_POWER"
"{stsi|stswi} %2,%P1,%O0")
\f
;; Define insns that do load or store with update. Some of these we can
(match_operand:SI 2 "reg_or_short_operand" "r,I"))))
(set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
(plus:SI (match_dup 1) (match_dup 2)))]
- ""
+ "TARGET_HARD_FLOAT"
"@
lfsux %3,%0,%2
lfsu %3,%2(%0)"
(match_operand:SF 3 "gpc_reg_operand" "f,f"))
(set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
(plus:SI (match_dup 1) (match_dup 2)))]
- ""
+ "TARGET_HARD_FLOAT"
"@
stfsux %3,%0,%2
stfsu %3,%2(%0)")
(match_operand:SI 2 "reg_or_short_operand" "r,I"))))
(set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
(plus:SI (match_dup 1) (match_dup 2)))]
- ""
+ "TARGET_HARD_FLOAT"
"@
lfdux %3,%0,%2
lfdu %3,%2(%0)"
(match_operand:DF 3 "gpc_reg_operand" "f,f"))
(set (match_operand:SI 0 "gpc_reg_operand" "=b,b")
(plus:SI (match_dup 1) (match_dup 2)))]
- ""
+ "TARGET_HARD_FLOAT"
"@
stfdux %3,%0,%2
stfdu %3,%2(%0)")
(set (match_operand:DF 2 "gpc_reg_operand" "=f")
(match_operand:DF 3 "memory_operand" ""))]
"TARGET_POWER2
+ && TARGET_HARD_FLOAT
&& registers_ok_for_quad_peep (operands[0], operands[2])
&& ! MEM_VOLATILE_P (operands[1]) && ! MEM_VOLATILE_P (operands[3])
&& addrs_ok_for_quad_peep (XEXP (operands[1], 0), XEXP (operands[3], 0))"
(set (match_operand:DF 2 "memory_operand" "")
(match_operand:DF 3 "gpc_reg_operand" "f"))]
"TARGET_POWER2
+ && TARGET_HARD_FLOAT
&& registers_ok_for_quad_peep (operands[1], operands[3])
&& ! MEM_VOLATILE_P (operands[0]) && ! MEM_VOLATILE_P (operands[2])
&& addrs_ok_for_quad_peep (XEXP (operands[0], 0), XEXP (operands[2], 0))"
""
"*
{
- if (GET_CODE (operands[0]) == REG)
- {
#ifndef USING_SVR4_H
- return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
-#else
- return \"{brl|blrl}\";
-#endif
- }
+ if (GET_CODE (operands[0]) == REG)
+ return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
return \"bl %z0\;%.\";
+
+#else
+ if (GET_CODE (operands[0]) == REG)
+ return \"{brl|blrl}\";
+
+ return \"bl %z0\";
+#endif
}"
[(set_attr "length" "8")])
""
"*
{
- if (GET_CODE (operands[1]) == REG)
- {
#ifndef USING_SVR4_H
- return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
-#else
- return \"{brl|blrl}\";
-#endif
- }
+ if (GET_CODE (operands[1]) == REG)
+ return \"{brl|blrl}\;{l|lwz} 2,20(1)\";
return \"bl %z1\;%.\";
+
+#else
+ if (GET_CODE (operands[1]) == REG)
+ return \"{brl|blrl}\";
+
+ return \"bl %z1\";
+#endif
}"
[(set_attr "length" "8")])
(define_expand "cmpsf"
[(set (cc0) (compare (match_operand:SF 0 "gpc_reg_operand" "")
(match_operand:SF 1 "gpc_reg_operand" "")))]
- ""
+ "TARGET_HARD_FLOAT"
"
{
rs6000_compare_op0 = operands[0];
(define_expand "cmpdf"
[(set (cc0) (compare (match_operand:DF 0 "gpc_reg_operand" "")
(match_operand:DF 1 "gpc_reg_operand" "")))]
- ""
+ "TARGET_HARD_FLOAT"
"
{
rs6000_compare_op0 = operands[0];
[(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
(compare:CCFP (match_operand:SF 1 "gpc_reg_operand" "f")
(match_operand:SF 2 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"fcmpu %0,%1,%2"
[(set_attr "type" "fpcompare")])
[(set (match_operand:CCFP 0 "cc_reg_operand" "=y")
(compare:CCFP (match_operand:DF 1 "gpc_reg_operand" "f")
(match_operand:DF 2 "gpc_reg_operand" "f")))]
- ""
+ "TARGET_HARD_FLOAT"
"fcmpu %0,%1,%2"
[(set_attr "type" "fpcompare")])
\f
{sfi|subfic} %0,%1,%2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0"
[(set_attr "length" "12,8,12,12,12")])
+;; Simplify (ne X (const_int 0)) on the PowerPC. No need to on the Power,
+;; since it nabs/sr is just as fast.
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (lshiftrt:SI (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))
+ (const_int 31)))
+ (clobber (match_scratch:SI 2 "=&r"))]
+ "!TARGET_POWER"
+ "{ai|addic} %2,%1,-1\;{sfe|subfe} %0,%2,%1"
+ [(set_attr "length" "8")])
+
;; This is what (plus (ne X (const_int 0)) Y) looks like.
(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")