/* Create static initializers for the information returned by
direct_internal_fn. */
-#define not_direct { -2, -2, false, false }
-#define direct_insn { -2, -2, true, false }
-#define optab1(TYPE0) { TYPE0, TYPE0, true, false }
-#define optab2(TYPE0, TYPE1) { TYPE0, TYPE1, true, false }
-#define vectorizable_optab1(TYPE0) { TYPE0, TYPE0, true, true }
-
-#define mask_load_direct optab2 (-1, 2)
-#define load_lanes_direct optab1 (-1)
-#define mask_load_lanes_direct optab1 (-1)
-#define gather_load_direct optab2 (3, 1)
-#define len_load_direct optab1 (-1)
-#define mask_store_direct optab2 (3, 2)
-#define store_lanes_direct optab1 (0)
-#define mask_store_lanes_direct optab1 (0)
-#define vec_cond_mask_direct optab2 (1, 0)
-#define vec_cond_direct optab2 (2, 0)
-#define scatter_store_direct optab2 (3, 1)
-#define len_store_direct optab1 (3)
-#define vec_set_direct optab1 (3)
-#define unary_direct vectorizable_optab1 (0)
-#define binary_direct vectorizable_optab1 (0)
-#define ternary_direct vectorizable_optab1 (0)
-#define cond_unary_direct vectorizable_optab1 (1)
-#define cond_binary_direct vectorizable_optab1 (1)
-#define cond_ternary_direct vectorizable_optab1 (1)
-#define while_direct optab2 (0, 2)
-#define fold_extract_direct optab1 (2)
-#define fold_left_direct optab1 (1)
-#define mask_fold_left_direct optab1 (1)
-#define check_ptrs_direct optab1 (0)
+#define not_direct { -2, -2, false }
+#define mask_load_direct { -1, 2, false }
+#define load_lanes_direct { -1, -1, false }
+#define mask_load_lanes_direct { -1, -1, false }
+#define gather_load_direct { 3, 1, false }
+#define len_load_direct { -1, -1, false }
+#define mask_store_direct { 3, 2, false }
+#define store_lanes_direct { 0, 0, false }
+#define mask_store_lanes_direct { 0, 0, false }
+#define vec_cond_mask_direct { 1, 0, false }
+#define vec_cond_direct { 2, 0, false }
+#define scatter_store_direct { 3, 1, false }
+#define len_store_direct { 3, 3, false }
+#define vec_set_direct { 3, 3, false }
+#define unary_direct { 0, 0, true }
+#define binary_direct { 0, 0, true }
+#define ternary_direct { 0, 0, true }
+#define cond_unary_direct { 1, 1, true }
+#define cond_binary_direct { 1, 1, true }
+#define cond_ternary_direct { 1, 1, true }
+#define while_direct { 0, 2, false }
+#define fold_extract_direct { 2, 2, false }
+#define fold_left_direct { 1, 1, false }
+#define mask_fold_left_direct { 1, 1, false }
+#define check_ptrs_direct { 0, 0, false }
const direct_internal_fn_info direct_internal_fn_array[IFN_LAST + 1] = {
#define DEF_INTERNAL_FN(CODE, FLAGS, FNSPEC) not_direct,
#define DEF_INTERNAL_OPTAB_FN(CODE, FLAGS, OPTAB, TYPE) TYPE##_direct,
#define DEF_INTERNAL_SIGNED_OPTAB_FN(CODE, FLAGS, SELECTOR, SIGNED_OPTAB, \
UNSIGNED_OPTAB, TYPE) TYPE##_direct,
-#define DEF_INTERNAL_INSN_FN(CODE, FLAGS, INSN, NOUTPUTS, NINPUTS) \
- direct_insn,
#include "internal-fn.def"
not_direct
};
gcc_unreachable ();
}
+/* Allocate per-lane storage and begin non-uniform execution region. */
+
+static void
+expand_GOMP_SIMT_ENTER_ALLOC (internal_fn, gcall *stmt)
+{
+ rtx target;
+ tree lhs = gimple_call_lhs (stmt);
+ if (lhs)
+ target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ else
+ target = gen_reg_rtx (Pmode);
+ rtx size = expand_normal (gimple_call_arg (stmt, 0));
+ rtx align = expand_normal (gimple_call_arg (stmt, 1));
+ class expand_operand ops[3];
+ create_output_operand (&ops[0], target, Pmode);
+ create_input_operand (&ops[1], size, Pmode);
+ create_input_operand (&ops[2], align, Pmode);
+ gcc_assert (targetm.have_omp_simt_enter ());
+ expand_insn (targetm.code_for_omp_simt_enter, 3, ops);
+ if (!rtx_equal_p (target, ops[0].value))
+ emit_move_insn (target, ops[0].value);
+}
+
+/* Deallocate per-lane storage and leave non-uniform execution region. */
+
+static void
+expand_GOMP_SIMT_EXIT (internal_fn, gcall *stmt)
+{
+ gcc_checking_assert (!gimple_call_lhs (stmt));
+ rtx arg = expand_normal (gimple_call_arg (stmt, 0));
+ class expand_operand ops[1];
+ create_input_operand (&ops[0], arg, Pmode);
+ gcc_assert (targetm.have_omp_simt_exit ());
+ expand_insn (targetm.code_for_omp_simt_exit, 1, ops);
+}
+
+/* Lane index on SIMT targets: thread index in the warp on NVPTX. On targets
+ without SIMT execution this should be expanded in omp_device_lower pass. */
+
+static void
+expand_GOMP_SIMT_LANE (internal_fn, gcall *stmt)
+{
+ tree lhs = gimple_call_lhs (stmt);
+ if (!lhs)
+ return;
+
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ gcc_assert (targetm.have_omp_simt_lane ());
+ emit_insn (targetm.gen_omp_simt_lane (target));
+}
+
/* This should get expanded in omp_device_lower pass. */
static void
gcc_unreachable ();
}
+/* Lane index of the first SIMT lane that supplies a non-zero argument.
+ This is a SIMT counterpart to GOMP_SIMD_LAST_LANE, used to represent the
+ lane that executed the last iteration for handling OpenMP lastprivate. */
+
+static void
+expand_GOMP_SIMT_LAST_LANE (internal_fn, gcall *stmt)
+{
+ tree lhs = gimple_call_lhs (stmt);
+ if (!lhs)
+ return;
+
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ rtx cond = expand_normal (gimple_call_arg (stmt, 0));
+ machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+ class expand_operand ops[2];
+ create_output_operand (&ops[0], target, mode);
+ create_input_operand (&ops[1], cond, mode);
+ gcc_assert (targetm.have_omp_simt_last_lane ());
+ expand_insn (targetm.code_for_omp_simt_last_lane, 2, ops);
+ if (!rtx_equal_p (target, ops[0].value))
+ emit_move_insn (target, ops[0].value);
+}
+
+/* Non-transparent predicate used in SIMT lowering of OpenMP "ordered". */
+
+static void
+expand_GOMP_SIMT_ORDERED_PRED (internal_fn, gcall *stmt)
+{
+ tree lhs = gimple_call_lhs (stmt);
+ if (!lhs)
+ return;
+
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ rtx ctr = expand_normal (gimple_call_arg (stmt, 0));
+ machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+ class expand_operand ops[2];
+ create_output_operand (&ops[0], target, mode);
+ create_input_operand (&ops[1], ctr, mode);
+ gcc_assert (targetm.have_omp_simt_ordered ());
+ expand_insn (targetm.code_for_omp_simt_ordered, 2, ops);
+ if (!rtx_equal_p (target, ops[0].value))
+ emit_move_insn (target, ops[0].value);
+}
+
+/* "Or" boolean reduction across SIMT lanes: return non-zero in all lanes if
+ any lane supplies a non-zero argument. */
+
+static void
+expand_GOMP_SIMT_VOTE_ANY (internal_fn, gcall *stmt)
+{
+ tree lhs = gimple_call_lhs (stmt);
+ if (!lhs)
+ return;
+
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ rtx cond = expand_normal (gimple_call_arg (stmt, 0));
+ machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+ class expand_operand ops[2];
+ create_output_operand (&ops[0], target, mode);
+ create_input_operand (&ops[1], cond, mode);
+ gcc_assert (targetm.have_omp_simt_vote_any ());
+ expand_insn (targetm.code_for_omp_simt_vote_any, 2, ops);
+ if (!rtx_equal_p (target, ops[0].value))
+ emit_move_insn (target, ops[0].value);
+}
+
+/* Exchange between SIMT lanes with a "butterfly" pattern: source lane index
+ is destination lane index XOR given offset. */
+
+static void
+expand_GOMP_SIMT_XCHG_BFLY (internal_fn, gcall *stmt)
+{
+ tree lhs = gimple_call_lhs (stmt);
+ if (!lhs)
+ return;
+
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ rtx src = expand_normal (gimple_call_arg (stmt, 0));
+ rtx idx = expand_normal (gimple_call_arg (stmt, 1));
+ machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+ class expand_operand ops[3];
+ create_output_operand (&ops[0], target, mode);
+ create_input_operand (&ops[1], src, mode);
+ create_input_operand (&ops[2], idx, SImode);
+ gcc_assert (targetm.have_omp_simt_xchg_bfly ());
+ expand_insn (targetm.code_for_omp_simt_xchg_bfly, 3, ops);
+ if (!rtx_equal_p (target, ops[0].value))
+ emit_move_insn (target, ops[0].value);
+}
+
+/* Exchange between SIMT lanes according to given source lane index. */
+
+static void
+expand_GOMP_SIMT_XCHG_IDX (internal_fn, gcall *stmt)
+{
+ tree lhs = gimple_call_lhs (stmt);
+ if (!lhs)
+ return;
+
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ rtx src = expand_normal (gimple_call_arg (stmt, 0));
+ rtx idx = expand_normal (gimple_call_arg (stmt, 1));
+ machine_mode mode = TYPE_MODE (TREE_TYPE (lhs));
+ class expand_operand ops[3];
+ create_output_operand (&ops[0], target, mode);
+ create_input_operand (&ops[1], src, mode);
+ create_input_operand (&ops[2], idx, SImode);
+ gcc_assert (targetm.have_omp_simt_xchg_idx ());
+ expand_insn (targetm.code_for_omp_simt_xchg_idx, 3, ops);
+ if (!rtx_equal_p (target, ops[0].value))
+ emit_move_insn (target, ops[0].value);
+}
+
/* This should get expanded in adjust_simduid_builtins. */
static void
direct_internal_fn_types (internal_fn fn, tree return_type, tree *args)
{
const direct_internal_fn_info &info = direct_internal_fn (fn);
- if (info.type0 == -2)
- /* Functions created by DEF_INTERNAL_INSN_FN are not type-dependent. */
- return tree_pair {};
-
tree type0 = (info.type0 < 0 ? return_type : TREE_TYPE (args[info.type0]));
tree type1 = (info.type1 < 0 ? return_type : TREE_TYPE (args[info.type1]));
return tree_pair (type0, type1);
direct_internal_fn_types (internal_fn fn, gcall *call)
{
const direct_internal_fn_info &info = direct_internal_fn (fn);
- if (info.type0 == -2)
- /* Functions created by DEF_INTERNAL_INSN_FN are not type-dependent. */
- return tree_pair {};
-
tree op0 = (info.type0 < 0
? gimple_call_lhs (call)
: gimple_call_arg (call, info.type0));
return direct_##TYPE##_optab_supported_p (which_optab, types, \
opt_type); \
}
-#define DEF_INTERNAL_INSN_FN(CODE, FLAGS, INSN, NOUTPUTS, NINPUTS) \
- case IFN_##CODE: return targetm.have_##INSN ();
#include "internal-fn.def"
case IFN_LAST:
optab which_optab = direct_internal_fn_optab (fn, types); \
expand_##TYPE##_optab_fn (fn, stmt, which_optab); \
}
-#define DEF_INTERNAL_INSN_FN(CODE, FLAGS, INSN, NOUTPUTS, NINPUTS) \
- static void \
- expand_##CODE (internal_fn, gcall *stmt) \
- { \
- gcc_assert (targetm.have_##INSN ()); \
- expand_fn_using_insn (stmt, targetm.code_for_##INSN, \
- NOUTPUTS, NINPUTS); \
- }
#include "internal-fn.def"
/* Routines to expand each internal function, indexed by function number.
UNSIGNED_OPTAB, TYPE)
DEF_INTERNAL_FLT_FN (NAME, FLAGS, OPTAB, TYPE)
DEF_INTERNAL_INT_FN (NAME, FLAGS, OPTAB, TYPE)
- DEF_INTERNAL_INSN_FN (NAME, FLAGS, INSN, NOUTPUTS, NINPUTS)
where NAME is the name of the function, FLAGS is a set of
ECF_* flags and FNSPEC is a string describing functions fnspec.
says that the function extends the C-level BUILT_IN_<NAME>{,L,LL,IMAX}
group of functions to any integral mode (including vector modes).
- DEF_INTERNAL_INSN_FN defines an internal function that maps to target
- instruction INSN, which is one of those defined in target-insns.def.
- The instruction has NOUTPUTS output operands (either 0 or 1) and
- NINPUTS input operands.
-
Each entry must have a corresponding expander of the form:
void expand_NAME (gimple_call stmt)
DEF_INTERNAL_OPTAB_FN (NAME, FLAGS, OPTAB, TYPE)
#endif
-#ifndef DEF_INTERNAL_INSN_FN
-#define DEF_INTERNAL_INSN_FN(NAME, FLAGS, INSN, NOUTPUTS, NINPUTS) \
- DEF_INTERNAL_FN (NAME, FLAGS | ECF_LEAF, NULL)
-#endif
-
DEF_INTERNAL_OPTAB_FN (MASK_LOAD, ECF_PURE, maskload, mask_load)
DEF_INTERNAL_OPTAB_FN (LOAD_LANES, ECF_CONST, vec_load_lanes, load_lanes)
DEF_INTERNAL_OPTAB_FN (MASK_LOAD_LANES, ECF_PURE,
DEF_INTERNAL_FN (GOMP_USE_SIMT, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (GOMP_SIMT_ENTER, ECF_LEAF | ECF_NOTHROW, NULL)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_ENTER_ALLOC, ECF_NOTHROW, omp_simt_enter, 1, 2)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_EXIT, ECF_NOTHROW, omp_simt_exit, 0, 1)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_LANE, ECF_NOVOPS | ECF_NOTHROW,
- omp_simt_lane, 1, 0)
+DEF_INTERNAL_FN (GOMP_SIMT_ENTER_ALLOC, ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (GOMP_SIMT_EXIT, ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (GOMP_SIMT_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (GOMP_SIMT_VF, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_LAST_LANE, ECF_NOVOPS | ECF_NOTHROW,
- omp_simt_last_lane, 1, 1)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_ORDERED_PRED, ECF_NOTHROW,
- omp_simt_ordered, 1, 1)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_VOTE_ANY, ECF_NOVOPS | ECF_NOTHROW,
- omp_simt_vote_any, 1, 1)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_XCHG_BFLY, ECF_NOVOPS | ECF_NOTHROW,
- omp_simt_xchg_bfly, 1, 2)
-DEF_INTERNAL_INSN_FN (GOMP_SIMT_XCHG_IDX, ECF_NOVOPS | ECF_NOTHROW,
- omp_simt_xchg_idx, 1, 2)
+DEF_INTERNAL_FN (GOMP_SIMT_LAST_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (GOMP_SIMT_ORDERED_PRED, ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (GOMP_SIMT_VOTE_ANY, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (GOMP_SIMT_XCHG_BFLY, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
+DEF_INTERNAL_FN (GOMP_SIMT_XCHG_IDX, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (GOMP_SIMD_LANE, ECF_NOVOPS | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (GOMP_SIMD_VF, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
DEF_INTERNAL_FN (GOMP_SIMD_LAST_LANE, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
/* <=> optimization. */
DEF_INTERNAL_FN (SPACESHIP, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
-#undef DEF_INTERNAL_INSN_FN
#undef DEF_INTERNAL_INT_FN
#undef DEF_INTERNAL_FLT_FN
#undef DEF_INTERNAL_FLT_FLOATN_FN