У меня есть эта функция «cost_compare», которую я хотел бы разгрузить на FPGA для некоторых экспериментальных целей. Эта функция, как она вызывается и ее аргументы следующие.
Инструмент синтеза не принимает двойные указатели в качестве аргументов для аппаратных функций (на самом деле он очень разборчив в использовании указателей, особенно на структуры данных).
Как избавиться от указателей в списке аргументов функции? Другими словами, как преобразовать указатели в этом примере в значения? Как это возможное решение влияет на вызов по ссылке, выполняемый spec_qsort?
заранее спасибо Хуман
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];
}
}
/* ... */
=========================================
Спасибо @Gerardo Zinno. Когда я запускаю SW, ваш подход (в последнем абзаце) работает нормально. Однако, когда я синтезирую «cost_compare» на FPGA с использованием Xilinx SDSoC, он работает только для
if (b1->abs_cost < b2->abs_cost)
но не для
if ( b1->a->id > b2->a->id )
и инструменты дают мне эту ошибку:
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).'
Также при вызове 'qsort' как
qsort(perm + 1, basket_sizes[thread], sizeof(BASKET*), cost_compare);
Я получаю это предупреждение:
warning: incompatible pointer types passing 'int (void *, void *)' to parameter of type '__compar_fn_t' (aka 'int (*)(const void *, const void *)') [-Wincompatible-pointer-types]
Я знаю, что эта ошибка не имеет ничего общего с программированием на C, но если есть способ избавиться от «b1->a->id» и «b2->a->id», я считаю, что проблема может быть решена с помощью Инструмент синтеза HW.
С уважением Хуман
Замените BASKET **b1, BASKET **b2
любым (*b1)->abs_cost, (*b2)->abs_cost
. (например, cost_t cost1, cost_t cost2
, а затем сравнить cost1 < cost2
и т. д.) Для начала нет необходимости передавать адрес указателя в эту функцию.
В сторону: финал return -1;
кажется неправильным. Я ожидал return ((*b1)->a->id < (*b2)->a->id )) ? -1 : 0;
В int cost_compare( BASKET **b1, BASKET **b2 )
вам не нужны двойные указатели, так как вы просто сравниваете элементы и ничего не меняете местами. (На самом деле обратите внимание, что вы не используете b1 напрямую, но всегда разыменовываете его)
Просто измените сигнатуру функции на int cost_compare( BASKET *b1, BASKET *b2 )
. В теле функции замените каждый (*b1)->abs_const
на b1->abs_const
.
Кроме того, поскольку spec_qsort
ожидает функцию с сигнатурой int compare (void *, void *)
, вы можете избавиться от этого приведения "(int (*)(const void *, const void *)) cost_compare)", изменить сигнатуру cost_compare на соответствующую и привести аргументы внутри функции, например:
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;
}
а потом звоните spec_qsort(perm + 1, basket_sizes[thread], sizeof(BASKET*), cost_compare)
, так все читается легче.
Обновлено: Чтобы ответить на один пункт последнего сделанного вами редактирования, измените cost_compare на:
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;
}
В функции cost_compare
вам, вероятно, нужно также рассмотреть случай, когда b1 и b2 равны, и сделать так, чтобы функция возвращала 0.
Спасибо, но код взят из SPEC CPU 2006, RoutePlanning.
Я попробовал решение @Gerardo Zinno и включил результаты в конец своего вопроса.
@Hooman попробуйте добавить теги пылинки к вопросу, чтобы сделать его видимым для людей, специализирующихся в этой области. А еще лучше задайте еще вопрос только по новым ошибкам
Поскольку функция cost_compare просто сравнивает abs_cost и id, почему бы вам не передать их напрямую, вот так.
int cost_compare(cost_t abs_cost1, int id1, cost_t abs_cost2, int id2)
{
if ( abs_cost1 < abs_cost2 )
return 1;
if ( abs_cost1 > abs_cost2 )
return -1;
if ( id1 > id2 )
return 1;
else
return -1;
}
и тогда вы называете это так.
const_compare(act->abs_cost, act->a->id, max->abs_cost, max->a->id)
потому что функция должна иметь определенную сигнатуру, так как spec_qsort
не будет вызывать const_compare
со всеми этими параметрами, а только с двумя элементами из массива, который она должна отсортировать
@GerardoZinno Итак, вы говорите, что вызов const_compare в spec_qsort нельзя изменить?
Он может передать любую функцию, которую он хочет spec_qsort
, если функция имеет правильную сигнатуру, как обычная qsort
из C. Это тип параметра последнего аргумента spec_qsort int (*compar)(const void *, const void *)
, и вы не можете передать функцию с другая подпись.
Какой "инструмент синтеза"?