* config/nvptx/nvptx-protos.h (nvptx_output_mov_insn): Declare.
(nvptx_underlying_object_mode): Delete.
* config/nvptx/nvptx.c (nvptx_underlying_object_mode): Delete.
(output_reg): New.
(nvptx_declare_function_name): Use output_reg. Remove punning
buffer.
(nvptx_output_mov_insn): New.
(nvptx_print_operand): Separate SUBREG handling, remove 'f' case,
Use output_reg. Merge 't' and 'u' handling.
* config/nvptx/nvptx.h (NVPTX_PUNNING_BUFFER_REGNUM): Delete.
(struct machine_function): Remvoe punning_buffer_size.
(REGISTER_NAMES): Remove %punbuffer.
* config/nvptx/nvptx.md (UNSPEC_CPLX_LOWPART,
UNSPEC_CPLX_HIGHPART): Delete.
(*mov<mode>_insn [QHSDIM): Remove unnecessary constraints, use
nvptx_output_mov_insn.
(*mov<mode>_insn [SDFM): Reorder constraints to match integer
moc. Use nvptx_output_mov_insn.
(highpartscsf2, set_highpartscsf2, lowpartscsf2,
set_lowpartscsf2): Delete.
(mov<mode> [SDCM]): Delete.
From-SVN: r231180
+2015-12-02 Nathan Sidwell <nathan@acm.org>
+
+ * config/nvptx/nvptx-protos.h (nvptx_output_mov_insn): Declare.
+ (nvptx_underlying_object_mode): Delete.
+ * config/nvptx/nvptx.c (nvptx_underlying_object_mode): Delete.
+ (output_reg): New.
+ (nvptx_declare_function_name): Use output_reg. Remove punning
+ buffer.
+ (nvptx_output_mov_insn): New.
+ (nvptx_print_operand): Separate SUBREG handling, remove 'f' case,
+ Use output_reg. Merge 't' and 'u' handling.
+ * config/nvptx/nvptx.h (NVPTX_PUNNING_BUFFER_REGNUM): Delete.
+ (struct machine_function): Remvoe punning_buffer_size.
+ (REGISTER_NAMES): Remove %punbuffer.
+ * config/nvptx/nvptx.md (UNSPEC_CPLX_LOWPART,
+ UNSPEC_CPLX_HIGHPART): Delete.
+ (*mov<mode>_insn [QHSDIM): Remove unnecessary constraints, use
+ nvptx_output_mov_insn.
+ (*mov<mode>_insn [SDFM): Reorder constraints to match integer
+ moc. Use nvptx_output_mov_insn.
+ (highpartscsf2, set_highpartscsf2, lowpartscsf2,
+ set_lowpartscsf2): Delete.
+ (mov<mode> [SDCM]): Delete.
+
2015-12-02 Richard Biener <rguenther@suse.de>
* tree.h (tree_invariant_p): Declare.
extern void nvptx_expand_call (rtx, rtx);
extern rtx nvptx_expand_compare (rtx);
extern const char *nvptx_ptx_type_from_mode (machine_mode, bool);
+extern const char *nvptx_output_mov_insn (rtx, rtx);
extern const char *nvptx_output_call_insn (rtx_insn *, rtx, rtx);
extern const char *nvptx_output_return (void);
-extern machine_mode nvptx_underlying_object_mode (rtx);
extern const char *nvptx_section_from_addr_space (addr_space_t);
extern bool nvptx_hard_regno_mode_ok (int, machine_mode);
extern rtx nvptx_maybe_convert_symbolic_operand (rtx);
worker_red_align = GET_MODE_ALIGNMENT (SImode) / BITS_PER_UNIT;
}
-/* Return the mode to be used when declaring a ptx object for OBJ.
- For objects with subparts such as complex modes this is the mode
- of the subpart. */
-
-machine_mode
-nvptx_underlying_object_mode (rtx obj)
-{
- if (GET_CODE (obj) == SUBREG)
- obj = SUBREG_REG (obj);
- machine_mode mode = GET_MODE (obj);
- if (mode == TImode)
- return DImode;
- if (COMPLEX_MODE_P (mode))
- return GET_MODE_INNER (mode);
- return mode;
-}
-
/* Return a ptx type for MODE. If PROMOTE, then use .u32 for QImode to
deal with ptx ideosyncracies. */
return VOIDmode;
}
+/* Output a register, subreg, or register pair (with optional
+ enclosing braces). */
+
+static void
+output_reg (FILE *file, unsigned regno, machine_mode inner_mode,
+ int subreg_offset = -1)
+{
+ if (inner_mode == VOIDmode)
+ {
+ if (HARD_REGISTER_NUM_P (regno))
+ fprintf (file, "%s", reg_names[regno]);
+ else
+ fprintf (file, "%%r%d", regno);
+ }
+ else if (subreg_offset >= 0)
+ {
+ output_reg (file, regno, VOIDmode);
+ fprintf (file, "$%d", subreg_offset);
+ }
+ else
+ {
+ if (subreg_offset == -1)
+ fprintf (file, "{");
+ output_reg (file, regno, inner_mode, GET_MODE_SIZE (inner_mode));
+ fprintf (file, ",");
+ output_reg (file, regno, inner_mode, 0);
+ if (subreg_offset == -1)
+ fprintf (file, "}");
+ }
+}
+
/* Emit forking instructions for MASK. */
static void
{
machine_mode mode = PSEUDO_REGNO_MODE (i);
machine_mode split = maybe_split_mode (mode);
+
if (split != VOIDmode)
- {
- fprintf (file, "\t.reg%s %%r%d$%d;\n",
- nvptx_ptx_type_from_mode (split, true), i, 0);
- fprintf (file, "\t.reg%s %%r%d$%d;\n",
- nvptx_ptx_type_from_mode (split, true), i, 1);
- }
- else
- fprintf (file, "\t.reg%s %%r%d;\n",
- nvptx_ptx_type_from_mode (mode, true), i);
+ mode = split;
+ fprintf (file, "\t.reg%s ", nvptx_ptx_type_from_mode (mode, true));
+ output_reg (file, i, split, -2);
+ fprintf (file, ";\n");
}
}
BITS_PER_WORD);
}
- if (cfun->machine->punning_buffer_size > 0)
- {
- fprintf (file, "\t.reg.u%d %%punbuffer;\n"
- "\t.local.align 8 .b8 %%punbuffer_ar[%d];\n",
- BITS_PER_WORD, cfun->machine->punning_buffer_size);
- fprintf (file, "\tcvta.local.u%d %%punbuffer, %%punbuffer_ar;\n",
- BITS_PER_WORD);
- }
-
/* Declare a local variable for the frame. */
sz = get_frame_size ();
if (sz > 0 || cfun->machine->has_call_with_sc)
/* Implement TARGET_ASM_ASSEMBLE_UNDEFINED_DECL. Write an extern
declaration only for variable DECL with NAME to FILE. */
+
static void
nvptx_assemble_undefined_decl (FILE *file, const char *name, const_tree decl)
{
fprintf (file, ";\n\n");
}
+/* Output a pattern for a move instruction. */
+
+const char *
+nvptx_output_mov_insn (rtx dst, rtx src)
+{
+ machine_mode dst_mode = GET_MODE (dst);
+ machine_mode dst_inner = (GET_CODE (dst) == SUBREG
+ ? GET_MODE (XEXP (dst, 0)) : dst_mode);
+ machine_mode src_inner = (GET_CODE (src) == SUBREG
+ ? GET_MODE (XEXP (src, 0)) : dst_mode);
+
+ if (REG_P (dst) && REGNO (dst) == NVPTX_RETURN_REGNUM && dst_mode == HImode)
+ /* Special handling for the return register. It's never really an
+ HI object, and only occurs as the destination of a move
+ insn. */
+ dst_inner = SImode;
+
+ if (src_inner == dst_inner)
+ return "%.\tmov%t0\t%0, %1;";
+
+ if (CONSTANT_P (src))
+ return (GET_MODE_CLASS (dst_inner) == MODE_INT
+ && GET_MODE_CLASS (src_inner) != MODE_FLOAT
+ ? "%.\tmov%t0\t%0, %1;" : "%.\tmov.b%T0\t%0, %1;");
+
+ if (GET_MODE_SIZE (dst_inner) == GET_MODE_SIZE (src_inner))
+ return "%.\tmov.b%T0\t%0, %1;";
+
+ return "%.\tcvt%t0%t1\t%0, %1;";
+}
+
/* Output INSN, which is a call to CALLEE with result RESULT. For ptx, this
involves writing .param declarations and in/out copies into them. For
indirect calls, also write the .callprototype. */
A -- print an address space identifier for a MEM
c -- print an opcode suffix for a comparison operator, including a type code
- f -- print a full reg even for something that must always be split
S -- print a shuffle kind specified by CONST_INT
t -- print a type opcode suffix, promoting QImode to 32 bits
T -- print a type size in bits
static void
nvptx_print_operand (FILE *file, rtx x, int code)
{
- rtx orig_x = x;
- machine_mode op_mode;
-
if (code == '.')
{
x = current_insn_predicate;
}
enum rtx_code x_code = GET_CODE (x);
+ machine_mode mode = GET_MODE (x);
switch (code)
{
break;
case 't':
- op_mode = nvptx_underlying_object_mode (x);
- fprintf (file, "%s", nvptx_ptx_type_from_mode (op_mode, true));
- break;
-
case 'u':
- op_mode = nvptx_underlying_object_mode (x);
- fprintf (file, "%s", nvptx_ptx_type_from_mode (op_mode, false));
+ if (x_code == SUBREG)
+ {
+ mode = GET_MODE (SUBREG_REG (x));
+ if (mode == TImode)
+ mode = DImode;
+ else if (COMPLEX_MODE_P (mode))
+ mode = GET_MODE_INNER (mode);
+ }
+ fprintf (file, "%s", nvptx_ptx_type_from_mode (mode, code == 't'));
break;
case 'S':
break;
case 'T':
- fprintf (file, "%d", GET_MODE_BITSIZE (GET_MODE (x)));
+ fprintf (file, "%d", GET_MODE_BITSIZE (mode));
break;
case 'j':
goto common;
case 'c':
- op_mode = GET_MODE (XEXP (x, 0));
+ mode = GET_MODE (XEXP (x, 0));
switch (x_code)
{
case EQ:
fputs (".eq", file);
break;
case NE:
- if (FLOAT_MODE_P (op_mode))
+ if (FLOAT_MODE_P (mode))
fputs (".neu", file);
else
fputs (".ne", file);
default:
gcc_unreachable ();
}
- if (FLOAT_MODE_P (op_mode)
+ if (FLOAT_MODE_P (mode)
|| x_code == EQ || x_code == NE
|| x_code == GEU || x_code == GTU
|| x_code == LEU || x_code == LTU)
- fputs (nvptx_ptx_type_from_mode (op_mode, true), file);
+ fputs (nvptx_ptx_type_from_mode (mode, true), file);
else
- fprintf (file, ".s%d", GET_MODE_BITSIZE (op_mode));
+ fprintf (file, ".s%d", GET_MODE_BITSIZE (mode));
break;
default:
common:
switch (x_code)
{
case SUBREG:
- x = SUBREG_REG (x);
- /* fall through */
+ {
+ rtx inner_x = SUBREG_REG (x);
+ machine_mode inner_mode = GET_MODE (inner_x);
+ machine_mode split = maybe_split_mode (inner_mode);
+
+ if (split != VOIDmode
+ && (GET_MODE_SIZE (inner_mode) == GET_MODE_SIZE (mode)))
+ output_reg (file, REGNO (inner_x), split);
+ else
+ output_reg (file, REGNO (inner_x), split, SUBREG_BYTE (x));
+ }
+ break;
case REG:
- if (HARD_REGISTER_P (x))
- fprintf (file, "%s", reg_names[REGNO (x)]);
- else
- fprintf (file, "%%r%d", REGNO (x));
- if (code != 'f' && maybe_split_mode (GET_MODE (x)) != VOIDmode)
- {
- gcc_assert (GET_CODE (orig_x) == SUBREG
- && maybe_split_mode (GET_MODE (orig_x)) == VOIDmode);
- fprintf (file, "$%d", SUBREG_BYTE (orig_x) / UNITS_PER_WORD);
- }
+ output_reg (file, REGNO (x), maybe_split_mode (mode));
break;
case MEM:
fputc ('[', file);
- nvptx_print_address_operand (file, XEXP (x, 0), GET_MODE (x));
+ nvptx_print_address_operand (file, XEXP (x, 0), mode);
fputc (']', file);
break;
case CONST_DOUBLE:
long vals[2];
- real_to_target (vals, CONST_DOUBLE_REAL_VALUE (x), GET_MODE (x));
+ real_to_target (vals, CONST_DOUBLE_REAL_VALUE (x), mode);
vals[0] &= 0xffffffff;
vals[1] &= 0xffffffff;
- if (GET_MODE (x) == SFmode)
+ if (mode == SFmode)
fprintf (file, "0f%08lx", vals[0]);
else
fprintf (file, "0d%08lx%08lx", vals[1], vals[0]);
#define STACK_POINTER_REGNUM 1
#define HARD_FRAME_POINTER_REGNUM 2
-#define NVPTX_PUNNING_BUFFER_REGNUM 3
#define NVPTX_RETURN_REGNUM 4
#define FRAME_POINTER_REGNUM 15
#define ARG_POINTER_REGNUM 14
bool has_call_with_sc;
HOST_WIDE_INT outgoing_stdarg_size;
int ret_reg_mode; /* machine_mode not defined yet. */
- int punning_buffer_size;
rtx axis_predicate[2];
};
#endif
#define REGISTER_NAMES \
{ \
- "%hr0", "%outargs", "%hfp", "%punbuffer", "%retval", "%retval_in", "%hr6", "%hr7", \
+ "%hr0", "%outargs", "%hfp", "%hr3", "%retval", "%retval_in", "%hr6", "%hr7", \
"%hr8", "%hr9", "%hr10", "%hr11", "%hr12", "%hr13", "%argp", "%frame" \
}
UNSPEC_TO_SHARED
UNSPEC_TO_CONST
- UNSPEC_CPLX_LOWPART
- UNSPEC_CPLX_HIGHPART
-
UNSPEC_COPYSIGN
UNSPEC_LOG2
UNSPEC_EXP2
%.\\tsetp.eq.u32\\t%0, 1, 1;")
(define_insn "*mov<mode>_insn"
- [(set (match_operand:QHSDIM 0 "nvptx_nonimmediate_operand" "=R,R,R,m")
- (match_operand:QHSDIM 1 "general_operand" "n,Ri,m,R"))]
- "!(MEM_P (operands[0])
- && (!REG_P (operands[1]) || REGNO (operands[1]) <= LAST_VIRTUAL_REGISTER))"
+ [(set (match_operand:QHSDIM 0 "nvptx_nonimmediate_operand" "=R,R,m")
+ (match_operand:QHSDIM 1 "general_operand" "Ri,m,R"))]
+ "!MEM_P (operands[0])
+ || (REG_P (operands[1]) && REGNO (operands[1]) > LAST_VIRTUAL_REGISTER)"
{
- if (which_alternative == 2)
+ if (which_alternative == 1)
return "%.\\tld%A1%u1\\t%0, %1;";
- if (which_alternative == 3)
+ if (which_alternative == 2)
return "%.\\tst%A0%u0\\t%0, %1;";
- rtx dst = operands[0];
- rtx src = operands[1];
-
- enum machine_mode dst_mode = nvptx_underlying_object_mode (dst);
- enum machine_mode src_mode = nvptx_underlying_object_mode (src);
- if (GET_CODE (dst) == SUBREG)
- dst = SUBREG_REG (dst);
- if (GET_CODE (src) == SUBREG)
- src = SUBREG_REG (src);
- if (src_mode == QImode)
- src_mode = SImode;
- if (dst_mode == QImode)
- dst_mode = SImode;
- if (CONSTANT_P (src))
- {
- if (GET_MODE_CLASS (dst_mode) != MODE_INT)
- return "%.\\tmov.b%T0\\t%0, %1;";
- else
- return "%.\\tmov%t0\\t%0, %1;";
- }
-
- /* Special handling for the return register; we allow this register to
- only occur in the destination of a move insn. */
- if (REG_P (dst) && REGNO (dst) == NVPTX_RETURN_REGNUM
- && dst_mode == HImode)
- dst_mode = SImode;
- if (dst_mode == src_mode)
- return "%.\\tmov%t0\\t%0, %1;";
- /* Mode-punning between floating point and integer. */
- if (GET_MODE_SIZE (dst_mode) == GET_MODE_SIZE (src_mode))
- return "%.\\tmov.b%T0\\t%0, %1;";
- return "%.\\tcvt%t0%t1\\t%0, %1;";
+ return nvptx_output_mov_insn (operands[0], operands[1]);
}
[(set_attr "subregs_ok" "true")])
(define_insn "*mov<mode>_insn"
[(set (match_operand:SDFM 0 "nvptx_nonimmediate_operand" "=R,R,m")
(match_operand:SDFM 1 "general_operand" "RF,m,R"))]
- "!(MEM_P (operands[0]) && !REG_P (operands[1]))"
+ "!MEM_P (operands[0]) || REG_P (operands[1])"
{
if (which_alternative == 1)
return "%.\\tld%A1%u0\\t%0, %1;";
if (which_alternative == 2)
return "%.\\tst%A0%u1\\t%0, %1;";
- rtx dst = operands[0];
- rtx src = operands[1];
- if (GET_CODE (dst) == SUBREG)
- dst = SUBREG_REG (dst);
- if (GET_CODE (src) == SUBREG)
- src = SUBREG_REG (src);
- enum machine_mode dst_mode = GET_MODE (dst);
- enum machine_mode src_mode = GET_MODE (src);
- if (dst_mode == src_mode)
- return "%.\\tmov%t0\\t%0, %1;";
- if (GET_MODE_SIZE (dst_mode) == GET_MODE_SIZE (src_mode))
- return "%.\\tmov.b%T0\\t%0, %1;";
- gcc_unreachable ();
+ return nvptx_output_mov_insn (operands[0], operands[1]);
}
[(set_attr "subregs_ok" "true")])
}
})
-(define_insn "highpartscsf2"
- [(set (match_operand:SF 0 "nvptx_register_operand" "=R")
- (unspec:SF [(match_operand:SC 1 "nvptx_register_operand")]
- UNSPEC_CPLX_HIGHPART))]
- ""
- "%.\\tmov%t0\\t%0, %f1$1;")
-
-(define_insn "set_highpartsfsc2"
- [(set (match_operand:SC 0 "nvptx_register_operand" "+R")
- (unspec:SC [(match_dup 0)
- (match_operand:SF 1 "nvptx_register_operand")]
- UNSPEC_CPLX_HIGHPART))]
- ""
- "%.\\tmov%t1\\t%f0$1, %1;")
-
-(define_insn "lowpartscsf2"
- [(set (match_operand:SF 0 "nvptx_register_operand" "=R")
- (unspec:SF [(match_operand:SC 1 "nvptx_register_operand")]
- UNSPEC_CPLX_LOWPART))]
- ""
- "%.\\tmov%t0\\t%0, %f1$0;")
-
-(define_insn "set_lowpartsfsc2"
- [(set (match_operand:SC 0 "nvptx_register_operand" "+R")
- (unspec:SC [(match_dup 0)
- (match_operand:SF 1 "nvptx_register_operand")]
- UNSPEC_CPLX_LOWPART))]
- ""
- "%.\\tmov%t1\\t%f0$0, %1;")
-
-(define_expand "mov<mode>"
- [(set (match_operand:SDCM 0 "nvptx_nonimmediate_operand" "")
- (match_operand:SDCM 1 "general_operand" ""))]
- ""
-{
- enum machine_mode submode = <MODE>mode == SCmode ? SFmode : DFmode;
- int sz = GET_MODE_SIZE (submode);
- rtx xops[4];
- rtx punning_reg = NULL_RTX;
- rtx copyback = NULL_RTX;
-
- if (GET_CODE (operands[0]) == SUBREG)
- {
- rtx inner = SUBREG_REG (operands[0]);
- enum machine_mode inner_mode = GET_MODE (inner);
- int sz2 = GET_MODE_SIZE (inner_mode);
- gcc_assert (sz2 >= sz);
- cfun->machine->punning_buffer_size
- = MAX (cfun->machine->punning_buffer_size, sz2);
- if (punning_reg == NULL_RTX)
- punning_reg = gen_rtx_REG (Pmode, NVPTX_PUNNING_BUFFER_REGNUM);
- copyback = gen_move_insn (inner, gen_rtx_MEM (inner_mode, punning_reg));
- operands[0] = gen_rtx_MEM (<MODE>mode, punning_reg);
- }
- if (GET_CODE (operands[1]) == SUBREG)
- {
- rtx inner = SUBREG_REG (operands[1]);
- enum machine_mode inner_mode = GET_MODE (inner);
- int sz2 = GET_MODE_SIZE (inner_mode);
- gcc_assert (sz2 >= sz);
- cfun->machine->punning_buffer_size
- = MAX (cfun->machine->punning_buffer_size, sz2);
- if (punning_reg == NULL_RTX)
- punning_reg = gen_rtx_REG (Pmode, NVPTX_PUNNING_BUFFER_REGNUM);
- emit_move_insn (gen_rtx_MEM (inner_mode, punning_reg), inner);
- operands[1] = gen_rtx_MEM (<MODE>mode, punning_reg);
- }
-
- if (REG_P (operands[0]) && submode == SFmode)
- {
- xops[0] = gen_reg_rtx (submode);
- xops[1] = gen_reg_rtx (submode);
- }
- else
- {
- xops[0] = gen_lowpart (submode, operands[0]);
- if (MEM_P (operands[0]))
- xops[1] = adjust_address_nv (operands[0], submode, sz);
- else
- xops[1] = gen_highpart (submode, operands[0]);
- }
-
- if (REG_P (operands[1]) && submode == SFmode)
- {
- xops[2] = gen_reg_rtx (submode);
- xops[3] = gen_reg_rtx (submode);
- emit_insn (gen_lowpartscsf2 (xops[2], operands[1]));
- emit_insn (gen_highpartscsf2 (xops[3], operands[1]));
- }
- else
- {
- xops[2] = gen_lowpart (submode, operands[1]);
- if (MEM_P (operands[1]))
- xops[3] = adjust_address_nv (operands[1], submode, sz);
- else
- xops[3] = gen_highpart (submode, operands[1]);
- }
-
- emit_move_insn (xops[0], xops[2]);
- emit_move_insn (xops[1], xops[3]);
- if (REG_P (operands[0]) && submode == SFmode)
- {
- emit_insn (gen_set_lowpartsfsc2 (operands[0], xops[0]));
- emit_insn (gen_set_highpartsfsc2 (operands[0], xops[1]));
- }
- if (copyback)
- emit_insn (copyback);
- DONE;
-})
-
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "nvptx_register_operand" "=R,R")
(zero_extend:HI (match_operand:QI 1 "nvptx_reg_or_mem_operand" "R,m")))]