Ahmed moreilp
This commit is contained in:
committed by
Linus Baumberger
parent
e4b9087e8b
commit
00b6a58d71
@@ -175,21 +175,44 @@ Pedestrian *init_pedestrians(int n_p) {
|
||||
|
||||
Board init_board_without_obstacles() { return Board(BOARD_LENGTH, BOARD_WIDTH, 0, nullptr); }
|
||||
|
||||
// # 64 MULTs, 56 ADDs
|
||||
static inline float32x4_t _neon_exp_ps(float32x4_t x) {
|
||||
const float32x4_t log2e = vdupq_n_f32(1.4426950408889634f);
|
||||
|
||||
// # 4 MULTS
|
||||
float32x4_t nf = vrndnq_f32(vmulq_f32(x, log2e));
|
||||
|
||||
const float32x4_t ln2 = vdupq_n_f32(0.6931471805599453f);
|
||||
|
||||
// # 4 MULTs, 4 ADDs
|
||||
float32x4_t r = vfmsq_f32(x, nf, ln2); // r = x - nf*ln2
|
||||
|
||||
const float32x4_t c5 = vdupq_n_f32(1.0f / 120.0f);
|
||||
const float32x4_t c4 = vdupq_n_f32(1.0f / 24.0f);
|
||||
const float32x4_t c3 = vdupq_n_f32(1.0f / 6.0f);
|
||||
const float32x4_t c2 = vdupq_n_f32(0.5f);
|
||||
const float32x4_t c1 = vdupq_n_f32(1.0f);
|
||||
const float32x4_t c0 = vdupq_n_f32(1.0f);
|
||||
const float32x4_t c12 = vdupq_n_f32(c12_scalar);
|
||||
const float32x4_t c11 = vdupq_n_f32(c11_scalar);
|
||||
const float32x4_t c10 = vdupq_n_f32(c10_scalar);
|
||||
const float32x4_t c9 = vdupq_n_f32(c9_scalar);
|
||||
const float32x4_t c8 = vdupq_n_f32(c8_scalar);
|
||||
const float32x4_t c7 = vdupq_n_f32(c7_scalar);
|
||||
const float32x4_t c6 = vdupq_n_f32(c6_scalar);
|
||||
const float32x4_t c5 = vdupq_n_f32(c5_scalar);
|
||||
const float32x4_t c4 = vdupq_n_f32(c4_scalar);
|
||||
const float32x4_t c3 = vdupq_n_f32(c3_scalar);
|
||||
const float32x4_t c2 = vdupq_n_f32(c2_scalar);
|
||||
const float32x4_t c1 = vdupq_n_f32(c1_scalar);
|
||||
const float32x4_t c0 = vdupq_n_f32(c0_scalar);
|
||||
|
||||
float32x4_t p = c5;
|
||||
float32x4_t p = c12;
|
||||
|
||||
// # 13 * (4 MULTs, 4 ADDs)
|
||||
// # = 52 MULTs, 52 ADDs
|
||||
p = vfmaq_f32(c12, p, r);
|
||||
p = vfmaq_f32(c11, p, r);
|
||||
p = vfmaq_f32(c10, p, r);
|
||||
p = vfmaq_f32(c9, p, r);
|
||||
p = vfmaq_f32(c8, p, r);
|
||||
p = vfmaq_f32(c7, p, r);
|
||||
p = vfmaq_f32(c6, p, r);
|
||||
p = vfmaq_f32(c5, p, r);
|
||||
p = vfmaq_f32(c4, p, r);
|
||||
p = vfmaq_f32(c3, p, r);
|
||||
p = vfmaq_f32(c2, p, r);
|
||||
@@ -201,12 +224,17 @@ static inline float32x4_t _neon_exp_ps(float32x4_t x) {
|
||||
int32x4_t scaled = vshlq_n_s32(biased, 23);
|
||||
float32x4_t pow2n = vreinterpretq_f32_s32(scaled);
|
||||
|
||||
// # 4 MULTs
|
||||
return vmulq_f32(p, pow2n);
|
||||
}
|
||||
|
||||
// # 4 ADD, 16 MULTS, 4 SQRT, 4 DIV
|
||||
// Newton-Raphson refinement formula.
|
||||
static inline float32x4_t _neon_rsqrt_ps(float32x4_t x) {
|
||||
// # 4 SQRT, 4 DIV
|
||||
float32x4_t y = vrsqrteq_f32(x);
|
||||
|
||||
// # 16 MULTS, 4 ADD
|
||||
y = vmulq_f32(y, vrsqrtsq_f32(vmulq_f32(x, y), y));
|
||||
return y;
|
||||
}
|
||||
@@ -244,12 +272,42 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
const float32x4_t v_np = vdupq_n_f32((float)n_p);
|
||||
const float32x4_t v_exp_min = vdupq_n_f32(-87.0f);
|
||||
|
||||
// # ADDs: n_iter * (
|
||||
// # n_p * 20 +
|
||||
// # n_p * n_p_pad * 32 +
|
||||
// # n_p * board.n_obstacles * 10 +
|
||||
// # n_p_pad * 9
|
||||
// # )
|
||||
|
||||
// # MULTs: n_iter * (
|
||||
// # n_p * 4 +
|
||||
// # n_p * n_p_pad * 54 +
|
||||
// # n_p * board.n_obstacles * 13 +
|
||||
// # n_p_pad * 24
|
||||
// # )
|
||||
|
||||
// # DIVs: n_iter * (
|
||||
// # n_p * n_p_pad * 3 +
|
||||
// # n_p * board.n_obstacles +
|
||||
// # n_p_pad * 2
|
||||
// # )
|
||||
|
||||
// # SQRTs: n_iter * (
|
||||
// # n_p * n_p_pad * 3 +
|
||||
// # n_p * board.n_obstacles +
|
||||
// # n_p_pad * 3
|
||||
// # )
|
||||
|
||||
// # EXPs: n_iter * n_p * board.n_obstacles
|
||||
|
||||
for (int t = 0; t < n_iter; t++) {
|
||||
for (int i = 0; i < n_p; i++) {
|
||||
|
||||
// # 2 MULTS
|
||||
float desired_velocity_x = e_x[i] * desired_v0[i];
|
||||
float desired_velocity_y = e_y[i] * desired_v0[i];
|
||||
|
||||
// # 2 ADDS, 2 MULTS
|
||||
float f_alpha_dt_x = (desired_velocity_x - curr_vel_x[i]) * dt_times_tau_alpha_inv;
|
||||
float f_alpha_dt_y = (desired_velocity_y - curr_vel_y[i]) * dt_times_tau_alpha_inv;
|
||||
|
||||
@@ -266,6 +324,7 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
|
||||
for (int j = 0; j < n_p_pad; j += 8) {
|
||||
|
||||
// # 8 ADDS
|
||||
float32x4_t j_idx_0 = vaddq_f32(vdupq_n_f32((float)j), lane_off);
|
||||
float32x4_t j_idx_1 = vaddq_f32(vdupq_n_f32((float)(j + 4)), lane_off);
|
||||
|
||||
@@ -287,86 +346,107 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
float32x4_t sb_jsq_0 = vld1q_f32(&sb_sq[j]);
|
||||
float32x4_t sb_jsq_1 = vld1q_f32(&sb_sq[j + 4]);
|
||||
|
||||
// # 16 ADDS
|
||||
float32x4_t r_ab_x_0 = vsubq_f32(pix, pjx_0);
|
||||
float32x4_t r_ab_x_1 = vsubq_f32(pix, pjx_1);
|
||||
float32x4_t r_ab_y_0 = vsubq_f32(piy, pjy_0);
|
||||
float32x4_t r_ab_y_1 = vsubq_f32(piy, pjy_1);
|
||||
|
||||
// # 8 ADDS, 16 MULTS
|
||||
float32x4_t r_ab_n2_0 = vfmaq_f32(vmulq_f32(r_ab_y_0, r_ab_y_0), r_ab_x_0, r_ab_x_0);
|
||||
float32x4_t r_ab_n2_1 = vfmaq_f32(vmulq_f32(r_ab_y_1, r_ab_y_1), r_ab_x_1, r_ab_x_1);
|
||||
|
||||
r_ab_n2_0 = vmaxq_f32(r_ab_n2_0, v_eps_sq);
|
||||
r_ab_n2_1 = vmaxq_f32(r_ab_n2_1, v_eps_sq);
|
||||
|
||||
// # 8 ADD, 32 MULTS, 8 SQRT, 8 DIV
|
||||
float32x4_t inv_r_ab_n_0 = _neon_rsqrt_ps(r_ab_n2_0);
|
||||
float32x4_t inv_r_ab_n_1 = _neon_rsqrt_ps(r_ab_n2_1);
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t r_ab_n_0 = vmulq_f32(r_ab_n2_0, inv_r_ab_n_0);
|
||||
float32x4_t r_ab_n_1 = vmulq_f32(r_ab_n2_1, inv_r_ab_n_1);
|
||||
|
||||
// # 16 ADDS
|
||||
float32x4_t r_ab2_x_0 = vsubq_f32(r_ab_x_0, sbe_jx_0);
|
||||
float32x4_t r_ab2_x_1 = vsubq_f32(r_ab_x_1, sbe_jx_1);
|
||||
float32x4_t r_ab2_y_0 = vsubq_f32(r_ab_y_0, sbe_jy_0);
|
||||
float32x4_t r_ab2_y_1 = vsubq_f32(r_ab_y_1, sbe_jy_1);
|
||||
|
||||
// # 8 ADDS, 16 MULTS
|
||||
float32x4_t r_ab2_n2_0 = vfmaq_f32(vmulq_f32(r_ab2_y_0, r_ab2_y_0), r_ab2_x_0, r_ab2_x_0);
|
||||
float32x4_t r_ab2_n2_1 = vfmaq_f32(vmulq_f32(r_ab2_y_1, r_ab2_y_1), r_ab2_x_1, r_ab2_x_1);
|
||||
|
||||
r_ab2_n2_0 = vmaxq_f32(r_ab2_n2_0, v_eps_sq);
|
||||
r_ab2_n2_1 = vmaxq_f32(r_ab2_n2_1, v_eps_sq);
|
||||
|
||||
// # 8 ADD, 32 MULTS, 8 SQRT, 8 DIV
|
||||
float32x4_t inv_r_ab2_n_0 = _neon_rsqrt_ps(r_ab2_n2_0);
|
||||
float32x4_t inv_r_ab2_n_1 = _neon_rsqrt_ps(r_ab2_n2_1);
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t r_ab2_n_0 = vmulq_f32(r_ab2_n2_0, inv_r_ab2_n_0);
|
||||
float32x4_t r_ab2_n_1 = vmulq_f32(r_ab2_n2_1, inv_r_ab2_n_1);
|
||||
|
||||
// # 8 ADDS
|
||||
float32x4_t r_sum_0 = vaddq_f32(r_ab_n_0, r_ab2_n_0);
|
||||
float32x4_t r_sum_1 = vaddq_f32(r_ab_n_1, r_ab2_n_1);
|
||||
|
||||
// # 8 ADDS, 8 MULTS
|
||||
float32x4_t two_b_sq_0 = vsubq_f32(vmulq_f32(r_sum_0, r_sum_0), sb_jsq_0);
|
||||
float32x4_t two_b_sq_1 = vsubq_f32(vmulq_f32(r_sum_1, r_sum_1), sb_jsq_1);
|
||||
|
||||
two_b_sq_0 = vmaxq_f32(two_b_sq_0, v_eps_sq);
|
||||
two_b_sq_1 = vmaxq_f32(two_b_sq_1, v_eps_sq);
|
||||
|
||||
// # 8 ADD, 32 MULTS, 8 SQRT, 8 DIV
|
||||
float32x4_t inv_two_b_0 = _neon_rsqrt_ps(two_b_sq_0);
|
||||
float32x4_t inv_two_b_1 = _neon_rsqrt_ps(two_b_sq_1);
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t two_b_0 = vmulq_f32(two_b_sq_0, inv_two_b_0);
|
||||
float32x4_t two_b_1 = vmulq_f32(two_b_sq_1, inv_two_b_1);
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t e_arg_0 = vmulq_f32(two_b_0, v_neg_2s_inv);
|
||||
float32x4_t e_arg_1 = vmulq_f32(two_b_1, v_neg_2s_inv);
|
||||
|
||||
e_arg_0 = vmaxq_f32(e_arg_0, v_exp_min);
|
||||
e_arg_1 = vmaxq_f32(e_arg_1, v_exp_min);
|
||||
|
||||
// # 128 MULTs, 112 ADDs
|
||||
float32x4_t e_val_0 = _neon_exp_ps(e_arg_0);
|
||||
float32x4_t e_val_1 = _neon_exp_ps(e_arg_1);
|
||||
|
||||
// # 24 MULTS
|
||||
float32x4_t numer_inv_two_b_0 = vmulq_f32(vmulq_f32(r_sum_0, v_neg_v0_div_2s), vmulq_f32(e_val_0, inv_two_b_0));
|
||||
float32x4_t numer_inv_two_b_1 = vmulq_f32(vmulq_f32(r_sum_1, v_neg_v0_div_2s), vmulq_f32(e_val_1, inv_two_b_1));
|
||||
|
||||
// # 16 MULTS
|
||||
float32x4_t sm_r_ab_0 = vmulq_f32(numer_inv_two_b_0, inv_r_ab_n_0);
|
||||
float32x4_t sm_r_ab_1 = vmulq_f32(numer_inv_two_b_1, inv_r_ab_n_1);
|
||||
float32x4_t sm_r_ab2_0 = vmulq_f32(numer_inv_two_b_0, inv_r_ab2_n_0);
|
||||
float32x4_t sm_r_ab2_1 = vmulq_f32(numer_inv_two_b_1, inv_r_ab2_n_1);
|
||||
|
||||
// # 16 ADDS, 32 MULTS
|
||||
float32x4_t f_x_0 = vfmaq_f32(vmulq_f32(r_ab_x_0, sm_r_ab_0), r_ab2_x_0, sm_r_ab2_0);
|
||||
float32x4_t f_x_1 = vfmaq_f32(vmulq_f32(r_ab_x_1, sm_r_ab_1), r_ab2_x_1, sm_r_ab2_1);
|
||||
float32x4_t f_y_0 = vfmaq_f32(vmulq_f32(r_ab_y_0, sm_r_ab_0), r_ab2_y_0, sm_r_ab2_0);
|
||||
float32x4_t f_y_1 = vfmaq_f32(vmulq_f32(r_ab_y_1, sm_r_ab_1), r_ab2_y_1, sm_r_ab2_1);
|
||||
|
||||
// # 8 ADDS, 16 MULTS
|
||||
float32x4_t f_norm_sq_0 = vfmaq_f32(vmulq_f32(f_y_0, f_y_0), f_x_0, f_x_0);
|
||||
float32x4_t f_norm_sq_1 = vfmaq_f32(vmulq_f32(f_y_1, f_y_1), f_x_1, f_x_1);
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t rhs_0 = vmulq_f32(f_norm_sq_0, v_cos_phi_sq);
|
||||
float32x4_t rhs_1 = vmulq_f32(f_norm_sq_1, v_cos_phi_sq);
|
||||
|
||||
// # 8 ADDS, 16 MULTS
|
||||
float32x4_t e_dot_f_0 = vfmaq_f32(vmulq_f32(eiy, f_y_0), eix, f_x_0);
|
||||
float32x4_t e_dot_f_1 = vfmaq_f32(vmulq_f32(eiy, f_y_1), eix, f_x_1);
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t e_dot_f_sq_0 = vmulq_f32(e_dot_f_0, e_dot_f_0);
|
||||
float32x4_t e_dot_f_sq_1 = vmulq_f32(e_dot_f_1, e_dot_f_1);
|
||||
|
||||
@@ -386,21 +466,26 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
float32x4_t f_y_safe_0 = vbslq_f32(active_0, f_y_0, v_zero);
|
||||
float32x4_t f_y_safe_1 = vbslq_f32(active_1, f_y_1, v_zero);
|
||||
|
||||
// # 16 ADDS, 16 MULTS
|
||||
acc_x_0 = vfmaq_f32(acc_x_0, f_x_safe_0, w_val_0);
|
||||
acc_x_1 = vfmaq_f32(acc_x_1, f_x_safe_1, w_val_1);
|
||||
acc_y_0 = vfmaq_f32(acc_y_0, f_y_safe_0, w_val_0);
|
||||
acc_y_1 = vfmaq_f32(acc_y_1, f_y_safe_1, w_val_1);
|
||||
}
|
||||
|
||||
// # 16 ADDS
|
||||
f_alpha_dt_x += vaddvq_f32(vaddq_f32(acc_x_0, acc_x_1));
|
||||
f_alpha_dt_y += vaddvq_f32(vaddq_f32(acc_y_0, acc_y_1));
|
||||
|
||||
for (int k = 0; k < board.n_obstacles; k++) {
|
||||
|
||||
// # 2 ADDs
|
||||
float v1_x = pos_x[i] - board.obstacles[k].start_x;
|
||||
float v1_y = pos_y[i] - board.obstacles[k].start_y;
|
||||
float v2_x = board.obstacles[k].obstacle_v_x;
|
||||
float v2_y = board.obstacles[k].obstacle_v_y;
|
||||
|
||||
// # 3 MULTs, 1 ADD
|
||||
float projection = (v1_x * v2_x + v1_y * v2_y) * board.obstacles[k].length_sq_inv;
|
||||
|
||||
if (projection < 0.0f)
|
||||
@@ -408,12 +493,15 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
else if (projection > 1.0f)
|
||||
projection = 1.0f;
|
||||
|
||||
// # 4 ADDs, 2 MULTs
|
||||
float r_aB_x = pos_x[i] - (board.obstacles[k].start_x + board.obstacles[k].obstacle_v_x * projection);
|
||||
float r_aB_y = pos_y[i] - (board.obstacles[k].start_y + board.obstacles[k].obstacle_v_y * projection);
|
||||
|
||||
// # 1 SQRT, 2 MULTs, 1 ADD
|
||||
float r_aB_norm = sqrt(r_aB_x * r_aB_x + r_aB_y * r_aB_y);
|
||||
r_aB_norm = r_aB_norm > EPS ? r_aB_norm : EPS;
|
||||
|
||||
// # 4 MULTs, 1 EXP, 1 DIV
|
||||
float scalar_mult = (NEG_U0_AB_div_R * exp(r_aB_norm * NEG_R_INV)) / r_aB_norm;
|
||||
float f_alpha_B_neg_x = r_aB_x * scalar_mult;
|
||||
float f_alpha_B_neg_y = r_aB_y * scalar_mult;
|
||||
@@ -424,13 +512,16 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
if (e_dot_f < cos_phi)
|
||||
w_val = c_neg_times_dt;
|
||||
|
||||
// # 2 MULTS
|
||||
float f_alpha_B_dt_x = f_alpha_B_neg_x * w_val;
|
||||
float f_alpha_B_dt_y = f_alpha_B_neg_y * w_val;
|
||||
|
||||
// # 2 ADDs
|
||||
f_alpha_dt_x += f_alpha_B_dt_x;
|
||||
f_alpha_dt_y += f_alpha_B_dt_y;
|
||||
}
|
||||
|
||||
// # 2 ADDs
|
||||
w_x[i] += f_alpha_dt_x;
|
||||
w_y[i] += f_alpha_dt_y;
|
||||
}
|
||||
@@ -447,14 +538,22 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
float32x4_t desired_v0_i_vec = vld1q_f32(&desired_v0[i]);
|
||||
int32x4_t color_i_vec = vld1q_s32(&color[i]);
|
||||
|
||||
// # 4 ADDS, 8 MULTS
|
||||
float32x4_t w_norm_sq = vfmaq_f32(vmulq_f32(w_y_i_vec, w_y_i_vec), w_x_i_vec, w_x_i_vec);
|
||||
|
||||
// # 4 ADD, 16 MULTS, 4 SQRT, 4 DIV
|
||||
float32x4_t w_norm_inv = _neon_rsqrt_ps(w_norm_sq);
|
||||
|
||||
// # 4 MULTS
|
||||
float32x4_t correction_factor = vminq_f32(v_one, vmulq_f32(v_max_i_vec, w_norm_inv));
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t curr_vel_x_i_vec = vmulq_f32(w_x_i_vec, correction_factor);
|
||||
float32x4_t curr_vel_y_i_vec = vmulq_f32(w_y_i_vec, correction_factor);
|
||||
|
||||
const float32x4_t dt_vec = vdupq_n_f32(dt);
|
||||
|
||||
// # 8 ADDS, 8 MULTS
|
||||
pos_x_i_vec = vfmaq_f32(pos_x_i_vec, curr_vel_x_i_vec, dt_vec);
|
||||
pos_y_i_vec = vfmaq_f32(pos_y_i_vec, curr_vel_y_i_vec, dt_vec);
|
||||
|
||||
@@ -485,15 +584,27 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
pos_y_i_vec = vmaxq_f32(pos_y_i_vec, vdupq_n_f32(WALL_EPS));
|
||||
pos_y_i_vec = vminq_f32(pos_y_i_vec, vdupq_n_f32(BOARD_WIDTH_MINUS_WALL_EPS));
|
||||
|
||||
// # 8 ADDS
|
||||
float32x4_t ex_vec = vsubq_f32(destination_x_i_vec, pos_x_i_vec);
|
||||
float32x4_t ey_vec = vsubq_f32(destination_y_i_vec, pos_y_i_vec);
|
||||
|
||||
// # 4 ADDS, 8 MULTS
|
||||
float32x4_t e_norm_sq = vfmaq_f32(vmulq_f32(ey_vec, ey_vec), ex_vec, ex_vec);
|
||||
|
||||
// # 4 ADD, 16 MULTS, 4 SQRT, 4 DIV
|
||||
float32x4_t e_norm_inv = _neon_rsqrt_ps(e_norm_sq);
|
||||
|
||||
// # 8 MULTS
|
||||
float32x4_t e_x_i_vec = vmulq_f32(ex_vec, e_norm_inv);
|
||||
float32x4_t e_y_i_vec = vmulq_f32(ey_vec, e_norm_inv);
|
||||
|
||||
// # 4 ADDS, 8 MULTS
|
||||
float32x4_t vel_norm_sq = vfmaq_f32(vmulq_f32(curr_vel_y_i_vec, curr_vel_y_i_vec), curr_vel_x_i_vec, curr_vel_x_i_vec);
|
||||
|
||||
// # 4 MULTS
|
||||
float32x4_t sb_sq_i_vec = vmulq_f32(vel_norm_sq, vdupq_n_f32(delta_t_sq));
|
||||
|
||||
// # 4 SQRT
|
||||
float32x4_t vel_norm_dt = vsqrtq_f32(sb_sq_i_vec); // full-precision sqrt, matches AVX-512
|
||||
|
||||
vst1q_f32(&curr_vel_x[i], curr_vel_x_i_vec);
|
||||
@@ -506,6 +617,8 @@ int run_simulation(Pedestrian *pedestrians, Board &board, int n_p, int n_iter, c
|
||||
vst1q_f32(&e_y[i], e_y_i_vec);
|
||||
vst1q_f32(&destination_y[i], destination_y_i_vec);
|
||||
vst1q_f32(&sb_sq[i], sb_sq_i_vec);
|
||||
|
||||
// # 8 MULTS
|
||||
vst1q_f32(&sb_e_x[i], vmulq_f32(e_x_i_vec, vel_norm_dt));
|
||||
vst1q_f32(&sb_e_y[i], vmulq_f32(e_y_i_vec, vel_norm_dt));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user