; ------------------------------------------------------------------
; Reference Assembly for
;   Microsoft Visual C++ Compiler Generated Code Performance
;
; This work is released into public domain, under applicable law,
; absolutely without warranty neither implied nor expressed.
; ------------------------------------------------------------------

.386p
.model  flat

includelib  kernel32.lib
includelib  msvcrt.lib
includelib  user32.lib

extern      _ExitProcess@4          :proc
extern      _GetCurrentProcess@0    :proc
extern      _GetCurrentThread@0     :proc
extern      _GetTickCount@0         :proc
extern      _SetPriorityClass@8     :proc
extern      _SetThreadPriority@8    :proc
extern      _Sleep@4                :proc
extern      _VirtualAlloc@16        :proc
extern      _VirtualFree@12         :proc
extern      _fclose                 :proc
extern      _fopen                  :proc
extern      _fprintf                :proc
extern      _printf                 :proc

_DATA   segment

    szTitle db  'Compiler generated code benchmark (reference assembly).',10,0
    szLgFil db  'asmref.log',0
    szLgMod db  'w',0
    szLgItm db  '%lu | %lu | %ld',10,0
    szClose db  'Average delay: %lu ms',10,0

_DATA   ends

_TEXT   segment

_bench  proc    near
    PUSH    EDI
    MOV     EDI,DWORD PTR SS:[ESP+8]
    PUSH    ESI
    MOV     ESI,DWORD PTR SS:[ESP+16]

    PUSH    EBX
    PUSH    ECX
    PUSH    EDX
    MOV     EBX,[ESI]
    MOV     ECX,100000000
lInnerLoop:
    DEC     ECX
    ; i/8
    MOV     EAX,ECX
    SHR     EAX,3
    ADD     EBX,EAX
    ; i%8
    SHL     EAX,3
    ADD     EBX,ECX
    SUB     EBX,EAX
    ; i/789
    MOV     EAX,530FE60Bh
    MUL     ECX
    ADD     EAX,530FE60Bh
    ADC     EDX,0
    SHR     EDX,8
    ADD     EBX,EDX
    ; i+i*123 (i*124 (i*128-i*4))
    MOV     EAX,ECX
    SHL     EAx,2
    SUB     EBX,EAX
    SHL     EAX,5
    ADD     EBX,EAX

    TEST    ECX,ECX
    JNZ     lInnerLoop

    MOV     [ESI],EBX

    ; FillMemory(..., 0x7e);
    MOV     ECX,1900000h            ; 100MB/4
    MOV     EAX,7E7E7E7Eh
    REP     STOSD

    POP     EDX
    POP     ECX
    POP     EBX
    POP     ESI
    POP     EDI

    RETN    8
_bench  endp

_main   proc    near
    ENTER 24,0

    PUSH    OFFSET  szTitle
    CALL    _printf
    ADD     ESP,4

    PUSH    OFFSET  szLgMod
    PUSH    OFFSET  szLgFil
    CALL    _fopen
    ADD     ESP,8

    TEST    EAX,EAX
    JZ      lNoFile
    MOV     DWORD PTR SS:[EBP-4],EAX

    PUSH    4                       ; PAGE_READWRITE
    PUSH    1000h                   ; MEM_COMMIT
    PUSH    6400000h                ; 100 MB
    PUSH    0                       ; NULL
    CALL    _VirtualAlloc@16

    TEST    EAX,EAX
    JZ      lNoMemory
    MOV     DWORD PTR SS:[EBP-8],EAX

    PUSH    15                      ; THREAD_PRIORITY_TIME_CRITICAL
    CALL    _GetCurrentThread@0
    PUSH    EAX
    CALL    _SetThreadPriority@8

    PUSH    1000
    CALL    _Sleep@4

    PUSH    EBX
    PUSH    ECX
    PUSH    ESI
    PUSH    EDI
    MOV     ECX,100
    XOR     EAX,EAX
    MOV     DWORD PTR SS:[EBP-16],EAX
    INC     EAX
    MOV     DWORD PTR SS:[EBP-12],EAX
    MOV     EDI,_GetTickCount@0
lOuterLoop:
    DEC     ECX
    PUSH    ECX

    LEA     ESI,DWORD PTR SS:[EBP-12]

    PUSH    100h                    ; REALTIME_PRIORITY_CLASS
    CALL    _GetCurrentProcess@0
    PUSH    EAX
    CALL    _SetPriorityClass@8

    CALL    EDI
    MOV     EBX,EAX

    PUSH    ESI
    PUSH    DWORD PTR SS:[EBP-8]
    CALL    _bench

    CALL    EDI
    SUB     EAX,EBX
    MOV     EBX,EAX

    PUSH    20h                     ; NORMAL_PRIORITY_CLASS
    CALL    _GetCurrentProcess@0
    PUSH    EAX
    CALL    _SetPriorityClass@8

    MOV     EAX,DWORD PTR SS:[EBP-16]
    TEST    EAX,EAX
    JZ      lFirstDelay
    ADD     EAX,EBX
    SHR     EAX,1
    JMP     lAfterDelay
lFirstDelay:
    MOV     EAX,EBX
lAfterDelay:
    MOV     DWORD PTR SS:[EBP-16],EAX

    MOV     ESI,EBX
    SUB     ESI,EAX

    PUSH    ESI
    PUSH    EAX
    PUSH    EBX
    PUSH    OFFSET  szLgItm
    PUSH    DWORD PTR SS:[EBP-4]
    CALL    _fprintf
    ADD     ESP,20

    POP     ECX
    TEST    ECX,ECX
    JNZ     lOuterLoop

    PUSH    8000h                   ; MEM_RELEASE
    PUSH    0
    PUSH    DWORD PTR SS:[EBP-8]
    CALL    _VirtualFree@12

    PUSH    DWORD PTR SS:[EBP-16]
    PUSH    OFFSET  szClose
    CALL    _printf
    ADD     ESP,8

    POP     EDI
    POP     ESI
    POP     ECX
    POP     EBX

lNoMemory:
    PUSH    DWORD PTR SS:[EBP-4]
    CALL    _fclose
    ADD     ESP,4

lNoFile:

    PUSH    0
    CALL    _ExitProcess@4

    LEAVE
    RETN
_main   endp

_TEXT   ends

end
