return 0;
return register_operand (op, mode);
}
-\f
+
+/* Recognize a addition operation that includes a constant. Used to
+ convince reload to canonize (plus (plus reg c1) c2) during register
+ elimination. */
+
+int
+addition_operation (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ if (GET_MODE (op) != mode && mode != VOIDmode)
+ return 0;
+ if (GET_CODE (op) == PLUS
+ && register_operand (XEXP (op, 0), mode)
+ && GET_CODE (XEXP (op, 1)) == CONST_INT
+ && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op, 1)), 'K'))
+ return 1;
+ return 0;
+}
+
/* Return 1 if this function can directly return via $26. */
int
&& current_function_outgoing_args_size == 0
&& current_function_pretend_args_size == 0);
}
-
+\f
/* REF is an alignable memory location. Place an aligned SImode
reference into *PALIGNED_MEM and the number of bits to shift into
*PBITNUM. SCRATCH is a free register for use in reloading out
return plus_constant (base, offset + extra_offset);
}
+
+/* Loading and storing HImode or QImode values to and from memory
+ usually requires a scratch register. The exceptions are loading
+ QImode and HImode from an aligned address to a general register
+ unless byte instructions are permitted.
+
+ We also cannot load an unaligned address or a paradoxical SUBREG
+ into an FP register.
+
+ We also cannot do integral arithmetic into FP regs, as might result
+ from register elimination into a DImode fp register. */
+
+enum reg_class
+secondary_reload_class (class, mode, x, in)
+ enum reg_class class;
+ enum machine_mode mode;
+ rtx x;
+ int in;
+{
+ if ((GET_CODE (x) == MEM
+ || (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+ || (GET_CODE (x) == SUBREG
+ && (GET_CODE (SUBREG_REG (x)) == MEM
+ || (GET_CODE (SUBREG_REG (x)) == REG
+ && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER))))
+ && ((class == FLOAT_REGS
+ && (mode == SImode || mode == HImode || mode == QImode))
+ || ((mode == QImode || mode == HImode)
+ && ! TARGET_BWX && ! aligned_memory_operand (x, mode))))
+ return GENERAL_REGS;
+
+ if (class == FLOAT_REGS)
+ {
+ if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND)
+ return GENERAL_REGS;
+
+ if (GET_CODE (x) == SUBREG
+ && (GET_MODE_SIZE (GET_MODE (x))
+ > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+ return GENERAL_REGS;
+
+ if (in && INTEGRAL_MODE_P (mode) && ! general_operand (x, mode))
+ return GENERAL_REGS;
+ }
+
+ return NO_REGS;
+}
\f
/* Subfunction of the following function. Update the flags of any MEM
found in part of X. */
We also cannot load an unaligned address or a paradoxical SUBREG into an
FP register. */
-#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,IN) \
-(((GET_CODE (IN) == MEM \
- || (GET_CODE (IN) == REG && REGNO (IN) >= FIRST_PSEUDO_REGISTER) \
- || (GET_CODE (IN) == SUBREG \
- && (GET_CODE (SUBREG_REG (IN)) == MEM \
- || (GET_CODE (SUBREG_REG (IN)) == REG \
- && REGNO (SUBREG_REG (IN)) >= FIRST_PSEUDO_REGISTER)))) \
- && (((CLASS) == FLOAT_REGS \
- && ((MODE) == SImode || (MODE) == HImode || (MODE) == QImode)) \
- || (((MODE) == QImode || (MODE) == HImode) \
- && ! TARGET_BWX && ! aligned_memory_operand (IN, MODE)))) \
- ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (IN) == MEM \
- && GET_CODE (XEXP (IN, 0)) == AND) ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (IN) == SUBREG \
- && (GET_MODE_SIZE (GET_MODE (IN)) \
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (IN))))) ? GENERAL_REGS \
- : NO_REGS)
-
-#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,OUT) \
-(((GET_CODE (OUT) == MEM \
- || (GET_CODE (OUT) == REG && REGNO (OUT) >= FIRST_PSEUDO_REGISTER) \
- || (GET_CODE (OUT) == SUBREG \
- && (GET_CODE (SUBREG_REG (OUT)) == MEM \
- || (GET_CODE (SUBREG_REG (OUT)) == REG \
- && REGNO (SUBREG_REG (OUT)) >= FIRST_PSEUDO_REGISTER)))) \
- && ((((MODE) == HImode || (MODE) == QImode) \
- && (! TARGET_BWX || (CLASS) == FLOAT_REGS)) \
- || ((MODE) == SImode && (CLASS) == FLOAT_REGS))) \
- ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (OUT) == MEM \
- && GET_CODE (XEXP (OUT, 0)) == AND) ? GENERAL_REGS \
- : ((CLASS) == FLOAT_REGS && GET_CODE (OUT) == SUBREG \
- && (GET_MODE_SIZE (GET_MODE (OUT)) \
- > GET_MODE_SIZE (GET_MODE (SUBREG_REG (OUT))))) ? GENERAL_REGS \
- : NO_REGS)
+#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,IN) \
+ secondary_reload_class((CLASS), (MODE), (IN), 1)
+
+#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,OUT) \
+ secondary_reload_class((CLASS), (MODE), (OUT), 0)
/* If we are copying between general and FP registers, we need a memory
location unless the FIX extension is available. */
{"any_memory_operand", {MEM}}, \
{"hard_fp_register_operand", {SUBREG, REG}}, \
{"reg_not_elim_operand", {SUBREG, REG}}, \
- {"reg_no_subreg_operand", {REG}},
+ {"reg_no_subreg_operand", {REG}}, \
+ {"addition_operation", {PLUS}},
\f
/* Define the `__builtin_va_list' type for the ABI. */
#define BUILD_VA_LIST_TYPE(VALIST) \
operands[7] = gen_lowpart (SImode, operands[5]);
}")
-(define_insn "adddi3"
- [(set (match_operand:DI 0 "register_operand" "=r,r,r,r")
- (plus:DI (match_operand:DI 1 "reg_or_0_operand" "%rJ,rJ,rJ,rJ")
- (match_operand:DI 2 "add_operand" "rI,O,K,L")))]
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "register_operand" "")
+ (plus:DI (match_operand:DI 1 "register_operand" "")
+ (match_operand:DI 2 "add_operand" "")))]
""
- "*
-{
- static const char * const pattern[4] = {
- \"addq %r1,%2,%0\",
- \"subq %r1,%n2,%0\",
- \"lda %0,%2(%r1)\",
- \"ldah %0,%h2(%r1)\"
- };
-
- /* The NT stack unwind code can't handle a subq to adjust the stack
- (that's a bug, but not one we can do anything about). As of NT4.0 SP3,
- the exception handling code will loop if a subq is used and an
- exception occurs.
-
- The 19980616 change to emit prologues as RTL also confused some
- versions of GDB, which also interprets prologues. This has been
- fixed as of GDB 4.18, but it does not harm to unconditionally
- use lda here. */
-
- int which = which_alternative;
-
- if (operands[0] == stack_pointer_rtx
- && GET_CODE (operands[2]) == CONST_INT
- && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))
- which = 2;
-
- return pattern[which];
-}")
+ "")
+
+;; This pattern exists so that register elimination tries to canonize
+;; (plus (plus reg c1) c2).
+
+(define_insn "*lda"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (match_operand:DI 1 "addition_operation" "p"))]
+ ""
+ "lda %0,%a1")
+
+;; We used to expend quite a lot of effort choosing addq/subq/lda.
+;; With complications like
+;;
+;; The NT stack unwind code can't handle a subq to adjust the stack
+;; (that's a bug, but not one we can do anything about). As of NT4.0 SP3,
+;; the exception handling code will loop if a subq is used and an
+;; exception occurs.
+;;
+;; The 19980616 change to emit prologues as RTL also confused some
+;; versions of GDB, which also interprets prologues. This has been
+;; fixed as of GDB 4.18, but it does not harm to unconditionally
+;; use lda here.
+;;
+;; and the fact that the three insns schedule exactly the same, it's
+;; just not worth the effort.
+
+(define_insn "*adddi_2"
+ [(set (match_operand:DI 0 "register_operand" "=r,r,r")
+ (plus:DI (match_operand:DI 1 "register_operand" "%r,r,r")
+ (match_operand:DI 2 "add_operand" "r,K,L")))]
+ ""
+ "@
+ addq %1,%2,%0
+ lda %0,%2(%1)
+ ldah %0,%h2(%1)")
;; ??? Allow large constants when basing off the frame pointer or some
;; virtual register that may eliminate to the frame pointer. This is
;; they are simpler.
(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,r,r,m,m")
- (match_operand:SF 1 "input_operand" "fG,m,rG,m,fG,r"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m")
+ (match_operand:SF 1 "input_operand" "fG,m,*rG,m,fG,*r"))]
"! TARGET_FIX
&& (register_operand (operands[0], SFmode)
|| reg_or_fp0_operand (operands[1], SFmode))"
[(set_attr "type" "fcpys,fld,ilog,ild,fst,ist")])
(define_insn ""
- [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,r,r,m,m,f,*r")
- (match_operand:SF 1 "input_operand" "fG,m,rG,m,fG,r,r,*f"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m,f,*r")
+ (match_operand:SF 1 "input_operand" "fG,m,*rG,m,fG,*r,*r,f"))]
"TARGET_FIX
&& (register_operand (operands[0], SFmode)
|| reg_or_fp0_operand (operands[1], SFmode))"
[(set_attr "type" "fcpys,fld,ilog,ild,fst,ist,itof,ftoi")])
(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,r,r,m,m")
- (match_operand:DF 1 "input_operand" "fG,m,rG,m,fG,r"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m")
+ (match_operand:DF 1 "input_operand" "fG,m,*rG,m,fG,*r"))]
"! TARGET_FIX
&& (register_operand (operands[0], DFmode)
|| reg_or_fp0_operand (operands[1], DFmode))"
[(set_attr "type" "fcpys,fld,ilog,ild,fst,ist")])
(define_insn ""
- [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,r,r,m,m,f,*r")
- (match_operand:DF 1 "input_operand" "fG,m,rG,m,fG,r,r,*f"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,*r,*r,m,m,f,*r")
+ (match_operand:DF 1 "input_operand" "fG,m,*rG,m,fG,*r,*r,f"))]
"TARGET_FIX
&& (register_operand (operands[0], DFmode)
|| reg_or_fp0_operand (operands[1], DFmode))"
}")
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,f,f,m")
- (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,fJ,m,f"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,*f,*f,m")
+ (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,*fJ,m,*f"))]
"! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && ! TARGET_FIX
&& (register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))"
[(set_attr "type" "ilog,iadd,iadd,ild,ist,fcpys,fld,fst")])
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,f,f,m,r,*f")
- (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,fJ,m,f,f,*r"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,*f,*f,m,r,*f")
+ (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,*fJ,m,*f,*f,r"))]
"! TARGET_WINDOWS_NT && ! TARGET_OPEN_VMS && TARGET_FIX
&& (register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))"
[(set_attr "type" "ilog,iadd,iadd,ild,ist,fcpys,fld,fst,ftoi,itof")])
(define_insn ""
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f,m")
- (match_operand:SI 1 "input_operand" "rJ,K,L,s,m,rJ,fJ,m,f"))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,m")
+ (match_operand:SI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,m,*f"))]
"(TARGET_WINDOWS_NT || TARGET_OPEN_VMS)
&& (register_operand (operands[0], SImode)
|| reg_or_0_operand (operands[1], SImode))"
}")
(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f,Q")
- (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,fJ,Q,f"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q")
+ (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f"))]
"! TARGET_FIX
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"
[(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
(define_insn ""
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,f,f,Q,r,*f")
- (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,fJ,Q,f,f,*r"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q,r,*f")
+ (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f,*f,r"))]
"TARGET_FIX
&& (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))"