·642 words·4 mins
๐ ์์ธ ์ ๋ฆฌ # Floating-Point Code ๋ถ๋์์์ ์ํคํ
์ณ๋ ์ด์ผ ๋์ํ ๋ผ๋ ๋ถ๋์์์ ๊ฐ์ด ์ ์ฅ๋๊ณ ์์ธ์ค๋๋ ๋ฐฉ๋ฒ ๋ถ๋์์ซ์ ๋ฐ์ดํฐ์์ ์๋ํ๋ ๋ช
๋ น์ด ๋ถ๋์์์ ๊ฐ์ ํจ์์ ์ ๋ฌํ๊ณ ๋ฐํํ๋๋ฐ ์ฌ์ฉ๋๋ ์ปจ๋ฒค์
/๊ด๋ก ํจ์ ํธ์ถ ์ค ๋ ์ง์คํฐ๊ฐ ๋ณด์กด๋๋ ๋ฐฉ๋ฒ์ ๋ํ ๊ท์ฝ SSE๋ 128๋นํธ, AVX๋ 256๋นํธ, AVX-512๋ 512๋นํธ.. %xmm0, %xmm1๋ฑ์ ์ด์
๋ธ๋ฆฌ ์ฝ๋๊ฐ ๋์ค๋ฉด ํ๋์ ์ธ ๋ ์ง์คํฐ๋ค! %rax, %rbx, %rsp, … %r15๋์ ์์ ๋ณ๊ฐ. ์์น๋ ๋ค๋ฅธ๋ฏ? ์ฐ์ฐ ๋ฐฉ์ ์์ฒด๊ฐ ๋ณด์๋ฐฉ์ / ์ง์๊ฐ์ ๋ฐฉ์์ผ๋ก ๋ค๋ฅด๋๊น ๋ค๋ฅธ ์ฅ์น์์ SIMD๋ ๊ฐ๋ฅํ๋ค! 3.11.1 Floating-Point Movement and Conversion Operations vmovss / vmovsd / vmovaps / vmovapd ๊ฐ์ ๋ช
๋ น์ด๋ค์ด ์๋ค ์ฝ๋ ์ต์ ํ ์ง์นจ์ 32๋นํธ ๋ฐ์ดํฐ๋ 4๋ฐ์ดํธ ์ ๋ ฌ์, 64๋นํธ ๋ฐ์ดํฐ๋ 8๋ฐ์ดํธ ์ ๋ ฌ์ ๋ง์กฑํ๋๋ก ๊ถ์ฅํ์ง๋ง ์๊ทธ๋๋ ๋์์ ํ๋ค ์ ์ mov๊ณผ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ฌ๋งํ๋ฉด ๋์ํ๋ค! GCC๋ ์ค์นผ๋ผ ์ด๋ ์ฐ์ฐ์ xmm ๋ ์ง์คํฐ - ๋ฉ๋ชจ๋ฆฌ ์ฌ์ด์์๋ง ์ํํ๋ค. xmm ๋ ์ง์คํฐ ์ฌ์ด์์ ์ ์กํ๊ธฐ ์ํด์ vmovaps๋ vmoapd ์์์๋ a๋ aligned, ์ ๋ ฌ์ ์๋ฏธํ๋ค float float_mov(float v1, float *src, float *dst){ float v2 = *src; *dst = v1; return v2; } ์ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ด ๋ฒ์ญ๋๋ค. v1 in %xmm0, src in %rdi, dst in %rsi 1 float_mov: 2 vmovaps %xmm0, %xmm1 Copy v1 3 vmovss (%rdi), %xmm0 Read v2 from src 4 vmovss %xmm1, (%rsi) Write v1 to dst 5 ret Return v2 in %xmm0 ``` vmovaps, vmovss๋ฅผ ๋๋ค ํ์ธํ ์ ์๋ค! float -> ์ ์์์๋ ์ ๋ฐ์ฌ๋ฆผํด์ ๋ค์ด๊ฐ ์ ์ -> float์์๋ ์ ๊ธฐํ๊ฒ๋ ๋ค์ ํผ์ฐ์ฐ์๊ฐ 3๊ฐ ๋ค์ด๊ฐ๋ค ์ด๋ ๋๋ฒ์งธ ํผ์ฐ์ฐ์๋ ์์ ๋ฐ์ดํธ์๋ง ์ํฅ์ ๋ฏธ์ณ์ ๋ฌด์ํด๋ ๋๋ค ์ผ๋จ ๋๋ฒ์งธ ์ฐ์ฐ์๋ ๊ฒฐ๊ณผ๊ฐ ๋ค์ด๊ฐ ๋ ์ง์คํฐ์๊ธฐ ๊ธฐ์กด ๊ฐ์ ์๋ฏธํ๋ค. ์ฌ๋งํ ์ฐ์ฐ์์ ๋๋ฒ์งธ ํผ์ฐ์ฐ์์ ์ธ๋ฒ์งธ ๋ชฉ์ ์ง ํผ์ฐ์ฐ์๋ ๊ฐ๋ค float -> float์์ ์กฐ๊ธ ์ด์ํ ์ฝ๋๊ฐ ์์ฑ๋๋ค ์์๋นํธ๋ฅผ ๋ค์ ํ์ฉํ์ง ๋ชปํ๊ฒ ํ๊ธฐ ์ํจ ๊ฐ์ง ์์กด์ฑ ์ด์ ์ ์์ ๋นํธ๊ฐ์ ์จ์ผ๋ ๋ ๊ฐ์ ๊ธฐ๋ค๋ฆฌ๊ฒ ํ์ง ์๊ธฐ ์ํด, ๊ทธ๋ฅ ๋ฎ์ด๋ฒ๋ฆฐ๋ค single -> double, double -> single ๋๋ค ๋ง์ฐฌ๊ฐ์ง 3.11.2 Floating-Point Code in Procedures ํฌ์์
ํ๋ก์์ ธ๋ค ์ธ์ ๋ ๊ทธ๋ฌ๋ฏ XMM ๋ ์ง์คํฐ๋ฅผ ์ด์ฉํด์ float ์ธ์๋ค์ ํจ์๋ก ์ ๋ฌํ๊ณ ๋ฐํ๋ฐ๊ณ ํ๋ค x86-64์์๋ ๋ค์๊ณผ ๊ฐ์ ๊ด์ต์ด ๊ด์ฐฐ๋๋ค ์ต๋ 8๊ฐ์ float arg๊ฐ xmm0~7๋ก ์ ๋ฌ๋๊ณ , ๋ ํ์ํ๋ฉด ์คํ ์ฌ์ฉ float ๋ฐํ์ xm0์์ ๋ชจ๋ XMM ๋ ์ง์คํฐ๋ caller-saved. ์ดํ์ ํธ์ถ๋๋์ด ๋ง๋๋ก ๋ฐ๊ฟ๋ ๋จ double f1(int x, double y, long z); ์์ ์์์, %edi์ x, %xmm0์ y, %rsi์ z 3.11.3 Floating-Point Arithmetic Operations double funct(double a, float x, double b, int i){ return a*x - b/i; } ์ ์ฝ๋๋ ๋ค์๊ณผ๊ฐ์ด ๋ฒ์ญ๋๋ค. a in %xmm0, x in %xmm1, b in %xmm2, i in %edi 1 funct: The following two instructions convert x to double 2 vunpcklps %xmm1, %xmm1, %xmm1 3 vcvtps2pd %xmm1, %xmm1 4 vmulsd %xmm0, %xmm1, %xmm0 Multiply a by x 5 vcvtsi2sd %edi, %xmm1, %xmm1 Convert i to double 6 vdivsd %xmm1, %xmm2, %xmm2 Compute b/i 7 vsubsd %xmm2, %xmm0, %xmm0 Subtract from a*x 8 ret Return ``` 3.11.4 Defining and Using Floating-Point Constants ์ ์ ์ฐ์ฐ๊ณผ ๋ฌ๋ฆฌ AVX float ์ฐ์ฐ์ immediate value๋ก ์ฐ์ฐํ ์ ์๋ค. ๋์ ์ปดํ์ผ๋ฌ๋ ์์๊ฐ์ ๋ํด ์คํ ๋ฆฌ์ง๋ฅผ ํ ๋นํ๊ณ ์ด๊ธฐํํ๊ณ , ๋ฉ๋ชจ๋ฆฌ๋ก๋ถํฐ ๊ฐ์ ์ฝ๋๋ค. double cel2fahr(double temp){ return 1.8 * temp + 32.0; } ๊ณผ ๊ฐ์ ํจ์๊ฐ ์๋ค๋ฉด, ์ด๋ ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๋๋ค. double cel2fahr(double temp) temp in %xmm0 1 cel2fahr: 2 vmulsd .LC2(%rip), %xmm0, %xmm0 Multiply by 1.8 3 vaddsd .LC3(%rip), %xmm0, %xmm0 Add 32.0 4 ret 5 .LC2: 6 .long 3435973837 Low-order 4 bytes of 1.8 7 .long 1073532108 High-order 4 bytes of 1.8 8 .LC3: 9 .long 0 Low-order 4 bytes of 32.0 10 .long 1077936128 High-order 4 bytes of 32.0 ``` .LC2์ ์์น๋ก๋ถํฐ 1.8์ ๊ฐ์ ธ์ค๊ณ , .LC3์์ 32.0์ ํ๋
ํด์ค๋ ๊ฒ์ผ๋ก ๋ณด์ธ๋ค. 3.11.5 Using Bitwise Operations in Floating-Point Code ๋นํธ์ฐ์ฐ์ float์์๋ ์ฌ์ฉํ ์ ์๋ค! vxorps, vxorpd, vandps, vandpd ๊ทผ๋ฐ float์์ ๋นํธ์ฐ์ฐ์ ์ง์ง ์ํ์ง? ๋ ์ง์คํฐ๋ฅผ 0์ผ๋ก ์ด๊ธฐํํ๊ณ ์ถ์ ๋ ์๊ธฐ ์์ ์ xorํ๊ธฐ ๋ถํธ ๋ฐ์ / ์ ๋๊ฐํ ๋งจ์ MSB ๋ง์ง๊ธฐ (x<0 ? 0:x)๊ณผ ๊ฐ์ ๊ฒฝ์ฐ (RELU) 3.11.6 Floating Point Comparison Operations ์๋ฌด๋๋ ์๋ฅผ ๋น๊ต๋ ํด์ผ๊ฒ ์ง ucomiss / ucomisd S1์ S2 ๋น๊ต ๋ ๊ทธ๋ฌ๋ฏ ZF, CF, PF๋ฅผ ์ค์ ํ๋ค ํ๋๋ผ๋ NaN์ด๋ฉด, ์ธ ํ๋๊ทธ๋ฅผ ๋ค ํจ๋ค! 3.11.7 Observations about Floating-Point Code AVX2๊ฐ float์ ๋ํด ์ ์๋ ๋น์ทํ์ง๋ง, ํจ์ฌ๋ ๋ค์ํ ๋ช
๋ น์ด์ ํ์์ ํฌํจํ๋๊ฑธ ์ ์ ์์๋ค. ๋ํ ํจํน๋ ๋ฐ์ดํฐ์ ๋ณ๋ ฌ์ฐ์ฐ์ ์ํํด์ ๋ ๋น ๋ฅด๊ฒ ์คํ์ํฌ์๋ ์๋ค. ์์ gcc๊ฐ ํด์ฃผ๋๋ผ โ์ง๋ฌธ ์ฌํญ # ๐ ์ฐธ๊ณ ์๋ฃ #