aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/vsx.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000/vsx.md')
-rw-r--r--gcc/config/rs6000/vsx.md87
1 files changed, 87 insertions, 0 deletions
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index 4fa7f6a..2e1d41d 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -263,6 +263,21 @@
(define_mode_iterator VSINT_84 [V4SI V2DI DI])
(define_mode_iterator VSINT_842 [V8HI V4SI V2DI])
+;; Iterator for ISA 3.0 vector extract/insert of integer vectors
+(define_mode_iterator VSX_EXTRACT_I [V16QI V8HI V4SI])
+
+;; Mode attribute to give the correct predicate for ISA 3.0 vector extract and
+;; insert to validate the operand number.
+(define_mode_attr VSX_EXTRACT_PREDICATE [(V16QI "const_0_to_15_operand")
+ (V8HI "const_0_to_7_operand")
+ (V4SI "const_0_to_3_operand")])
+
+;; Mode attribute to give the constraint for vector extract and insert
+;; operations.
+(define_mode_attr VSX_EX [(V16QI "v")
+ (V8HI "v")
+ (V4SI "wa")])
+
;; Constants for creating unspecs
(define_c_enum "unspec"
[UNSPEC_VSX_CONCAT
@@ -2322,6 +2337,78 @@
FAIL;
})
+;; Extraction of a single element in a small integer vector. None of the small
+;; types are currently allowed in a vector register, so we extract to a DImode
+;; and either do a direct move or store.
+(define_insn_and_split "vsx_extract_<mode>"
+ [(set (match_operand:<VS_scalar> 0 "nonimmediate_operand" "=r,Z")
+ (vec_select:<VS_scalar>
+ (match_operand:VSX_EXTRACT_I 1 "gpc_reg_operand" "<VSX_EX>,<VSX_EX>")
+ (parallel [(match_operand:QI 2 "<VSX_EXTRACT_PREDICATE>" "n,n")])))
+ (clobber (match_scratch:DI 3 "=<VSX_EX>,<VSX_EX>"))]
+ "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_VEXTRACTUB"
+ "#"
+ "&& (reload_completed || MEM_P (operands[0]))"
+ [(const_int 0)]
+{
+ rtx dest = operands[0];
+ rtx src = operands[1];
+ rtx element = operands[2];
+ rtx di_tmp = operands[3];
+
+ if (GET_CODE (di_tmp) == SCRATCH)
+ di_tmp = gen_reg_rtx (DImode);
+
+ emit_insn (gen_vsx_extract_<mode>_di (di_tmp, src, element));
+
+ if (REG_P (dest))
+ emit_move_insn (gen_rtx_REG (DImode, REGNO (dest)), di_tmp);
+ else if (SUBREG_P (dest))
+ emit_move_insn (gen_rtx_REG (DImode, subreg_regno (dest)), di_tmp);
+ else if (MEM_P (operands[0]))
+ {
+ if (can_create_pseudo_p ())
+ dest = rs6000_address_for_fpconvert (dest);
+
+ if (<MODE>mode == V16QImode)
+ emit_insn (gen_p9_stxsibx (dest, di_tmp));
+ else if (<MODE>mode == V8HImode)
+ emit_insn (gen_p9_stxsihx (dest, di_tmp));
+ else if (<MODE>mode == V4SImode)
+ emit_insn (gen_stfiwx (dest, di_tmp));
+ else
+ gcc_unreachable ();
+ }
+ else
+ gcc_unreachable ();
+
+ DONE;
+}
+ [(set_attr "type" "vecsimple,fpstore")])
+
+(define_insn "vsx_extract_<mode>_di"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=<VSX_EX>")
+ (zero_extend:DI
+ (vec_select:<VS_scalar>
+ (match_operand:VSX_EXTRACT_I 1 "gpc_reg_operand" "<VSX_EX>")
+ (parallel [(match_operand:QI 2 "<VSX_EXTRACT_PREDICATE>" "n")]))))]
+ "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_VEXTRACTUB"
+{
+ int element = INTVAL (operands[2]);
+ int unit_size = GET_MODE_UNIT_SIZE (<MODE>mode);
+ int offset = ((VECTOR_ELT_ORDER_BIG)
+ ? unit_size * element
+ : unit_size * (GET_MODE_NUNITS (<MODE>mode) - 1 - element));
+
+ operands[2] = GEN_INT (offset);
+ if (unit_size == 4)
+ return "xxextractuw %x0,%x1,%2";
+ else
+ return "vextractu<wd> %0,%1,%2";
+}
+ [(set_attr "type" "vecsimple")])
+
+
;; Expanders for builtins
(define_expand "vsx_mergel_<mode>"
[(use (match_operand:VSX_D 0 "vsx_register_operand" ""))