+2016-06-15 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/vsx.md (VSINT_84): Add DImode to enable loading
+ DImode constants with XXSPLTIB in vector registers.
+ (vsx_extract_<mode>, V2DImode/V2DFmode): Combine both
+ vsx_extract_<mode>_internal{1,2} into a single insn that handles
+ direct move (both ISA 2.07 and ISA 3.0 versions), and optimizes
+ extraction of the element at the top of the register as a scalar
+ value.
+ (vsx_extract_<mode>_internal1): Likewise.
+ (vsx_extract_<mode>_internal2): Likewise.
+ * config/rs6000/constraints.md (wi constraint): Remove a comment
+ about DImode not being allowed in Altivec registers.
+ (wB constraint): New constraint for constants that can be
+ generated in Altivec registers with VSPLTISW/VUPKHSW.
+ * config/rs6000/predicates.md (xxspltib_constant_split): Update
+ comments.
+ (xxspltib_constant_nosplit): Likewise.
+ * config/rs6000/rs6000-cpus.def (ISA_2_6_MASKS_SERVER): Add
+ support for -mupper-regs-di to enable DImode to go into Altivec
+ registers.
+ (POWERPC_MASKS): Likewise.
+ (power7 cpu): Likewise.
+ * config/rs6000/rs6000.opt (-mupper-regs-di): Likewise.
+ * config/rs6000/rs6000.c (rs6000_hard_regno_mode_ok): Add support
+ for DImode being allowed in Altivec registers. Update wi/wj
+ constraints. Set scalar_in_vmx_p flag.
+ (rs6000_option_override_internal): Add checks for -mupper-regs-di.
+ (xxspltib_constant_p): Allow CONST_INT's with VOIDmode. Don't
+ return true if we could use VSPLTISW/VUPKHSW instead of XXSPLTIB.
+ (rs6000_opt_masks): Add -mupper-regs-di.
+ * config/rs6000/rs6000.md (lfiwax): Update clobbers that don't use
+ direct move to use wi and not wj.
+ (lfiwzx): Likewise.
+ (floatsi<mode>2_lfiwax_mem): Combine alternatives into a single
+ alternative.
+ (floatunssi<mode>2_lfiwzx_mem): Likewise.
+ (fix_trunc<mode>di2_fctidz): Change second alternative to allow
+ any VSX register, instead of just Altivec registers, to allow
+ either operand to be an Altivec register or both.
+ (fixuns_trunc<mode>di2_fctiduz): Likewise.
+ (movdi_internal32): Add support for -mupper-regs-di. Add support
+ to load constants via XXSPLTIB or VSPLTISW. Add spacing to allow
+ the alternatives and attributes to be lined up to be easier to
+ read.
+ (movdi_internal64): Likewise.
+ (64-bit DImode splitters): Change predicates to only split loading
+ up GPR registers. Add splits for using XXSPLTIB or VSPLTISW to
+ load constants in ISA 3.0 or ISA 2.07 respectively.
+ * doc/invoke.texi (RS/6000 and PowerPC Options): Document
+ -mupper-regs-di. Update -mupper-regs-df and -mupper-regs-sf to
+ mention -mcpu=power9 sets these options.
+ * doc/md.texi (PowerPC and IBM RS6000 constraints): Document the
+ wB constraint.
+
2016-06-15 Pitchumani Sivanupandi <pitchumani.s@atmel.com>
PR target/67353
(define_register_constraint "wh" "rs6000_constraints[RS6000_CONSTRAINT_wh]"
"Floating point register if direct moves are available, or NO_REGS.")
-;; At present, DImode is not allowed in the Altivec registers. If in the
-;; future it is allowed, wi/wj can be set to VSX_REGS instead of FLOAT_REGS.
(define_register_constraint "wi" "rs6000_constraints[RS6000_CONSTRAINT_wi]"
"FP or VSX register to hold 64-bit integers for VSX insns or NO_REGS.")
(define_register_constraint "wz" "rs6000_constraints[RS6000_CONSTRAINT_wz]"
"Floating point register if the LFIWZX instruction is enabled or NO_REGS.")
+;; wB needs ISA 2.07 VUPKHSW
+(define_constraint "wB"
+ "Signed 5-bit constant integer that can be loaded into an altivec register."
+ (and (match_code "const_int")
+ (and (match_test "TARGET_P8_VECTOR")
+ (match_operand 0 "s5bit_cint_operand"))))
+
(define_constraint "wD"
"Int constant that is the element number of the 64-bit scalar in a vector."
(and (match_code "const_int")
}
})
-;; Return 1 if the operand is a CONST_VECTOR or VEC_DUPLICATE of a constant
-;; that can loaded with a XXSPLTIB instruction and then a VUPKHSB, VECSB2W or
-;; VECSB2D instruction.
+;; Return 1 if the operand is a constant that can loaded with a XXSPLTIB
+;; instruction and then a VUPKHSB, VECSB2W or VECSB2D instruction.
(define_predicate "xxspltib_constant_split"
(match_code "const_vector,vec_duplicate,const_int")
})
-;; Return 1 if the operand is a CONST_VECTOR that can loaded directly with a
-;; XXSPLTIB instruction.
+;; Return 1 if the operand is constant that can loaded directly with a XXSPLTIB
+;; instruction.
(define_predicate "xxspltib_constant_nosplit"
(match_code "const_vector,vec_duplicate,const_int")
| OPTION_MASK_POPCNTD \
| OPTION_MASK_ALTIVEC \
| OPTION_MASK_VSX \
+ | OPTION_MASK_UPPER_REGS_DI \
| OPTION_MASK_UPPER_REGS_DF)
/* For now, don't provide an embedded version of ISA 2.07. */
| OPTION_MASK_SOFT_FLOAT \
| OPTION_MASK_STRICT_ALIGN_OPTIONAL \
| OPTION_MASK_TOC_FUSION \
+ | OPTION_MASK_UPPER_REGS_DI \
| OPTION_MASK_UPPER_REGS_DF \
| OPTION_MASK_UPPER_REGS_SF \
| OPTION_MASK_VSX \
RS6000_CPU ("power7", PROCESSOR_POWER7, /* Don't add MASK_ISEL by default */
POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF
| MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD
- | MASK_VSX | MASK_RECIP_PRECISION | OPTION_MASK_UPPER_REGS_DF)
+ | MASK_VSX | MASK_RECIP_PRECISION | OPTION_MASK_UPPER_REGS_DF
+ | OPTION_MASK_UPPER_REGS_DI)
RS6000_CPU ("power8", PROCESSOR_POWER8, MASK_POWERPC64 | ISA_2_7_MASKS_SERVER)
RS6000_CPU ("power9", PROCESSOR_POWER9, MASK_POWERPC64 | ISA_3_0_MASKS_SERVER)
RS6000_CPU ("powerpc", PROCESSOR_POWERPC, 0)
|| FLOAT128_VECTOR_P (mode)
|| reg_addr[mode].scalar_in_vmx_p
|| (TARGET_VSX_TIMODE && mode == TImode)
- || (TARGET_VADDUQM && mode == V1TImode)))
+ || (TARGET_VADDUQM && mode == V1TImode)
+ || (TARGET_UPPER_REGS_DI && mode == DImode)))
{
if (FP_REGNO_P (regno))
return FP_REGNO_P (last_regno);
rs6000_constraints[RS6000_CONSTRAINT_wa] = VSX_REGS;
rs6000_constraints[RS6000_CONSTRAINT_wd] = VSX_REGS; /* V2DFmode */
rs6000_constraints[RS6000_CONSTRAINT_wf] = VSX_REGS; /* V4SFmode */
- rs6000_constraints[RS6000_CONSTRAINT_wi] = FLOAT_REGS; /* DImode */
if (TARGET_VSX_TIMODE)
rs6000_constraints[RS6000_CONSTRAINT_wt] = VSX_REGS; /* TImode */
}
else
rs6000_constraints[RS6000_CONSTRAINT_ws] = FLOAT_REGS;
+
+ if (TARGET_UPPER_REGS_DF) /* DImode */
+ rs6000_constraints[RS6000_CONSTRAINT_wi] = VSX_REGS;
+ else
+ rs6000_constraints[RS6000_CONSTRAINT_wi] = FLOAT_REGS;
}
/* Add conditional constraints based on various options, to allow us to
if (TARGET_UPPER_REGS_DF)
reg_addr[DFmode].scalar_in_vmx_p = true;
+ if (TARGET_UPPER_REGS_DI)
+ reg_addr[DImode].scalar_in_vmx_p = true;
+
if (TARGET_UPPER_REGS_SF)
reg_addr[SFmode].scalar_in_vmx_p = true;
}
rs6000_isa_flags &= ~OPTION_MASK_DFP;
}
- /* Allow an explicit -mupper-regs to set both -mupper-regs-df and
- -mupper-regs-sf, depending on the cpu, unless the user explicitly also set
- the individual option. */
+ /* Allow an explicit -mupper-regs to set -mupper-regs-df, -mupper-regs-di,
+ and -mupper-regs-sf, depending on the cpu, unless the user explicitly also
+ set the individual option. */
if (TARGET_UPPER_REGS > 0)
{
if (TARGET_VSX
rs6000_isa_flags |= OPTION_MASK_UPPER_REGS_DF;
rs6000_isa_flags_explicit |= OPTION_MASK_UPPER_REGS_DF;
}
+ if (TARGET_VSX
+ && !(rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_DI))
+ {
+ rs6000_isa_flags |= OPTION_MASK_UPPER_REGS_DI;
+ rs6000_isa_flags_explicit |= OPTION_MASK_UPPER_REGS_DI;
+ }
if (TARGET_P8_VECTOR
&& !(rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_SF))
{
rs6000_isa_flags &= ~OPTION_MASK_UPPER_REGS_DF;
rs6000_isa_flags_explicit |= OPTION_MASK_UPPER_REGS_DF;
}
+ if (TARGET_VSX
+ && !(rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_DI))
+ {
+ rs6000_isa_flags &= ~OPTION_MASK_UPPER_REGS_DI;
+ rs6000_isa_flags_explicit |= OPTION_MASK_UPPER_REGS_DI;
+ }
if (TARGET_P8_VECTOR
&& !(rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_SF))
{
rs6000_isa_flags &= ~OPTION_MASK_UPPER_REGS_DF;
}
+ if (TARGET_UPPER_REGS_DI && !TARGET_VSX)
+ {
+ if (rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_DF)
+ error ("-mupper-regs-di requires -mvsx");
+ rs6000_isa_flags &= ~OPTION_MASK_UPPER_REGS_DF;
+ }
+
if (TARGET_UPPER_REGS_SF && !TARGET_P8_VECTOR)
{
if (rs6000_isa_flags_explicit & OPTION_MASK_UPPER_REGS_SF)
if (TARGET_FLOAT128_HW
&& (rs6000_isa_flags & (OPTION_MASK_P9_VECTOR
| OPTION_MASK_DIRECT_MOVE
+ | OPTION_MASK_UPPER_REGS_DI
| OPTION_MASK_UPPER_REGS_DF
| OPTION_MASK_UPPER_REGS_SF)) == 0)
{
if (mode == VOIDmode)
mode = GET_MODE (op);
- else if (mode != GET_MODE (op))
+ else if (mode != GET_MODE (op) && GET_MODE (op) != VOIDmode)
return false;
/* Handle (vec_duplicate <constant>). */
}
/* Handle integer constants being loaded into the upper part of the VSX
- register as a scalar. If the value isn't 0/-1, only allow it if
- the mode can go in Altivec registers. */
+ register as a scalar. If the value isn't 0/-1, only allow it if the mode
+ can go in Altivec registers. Prefer VSPLTISW/VUPKHSW over XXSPLITIB. */
else if (CONST_INT_P (op))
{
if (!SCALAR_INT_MODE_P (mode))
if (!IN_RANGE (value, -128, 127))
return false;
- if (!IN_RANGE (value, -1, 0)
- && (reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID) == 0)
- return false;
+ if (!IN_RANGE (value, -1, 0))
+ {
+ if (!(reg_addr[mode].addr_mask[RELOAD_REG_VMX] & RELOAD_REG_VALID))
+ return false;
+
+ if (EASY_VECTOR_15 (value))
+ return false;
+ }
}
else
{ "string", OPTION_MASK_STRING, false, true },
{ "toc-fusion", OPTION_MASK_TOC_FUSION, false, true },
{ "update", OPTION_MASK_NO_UPDATE, true , true },
+ { "upper-regs-di", OPTION_MASK_UPPER_REGS_DI, false, true },
{ "upper-regs-df", OPTION_MASK_UPPER_REGS_DF, false, true },
{ "upper-regs-sf", OPTION_MASK_UPPER_REGS_SF, false, true },
{ "vsx", OPTION_MASK_VSX, false, true },
(define_insn_and_split "floatsi<mode>2_lfiwax"
[(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Fv>")
(float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r")))
- (clobber (match_scratch:DI 2 "=wj"))]
+ (clobber (match_scratch:DI 2 "=wi"))]
"TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
&& <SI_CONVERT_FP> && can_create_pseudo_p ()"
"#"
(set_attr "type" "fpload")])
(define_insn_and_split "floatsi<mode>2_lfiwax_mem"
- [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Ff>,<Fa>")
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Fv>")
(float:SFDF
(sign_extend:DI
- (match_operand:SI 1 "indexed_or_indirect_operand" "Z,Z"))))
- (clobber (match_scratch:DI 2 "=0,d"))]
+ (match_operand:SI 1 "indexed_or_indirect_operand" "Z"))))
+ (clobber (match_scratch:DI 2 "=wi"))]
"TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
&& <SI_CONVERT_FP>"
"#"
(define_insn_and_split "floatunssi<mode>2_lfiwzx"
[(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Fv>")
(unsigned_float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r")))
- (clobber (match_scratch:DI 2 "=wj"))]
+ (clobber (match_scratch:DI 2 "=wi"))]
"TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
&& <SI_CONVERT_FP>"
"#"
(set_attr "type" "fpload")])
(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem"
- [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Ff>,<Fa>")
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<Fv>")
(unsigned_float:SFDF
(zero_extend:DI
- (match_operand:SI 1 "indexed_or_indirect_operand" "Z,Z"))))
- (clobber (match_scratch:DI 2 "=0,d"))]
+ (match_operand:SI 1 "indexed_or_indirect_operand" "Z"))))
+ (clobber (match_scratch:DI 2 "=wi"))]
"TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
&& <SI_CONVERT_FP>"
"#"
(define_insn "*fix_trunc<mode>di2_fctidz"
[(set (match_operand:DI 0 "gpc_reg_operand" "=d,wi")
- (fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "<Ff>,<Fa>")))]
+ (fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "<Ff>,<Fv>")))]
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
&& TARGET_FCFID"
"@
(define_insn "*fixuns_trunc<mode>di2_fctiduz"
[(set (match_operand:DI 0 "gpc_reg_operand" "=d,wi")
- (unsigned_fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "<Ff>,<Fa>")))]
+ (unsigned_fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "<Ff>,<Fv>")))]
"TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
&& TARGET_FCTIDUZ"
"@
;; non-offsettable address by using r->r which won't make progress.
;; Use of fprs is disparaged slightly otherwise reload prefers to reload
;; a gpr into a fpr instead of reloading an invalid 'Y' address
+
+;; GPR store GPR load GPR move FPR store FPR load FPR move
+;; GPR const AVX store AVX store AVX load AVX load VSX move
+;; P9 0 P9 -1 AVX 0/-1 VSX 0 VSX -1 P9 const
+;; AVX const
+
(define_insn "*movdi_internal32"
- [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=Y,r,r,?m,?*d,?*d,r")
- (match_operand:DI 1 "input_operand" "r,Y,r,d,m,d,IJKnGHF"))]
+ [(set (match_operand:DI 0 "rs6000_nonimmediate_operand"
+ "=Y, r, r, ?m, ?*d, ?*d,
+ r, ?Y, ?Z, ?*wb, ?*wv, ?wi,
+ ?wo, ?wo, ?wv, ?wi, ?wi, ?wv,
+ ?wv")
+
+ (match_operand:DI 1 "input_operand"
+ "r, Y, r, d, m, d,
+ IJKnGHF, wb, wv, Y, Z, wi,
+ Oj, wM, OjwM, Oj, wM, wS,
+ wB"))]
+
"! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
+ #
+ stxsd %1,%0
+ stxsdx %x1,%y0
+ lxsd %0,%1
+ lxsdx %x0,%y1
+ xxlor %x0,%x1,%x1
+ xxspltib %x0,0
+ xxspltib %x0,255
+ vspltisw %0,%1
+ xxlxor %x0,%x0,%x0
+ xxlorc %x0,%x0,%x0
+ #
#"
- [(set_attr "type" "store,load,*,fpstore,fpload,fp,*")])
+ [(set_attr "type"
+ "store, load, *, fpstore, fpload, fp,
+ *, fpstore, fpstore, fpload, fpload, vecsimple,
+ vecsimple, vecsimple, vecsimple, vecsimple, vecsimple, vecsimple,
+ vecsimple")])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
[(pc)]
{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; })
+;; GPR store GPR load GPR move GPR li GPR lis GPR #
+;; FPR store FPR load FPR move AVX store AVX store AVX load
+;; AVX load VSX move P9 0 P9 -1 AVX 0/-1 VSX 0
+;; VSX -1 P9 const AVX const From SPR To SPR SPR<->SPR
+;; FPR->GPR GPR->FPR VSX->GPR GPR->VSX
(define_insn "*movdi_internal64"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=Y,r,r,r,r,r,?m,?*d,?*d,r,*h,*h,r,?*wg,r,?*wj,?*wi")
- (match_operand:DI 1 "input_operand" "r,Y,r,I,L,nF,d,m,d,*h,r,0,*wg,r,*wj,r,O"))]
+ [(set (match_operand:DI 0 "nonimmediate_operand"
+ "=Y, r, r, r, r, r,
+ ?m, ?*d, ?*d, ?Y, ?Z, ?*wb,
+ ?*wv, ?wi, ?wo, ?wo, ?wv, ?wi,
+ ?wi, ?wv, ?wv, r, *h, *h,
+ ?*r, ?*wg, ?*r, ?*wj")
+
+ (match_operand:DI 1 "input_operand"
+ "r, Y, r, I, L, nF,
+ d, m, d, wb, wv, Y,
+ Z, wi, Oj, wM, OjwM, Oj,
+ wM, wS, wB, *h, r, 0,
+ wg, r, wj, r"))]
+
"TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], DImode)
|| gpc_reg_operand (operands[1], DImode))"
stfd%U0%X0 %1,%0
lfd%U1%X1 %0,%1
fmr %0,%1
+ stxsd %1,%0
+ stxsdx %x1,%y0
+ lxsd %0,%1
+ lxsdx %x0,%y1
+ xxlor %x0,%x1,%x1
+ xxspltib %x0,0
+ xxspltib %x0,255
+ vspltisw %0,%1
+ xxlxor %x0,%x0,%x0
+ xxlorc %x0,%x0,%x0
+ #
+ #
mf%1 %0
mt%0 %1
nop
mftgpr %0,%1
mffgpr %0,%1
mfvsrd %0,%x1
- mtvsrd %x0,%1
- xxlxor %x0,%x0,%x0"
- [(set_attr "type" "store,load,*,*,*,*,fpstore,fpload,fp,mfjmpr,mtjmpr,*,mftgpr,mffgpr,mftgpr,mffgpr,vecsimple")
- (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4,4,4,4")])
+ mtvsrd %x0,%1"
+ [(set_attr "type"
+ "store, load, *, *, *, *,
+ fpstore, fpload, fp, fpstore, fpstore, fpload,
+ fpload, vecsimple, vecsimple, vecsimple, vecsimple, vecsimple,
+ vecsimple, vecsimple, vecsimple, mfjmpr, mtjmpr, *,
+ mftgpr, mffgpr, mftgpr, mffgpr")
+
+ (set_attr "length"
+ "4, 4, 4, 4, 4, 20,
+ 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 8,
+ 8, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4")])
; Some DImode loads are best done as a load of -1 followed by a mask
; instruction.
(define_split
- [(set (match_operand:DI 0 "gpc_reg_operand")
+ [(set (match_operand:DI 0 "int_reg_operand_not_pseudo")
(match_operand:DI 1 "const_int_operand"))]
"TARGET_POWERPC64
&& num_insns_constant (operands[1], DImode) > 1
;; When non-easy constants can go in the TOC, this should use
;; easy_fp_constant predicate.
(define_split
- [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ [(set (match_operand:DI 0 "int_reg_operand_not_pseudo" "")
(match_operand:DI 1 "const_int_operand" ""))]
"TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1"
[(set (match_dup 0) (match_dup 2))
}")
(define_split
- [(set (match_operand:DI 0 "gpc_reg_operand" "")
+ [(set (match_operand:DI 0 "int_reg_operand_not_pseudo" "")
(match_operand:DI 1 "const_scalar_int_operand" ""))]
"TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1"
[(set (match_dup 0) (match_dup 2))
else
FAIL;
}")
+
+(define_split
+ [(set (match_operand:DI 0 "altivec_register_operand" "")
+ (match_operand:DI 1 "s5bit_cint_operand" ""))]
+ "TARGET_UPPER_REGS_DI && TARGET_VSX && reload_completed"
+ [(const_int 0)]
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ int r = REGNO (op0);
+ rtx op0_v4si = gen_rtx_REG (V4SImode, r);
+
+ emit_insn (gen_altivec_vspltisw (op0_v4si, op1));
+ if (op1 != const0_rtx && op1 != constm1_rtx)
+ {
+ rtx op0_v2di = gen_rtx_REG (V2DImode, r);
+ emit_insn (gen_altivec_vupkhsw (op0_v2di, op0_v4si));
+ }
+ DONE;
+})
+
+(define_split
+ [(set (match_operand:DI 0 "altivec_register_operand" "")
+ (match_operand:DI 1 "xxspltib_constant_split" ""))]
+ "TARGET_UPPER_REGS_DI && TARGET_P9_VECTOR && reload_completed"
+ [(const_int 0)]
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+ int r = REGNO (op0);
+ rtx op0_v16qi = gen_rtx_REG (V16QImode, r);
+
+ emit_insn (gen_xxspltib_v16qi (op0_v16qi, op1));
+ emit_insn (gen_vsx_sign_extend_qi_di (operands[0], op0_v16qi));
+ DONE;
+})
+
\f
;; TImode/PTImode is similar, except that we usually want to compute the
;; address into a register and use lsi/stsi (the exception is during reload).
Target Report Var(TARGET_UPPER_REGS) Init(-1) Save
Allow float/double variables in upper registers if cpu allows it.
+mupper-regs-di
+Target Report Mask(UPPER_REGS_DI) Var(rs6000_isa_flags)
+Allow 64-bit integer variables in upper registers with -mcpu=power7 or -mvsx.
+
moptimize-swaps
Target Undocumented Var(rs6000_optimize_swaps) Init(1) Save
Analyze and remove doubleword swaps from VSX computations.
(V2DI "wi")])
;; Iterators for loading constants with xxspltib
-(define_mode_iterator VSINT_84 [V4SI V2DI])
+(define_mode_iterator VSINT_84 [V4SI V2DI DI])
(define_mode_iterator VSINT_842 [V8HI V4SI V2DI])
;; Constants for creating unspecs
[(set_attr "type" "vecperm")])
;; Extract a DF/DI element from V2DF/V2DI
-(define_expand "vsx_extract_<mode>"
- [(set (match_operand:<VS_scalar> 0 "register_operand" "")
- (vec_select:<VS_scalar> (match_operand:VSX_D 1 "register_operand" "")
- (parallel
- [(match_operand:QI 2 "u5bit_cint_operand" "")])))]
- "VECTOR_MEM_VSX_P (<MODE>mode)"
- "")
-
;; Optimize cases were we can do a simple or direct move.
;; Or see if we can avoid doing the move at all
-(define_insn "*vsx_extract_<mode>_internal1"
- [(set (match_operand:<VS_scalar> 0 "register_operand" "=d,<VS_64reg>,r,r")
+
+;; There are some unresolved problems with reload that show up if an Altivec
+;; register was picked. Limit the scalar value to FPRs for now.
+
+(define_insn "vsx_extract_<mode>"
+ [(set (match_operand:<VS_scalar> 0 "gpc_reg_operand"
+ "=d, wm, wo, d")
+
(vec_select:<VS_scalar>
- (match_operand:VSX_D 1 "register_operand" "d,<VS_64reg>,<VS_64dm>,<VS_64dm>")
+ (match_operand:VSX_D 1 "gpc_reg_operand"
+ "<VSa>, <VSa>, <VSa>, <VSa>")
+
(parallel
- [(match_operand:QI 2 "vsx_scalar_64bit" "wD,wD,wD,wL")])))]
- "VECTOR_MEM_VSX_P (<MODE>mode) && TARGET_POWERPC64 && TARGET_DIRECT_MOVE"
+ [(match_operand:QI 2 "const_0_to_1_operand"
+ "wD, wD, wL, n")])))]
+ "VECTOR_MEM_VSX_P (<MODE>mode)"
{
+ int element = INTVAL (operands[2]);
int op0_regno = REGNO (operands[0]);
int op1_regno = REGNO (operands[1]);
+ int fldDM;
- if (op0_regno == op1_regno)
- return "nop";
-
- if (INT_REGNO_P (op0_regno))
- return ((INTVAL (operands[2]) == VECTOR_ELEMENT_MFVSRLD_64BIT)
- ? "mfvsrdl %0,%x1"
- : "mfvsrd %0,%x1");
+ gcc_assert (IN_RANGE (element, 0, 1));
+ gcc_assert (VSX_REGNO_P (op1_regno));
- if (FP_REGNO_P (op0_regno) && FP_REGNO_P (op1_regno))
- return "fmr %0,%1";
+ if (element == VECTOR_ELEMENT_SCALAR_64BIT)
+ {
+ if (op0_regno == op1_regno)
+ return ASM_COMMENT_START " vec_extract to same register";
- return "xxlor %x0,%x1,%x1";
-}
- [(set_attr "type" "fp,vecsimple,mftgpr,mftgpr")
- (set_attr "length" "4")])
+ else if (INT_REGNO_P (op0_regno) && TARGET_DIRECT_MOVE
+ && TARGET_POWERPC64)
+ return "mfvsrd %0,%x1";
-(define_insn "*vsx_extract_<mode>_internal2"
- [(set (match_operand:<VS_scalar> 0 "vsx_register_operand" "=d,<VS_64reg>,<VS_64reg>")
- (vec_select:<VS_scalar>
- (match_operand:VSX_D 1 "vsx_register_operand" "d,wd,wd")
- (parallel [(match_operand:QI 2 "u5bit_cint_operand" "wD,wD,i")])))]
- "VECTOR_MEM_VSX_P (<MODE>mode)
- && (!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE
- || INTVAL (operands[2]) != VECTOR_ELEMENT_SCALAR_64BIT)"
-{
- int fldDM;
- gcc_assert (UINTVAL (operands[2]) <= 1);
+ else if (FP_REGNO_P (op0_regno) && FP_REGNO_P (op1_regno))
+ return "fmr %0,%1";
- if (INTVAL (operands[2]) == VECTOR_ELEMENT_SCALAR_64BIT)
- {
- int op0_regno = REGNO (operands[0]);
- int op1_regno = REGNO (operands[1]);
+ else if (VSX_REGNO_P (op0_regno))
+ return "xxlor %x0,%x1,%x1";
- if (op0_regno == op1_regno)
- return "nop";
+ else
+ gcc_unreachable ();
+ }
- if (FP_REGNO_P (op0_regno) && FP_REGNO_P (op1_regno))
- return "fmr %0,%1";
+ else if (element == VECTOR_ELEMENT_MFVSRLD_64BIT && INT_REGNO_P (op0_regno)
+ && TARGET_P9_VECTOR && TARGET_POWERPC64 && TARGET_DIRECT_MOVE)
+ return "mfvsrdl %0,%x1";
- return "xxlor %x0,%x1,%x1";
+ else if (VSX_REGNO_P (op0_regno))
+ {
+ fldDM = element << 1;
+ if (!BYTES_BIG_ENDIAN)
+ fldDM = 3 - fldDM;
+ operands[3] = GEN_INT (fldDM);
+ return "xxpermdi %x0,%x1,%x1,%3";
}
- fldDM = INTVAL (operands[2]) << 1;
- if (!BYTES_BIG_ENDIAN)
- fldDM = 3 - fldDM;
- operands[3] = GEN_INT (fldDM);
- return "xxpermdi %x0,%x1,%x1,%3";
+ else
+ gcc_unreachable ();
}
- [(set_attr "type" "fp,vecsimple,vecperm")
- (set_attr "length" "4")])
+ [(set_attr "type" "vecsimple,mftgpr,mftgpr,vecperm")])
;; Optimize extracting a single scalar element from memory if the scalar is in
;; the correct location to use a single load.
-mquad-memory-atomic -mno-quad-memory-atomic @gol
-mcompat-align-parm -mno-compat-align-parm @gol
-mupper-regs-df -mno-upper-regs-df -mupper-regs-sf -mno-upper-regs-sf @gol
+-mupper-regs-di -mno-upper-regs-di @gol
-mupper-regs -mno-upper-regs -mmodulo -mno-modulo @gol
-mfloat128 -mno-float128 -mfloat128-hardware -mno-float128-hardware @gol
-mpower9-fusion -mno-mpower9-fusion -mpower9-vector -mno-power9-vector @gol
instructions. The @option{-mquad-memory-atomic} option requires use of
64-bit mode.
+@item -mupper-regs-di
+@itemx -mno-upper-regs-di
+@opindex mupper-regs-di
+@opindex mno-upper-regs-di
+Generate code that uses (does not use) the scalar instructions that
+target all 64 registers in the vector/scalar floating point register
+set that were added in version 2.06 of the PowerPC ISA when processing
+integers. @option{-mupper-regs-di} is turned on by default if you use
+any of the @option{-mcpu=power7}, @option{-mcpu=power8},
+@option{-mcpu=power9}, or @option{-mvsx} options.
+
@item -mupper-regs-df
@itemx -mno-upper-regs-df
@opindex mupper-regs-df
instructions that target all 64 registers in the vector/scalar
floating point register set that were added in version 2.06 of the
PowerPC ISA. @option{-mupper-regs-df} is turned on by default if you
-use any of the @option{-mcpu=power7}, @option{-mcpu=power8}, or
-@option{-mvsx} options.
+use any of the @option{-mcpu=power7}, @option{-mcpu=power8},
+@option{-mcpu=power9}, or @option{-mvsx} options.
@item -mupper-regs-sf
@itemx -mno-upper-regs-sf
instructions that target all 64 registers in the vector/scalar
floating point register set that were added in version 2.07 of the
PowerPC ISA. @option{-mupper-regs-sf} is turned on by default if you
-use either of the @option{-mcpu=power8} or @option{-mpower8-vector}
-options.
+use either of the @option{-mcpu=power8}, @option{-mpower8-vector}, or
+@option{-mpower9} options.
@item -mupper-regs
@itemx -mno-upper-regs
@item wz
Floating point register if the LFIWZX instruction is enabled or NO_REGS.
+@item wB
+Signed 5-bit constant integer that can be loaded into an altivec register.
+
@item wD
Int constant that is the element number of the 64-bit scalar in a vector.
+2016-06-15 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * gcc.target/powerpc/p9-dimode1.c: New test.
+ * gcc.target/powerpc/p9-dimode2.c: Likewise.
+
2016-06-15 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/compile/20160615-1.c: New test.
--- /dev/null
+/* { dg-do compile { target { powerpc64*-*-* && lp64 } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -mupper-regs-di" } */
+
+/* Verify P9 changes to allow DImode into Altivec registers, and generate
+ constants using XXSPLTIB. */
+
+#ifndef _ARCH_PPC64
+#error "This code is 64-bit."
+#endif
+
+double
+p9_zero (void)
+{
+ long l = 0;
+ double ret;
+
+ __asm__ ("xxlor %x0,%x1,%x1" : "=&d" (ret) : "wi" (l));
+
+ return ret;
+}
+
+double
+p9_plus_1 (void)
+{
+ long l = 1;
+ double ret;
+
+ __asm__ ("xxlor %x0,%x1,%x1" : "=&d" (ret) : "wi" (l));
+
+ return ret;
+}
+
+double
+p9_minus_1 (void)
+{
+ long l = -1;
+ double ret;
+
+ __asm__ ("xxlor %x0,%x1,%x1" : "=&d" (ret) : "wi" (l));
+
+ return ret;
+}
+
+/* { dg-final { scan-assembler "xxspltib" } } */
+/* { dg-final { scan-assembler-not "mtvsrd" } } */
+/* { dg-final { scan-assembler-not "lfd" } } */
+/* { dg-final { scan-assembler-not "ld" } } */
+/* { dg-final { scan-assembler-not "lxsd" } } */
--- /dev/null
+/* { dg-do compile { target { powerpc64*-*-* && lp64 } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mcpu=power9 -O2 -mupper-regs-di" } */
+
+/* Verify that large integer constants are loaded via direct move instead of being
+ loaded from memory. */
+
+#ifndef _ARCH_PPC64
+#error "This code is 64-bit."
+#endif
+
+double
+p9_large (void)
+{
+ long l = 0x12345678;
+ double ret;
+
+ __asm__ ("xxlor %x0,%x1,%x1" : "=&d" (ret) : "wi" (l));
+
+ return ret;
+}
+
+/* { dg-final { scan-assembler "mtvsrd" } } */
+/* { dg-final { scan-assembler-not "ld" } } */
+/* { dg-final { scan-assembler-not "lfd" } } */
+/* { dg-final { scan-assembler-not "lxsd" } } */