+2000-11-21 Richard Henderson <rth@redhat.com>
+
+ * config/alpha/alpha.c (alpha_split_tfmode_frobsign): New.
+ * config/alpha/alpha-protos.h: Declare it.
+ * config/alpha/alpha.md (abstf_internal): Use it.
+ (negtf_internal): Likewise.
+ (andnotdi3): Unstar the name.
+ (movtf_internal): Add o/G alternative.
+
2000-11-21 Zack Weinberg <zack@wolery.stanford.edu>
* stringpool.c (stringpool_statistics): Also report number and
extern void alpha_emit_xfloating_arith PARAMS ((enum rtx_code, rtx[]));
extern void alpha_emit_xfloating_cvt PARAMS ((enum rtx_code, rtx[]));
extern void alpha_split_tfmode_pair PARAMS ((rtx[]));
+extern void alpha_split_tfmode_frobsign PARAMS ((rtx[],
+ rtx (*)(rtx, rtx, rtx)));
extern void alpha_expand_unaligned_load PARAMS ((rtx, rtx, HOST_WIDE_INT,
HOST_WIDE_INT, int));
extern void alpha_expand_unaligned_store PARAMS ((rtx, rtx, HOST_WIDE_INT,
operands[1]));
}
+/* Split a TFmode OP[1] into DImode OP[2,3] and likewise for
+ OP[0] into OP[0,1]. Naturally, output operand ordering is
+ little-endian. */
+
void
alpha_split_tfmode_pair (operands)
rtx operands[4];
else
abort ();
}
+
+/* Implement negtf2 or abstf2. Op0 is destination, op1 is source,
+ op2 is a register containing the sign bit, operation is the
+ logical operation to be performed. */
+
+void
+alpha_split_tfmode_frobsign (operands, operation)
+ rtx operands[3];
+ rtx (*operation) PARAMS ((rtx, rtx, rtx));
+{
+ rtx high_bit = operands[2];
+ rtx scratch;
+ int move;
+
+ alpha_split_tfmode_pair (operands);
+
+ /* Detect three flavours of operand overlap. */
+ move = 1;
+ if (rtx_equal_p (operands[0], operands[2]))
+ move = 0;
+ else if (rtx_equal_p (operands[1], operands[2]))
+ {
+ if (rtx_equal_p (operands[0], high_bit))
+ move = 2;
+ else
+ move = -1;
+ }
+
+ if (move < 0)
+ emit_move_insn (operands[0], operands[2]);
+
+ /* ??? If the destination overlaps both source tf and high_bit, then
+ assume source tf is dead in its entirety and use the other half
+ for a scratch register. Otherwise "scratch" is just the proper
+ destination register. */
+ scratch = operands[move < 2 ? 1 : 3];
+
+ emit_insn ((*operation) (scratch, high_bit, operands[3]));
+
+ if (move > 0)
+ {
+ emit_move_insn (operands[0], operands[2]);
+ if (move > 1)
+ emit_move_insn (operands[1], scratch);
+ }
+}
\f
/* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
unaligned data:
"zapnot %1,15,%0"
[(set_attr "type" "shift")])
-(define_insn "*andnot"
+(define_insn "andnotdi3"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (not:DI (match_operand:DI 1 "reg_or_8bit_operand" "rI"))
(match_operand:DI 2 "reg_or_0_operand" "rJ")))]
(define_insn_and_split "*abstf_internal"
[(set (match_operand:TF 0 "register_operand" "=r")
(abs:TF (match_operand:TF 1 "reg_or_fp0_operand" "rG")))
- (use (match_operand:DI 2 "register_operand" "=r"))]
+ (use (match_operand:DI 2 "register_operand" "r"))]
"TARGET_HAS_XFLOATING_LIBS"
"#"
"&& reload_completed"
[(const_int 0)]
- "
-{
- int move;
- rtx tmp;
-
- alpha_split_tfmode_pair (operands);
-
- move = 1;
- if (rtx_equal_p (operands[0], operands[2]))
- move = 0;
- else if (rtx_equal_p (operands[1], operands[2]))
- move = -1;
-
- if (move < 0)
- emit_move_insn (operands[0], operands[2]);
-
- tmp = gen_rtx_NOT (DImode, operands[4]);
- tmp = gen_rtx_AND (DImode, tmp, operands[3]);
- emit_insn (gen_rtx_SET (VOIDmode, operands[1], tmp));
-
- if (move > 0)
- emit_move_insn (operands[0], operands[2]);
- DONE;
-}")
+ "alpha_split_tfmode_frobsign (operands, gen_andnotdi3); DONE;")
(define_insn "negsf2"
[(set (match_operand:SF 0 "register_operand" "=f")
(define_insn_and_split "*negtf_internal"
[(set (match_operand:TF 0 "register_operand" "=r")
(neg:TF (match_operand:TF 1 "reg_or_fp0_operand" "rG")))
- (use (match_operand:DI 2 "register_operand" "=r"))]
+ (use (match_operand:DI 2 "register_operand" "r"))]
"TARGET_HAS_XFLOATING_LIBS"
"#"
"&& reload_completed"
[(const_int 0)]
- "
-{
- int move;
-
- alpha_split_tfmode_pair (operands);
-
- move = 1;
- if (rtx_equal_p (operands[0], operands[2]))
- move = 0;
- else if (rtx_equal_p (operands[1], operands[2]))
- move = -1;
-
- if (move < 0)
- emit_move_insn (operands[0], operands[2]);
-
- emit_insn (gen_xordi3 (operands[1], operands[3], operands[4]));
-
- if (move > 0)
- emit_move_insn (operands[0], operands[2]);
- DONE;
-}")
+ "alpha_split_tfmode_frobsign (operands, gen_xordi3); DONE;")
(define_insn "*addsf_ieee"
[(set (match_operand:SF 0 "register_operand" "=&f")
(define_insn_and_split "*movtf_internal"
[(set (match_operand:TF 0 "nonimmediate_operand" "=r,o")
- (match_operand:TF 1 "input_operand" "roG,r"))]
+ (match_operand:TF 1 "input_operand" "roG,rG"))]
"register_operand (operands[0], TFmode)
|| reg_or_fp0_operand (operands[1], TFmode)"
"#"