이것은 컴파일러가 최적의 코드를 생성하지 못하는 코드 부분의 속도를 높이기 위해 컴파일러 내장 함수를 사용하는 것에 관한 세 번째 실습입니다.
이 실습의 과제는 3차원 공간에 있는 일련의 위치들의 평균 위치를 구하는 것입니다:
struct Position {
u32 x;
u32 y;
u32 z;
}
...
u64 x = 0;
u64 y = 0;
u64 z = 0;
for (Position pos: input) {
x += pos.x; // extend 32 bit to 64 bit and accumulate
y += pos.y;
z += pos.z;
}
현재 컴파일러는 x86에서 이 코드를 벡터화하지 못합니다. 그러나 ARM에서는 XYZ 성분을 디인터리브하는 마법 같은 LDM 명령어를 사용하여 영리한 코드를 생성합니다. 1 그렇지만 여전히 이를 더 효율적으로 벡터화할 수 있습니다.
이 루프를 수동으로 벡터화하려면 메모리 레이아웃과 요소에 적용되는 연산에 대해 생각해 보십시오.
주의 사항: 현재 벤치마크는 16k개의 위치를 처리하며, 이는 192KB의
공간을 차지합니다(12 bytes * 16K positions). 입력 크기가
커질수록 벤치마크는 점점 더 Memory Bound 상태가 되어 성능 향상 폭이
줄어듭니다.
이 실습은 Jonathan Hallström(@JonathanHallstrom)이 기여했습니다.
다음은 ARM의 LDM 명령어의 예시입니다.
↩︎// Assume input points to an array of structures {u32 x, u32 y, u32 z} LD3 {V0.4S, V1.4S, V2.4S}, [input] // Load 4 positions at once (each containing xyz elements) // After that: // V0.4S will have four X coordinates, // V1.4S will have four Y coordinates, // V2.4S will have four Z coordinates, // Reducing vectors with such a friendly layout is much easier.