#include "PPintrin.h" #include #include // implementation of absSerial(), but it is vectorized using PP intrinsics void absVector(float *values, float *output, int N) { __pp_vec_float x; __pp_vec_float result; __pp_vec_float zero = _pp_vset_float(0.f); __pp_mask maskAll, maskIsNegative, maskIsNotNegative; // Note: Take a careful look at this loop indexing. This example // code is not guaranteed to work when (N % VECTOR_WIDTH) != 0. // Why is that the case? for (int i = 0; i < N; i += VECTOR_WIDTH) { // All ones maskAll = _pp_init_ones(); // All zeros maskIsNegative = _pp_init_ones(0); // Load vector of values from contiguous memory addresses _pp_vload_float(x, values + i, maskAll); // x = values[i]; // Set mask according to predicate _pp_vlt_float(maskIsNegative, x, zero, maskAll); // if (x < 0) { // Execute instruction using mask ("if" clause) _pp_vsub_float(result, zero, x, maskIsNegative); // output[i] = -x; // Inverse maskIsNegative to generate "else" mask maskIsNotNegative = _pp_mask_not(maskIsNegative); // } else { // Execute instruction ("else" clause) _pp_vload_float(result, values + i, maskIsNotNegative); // output[i] = x; } // Write results back to memory _pp_vstore_float(output + i, result, maskAll); } } void clampedExpVector(float *values, int *exponents, float *output, int N) { // // PP STUDENTS TODO: Implement your vectorized version of // clampedExpSerial() here. // // Your solution should work for any value of // N and VECTOR_WIDTH, not just when VECTOR_WIDTH divides N // __pp_vec_float x; __pp_vec_int y; __pp_vec_float result; __pp_vec_int zero = _pp_vset_int(0); __pp_vec_float cap = _pp_vset_float(9.999999f); __pp_vec_int one = _pp_vset_int(1); __pp_mask maskAll, maskNonZero, maskGreater; maskAll = _pp_init_ones(); for (int i = 0; i < N; i += VECTOR_WIDTH) { if (i + VECTOR_WIDTH > N) { float *tmp = new float[VECTOR_WIDTH]; for (int j = 0; i + j < N; j++) tmp[j] = values[i+j]; for (int j = N % VECTOR_WIDTH; j < VECTOR_WIDTH; j++) tmp[j] = 0; _pp_vload_float(x, tmp, maskAll); delete []tmp; } else { _pp_vload_float(x, values + i, maskAll); // x = values[i]; } if (i + VECTOR_WIDTH > N) { int *tmp = new int[VECTOR_WIDTH]; for (int j = 0; i + j < N; j++) tmp[j] = exponents[i+j]; for (int j = N % VECTOR_WIDTH; j < VECTOR_WIDTH; j++) tmp[j] = 0; _pp_vload_int(y, tmp, maskAll); delete []tmp; } else { _pp_vload_int(y, exponents + i, maskAll); // y = exponents[i]; } cout << "min exponents: " << *min_element(y.value, y.value+VECTOR_WIDTH) << endl; cout << "max exponents: " << *max_element(y.value, y.value+VECTOR_WIDTH) << endl; _pp_vset_float(result, 1.f, maskAll); maskNonZero = _pp_init_ones(); while (_pp_cntbits(maskNonZero) > 0) { _pp_veq_int(maskNonZero, y, zero, maskAll); maskNonZero = _pp_mask_not(maskNonZero); _pp_vmult_float(result, result, x, maskNonZero); _pp_vsub_int(y, y, one, maskNonZero); } _pp_vgt_float(maskGreater, result, cap, maskAll); _pp_vset_float(result, 9.999999f, maskGreater); if (i + VECTOR_WIDTH > N) { float *tmp = new float[VECTOR_WIDTH]; _pp_vstore_float(tmp, result, maskAll); for (int j = 0; i + j < N; j++) output[i+j] = tmp[j]; delete []tmp; } else { _pp_vstore_float(output + i, result, maskAll); } } } // returns the sum of all elements in values // You can assume N is a multiple of VECTOR_WIDTH // You can assume VECTOR_WIDTH is a power of 2 float arraySumVector(float *values, int N) { // // PP STUDENTS TODO: Implement your vectorized version of arraySumSerial here // __pp_vec_float x; __pp_mask maskAll; maskAll = _pp_init_ones(); float total = 0.f; for (int i = 0; i < N; i += VECTOR_WIDTH) { _pp_vload_float(x, values + i, maskAll); for (int n = VECTOR_WIDTH; n > 1; n >>= 1) { _pp_hadd_float(x, x); _pp_interleave_float(x, x); } float *tmp = new float[VECTOR_WIDTH]; _pp_vstore_float(tmp, x, maskAll); total += tmp[0]; delete []tmp; } return total; }