2013-09-26 3 views
11

Есть ли способ сказать компилятору C99, что единственный способ доступа к данному массиву - использовать myarray [index]? сказать что-то вроде этого:Использование ограничений с массивами?

int heavy_calcualtions(float* restrict range1, float* restrict range2) 
{ 
    float __I promise I won't alias this__ tmpvalues[1000] = {0}; 

    .... 
    heavy calculations using range1, range2 and tmpvalues; 
    .... 
} 

С помощью ограничения я обещал, что я не псевдоним диапазон1 и Range2, но как я могу сделать то же самое для массива, объявленная внутри моей функции?

+0

Какое предупреждение оно бросает? – dhein

+1

«Недопустимое использование ограничения» - предполагается, что оно будет использоваться с указателями, а не с массивами (насколько я понимаю). Я мог бы делать float * ограничивать tmpvalues ​​= malloc (sizeof (float) * 1000), но тогда я не выделяю на стек, который также может повлиять на производительность. Кроме того, говоря компилятору, что доступ к индексам массивов является безопасным (поэтому нет необходимости в защитных чтениях) кажется очень естественным расширением ограничения использования с указателями, поэтому интуитивно должен быть способ сделать это. –

+1

Я сделал: float * ограничил tmpvalues ​​= alloca (sizeof (float) * 1000); memset (tmpvalues, 0, sizeof (float) * 1000); и это измеримое улучшение, но я бы предпочел сделать это в стандартном (как в случае с жалобой C99) –

ответ

3

Почему вы не можете сделать следующее? Вы не получаете доступ к данным, связанным с tmpvalues через эту переменную, поэтому допустимо использовать указатель ограничения в вычислительной части кода.

#include <stdio.h> 
#include <stdlib.h> 

int heavy_calcs(int n, float* restrict range1, float* restrict range2) 
{ 
    if (n>1000) return 1; 
    float tmpvalues[1000] = {0}; 
    { 
     float * restrict ptv = tmpvalues; 
     for (int i=0; i<n; i++) { 
      ptv[i] = range1[i] + range2[i]; 
     } 
    } 
    return 0; 
} 

int main(int argc, char * argv[]) 
{ 
    int n = (argc>1) ? atoi(argv[1]) : 1000; 
    float * r1 = (float*)malloc(n*sizeof(float)); 
    float * r2 = (float*)malloc(n*sizeof(float)); 
    int rc = heavy_calcs(n,r1,r2); 
    free(r1); 
    free(r2); 
    return rc; 
} 

Я провел это через компилятор Intel 15, и у него не было проблем с векторизации цикла. Конечно, этот цикл тривиален по сравнению с тем, что я считаю вашим, поэтому ваш пробег может отличаться.

+0

[Не нужно приводить результат 'malloc' в C] (http: // stackoverflow.com/q/605845/995714) –

+1

Нет необходимости в '{}' вокруг назначения 'ptv'. – Jeff

10

Хотя ответ Джеффа правильно, то есть, вы всегда можете сделать указатель на выделенный массив, тот факт, что компилятор знает во время компиляции, что tmpvalues ​​не будет совмещенным, так как переменная объявлена ​​как фактический массив, а не указатель. Единственные шансы на псевдоним массива - объявить указатель на него, поэтому, если вы этого не сделаете, нет необходимости объявлять его как restrict. Это более очевидно, если tmpvalues - единственная переменная, которую вы будете иметь в функции.

Проблема может возникнуть, если вы передадите указатель на другую функцию, тогда вы должны указать, ограничен ли полученный указатель или нет.

В документации я столкнулся, связанным с этой темой включает C99:

Пусть D будет декларация обычного идентификатора, который обеспечивает средство назначающего объект P в качестве ограничения квалифицированного указателя на тип T .

Обратите внимание, что это относится только к указателям.

от TI предоставляет некоторые подсказки по настройке производительности, используя ключевое слово restrict. В дополнение ко всем подсказкам в разделе 3.3 приведены примеры, когда можно применить этот тип классификатора, а когда нет. Ищите объявление массива x в середине страницы 16, он заявляет, что он не объявляет указатель и, следовательно, не может быть restrict -qualified.

+0

Если указатель на массив передается внешнему коду, нет чистого способа указать, что внешний код не будет хранить копию указателя и использовать эту копию для произвольных целей при следующем вызове внешнего кода. ИМХО было бы полезно, чтобы у C был классификатор, похожий на 'ограничивать', но для использования с переменными, чей адрес был взят, но будет использоваться только очень ограниченным образом, но такая функция не определена. – supercat

+0

@supercat проблема - как вы определяете эти «различные способы»? gcc имеет атрибуты (такие как «чистый»), которые могут быть привязаны к функциям, которые обещают, что функция не будет выполнять определенные классы вещей. Помимо этого, у нас теперь есть «оптимизация времени ссылки», где набор инструментов компилятора может в основном перейти к тому, что фактически выполняет функция, и использовать эту информацию. – greggo

+0

@greggo: Если бы я писал правила, я бы сказал, что объект, зарегистрированный в регистре, может иметь только свой адрес, принятый при оценке аргумента функции, и поведение будет определяться только в тех случаях, когда все виды использования результирующего указатель или указатели, полученные из них, происходят до того, как функция вернется, а во время выполнения функции либо (1) к объекту обращаются исключительно через результирующий указатель или другие, полученные из него, либо (2) объект не модифицируется никакими способами. Если процесс сборки начинается с построения списка всех внешних символов, используемых в каждой функции ... – supercat