2016-10-11 2 views
0

Локальная переменная (скажем, int) может храниться в регистре процессора, по крайней мере, до тех пор, пока его адрес не нужен нигде. Рассмотрим функцию, вычисляющую что-то, скажем, сложный хеш:Может ли переменная-член (атрибут) находиться в регистре в C++?

int foo(int const* buffer, int size) 
{ 
    int a; // local variable 
    // perform heavy computations involving frequent reads and writes to a 
    return a; 
} 

Предположим, что буфер не вписывается в память. Обозначим класс для вычисления хэш из кусков данных, вызывая foo несколько раз:

struct A 
{ 
    void foo(int const* buffer, int size) 
    { 
     // perform heavy computations involving frequent reads and writes to a 
    } 

    int a; 
}; 

A object; 
while (...more data...) 
{ 
    A.foo(buffer, size); 
} 
// do something with object.a 

Пример может быть немного неестественно. Важное различие здесь состоит в том, что a была локальной переменной в свободной функции и теперь является переменной-членом объекта, поэтому состояние сохраняется для нескольких вызовов.

Теперь вопрос: было ли законным компилятор загружать a в начале метода foo в регистр и хранить его обратно в конце? Фактически это означало бы, что второй поток, контролирующий объект, никогда не может наблюдать промежуточное значение a (синхронизация и неопределенное поведение в сторону). При условии, что скорость является основной целью C++, это, по-видимому, разумное поведение. Есть ли что-нибудь в стандарте, которое могло бы заставить компилятор сделать это? Если нет, действительно ли это делают компиляторы? Другими словами, можем ли мы ожидать (возможно, малого) снижения производительности за использование переменной-члена, кроме загрузки и сохранения ее один раз в начале и в конце функции?

Насколько я знаю, сам язык C++ даже не указывает, что такое регистр. Тем не менее, я думаю, что вопрос в любом случае ясен. Это важно, я ценю ответы на стандартную архитектуру x86 или x64.

+0

Проверить флажки "register" и "volatile" – amchacon

+0

@amchacon Действительно у C++ в настоящее время есть ключевое слово 'register'. Но я бы также отметил, что он устарел в C++ 17. –

ответ

2

Компилятор может сделать это, если (и только если), он может доказать, что ничто иное не получит доступ к a во время выполнения foo.
Это вообще нетривиальная проблема; Я не думаю, что какой-либо компилятор пытается его решить.

Рассмотрим (еще более надуманный) пример

struct B 
{ 
    B (int& y) : x(y) {} 
    void bar() { x = 23; } 
    int& x; 
}; 

struct A 
{ 
    int a; 
    void foo(B& b) 
    { 
     a = 12; 
     b.bar();    
    } 
}; 

выглядит достаточно невинно, но тогда мы говорим

A baz; 
B b(baz.a); 
baz.foo(b); 

"Оптимизация" это оставит 12 в baz.a, не 23, и это явно неправильно.

+0

В примере нет многопоточности, и объект создается локально, поэтому как компилятор не смог бы доказать это и все еще доказать это для примитива?Даже для многопоточности сохранение переменных в регистрах на самом деле является проблемой при доступе, хотя и не заблокированном (актуальная проблема не является блокировкой). – stefaanv

+0

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

+0

Благодарим вас за пример. Я думал больше о временном пребывании в регистре во время цикла, но я признаю, что существуют пределы того, что может доказать компилятор, особенно в сочетании с функциями. Однако не забывайте, что примитивы также могут иметь ссылки. – stefaanv

1

Краткий ответ на вопрос «Может ли переменная-член (атрибут) находиться в регистре?»: Да.

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

+0

Спасибо за быстрый ответ. Это то, чего я ожидал и на самом деле надеялся, хорошо знать, что мои проблемы недействительны. – tglas

Смежные вопросы