Будет ли процессор переупорядочивать STORE инструкции по тому же адресу? - PullRequest
0 голосов
/ 19 декабря 2018

Приведенный ниже код, будет ли процесс переупорядочивать STORE a и STORE b?От логики кода, a и b независимы.

int* __attribute__ ((noinline)) GetMemAddr(int index) {
    static int data[10];
    return &data[0];
}

void fun() {
    int *a=GetMemAddr(1); //use different args to get same address to avoid optimiztion
    int *b=GetMemAddr(2);
    *a=1;
    *b=3;
}

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Процессор может переупорядочить два хранилища, если это не нарушает никаких гарантий, которые процессор может предоставить.Работа компилятора состоит в том, чтобы генерировать код для ЦП, который не позволяет выполнять оптимизацию, которая приводит к тому, что сгенерированный код нарушает стандарт Си.Другими словами, компилятор C принимает обещанный им код, который будет выполняться в соответствии с правилами стандарта C, и превращает его в код сборки, который на самом деле будет выполняться в соответствии с правилами стандарта C, полагаясь на процессор длязапускаться в соответствии с правилами спецификации его архитектуры.

Таким образом, если эти два хранилища оказываются в одной и той же ячейке памяти, невозможна «оптимизация», которая позволяет наблюдать неправильный результат в том же потоке.Это нарушило бы стандарт C, поэтому неработающий компилятор будет генерировать любой код, необходимый для того, чтобы не сломанный процессор не делал этого.Тем не менее, ничто не мешает оптимизации, которая может привести к тому, что другие потоки будут видеть странные промежуточные результаты, если только стандарт потоков вашей платформы не говорит что-то другое (и ни один из тех, о которых я знаю, не делает).

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

0 голосов
/ 19 декабря 2018

Ваш вопрос в значительной степени бессмыслен, как и сейчас.

int* __attribute__ ((noinline)) GetMemAddr(int index) {
    static int data[10];
    return &data[0];
}

void fun() {
    int *a=GetMemAddr(1); //use different args to get same address to avoid optimiztion
    int *b=GetMemAddr(2);
    *a=1;
    *b=3;
}

это скомпилировано с GCC 7.3 и -O3 полностью исключает первый вызов GetMemAddr, посколькуне имеет побочных эффектовЭто исключает назначение *a=1 тоже.noinline означает, что функция не должна быть встроенной.Это не значит, что его нужно вызывать вообще.

Единственный правильный способ избежать elision - это объявить a и b как volatile int * s.Таким образом, магазины также должны быть в порядке.Однако до сих пор не гарантируется, что эти хранилища будут атомарными , поэтому в другом потоке могут происходить забавные вещи - для тех, кому нужно использовать атомарные функции C11 или расширение / гарантия компилятора.

...