	.x64
	option casemap:none
	option win64:11
	option frame:auto
	option STACKBASE:RSP
	
	ExitProcess proto :DWORD

    includelib <kernel32.lib>
    includelib <user32.lib>


; Define an HVA 2 element structure.
; Both elements are 128bit XMM types.		
	hva2 struct
		a __m128f <>
		b __m128f <>
	hva2 ends

; Define an HVA 3 element structure.
; All elements are 128bit XMM types.	
	hva3 struct
		a __m128f <>
		b __m128f <>
		cc __m128f <>		
	hva3 ends

; Define an HVA 4 element structure.
; All elements are 128bit XMM types.	
	hva4 struct
		a __m128f <>
		b __m128f <>
		cc __m128f <>
		d __m128f <>
	hva4 ends

; Define an HVA 2 element structure.
; All elements are 256bit YMM types.	
	hva22 struct
		a __m256f <>
		b __m256f <>
	hva22 ends

; Define an HVA 4 element structure.
; All elements are 256bit YMM types.	
	hva42 struct
		a __m256f <>
		b __m256f <>
		cc __m256f <>
		d __m256f <>
	hva42 ends

; Define an HFA 2 element structure.
; All elements are floats.	
	hfa2 struct
		f0 real4 0.0
		f1 real4 0.0
	hfa2 ends

; Define an HFA 3 element structure.
; All elements are floats.
	hfa3 struct
		f0 real4 0.0
		f1 real4 0.0
		f2 real4 0.0
	hfa3 ends

; Define an HFA 4 element structure.
; All elements are floats.	
	hfa4 struct
		f0 real4 0.0
		f1 real4 1.0
		f2 real4 2.0
		f3 real4 3.0
	hfa4 ends

; Define an HFA 2 element structure.
; All elements are doubles.	
	hfa5 struct
		d0 real8 0.0
		d1 real8 0.0
	hfa5 ends

; Define an HFA 3 element structure.
; All elements are doubles.
	hfa6 struct
		d0 real8 0.0
		d1 real8 0.0
		d2 real8 0.0
	hfa6 ends

; Define an HFA 4 element structure.
; All elements are doubles.	
	hfa7 struct
		d0 real8 0.0
		d1 real8 0.0
		d2 real8 0.0
		d3 real8 0.0		
	hfa7 ends	

; Declare prototypes for a range of different r-vectorcall combinations.
; Disassembly of the invocation of these procedures will help to understand the calling convention and ABI.		
TestProc      PROTO a:DWORD, b:REAL4
TestProc2     PROTO a:DWORD, b:QWORD
TestProc3     PROTO VECTORCALL a:DWORD, b:REAL4, cc:__m128
TestProc4     PROTO VECTORCALL a:hfa2
TestProc5     PROTO VECTORCALL a:hfa3, b:REAL4
TestProc6     PROTO VECTORCALL a:hfa4
TestProc7     PROTO VECTORCALL a:DWORD, b:REAL4, cc:__m128f, e:DWORD, f:DWORD, cd:__m128
TestProc8     PROTO VECTORCALL a:hfa5
TestProc9     PROTO VECTORCALL a:hfa6
TestProc10    PROTO VECTORCALL a:hfa7
TestProc11    PROTO VECTORCALL a:DWORD, b:REAL4, cc:__m128, d:__m128, e:hva2, f:__m128f
TestProc12    PROTO VECTORCALL a:hfa4, b:hfa4
TestProc13    PROTO VECTORCALL a:hfa4, b:REAL4, cc:REAL4, d:REAL4
TestProc14    PROTO VECTORCALL a:hfa4, b:DWORD, cc:DWORD, d:DWORD, e:DWORD
TestProc15    PROTO VECTORCALL a:hfa4, b:DWORD, cc:DWORD, d:DWORD, e:DWORD, f:DWORD
TestProc16    PROTO VECTORCALL a:DWORD, b:DWORD, cc:DWORD, d:DWORD, e:REAL4, f:REAL4, g:REAL4, h:REAL4
TestProc17    PROTO VECTORCALL a:hfa4, b:REAL4, cc:REAL4, d:REAL4, e:REAL4
TestProc18    PROTO VECTORCALL a:__m128f, b:DWORD, cc:DWORD, d:__m128f
TestProc19    PROTO VECTORCALL a:hfa4, b:DWORD, cc:DWORD, d:__m128f
TestProc20    PROTO VECTORCALL a:hva4, b:hva2, cc:__m128f
TestProc21    PROTO VECTORCALL a:__m128f, b:hva2
TestProcHVA1  PROTO VECTORCALL a:hva2
TestProcHVA2  PROTO VECTORCALL a:hva4
TestProcHVA3  PROTO VECTORCALL a:hva22
TestProcHVA4  PROTO VECTORCALL a:hva42
TestProcHVA5  PROTO VECTORCALL a:hva3
TestProcHVA1x PROTO VECTORCALL i:DWORD, a:hva2
TestProcHVA2x PROTO VECTORCALL i:DWORD, a:hva4
TestProcHVA3x PROTO VECTORCALL i:DWORD, a:hva22
TestProcHVA4x PROTO VECTORCALL i:DWORD, a:hva42
TestProcHVA5x PROTO VECTORCALL i:DWORD, a:REAL4, b:REAL8, cc:REAL4, d:hva42
TestProc22    PROTO VECTORCALL a:DWORD, b:REAL4, cc:hfa4, d:hfa4
TestProc23    PROTO VECTORCALL a:DWORD, b:REAL4, c1:__m128, c2:__m128,c3:__m128,c4:__m128,c5:__m128
TestProc24    PROTO VECTORCALL a:DWORD, b:REAL4, c1:__m128, c2:__m128,c3:__m128,c4:__m128,c5:__m128, c6:__m128f
TestProc25    PROTO VECTORCALL a:DWORD, b:REAL4, cc:__m128f, d:__m128
TestProc26    PROTO VECTORCALL a:__m128f, b:REAL4, cc:REAL4

.data
	
	align 16
	MyVector __m128 { <1.0, 2.0, 3.0, 4.0> }							; Declare a 4-element float SIMD type.
	MyVec4   __m128 { <00001111r, 00002222r, 00003333r, 00004444r> }	; Declare a 4-element float SIMD type (using hex notation).
	MyVector2 __m128f <5.0, 6.0, 7.0, 8.0>								; Declare a 4-element float SIMD type.
	align 16	
	hf1 hfa2 < 9.0, 10.0 >
	align 16	
	hf2 hfa3 < 11.0, 12.0, 13.0 >
	align 16	
	hf3 hfa4 < 4.0, 5.0, 6.0, 7.0 >										; Declare a 4-element float HFA type.
	hf5 hfa5 < 1.0, 2.0 >
	hf6 hfa6 < 1.0, 2.0, 3.0 >
	hf7 hfa7 < 4.0, 5.0, 6.0, 7.0 >	
	align 16	
	hv1 hva2 { <1.0, 2.0, 3.0, 4.0>, <1.0, 2.0, 3.0, 4.0> }
	align 16	
	hv2 hva4 < <1.0, 2.0, 3.0, 4.0>, <1.0, 2.0, 3.0, 4.0>, <1.0, 2.0, 3.0, 4.0>, <1.0, 2.0, 3.0, 4.0> >
	align 32
	hv3 hva22 < <1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0>, <1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0> >
	align 32
	hv4 hva42 < <1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0>, <1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0>, <1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0>, <1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0> >
	hv5 hva3 < <1.0, 2.0, 3.0, 4.0>, <1.0, 2.0, 3.0, 4.0>, <1.0, 2.0, 3.0, 4.0> >
	mvar dd 0
	
.code

MainCRT PROC FRAME
	
	local aba:__m128f

	invoke TestProc26, xmm2, 1.0, 2.0
	
	invoke TestProc12, hf3, hf3                				
	
	invoke TestProc11, 10, 2.0, MyVector2, MyVector, hv1, xmm6	
	invoke TestProc23, 10, 2.0, xmm7, xmm7, xmm7, xmm7, MyVector2
	invoke TestProcHVA5x, mvar, 2.0, FP8(3.0), 4.0, hv4		
	;invoke TestProc25, 1, 1.0, xmm1, xmm2		; overwritten by invoke test
	invoke TestProc22, 2, 1.0, hf3, hf3	
	invoke TestProc24, 10, 2.0, xmm7, xmm7, xmm7, xmm7, MyVector2, MyVector
	invoke TestProc19, hf3, 2, 3, xmm3		    				
	invoke TestProc21, MyVector, hv1
	invoke TestProc15, hf3, 1, 2, 3, 4, 5	    				
	invoke TestProc13, hf3, 1.0, 2.0, 3.0      				
	invoke TestProc18, MyVector, 2, 3, xmm3    				
	invoke TestProc17, hf3, 1.0, 2.0, 3.0, 4.0					
	invoke TestProc16, 1, 2, 3, 4, 1.0, 2.0, 3.0, 4.0			
	invoke TestProc14, hf3, 1, 2, 3, 4							
	invoke TestProc2, 32, CStr("this is text")					
	invoke TestProc3, 40, FP4(1.0), xmm3						
	invoke TestProc3, 40, FP4(1.0), aba						
	invoke TestProc3, 40, FP4(1.0), MyVector2					
	invoke TestProc4, hf1										
	invoke TestProc5, hf2, 1.0 										
	invoke TestProc8, hf5										
	invoke TestProc9, hf6										
	invoke TestProc10, hf7										
	invoke TestProc6, hf3										
	invoke TestProc7, 30, 1.0, MyVector, 10, 20, MyVector2		 
	invoke TestProcHVA1, hv1									
	invoke TestProcHVA2, hv2									
	invoke TestProcHVA3, hv3									
	invoke TestProcHVA4, hv4									
	invoke TestProcHVA5, hv5									
	invoke TestProcHVA1x, eax, hv1								
	invoke TestProcHVA2x, 20, hv2								
	invoke TestProcHVA3x, ebx, hv3								
	invoke TestProcHVA4x, mvar, hv4							
	invoke TestProc20, hv2, hv1, xmm3							
		
	invoke ExitProcess,0

	ret
MainCRT ENDP

TestProc26 PROC VECTORCALL FRAME a:__m128f, b:REAL4, cc:REAL4

vmovaps xmm0,a
vmovss xmm1,b
vmovss xmm2,cc

ret
TestProc26 ENDP

TestProc21 PROC VECTORCALL FRAME a:__m128f, b:hva2

	mov rax,a
	vmovups xmm9,[rax]
	mov rax,b
	vmovups xmm10,[rax]
	vmovups xmm11,[rax+16]
	
	ret
TestProc21 endp

TestProc20 PROC VECTORCALL FRAME a:hva4, b:hva2, cc:__m128f

	ret
TestProc20 endp

; Standard PROC
TestProc PROC FRAME a:DWORD, b:REAL4

	movss xmm10,b
	  
	ret	
TestProc ENDP

; TEST: m128 and m256 local types.
TestProc2 PROC FRAME a:DWORD, b:QWORD
	LOCAL bob2:__m256
	LOCAL bob:__m128
	
	movaps xmm0,bob    ;this should be fine.
	vmovaps xmm0,bob   ;so should this.
	vmovups ymm2,bob2  ;this should be fine always.
	
	mov eax,a
	mov rdi,b
	
	ret	
TestProc2 ENDP

TestProc3 PROC VECTORCALL FRAME uses  xmm7 ymm8 rbx a:DWORD, b:REAL4, cc:__m128
	LOCAL dummy:QWORD

	Mov eax,a   ; this will work.. a will = [rsp+n]  … although smart people would probably just use ecx knowing the argument order…
	mov dummy,rax
	
	;In fastcall b would have been in xmm0, but under vectorcall it's position dependant so would be xmm1
	movss xmm10,b          ;

;	mov rax,cc ; this still needs a QWORD PTR ?
	mov rax,qword ptr cc
	movups xmm11,[rax]  ;

	mov rax,dummy
	
	ret
TestProc3 ENDP

TestProc4 PROC VECTORCALL FRAME a:hfa2

	vmovups xmm0,a ; ensure that a is used to verify it's written correct to shadow space.
	
	ret
TestProc4 ENDP

TestProc8 PROC VECTORCALL FRAME a:hfa5

	vmovups xmm0,a ; ensure that a is used to verify it's written correct to shadow space.
	
	ret
TestProc8 ENDP


TestProc9 PROC VECTORCALL FRAME a:hfa6

	vmovups xmm0,a ; ensure that a is used to verify it's written correct to shadow space.
	
	ret
TestProc9 ENDP


TestProc10 PROC VECTORCALL FRAME a:hfa7

	vmovups xmm0,a ; ensure that a is used to verify it's written correct to shadow space.
	
	ret
TestProc10 ENDP


TestProc11 PROC VECTORCALL FRAME a:DWORD, b:REAL4, cc:__m128, d:__m128, e:hva2, f:__m128f

	ret
TestProc11 ENDP

TestProc12 PROC VECTORCALL FRAME a:hfa4, b:hfa4

	; In this case, a should have come through in xmm0-xmm3
	mov rax,a
	vmovss xmm9,[rax]
	vmovss xmm10,[rax+4]
	vmovss xmm11,[rax+8]
	vmovss xmm12,[rax+12]
	
	; b should have been passed by reference in rdx
	mov rax,b
	vmovss xmm9,[rax]
	vmovss xmm10,[rax+4]
	vmovss xmm11,[rax+8]
	vmovss xmm12,[rax+12]	
	
	vmovss xmm9,[rdx]
	vmovss xmm10,[rdx+4]
	vmovss xmm11,[rdx+8]
	vmovss xmm12,[rdx+12]
		
	ret
TestProc12 ENDP

TestProc13 PROC VECTORCALL FRAME a:hfa4, b:REAL4, cc:REAL4, d:REAL4

	ret
TestProc13 ENDP

TestProc14 PROC VECTORCALL FRAME a:hfa4, b:DWORD, cc:DWORD, d:DWORD, e:DWORD
	ret
TestProc14 endp

TestProc15 PROC VECTORCALL FRAME a:hfa4, b:DWORD, cc:DWORD, d:DWORD, e:DWORD, f:DWORD

	mov rax,a
	vmovss xmm9,[rax].hfa4.f0
	vmovss xmm10,[rax].hfa4.f1
	vmovss xmm11,[rax].hfa4.f2
	vmovss xmm12,[rax].hfa4.f3
	
	mov ebx,b
	mov ebx,cc
	mov ebx,d
	mov ebx,e
	mov ebx,f
	
	ret
TestProc15 endp

TestProc16 PROC VECTORCALL FRAME a:DWORD, b:DWORD, cc:DWORD, d:DWORD, e:REAL4, f:REAL4, g:REAL4, h:REAL4
	ret
TestProc16 endp

TestProc17 PROC VECTORCALL FRAME a:hfa4, b:REAL4, cc:REAL4, d:REAL4, e:REAL4
	ret
TestProc17 endp

TestProc18 PROC VECTORCALL FRAME a:__m128f, b:DWORD, cc:DWORD, d:__m128f
	ret
TestProc18 endp

TestProc19 PROC VECTORCALL FRAME a:hfa4, b:DWORD, cc:DWORD, d:__m128f
	
	mov rax,a
	
	ret
TestProc19 endp

TestProc5 PROC VECTORCALL FRAME a:hfa3, b:REAL4

	vmovups xmm0,a  ; This ssould be bad.. as HFA3 would have been passed in xmm0, xmm1, xmm2.. as individual floats.
	mov rdi,a       ; This shouldn't be very useful.
	vmovss xmm0,b
	
	ret
TestProc5 ENDP

TestProc6 PROC VECTORCALL FRAME a:hfa4

	vmovups xmm0,a ;ensure that a is used so is written to shadow space.
	
	ret
TestProc6 ENDP

TestProc7 PROC VECTORCALL FRAME uses  xmm7 ymm8 rbx a:DWORD, b:REAL4, cc:__m128f, e:DWORD, f:DWORD, cd:__m128
	LOCAL dummy:QWORD

	Mov eax,a   ; this will work.. a will = [rsp+n]  … although smart people would probably just use ecx knowing the argument order…
	mov dummy,rax
	
	;In fastcall b would have been in xmm0, but under vectorcall it's position dependant so would be xmm1
	movss xmm10,b          ;

;	mov rax,cc ; this still needs a QWORD PTR ?
	mov rax,qword ptr cc
	movups xmm11,[rax]  ;

	mov ebx,e
	mov ecx,f
	
	mov rax,dummy
	
	ret
TestProc7 ENDP

TestProcHVA1 PROC VECTORCALL FRAME uses rbx rsi a:hva2

	ret
TestProcHVA1 ENDP

TestProcHVA2 PROC VECTORCALL FRAME a:hva4

	vmovups xmm0,a
		
	ret
TestProcHVA2 ENDP


TestProcHVA3 PROC VECTORCALL FRAME uses rdi a:hva22

	ret
TestProcHVA3 ENDP

TestProcHVA4 PROC VECTORCALL FRAME a:hva42

	vmovups ymm7,a
	
	ret
TestProcHVA4 endp

TestProcHVA5 PROC VECTORCALL FRAME a:hva3

	vmovups ymm7,a
	
	ret
TestProcHVA5 endp

TestProcHVA1x PROC VECTORCALL FRAME uses rbx rsi i:DWORD, a:hva2

	ret
TestProcHVA1x ENDP

TestProcHVA2x PROC VECTORCALL FRAME i:DWORD, a:hva4

	vmovups xmm0,a
		
	ret
TestProcHVA2x ENDP


TestProcHVA3x PROC VECTORCALL FRAME uses rdi i:DWORD, a:hva22

	ret
TestProcHVA3x ENDP

TestProcHVA4x PROC VECTORCALL FRAME i:DWORD, a:hva42

	vmovups ymm7,a
	
	ret
TestProcHVA4x endp

TestProcHVA5x PROC VECTORCALL FRAME i:DWORD, a:REAL4, b:REAL8, cc:REAL4, d:hva42

	mov eax,i
	vmovss xmm9,a
	vmovsd xmm10,b
	vmovss xmm11,cc
	
	vmovups ymm12,d.a
	vmovups ymm13,d.b
	vmovups ymm14,d.cc
	vmovups ymm15,d.d
	
	ret
TestProcHVA5x endp

TestProc22 PROC VECTORCALL FRAME a:DWORD, b:REAL4, cc:hfa4, d:hfa4

	mov rax,d     ;d should already be in r9
	vmovss xmm11,[rax].hfa4.f0
	vmovss xmm11,[rax].hfa4.f1
	vmovss xmm11,[rax].hfa4.f2
	vmovss xmm11,[rax].hfa4.f3
	
	mov ebx,a
	vmovss xmm11,b
	mov rax,cc
	vmovss xmm11,[rax].hfa4.f0
	vmovss xmm11,[rax].hfa4.f1
	vmovss xmm11,[rax].hfa4.f2
	vmovss xmm11,[rax].hfa4.f3
	
	ret
TestProc22 endp

TestProc23 PROC VECTORCALL FRAME a:DWORD, b:REAL4, c1:__m128, c2:__m128,c3:__m128,c4:__m128,c5:__m128

	mov eax,a
	vmovss xmm9,b
	
	mov rax,c1
	vmovaps xmm0,[rax]
	mov rax,c2
	vmovaps xmm1,[rax]
	mov rax,c3
	vmovaps xmm2,[rax]
	mov rax,c4
	vmovaps xmm3,[rax]
	mov rax,c5
	vmovaps xmm5,[rax]
	
	ret
TestProc23 endp


TestProc24 PROC VECTORCALL FRAME a:DWORD, b:REAL4, c1:__m128, c2:__m128,c3:__m128,c4:__m128,c5:__m128, c6:__m128f

	mov eax,a
	vmovss xmm9,b
	
	mov rax,c1
	vmovaps xmm0,[rax]
	mov rax,c2
	vmovaps xmm1,[rax]
	mov rax,c3
	vmovaps xmm2,[rax]
	mov rax,c4
	vmovaps xmm3,[rax]
	mov rax,c5
	vmovaps xmm5,[rax]
	
	ret
TestProc24 endp

TestProc25 PROC VECTORCALL FRAME a:DWORD, b:REAL4, cc:__m128f, d:__m128

	mov rax,cc
	vmovaps xmm0,[rax]
	mov rax,d
	vmovaps xmm1,[rax]
	
	ret
TestProc25 ENDP

end MainCRT
