diff --git a/gcc/testsuite/gcc.dg/vect/pr109011-1.c b/gcc/testsuite/gcc.dg/vect/pr109011-1.c index 707a82aaf432de6a3086bec104b6775c519cd11b..16a58267dc801bda1bac592144649bfd5ac9567e 100644 --- a/gcc/testsuite/gcc.dg/vect/pr109011-1.c +++ b/gcc/testsuite/gcc.dg/vect/pr109011-1.c @@ -4,7 +4,6 @@ /* { dg-additional-options "-mavx512cd" { target { { i?86-*-* x86_64-*-* } && avx512cd } } } */ /* { dg-additional-options "-mavx512vpopcntdq" { target { { i?86-*-* x86_64-*-* } && avx512vpopcntdq } } } */ /* { dg-additional-options "-mpower8-vector" { target powerpc_p8vector_ok } } */ -/* { dg-additional-options "-mpower9-vector" { target powerpc_p9vector_ok } } */ /* { dg-additional-options "-march=z13 -mzarch" { target s390_vx } } */ void @@ -28,21 +27,3 @@ bar (long long *p, long long *q) /* { dg-final { scan-tree-dump-times " = \.CLZ \\\(" 1 "optimized" { target { { i?86-*-* x86_64-*-* } && avx512cd } } } } */ /* { dg-final { scan-tree-dump-times " = \.CLZ \\\(" 1 "optimized" { target { powerpc_p8vector_ok || s390_vx } } } } */ - -void -baz (long long *p, long long *q) -{ -#pragma omp simd - for (int i = 0; i < 2048; ++i) - p[i] = __builtin_ctzll (q[i]); -} - -/* { dg-final { scan-tree-dump-times " = \.CTZ \\\(" 1 "optimized" { target { powerpc_p9vector_ok || s390_vx } } } } */ - -void -qux (long long *p, long long *q) -{ -#pragma omp simd - for (int i = 0; i < 2048; ++i) - p[i] = __builtin_ffsll (q[i]); -} diff --git a/gcc/testsuite/gcc.dg/vect/pr109011-2.c b/gcc/testsuite/gcc.dg/vect/pr109011-2.c new file mode 100644 index 0000000000000000000000000000000000000000..191af8945e57a7a094ebe48c6cd9379dc17afa41 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr109011-2.c @@ -0,0 +1,35 @@ +/* PR tree-optimization/109011 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-unroll-loops --param=vect-epilogues-nomask=0 -fdump-tree-optimized" } */ +/* { dg-additional-options "-mavx512cd -mbmi -mlzcnt -mno-avx512vpopcntdq" { target { { { { i?86-*-* x86_64-*-* } && avx512cd } && lzcnt } && bmi } } } */ +/* { dg-additional-options "-mpower9-vector" { target powerpc_p9vector_ok } } */ +/* { dg-additional-options "-march=z13 -mzarch" { target s390_vx } } */ + +void +foo (int *p, int *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ctz (q[i]); +} + +void +bar (int *p, int *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = q[i] ? __builtin_ctz (q[i]) : __SIZEOF_INT__ * __CHAR_BIT__; +} + +void +baz (int *p, int *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ffs (q[i]); +} + +/* { dg-final { scan-tree-dump-times " = \.CLZ \\\(" 3 "optimized" { target { { { { i?86-*-* x86_64-*-* } && avx512cd } && lzcnt } && bmi } } } } */ +/* { dg-final { scan-tree-dump-times " = \.CTZ \\\(" 4 "optimized" { target powerpc_p9vector_ok } } } */ +/* { dg-final { scan-tree-dump-times " = \.CTZ \\\(" 2 "optimized" { target s390_vx } } } */ +/* { dg-final { scan-tree-dump-times " = \.POPCOUNT \\\(" 1 "optimized" { target s390_vx } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr109011-3.c b/gcc/testsuite/gcc.dg/vect/pr109011-3.c new file mode 100644 index 0000000000000000000000000000000000000000..2e631fc1506d6bdb77397e75d794be3f96d43105 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr109011-3.c @@ -0,0 +1,32 @@ +/* PR tree-optimization/109011 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-unroll-loops --param=vect-epilogues-nomask=0 -fdump-tree-optimized" } */ +/* { dg-additional-options "-mno-avx512cd -mbmi -mlzcnt -mavx512vpopcntdq" { target { { { { i?86-*-* x86_64-*-* } && avx512vpopcntdq } && lzcnt } && bmi } } } */ +/* { dg-additional-options "-mpower8-vector -mno-power9-vector" { target powerpc_p8vector_ok } } */ + +void +foo (int *p, int *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ctz (q[i]); +} + +void +bar (int *p, int *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = q[i] ? __builtin_ctz (q[i]) : __SIZEOF_INT__ * __CHAR_BIT__; +} + +void +baz (int *p, int *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ffs (q[i]); +} + +/* { dg-final { scan-tree-dump-times " = \.POPCOUNT \\\(" 3 "optimized" { target { { { { i?86-*-* x86_64-*-* } && avx512vpopcntdq } && lzcnt } && bmi } } } } */ +/* { dg-final { scan-tree-dump-times " = \.CLZ \\\(" 3 "optimized" { target powerpc_p8vector_ok } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr109011-4.c b/gcc/testsuite/gcc.dg/vect/pr109011-4.c new file mode 100644 index 0000000000000000000000000000000000000000..ce1ee02516e3bfc4d851ce6add79f3eec7fac9c6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr109011-4.c @@ -0,0 +1,35 @@ +/* PR tree-optimization/109011 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-unroll-loops --param=vect-epilogues-nomask=0 -fdump-tree-optimized" } */ +/* { dg-additional-options "-mavx512cd -mbmi -mlzcnt -mno-avx512vpopcntdq" { target { { { { i?86-*-* x86_64-*-* } && avx512cd } && lzcnt } && bmi } } } */ +/* { dg-additional-options "-mpower9-vector" { target powerpc_p9vector_ok } } */ +/* { dg-additional-options "-march=z13 -mzarch" { target s390_vx } } */ + +void +foo (long long *p, long long *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ctzll (q[i]); +} + +void +bar (long long *p, long long *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = q[i] ? __builtin_ctzll (q[i]) : __SIZEOF_LONG_LONG__ * __CHAR_BIT__; +} + +void +baz (long long *p, long long *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ffsll (q[i]); +} + +/* { dg-final { scan-tree-dump-times " = \.CLZ \\\(" 3 "optimized" { target { { { { i?86-*-* x86_64-*-* } && avx512cd } && lzcnt } && bmi } } } } */ +/* { dg-final { scan-tree-dump-times " = \.CTZ \\\(" 4 "optimized" { target powerpc_p9vector_ok } } } */ +/* { dg-final { scan-tree-dump-times " = \.CTZ \\\(" 2 "optimized" { target s390_vx } } } */ +/* { dg-final { scan-tree-dump-times " = \.POPCOUNT \\\(" 1 "optimized" { target s390_vx } } } */ diff --git a/gcc/testsuite/gcc.dg/vect/pr109011-5.c b/gcc/testsuite/gcc.dg/vect/pr109011-5.c new file mode 100644 index 0000000000000000000000000000000000000000..51168ef87087310dfe3a7dad9b87d824a0733d62 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vect/pr109011-5.c @@ -0,0 +1,32 @@ +/* PR tree-optimization/109011 */ +/* { dg-do compile } */ +/* { dg-options "-O3 -fno-unroll-loops --param=vect-epilogues-nomask=0 -fdump-tree-optimized" } */ +/* { dg-additional-options "-mno-avx512cd -mbmi -mlzcnt -mavx512vpopcntdq" { target { { { { i?86-*-* x86_64-*-* } && avx512vpopcntdq } && lzcnt } && bmi } } } */ +/* { dg-additional-options "-mpower8-vector -mno-power9-vector" { target powerpc_p8vector_ok } } */ + +void +foo (long long *p, long long *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ctzll (q[i]); +} + +void +bar (long long *p, long long *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = q[i] ? __builtin_ctzll (q[i]) : __SIZEOF_LONG_LONG__ * __CHAR_BIT__; +} + +void +baz (long long *p, long long *q) +{ +#pragma omp simd + for (int i = 0; i < 2048; ++i) + p[i] = __builtin_ffsll (q[i]); +} + +/* { dg-final { scan-tree-dump-times " = \.POPCOUNT \\\(" 3 "optimized" { target { { { { i?86-*-* x86_64-*-* } && avx512vpopcntdq } && lzcnt } && bmi } } } } */ +/* { dg-final { scan-tree-dump-times " = \.CLZ \\\(" 3 "optimized" { target powerpc_p8vector_ok } } } */ diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc index 633998e8e3a8a866be9fb7ebafbc7a5f351c690e..d1b86e8b5e00cb7d233f020bccb07fd26c98ae09 100644 --- a/gcc/tree-vect-patterns.cc +++ b/gcc/tree-vect-patterns.cc @@ -1501,6 +1501,266 @@ vect_recog_widen_minus_pattern (vec_info *vinfo, stmt_vec_info last_stmt_info, "vect_recog_widen_minus_pattern"); } +/* Function vect_recog_ctz_ffs_pattern + + Try to find the following pattern: + + TYPE1 A; + TYPE1 B; + + B = __builtin_ctz{,l,ll} (A); + + or + + B = __builtin_ffs{,l,ll} (A); + + Input: + + * STMT_VINFO: The stmt from which the pattern search begins. + here it starts with B = __builtin_* (A); + + Output: + + * TYPE_OUT: The vector type of the output of this pattern. + + * Return value: A new stmt that will be used to replace the sequence of + stmts that constitute the pattern, using clz or popcount builtins. */ + +static gimple * +vect_recog_ctz_ffs_pattern (vec_info *vinfo, stmt_vec_info stmt_vinfo, + tree *type_out) +{ + gimple *call_stmt = stmt_vinfo->stmt; + gimple *pattern_stmt; + tree rhs_oprnd, rhs_type, lhs_oprnd, lhs_type, vec_type, vec_rhs_type; + tree new_var; + internal_fn ifn = IFN_LAST, ifnnew = IFN_LAST; + bool defined_at_zero = true, defined_at_zero_new = false; + int val = 0, val_new = 0; + int prec; + int sub = 0, add = 0; + location_t loc; + + if (!is_gimple_call (call_stmt)) + return NULL; + + if (gimple_call_num_args (call_stmt) != 1) + return NULL; + + rhs_oprnd = gimple_call_arg (call_stmt, 0); + rhs_type = TREE_TYPE (rhs_oprnd); + lhs_oprnd = gimple_call_lhs (call_stmt); + if (!lhs_oprnd) + return NULL; + lhs_type = TREE_TYPE (lhs_oprnd); + if (!INTEGRAL_TYPE_P (lhs_type) + || !INTEGRAL_TYPE_P (rhs_type) + || !type_has_mode_precision_p (rhs_type) + || TREE_CODE (rhs_oprnd) != SSA_NAME) + return NULL; + + switch (gimple_call_combined_fn (call_stmt)) + { + CASE_CFN_CTZ: + ifn = IFN_CTZ; + if (!gimple_call_internal_p (call_stmt) + || CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (rhs_type), + val) != 2) + defined_at_zero = false; + break; + CASE_CFN_FFS: + ifn = IFN_FFS; + break; + default: + return NULL; + } + + prec = TYPE_PRECISION (rhs_type); + loc = gimple_location (call_stmt); + + vec_type = get_vectype_for_scalar_type (vinfo, lhs_type); + if (!vec_type) + return NULL; + + vec_rhs_type = get_vectype_for_scalar_type (vinfo, rhs_type); + if (!vec_rhs_type) + return NULL; + + /* Do it only if the backend doesn't have ctz<vector_mode>2 or + ffs<vector_mode>2 pattern but does have clz<vector_mode>2 or + popcount<vector_mode>2. */ + if (!vec_type + || direct_internal_fn_supported_p (ifn, vec_rhs_type, + OPTIMIZE_FOR_SPEED)) + return NULL; + + if (ifn == IFN_FFS + && direct_internal_fn_supported_p (IFN_CTZ, vec_rhs_type, + OPTIMIZE_FOR_SPEED)) + { + ifnnew = IFN_CTZ; + defined_at_zero_new + = CTZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (rhs_type), + val_new) == 2; + } + else if (direct_internal_fn_supported_p (IFN_CLZ, vec_rhs_type, + OPTIMIZE_FOR_SPEED)) + { + ifnnew = IFN_CLZ; + defined_at_zero_new + = CLZ_DEFINED_VALUE_AT_ZERO (SCALAR_INT_TYPE_MODE (rhs_type), + val_new) == 2; + } + if ((ifnnew == IFN_LAST + || (defined_at_zero && !defined_at_zero_new)) + && direct_internal_fn_supported_p (IFN_POPCOUNT, vec_rhs_type, + OPTIMIZE_FOR_SPEED)) + { + ifnnew = IFN_POPCOUNT; + defined_at_zero_new = true; + val_new = prec; + } + if (ifnnew == IFN_LAST) + return NULL; + + vect_pattern_detected ("vec_recog_ctz_ffs_pattern", call_stmt); + + if ((ifnnew == IFN_CLZ + && defined_at_zero + && defined_at_zero_new + && val == prec + && val_new == prec) + || (ifnnew == IFN_POPCOUNT && ifn == IFN_CLZ)) + { + /* .CTZ (X) = PREC - .CLZ ((X - 1) & ~X) + .CTZ (X) = .POPCOUNT ((X - 1) & ~X). */ + if (ifnnew == IFN_CLZ) + sub = prec; + val_new = prec; + + if (!TYPE_UNSIGNED (rhs_type)) + { + rhs_type = unsigned_type_for (rhs_type); + vec_rhs_type = get_vectype_for_scalar_type (vinfo, rhs_type); + new_var = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (new_var, NOP_EXPR, rhs_oprnd); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, + vec_rhs_type); + rhs_oprnd = new_var; + } + + tree m1 = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (m1, PLUS_EXPR, rhs_oprnd, + build_int_cst (rhs_type, -1)); + gimple_set_location (pattern_stmt, loc); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_rhs_type); + + new_var = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (new_var, BIT_NOT_EXPR, rhs_oprnd); + gimple_set_location (pattern_stmt, loc); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_rhs_type); + rhs_oprnd = new_var; + + new_var = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (new_var, BIT_AND_EXPR, + m1, rhs_oprnd); + gimple_set_location (pattern_stmt, loc); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_rhs_type); + rhs_oprnd = new_var; + } + else if (ifnnew == IFN_CLZ) + { + /* .CTZ (X) = (PREC - 1) - .CLZ (X & -X) + .FFS (X) = PREC - .CLZ (X & -X). */ + sub = prec - (ifn == IFN_CTZ); + val_new = sub - val_new; + + tree neg = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (neg, NEGATE_EXPR, rhs_oprnd); + gimple_set_location (pattern_stmt, loc); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_rhs_type); + + new_var = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (new_var, BIT_AND_EXPR, + rhs_oprnd, neg); + gimple_set_location (pattern_stmt, loc); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_rhs_type); + rhs_oprnd = new_var; + } + else if (ifnnew == IFN_POPCOUNT) + { + /* .CTZ (X) = PREC - .POPCOUNT (X | -X) + .FFS (X) = (PREC + 1) - .POPCOUNT (X | -X). */ + sub = prec + (ifn == IFN_FFS); + val_new = sub; + + tree neg = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (neg, NEGATE_EXPR, rhs_oprnd); + gimple_set_location (pattern_stmt, loc); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_rhs_type); + + new_var = vect_recog_temp_ssa_var (rhs_type, NULL); + pattern_stmt = gimple_build_assign (new_var, BIT_IOR_EXPR, + rhs_oprnd, neg); + gimple_set_location (pattern_stmt, loc); + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_rhs_type); + rhs_oprnd = new_var; + } + else if (ifnnew == IFN_CTZ) + { + /* .FFS (X) = .CTZ (X) + 1. */ + add = 1; + val_new++; + } + + /* Create B = .IFNNEW (A). */ + new_var = vect_recog_temp_ssa_var (lhs_type, NULL); + pattern_stmt = gimple_build_call_internal (ifnnew, 1, rhs_oprnd); + gimple_call_set_lhs (pattern_stmt, new_var); + gimple_set_location (pattern_stmt, loc); + *type_out = vec_type; + + if (sub) + { + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_type); + tree ret_var = vect_recog_temp_ssa_var (lhs_type, NULL); + pattern_stmt = gimple_build_assign (ret_var, MINUS_EXPR, + build_int_cst (lhs_type, sub), + new_var); + gimple_set_location (pattern_stmt, loc); + new_var = ret_var; + } + else if (add) + { + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_type); + tree ret_var = vect_recog_temp_ssa_var (lhs_type, NULL); + pattern_stmt = gimple_build_assign (ret_var, PLUS_EXPR, new_var, + build_int_cst (lhs_type, add)); + gimple_set_location (pattern_stmt, loc); + new_var = ret_var; + } + + if (defined_at_zero + && (!defined_at_zero_new || val != val_new)) + { + append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_type); + tree ret_var = vect_recog_temp_ssa_var (lhs_type, NULL); + rhs_oprnd = gimple_call_arg (call_stmt, 0); + rhs_type = TREE_TYPE (rhs_oprnd); + tree cmp = build2_loc (loc, NE_EXPR, boolean_type_node, + rhs_oprnd, build_zero_cst (rhs_type)); + pattern_stmt = gimple_build_assign (ret_var, COND_EXPR, cmp, + new_var, + build_int_cst (lhs_type, val)); + } + + if (dump_enabled_p ()) + dump_printf_loc (MSG_NOTE, vect_location, + "created pattern stmt: %G", pattern_stmt); + + return pattern_stmt; +} + /* Function vect_recog_popcount_clz_ctz_ffs_pattern Try to find the following pattern: @@ -1680,15 +1940,42 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo, gcc_unreachable (); } - vect_pattern_detected ("vec_recog_popcount_clz_ctz_ffs_pattern", - call_stmt); vec_type = get_vectype_for_scalar_type (vinfo, lhs_type); /* Do it only if the backend has popcount<vector_mode>2 etc. pattern. */ - if (!vec_type - || !direct_internal_fn_supported_p (ifn, vec_type, - OPTIMIZE_FOR_SPEED)) + if (!vec_type) return NULL; + bool supported + = direct_internal_fn_supported_p (ifn, vec_type, OPTIMIZE_FOR_SPEED); + if (!supported) + switch (ifn) + { + case IFN_POPCOUNT: + case IFN_CLZ: + return NULL; + case IFN_FFS: + /* vect_recog_ctz_ffs_pattern can implement ffs using ctz. */ + if (direct_internal_fn_supported_p (IFN_CTZ, vec_type, + OPTIMIZE_FOR_SPEED)) + break; + /* FALLTHRU */ + case IFN_CTZ: + /* vect_recog_ctz_ffs_pattern can implement ffs or ctz using + clz or popcount. */ + if (direct_internal_fn_supported_p (IFN_CLZ, vec_type, + OPTIMIZE_FOR_SPEED)) + break; + if (direct_internal_fn_supported_p (IFN_POPCOUNT, vec_type, + OPTIMIZE_FOR_SPEED)) + break; + return NULL; + default: + gcc_unreachable (); + } + + vect_pattern_detected ("vec_recog_popcount_clz_ctz_ffs_pattern", + call_stmt); + /* Create B = .POPCOUNT (A). */ new_var = vect_recog_temp_ssa_var (lhs_type, NULL); pattern_stmt = gimple_build_call_internal (ifn, 1, unprom_diff.op); @@ -1702,11 +1989,26 @@ vect_recog_popcount_clz_ctz_ffs_pattern (vec_info *vinfo, if (addend) { + gcc_assert (supported); append_pattern_def_seq (vinfo, stmt_vinfo, pattern_stmt, vec_type); tree ret_var = vect_recog_temp_ssa_var (lhs_type, NULL); pattern_stmt = gimple_build_assign (ret_var, PLUS_EXPR, new_var, build_int_cst (lhs_type, addend)); } + else if (!supported) + { + stmt_vec_info new_stmt_info = vinfo->add_stmt (pattern_stmt); + STMT_VINFO_VECTYPE (new_stmt_info) = vec_type; + pattern_stmt + = vect_recog_ctz_ffs_pattern (vinfo, new_stmt_info, type_out); + if (pattern_stmt == NULL) + return NULL; + if (gimple_seq seq = STMT_VINFO_PATTERN_DEF_SEQ (new_stmt_info)) + { + gimple_seq *pseq = &STMT_VINFO_PATTERN_DEF_SEQ (stmt_vinfo); + gimple_seq_add_seq_without_update (pseq, seq); + } + } return pattern_stmt; } @@ -6150,6 +6452,7 @@ static vect_recog_func vect_vect_recog_func_ptrs[] = { { vect_recog_widen_sum_pattern, "widen_sum" }, { vect_recog_pow_pattern, "pow" }, { vect_recog_popcount_clz_ctz_ffs_pattern, "popcount_clz_ctz_ffs" }, + { vect_recog_ctz_ffs_pattern, "ctz_ffs" }, { vect_recog_widen_shift_pattern, "widen_shift" }, { vect_recog_rotate_pattern, "rotate" }, { vect_recog_vector_vector_shift_pattern, "vector_vector_shift" },