init: HW1
This commit is contained in:
20 files changed
+1197
No files matched your search
@@ -0,0 +1,20 @@
|
|||||||
|
CXX := g++
|
||||||
|
CXXFLAGS := -O3 -std=c++17 -Wall
|
||||||
|
|
||||||
|
ifneq ($(VECTOR_WIDTH),)
|
||||||
|
CXXFLAGS += -DVECTOR_WIDTH=$(VECTOR_WIDTH)
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: myexp
|
||||||
|
|
||||||
|
logger.o: logger.cpp logger.h PPintrin.h PPintrin.cpp def.h
|
||||||
|
$(CXX) $(CXXFLAGS) -c logger.cpp
|
||||||
|
|
||||||
|
PPintrin.o: PPintrin.cpp PPintrin.h logger.cpp logger.h def.h
|
||||||
|
$(CXX) $(CXXFLAGS) -c PPintrin.cpp
|
||||||
|
|
||||||
|
myexp: PPintrin.o logger.o main.cpp serialOP.cpp vectorOP.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) logger.o PPintrin.o main.cpp serialOP.cpp vectorOP.cpp -o myexp
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) *.o *.s myexp *~
|
||||||
@@ -0,0 +1,304 @@
|
|||||||
|
#include "PPintrin.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
|
//******************
|
||||||
|
//* Implementation *
|
||||||
|
//******************
|
||||||
|
|
||||||
|
__pp_mask _pp_init_ones(int first)
|
||||||
|
{
|
||||||
|
__pp_mask mask;
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
mask.value[i] = (i < first) ? true : false;
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
__pp_mask _pp_mask_not(__pp_mask &maska)
|
||||||
|
{
|
||||||
|
__pp_mask resultMask;
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
resultMask.value[i] = !maska.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("masknot", _pp_init_ones(), VECTOR_WIDTH);
|
||||||
|
return resultMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
__pp_mask _pp_mask_or(__pp_mask &maska, __pp_mask &maskb)
|
||||||
|
{
|
||||||
|
__pp_mask resultMask;
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
resultMask.value[i] = maska.value[i] | maskb.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("maskor", _pp_init_ones(), VECTOR_WIDTH);
|
||||||
|
return resultMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
__pp_mask _pp_mask_and(__pp_mask &maska, __pp_mask &maskb)
|
||||||
|
{
|
||||||
|
__pp_mask resultMask;
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
resultMask.value[i] = maska.value[i] && maskb.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("maskand", _pp_init_ones(), VECTOR_WIDTH);
|
||||||
|
return resultMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _pp_cntbits(__pp_mask &maska)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
if (maska.value[i])
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
PPLogger.addLog("cntbits", _pp_init_ones(), VECTOR_WIDTH);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vset(__pp_vec<T> &vecResult, T value, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
vecResult.value[i] = mask.value[i] ? value : vecResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vset", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vset<float>(__pp_vec_float &vecResult, float value, __pp_mask &mask);
|
||||||
|
template void _pp_vset<int>(__pp_vec_int &vecResult, int value, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vset_float(__pp_vec_float &vecResult, float value, __pp_mask &mask) { _pp_vset<float>(vecResult, value, mask); }
|
||||||
|
void _pp_vset_int(__pp_vec_int &vecResult, int value, __pp_mask &mask) { _pp_vset<int>(vecResult, value, mask); }
|
||||||
|
|
||||||
|
__pp_vec_float _pp_vset_float(float value)
|
||||||
|
{
|
||||||
|
__pp_vec_float vecResult;
|
||||||
|
__pp_mask mask = _pp_init_ones();
|
||||||
|
_pp_vset_float(vecResult, value, mask);
|
||||||
|
return vecResult;
|
||||||
|
}
|
||||||
|
__pp_vec_int _pp_vset_int(int value)
|
||||||
|
{
|
||||||
|
__pp_vec_int vecResult;
|
||||||
|
__pp_mask mask = _pp_init_ones();
|
||||||
|
_pp_vset_int(vecResult, value, mask);
|
||||||
|
return vecResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vmove(__pp_vec<T> &dest, __pp_vec<T> &src, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
dest.value[i] = mask.value[i] ? src.value[i] : dest.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vmove", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vmove<float>(__pp_vec_float &dest, __pp_vec_float &src, __pp_mask &mask);
|
||||||
|
template void _pp_vmove<int>(__pp_vec_int &dest, __pp_vec_int &src, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vmove_float(__pp_vec_float &dest, __pp_vec_float &src, __pp_mask &mask) { _pp_vmove<float>(dest, src, mask); }
|
||||||
|
void _pp_vmove_int(__pp_vec_int &dest, __pp_vec_int &src, __pp_mask &mask) { _pp_vmove<int>(dest, src, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vload(__pp_vec<T> &dest, T *src, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
dest.value[i] = mask.value[i] ? src[i] : dest.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vload", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vload<float>(__pp_vec_float &dest, float *src, __pp_mask &mask);
|
||||||
|
template void _pp_vload<int>(__pp_vec_int &dest, int *src, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vload_float(__pp_vec_float &dest, float *src, __pp_mask &mask) { _pp_vload<float>(dest, src, mask); }
|
||||||
|
void _pp_vload_int(__pp_vec_int &dest, int *src, __pp_mask &mask) { _pp_vload<int>(dest, src, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vstore(T *dest, __pp_vec<T> &src, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
dest[i] = mask.value[i] ? src.value[i] : dest[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vstore", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vstore<float>(float *dest, __pp_vec_float &src, __pp_mask &mask);
|
||||||
|
template void _pp_vstore<int>(int *dest, __pp_vec_int &src, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vstore_float(float *dest, __pp_vec_float &src, __pp_mask &mask) { _pp_vstore<float>(dest, src, mask); }
|
||||||
|
void _pp_vstore_int(int *dest, __pp_vec_int &src, __pp_mask &mask) { _pp_vstore<int>(dest, src, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vadd(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
vecResult.value[i] = mask.value[i] ? (veca.value[i] + vecb.value[i]) : vecResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vadd", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vadd<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
template void _pp_vadd<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vadd_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vadd<float>(vecResult, veca, vecb, mask); }
|
||||||
|
void _pp_vadd_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vadd<int>(vecResult, veca, vecb, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vsub(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
vecResult.value[i] = mask.value[i] ? (veca.value[i] - vecb.value[i]) : vecResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vsub", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vsub<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
template void _pp_vsub<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vsub_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vsub<float>(vecResult, veca, vecb, mask); }
|
||||||
|
void _pp_vsub_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vsub<int>(vecResult, veca, vecb, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vmult(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
vecResult.value[i] = mask.value[i] ? (veca.value[i] * vecb.value[i]) : vecResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vmult", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vmult<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
template void _pp_vmult<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vmult_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vmult<float>(vecResult, veca, vecb, mask); }
|
||||||
|
void _pp_vmult_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vmult<int>(vecResult, veca, vecb, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vdiv(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
vecResult.value[i] = mask.value[i] ? (veca.value[i] / vecb.value[i]) : vecResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vdiv", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vdiv<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
template void _pp_vdiv<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vdiv_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vdiv<float>(vecResult, veca, vecb, mask); }
|
||||||
|
void _pp_vdiv_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vdiv<int>(vecResult, veca, vecb, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vabs(__pp_vec<T> &vecResult, __pp_vec<T> &veca, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
vecResult.value[i] = mask.value[i] ? (abs(veca.value[i])) : vecResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vabs", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vabs<float>(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_mask &mask);
|
||||||
|
template void _pp_vabs<int>(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vabs_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_mask &mask) { _pp_vabs<float>(vecResult, veca, mask); }
|
||||||
|
void _pp_vabs_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_mask &mask) { _pp_vabs<int>(vecResult, veca, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vgt(__pp_mask &maskResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
maskResult.value[i] = mask.value[i] ? (veca.value[i] > vecb.value[i]) : maskResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vgt", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vgt<float>(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
template void _pp_vgt<int>(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vgt_float(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vgt<float>(maskResult, veca, vecb, mask); }
|
||||||
|
void _pp_vgt_int(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vgt<int>(maskResult, veca, vecb, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_vlt(__pp_mask &maskResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
maskResult.value[i] = mask.value[i] ? (veca.value[i] < vecb.value[i]) : maskResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("vlt", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_vlt<float>(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
template void _pp_vlt<int>(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_vlt_float(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_vlt<float>(maskResult, veca, vecb, mask); }
|
||||||
|
void _pp_vlt_int(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_vlt<int>(maskResult, veca, vecb, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_veq(__pp_mask &maskResult, __pp_vec<T> &veca, __pp_vec<T> &vecb, __pp_mask &mask)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
maskResult.value[i] = mask.value[i] ? (veca.value[i] == vecb.value[i]) : maskResult.value[i];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("veq", mask, VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_veq<float>(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
template void _pp_veq<int>(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
void _pp_veq_float(__pp_mask &maskResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask) { _pp_veq<float>(maskResult, veca, vecb, mask); }
|
||||||
|
void _pp_veq_int(__pp_mask &maskResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask) { _pp_veq<int>(maskResult, veca, vecb, mask); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_hadd(__pp_vec<T> &vecResult, __pp_vec<T> &vec)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH / 2; i++)
|
||||||
|
{
|
||||||
|
T result = vec.value[2 * i] + vec.value[2 * i + 1];
|
||||||
|
vecResult.value[2 * i] = result;
|
||||||
|
vecResult.value[2 * i + 1] = result;
|
||||||
|
}
|
||||||
|
PPLogger.addLog("hadd", _pp_init_ones(), VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_hadd<float>(__pp_vec_float &vecResult, __pp_vec_float &vec);
|
||||||
|
|
||||||
|
void _pp_hadd_float(__pp_vec_float &vecResult, __pp_vec_float &vec) { _pp_hadd<float>(vecResult, vec); }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void _pp_interleave(__pp_vec<T> &vecResult, __pp_vec<T> vec)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
int index = i < VECTOR_WIDTH / 2 ? (2 * i) : (2 * (i - VECTOR_WIDTH / 2) + 1);
|
||||||
|
vecResult.value[i] = vec.value[index];
|
||||||
|
}
|
||||||
|
PPLogger.addLog("interleave", _pp_init_ones(), VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
template void _pp_interleave<float>(__pp_vec_float &vecResult, __pp_vec_float vec);
|
||||||
|
|
||||||
|
void _pp_interleave_float(__pp_vec_float &vecResult, __pp_vec_float vec) { _pp_interleave<float>(vecResult, vec); }
|
||||||
|
|
||||||
|
void addUserLog(const char *logStr)
|
||||||
|
{
|
||||||
|
PPLogger.addLog(logStr, _pp_init_ones(), 0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
#ifndef PPINTRIN_H_
|
||||||
|
#define PPINTRIN_H_
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cmath>
|
||||||
|
#include "logger.h"
|
||||||
|
#include "def.h"
|
||||||
|
//*******************
|
||||||
|
//* Type Definition *
|
||||||
|
//*******************
|
||||||
|
|
||||||
|
extern Logger PPLogger;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct __pp_vec {
|
||||||
|
T value[VECTOR_WIDTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Declare a mask with __pp_mask
|
||||||
|
struct __pp_mask : __pp_vec<bool> {};
|
||||||
|
|
||||||
|
// Declare a floating point vector register with __pp_vec_float
|
||||||
|
#define __pp_vec_float __pp_vec<float>
|
||||||
|
|
||||||
|
// Declare an integer vector register with __pp_vec_int
|
||||||
|
#define __pp_vec_int __pp_vec<int>
|
||||||
|
|
||||||
|
//***********************
|
||||||
|
//* Function Definition *
|
||||||
|
//***********************
|
||||||
|
|
||||||
|
// Return a mask initialized to 1 in the first N lanes and 0 in the others
|
||||||
|
__pp_mask _pp_init_ones(int first = VECTOR_WIDTH);
|
||||||
|
|
||||||
|
// Return the inverse of maska
|
||||||
|
__pp_mask _pp_mask_not(__pp_mask &maska);
|
||||||
|
|
||||||
|
// Return (maska | maskb)
|
||||||
|
__pp_mask _pp_mask_or(__pp_mask &maska, __pp_mask &maskb);
|
||||||
|
|
||||||
|
// Return (maska & maskb)
|
||||||
|
__pp_mask _pp_mask_and(__pp_mask &maska, __pp_mask &maskb);
|
||||||
|
|
||||||
|
// Count the number of 1s in maska
|
||||||
|
int _pp_cntbits(__pp_mask &maska);
|
||||||
|
|
||||||
|
// Set register to value if vector lane is active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vset_float(__pp_vec_float &vecResult, float value, __pp_mask &mask);
|
||||||
|
void _pp_vset_int(__pp_vec_int &vecResult, int value, __pp_mask &mask);
|
||||||
|
// For user's convenience, returns a vector register with all lanes initialized to value
|
||||||
|
__pp_vec_float _pp_vset_float(float value);
|
||||||
|
__pp_vec_int _pp_vset_int(int value);
|
||||||
|
|
||||||
|
// Copy values from vector register src to vector register dest if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vmove_float(__pp_vec_float &dest, __pp_vec_float &src, __pp_mask &mask);
|
||||||
|
void _pp_vmove_int(__pp_vec_int &dest, __pp_vec_int &src, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Load values from array src to vector register dest if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vload_float(__pp_vec_float &dest, float* src, __pp_mask &mask);
|
||||||
|
void _pp_vload_int(__pp_vec_int &dest, int* src, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Store values from vector register src to array dest if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vstore_float(float* dest, __pp_vec_float &src, __pp_mask &mask);
|
||||||
|
void _pp_vstore_int(int* dest, __pp_vec_int &src, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Return calculation of (veca + vecb) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vadd_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
void _pp_vadd_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Return calculation of (veca - vecb) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vsub_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
void _pp_vsub_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Return calculation of (veca * vecb) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vmult_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
void _pp_vmult_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Return calculation of (veca / vecb) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vdiv_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
void _pp_vdiv_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
|
||||||
|
// Return calculation of absolute value abs(veca) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vabs_float(__pp_vec_float &vecResult, __pp_vec_float &veca, __pp_mask &mask);
|
||||||
|
void _pp_vabs_int(__pp_vec_int &vecResult, __pp_vec_int &veca, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Return a mask of (veca > vecb) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vgt_float(__pp_mask &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
void _pp_vgt_int(__pp_mask &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Return a mask of (veca < vecb) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_vlt_float(__pp_mask &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
void _pp_vlt_int(__pp_mask &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Return a mask of (veca == vecb) if vector lane active
|
||||||
|
// otherwise keep the old value
|
||||||
|
void _pp_veq_float(__pp_mask &vecResult, __pp_vec_float &veca, __pp_vec_float &vecb, __pp_mask &mask);
|
||||||
|
void _pp_veq_int(__pp_mask &vecResult, __pp_vec_int &veca, __pp_vec_int &vecb, __pp_mask &mask);
|
||||||
|
|
||||||
|
// Adds up adjacent pairs of elements, so
|
||||||
|
// [0 1 2 3] -> [0+1 0+1 2+3 2+3]
|
||||||
|
void _pp_hadd_float(__pp_vec_float &vecResult, __pp_vec_float &vec);
|
||||||
|
|
||||||
|
// Performs an even-odd interleaving where all even-indexed elements move to front half
|
||||||
|
// of the array and odd-indexed to the back half, so
|
||||||
|
// [0 1 2 3 4 5 6 7] -> [0 2 4 6 1 3 5 7]
|
||||||
|
void _pp_interleave_float(__pp_vec_float &vecResult, __pp_vec_float vec);
|
||||||
|
|
||||||
|
// Add a customized log to help debugging
|
||||||
|
void addUserLog(const char * logStr);
|
||||||
|
|
||||||
|
#endif
|
||||||
Binary file not shown.
@@ -0,0 +1,5 @@
|
|||||||
|
// Define vector unit width here
|
||||||
|
#ifndef VECTOR_WIDTH
|
||||||
|
#define VECTOR_WIDTH 4
|
||||||
|
#endif
|
||||||
|
#define EXP_MAX 10
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#include "logger.h"
|
||||||
|
#include "PPintrin.h"
|
||||||
|
|
||||||
|
void Logger::addLog(const char *instruction, __pp_mask mask, int N)
|
||||||
|
{
|
||||||
|
Log newLog;
|
||||||
|
strcpy(newLog.instruction, instruction);
|
||||||
|
newLog.mask = 0;
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
if (mask.value[i])
|
||||||
|
{
|
||||||
|
newLog.mask |= (((unsigned long long)1) << i);
|
||||||
|
stats.utilized_lane++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stats.total_lane += N;
|
||||||
|
stats.total_instructions += (N > 0);
|
||||||
|
log.push_back(newLog);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::printStats()
|
||||||
|
{
|
||||||
|
printf("****************** Printing Vector Unit Statistics *******************\n");
|
||||||
|
printf("Vector Width: %d\n", VECTOR_WIDTH);
|
||||||
|
printf("Total Vector Instructions: %lld\n", stats.total_instructions);
|
||||||
|
printf("Vector Utilization: %.1f%%\n", (double)stats.utilized_lane / stats.total_lane * 100);
|
||||||
|
printf("Utilized Vector Lanes: %lld\n", stats.utilized_lane);
|
||||||
|
printf("Total Vector Lanes: %lld\n", stats.total_lane);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::printLog()
|
||||||
|
{
|
||||||
|
printf("***************** Printing Vector Unit Execution Log *****************\n");
|
||||||
|
printf(" Instruction | Vector Lane Occupancy ('*' for active, '_' for inactive)\n");
|
||||||
|
printf("------------- --------------------------------------------------------\n");
|
||||||
|
for (int i = 0; i < log.size(); i++)
|
||||||
|
{
|
||||||
|
printf("%12s | ", log[i].instruction);
|
||||||
|
for (int j = 0; j < VECTOR_WIDTH; j++)
|
||||||
|
{
|
||||||
|
if (log[i].mask & (((unsigned long long)1) << j))
|
||||||
|
{
|
||||||
|
printf("*");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("_");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::refresh()
|
||||||
|
{
|
||||||
|
stats.total_instructions = 0;
|
||||||
|
stats.total_lane = 0;
|
||||||
|
stats.utilized_lane = 0;
|
||||||
|
fflush(stdout);
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long long Logger::getTotalInstrs()
|
||||||
|
{
|
||||||
|
return stats.total_instructions;
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef LOGGER_H_
|
||||||
|
#define LOGGER_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <string.h>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define MAX_INST_LEN 32
|
||||||
|
|
||||||
|
struct __pp_mask;
|
||||||
|
|
||||||
|
struct Log {
|
||||||
|
char instruction[MAX_INST_LEN];
|
||||||
|
unsigned long long mask; // support vector width up to 64
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Statistics {
|
||||||
|
unsigned long long utilized_lane;
|
||||||
|
unsigned long long total_lane;
|
||||||
|
unsigned long long total_instructions;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
private:
|
||||||
|
vector<Log> log;
|
||||||
|
Statistics stats;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addLog(const char * instruction, __pp_mask mask, int N = 0);
|
||||||
|
void printStats();
|
||||||
|
void printLog();
|
||||||
|
void refresh();
|
||||||
|
unsigned long long getTotalInstrs();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
Binary file not shown.
+204
@@ -0,0 +1,204 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "logger.h"
|
||||||
|
#include <sstream>
|
||||||
|
#include "def.h"
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
Logger PPLogger;
|
||||||
|
|
||||||
|
void usage(const char *progname);
|
||||||
|
void initValue(float *values, int *exponents, float *output, float *gold, unsigned int N);
|
||||||
|
void absSerial(float *values, float *output, int N);
|
||||||
|
void absVector(float *values, float *output, int N);
|
||||||
|
void clampedExpSerial(float *values, int *exponents, float *output, int N);
|
||||||
|
void clampedExpVector(float *values, int *exponents, float *output, int N);
|
||||||
|
float arraySumSerial(float *values, int N);
|
||||||
|
float arraySumVector(float *values, int N);
|
||||||
|
bool verifyResult(float *values, int *exponents, float *output, float *gold, int N);
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int N = 16;
|
||||||
|
bool printLog = false;
|
||||||
|
|
||||||
|
// parse commandline options ////////////////////////////////////////////
|
||||||
|
int opt;
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"size", 1, 0, 's'},
|
||||||
|
{"log", 0, 0, 'l'},
|
||||||
|
{"help", 0, 0, '?'},
|
||||||
|
{0, 0, 0, 0}};
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "s:l?", long_options, NULL)) != EOF)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (opt)
|
||||||
|
{
|
||||||
|
case 's':
|
||||||
|
N = atoi(optarg);
|
||||||
|
if (N <= 0)
|
||||||
|
{
|
||||||
|
printf("Error: Workload size is set to %d (<0).\n", N);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
printLog = true;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float *values = new float[N + VECTOR_WIDTH];
|
||||||
|
int *exponents = new int[N + VECTOR_WIDTH];
|
||||||
|
float *output = new float[N + VECTOR_WIDTH];
|
||||||
|
float *gold = new float[N + VECTOR_WIDTH];
|
||||||
|
initValue(values, exponents, output, gold, N);
|
||||||
|
|
||||||
|
clampedExpSerial(values, exponents, gold, N);
|
||||||
|
clampedExpVector(values, exponents, output, N);
|
||||||
|
|
||||||
|
//absSerial(values, gold, N);
|
||||||
|
//absVector(values, output, N);
|
||||||
|
|
||||||
|
printf("\e[1;31mCLAMPED EXPONENT\e[0m (required) \n");
|
||||||
|
bool clampedCorrect = verifyResult(values, exponents, output, gold, N);
|
||||||
|
if (printLog)
|
||||||
|
PPLogger.printLog();
|
||||||
|
PPLogger.printStats();
|
||||||
|
|
||||||
|
printf("************************ Result Verification *************************\n");
|
||||||
|
if (!clampedCorrect)
|
||||||
|
{
|
||||||
|
printf("@@@ ClampedExp Failed!!!\n");
|
||||||
|
}
|
||||||
|
else if (PPLogger.getTotalInstrs() == 0)
|
||||||
|
{
|
||||||
|
printf("Not using fake intrinsics in ClampedExp\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ClampedExp Passed!!!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
PPLogger.refresh();
|
||||||
|
|
||||||
|
printf("\n\e[1;31mARRAY SUM\e[0m (bonus) \n");
|
||||||
|
if (N % VECTOR_WIDTH == 0)
|
||||||
|
{
|
||||||
|
float sumGold = arraySumSerial(values, N);
|
||||||
|
float sumOutput = arraySumVector(values, N);
|
||||||
|
|
||||||
|
if (printLog)
|
||||||
|
PPLogger.printLog();
|
||||||
|
PPLogger.printStats();
|
||||||
|
|
||||||
|
printf("************************ Result Verification *************************\n");
|
||||||
|
|
||||||
|
float epsilon = 0.1;
|
||||||
|
bool sumCorrect = abs(sumGold - sumOutput) < epsilon * 2;
|
||||||
|
if (!sumCorrect)
|
||||||
|
{
|
||||||
|
printf("Expected %f, got %f\n.", sumGold, sumOutput);
|
||||||
|
printf("@@@ ArraySum Failed!!!\n");
|
||||||
|
}
|
||||||
|
else if (PPLogger.getTotalInstrs() == 0)
|
||||||
|
{
|
||||||
|
printf("Not using fake intrinsics in ArraySum\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ArraySum Passed!!!\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Must have N %% VECTOR_WIDTH == 0 for this problem (VECTOR_WIDTH is %d)\n", VECTOR_WIDTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] values;
|
||||||
|
delete[] exponents;
|
||||||
|
delete[] output;
|
||||||
|
delete[] gold;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(const char *progname)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [options]\n", progname);
|
||||||
|
printf("Program Options:\n");
|
||||||
|
printf(" -s --size <N> Use workload size N (Default = 16)\n");
|
||||||
|
printf(" -l --log Print vector unit execution log\n");
|
||||||
|
printf(" -? --help This message\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void initValue(float *values, int *exponents, float *output, float *gold, unsigned int N)
|
||||||
|
{
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < N + VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
// random input values
|
||||||
|
values[i] = -1.f + 4.f * static_cast<float>(rand()) / RAND_MAX;
|
||||||
|
exponents[i] = rand() % EXP_MAX;
|
||||||
|
output[i] = 0.f;
|
||||||
|
gold[i] = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool verifyResult(float *values, int *exponents, float *output, float *gold, int N)
|
||||||
|
{
|
||||||
|
int incorrect = -1;
|
||||||
|
float epsilon = 0.00001;
|
||||||
|
for (int i = 0; i < N + VECTOR_WIDTH; i++)
|
||||||
|
{
|
||||||
|
if (abs(output[i] - gold[i]) > epsilon)
|
||||||
|
{
|
||||||
|
incorrect = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (incorrect != -1)
|
||||||
|
{
|
||||||
|
if (incorrect >= N)
|
||||||
|
printf("You have written to out of bound value!\n");
|
||||||
|
printf("Wrong calculation at value[%d]!\n", incorrect);
|
||||||
|
printf("value = ");
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
printf("% f ", values[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("exp = ");
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
printf("% 9d ", exponents[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("output = ");
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
printf("% f ", output[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("gold = ");
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
printf("% f ", gold[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("Results matched with answer!\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,61 @@
|
|||||||
|
// computes the absolute value of all elements in the input array
|
||||||
|
// values, stores result in output
|
||||||
|
void absSerial(float *values, float *output, int N)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
float x = values[i];
|
||||||
|
if (x < 0)
|
||||||
|
{
|
||||||
|
output[i] = -x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output[i] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// accepts an array of values and an array of exponents
|
||||||
|
//
|
||||||
|
// For each element, compute values[i]^exponents[i] and clamp value to
|
||||||
|
// 9.999. Store result in output.
|
||||||
|
void clampedExpSerial(float *values, int *exponents, float *output, int N)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
float x = values[i];
|
||||||
|
int y = exponents[i];
|
||||||
|
if (y == 0)
|
||||||
|
{
|
||||||
|
output[i] = 1.f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
float result = x;
|
||||||
|
int count = y - 1;
|
||||||
|
while (count > 0)
|
||||||
|
{
|
||||||
|
result *= x;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
if (result > 9.999999f)
|
||||||
|
{
|
||||||
|
result = 9.999999f;
|
||||||
|
}
|
||||||
|
output[i] = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the sum of all elements in values
|
||||||
|
float arraySumSerial(float *values, int N)
|
||||||
|
{
|
||||||
|
float sum = 0;
|
||||||
|
for (int i = 0; i < N; i++)
|
||||||
|
{
|
||||||
|
sum += values[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#include "PPintrin.h"
|
||||||
|
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
for (int i = 0; i < N; i += VECTOR_WIDTH)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
for (int i = 0; i < N; i += VECTOR_WIDTH)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
TARGET := test_auto_vectorize
|
||||||
|
|
||||||
|
OBJS := main.o test1.o test2.o test3.o
|
||||||
|
|
||||||
|
CC := clang
|
||||||
|
|
||||||
|
CFLAGS := -O3 -std=c11 -Wall -D_POSIX_C_SOURCE=200809L
|
||||||
|
|
||||||
|
ifeq ($(ASSEMBLE),1)
|
||||||
|
CFLAGS += -S
|
||||||
|
endif
|
||||||
|
ifeq ($(VECTORIZE),1)
|
||||||
|
CFLAGS += -Rpass=loop-vectorize -Rpass-missed=loop-vectorize -Rpass-analysis=loop-vectorize
|
||||||
|
SUFFIX := .vec
|
||||||
|
else
|
||||||
|
CFLAGS += -fno-vectorize
|
||||||
|
SUFFIX := .novec
|
||||||
|
endif
|
||||||
|
ifeq ($(RESTRICT),1)
|
||||||
|
SUFFIX := $(SUFFIX).restr
|
||||||
|
endif
|
||||||
|
ifeq ($(ALIGN),1)
|
||||||
|
SUFFIX := $(SUFFIX).align
|
||||||
|
endif
|
||||||
|
ifeq ($(AVX2),1)
|
||||||
|
CFLAGS += -mavx2
|
||||||
|
SUFFIX := $(SUFFIX).avx2
|
||||||
|
endif
|
||||||
|
ifeq ($(FASTMATH),1)
|
||||||
|
CFLAGS += -ffast-math
|
||||||
|
SUFFIX := $(SUFFIX).fmath
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
%.o: %.c test.h
|
||||||
|
ifeq ($(ASSEMBLE),1)
|
||||||
|
mkdir -p "./assembly"
|
||||||
|
$(CC) $(CFLAGS) -c $< -o assembly/$(basename $<)$(SUFFIX).s
|
||||||
|
else
|
||||||
|
$(CC) $(CFLAGS) -c $<
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
ifneq ($(ASSEMBLE),1)
|
||||||
|
$(CC) $(CFLAGS) $(OBJS) -o $@
|
||||||
|
endif
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) *.o *.s $(TARGET) *~
|
||||||
|
|
||||||
|
cleanall:
|
||||||
|
$(RM) -r *.o *.s $(TARGET) *~ assembly
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2014 MIT License by 6.172 Staff
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#ifndef INCLUDED_FASTTIME_DOT_H
|
||||||
|
#define INCLUDED_FASTTIME_DOT_H
|
||||||
|
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#ifdef __MACH__
|
||||||
|
#include <mach/mach_time.h> // mach_absolute_time
|
||||||
|
|
||||||
|
typedef uint64_t fasttime_t;
|
||||||
|
|
||||||
|
|
||||||
|
// Return the current time.
|
||||||
|
static inline fasttime_t gettime(void) {
|
||||||
|
return mach_absolute_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the time different between the start and the end, as a float
|
||||||
|
// in units of seconds. This function does not need to be fast.
|
||||||
|
// Implementation notes: See
|
||||||
|
// https://developer.apple.com/library/mac/qa/qa1398/_index.html
|
||||||
|
static inline double tdiff(fasttime_t start, fasttime_t end) {
|
||||||
|
static mach_timebase_info_data_t timebase;
|
||||||
|
int r = mach_timebase_info(&timebase);
|
||||||
|
assert(r == 0);
|
||||||
|
fasttime_t elapsed = end-start;
|
||||||
|
double ns = (double)elapsed * timebase.numer / timebase.denom;
|
||||||
|
return ns*1e-9;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int random_seed_from_clock(void) {
|
||||||
|
fasttime_t now = gettime();
|
||||||
|
return (now & 0xFFFFFFFF) + (now>>32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // LINUX
|
||||||
|
|
||||||
|
// We need _POSIX_C_SOURCE to pick up 'struct timespec' and clock_gettime.
|
||||||
|
// #define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
typedef struct timespec fasttime_t;
|
||||||
|
|
||||||
|
// Return the current time.
|
||||||
|
static inline fasttime_t gettime(void) {
|
||||||
|
struct timespec s;
|
||||||
|
#ifdef NDEBUG
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &s);
|
||||||
|
#else
|
||||||
|
int r = clock_gettime(CLOCK_MONOTONIC, &s);
|
||||||
|
assert(r == 0);
|
||||||
|
#endif
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the time different between the start and the end, as a float
|
||||||
|
// in units of seconds. This function does not need to be fast.
|
||||||
|
static inline double tdiff(fasttime_t start, fasttime_t end) {
|
||||||
|
return end.tv_sec - start.tv_sec + 1e-9*(end.tv_nsec - start.tv_nsec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int random_seed_from_clock(void) {
|
||||||
|
fasttime_t now = gettime();
|
||||||
|
return now.tv_sec + now.tv_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poison these symbols to help find portability problems.
|
||||||
|
int clock_gettime(clockid_t, struct timespec *) __attribute__((deprecated));
|
||||||
|
time_t time(time_t *) __attribute__((deprecated));
|
||||||
|
|
||||||
|
#endif // LINUX
|
||||||
|
|
||||||
|
#endif // INCLUDED_FASTTIME_DOT_H
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "fasttime.h"
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
void usage(const char *progname);
|
||||||
|
void initValue(float *values1, float *values2, double *value3, float *output, unsigned int N);
|
||||||
|
|
||||||
|
extern void test1(float *a, float *b, float *c, int N);
|
||||||
|
extern void test2(float *__restrict a, float *__restrict b, float *__restrict c, int N);
|
||||||
|
extern double test3(double *__restrict a, int N) ;
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
int N = 1024;
|
||||||
|
int whichTestToRun = 1;
|
||||||
|
|
||||||
|
// parse commandline options
|
||||||
|
int opt;
|
||||||
|
static struct option long_options[] = {
|
||||||
|
{"size", 1, 0, 's'},
|
||||||
|
{"test", 1, 0, 't'},
|
||||||
|
{"help", 0, 0, '?'},
|
||||||
|
{0 ,0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "st:?", long_options, NULL)) != EOF) {
|
||||||
|
|
||||||
|
switch (opt) {
|
||||||
|
case 's':
|
||||||
|
N = atoi(optarg);
|
||||||
|
if (N <= 0) {
|
||||||
|
printf("Error: Workload size is set to %d (<0).\n", N);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
whichTestToRun = atoi(optarg);
|
||||||
|
if (whichTestToRun <= 0 || whichTestToRun >= 4) {
|
||||||
|
printf("Error: test%d() is not available.\n", whichTestToRun);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
default:
|
||||||
|
usage(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define AVX_ALIGNMENT 256
|
||||||
|
float *values1 = (float *)__builtin_alloca_with_align(N * sizeof(float), AVX_ALIGNMENT);
|
||||||
|
float *values2 = (float *)__builtin_alloca_with_align(N * sizeof(float), AVX_ALIGNMENT);
|
||||||
|
double *values3 = (double *)__builtin_alloca_with_align(N * sizeof(double), AVX_ALIGNMENT);
|
||||||
|
float *output = (float *)__builtin_alloca_with_align(N * sizeof(float), AVX_ALIGNMENT);
|
||||||
|
#undef AVX_ALIGNMENT
|
||||||
|
initValue(values1, values2, values3, output, N);
|
||||||
|
|
||||||
|
printf("Running test%d()...\n", whichTestToRun);
|
||||||
|
fasttime_t time1 = gettime();
|
||||||
|
switch (whichTestToRun) {
|
||||||
|
case 1: test1(values1, values2, output, N); break;
|
||||||
|
case 2: test2(values1, values2, output, N); break;
|
||||||
|
case 3: test3(values3, N); break;
|
||||||
|
}
|
||||||
|
fasttime_t time2 = gettime();
|
||||||
|
|
||||||
|
double elapsedf = tdiff(time1, time2);
|
||||||
|
printf("Elapsed execution time of the loop in test%d():\n", whichTestToRun);
|
||||||
|
printf("%lfsec (N: %d, I: %d)\n", elapsedf, N, I);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage(const char *progname) {
|
||||||
|
printf("Usage: %s [options]\n", progname);
|
||||||
|
printf("Program Options:\n");
|
||||||
|
printf(" -s --size <N> Use workload size N (Default = 1024)\n");
|
||||||
|
printf(" -t --test <N> Just run the testN function (Default = 1)\n");
|
||||||
|
printf(" -h --help This message\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void initValue(float *values1, float *values2, double *values3, float *output, unsigned int N) {
|
||||||
|
for (unsigned int i=0; i<N; i++)
|
||||||
|
{
|
||||||
|
// random input values
|
||||||
|
values1[i] = -1.0f + 4.0f * rand() / (float)RAND_MAX;
|
||||||
|
values2[i] = -1.0f + 4.0f * rand() / (float)RAND_MAX;
|
||||||
|
values3[i] = -1.0 + 4.0 * rand() / (double)RAND_MAX;
|
||||||
|
output[i] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#ifndef TEST_H
|
||||||
|
#define TEST_H
|
||||||
|
|
||||||
|
// Run for multiple experiments to reduce measurement error on gettime().
|
||||||
|
#define I 20000000
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
void test1(float *a, float *b, float *c, int N) {
|
||||||
|
__builtin_assume(N == 1024);
|
||||||
|
|
||||||
|
for (int i=0; i<I; i++) {
|
||||||
|
for (int j=0; j<N; j++) {
|
||||||
|
c[j] = a[j] + b[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
void test2(float *__restrict a, float *__restrict b, float *__restrict c, int N)
|
||||||
|
{
|
||||||
|
__builtin_assume(N == 1024);
|
||||||
|
a = (float *)__builtin_assume_aligned(a, 16);
|
||||||
|
b = (float *)__builtin_assume_aligned(b, 16);
|
||||||
|
|
||||||
|
for (int i = 0; i < I; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < N; j++)
|
||||||
|
{
|
||||||
|
/* max() */
|
||||||
|
c[j] = a[j];
|
||||||
|
if (b[j] > a[j])
|
||||||
|
c[j] = b[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
--- test2.c
|
||||||
|
+++ test2.c
|
||||||
|
@@ -14,9 +14,8 @@
|
||||||
|
for (int j = 0; j < N; j++)
|
||||||
|
{
|
||||||
|
/* max() */
|
||||||
|
- c[j] = a[j];
|
||||||
|
- if (b[j] > a[j])
|
||||||
|
- c[j] = b[j];
|
||||||
|
+ if (b[j] > a[j]) c[j] = b[j];
|
||||||
|
+ else c[j] = a[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
double test3(double *__restrict a, int N) {
|
||||||
|
__builtin_assume(N == 1024);
|
||||||
|
a = (double *)__builtin_assume_aligned(a, 16);
|
||||||
|
|
||||||
|
double b = 0;
|
||||||
|
for (int i=0; i<I; i++) {
|
||||||
|
for (int j=0; j<N; j++) {
|
||||||
|
b += a[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user