UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Observer apoptose_tnf
Observer
8,254 Views
Registered: ‎07-07-2014

Incomprehensible error for C++ template class

Hello,

 

since I'm working on a larger design project.

Since I prefer clear and clean interfaces, I tried to design a resusable Matrix class.

From an interface point of view, it should also be in some sense compatible to the Eigen library,

which is used in other libraries that I am using (of course, Eigen itself cannot be used for synthesis).

 

I do not want to pollute all my ode with two dimensional arrays etc,

so I decided to develop a template based matrix class, which carries all informations

in its template parameters.

 

One problem (see below) occurs, when I use a "Transposed" form.

 

The class looks like this (matrix.h):

 

 

#ifndef __R_MATRIX_H__
#define __R_MATRIX_H__

#include <cstddef>
#include <cassert>
#include <iostream>

#include "ap_fixed.h"
#define fixed_point_type ap_fixed
#define quantization_type ap_q_mode
#define overfow_type ap_o_mode

template  < unsigned int _N, unsigned int _I=_N/2>
class RBitWidth
{
public:
    static const unsigned int Value = 1 + RBitWidth<_N,_I/2>::Value;
};

template <unsigned int _N>
class RBitWidth<_N, 0>
{
public:
    static const unsigned int Value = 1;
};


struct Transposed{

};

struct NotTransposed{

};


template<typename _Scalar, int _Rows, int _Cols, typename TTransposed, int _Options, int _MaxRows,
		int _MaxCols>
class Matrix;


template<typename TScalar, int TRows, int TCols, typename TTransposed=NotTransposed, int TOptions = 0, int TMaxRows = TRows,
		int TMaxCols = TCols>
class Matrix
{
public:

	/** \brief Default constructor.
	 */
	Matrix()
	{}


	Matrix(TScalar raw_data[TRows][TCols])
	{
		for (size_t i = 0; i < TRows; ++i)
		{
			for (size_t j = 0; j < TCols; ++j)
			{
				m_data[i][j] = raw_data[i][j];
			}
		}
	}

	/** \brief Copy constructor
	 */
	Matrix(const Matrix& other)
	{
		for (size_t i = 0; i < TRows; ++i)
		{
			for (size_t j = 0; j < TCols; ++j)
			{
				m_data[i][j] = other(i,j);
			}
		}
	}

	Matrix(const Matrix<TScalar, TCols, TRows, Transposed, TOptions, TMaxCols, TMaxRows> & other)
	{
		for (size_t i = 0; i < TRows; ++i)
		{
			for (size_t j = 0; j < TCols; ++j)
			{
				m_data[i][j] = other(i,j);
			}
		}
	}

	/**
	 * \brief Assigns matrices to each other.
	 */
	inline TScalar & operator()(unsigned row, unsigned col)
	{
		return m_data[row][col];
	}

	inline const TScalar & operator()(unsigned row, unsigned col) const
	{
		return m_data[row][col];
	}

	// ... operator overloads ...

	//! \brief Return transposed "view" of a matrix
	Matrix<TScalar, TCols, TRows, Transposed, TOptions, TMaxCols, TMaxRows>
	transpose()
	{
		return Matrix<TScalar, TCols, TRows, Transposed, TOptions, TMaxCols, TMaxRows>(*this);
	}

	inline TScalar (* data())[TMaxCols]
	{
		return m_data;
	}

	typedef TScalar scalar_type;
	static const int rows = TRows;
	static const int cols = TCols;
	static const int options = TOptions;
	static const int max_rows = TMaxRows;
	static const int max_columns = TMaxCols;

private:
	TScalar m_data[TMaxRows][TMaxCols];
};

/**
 *  \brief The transposed "view" of an existing matrix
 *
 *  This class is used to represent a transposed version of an existing matrix.
 *  It is not meant to be used on it's own, but only in dot products.
 *
 */
template<typename TScalar, int TRows, int TCols, int TOptions, int TMaxRows,
		int TMaxCols>
class Matrix<TScalar, TRows, TCols, Transposed, TOptions, TMaxRows, TMaxCols>
{
public:
	Matrix(Matrix<TScalar, TCols, TRows, NotTransposed, TOptions, TMaxCols, TMaxRows> & m)
	{
		m_data = m.data();
	}

	inline TScalar & operator()(unsigned row, unsigned col)
	{
		return m_data[col][row];
	}

	inline const TScalar & operator()(unsigned row, unsigned col) const
	{
		return m_data[col][row];
	}

	/** \brief Return the transpose of the matrix
	 *
	 *	Remark: the returned matrix has flipped dimensions
	 */
	Matrix<TScalar, TCols, TRows, NotTransposed, TOptions, TMaxCols, TMaxRows>
	transpose()
	{
		Matrix<TScalar, TCols, TRows, NotTransposed, TOptions, TMaxCols, TMaxRows> matrix(m_data);
		return matrix;
	}

	typedef TScalar scalar_type;
	static const int rows = TRows;
	static const int cols = TCols;
	static const int options = TOptions;
	static const int max_rows = TMaxRows;
	static const int max_columns = TMaxCols;

private:
    TScalar (* m_data)[TMaxRows];

};


template<
  int RowsA,
  int ColsA,
  int RowsB,
  int ColsB,
  typename InputType,
  typename OutputType>
struct r_matrix_multiply_traits {
  typedef          InputType                                 INPUT_T;
  typedef OutputType     MULT_T;
  typedef OutputType ACCUM_T;
};

// Specialization for ap_fixed
template<
  int RowsA,
  int ColsA,
  int RowsB,
  int ColsB,
  int W1, int I1, ap_q_mode Q1, ap_o_mode O1, int N1,
  int W2, int I2, ap_q_mode Q2, ap_o_mode O2, int N2>
struct r_matrix_multiply_traits
<RowsA, ColsA, RowsB, ColsB, ap_fixed<W1, I1, Q1, O1, N1>,ap_fixed<W2, I2, Q2, O2, N2> > {
  typedef ap_fixed<W1,                                I1,                                Q1,     O1     ,N1>  INPUT_T;
  typedef ap_fixed<W1+W2,                             I1+I2,                             AP_TRN, AP_WRAP, 0>  MULT_T;
  typedef ap_fixed<W1+W2+RBitWidth<ColsA>::Value, I1+I2+RBitWidth<ColsA>::Value, AP_TRN, AP_WRAP, 0>  ACCUM_T;
};


template<typename TScalarA, int TRowsA, int TColsA,
		typename TTransposedA, int TOptionsA, int TMaxRowsA,
		int TMaxColsA, typename TScalarB, int TRowsB,
		int TColsB, typename TTransposedB, int TOptionsB,
		int TMaxRowsB, int TMaxColsB>
inline Matrix<TScalarA, TRowsA, TColsB, NotTransposed,
TOptionsA, TMaxRowsA, TMaxColsB> operator*(
		const Matrix<TScalarA, TRowsA, TColsA, TTransposedA,
				TOptionsA, TMaxRowsA, TMaxColsA> & A,
		const Matrix<TScalarB, TRowsB, TColsB,
				TTransposedB, TOptionsB, TMaxRowsB,
				TMaxColsB> & B)
{
	// the inner product of matrices (m*p) and (p*n) results in dimensions (m*n)
	TScalarA cast_in_a;
	TScalarB cast_in_b;
	Matrix<TScalarA, TRowsA, TColsB, NotTransposed, TOptionsA, TMaxRowsA, TMaxColsB> result;;
	typename r_matrix_multiply_traits< TRowsA, TColsA, TRowsB, TColsB, TScalarA, TScalarB>::MULT_T mult;
	typename r_matrix_multiply_traits< TRowsA, TColsA, TRowsB, TColsB, TScalarA, TScalarB>::ACCUM_T recast_mult, sum_mult;
	TScalarA out;

	a_row_loop: for (int r = 0; r < A.rows; r++)
	{
		b_col_loop: for (int c = 0; c < B.cols; c++)
		{
			a_col_loop: for (int k = 0; k < A.cols; k++)
			{
				if (k == 0)
					sum_mult = 0;

				cast_in_a = A(r,k);
				cast_in_b = B(k,c);
				mult = cast_in_a + cast_in_b;

				// Cast mult to the correct output size before adding.
				recast_mult = mult;
				sum_mult += recast_mult;
			}
			// Store result
			result(r,c) = sum_mult;
		}
	}
	return result;
}


#endif // __R_MATRIX_H__

My toplevel function looks like this:

 

 

#include "ap_fixed.h"
#include "matrix.h"

typedef ap_fixed<32, 9, AP_RND, AP_SAT> data_type;
typedef ap_fixed<24, 9, AP_RND, AP_SAT> weights_type;
typedef ap_fixed<32, 9, AP_RND, AP_SAT> results_type;

#define DIM_IN1 23
#define DIM_IN2 1

void passive_aggressive_0_top(data_type DIN[DIM_IN1][DIM_IN2],
		results_type * DOUT,
		data_type * LABEL,
		bool update)
{
	static Matrix<weights_type, DIM_IN1, DIM_IN2> var;
	Matrix<data_type, DIM_IN1, DIM_IN2> data(DIN);
	Matrix<weights_type, DIM_IN2, DIM_IN2> result =  var.transpose() * data;

	*DOUT = result(0,0);
}

The C-based simulation works fine.

However, when I try to synthesize it, I get the following error:

 

 

@I [HLS-10] Checking synthesizability ...
@E [SYNCHK-41] pointer reinterpretation on global variable 'var.m_data.V' from type '[23 x i24]*' to type 'Matrix<ap_fixed<24, 9, 0, 0, 0>, 1, 1, NotTransposed, 0, 1, 1>' is unsupported.
@I [SYNCHK-10] 1 error(s), 0 warning(s).
@E [HLS-70] Synthesizability check failed.

Curiously,

 

 

  1. I don't have any global variable
  2. When I use
    typedef ap_fixed<32, 9, AP_RND, AP_SAT> weights_type;
    everything works fine.
  3. This is also the case, when I use
    Matrix<data_type, DIM_IN2, DIM_IN2> result =  data.transpose() * var;

My first guess that I made a mistake with the templated matrix sizes somewhere, however, since the C-simulation works, and with the data_type as specified in (2), I came to the conlusion that the problem must

What is wrong here? What are possible solution approaches?

 

I spent quite a lot of time in traing to find the problem, but I'm stuck.

It is quite annoying, that the error message does not provide further information...

 

PS: I use Vivado 2014.2

0 Kudos
3 Replies
Teacher muzaffer
Teacher
8,218 Views
Registered: ‎03-31-2012

Re: Incomprehensible error for C++ template class

I think the reinterpret is happening here:

inline TScalar (* data())[TMaxCols]
{
return m_data;
}

One thing I don't see is where is m_data being allocated. It's defined as TScalar (* m_data)[TMaxRows]; ie as a pointer to an array (not an array of pointers) and it's assigned with m_data[] etc but I don't see an assignment to it itself.

I think by global VHLS means that static ... var; static variables are global in a restricted namespace.
- Please mark the Answer as "Accept as solution" if information provided is helpful.
Give Kudos to a post which you think is helpful and reply oriented.
0 Kudos
Observer apoptose_tnf
Observer
8,046 Views
Registered: ‎07-07-2014

Re: Incomprehensible error for C++ template class

Thanks for your response!

 

Originally, an instance of the Transposed matrix class was designed to be only usable in connection to an existing NotTransposed instance, i.e., without storing the data itself. It was assigned in the contructor.

 

In "normal" C++ I would use dynamic memory and a shared pointer to control the existence of the m_data array,

however, for HLS the data has to be statically allocated.

 

When I change m_data to TScalar m_data[TMaxRows][TMaxCols], the error does not appear,

and it seems that this "redundant" memory is optimized away by VHLS.

0 Kudos
Visitor ajrg
Visitor
4,201 Views
Registered: ‎10-07-2016

Re: Incomprehensible error for C++ template class

Hi,

 

I am also working with Eigen libraries and I am now trying to synthesize my program in Vivado HLS with Eigen includes. Why did you say that Eigen library cannot be synthesize? I am getting some extrange errors, and probably because you are right and Eigen cannot be synthesize, but I cannot understand why. As I know, Eigen is general code and I guess there are no dynamic memory allocation in the Eigen functions, so it should be synthesizable, isn´t it?

 

Kind regards,

 

Tom

 

 

0 Kudos