aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/s390
diff options
context:
space:
mode:
authorJerry DeLisle <jvdelisle@gcc.gnu.org>2025-09-02 15:58:26 -0700
committerJerry DeLisle <jvdelisle@gcc.gnu.org>2025-09-02 15:58:26 -0700
commit071b4126c613881f4cb25b4e5c39032964827f88 (patch)
tree7ed805786566918630d1d617b1ed8f7310f5fd8e /gcc/config/s390
parent845d23f3ea08ba873197c275a8857eee7edad996 (diff)
parentcaa1c2f42691d68af4d894a5c3e700ecd2dba080 (diff)
downloadgcc-devel/gfortran-test.zip
gcc-devel/gfortran-test.tar.gz
gcc-devel/gfortran-test.tar.bz2
Merge branch 'master' into gfortran-testdevel/gfortran-test
Diffstat (limited to 'gcc/config/s390')
-rw-r--r--gcc/config/s390/s390-protos.h2
-rw-r--r--gcc/config/s390/s390.cc198
-rw-r--r--gcc/config/s390/s390.md67
-rw-r--r--gcc/config/s390/vector.md84
4 files changed, 274 insertions, 77 deletions
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index d760a7e..6becad1 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -128,6 +128,8 @@ extern void s390_expand_vcond (rtx, rtx, rtx, enum rtx_code, rtx, rtx);
extern void s390_expand_vec_init (rtx, rtx);
extern rtx s390_expand_merge_perm_const (machine_mode, bool);
extern void s390_expand_merge (rtx, rtx, rtx, bool);
+extern void s390_expand_int_spaceship (rtx, rtx, rtx, rtx);
+extern void s390_expand_fp_spaceship (rtx, rtx, rtx, rtx);
extern rtx s390_build_signbit_mask (machine_mode);
extern rtx s390_return_addr_rtx (int, rtx);
extern rtx s390_back_chain_rtx (void);
diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index abe551c..1a47f47 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -8213,6 +8213,167 @@ s390_expand_atomic (machine_mode mode, enum rtx_code code,
NULL_RTX, 1, OPTAB_DIRECT), 1);
}
+/* Expand integer op0 = op1 <=> op2, i.e.,
+ op0 = op1 == op2 ? 0 : op1 < op2 ? -1 : 1.
+
+ Signedness is specified by op3. If op3 equals 1, then perform an unsigned
+ comparison, and if op3 equals -1, then perform a signed comparison.
+
+ For integer comparisons we strive for a sequence like
+ CR[L] ; LHI ; LOCHIL ; LOCHIH
+ where the first three instructions fit into a group. */
+
+void
+s390_expand_int_spaceship (rtx op0, rtx op1, rtx op2, rtx op3)
+{
+ gcc_assert (op3 == const1_rtx || op3 == constm1_rtx);
+
+ rtx cc, cond_lt, cond_gt;
+ machine_mode cc_mode;
+ machine_mode mode = GET_MODE (op1);
+
+ /* Prior VXE3 emulate a 128-bit comparison by breaking it up into three
+ comparisons. First test the high halfs. In case they equal, then test
+ the low halfs. Finally, test for equality. Depending on the results
+ make use of LOCs. */
+ if (mode == TImode && !TARGET_VXE3)
+ {
+ gcc_assert (TARGET_VX);
+ op1
+ = force_reg (V2DImode, simplify_gen_subreg (V2DImode, op1, TImode, 0));
+ op2
+ = force_reg (V2DImode, simplify_gen_subreg (V2DImode, op2, TImode, 0));
+ rtx lab = gen_label_rtx ();
+ rtx ccz = gen_rtx_REG (CCZmode, CC_REGNUM);
+ /* Compare high halfs for equality.
+ VEC[L]G op1, op2 sets
+ CC1 if high(op1) < high(op2)
+ and
+ CC2 if high(op1) > high(op2). */
+ machine_mode cc_mode = op3 == const1_rtx ? CCUmode : CCSmode;
+ rtx lane0 = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (1, const0_rtx));
+ emit_insn (gen_rtx_SET (
+ gen_rtx_REG (cc_mode, CC_REGNUM),
+ gen_rtx_COMPARE (cc_mode,
+ gen_rtx_VEC_SELECT (DImode, op1, lane0),
+ gen_rtx_VEC_SELECT (DImode, op2, lane0))));
+ s390_emit_jump (lab, gen_rtx_NE (CCZmode, ccz, const0_rtx));
+ /* At this point we know that the high halfs equal.
+ VCHLGS op2, op1 sets CC1 if low(op1) < low(op2) */
+ emit_insn (gen_rtx_PARALLEL (
+ VOIDmode,
+ gen_rtvec (2,
+ gen_rtx_SET (gen_rtx_REG (CCVIHUmode, CC_REGNUM),
+ gen_rtx_COMPARE (CCVIHUmode, op2, op1)),
+ gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (V2DImode)))));
+ emit_label (lab);
+ emit_insn (gen_rtx_SET (op0, const1_rtx));
+ emit_insn (
+ gen_movsicc (op0,
+ gen_rtx_LTU (CCUmode, gen_rtx_REG (CCUmode, CC_REGNUM),
+ const0_rtx),
+ constm1_rtx, op0));
+ /* Deal with the case where both halfs equal. */
+ emit_insn (gen_rtx_PARALLEL (
+ VOIDmode,
+ gen_rtvec (2,
+ gen_rtx_SET (gen_rtx_REG (CCVEQmode, CC_REGNUM),
+ gen_rtx_COMPARE (CCVEQmode, op1, op2)),
+ gen_rtx_SET (gen_reg_rtx (V2DImode),
+ gen_rtx_EQ (V2DImode, op1, op2)))));
+ emit_insn (gen_movsicc (op0, gen_rtx_EQ (CCZmode, ccz, const0_rtx),
+ const0_rtx, op0));
+ return;
+ }
+
+ if (mode == QImode || mode == HImode)
+ {
+ rtx_code extend = op3 == const1_rtx ? ZERO_EXTEND : SIGN_EXTEND;
+ op1 = simplify_gen_unary (extend, SImode, op1, mode);
+ op1 = force_reg (SImode, op1);
+ op2 = simplify_gen_unary (extend, SImode, op2, mode);
+ op2 = force_reg (SImode, op2);
+ mode = SImode;
+ }
+
+ if (op3 == const1_rtx)
+ {
+ cc_mode = CCUmode;
+ cc = gen_rtx_REG (cc_mode, CC_REGNUM);
+ cond_lt = gen_rtx_LTU (mode, cc, const0_rtx);
+ cond_gt = gen_rtx_GTU (mode, cc, const0_rtx);
+ }
+ else
+ {
+ cc_mode = CCSmode;
+ cc = gen_rtx_REG (cc_mode, CC_REGNUM);
+ cond_lt = gen_rtx_LT (mode, cc, const0_rtx);
+ cond_gt = gen_rtx_GT (mode, cc, const0_rtx);
+ }
+
+ emit_insn (gen_rtx_SET (cc, gen_rtx_COMPARE (cc_mode, op1, op2)));
+ emit_move_insn (op0, const0_rtx);
+ emit_insn (gen_movsicc (op0, cond_lt, constm1_rtx, op0));
+ emit_insn (gen_movsicc (op0, cond_gt, const1_rtx, op0));
+}
+
+/* Expand floating-point op0 = op1 <=> op2, i.e.,
+ op0 = op1 == op2 ? 0 : op1 < op2 ? -1 : op1 > op2 ? 1 : -128.
+
+ If op3 equals const0_rtx, then we are interested in the compare only (see
+ test spaceship-fp-4.c). Otherwise, op3 is a CONST_INT different than
+ const1_rtx and constm1_rtx which is used in order to set op0 for unordered.
+
+ Emit a branch-only solution, i.e., let if-convert fold the branches into
+ LOCs if applicable. This has the benefit that the solution is also
+ applicable if we are only interested in the compare, i.e., if op3 equals
+ const0_rtx.
+ */
+
+void
+s390_expand_fp_spaceship (rtx op0, rtx op1, rtx op2, rtx op3)
+{
+ gcc_assert (op3 != const1_rtx && op3 != constm1_rtx);
+
+ machine_mode mode = GET_MODE (op1);
+ machine_mode cc_mode = s390_select_ccmode (LTGT, op1, op2);
+ rtx cc_reg = gen_rtx_REG (cc_mode, CC_REGNUM);
+ rtx cond_unordered = gen_rtx_UNORDERED (mode, cc_reg, const0_rtx);
+ rtx cond_eq = gen_rtx_EQ (mode, cc_reg, const0_rtx);
+ rtx cond_gt = gen_rtx_GT (mode, cc_reg, const0_rtx);
+ rtx_insn *insn;
+ rtx l_unordered = gen_label_rtx ();
+ rtx l_eq = gen_label_rtx ();
+ rtx l_gt = gen_label_rtx ();
+ rtx l_end = gen_label_rtx ();
+
+ s390_emit_compare (VOIDmode, LTGT, op1, op2);
+ if (!flag_finite_math_only)
+ {
+ insn = s390_emit_jump (l_unordered, cond_unordered);
+ add_reg_br_prob_note (insn, profile_probability::very_unlikely ());
+ }
+ insn = s390_emit_jump (l_eq, cond_eq);
+ add_reg_br_prob_note (insn, profile_probability::unlikely ());
+ insn = s390_emit_jump (l_gt, cond_gt);
+ add_reg_br_prob_note (insn, profile_probability::even ());
+ emit_move_insn (op0, constm1_rtx);
+ emit_jump (l_end);
+ emit_label (l_eq);
+ emit_move_insn (op0, const0_rtx);
+ emit_jump (l_end);
+ emit_label (l_gt);
+ emit_move_insn (op0, const1_rtx);
+ if (!flag_finite_math_only)
+ {
+ emit_jump (l_end);
+ emit_label (l_unordered);
+ rtx unord_val = op3 == const0_rtx ? GEN_INT (-128) : op3;
+ emit_move_insn (op0, unord_val);
+ }
+ emit_label (l_end);
+}
+
/* This is called from dwarf2out.cc via TARGET_ASM_OUTPUT_DWARF_DTPREL.
We need to emit DTP-relative relocations. */
@@ -9078,15 +9239,12 @@ print_operand (FILE *file, rtx x, int code)
else if (code == 'h')
fprintf (file, HOST_WIDE_INT_PRINT_DEC,
((CONST_WIDE_INT_ELT (x, 0) & 0xffff) ^ 0x8000) - 0x8000);
+ /* Support arbitrary _BitInt constants in asm statements. */
+ else if (code == 0)
+ output_addr_const (file, x);
else
- {
- if (code == 0)
- output_operand_lossage ("invalid constant - try using "
- "an output modifier");
- else
- output_operand_lossage ("invalid constant for output modifier '%c'",
- code);
- }
+ output_operand_lossage ("invalid constant for output modifier '%c'",
+ code);
break;
case CONST_VECTOR:
switch (code)
@@ -18607,6 +18765,27 @@ s390_c_mode_for_floating_type (enum tree_index ti)
return default_mode_for_floating_type (ti);
}
+/* Return true if _BitInt(N) is supported and fill its details into *INFO. */
+
+bool
+s390_bitint_type_info (int n, struct bitint_info *info)
+{
+ if (!TARGET_64BIT)
+ return false;
+ if (n <= 8)
+ info->limb_mode = QImode;
+ else if (n <= 16)
+ info->limb_mode = HImode;
+ else if (n <= 32)
+ info->limb_mode = SImode;
+ else
+ info->limb_mode = DImode;
+ info->abi_limb_mode = info->limb_mode;
+ info->big_endian = true;
+ info->extended = true;
+ return true;
+}
+
/* Initialize GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
@@ -18928,6 +19107,9 @@ s390_c_mode_for_floating_type (enum tree_index ti)
#undef TARGET_DOCUMENTATION_NAME
#define TARGET_DOCUMENTATION_NAME "S/390"
+#undef TARGET_C_BITINT_TYPE_INFO
+#define TARGET_C_BITINT_TYPE_INFO s390_bitint_type_info
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-s390.h"
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index 1edbfde..858387c 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -1527,6 +1527,27 @@
operands[0] = SET_DEST (PATTERN (curr_insn));
})
+; Restrict spaceship optab to z13 or later since there we have
+; LOAD HALFWORD IMMEDIATE ON CONDITION.
+
+(define_mode_iterator SPACESHIP_INT [(TI "TARGET_VX") DI SI HI QI])
+(define_expand "spaceship<mode>4"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SPACESHIP_INT 1 "register_operand")
+ (match_operand:SPACESHIP_INT 2 "register_operand")
+ (match_operand:SI 3 "const_int_operand")]
+ "TARGET_Z13 && TARGET_64BIT"
+ "s390_expand_int_spaceship (operands[0], operands[1], operands[2], operands[3]); DONE;")
+
+(define_mode_iterator SPACESHIP_BFP [TF DF SF])
+(define_expand "spaceship<mode>4"
+ [(match_operand:SI 0 "register_operand")
+ (match_operand:SPACESHIP_BFP 1 "register_operand")
+ (match_operand:SPACESHIP_BFP 2 "register_operand")
+ (match_operand:SI 3 "const_int_operand")]
+ "TARGET_Z13 && TARGET_64BIT && TARGET_HARD_FLOAT"
+ "s390_expand_fp_spaceship (operands[0], operands[1], operands[2], operands[3]); DONE;")
+
; (TF|DF|SF|TD|DD|SD) instructions
@@ -5227,18 +5248,19 @@
})
(define_insn "*zero_extendsidi2"
- [(set (match_operand:DI 0 "register_operand" "=d,d,d")
- (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,T,b")))]
+ [(set (match_operand:DI 0 "register_operand" "=d,d,d,d")
+ (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "d,T,b,v")))]
"TARGET_ZARCH"
"@
llgfr\t%0,%1
llgf\t%0,%1
- llgfrl\t%0,%1"
- [(set_attr "op_type" "RRE,RXY,RIL")
- (set_attr "type" "*,*,larl")
- (set_attr "cpu_facility" "*,*,z10")
- (set_attr "z10prop" "z10_fwd_E1,z10_fwd_A3,z10_fwd_A3")
- (set_attr "relative_long" "*,*,yes")])
+ llgfrl\t%0,%1
+ vlgvf\t%0,%v1,0"
+ [(set_attr "op_type" "RRE,RXY,RIL,VRS")
+ (set_attr "type" "*,*,larl,*")
+ (set_attr "cpu_facility" "*,*,z10,vx")
+ (set_attr "z10prop" "z10_fwd_E1,z10_fwd_A3,z10_fwd_A3,*")
+ (set_attr "relative_long" "*,*,yes,*")])
;
; LLGT-type instructions (zero-extend from 31 bit to 64 bit).
@@ -5341,29 +5363,32 @@
; llhrl, llghrl
(define_insn "*zero_extendhi<mode>2_z10"
- [(set (match_operand:GPR 0 "register_operand" "=d,d,d")
- (zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" "d,T,b")))]
+ [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d")
+ (zero_extend:GPR (match_operand:HI 1 "nonimmediate_operand" "d,T,b,v")))]
"TARGET_Z10"
"@
ll<g>hr\t%0,%1
ll<g>h\t%0,%1
- ll<g>hrl\t%0,%1"
- [(set_attr "op_type" "RXY,RRE,RIL")
- (set_attr "type" "*,*,larl")
- (set_attr "cpu_facility" "*,*,z10")
- (set_attr "z10prop" "z10_super_E1,z10_fwd_A3,z10_fwd_A3")
- (set_attr "relative_long" "*,*,yes")])
+ ll<g>hrl\t%0,%1
+ vlgvh\t%0,%v1,0"
+ [(set_attr "op_type" "RXY,RRE,RIL,VRS")
+ (set_attr "type" "*,*,larl,*")
+ (set_attr "cpu_facility" "*,*,z10,vx")
+ (set_attr "z10prop" "z10_super_E1,z10_fwd_A3,z10_fwd_A3,*")
+ (set_attr "relative_long" "*,*,yes,*")])
; llhr, llcr, llghr, llgcr, llh, llc, llgh, llgc
(define_insn "*zero_extend<HQI:mode><GPR:mode>2_extimm"
- [(set (match_operand:GPR 0 "register_operand" "=d,d")
- (zero_extend:GPR (match_operand:HQI 1 "nonimmediate_operand" "d,T")))]
+ [(set (match_operand:GPR 0 "register_operand" "=d,d,d")
+ (zero_extend:GPR (match_operand:HQI 1 "nonimmediate_operand" "d,T,v")))]
"TARGET_EXTIMM"
"@
ll<g><hc>r\t%0,%1
- ll<g><hc>\t%0,%1"
- [(set_attr "op_type" "RRE,RXY")
- (set_attr "z10prop" "z10_super_E1,z10_fwd_A3")])
+ ll<g><hc>\t%0,%1
+ vlgv<HQI:bhfgq>\t%0,%v1,0"
+ [(set_attr "op_type" "RRE,RXY,VRS")
+ (set_attr "cpu_facility" "*,*,vx")
+ (set_attr "z10prop" "z10_super_E1,z10_fwd_A3,*")])
; llgh, llgc
(define_insn "*zero_extend<HQI:mode><GPR:mode>2"
diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md
index 12bbeb6..745634e 100644
--- a/gcc/config/s390/vector.md
+++ b/gcc/config/s390/vector.md
@@ -501,54 +501,6 @@
SIL,SIL,RI,RI,RRE,RRE,RIL,RR,RXY,RXY,RIL")])
-; Instructions vlgvb, vlgvh, vlgvf zero all remaining bits of a GPR, i.e.,
-; an implicit zero extend is done.
-
-(define_insn "*movdi<mode>_zero_extend_A"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (zero_extend:DI (match_operand:SINT 1 "register_operand" "v")))]
- "TARGET_VX"
- "vlgv<bhfgq>\t%0,%v1,0"
- [(set_attr "op_type" "VRS")])
-
-(define_insn "*movsi<mode>_zero_extend_A"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extend:SI (match_operand:HQI 1 "register_operand" "v")))]
- "TARGET_VX"
- "vlgv<bhfgq>\t%0,%v1,0"
- [(set_attr "op_type" "VRS")])
-
-(define_mode_iterator VLGV_DI [V1QI V2QI V4QI V8QI V16QI
- V1HI V2HI V4HI V8HI
- V1SI V2SI V4SI])
-(define_insn "*movdi<mode>_zero_extend_B"
- [(set (match_operand:DI 0 "register_operand" "=d")
- (zero_extend:DI (vec_select:<non_vec>
- (match_operand:VLGV_DI 1 "register_operand" "v")
- (parallel [(match_operand:SI 2 "const_int_operand" "n")]))))]
- "TARGET_VX"
-{
- operands[2] = GEN_INT (UINTVAL (operands[2]) & (GET_MODE_NUNITS (<MODE>mode) - 1));
- return "vlgv<bhfgq>\t%0,%v1,%Y2";
-}
- [(set_attr "op_type" "VRS")
- (set_attr "mnemonic" "vlgv<bhfgq>")])
-
-(define_mode_iterator VLGV_SI [V1QI V2QI V4QI V8QI V16QI
- V1HI V2HI V4HI V8HI])
-(define_insn "*movsi<mode>_zero_extend_B"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extend:SI (vec_select:<non_vec>
- (match_operand:VLGV_SI 1 "register_operand" "v")
- (parallel [(match_operand:SI 2 "const_int_operand" "n")]))))]
- "TARGET_VX"
-{
- operands[2] = GEN_INT (UINTVAL (operands[2]) & (GET_MODE_NUNITS (<MODE>mode) - 1));
- return "vlgv<bhfgq>\t%0,%v1,%Y2";
-}
- [(set_attr "op_type" "VRS")
- (set_attr "mnemonic" "vlgv<bhfgq>")])
-
; vec_load_lanes?
; vec_store_lanes?
@@ -763,6 +715,42 @@
DONE;
})
+; Instructions vlgvb, vlgvh, vlgvf zero all remaining bits of a GPR, i.e.,
+; an implicit zero extend is done.
+
+(define_mode_iterator VLGV_DI [V1QI V2QI V4QI V8QI V16QI
+ V1HI V2HI V4HI V8HI
+ V1SI V2SI V4SI])
+(define_insn "*vec_extract<mode>_zero_extend"
+ [(set (match_operand:DI 0 "register_operand" "=d")
+ (zero_extend:DI (vec_select:<non_vec>
+ (match_operand:VLGV_DI 1 "register_operand" "v")
+ (parallel [(match_operand:SI 2 "nonmemory_operand" "an")]))))]
+ "TARGET_VX"
+{
+ if (CONST_INT_P (operands[2]))
+ operands[2] = GEN_INT (UINTVAL (operands[2]) & (GET_MODE_NUNITS (<MODE>mode) - 1));
+ return "vlgv<bhfgq>\t%0,%v1,%Y2";
+}
+ [(set_attr "op_type" "VRS")
+ (set_attr "mnemonic" "vlgv<bhfgq>")])
+
+(define_mode_iterator VLGV_SI [V1QI V2QI V4QI V8QI V16QI
+ V1HI V2HI V4HI V8HI])
+(define_insn "*vec_extract<mode>_zero_extend"
+ [(set (match_operand:SI 0 "register_operand" "=d")
+ (zero_extend:SI (vec_select:<non_vec>
+ (match_operand:VLGV_SI 1 "register_operand" "v")
+ (parallel [(match_operand:SI 2 "nonmemory_operand" "an")]))))]
+ "TARGET_VX"
+{
+ if (CONST_INT_P (operands[2]))
+ operands[2] = GEN_INT (UINTVAL (operands[2]) & (GET_MODE_NUNITS (<MODE>mode) - 1));
+ return "vlgv<bhfgq>\t%0,%v1,%Y2";
+}
+ [(set_attr "op_type" "VRS")
+ (set_attr "mnemonic" "vlgv<bhfgq>")])
+
(define_insn "*vec_vllezlf<mode>"
[(set (match_operand:V_HW_4 0 "register_operand" "=v")
(vec_concat:V_HW_4