Load address calculation when using AVX2 gather instructions

牧云@^-^@ 提交于 2019-11-27 08:55:36

Gather instructions do not have any alignment requirements. So it would be too restrictive not to allow byte addressing.

Other reason is consistency. With SIB addressing we obviously have byte address:

MOV eax, [rcx + rdx * 2]

Since VPGATHERDD is just a vectorized variant of this MOV instruction, we should not expect anything different with VSIB addressing:

VPGATHERDD ymm0, [rcx + ymm2 * 2], ymm3

As for real life use for byte addressing, we could have a 24-bit color image where each pixel is 3-byte aligned. We could load 8 pixels with single VPGATHERDD instruction but only if "scale" field in VSIB is "1" and VPGATHERDD uses byte addressing.

Judging by the description in Intel's AVX programming reference document available here, it looks like the gather instructions use byte addressing. Specifically, see the following quotes from the description of the VPGATHERDD instruction (on page 389):

DISP: optional 1, 2, 4 byte displacement;
DATA_ADDR = BASE_ADDR + (SignExtend(VINDEX[i+31:i])*SCALE + DISP;

Since you can use 1/2/4 byte displacements, I would assume that the overall memory address is a byte address. While it may not be a common application, there could be cases where you would want to read a 32- or 64-bit value from a misaligned address. That's one of the more flexible things about the x86 architecture when compared to something like ARM; you have the flexibility to perform misaligned accesses if you want, instead of triggering a CPU exception as some others do.

why would you want to load from misaligned addresses (i.e. use scale < 4) ?

Misaligned loads are not the only use-case for scale < element size. You might just have indices that are pre-scaled byte offsets. Or consider vectorizing a loop over an array of pointers to structs: you could gather with a base "address" of zero or a small integer offset into the struct.

Supporting this use-case is one reason for Intel to design the asm instruction to support this, because gathers are supposed to help compilers auto-vectorize more code. It also fits naturally for the VSIB byte to be very close to SIB in the machine-code encoding, but they could easily have pre-biased the scale factor to give you a choice of scale = 4,8,16,32 (or 8,16,32,64 for qword gathers) with the 2-bit scale field.

Scale factors larger than the element size are not obviously useful in many cases either, and are easy to emulate with a single left-shift instruction before the gather. But it would be impossible to work around a baked-in scale factor, so allowing unscaled indices is clearly the more flexible design choice.


Other use-cases: gathering 16-bit elements. Use a 32-bit gather and mask off the top half of each element after the gather. (Or just leave it holding garbage). That would result in misaligned loads if any of your indices are odd (for a scale-factor of 2), so it's could be slow if they cross 4k boundaries (unlike a true 16-bit gather).

You could also imagine using a gather as part of a decompression function, where after some decoding you have a vector of offsets into a buffer, and you want arbitrary 4-byte or 8-byte windows of data.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!