It was a bit of a puzzle to create but I hope this works for you.
It should work on x64 and x86, both ascii and unicode.
Code:
Procedure.l CountWords(*Text.Character); Requires SSE
; init some mmx registers
!mov eax, 1
!movd mm4, eax ; mm4 = previous comparison result
!pxor mm3, mm3 ; mm3 = 0
!movq mm2, mm4 ; mm2 = counter
!mov eax, 0x200d0a09
!movd mm1, eax
!punpcklbw mm1, mm3 ; mm1 = separation characters (tab, lf, cr, space)
!movq mm0, mm4 ; mm0 = working register
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_Text]
CompilerElse
!mov edx, [p.p_Text]
CompilerEndIf
!jmp countwords_entry
; main loop
!countwords_loop:
; compare character with separation chars
!pshufw mm0, mm5, 0
!pcmpeqw mm0, mm1
!psrlw mm0, 15
!psadbw mm0, mm3
; at this time mm0 = 1 if a separation char is found otherwise 0
!pandn mm4, mm0
!paddd mm2, mm4
; make a copy of the comparison result
!movq mm4, mm0
; entry point for first character
!countwords_entry:
CompilerIf #PB_Compiler_Unicode
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!movzx eax, word [rdx]
!add rdx, 2
CompilerElse
!movzx eax, word [edx]
!add edx, 2
CompilerEndIf
CompilerElse
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!movzx eax, byte [rdx]
!add rdx, 1
CompilerElse
!movzx eax, byte [edx]
!add edx, 1
CompilerEndIf
CompilerEndIf
!movd mm5, eax
; loop if not end of string
!and ax, ax
!jnz countwords_loop
; correct counter if last character was a separation character
!psubd mm2, mm0
; set result and empty mmx state
!movd eax, mm2
!emms
ProcedureReturn
EndProcedure
Example
Code:
S.s = "This is a test string"
Debug CountWords(@S)