This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] S/390 backend update
- To: gcc-patches at gcc dot gnu dot org
- Subject: [PATCH] S/390 backend update
- From: Ulrich Weigand <weigand at immd1 dot informatik dot uni-erlangen dot de>
- Date: Sun, 30 Sep 2001 00:59:13 +0200 (MET DST)
- Cc: uweigand at de dot ibm dot com, hpenner at de dot ibm dot com
This patch fixes several bugs in the s390 backend:
- The addsi3_cc and related insns tried to use the condition code
set by the arithmetic instructions to compare the result of the
addition/subtraction against zero. This works most of the time,
but fails unfortunately if the operation overflows.
For comparisons of the type > 0 or < 0 this cannot be fixed; so
we have to generate an explicit compare instruction after the
add/subtract. However, for EQ or NE comparisons we can use
the 'logical' add/subtract instructions instead, which set the
condition code so that it can reliably be used.
However, they set the condition code in a different way than
most other instructions, therefore some changes to the condition
code handling have been necessary.
This change exposed some latent condition code handling bugs
which are also fixed.
- The load address 'la' instructions performs a 31-bit addition,
not 32-bit, therefore it must not be used to add non-addresses.
This patch fixes some cases where the la instruction was used
incorrectly.
- When using -mno-backchain, in some rare corner cases incorrect
prolog code was generated.
- The operands 0 and 1 of cmpsi_cct do not commute (thanks to
Tod for pointing this out).
In addition, some other changes are included:
- Add the UNORDERED family of comparisons.
- Improve legitimize_address to make better use of the two-register
(base + index + displacement) addressing mode.
Bootstrapped and regtested on s390-ibm-linux and s390x-ibm-linux.
Installed on mainline.
Bye,
Ulrich
ChangeLog:
* config/s390/s390.h (EXTRA_CC_MODES): Add CCLmode.
(SELECT_CC_MODE): Use s390_select_ccmode.
* config/s390/s390-protos.h (s390_select_ccmode): Add.
* config/s390/s390.c (s390_select_ccmode): New.
(s390_match_ccmode): Add CCLmode.
(s390_branch_condition_mask, s390_branch_condition_mnemonic): New.
(output_branch_condition, output_inverse_branch_condition): Removed.
(print_operand): Use s390_branch_condition_mnemonic.
* config/s390/s390.md (addsi3_cc, addsi3_cconly, addsi3_cconly2,
subsi3_cc, subsi3_cconly): Use logical instructions and CCLmode.
(bunordered, bordered, buneq, bungt, bunlt, bnuge, bunle, bltgt): New.
* config/s390/s390.c (check_and_change_labels): Preserve CC mode
when converting conditional branches to far branches.
* config/s390/s390.md (cmpstr_const, cmpstr_64, cmpstr_31, cmpint_si,
cmpint_di): Use CCSmode instead of CCUmode.
* config/s390/s390.c (legitimate_la_operand_p): New.
* config/s390/s390-protos.h (legitimate_la_operand_p): Add.
* config/s390/s390.md (movsi): Convert load address patterns to
arithmetic operations when necessary.
(addaddr_picR, addaddr_picL, addaddr_picN): Removed.
(do_la): Renamed to *do_la and use legitimate_la_operand_p.
(*do_la_reg_0): Don't use before reload.
* config/s390/s390.c (legitimize_address): Make more efficient
use of two-register addressing mode.
* config/s390/s390.c (s390_function_prologue): Fix incorrect prolog
with -mno-backchain in some corner cases.
* config/s390/s390.md (cmpsi_cct): Operands 0 and 1 do not commute.
Index: gcc/config/s390/s390-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390-protos.h,v
retrieving revision 1.3
diff -c -p -r1.3 s390-protos.h
*** s390-protos.h 2001/08/18 20:25:53 1.3
--- s390-protos.h 2001/09/29 22:51:51
*************** extern int load_multiple_operation PARAM
*** 42,48 ****
--- 42,50 ----
extern int store_multiple_operation PARAMS ((rtx, enum machine_mode));
extern int s390_match_ccmode PARAMS ((rtx, enum machine_mode));
+ extern enum machine_mode s390_select_ccmode PARAMS ((enum rtx_code, rtx, rtx));
extern int symbolic_reference_mentioned_p PARAMS ((rtx));
+ extern int legitimate_la_operand_p PARAMS ((rtx));
extern int legitimate_pic_operand_p PARAMS ((rtx));
extern int legitimate_constant_p PARAMS ((rtx));
extern int legitimate_address_p PARAMS ((enum machine_mode, rtx, int));
Index: gcc/config/s390/s390.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.c,v
retrieving revision 1.8
diff -c -p -r1.8 s390.c
*** s390.c 2001/09/21 11:41:43 1.8
--- s390.c 2001/09/29 22:51:57
*************** struct s390_address
*** 94,104 ****
};
static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));
static int base_n_index_p PARAMS ((rtx));
static int check_mode PARAMS ((rtx, enum machine_mode *));
static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));
- static void output_branch_condition PARAMS ((FILE *, rtx));
- static void output_inverse_branch_condition PARAMS ((FILE *, rtx));
static int reg_used_in_mem_p PARAMS ((int, rtx));
static int addr_generation_dependency_p PARAMS ((rtx, rtx));
static int other_chunk PARAMS ((int *, int, int));
--- 94,104 ----
};
static int s390_match_ccmode_set PARAMS ((rtx, enum machine_mode));
+ static int s390_branch_condition_mask PARAMS ((rtx));
+ static const char *s390_branch_condition_mnemonic PARAMS ((rtx, int));
static int base_n_index_p PARAMS ((rtx));
static int check_mode PARAMS ((rtx, enum machine_mode *));
static int s390_decompose_address PARAMS ((rtx, struct s390_address *, int));
static int reg_used_in_mem_p PARAMS ((int, rtx));
static int addr_generation_dependency_p PARAMS ((rtx, rtx));
static int other_chunk PARAMS ((int *, int, int));
*************** s390_match_ccmode_set (set, req_mode)
*** 135,143 ****
set_mode = GET_MODE (SET_DEST (set));
switch (set_mode)
{
- case CCmode:
- return 0;
-
case CCSmode:
if (req_mode != CCSmode)
return 0;
--- 135,140 ----
*************** s390_match_ccmode_set (set, req_mode)
*** 146,151 ****
--- 143,152 ----
if (req_mode != CCUmode)
return 0;
break;
+ case CCLmode:
+ if (req_mode != CCLmode)
+ return 0;
+ break;
case CCZmode:
if (req_mode != CCSmode && req_mode != CCUmode && req_mode != CCTmode)
return 0;
*************** s390_match_ccmode (insn, req_mode)
*** 184,189 ****
--- 185,345 ----
return 1;
}
+ /* Given a comparison code OP (EQ, NE, etc.) and the operands
+ OP0 and OP1 of a COMPARE, return the mode to be used for the
+ comparison. */
+
+ enum machine_mode
+ s390_select_ccmode (code, op0, op1)
+ enum rtx_code code;
+ rtx op0;
+ rtx op1;
+ {
+ switch (code)
+ {
+ case EQ:
+ case NE:
+ if (GET_CODE (op0) == PLUS || GET_CODE (op0) == MINUS
+ || GET_CODE (op1) == NEG)
+ return CCLmode;
+
+ return CCZmode;
+
+ case LE:
+ case LT:
+ case GE:
+ case GT:
+ case UNORDERED:
+ case ORDERED:
+ case UNEQ:
+ case UNLE:
+ case UNLT:
+ case UNGE:
+ case UNGT:
+ case LTGT:
+ return CCSmode;
+
+ case LEU:
+ case LTU:
+ case GEU:
+ case GTU:
+ return CCUmode;
+
+ default:
+ abort ();
+ }
+ }
+
+ /* Return branch condition mask to implement a branch
+ specified by CODE. */
+
+ static int
+ s390_branch_condition_mask (code)
+ rtx code;
+ {
+ const int CC0 = 1 << 3;
+ const int CC1 = 1 << 2;
+ const int CC2 = 1 << 1;
+ const int CC3 = 1 << 0;
+
+ if (GET_CODE (XEXP (code, 0)) != REG
+ || REGNO (XEXP (code, 0)) != CC_REGNUM
+ || XEXP (code, 1) != const0_rtx)
+ abort ();
+
+ switch (GET_MODE (XEXP (code, 0)))
+ {
+ case CCZmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0;
+ case NE: return CC1 | CC2 | CC3;
+ default:
+ abort ();
+ }
+ break;
+
+ case CCLmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0 | CC2;
+ case NE: return CC1 | CC3;
+ case UNORDERED: return CC2 | CC3; /* carry */
+ case ORDERED: return CC0 | CC1; /* no carry */
+ default:
+ abort ();
+ }
+ break;
+
+ case CCUmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0;
+ case NE: return CC1 | CC2 | CC3;
+ case LTU: return CC1;
+ case GTU: return CC2;
+ case LEU: return CC0 | CC1;
+ case GEU: return CC0 | CC2;
+ default:
+ abort ();
+ }
+ break;
+
+ case CCSmode:
+ switch (GET_CODE (code))
+ {
+ case EQ: return CC0;
+ case NE: return CC1 | CC2 | CC3;
+ case LT: return CC1;
+ case GT: return CC2;
+ case LE: return CC0 | CC1;
+ case GE: return CC0 | CC2;
+ case UNORDERED: return CC3;
+ case ORDERED: return CC0 | CC1 | CC2;
+ case UNEQ: return CC0 | CC3;
+ case UNLT: return CC1 | CC3;
+ case UNGT: return CC2 | CC3;
+ case UNLE: return CC0 | CC1 | CC3;
+ case UNGE: return CC0 | CC2 | CC3;
+ case LTGT: return CC1 | CC2;
+ default:
+ abort ();
+ }
+
+ default:
+ abort ();
+ }
+ }
+
+ /* If INV is false, return assembler mnemonic string to implement
+ a branch specified by CODE. If INV is true, return mnemonic
+ for the corresponding inverted branch. */
+
+ static const char *
+ s390_branch_condition_mnemonic (code, inv)
+ rtx code;
+ int inv;
+ {
+ static const char *mnemonic[16] =
+ {
+ NULL, "o", "h", "nle",
+ "l", "nhe", "lh", "ne",
+ "e", "nlh", "he", "nl",
+ "le", "nh", "no", NULL
+ };
+
+ int mask = s390_branch_condition_mask (code);
+
+ if (inv)
+ mask ^= 15;
+
+ if (mask < 1 || mask > 14)
+ abort ();
+
+ return mnemonic[mask];
+ }
+
+
/* Change optimizations to be performed, depending on the
optimization level.
*************** legitimate_address_p (mode, addr, strict
*** 887,892 ****
--- 1043,1082 ----
return s390_decompose_address (addr, NULL, strict);
}
+ /* Return 1 if OP is a valid operand for the LA instruction.
+ In 31-bit, we need to prove that the result is used as an
+ address, as LA performs only a 31-bit addition. */
+
+ int
+ legitimate_la_operand_p (op)
+ register rtx op;
+ {
+ struct s390_address addr;
+ if (!s390_decompose_address (op, &addr, FALSE))
+ return FALSE;
+
+ if (TARGET_64BIT)
+ return TRUE;
+
+ /* Use of the base or stack pointer implies address. */
+
+ if (addr.base && GET_CODE (addr.base) == REG)
+ {
+ if (REGNO (addr.base) == BASE_REGISTER
+ || REGNO (addr.base) == STACK_POINTER_REGNUM)
+ return TRUE;
+ }
+
+ if (addr.indx && GET_CODE (addr.indx) == REG)
+ {
+ if (REGNO (addr.indx) == BASE_REGISTER
+ || REGNO (addr.indx) == STACK_POINTER_REGNUM)
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
/* Return a legitimate reference for ORIG (an address) using the
register REG. If REG is 0, a new pseudo is generated.
*************** legitimize_address (x, oldx, mode)
*** 1199,1285 ****
register rtx oldx ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
! if (flag_pic && SYMBOLIC_CONST (x))
! return legitimize_pic_address (x, 0);
! return x;
! }
! /* Output branch condition code of CODE in assembler
! syntax to stdio stream FILE. */
! static void
! output_branch_condition (file, code)
! FILE *file;
! rtx code;
! {
! switch (GET_CODE (code))
{
! case EQ:
! fprintf (file, "e");
! break;
! case NE:
! fprintf (file, "ne");
! break;
! case GT:
! case GTU:
! fprintf (file, "h");
! break;
! case LT:
! case LTU:
! fprintf (file, "l");
! break;
! case GE:
! case GEU:
! fprintf (file, "he");
! break;
! case LE:
! case LEU:
! fprintf (file, "le");
! break;
! default:
! fatal_insn ("Unknown CC code", code);
! }
! }
! /* Output the inverse of the branch condition code of CODE
! in assembler syntax to stdio stream FILE. */
! static void
! output_inverse_branch_condition (file, code)
! FILE *file;
! rtx code;
! {
! switch (GET_CODE (code))
! {
! case EQ:
! fprintf (file, "ne");
! break;
! case NE:
! fprintf (file, "e");
! break;
! case GT:
! case GTU:
! fprintf (file, "nh");
! break;
! case LT:
! case LTU:
! fprintf (file, "nl");
! break;
! case GE:
! case GEU:
! fprintf (file, "nhe");
! break;
! case LE:
! case LEU:
! fprintf (file, "nle");
! break;
! default:
! fatal_insn ("Unknown CC code", code);
}
}
/* Output symbolic constant X in assembler syntax to
stdio stream FILE. */
--- 1389,1440 ----
register rtx oldx ATTRIBUTE_UNUSED;
enum machine_mode mode ATTRIBUTE_UNUSED;
{
! rtx constant_term = const0_rtx;
! if (flag_pic)
! {
! if (SYMBOLIC_CONST (x)
! || (GET_CODE (x) == PLUS
! && (SYMBOLIC_CONST (XEXP (x, 0))
! || SYMBOLIC_CONST (XEXP (x, 1)))))
! x = legitimize_pic_address (x, 0);
+ if (legitimate_address_p (mode, x, FALSE))
+ return x;
+ }
! x = eliminate_constant_term (x, &constant_term);
! if (GET_CODE (x) == PLUS)
{
! if (GET_CODE (XEXP (x, 0)) == REG)
! {
! register rtx temp = gen_reg_rtx (Pmode);
! register rtx val = force_operand (XEXP (x, 1), temp);
! if (val != temp)
! emit_move_insn (temp, val);
! x = gen_rtx_PLUS (Pmode, XEXP (x, 0), temp);
! }
! else if (GET_CODE (XEXP (x, 1)) == REG)
! {
! register rtx temp = gen_reg_rtx (Pmode);
! register rtx val = force_operand (XEXP (x, 0), temp);
! if (val != temp)
! emit_move_insn (temp, val);
!
! x = gen_rtx_PLUS (Pmode, temp, XEXP (x, 1));
! }
}
+
+ if (constant_term != const0_rtx)
+ x = gen_rtx_PLUS (Pmode, x, constant_term);
+
+ return x;
}
+
/* Output symbolic constant X in assembler syntax to
stdio stream FILE. */
*************** print_operand (file, x, code)
*** 1417,1427 ****
switch (code)
{
case 'C':
! output_branch_condition (file, x);
return;
case 'D':
! output_inverse_branch_condition (file, x);
return;
case 'Y':
--- 1572,1582 ----
switch (code)
{
case 'C':
! fprintf (file, s390_branch_condition_mnemonic (x, FALSE));
return;
case 'D':
! fprintf (file, s390_branch_condition_mnemonic (x, TRUE));
return;
case 'Y':
*************** check_and_change_labels (insn, ltorg_uid
*** 1806,1812 ****
int *ltorg_uids;
{
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
! rtx target, jump;
rtx pattern, tmp, body, label1;
int addr0, addr1;
--- 1961,1967 ----
int *ltorg_uids;
{
rtx temp_reg = gen_rtx_REG (Pmode, RETURN_REGNUM);
! rtx target, jump, cjump;
rtx pattern, tmp, body, label1;
int addr0, addr1;
*************** check_and_change_labels (insn, ltorg_uid
*** 1878,1884 ****
}
label1 = gen_label_rtx ();
! emit_jump_insn_before (gen_icjump (label1, XEXP (body, 0)), insn);
emit_insn_before (gen_movsi (temp_reg, target), insn);
tmp = emit_jump_insn_before (gen_indirect_jump (jump), insn);
INSN_ADDRESSES_NEW (emit_label_before (label1, insn), -1);
--- 2033,2042 ----
}
label1 = gen_label_rtx ();
! cjump = gen_rtx_LABEL_REF (VOIDmode, label1);
! cjump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (body, 0), pc_rtx, cjump);
! cjump = gen_rtx_SET (VOIDmode, pc_rtx, cjump);
! emit_jump_insn_before (cjump, insn);
emit_insn_before (gen_movsi (temp_reg, target), insn);
tmp = emit_jump_insn_before (gen_indirect_jump (jump), insn);
INSN_ADDRESSES_NEW (emit_label_before (label1, insn), -1);
*************** check_and_change_labels (insn, ltorg_uid
*** 1912,1918 ****
}
label1 = gen_label_rtx ();
! emit_jump_insn_before (gen_cjump (label1, XEXP (body, 0)), insn);
emit_insn_before (gen_movsi (temp_reg, target), insn);
tmp = emit_jump_insn_before (gen_indirect_jump (jump), insn);
INSN_ADDRESSES_NEW (emit_label_before (label1, insn), -1);
--- 2070,2079 ----
}
label1 = gen_label_rtx ();
! cjump = gen_rtx_LABEL_REF (VOIDmode, label1);
! cjump = gen_rtx_IF_THEN_ELSE (VOIDmode, XEXP (body, 0), cjump, pc_rtx);
! cjump = gen_rtx_SET (VOIDmode, pc_rtx, cjump);
! emit_jump_insn_before (cjump, insn);
emit_insn_before (gen_movsi (temp_reg, target), insn);
tmp = emit_jump_insn_before (gen_indirect_jump (jump), insn);
INSN_ADDRESSES_NEW (emit_label_before (label1, insn), -1);
*************** s390_function_prologue (file, lsize)
*** 2541,2548 ****
/* Decrement stack. */
! if (TARGET_BACKCHAIN || (STARTING_FRAME_OFFSET +
! lsize + STACK_POINTER_OFFSET > 4095
|| frame_pointer_needed
|| current_function_calls_alloca))
{
--- 2702,2708 ----
/* Decrement stack. */
! if (TARGET_BACKCHAIN || (frame_size + STACK_POINTER_OFFSET > 4095
|| frame_pointer_needed
|| current_function_calls_alloca))
{
*************** s390_function_prologue (file, lsize)
*** 2582,2589 ****
/* Generate backchain. */
! if (TARGET_BACKCHAIN || (STARTING_FRAME_OFFSET +
! lsize + STACK_POINTER_OFFSET > 4095
|| frame_pointer_needed
|| current_function_calls_alloca))
{
--- 2742,2748 ----
/* Generate backchain. */
! if (TARGET_BACKCHAIN || (frame_size + STACK_POINTER_OFFSET > 4095
|| frame_pointer_needed
|| current_function_calls_alloca))
{
Index: gcc/config/s390/s390.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.h,v
retrieving revision 1.6
diff -c -p -r1.6 s390.h
*** s390.h 2001/09/18 21:51:53 1.6
--- s390.h 2001/09/29 22:52:01
*************** do {
*** 1687,1692 ****
--- 1687,1693 ----
#define EXTRA_CC_MODES \
CC (CCZmode, "CCZ") \
CC (CCAmode, "CCA") \
+ CC (CCLmode, "CCL") \
CC (CCUmode, "CCU") \
CC (CCSmode, "CCS") \
CC (CCTmode, "CCT")
*************** do {
*** 1694,1706 ****
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
! #define SELECT_CC_MODE(OP, X, Y) \
! ( (OP) == EQ || (OP) == NE ? CCZmode \
! : (OP) == LE || (OP) == LT || \
! (OP) == GE || (OP) == GT ? CCSmode \
! : (OP) == LEU || (OP) == LTU || \
! (OP) == GEU || (OP) == GTU ? CCUmode \
! : CCmode )
/* Define the information needed to generate branch and scc insns. This is
--- 1695,1701 ----
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
return the mode to be used for the comparison. */
! #define SELECT_CC_MODE(OP, X, Y) s390_select_ccmode ((OP), (X), (Y))
/* Define the information needed to generate branch and scc insns. This is
Index: gcc/config/s390/s390.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/s390/s390.md,v
retrieving revision 1.4
diff -c -p -r1.4 s390.md
*** s390.md 2001/09/21 11:41:43 1.4
--- s390.md 2001/09/29 22:52:11
***************
*** 369,375 ****
(define_insn "*cmpsi_cct"
[(set (reg 33)
! (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "%d")
(match_operand:SI 1 "const1_operand" "")
(match_operand:SI 2 "immediate_operand" "I"))
(const_int 0)))]
--- 369,375 ----
(define_insn "*cmpsi_cct"
[(set (reg 33)
! (compare (zero_extract:SI (match_operand:SI 0 "register_operand" "d")
(match_operand:SI 1 "const1_operand" "")
(match_operand:SI 2 "immediate_operand" "I"))
(const_int 0)))]
***************
*** 856,861 ****
--- 856,874 ----
if (flag_pic && SYMBOLIC_CONST (operands[1]))
emit_pic_move (operands, SImode);
+
+ /* expr.c tries to load an effective address using
+ force_reg. This fails because we don't have a
+ generic load_address pattern. Convert the move
+ to a proper arithmetic operation instead, unless
+ it is guaranteed to be OK. */
+ if (GET_CODE (operands[1]) == PLUS
+ && !legitimate_la_operand_p (operands[1]))
+ {
+ operands[1] = force_operand (operands[1], operands[0]);
+ if (operands[1] == operands[0])
+ DONE;
+ }
}")
(define_insn "*movsi"
***************
*** 1835,1842 ****
; Compare a block that is less than 256 bytes in length.
(define_insn "cmpstr_const"
! [(set (reg:CCU 33)
! (compare:CCU (match_operand:BLK 0 "s_operand" "oQ")
(match_operand:BLK 1 "s_operand" "oQ")))
(use (match_operand 2 "immediate_operand" "I"))]
"(unsigned) INTVAL (operands[2]) < 256"
--- 1848,1855 ----
; Compare a block that is less than 256 bytes in length.
(define_insn "cmpstr_const"
! [(set (reg:CCS 33)
! (compare:CCS (match_operand:BLK 0 "s_operand" "oQ")
(match_operand:BLK 1 "s_operand" "oQ")))
(use (match_operand 2 "immediate_operand" "I"))]
"(unsigned) INTVAL (operands[2]) < 256"
***************
*** 1848,1855 ****
; Compare a block that is larger than 255 bytes in length.
(define_insn "cmpstr_64"
! [(set (reg:CCU 33)
! (compare:CCU (mem:BLK (subreg:DI (match_operand:TI 0 "register_operand" "d") 0))
(mem:BLK (subreg:DI (match_operand:TI 1 "register_operand" "d") 0))))
(clobber (subreg:DI (match_dup 0) 0))
(clobber (subreg:DI (match_dup 0) 8))
--- 1861,1868 ----
; Compare a block that is larger than 255 bytes in length.
(define_insn "cmpstr_64"
! [(set (reg:CCS 33)
! (compare:CCS (mem:BLK (subreg:DI (match_operand:TI 0 "register_operand" "d") 0))
(mem:BLK (subreg:DI (match_operand:TI 1 "register_operand" "d") 0))))
(clobber (subreg:DI (match_dup 0) 0))
(clobber (subreg:DI (match_dup 0) 8))
***************
*** 1862,1869 ****
(set_attr "type" "other")])
(define_insn "cmpstr_31"
! [(set (reg:CCU 33)
! (compare:CCU (mem:BLK (subreg:SI (match_operand:DI 0 "register_operand" "d") 0))
(mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "d") 0))))
(clobber (subreg:SI (match_dup 0) 0))
(clobber (subreg:SI (match_dup 0) 4))
--- 1875,1882 ----
(set_attr "type" "other")])
(define_insn "cmpstr_31"
! [(set (reg:CCS 33)
! (compare:CCS (mem:BLK (subreg:SI (match_operand:DI 0 "register_operand" "d") 0))
(mem:BLK (subreg:SI (match_operand:DI 1 "register_operand" "d") 0))))
(clobber (subreg:SI (match_dup 0) 0))
(clobber (subreg:SI (match_dup 0) 4))
***************
*** 1879,1885 ****
(define_insn "cmpint_si"
[(set (match_operand:SI 0 "register_operand" "=d")
! (compare:SI (reg:CCU 33) (const_int 0)))]
""
"*
{
--- 1892,1898 ----
(define_insn "cmpint_si"
[(set (match_operand:SI 0 "register_operand" "=d")
! (compare:SI (reg:CCS 33) (const_int 0)))]
""
"*
{
***************
*** 1896,1902 ****
(define_insn "cmpint_di"
[(set (match_operand:DI 0 "register_operand" "=d")
! (compare:DI (reg:CCU 33) (const_int 0)))]
"TARGET_64BIT"
"*
{
--- 1909,1915 ----
(define_insn "cmpint_di"
[(set (match_operand:DI 0 "register_operand" "=d")
! (compare:DI (reg:CCS 33) (const_int 0)))]
"TARGET_64BIT"
"*
{
***************
*** 2907,2982 ****
(set_attr "atype" "mem")
(set_attr "type" "la")])
- (define_insn "*addaddr_picR"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (plus:SI (match_operand:SI 1 "register_operand" "a")
- (unspec:SI [(match_operand:SI 2 "register_operand" "a")] 101)))]
- ""
- "la\\t%0,0(%1,%2)"
- [(set_attr "op_type" "RX")
- (set_attr "atype" "mem")
- (set_attr "type" "la")])
-
- (define_insn "*addaddr_picL"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (plus:SI (unspec:SI [(match_operand:SI 2 "register_operand" "a")] 101)
- (match_operand:SI 1 "register_operand" "a")))]
- ""
- "la\\t%0,0(%1,%2)"
- [(set_attr "op_type" "RX")
- (set_attr "atype" "mem")
- (set_attr "type" "la")])
-
- (define_insn "*addaddr_picN"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (unspec:SI [(match_operand:SI 1 "register_operand" "a")] 101))]
- ""
- "la\\t%0,0(%1)"
- [(set_attr "op_type" "RX")
- (set_attr "atype" "mem")
- (set_attr "type" "la")])
-
(define_insn "*addsi3_cc"
[(set (reg 33)
! (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0")
! (match_operand:SI 2 "general_operand" "d,K,m"))
(const_int 0)))
! (set (match_operand:SI 0 "register_operand" "=d,d,d")
(plus:SI (match_dup 1) (match_dup 2)))]
! "s390_match_ccmode(insn, CCSmode)"
"@
! ar\\t%0,%2
! ahi\\t%0,%h2
! a\\t%0,%2"
! [(set_attr "op_type" "RR,RI,RX")
! (set_attr "atype" "reg,reg,mem")])
(define_insn "*addsi3_cconly"
[(set (reg 33)
! (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0")
! (match_operand:SI 2 "general_operand" "d,K,m"))
(const_int 0)))
! (clobber (match_scratch:SI 0 "=d,d,d"))]
! "s390_match_ccmode(insn, CCSmode)"
"@
! ar\\t%0,%2
! ahi\\t%0,%h2
! a\\t%0,%2"
! [(set_attr "op_type" "RR,RI,RX")
! (set_attr "atype" "reg,reg,mem")])
(define_insn "*addsi3_cconly2"
[(set (reg 33)
! (compare (match_operand:SI 1 "register_operand" "%0,0,0")
! (neg:SI (match_operand:SI 2 "general_operand" "d,K,m"))))
! (clobber (match_scratch:SI 0 "=d,d,d"))]
! "s390_match_ccmode(insn, CCSmode)"
"@
! ar\\t%0,%2
! ahi\\t%0,%h2
! a\\t%0,%2"
! [(set_attr "op_type" "RR,RI,RX")
! (set_attr "atype" "reg,reg,mem")])
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
--- 2920,2963 ----
(set_attr "atype" "mem")
(set_attr "type" "la")])
(define_insn "*addsi3_cc"
[(set (reg 33)
! (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
! (match_operand:SI 2 "nonimmediate_operand" "d,m"))
(const_int 0)))
! (set (match_operand:SI 0 "register_operand" "=d,d")
(plus:SI (match_dup 1) (match_dup 2)))]
! "s390_match_ccmode(insn, CCLmode)"
"@
! alr\\t%0,%2
! al\\t%0,%2"
! [(set_attr "op_type" "RR,RX")
! (set_attr "atype" "reg,mem")])
(define_insn "*addsi3_cconly"
[(set (reg 33)
! (compare (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
! (match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
! (clobber (match_scratch:SI 0 "=d,d"))]
! "s390_match_ccmode(insn, CCLmode)"
"@
! alr\\t%0,%2
! al\\t%0,%2"
! [(set_attr "op_type" "RR,RX")
! (set_attr "atype" "reg,mem")])
(define_insn "*addsi3_cconly2"
[(set (reg 33)
! (compare (match_operand:SI 1 "register_operand" "%0,0")
! (neg:SI (match_operand:SI 2 "general_operand" "d,m"))))
! (clobber (match_scratch:SI 0 "=d,d"))]
! "s390_match_ccmode(insn, CCLmode)"
"@
! alr\\t%0,%2
! al\\t%0,%2"
! [(set_attr "op_type" "RR,RX")
! (set_attr "atype" "reg,mem")])
(define_insn "addsi3"
[(set (match_operand:SI 0 "register_operand" "=d,d,d")
***************
*** 2991,3000 ****
[(set_attr "op_type" "RR,RI,RX")
(set_attr "atype" "reg,reg,mem")])
! (define_insn "do_la"
[(set (match_operand:SI 0 "register_operand" "=a")
(match_operand:QI 1 "address_operand" "p"))]
! "volatile_ok"
"la\\t%0,%a1"
[(set_attr "op_type" "RX")
(set_attr "atype" "mem")
--- 2972,2982 ----
[(set_attr "op_type" "RR,RI,RX")
(set_attr "atype" "reg,reg,mem")])
! (define_insn "*do_la"
[(set (match_operand:SI 0 "register_operand" "=a")
(match_operand:QI 1 "address_operand" "p"))]
! "reload_in_progress || reload_completed
! || legitimate_la_operand_p (operands[1])"
"la\\t%0,%a1"
[(set_attr "op_type" "RX")
(set_attr "atype" "mem")
***************
*** 3004,3010 ****
[(set (match_operand:SI 0 "register_operand" "=d")
(plus:SI (match_operand:SI 1 "register_operand" "%0")
(match_operand:SI 2 "register_operand" "d")))]
! ""
"brxle\\t%0,%2,.+4"
[(set_attr "op_type" "RSI")
(set_attr "atype" "reg")])
--- 2986,2992 ----
[(set (match_operand:SI 0 "register_operand" "=d")
(plus:SI (match_operand:SI 1 "register_operand" "%0")
(match_operand:SI 2 "register_operand" "d")))]
! "reload_in_progress || reload_completed"
"brxle\\t%0,%2,.+4"
[(set_attr "op_type" "RSI")
(set_attr "atype" "reg")])
***************
*** 3220,3229 ****
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d,d")
(minus:SI (match_dup 1) (match_dup 2)))]
! "s390_match_ccmode(insn, CCSmode)"
"@
! sr\\t%0,%2
! s\\t%0,%2"
[(set_attr "op_type" "RR,RX")
(set_attr "atype" "reg,mem")])
--- 3202,3211 ----
(const_int 0)))
(set (match_operand:SI 0 "register_operand" "=d,d")
(minus:SI (match_dup 1) (match_dup 2)))]
! "s390_match_ccmode(insn, CCLmode)"
"@
! slr\\t%0,%2
! sl\\t%0,%2"
[(set_attr "op_type" "RR,RX")
(set_attr "atype" "reg,mem")])
***************
*** 3233,3242 ****
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=d,d"))]
! "s390_match_ccmode(insn, CCSmode)"
"@
! sr\\t%0,%2
! s\\t%0,%2"
[(set_attr "op_type" "RR,RX")
(set_attr "atype" "reg,mem")])
--- 3215,3224 ----
(match_operand:SI 2 "general_operand" "d,m"))
(const_int 0)))
(clobber (match_scratch:SI 0 "=d,d"))]
! "s390_match_ccmode(insn, CCLmode)"
"@
! slr\\t%0,%2
! sl\\t%0,%2"
[(set_attr "op_type" "RR,RX")
(set_attr "atype" "reg,mem")])
***************
*** 4940,4945 ****
--- 4922,4999 ----
[(set (reg:CCU 33) (compare:CCU (match_dup 1) (match_dup 2)))
(set (pc)
(if_then_else (leu (reg:CCU 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "bunordered"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (unordered (reg:CCS 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "bordered"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (ordered (reg:CCS 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "buneq"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (uneq (reg:CCS 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "bungt"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (ungt (reg:CCS 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "bunlt"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (unlt (reg:CCS 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "bunge"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (unge (reg:CCS 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "bunle"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (unle (reg:CCS 33) (const_int 0))
+ (label_ref (match_operand 0 "" ""))
+ (pc)))]
+ ""
+ "{ operands[1] = s390_compare_op0; operands[2] = s390_compare_op1; }")
+
+ (define_expand "bltgt"
+ [(set (reg:CCS 33) (compare:CCS (match_dup 1) (match_dup 2)))
+ (set (pc)
+ (if_then_else (ltgt (reg:CCS 33) (const_int 0))
(label_ref (match_operand 0 "" ""))
(pc)))]
""
--
Dr. Ulrich Weigand
weigand@informatik.uni-erlangen.de