Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update complex interface #488

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ matrix:
env: MATRIX_EVAL="CC=clang && CXX=clang++"
addons: {apt: {packages: [*common_packages, ]}}

- name: Linux s390x GCC 7
arch: s390x
env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
addons: {apt: {packages: [*common_packages, ]}}

- name: Linux ppc64le GCC 7
arch: ppc64le
env: MATRIX_EVAL="CC=gcc-7 && CXX=g++-7"
addons: {apt: {packages: [*common_packages, ]}}

script:
- eval "${MATRIX_EVAL}"
- lscpu
Expand Down
3 changes: 3 additions & 0 deletions compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
gcc -std=c17 -I/home/johannes/src/volk/include -I/home/johannes/src/volk/build/include -L/home/johannes/src/volk/build/lib -x c main.c -o mainvolkgnuc -lm -lvolk
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Guessing you didn't mean to include this file ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah ... guessing you're using this & main.c and main.cc as part of the draft for testing purposes, and you'll remove these once the PR is out of draft ... yes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This is a temporary file I intend to remove as soon as I figured out all the details of how to update the interface.

clang -std=c17 -I/home/johannes/src/volk/include -I/home/johannes/src/volk/build/include -L/home/johannes/src/volk/build/lib -x c main.c -o mainvolkclangc -lm -lvolk
g++ -std=c++17 -I/home/johannes/src/volk/include -I/home/johannes/src/volk/build/include -L/home/johannes/src/volk/build/lib -x c++ main.cc -o mainvolkcpp -lm -lfmt -lvolk
3 changes: 2 additions & 1 deletion include/volk/volk_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@
////////////////////////////////////////////////////////////////////////
// C-linkage declaration macros
// FIXME: due to the usage of complex.h, require gcc for c-linkage
// Hope that extern "C" works for all relevant compilers nowadays.
////////////////////////////////////////////////////////////////////////
#if defined(__cplusplus) && (__GNUC__)
#if defined(__cplusplus)
#define __VOLK_DECL_BEGIN extern "C" {
#define __VOLK_DECL_END }
#else
Expand Down
101 changes: 54 additions & 47 deletions include/volk/volk_complex.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,55 +26,61 @@
* - lv_conj - take the conjugate of the complex number
*/

#ifdef __cplusplus

#include <stdint.h>
#include <complex>

typedef std::complex<int8_t> lv_8sc_t;
typedef std::complex<int16_t> lv_16sc_t;
typedef std::complex<int32_t> lv_32sc_t;
typedef std::complex<int64_t> lv_64sc_t;
typedef std::complex<float> lv_32fc_t;
typedef std::complex<double> lv_64fc_t;

template <typename T>
inline std::complex<T> lv_cmake(const T& r, const T& i)
{
return std::complex<T>(r, i);
}

template <typename T>
inline typename T::value_type lv_creal(const T& x)
{
return x.real();
}

template <typename T>
inline typename T::value_type lv_cimag(const T& x)
{
return x.imag();
}

template <typename T>
inline T lv_conj(const T& x)
{
return std::conj(x);
}

#else /* __cplusplus */

#include <complex.h>
#include <tgmath.h>

typedef char complex lv_8sc_t;
typedef short complex lv_16sc_t;
typedef long complex lv_32sc_t;
typedef long long complex lv_64sc_t;
typedef float complex lv_32fc_t;
typedef double complex lv_64fc_t;
#include <volk/volk_common.h>

__VOLK_DECL_BEGIN
#ifndef _MSC_VER
// Obviously, we would love `typedef float complex lv_32fc_t` to work.
// However, this clashes with C++ definitions.
// error: expected initializer before ‘lv_32fc_t’
// --> typedef float complex lv_32fc_t;
// https://stackoverflow.com/a/10540302

typedef char _Complex lv_8sc_t;
typedef short _Complex lv_16sc_t;
typedef long _Complex lv_32sc_t;
typedef long long _Complex lv_64sc_t;
typedef float _Complex lv_32fc_t;
typedef double _Complex lv_64fc_t;

#else
// MSVC requires different treatment.
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-160
// https://docs.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support?view=msvc-160
// Refer to `complex.h` in
// https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk/
// https://github.com/microsoft/STL/blob/main/stl/inc/complex

typedef _Fcomplex lv_32fc_t;
typedef _Dcomplex lv_64fc_t;

// typedef char _Complex lv_8sc_t;
typedef struct lv_8sc_t {
char _Val[2];
} lv_8sc_t;

// typedef short _Complex lv_16sc_t;
typedef struct lv_16sc_t {
short _Val[2];
} lv_16sc_t;

// typedef long _Complex lv_32sc_t;
typedef struct lv_32sc_t {
long _Val[2];
} lv_32sc_t;

// typedef long long _Complex lv_64sc_t;
typedef struct lv_64sc_t {
long long _Val[2];
} lv_64sc_t;
#endif

#define lv_cmake(r, i) ((r) + _Complex_I * (i))
// We want `_Imaginary_I` to ensure the correct sign.
// https://en.cppreference.com/w/c/numeric/complex/Imaginary_I
// It does not compile. Complex numbers are a terribly implemented afterthought.
// #define lv_cmake(r, i) ((r) + _Imaginary_I * (i))

// When GNUC is available, use the complex extensions.
// The extensions always return the correct value type.
Expand All @@ -93,6 +99,7 @@ typedef double complex lv_64fc_t;
// with type-generic versions.
#else /* __GNUC__ */


#define lv_creal(x) (creal(x))

#define lv_cimag(x) (cimag(x))
Expand All @@ -101,6 +108,6 @@ typedef double complex lv_64fc_t;

#endif /* __GNUC__ */

#endif /* __cplusplus */
__VOLK_DECL_END

#endif /* INCLUDE_VOLK_COMPLEX_H */
4 changes: 3 additions & 1 deletion lib/kernel_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ std::vector<volk_test_case_t> init_test_list(volk_test_params_t test_params)
test_params_power.set_scalar(2.5);

volk_test_params_t test_params_rotator(test_params);
test_params_rotator.set_scalar(std::polar(1.0f, 0.1f));
auto rotator_value = std::polar(1.0f, 0.1f);
test_params_rotator.set_scalar(
lv_32fc_t{ rotator_value.real(), rotator_value.imag() });
test_params_rotator.set_tol(1e-3);

std::vector<volk_test_case_t> test_cases;
Expand Down
6 changes: 3 additions & 3 deletions lib/qa_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ bool run_volk_tests(volk_func_desc_t desc,
} else {
run_cast_test1_s32f((volk_fn_1arg_s32f)(manual_func),
test_data[i],
scalar.real(),
__real__ scalar,
vlen,
iter,
arch_list[i]);
Expand All @@ -659,7 +659,7 @@ bool run_volk_tests(volk_func_desc_t desc,
} else {
run_cast_test2_s32f((volk_fn_2arg_s32f)(manual_func),
test_data[i],
scalar.real(),
__real__ scalar,
vlen,
iter,
arch_list[i]);
Expand All @@ -682,7 +682,7 @@ bool run_volk_tests(volk_func_desc_t desc,
} else {
run_cast_test3_s32f((volk_fn_3arg_s32f)(manual_func),
test_data[i],
scalar.real(),
__real__ scalar,
vlen,
iter,
arch_list[i]);
Expand Down
10 changes: 4 additions & 6 deletions lib/volk_rank_archs.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@

#include <stdbool.h>
#include <stdlib.h>
#include <volk/volk_common.h>

#ifdef __cplusplus
extern "C" {
#endif
__VOLK_DECL_BEGIN

int volk_get_index(const char* impl_names[], // list of implementations by name
const size_t n_impls, // number of implementations available
Expand All @@ -30,7 +29,6 @@ int volk_rank_archs(const char* kern_name, // name of the kernel to rank
const bool align // if false, filter aligned implementations
);

#ifdef __cplusplus
}
#endif
__VOLK_DECL_END

#endif /*INCLUDED_VOLK_RANK_ARCHS_H*/
98 changes: 98 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@

#include <math.h>
#include <stdio.h>
#include <volk/volk.h>

void function_test(int num_points)
{
unsigned int alignment = volk_get_alignment();
lv_32fc_t* in0 = (lv_32fc_t*)volk_malloc(sizeof(lv_32fc_t) * num_points, alignment);
lv_32fc_t* in1 = (lv_32fc_t*)volk_malloc(sizeof(lv_32fc_t) * num_points, alignment);
lv_32fc_t* out = (lv_32fc_t*)volk_malloc(sizeof(lv_32fc_t) * num_points, alignment);

for (unsigned int ii = 0; ii < num_points; ++ii) {
// Generate two tones
float real_1 = cosf(0.3f * (float)ii);
float imag_1 = sinf(0.3f * (float)ii);
in0[ii] = lv_cmake(real_1, imag_1);
float real_2 = cosf(0.1f * (float)ii);
float imag_2 = sinf(0.1f * (float)ii);
in1[ii] = lv_cmake(real_2, imag_2);
}

volk_32fc_x2_multiply_32fc(out, in0, in1, num_points);

for (unsigned int ii = 0; ii < num_points; ++ii) {
lv_32fc_t v0 = in0[ii];
lv_32fc_t v1 = in1[ii];
lv_32fc_t o = out[ii];
printf("in0=(%+.1f%+.1fj), in1=(%+.1f%+.1fj), out=(%+.1f%+.1fj)\n",
creal(v0),
cimag(v0),
creal(v1),
cimag(v1),
creal(o),
cimag(o));
}

volk_free(in0);
volk_free(in1);
volk_free(out);
}

int main(int argc, char* argv[])
{
function_test(32);

lv_32fc_t fc_cpl[4];
printf("float=%lu, complex float=%lu, complex float array[4]=%lu\n",
sizeof(float),
sizeof(lv_32fc_t),
sizeof(fc_cpl));

for (int i = 0; i < 4; i++) {
fc_cpl[i] = (i + 3) + I * (i + 8);

fc_cpl[i] = lv_cmake(i + 3, i + 8);
}
for (int i = 0; i < 4; i++) {
lv_32fc_t val = fc_cpl[i];
lv_32fc_t cval = conj(val);
lv_32fc_t gval = ~val;
lv_32fc_t mult = val * val;
printf("val = %+.1f%+.1fj\n", creal(val), cimag(val));
printf("conj(val)= %+.1f%+.1fj\n", creal(cval), cimag(cval));
printf("gcc: ~val= %+.1f%+.1fj\n", creal(gval), cimag(gval));
printf("val*val = %+.1f%+.1fj\n", creal(mult), cimag(mult));
}

lv_8sc_t sc_cpl[4];
printf("\n\nchar=%lu, complex char=%lu, complex char array[4]=%lu\n",
sizeof(char),
sizeof(lv_8sc_t),
sizeof(sc_cpl));

for (int i = 0; i < 4; i++) {
// lv_8sc_t value = (i + 3) + I * (i + 8);
// printf("value=%+hhi%+hhij\n", creal(value), cimag(value));
// sc_cpl[i] = (i + 3) + I * (i + 8);
sc_cpl[i] = lv_cmake(i + 3, i + 8);
// printf("%i + j %i\n", creal(sc_cpl[i]), cimag(sc_cpl[i]));
}
for (int i = 0; i < 4; i++) {
lv_8sc_t val = sc_cpl[i];
lv_8sc_t cval = conj(val);
// lv_8sc_t cval = lv_cmake(creal(val), -cimag(val));
lv_8sc_t gval = ~val;
lv_8sc_t mult = val * val;
printf("val = %+hhi%+hhij\n", __real__ val, __imag__ val);
printf("conj(val)= %+hhi%+hhij\n", __real__ cval, __imag__ cval);
printf("gcc: ~val= %+hhi%+hhij\n", __real__ gval, __imag__ gval);
printf("val*val = %+hhi%+hhij\n", __real__ mult, __imag__ mult);
}

// char* values = (char*) sc_cpl;
// for (int i = 0; i < 8; i++) {
// printf("%hhi\n", values[i]);
// }
}
Loading