Что произойдет, если предварительно выбран неверный адрес?

#c #caching #assembly #disassembly #prefetch

#c #кэширование #сборка #разборка #предварительная выборка

Вопрос:

Простой MWE:

 int* ptr = (int*)malloc(64 * sizeof(int));
_mm_prefetch((const char*)(ptr   64), _MM_HINT_0);
  
  1. Это определенное или неопределенное поведение?
  2. Может ли это вызвать сигнал и прервать выполнение программы?

Я спрашиваю, поскольку я вижу такую предварительную выборку в сгенерированном компилятором коде, где внутри цикла предварительная выборка выполняется без проверки адреса (сохраненного в rbx ):

 400e73:       49 83 c5 40             add    r13,0x40
400e77:       62 f1 f9 08 28 03       vmovapd zmm0,ZMMWORD PTR [rbx]
400e7d:       4d 3b ec                cmp    r13,r12
400e80:       62 d1 f9 08 eb 4d ff    vporq  zmm1,zmm0,ZMMWORD PTR [r13-0x40]
400e87:       90                      nop
400e88:       62 d1 78 08 29 4d ff    vmovaps ZMMWORD PTR [r13-0x40],zmm1
400e8f:       72 03                   jb     400e94 <main 0x244>
400e91:       49 89 c5                mov    r13,rax
400e94:       62 f1 78 08 18 53 1d    vprefetch1 [rbx 0x740]
400e9b:       ff c1                   inc    ecx
400e9d:       62 f1 78 08 18 4b 02    vprefetch0 [rbx 0x80]
400ea4:       48 83 c3 40             add    rbx,0x40
400ea8:       81 f9 00 00 10 00       cmp    ecx,0x100000
400eae:       72 c3                   jb     400e73 <main 0x223>
  

Комментарии:

1. Вы ознакомились с документацией?

2. В руководстве Intel Intrinsics об этом ничего не говорится. Ни одна из встроенных функций Intel не ссылается. Нет ссылки на набор инструкций Intel Xeon Phi (дизассемблированный код был скомпилирован для KNC). Насколько я знаю. Я нашел только это замечание в том, что каждый программист должен знать о памяти: Программы могут использовать _mm_prefetch, встроенный в любой указатель в программе. Большинство процессоров (безусловно, все процессоры x86 и x86-64) игнорируют ошибки, возникающие в результате неверных указателей, которые значительно облегчают жизнь программиста.

3. Хорошие моменты. Спасибо, что посмотрели, прежде чем задавать этот вопрос. Интересно, что такая важная деталь остается недокументированной!

4. Возможно, одно замечание: ссылка на набор инструкций Xeon Phi не содержит исключения ошибки страницы (PF) для VPREFETCHx . Таким образом, для общего программирования с использованием встроенных функций, вероятно, следует найти ответ, проверив ссылки на инструкции для всех возможных архитектур.

Ответ №1:

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

Конечно, предварительная выборка не генерирует сигналы *, было бы почти бесполезно, если бы это было так. Однако для некоторых неверных указателей это может быть очень медленно, в зависимости от того, вызывают ли они промах TLB. Таким образом, компилятор может безопасно использовать его, но он не должен использовать его без разбора для чего бы то ни было.

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

* из руководства:

Инструкция PREFETCHh является просто подсказкой и не влияет на поведение программы.

Сигнал повлияет на поведение программы, поэтому они не могут быть сгенерированы.

Комментарии:

1. Хотя создание указателей, выходящих за рамки, хорошо работает в обычных архитектурах, вполне вероятно, что будущие компиляторы предполагают, что если вы вычисляете указатель, он действителен, и компилятор может разыменовать его заранее / умозрительно, что приведет к неопределенному поведению, если оно недействительно.

2. Компиляторы @FUZxxl IA64 уже делают это, но там все в порядке. Тем не менее, он не может быть сломан таким образом, по крайней мере, в случае использования этого указателя для предварительной выборки, иначе он просто был бы сломан.

3. UB? Это аппаратное обеспечение, а не языковой стандарт.

4. Это также взлом, _mm_prefetch не является частью стандартов C / C . Я спросил больше о том, что делает CPU, возможно, MWE в C не был хорошей идеей. Однако, как вы указали, даже указатели за пределами границ в C являются UB в соответствии со стандартом (за исключением предпоследнего особого случая).

5. Есть ли снижение производительности при предварительной выборке неверного адреса?