Xcode generates seemingly invalid code from OpenCL kernel - c

Xcode automatically generates code for submitting OpenCL kernels to dispatch queues but it seems that it generates invalid code which can't be compiled for one of my kernels. The problem is with a struct definition:
typedef struct {
float4 position; ///< The point position.
float4 velocity; ///< The point velocity.
float intensity; ///< The point intensity.
int links[6]; ///< The point links specified as indexes for other points in the array.
float align; ///< Dummy for alignment.
} PointElement;
This code is generated by Xcode:
typedef struct {
cl_float4 position;
cl_float4 velocity;
cl_float intensity;
int [6] links;
cl_float align;
} _PointElement_unalign;
I'm not expert at obscure C syntax variants but it surely int [6] links; is not valid C and therefore does not compile.
Why does Xcode do this? Have I done something wrong myself or is this a bug?

Related

Doxygen: Documenting struct as a member of a struct

I would like to document a struct as a member of a struct, in a style, that there will be clickable link to structure precalculated same as on calibrator_calibration_t and after click it will show me all members of precalculated.
Generated HTML:
I've tried many different approaches but none of them worked as I needed. Any tip?
/**
* #struct filter_t
* #brief Filter structure
*/
typedef struct
{
calibrator_calibration_t calibration; ///< Copied calibration
blackbox_weight_id_e weight_id;
struct
{
float slope;
float above_mixed;
float under_mixed;
float above_male;
float under_male;
float above_female;
float under_female;
uint32_t stable_counter_minimum;
} precalculated; ///< Precalculated values (for faster calculation) based on settings
} filter_t;
If you want the type of structure member precalculated to be documented with a name and a link to separate documentation of that type, then you must give that type a name or tag. You have not done that. C does not allow you to name it (via typedef) when its definition is inside a struct definition, however, and it is poor style to tag it in that context.
If you can get over your apparent aversion to structure tags and are also unconcerned with the stylistic problems involved, then I anticipate that adding a tag would induce Doxygen to do what you want:
typedef struct
{
calibrator_calibration_t calibration; ///< Copied calibration
blackbox_weight_id_e weight_id;
struct precalc // Note the structure tag here
{
float slope;
float above_mixed;
float under_mixed;
float above_male;
float under_male;
float above_female;
float under_female;
uint32_t stable_counter_minimum;
} precalculated; ///< Precalculated values (for faster calculation) based on settings
} filter_t;
But if you are going to tag the structure type then it would be better form to move it out of the host structure definition, and if you're going to do that, then it appears that your standard convention would be to name it instead of tagging it:
typedef struct {
float slope;
float above_mixed;
float under_mixed;
float above_male;
float under_male;
float above_female;
float under_female;
uint32_t stable_counter_minimum;
} precalculated_t;
typedef struct
{
calibrator_calibration_t calibration; ///< Copied calibration
blackbox_weight_id_e weight_id;
precalculated_t precalculated; ///< Precalculated values (for faster calculation) based on settings
} filter_t;

Error initializing stuct in source code

I am using some code made by someone else, to implement a kalman filter into my imu with arduino. I understand the vast majority of it and the maths behind it, but i am having some errors when implementing it which i cannot understand (serious lack of knowledge on typdefs and structs and initializing them). If someone could explain this error to me it would be much appreciated.
The header file contains this...
struct kalman_data{
float x1, x2, x3;
float p11, p12, p13,
p21, p22, p23,
p31, p32, p33;
float q1, q2, q3;
};
typedef struct _kalman_data kalman_data;
void kalman_data(kalman_data* data);
void kalman_calc(kalman_data* data, float z1, float z2);
My arduino code contains this..
kalman_data pitch_data;
kalman_data roll_data;
void loop(){
kalman_data(&pitch_data);
kalman_data(&roll_data);
kalman_calc(&pitch_data, pitch, gyro_yz);
kalman_calc(&roll_data, roll, gyro_xz);
}
And this is the error i get...
In file included from test.ino:2:0:
E:\Users\Alexander\Documents\Arduino\libraries\Kalman/kalman.h:30:29: error: conflicting declaration 'typedef struct _kalman_data kalman_data'
typedef struct _kalman_data kalman_data;
E:\Users\Alexander\Documents\Arduino\libraries\Kalman/kalman.h:17:8: error: 'struct kalman_data' has a previous declaration as 'struct kalman_data'
struct kalman_data{
struct kalman_data{
should be
struct _kalman_data{
in order to correspond to the subsequent
typedef struct _kalman_data kalman_data;
Then, the function
void kalman_data(kalman_data* data);
should better be renamed. As I recall both C and C++ allow you to reuse a type name for a function, to have both in scope at the same time, but even if that's allowed it's absolutely not a good idea. Very confusing.
The struct definition is reserving the name kalman_data and the typedef is trying to reserve the name again, for a struct called _kalman_data. This causes the error.
To rectify this, use struct _kalman_data and then the typedef will work as intended.

"array type has incomplete element type"

I am new to C programming, and have the following code. I am facing following error.
typedef struct Vertex Vertex;
typedef struct Edge Edge;
struct Vertex {
bool known;
char id[25];
Edge edges[20];
int distance;
};
struct Edge {
Vertex target;
int weight;
};
typedef struct {
Vertex Nodes[20];
int pass;
int infinity;
} Graph;
The error it gives is:
array type has incomplete element type
Can someone please help me understand what is the problem?
typedef struct Vertex Vertex;
typedef struct Edge Vertex;
this is probably generating some name conflict just change the name of one of them.
The only way this will be possible, is using a mixture of pointers and addressing how you implement your Vertex and Edge structures:
/*your typedefs didn't make sense to me as it was conflicting. So, I edited it accordingly*/
//typedef struct Vertex Vertex;
//typedef struct Edge Vertex;
struct Vertex;
struct Edge;
typedef struct Vertex {
bool known;
char id[25];
struct Edge *edges;//This HAS to be a pointer.
int distance;
} Vertex;
typedef struct Edge {
Vertex target;
int weight;
} Edge;
typedef struct {
Vertex Nodes[20];
int pass;
int infinity;
} Graph;
Why does this work? Because of something called forward declaration:
...a forward declaration is a declaration of an identifier (denoting
an entity such as a type, a variable, or a function) for which the
programmer has not yet given a complete definition. It is required for
a compiler to know the type of an identifier (size for memory
allocation, type for type checking, such as signature of functions),
but not a particular value it holds (in case of variables) or
definition (in the case of functions)...
In this declaration
struct Vertex {
bool known;
char id[25];
Edge edges[20];
int distance;
};
the type Edge is not yet declared. The compiler here only knows that it will correspond to a struct Edge, but that struct itself is not known.
Can someone please help me understand what is the problem?
Arrays have the following properties:
All its elements have the same size.
The elements are stored contigously.
This allows to calculate the memory address of each element (e.g. id[i]) from the size and memory address of the first element and the index i.
To do this, the compiler needs to know how large the array elements are. When you declare the Vertex::edges[20] member, the compiler does not yet know, how large objects of type Edge are. Hence the compiler error.
One way to avoid this is, to define the Edge struct before the Vertex struct. In your case, this won't help, because the Edge::target is of type Vertex and you will get a similar error. Memory addresses of struct members are calculated using the memory address of the object and adding the sizes of the members (and possibly some padding) that precede the requested member.
In such a case with circular dependencies, pointers as members can be used, because a pointer to a struct has the same size, no matter which members the struct has, that the pointer points to.
Think about it: the compiler has to know the size of the Vertex and Edge structures. If you make Edge contain a Vertex and Vertex contain an Edge, it can't really sort out the size. The solution is to provide just a pointer to the structure (pointer size should be known to the compiler). I would use a jrd1 version with a small change:
struct Edge {
struct Vertex* target;
int weight;
} Edge;
typedef struct Vertex {
bool known;
char id[25];
struct Edge edges[20];
int distance;
} Vertex;
typedef struct {
Vertex Nodes[20];
int pass;
int infinity;
} Graph;
That should work just fine.
Furthermore, if each edge is supposed to point the Vertex where it is contained, you don't really need to store that pointer, you could use something like the container_of macro in the linux kernel if you want.

Converting arm code to use NEON intrinsics

I have been trying to modify the code beneath to work with NEON Intrinsics, thereby creating a speedup. Unfortunately nothing seems to work correctly. Does anyone have any idea what is going wrong? I updated the doubles to single floating point elements.
typedef float REAL;
typedef REAL VEC3[3];
typedef struct driehoek
{
VEC3 norm; /* Face normal. */
REAL d; /* Plane equation D. */
VEC3 *vptr; /* Global vertex list pointer. */
VEC3 *nptr; /* Global normal list pointer. */
INT vindex[3]; /* Index of vertices. */
INT indx; /* Normal component max flag. */
BOOL norminterp; /* Do normal interpolation? */
BOOL vorder; /* Vertex order orientation. */
}driehoek;
typedef struct element
{
INT index;
struct object *parent; /* Ptr back to parent object. */
CHAR *data; /* Pointer to data info. */
BBOX bv; /* Element bounding volume. */
}ELEMENT;
INT TriangleIntersection(RAY *pr, ELEMENT *pe, IRECORD *hit)
{
FLOAT Rd_dot_Pn; /* Polygon normal dot ray direction. */
FLOAT Ro_dot_Pn; /* Polygon normal dot ray origin. */
FLOAT q1, q2;
FLOAT tval; /* Intersection t distance value. */
VEC3 *v1, *v2, *v3; /* Vertex list pointers. */
VEC3 e1, e2, e3; /* Edge vectors. */
driehoek *pt; /* Ptr to triangle data. */
pt = (driehoek *)pe->data;
Rd_dot_Pn = VecDot(pt->norm, pr->D);
if (ABS(Rd_dot_Pn) < RAYEPS) /* Ray is parallel. */
return (0);
hit->b3 = e1[0] * (q2 - (*v1)[1]) - e1[1] * (q1 - (*v1)[0]);
if (!INSIDE(hit->b3, pt->norm[2]))
return (0);
break;
}
return (1);
}
An array of float vec[3] is not enough of a hint to the compiler that NEON intrinsic can be used. The issue is that float vec[3] has each element individually addressable. The compiler must store each in a floating point register. See gcc NEON intrinsic documentation.
Although 3 dimensions is very common in this Universe, our friends the computers like binary. So you have two data types that can be used for NEON intrinsics; float32x4_t and float32x2_t. You need to use the intrinsics such as vfmaq_f32, vsubq_f32, etc. These intrinsics are different for each compiler; I guess you are using gcc. You should only use the intrinsic data types as combining float32x2_t with a single float can result in movement between register types, which is expensive. If your algorithm can treat each dimension separately, then you might be able to combine types. However, I don't think you will have register pressure and the SIMD speed-up should be beneficial. I would keep everything in float32x4_t to begin with. You maybe able to use the extra dimension for 3D-projection when it comes to the rendering phase.
Here is the source to a cmath library called math-neon under LGPL. Instead of using intrinsics with gcc, it uses inline assembler.Neon intrinsics vs assembly
See also: armcc NEON intrinsics, if you are using the ARM compiler.

Referencing a typedef as its struct counterpart

Ok guys, we all know there are all lot of typedef/struct questions out there, but I feel this one is a bit of a mind bender.
I'm simulating the neighbor interactions of a crystal lattice using strictly C. I have a struct called "ball_struct" which I typedef'ed as just "ball". The struct contains a pointer to a list of ball_structs (since I couldn't use the typedef name before its own declaration) that the ball considers its neighbors.
So here's the catch: I want to add balls to this list of list of ball_struct neighbors. When I compile (in Visual Studio 2009, no CLR support) I get:
error C2440: '=' : cannot convert from 'ball *' to 'ball_struct'
I'm not surprised, but I am stumped. Is there a way to cast the typedef back down to its respective struct? If not, is there anyway I can add a "ball" to a "ball_struct" list so I don't have to remove the typedef and paste "struct" keywords all over my code? Here's the code in question:
The struct / typedef:
typedef struct ball_struct
{
double mass;
vector pos, vel, acc;
/* keep list of neighbors and its size */
struct ball_struct *neighbors;
int numNeighbors;
} ball;
And the erroneous function:
/* adds ball reference to the neighbor list of the target */
void addNeighbor(ball *target, ball *neighbor)
{
int n = target->numNeighbors;
target->neighbors[n] = neighbor; // error C2440
target->numNeighbors = n+1;
}
Thanks, any help is appreciated. Remember, only solutions for C please.
On the line where you get the error:
target->neighbors[n] = neighbor;
you're assigning a pointer (neighbor) to an actual structure (not a pointer to a structure). Note that if you look at the error message carefully, you'll see that this is what it's saying. Note the asterisk in the 'from' type it talks about:
cannot convert from 'ball *' to 'ball_struct'
Assuming that target->neighbors points to an array of ball_struct structures, I think what you want to do is:
target->neighbors[n] = *neighbor;
PS: you may want to consider using the same name for your struct and the typedef of the struct:
typedef struct ball
{
/* etc... */
} ball;
While pre-ANSI compiler might not have supported that (Why are structure names different from their typedef names?), it's certainly well-supported today. And I think it makes things slightly less confusing.

Resources