aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog13
-rw-r--r--gcc/config/s390/s390-protos.h1
-rw-r--r--gcc/config/s390/s390.c95
-rw-r--r--gcc/config/s390/s390.md195
4 files changed, 261 insertions, 43 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 139c617..feb6a71 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,16 @@
+2005-10-19 Adrian Straetling <straetling@de.ibm.com>
+
+ * config/s390/s390.c (s390_expand_insv): New.
+ * config/s390/s390-protos.h (s390_expand_insv): Declare.
+ * config/s390/s390.md ("UNSPEC_SETHIGH"): Rename to "UNSPEC_ICM".
+ ("icm_hi"): Remove mode attribute.
+ ("*sethigh<mode><mode>"): Rewrite to "sethighpart<mode>".
+ Adjust all uses.
+ ("*extracthi", "*extractqi"): Remove.
+ (extv<mode>", "*extzv<mode>"): New.
+ ("insv", "*insv<mode>_mem_reg", "*insvdi_mem_reghigh",
+ "*insv<mode>_reg_imm", "*insv<mode>_reg_extimm"): New.
+
2005-10-19 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
* cfgexpand.c (discover_nonconstant_array_refs_r,
diff --git a/gcc/config/s390/s390-protos.h b/gcc/config/s390/s390-protos.h
index b18e1d1..3ae43ea 100644
--- a/gcc/config/s390/s390-protos.h
+++ b/gcc/config/s390/s390-protos.h
@@ -74,6 +74,7 @@ extern void s390_expand_movmem (rtx, rtx, rtx);
extern void s390_expand_setmem (rtx, rtx, rtx);
extern void s390_expand_cmpmem (rtx, rtx, rtx, rtx);
extern bool s390_expand_addcc (enum rtx_code, rtx, rtx, rtx, rtx, rtx);
+extern bool s390_expand_insv (rtx, rtx, rtx, rtx);
extern rtx s390_return_addr_rtx (int, rtx);
extern rtx s390_back_chain_rtx (void);
extern rtx s390_emit_call (rtx, rtx, rtx, rtx);
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 445f4e1..009c178 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -3815,6 +3815,101 @@ s390_expand_addcc (enum rtx_code cmp_code, rtx cmp_op0, rtx cmp_op1,
return false;
}
+/* Expand code for the insv template. Return true if successful, false else. */
+
+bool
+s390_expand_insv (rtx dest, rtx op1, rtx op2, rtx src)
+{
+ int bitsize = INTVAL (op1);
+ int bitpos = INTVAL (op2);
+
+ /* We need byte alignement. */
+ if (bitsize % BITS_PER_UNIT)
+ return false;
+
+ if (bitpos == 0
+ && memory_operand (dest, VOIDmode)
+ && (register_operand (src, word_mode)
+ || const_int_operand (src, VOIDmode)))
+ {
+ /* Emit standard pattern if possible. */
+ enum machine_mode mode = smallest_mode_for_size (bitsize, MODE_INT);
+ if (GET_MODE_BITSIZE (mode) == bitsize)
+ emit_move_insn (adjust_address (dest, mode, 0), gen_lowpart (mode, src));
+
+ /* (set (ze (mem)) (const_int)). */
+ else if (const_int_operand (src, VOIDmode))
+ {
+ int size = bitsize / BITS_PER_UNIT;
+ rtx src_mem = adjust_address (force_const_mem (word_mode, src), BLKmode,
+ GET_MODE_SIZE (word_mode) - size);
+
+ dest = adjust_address (dest, BLKmode, 0);
+ set_mem_size (dest, GEN_INT (size));
+ s390_expand_movmem (dest, src_mem, GEN_INT (size));
+ }
+
+ /* (set (ze (mem)) (reg)). */
+ else if (register_operand (src, word_mode))
+ {
+ if (bitsize <= GET_MODE_BITSIZE (SImode))
+ emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, op1,
+ const0_rtx), src);
+ else
+ {
+ /* Emit st,stcmh sequence. */
+ int stcmh_width = bitsize - GET_MODE_BITSIZE (SImode);
+ int size = stcmh_width / BITS_PER_UNIT;
+
+ emit_move_insn (adjust_address (dest, SImode, size),
+ gen_lowpart (SImode, src));
+ set_mem_size (dest, GEN_INT (size));
+ emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest, GEN_INT
+ (stcmh_width), const0_rtx),
+ gen_rtx_LSHIFTRT (word_mode, src, GEN_INT
+ (GET_MODE_BITSIZE (SImode))));
+ }
+ }
+ else
+ return false;
+
+ return true;
+ }
+
+ /* (set (ze (reg)) (const_int)). */
+ if (TARGET_ZARCH
+ && register_operand (dest, word_mode)
+ && (bitpos % 16) == 0
+ && (bitsize % 16) == 0
+ && const_int_operand (src, VOIDmode))
+ {
+ HOST_WIDE_INT val = INTVAL (src);
+ int regpos = bitpos + bitsize;
+
+ while (regpos > bitpos)
+ {
+ enum machine_mode putmode;
+ int putsize;
+
+ if (TARGET_EXTIMM && (regpos % 32 == 0) && (regpos >= bitpos + 32))
+ putmode = SImode;
+ else
+ putmode = HImode;
+
+ putsize = GET_MODE_BITSIZE (putmode);
+ regpos -= putsize;
+ emit_move_insn (gen_rtx_ZERO_EXTRACT (word_mode, dest,
+ GEN_INT (putsize),
+ GEN_INT (regpos)),
+ gen_int_mode (val, putmode));
+ val >>= putsize;
+ }
+ gcc_assert (regpos == bitpos);
+ return true;
+ }
+
+ return false;
+}
/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
We need to emit DTP-relative relocations. */
diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md
index baea3ff..bc9e4c3 100644
--- a/gcc/config/s390/s390.md
+++ b/gcc/config/s390/s390.md
@@ -102,7 +102,7 @@
[; Miscellaneous
(UNSPEC_ROUND 1)
(UNSPEC_CMPINT 2)
- (UNSPEC_SETHIGH 10)
+ (UNSPEC_ICM 10)
; GOT/PLT and lt-relative accesses
(UNSPEC_LTREL_OFFSET 100)
@@ -352,10 +352,6 @@
;; and "cfdbr" in SImode.
(define_mode_attr gf [(DI "g") (SI "f")])
-;; ICM mask required to load MODE value into the highest subreg
-;; of a SImode register.
-(define_mode_attr icm_hi [(HI "12") (QI "8")])
-
;; ICM mask required to load MODE value into the lowest subreg
;; of a SImode register.
(define_mode_attr icm_lo [(HI "3") (QI "1")])
@@ -2464,73 +2460,180 @@
;;- Conversion instructions.
;;
-
-(define_insn "*sethigh<mode>si"
+(define_insn "*sethighpartsi"
[(set (match_operand:SI 0 "register_operand" "=d,d")
- (unspec:SI [(match_operand:HQI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH))
+ (unspec:SI [(match_operand:BLK 1 "s_operand" "Q,S")
+ (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))]
""
"@
- icm\t%0,<icm_hi>,%S1
- icmy\t%0,<icm_hi>,%S1"
+ icm\t%0,%2,%S1
+ icmy\t%0,%2,%S1"
[(set_attr "op_type" "RS,RSY")])
-(define_insn "*sethighqidi_64"
+(define_insn "*sethighpartdi_64"
[(set (match_operand:DI 0 "register_operand" "=d")
- (unspec:DI [(match_operand:QI 1 "s_operand" "QS")] UNSPEC_SETHIGH))
+ (unspec:DI [(match_operand:BLK 1 "s_operand" "QS")
+ (match_operand 2 "const_int_operand" "n")] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))]
"TARGET_64BIT"
- "icmh\t%0,8,%S1"
+ "icmh\t%0,%2,%S1"
[(set_attr "op_type" "RSY")])
-(define_insn "*sethighqidi_31"
+(define_insn "*sethighpartdi_31"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (unspec:DI [(match_operand:QI 1 "s_operand" "Q,S")] UNSPEC_SETHIGH))
+ (unspec:DI [(match_operand:BLK 1 "s_operand" "Q,S")
+ (match_operand 2 "const_int_operand" "n,n")] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))]
"!TARGET_64BIT"
"@
- icm\t%0,8,%S1
- icmy\t%0,8,%S1"
+ icm\t%0,%2,%S1
+ icmy\t%0,%2,%S1"
[(set_attr "op_type" "RS,RSY")])
-(define_insn_and_split "*extractqi"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
- (match_operand 2 "const_int_operand" "n")
- (const_int 0)))
+(define_insn_and_split "*extzv<mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (zero_extract:GPR (match_operand:QI 1 "s_operand" "QS")
+ (match_operand 2 "const_int_operand" "n")
+ (const_int 0)))
(clobber (reg:CC CC_REGNUM))]
- "!TARGET_64BIT
- && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) < 8"
+ "INTVAL (operands[2]) > 0
+ && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
"#"
"&& reload_completed"
[(parallel
- [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH))
+ [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))])
- (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
+ (set (match_dup 0) (lshiftrt:GPR (match_dup 0) (match_dup 2)))]
{
- operands[2] = GEN_INT (32 - INTVAL (operands[2]));
- operands[1] = change_address (operands[1], QImode, 0);
+ int bitsize = INTVAL (operands[2]);
+ int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */
+ int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size);
+
+ operands[1] = adjust_address (operands[1], BLKmode, 0);
+ set_mem_size (operands[1], GEN_INT (size));
+ operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - bitsize);
+ operands[3] = GEN_INT (mask);
})
-(define_insn_and_split "*extracthi"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (zero_extract:SI (match_operand:QI 1 "s_operand" "Q")
- (match_operand 2 "const_int_operand" "n")
- (const_int 0)))
+(define_insn_and_split "*extv<mode>"
+ [(set (match_operand:GPR 0 "register_operand" "=d")
+ (sign_extract:GPR (match_operand:QI 1 "s_operand" "QS")
+ (match_operand 2 "const_int_operand" "n")
+ (const_int 0)))
(clobber (reg:CC CC_REGNUM))]
- "!TARGET_64BIT
- && INTVAL (operands[2]) >= 8 && INTVAL (operands[2]) < 16"
+ "INTVAL (operands[2]) > 0
+ && INTVAL (operands[2]) <= GET_MODE_BITSIZE (SImode)"
"#"
"&& reload_completed"
[(parallel
- [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH))
+ [(set (match_dup 0) (unspec:GPR [(match_dup 1) (match_dup 3)] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))])
- (set (match_dup 0) (lshiftrt:SI (match_dup 0) (match_dup 2)))]
+ (parallel
+ [(set (match_dup 0) (ashiftrt:GPR (match_dup 0) (match_dup 2)))
+ (clobber (reg:CC CC_REGNUM))])]
{
- operands[2] = GEN_INT (32 - INTVAL (operands[2]));
- operands[1] = change_address (operands[1], HImode, 0);
+ int bitsize = INTVAL (operands[2]);
+ int size = (bitsize - 1) / BITS_PER_UNIT + 1; /* round up */
+ int mask = ((1ul << size) - 1) << (GET_MODE_SIZE (SImode) - size);
+
+ operands[1] = adjust_address (operands[1], BLKmode, 0);
+ set_mem_size (operands[1], GEN_INT (size));
+ operands[2] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - bitsize);
+ operands[3] = GEN_INT (mask);
+})
+
+;
+; insv instruction patterns
+;
+
+(define_expand "insv"
+ [(set (zero_extract (match_operand 0 "nonimmediate_operand" "")
+ (match_operand 1 "const_int_operand" "")
+ (match_operand 2 "const_int_operand" ""))
+ (match_operand 3 "general_operand" ""))]
+ ""
+{
+ if (s390_expand_insv (operands[0], operands[1], operands[2], operands[3]))
+ DONE;
+ FAIL;
})
+(define_insn "*insv<mode>_mem_reg"
+ [(set (zero_extract:P (match_operand:QI 0 "memory_operand" "+Q,S")
+ (match_operand 1 "const_int_operand" "n,n")
+ (const_int 0))
+ (match_operand:P 2 "register_operand" "d,d"))]
+ "INTVAL (operands[1]) > 0
+ && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode)
+ && INTVAL (operands[1]) % BITS_PER_UNIT == 0"
+{
+ int size = INTVAL (operands[1]) / BITS_PER_UNIT;
+
+ operands[1] = GEN_INT ((1ul << size) - 1);
+ return (which_alternative == 0) ? "stcm\t%2,%1,%S0"
+ : "stcmy\t%2,%1,%S0";
+}
+ [(set_attr "op_type" "RS,RSY")])
+
+(define_insn "*insvdi_mem_reghigh"
+ [(set (zero_extract:DI (match_operand:QI 0 "memory_operand" "+QS")
+ (match_operand 1 "const_int_operand" "n")
+ (const_int 0))
+ (lshiftrt:DI (match_operand:DI 2 "register_operand" "d")
+ (const_int 32)))]
+ "TARGET_64BIT
+ && INTVAL (operands[1]) > 0
+ && INTVAL (operands[1]) <= GET_MODE_BITSIZE (SImode)
+ && INTVAL (operands[1]) % BITS_PER_UNIT == 0"
+{
+ int size = INTVAL (operands[1]) / BITS_PER_UNIT;
+
+ operands[1] = GEN_INT ((1ul << size) - 1);
+ return "stcmh\t%2,%1,%S0";
+}
+[(set_attr "op_type" "RSY")])
+
+(define_insn "*insv<mode>_reg_imm"
+ [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d")
+ (const_int 16)
+ (match_operand 1 "const_int_operand" "n"))
+ (match_operand:P 2 "const_int_operand" "K"))]
+ "TARGET_ZARCH
+ && INTVAL (operands[1]) >= 0
+ && INTVAL (operands[1]) < BITS_PER_WORD
+ && INTVAL (operands[1]) % 16 == 0"
+{
+ switch (BITS_PER_WORD - INTVAL (operands[1]))
+ {
+ case 64: return "iihh\t%0,%x2"; break;
+ case 48: return "iihl\t%0,%x2"; break;
+ case 32: return "iilh\t%0,%x2"; break;
+ case 16: return "iill\t%0,%x2"; break;
+ default: gcc_unreachable();
+ }
+}
+ [(set_attr "op_type" "RI")])
+
+(define_insn "*insv<mode>_reg_extimm"
+ [(set (zero_extract:P (match_operand:P 0 "register_operand" "+d")
+ (const_int 32)
+ (match_operand 1 "const_int_operand" "n"))
+ (match_operand:P 2 "const_int_operand" "Os"))]
+ "TARGET_EXTIMM
+ && INTVAL (operands[1]) >= 0
+ && INTVAL (operands[1]) < BITS_PER_WORD
+ && INTVAL (operands[1]) % 32 == 0"
+{
+ switch (BITS_PER_WORD - INTVAL (operands[1]))
+ {
+ case 64: return "iihf\t%0,%o2"; break;
+ case 32: return "iilf\t%0,%o2"; break;
+ default: gcc_unreachable();
+ }
+}
+ [(set_attr "op_type" "RIL")])
+
;
; extendsidi2 instruction pattern(s).
;
@@ -2626,12 +2729,15 @@
"#"
"&& reload_completed"
[(parallel
- [(set (match_dup 0) (unspec:DI [(match_dup 1)] UNSPEC_SETHIGH))
+ [(set (match_dup 0) (unspec:DI [(match_dup 1) (const_int 8)] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))])
(parallel
[(set (match_dup 0) (ashiftrt:DI (match_dup 0) (const_int 56)))
(clobber (reg:CC CC_REGNUM))])]
- "")
+{
+ operands[1] = adjust_address (operands[1], BLKmode, 0);
+ set_mem_size (operands[1], GEN_INT (GET_MODE_SIZE (QImode)));
+})
;
; extend(hi|qi)si2 instruction pattern(s).
@@ -2696,12 +2802,15 @@
"#"
"&& reload_completed"
[(parallel
- [(set (match_dup 0) (unspec:SI [(match_dup 1)] UNSPEC_SETHIGH))
+ [(set (match_dup 0) (unspec:SI [(match_dup 1) (const_int 8)] UNSPEC_ICM))
(clobber (reg:CC CC_REGNUM))])
(parallel
[(set (match_dup 0) (ashiftrt:SI (match_dup 0) (const_int 24)))
(clobber (reg:CC CC_REGNUM))])]
- "")
+{
+ operands[1] = adjust_address (operands[1], BLKmode, 0);
+ set_mem_size (operands[1], GEN_INT (GET_MODE_SIZE (QImode)));
+})
;
; extendqihi2 instruction pattern(s).