Search code examples
cfpgaxilinxsynthesis

using values instead of pointers as function arguments


I have this function "cost_compare" that I would like to offload on FPGA for some experimental purposes. This function, how it is called and its arguments are as follows.

The synthesis tool doesn't accept double pointers as arguments for HW functions (in fact it is very picky about using pointers especially to data structures).

How do I get rid of the pointers in the function argument list? In other words, how do I convert pointers in this example to values? How does this possible solution affect the call by reference performed by spec_qsort?

Thanks in advance Hooman

typedef struct arc *arc_p;
typedef LONG cost_t;

typedef struct basket
{
    arc_t *a;
    cost_t cost;
    cost_t abs_cost;
    LONG number;
} BASKET;
/* ... */
typedef struct arc
{
    int id;
    cost_t cost;
    node_p tail, head;
    short ident;
    arc_p nextout, nextin;
    flow_t flow;
    cost_t org_cost;
} arc;
/* ... */
extern int cost_compare( BASKET **b1, BASKET **b2 );
/* ... */
int cost_compare( BASKET **b1, BASKET **b2 )
{
    if( (*b1)->abs_cost < (*b2)->abs_cost )
        return 1;
    if( (*b1)->abs_cost > (*b2)->abs_cost )
        return -1;
    if( (*b1)->a->id > (*b2)->a->id )
        return 1;
    else
        return -1;
}
/* ... */
spec_qsort(perm + 1, basket_sizes[thread], sizeof(BASKET*),
           (int (*)(const void *, const void *))cost_compare);
/* ... */
BASKET* max, *act;
for (j = 1; j < num_threads; j++) {
    act = *perm_p[j];
    if (act->number >= 0) {
        if (!max || cost_compare(&act, &max) < 0) {
            max = act;
            max_pos = j;
        }
    }
    /* ... */
    BASKET*     max_basket;
    static BASKET    **opt_basket;

    for (i = 0; i< num_threads; i++) {
        if ((!max_basket && opt_basket[i]) || (opt_basket[i] && 
                                               cost_compare(&opt_basket[i], &max_basket) < 0)) {
            max_basket = opt_basket[i];
        }
    }
/* ... */

=========================================

Thanks @Gerardo Zinno. When I run in SW, your approach (in the last paragraph) works fine. However, when I synthesis 'cost_compare' on FPGA using Xilinx SDSoC, it only works for

if(b1->abs_cost < b2->abs_cost)

but not for

if( b1->a->id > b2->a->id )

and the tools gives me this error:

ERROR: [SYNCHK 200-61] /home/a1083898/Xilinx_examples/original_routeplanning/src/pbeampp.c:85: unsupported memory access on variable 'x' which is (or contains) an array with unknown size at compile time.

ERROR: [SYNCHK 200-41] /home/a1083898/Xilinx_examples/original_routeplanning/src/pbeampp.c:89: unsupported pointer reinterpretation from type 'i8*' to type '%struct.arc.1.4.6 = type { i32, i64, %struct.node.0.3.5*, %s...' on variable 'x'.

ERROR: [SYNCHK 200-11] /home/a1083898/Xilinx_examples/original_routeplanning/src/pbeampp.c:89: Argument 'x' has an unsynthesizable type 'i8*' (possible cause(s): pointer to pointer or global pointer).

ERROR: [SYNCHK 200-11] /home/a1083898/Xilinx_examples/original_routeplanning/src/pbeampp.c:89: Argument 'x' has an unsynthesizable type 'i8*' (possible cause(s): structure variable cannot be decomposed due to (1) unsupported type conversion; (2) memory copy operation; (3) function pointer used in struct; (4) unsupported pointer comparison).'

Also when called by 'qsort' as

qsort(perm + 1, basket_sizes[thread], sizeof(BASKET*), cost_compare); 

I receive this warning:

warning: incompatible pointer types passing 'int (void *, void *)' to parameter of type '__compar_fn_t' (aka 'int (*)(const void *, const void *)') [-Wincompatible-pointer-types]

I know this error has nothing to do with C programming but if there is any way to get rid of 'b1->a->id' and 'b2->a->id', I believe the problem could be solved with the HW synthesis tool.

Kind regards Hooman


Solution

  • In the int cost_compare( BASKET **b1, BASKET **b2 ) you don't need double pointers since you are just comparing elements and not swapping anything. (In fact notice that you aren't using b1 directly, but you're always dereferencing it)

    Just change the function signature to int cost_compare( BASKET *b1, BASKET *b2 ). In the function's body change every (*b1)->abs_const to b1->abs_const.

    Also, since spec_qsort expects a function with signature int compare (void *, void *), you could get rid of this cast "(int (*)(const void *, const void *)) cost_compare)" , change the signature of cost_compare to an appropriate one and cast the arguments inside the function, like this:

    int cost_compare( void *a, void *b ){
     BASKET *b1 = a;
     BASKET *b2 = b;
     if(b1->abs_cost < b2->abs_cost){
       return 1;
     }
     ...
     else return -1;
    }
    

    and then call spec_qsort(perm + 1, basket_sizes[thread], sizeof(BASKET*), cost_compare), in this way everything is easier to read.

    EDIT: To answer to one point of the last edit you made, change cost_compare to :

    int cost_compare( const void *a, const void *b ){
         BASKET b1 = *(BASKET *)a;
         BASKET b2 = *(BASKET *)b;
         if(b1.abs_cost < b2.abs_cost){
           return 1;
         }
         ...
         if(*(b1.a).id > *(b2.a).id)
             return 1;
         else return -1;
        }