почему для цикла есть 1 дополнительная инструкция, чем ожидалось?
Я пишу много векторизованных циклов, поэтому 1 общая идиома
volatile int dummy[1<<10];
for (int64_t i = 0; i + 16 <= argc; i+= 16) // process all elements with whole vector
{
int x = dummy[i];
}
// handle remainder (hopefully with SIMD too)
но полученный машинный код имеет на 1 больше инструкций ,чем я хотел бы (используя gcc 4.9)
.L3:
leaq -16(%rax), %rdx
addq , %rax
cmpq %rcx, %rax
movl -120(%rsp,%rdx,4), %edx
jbe .L3
если я изменю код на for (int64_t i = 0; i <= argc - 16; i+= 16)
, тогда "лишние"
инструкция пропала:
.L2:
movl -120(%rsp,%rax,4), %ecx
addq , %rax
cmpq %rdx, %rax
jbe .L2
но почему разница? Я думал, может быть, это из-за инвариантов цикла, но слишком смутно. Затем я заметил, что в случае с инструкцией 5 инкремент выполняется перед нагрузкой, которая будет требуется дополнительный ход из-за разрушительных инструкций 2 операнда x86. Таким образом, другое объяснение может заключаться в том, что это параллелизм торговых инструкций для 1 дополнительной инструкции.
хотя кажется, что вряд ли будет разница в производительности, может ли кто-нибудь объяснить эту тайну (желательно, кто знает о преобразованиях компилятора)?
В идеале я хотел бы сохранить форму I + 16
1 ответов
если argc
были ниже -2147483632, и i
был ниже 2147483632, выражения i+16 <= argc
потребуется, чтобы получить арифметически правильный результат, в то время как выражение и i<argc-16
не будет. Необходимость дать арифметически правильный результат в этом угловом случае не позволяет компилятору оптимизировать первое выражение для соответствия последнему.