6
typedef struct { 
    void * field1; 
} s1; 

void func1(void) { 
    s1 my_s1; 
    s1 * __restrict my_s1_ptr = &my_s1; 
    *((int*)((char*)my_s1_ptr->field1 + 4)) = 0; 
    *((int*)((char*)my_s1_ptr->field1 + 8)) = 1; 
    *((int*)((char*)my_s1_ptr->field1 + 12)) = 2; 
    *((int*)((char*)my_s1_ptr->field1 + 16)) = 3; 
} 

Wydaje się, że dla wersji 11.1 kompilatora Intel i wersji 4.6 gcc że ładuje kompilatora my_s1_ptr-> pole1 dla każdego z ostatnich 4 wypowiedzi. Moje rozumienie __restrict sugerowałoby mi, że ostatnie 3 obciążenia powinny być zbędne i mogą zostać wyeliminowane. Tak, wiem, że kod jest dziwny, ale jest powód, dla którego jest tak skonstruowany. Chciałbym móc skompilować kompilator, aby wyeliminować nadmiarowe ładunki. Masz pomysł, jak to przekonać?c99 __restrict i kompilator optymalizacji

+0

Czy kompilowałeś z optymalizacją? I dlaczego używasz '__restrict' zamiast' restrict', które jest słowem kluczowym C99? –

+0

Zrobiłem kompilację z optymalizacją, a __restrict versus restrict nie robi różnicy. – DrTodd13

+0

Po prostu próbowałem kilka odmian wskaźnika na pole zamiast wskaźnika do struktury i nic nie zmieniło. W prawdziwym kodzie może być wiele wskaźników wskazujących, które pole 1 wskazuje, więc nie jest ważne dodawanie ograniczenia do pola 1 (ale nawet gdy próbowałem, to nie eliminowało obciążenia). Jeśli skopiuję field1 do ograniczającego wskaźnika zmiennej lokalnej, wówczas zbędne obciążenia zostaną wyeliminowane, ale tak jak powiedziałem, narusza to semantykę programu. – DrTodd13

Odpowiedz

3

s1 * __restrict oznacza, że ​​jest to jedyny wskaźnik do określonego s1, więc nie ma żadnego aliasu dla tego typu. Nie oznacza to, że nie będzie aliasu dla innych typów wskaźników, takich jak void*, int* lub char*.

Używanie char* jest szczególnie kłopotliwe dla kompilatora, ponieważ char* jest szczególnie dozwolone do uzyskiwania dostępu do bajtów innych typów. (char oznacza także bajt i może być używany do uzyskiwania dostępu do podstawowej pamięci innych typów).

Jeśli kompilator nie może udowodnić, że twoje zadanie nigdy nie zmieni nigdy tego, co wskazano, będzie musiał ponownie załadować wskaźnik za każdym razem. Na przykład, w jaki sposób można stwierdzić, że void* field1 nie wskazuje na siebie?


Czy coś takiego nie działałoby bez wszystkich odlewów?

int* p = my_s1.field1; 
p[1] = 0; 
p[2] = 1; 
p[3] = 2; 
p[4] = 3; 

Zakładając int wynosi 4 bajty, a field1 faktycznie wskazuje na tablicę tych.

+0

"char" również oznacza bajt "-> Czy kompilator musi uważać na dowolny" char "lub po prostu" unsigned char "? (Nie jestem pewien, dlatego właśnie pytam.: P) – Mehrdad

+0

W większości używamy 'unsigned char', ponieważ wtedy znamy sygnaturę, ale zwykły' char' może być taki sam i może być również użyty do uzyskania dostępu do pamięci (czy faktycznie podpisany lub nie). –

+0

"' s1 * __restrict' oznacza, że ​​jest to jedyny wskaźnik do określonego 's1'": nie wiem o '__restrict', ale nie dotyczy to' ograniczania 'C99, na przykład w 'void * memcpy (void * ograniczyć s1, const void * ograniczyć s2, size_t n); '. Sekcja 6.7.3.1 definiuje pojęcie wyrażenia wskaźnika na podstawie obiektu i nie ma przepisu dotyczącego konwersji wskaźnika (umożliwiającego prototypowanie 'memcpy'). –

Powiązane problemy