;; 0 and remainder to operand 3.
;; ??? At some point, see what, if anything, we can do about if (x % y == 0).
-(define_insn "divmodsi4"
+(define_expand "divmodsi4"
+ [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (div:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" "")))
+ (set (match_operand:SI 3 "gpc_reg_operand" "")
+ (mod:SI (match_dup 1) (match_dup 2)))])]
+ "TARGET_POWER || (! TARGET_POWER && ! TARGET_POWERPC)"
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+ emit_insn (gen_divss_call ());
+ emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+ emit_move_insn (operands[3], gen_rtx (REG, SImode, 4));
+ DONE;
+ }
+}")
+(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(div:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand:SI 2 "gpc_reg_operand" "r")))
"divw %0, %1, %2"
[(set_attr "type" "idiv")])
-(define_insn "udivsi3"
+(define_expand "udivsi3"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "")
+ (match_operand:SI 2 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC || (! TARGET_POWER && ! TARGET_POWERPC)"
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+ emit_insn (gen_quous_call ());
+ emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+ DONE;
+ }
+}")
+(define_insn ""
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(udiv:SI (match_operand:SI 1 "gpc_reg_operand" "r")
(match_operand:SI 2 "gpc_reg_operand" "r")))]
;; For powers of two we can do srai/aze for divide and then adjust for
;; modulus. If it isn't a power of two, FAIL on POWER so divmodsi4 will be
-;; used; for PowerPC, force operands into register and do a normal divide.
+;; used; for PowerPC, force operands into register and do a normal divide;
+;; for AIX common-mode, use quoss call on register operands.
(define_expand "divsi3"
[(set (match_operand:SI 0 "gpc_reg_operand" "")
(div:SI (match_operand:SI 1 "gpc_reg_operand" "")
if (GET_CODE (operands[2]) == CONST_INT
&& exact_log2 (INTVAL (operands[2])) >= 0)
;
- else if (! TARGET_POWERPC)
+ else if (TARGET_POWER && ! TARGET_POWERPC)
FAIL;
else
operands[2] = force_reg (SImode, operands[2]);
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+ emit_insn (gen_quoss_call ());
+ emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+ DONE;
+ }
}")
(define_expand "modsi3"
emit_insn (gen_ashlsi3 (temp2, temp1, GEN_INT (i)));
emit_insn (gen_subsi3 (operands[0], operands[1], temp2));
DONE;
-
}")
(define_insn ""
(match_operand:SI 2 "reg_or_cint_operand" "")))
(set (match_operand:SI 3 "gpc_reg_operand" "")
(umod:SI (match_dup 1) (match_dup 2)))])]
- "TARGET_POWER"
+ ""
"
{
rtx label = 0;
+ if (! TARGET_POWER)
+ if (! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+ emit_insn (gen_divus_call ());
+ emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+ emit_move_insn (operands[3], gen_rtx (REG, SImode, 4));
+ DONE;
+ }
+ else
+ FAIL;
if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) < 0)
{
operands[2] = force_reg (SImode, operands[2]);
DONE;
}")
-
+;; 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
+;; instruction; R0 sometimes clobbered; also, MQ sometimes clobbered but
+;; assumed unused if generating common-mode, so ignore.
+(define_insn "mulh_call"
+ [(set (reg:SI 3)
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI (reg:SI 3))
+ (sign_extend:DI (reg:SI 4)))
+ (const_int 32))))
+ (clobber (match_scratch:SI 0 "=l"))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __mulh")
+(define_insn "mull_call"
+ [(set (reg:DI 3)
+ (mult:DI (sign_extend:DI (reg:SI 3))
+ (sign_extend:DI (reg:SI 4))))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __mull")
+(define_insn "divss_call"
+ [(set (reg:SI 3)
+ (div:SI (reg:SI 3) (reg:SI 4)))
+ (set (reg:SI 4)
+ (mod:SI (reg:SI 3) (reg:SI 4)))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __divss")
+(define_insn "divus_call"
+ [(set (reg:SI 3)
+ (udiv:SI (reg:SI 3) (reg:SI 4)))
+ (set (reg:SI 4)
+ (umod:SI (reg:SI 3) (reg:SI 4)))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __divus")
+(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")
+(define_insn "quous_call"
+ [(set (reg:SI 3)
+ (udiv:SI (reg:SI 3) (reg:SI 4)))
+ (clobber (match_scratch:SI 0 "=l"))
+ (clobber (reg:SI 0))]
+ "! TARGET_POWER && ! TARGET_POWERPC"
+ "bla __quous")
+\f
(define_insn "andsi3"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
(and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
(match_operand:SI 2 "reg_or_cint_operand" "ri"))
(const_int 0)))
(clobber (match_scratch:SI 3 "=r"))]
- "TARGET_POWERPC"
+ "! TARGET_POWER"
"slw%I2. %3,%1,%2"
[(set_attr "type" "delayed_compare")])
(const_int 0)))
(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(ashift:SI (match_dup 1) (match_dup 2)))]
- "TARGET_POWERPC"
+ "! TARGET_POWER"
"slw%I2. %0,%1,%2"
[(set_attr "type" "delayed_compare")])
[(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_POWER"
+ "! TARGET_POWERPC"
"{fa|fadd} %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_POWER"
+ "! TARGET_POWERPC"
"{fs|fsub} %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_POWER"
+ "! TARGET_POWERPC"
"{fm|fmul} %0,%1,%2"
[(set_attr "type" "fp")])
[(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_POWER"
+ "! TARGET_POWERPC"
"{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_POWER"
+ "! TARGET_POWERPC"
"{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_POWER"
+ "! TARGET_POWERPC"
"{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_POWER"
+ "! TARGET_POWERPC"
"{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_POWER"
+ "! TARGET_POWERPC"
"{fnms|fnmsub} %0,%1,%2,%3"
[(set_attr "type" "fp")])
""
"
{
- emit_insn (gen_trunc_call (operands[0], operands[1],
- gen_rtx (SYMBOL_REF, Pmode, RS6000_ITRUNC)));
- DONE;
+ if (TARGET_POWER2 || TARGET_POWERPC)
+ {
+ rtx stack_slot, temp = gen_reg_rtx (DImode);
+ emit_insn (gen_fpcvtsi (temp, operands[1]));
+ stack_slot = gen_rtx (MEM, DImode,
+ plus_constant (stack_pointer_rtx, 8));
+ emit_move_insn (stack_slot, temp);
+ emit_move_insn (operands[0],
+ operand_subword (stack_slot, 1, 0, DImode));
+ DONE;
+ }
+ else
+ {
+ emit_insn (gen_trunc_call (operands[0], operands[1],
+ gen_rtx (SYMBOL_REF, Pmode, RS6000_ITRUNC)));
+ DONE;
+ }
}")
+(define_insn "fpcvtsi"
+ [(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"
+ "{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"
"
{
emit_insn (gen_trunc_call (operands[0], operands[1],
"{sfi|subfic} %L0,%L1,0\;{sfze|subfze} %0,%1"
[(set_attr "length" "8")])
-(define_insn "mulsidi3"
+(define_expand "mulsidi3"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+ (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
+ ""
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+ emit_insn (gen_mull_call ());
+ emit_move_insn (operand_subword (operands[0], 0, 0, DImode),
+ gen_rtx (REG, SImode, 3));
+ emit_move_insn (operand_subword (operands[0], 1, 0, DImode),
+ gen_rtx (REG, SImode, 4));
+ DONE;
+ }
+ else if (TARGET_POWER)
+ {
+ emit_insn (gen_mulsidi3_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+(define_insn "mulsidi3_mq"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
- (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r"))
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
(sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))
(clobber (match_scratch:SI 3 "=q"))]
"TARGET_POWER"
"mul %0,%1,%2\;mfmq %L0"
- [(set_attr "length" "8")])
+ [(set_attr "type" "imul")
+ (set_attr "length" "8")])
+(define_insn ""
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+ "TARGET_POWERPC"
+ "mulhw %0,%1,%2\;mullw %L0,%1,%2"
+ [(set_attr "type" "imul")
+ (set_attr "length" "8")])
+(define_expand "smulsi3_highpart"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))]
+ ""
+ "
+{
+ if (! TARGET_POWER && ! TARGET_POWERPC)
+ {
+ emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+ emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+ emit_insn (gen_mulh_call ());
+ emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+ DONE;
+ }
+ else if (TARGET_POWER)
+ {
+ emit_insn (gen_smulsi3_highpart_mq (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+}")
+(define_insn "smulsi3_highpart_mq"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))
+ (clobber (match_scratch:SI 3 "=q"))]
+ "TARGET_POWER"
+ "mul %0,%1,%2"
+ [(set_attr "type" "imul")])
+(define_insn ""
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (sign_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (sign_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))]
+ "TARGET_POWERPC"
+ "mulhw %0,%1,%2"
+ [(set_attr "type" "imul")])
+(define_insn "umulsi3_highpart"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (truncate:SI
+ (lshiftrt:DI (mult:DI (zero_extend:DI
+ (match_operand:SI 1 "gpc_reg_operand" "%r"))
+ (zero_extend:DI
+ (match_operand:SI 2 "gpc_reg_operand" "r")))
+ (const_int 32))))]
+ "TARGET_POWERPC"
+ "mulhwu %0,%1,%2"
+ [(set_attr "type" "imul")])
;; If operands 0 and 2 are in the same register, we have a problem. But
;; operands 0 and 1 (the usual case) can be in the same register. That's
lis %0,%u1
mf%1 %0
mt%0 %1"
- [(set_attr "type" "*,load,*,*,*,*,*")])
+ [(set_attr "type" "*,load,*,*,*,*,mtjmpr")])
;; Split a load of a large constant into the appropriate two-insn
;; sequence.
#if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && ! defined(REAL_IS_NOT_DOUBLE)
|| GET_CODE (operands[1]) == CONST_DOUBLE
#endif
- || (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32)
- || (reload_in_progress && GET_CODE (operands[1]) == REG
- && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))
+ || (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));
}")
(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m")
- (match_operand:DI 1 "input_operand" "r,m,r"))]
+ [(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"))]
"gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode)"
"*
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 \"fmr %0,%1\";
+ case 4:
+ return \"lfd%U1%X1 %0,%1\";
+ case 5:
+ return \"stfd%U0%X0 %1,%0\";
}
}"
- [(set_attr "type" "*,load,*")
- (set_attr "length" "8")])
+ [(set_attr "type" "*,load,*,fp,fpload,*")
+ (set_attr "length" "8,8,8,*,*,*")])
\f
;; 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