mirror of
https://github.com/libretro/x86-assembly-cheat.git
synced 2026-11-07 12:47:59 -10:00
186 lines
5.0 KiB
NASM
186 lines
5.0 KiB
NASM
; # SIMD
|
|
|
|
; Do a single operations at once on multiple memory locations,
|
|
; e.g. add four integers in one go.
|
|
|
|
; https://www.kernel.org/pub/linux/kernel/people/geoff/cell/ps3-linux-docs/CellProgrammingTutorial/BasicsOfSIMDProgramming.html
|
|
|
|
; SIMD came in multiple stages: first MMX, then XMM, then SSE[1-4], then AVX.
|
|
|
|
; SIMD uses:
|
|
|
|
; - https://software.intel.com/en-us/intel-ipp
|
|
|
|
%include "lib/asm_io.inc"
|
|
|
|
section .bss
|
|
|
|
resd0 resd 1
|
|
resd1 resd 1
|
|
reso0 reso 1
|
|
reso1 reso 1
|
|
|
|
ENTRY
|
|
|
|
; # SIMD Registers
|
|
|
|
; # MMX
|
|
|
|
; From the MMX extenion.
|
|
|
|
; TODO. Not very useful after SSE: splits 32 bits into multiple sections,
|
|
; but not any larger than EAX.
|
|
|
|
; # XMM
|
|
|
|
; # movss
|
|
|
|
; Move Scalar Single precision 32 bits to or from memory.
|
|
|
|
mov dword [resd0], __float32__(0.1)
|
|
movss xmm0, [resd0]
|
|
movss xmm1, xmm0
|
|
movss [resd1], xmm1
|
|
ASSERT_EQ [resd0], __float32__(0.1), dword
|
|
|
|
; # movups
|
|
|
|
; Move Unaligned Parallel Single-precision float
|
|
|
|
; From SSE extensions.
|
|
|
|
; 16 bytes.
|
|
|
|
MOV4 reso0, 0x0000_0000, 0x1000_0000, 0x2000_0000, 0x3000_0000
|
|
|
|
movups xmm0, [reso0]
|
|
; Can also move between two xmm.
|
|
; But in this case we can use movaps.
|
|
movaps xmm1, xmm0
|
|
movups [reso1], xmm1
|
|
|
|
ASSERT_EQ4 reso1, 0x0000_0000, 0x1000_0000, 0x2000_0000, 0x3000_0000
|
|
|
|
; ERROR: invalid combination of opcode and operands.
|
|
|
|
;movups xmm0, 0
|
|
;mov xmm0, [reso0]
|
|
|
|
; Can only move data between RAM and XMM, no literals.
|
|
|
|
; movups must be used, mov does not work
|
|
|
|
; # movaps
|
|
|
|
; Aligned.
|
|
|
|
; May be faster.
|
|
|
|
; If you attempt to use it on unaligned memory,
|
|
; raises a general-protection exception (#GP).
|
|
; Let's do that now. One of the following must be misaligned:
|
|
|
|
;movaps xmm0, [reso0]
|
|
;movaps xmm0, [reso0 + 1]
|
|
|
|
; Linux gives a segmentation fault.
|
|
|
|
; # aligned
|
|
|
|
; # unaligned
|
|
|
|
; TODO why is aligned faster?
|
|
|
|
; TODO how to align?
|
|
|
|
; http://stackoverflow.com/questions/381244/purpose-of-memory-alignment
|
|
|
|
|
|
; # MOVHPS - Move 64bits to upper bits of an SIMD register (high).
|
|
|
|
; # MOVLPS - Move 64bits to lowe bits of an SIMD register (low).
|
|
|
|
; # MOVHLPS - Move upper 64bits of source register to the lower 64bits of destination register.
|
|
|
|
; # MOVLHPS - Move lower 64bits of source register to the upper 64bits of destination register.
|
|
|
|
; # MOVMSKPS - Move sign bits of each of the 4 packed scalars to an x86 integer register.
|
|
|
|
; # AVX
|
|
|
|
; From AVX extensions.
|
|
|
|
; 32 bytes.
|
|
|
|
; # pcmpeqd
|
|
|
|
; Compare each double word of the registers for equality.
|
|
|
|
; # pmovmskb
|
|
|
|
; # VEX prefix
|
|
|
|
; TODO
|
|
|
|
; # packed
|
|
|
|
; # scalar
|
|
|
|
; http://stackoverflow.com/questions/16218665/simd-and-difference-between-packed-and-scalar-double-precision
|
|
|
|
; Many SIMD instructions have two versions: parallel and scalar.
|
|
|
|
; - scalar only acts on the first bytes, doing a single value operation.
|
|
|
|
; It likely exists to allow FPU replacement.
|
|
|
|
; - packed: the more interesting method, which operates on multiple data at once (4 floats or 2 doubles)
|
|
|
|
; # SSE2
|
|
|
|
; # paddq
|
|
|
|
; Packed Add Quadwords (integers).
|
|
|
|
MOV4 reso0, 0x0000_0000, 0x0000_0001, 0x0000_0002, 0x0000_0003
|
|
MOV4 reso1, 0x0000_0000, 0x1000_0000, 0x2000_0000, 0x3000_0000
|
|
|
|
movups xmm0, [reso0]
|
|
movups xmm1, [reso1]
|
|
paddq xmm0, xmm1
|
|
movups [reso0], xmm0
|
|
|
|
ASSERT_EQ4 reso0, 0x0000_0000, 0x1000_0001, 0x2000_0002, 0x3000_0003
|
|
|
|
; # addps
|
|
|
|
; Add Packed Single precision float.
|
|
|
|
MOV4 reso0, __float32__(0.0), __float32__(0.5), __float32__(0.25), __float32__(0.125)
|
|
MOV4 reso1, __float32__(0.0), __float32__(1.0), __float32__(2.0), __float32__(4.0)
|
|
|
|
movups xmm0, [reso0]
|
|
movups xmm1, [reso1]
|
|
addps xmm0, xmm1
|
|
movups [reso0], xmm0
|
|
|
|
ASSERT_EQ4 reso0, __float32__(0.0), __float32__(1.5), __float32__(2.25), __float32__(4.125)
|
|
|
|
; # cvttss2si
|
|
|
|
; Convert with Truncation Scalar Single-Precision FP Value to Dword Integer.
|
|
|
|
; Typecast float to int.
|
|
|
|
mov dword [resd0], __float32__(1.5)
|
|
movss xmm0, [resd0]
|
|
cvttss2si eax, xmm0
|
|
call print_int
|
|
ASSERT_EQ eax, 1
|
|
|
|
; # SSSE3
|
|
|
|
; # SSE4
|
|
|
|
EXIT
|