When I use the PROLOGUE option that makes easy to make calls, create local varibles...
When I read Jochen sources he does not use the prologue?
Why?
What is the best choice?
it's simply a matter of knowing what the assembler generates for automatic prologue and epilogue
once you understand what it does, you can make the choice that best suits the function
when speed is an issue (the function is called thousands of times, perhaps),
it may be best to write your own prologue and epilogue
otherwise, using the assembler automatic prologue and epilogue makes for more readable code
Hi Grincheux,
As Dave said, it's a matter of personal choice. You can remove the prologue \ epilogue sections for optimization purposes.
Quote from: Grincheux on January 07, 2016, 03:47:07 AMWhen I read Jochen sources he does not use the prologue?
90% of my procs do have a prologue. But occasionally you can produce shorter and/or faster code without, mainly if
- you have enough spare registers (i.e. no need for locals)
- you need to access the arguments only a few times
If you access args frequently, code size will be shorter with a stack frame:
mov eax, [e
bp+nn] is one byte shorter than
mov eax, [e
sp+nn]
Thank you every one it is clear. I have been very pleased to get your help all the time I was programming this utility.
For Jochen : In my program CatchWebImages (http://www.phrio.biz/mediawiki/Catch_Web_Pages) I have used two functions MbStrLen and InstrJJ.
If you write an InstrJJ backward function think to me.
Quote from: Grincheux on January 07, 2016, 07:03:30 AMIf you write an InstrJJ backward function think to me.
There is Rinstr() (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1154), but it's not particularly fast:
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz (SSE4)
34076 cycles for 100 * InString
26291 cycles for 100 * MB Instr_()
7121 cycles for 100 * MB Instr_(FAST, )
29626 cycles for 100 * MB Rinstr()
31901 cycles for 100 * CRT strstr
To PROLOGUE option
http://www.masmforum.com/board/index.php?PHPSESSID=786dd40408172108b65a5a36b09c88c0&topic=11514.0
But i have never used if i use Global and local Variables have i problems to calc the esp pointer ::)
And a good tutorial about it have i never found.
http://masm32.com/board/index.php?topic=3326.msg35046#msg35046 (http://masm32.com/board/index.php?topic=3326.msg35046#msg35046)
http://masm32.com/board/index.php?topic=3326.msg35052#msg35052 (http://masm32.com/board/index.php?topic=3326.msg35052#msg35052)
Philippe,
> If you write an InstrJJ backward function think to me.
They are not that hard to write, once you have the word length to find, subtract that from the text length then scan backwards testing each start character and following characters to see if you get a match. Stop when the 1st search character is the start of the text being searched. return whatever return value you want on match or no match, I usually use 0 for no match or the offset from the front for a match.
RE: The PROLOGUE and EPILOGUE notation, it is mainly used to turn the automatic stack frame off so if you are writing a leaf procedure (one that does not call other procedures) you reduce the stack overhead by writing it with no stack frame. You can do it even faster by using a register to pass the values, its a roll your own version of FASTCALL where you can pass data in EAX, ECX and EDX and return up to 3 values in the same three registers.
My real code, that solving this problem looks, like this :
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
strlen PROC FUNC_IMP_ASM, ; USES preserve,
string : POINTER
ifdef HUTCHSTRLEN
ifidni FUNC_IMP_ASM, <FASTCALL>
mov eax, ecx ; get pointer to string
else
mov eax, [esp + 4] ; get pointer to string
endif
...
But problem is really conceptual, as best way to strip when no need prologue and epilogue, that's automatically by assembler, but that is to JWasm authors request ...
First : Reply to Hutch.
I have wrote my own but Jochen code is very efficient, for this reason I told him to think to me.
You are right for passing the parameters, I continue using standard prologue and epilogue, but if I can write a function which takes its parameters throught the registers, I define the function as a label.
Adamanteus, you are a fox. It's a good idea.
Philippe,
Here is a small demo of FASTCALL versus inlined code The second is faster again than a FASTCALL. The algo is a tiny and not that fast byte scanner for a string length but it is trivial, it only demos the technique difference.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
; *****************************
lost MACRO ; length of string
mov ecx, eax
sub eax, 1
lbl:
add eax, 1
cmp BYTE PTR [eax], 0
jne lbl
sub eax, ecx
ENDM
; *****************************
.data
item db "12345678901234567890",0
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
mov eax, OFFSET item
call sln ; call procedure
print str$(eax),13,10
mov eax, OFFSET item
lost ; run inline macro
print str$(eax),13,10
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
sln proc
mov ecx, eax
sub eax, 1
lbl:
add eax, 1
cmp BYTE PTR [eax], 0
jne lbl
sub eax, ecx
ret
sln endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Thank you Hutch
The difference is the time for calling the proc.
I would like to answer you if rather having many local variables we define a structure for accessing these variable, is it good ?
An other thing, if I do a PUSHF, what becomes the flags affected by instructions before I do the POPF?
Would it be better to do :
PUSHF
Instruction 1
Instruction 2
POPF
OR
PUSHF
Instruction 1
.
.
.
Instruction <n>
POPF
When I was programming under MSDOS with the famous INT 21h, the STC instruction was called to signal an error. Why this his not the same now on Windows?
I don't speak to you very often, but now I made it for a year!
Here is a better version with simple timing.
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
include \masm32\include\masm32rt.inc
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
comment * -----------------------------------------------------
Build this template with
"CONSOLE ASSEMBLE AND LINK"
----------------------------------------------------- *
; *****************************
lost MACRO ; length of string
LOCAL lbl
mov ecx, eax
sub eax, 1
lbl:
add eax, 1
cmp BYTE PTR [eax], 0
jne lbl
sub eax, ecx
ENDM
; *****************************
.data
item db "12345678901234567890",0
.code
start:
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
call main
inkey
exit
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
main proc
LOCAL tc :DWORD
push ebx
push esi
push edi
mov eax, OFFSET item
call sln ; call procedure
print str$(eax)," correct test",13,10
mov eax, OFFSET item
lost ; run inline macro
print str$(eax)," correct test",13,10
; --------------------------------
mov esi, 100000000
fn GetTickCount
push eax
lbl1:
mov eax, OFFSET item
call sln ; call procedure
; print str$(eax),13,10
sub esi, 1
jnz lbl1
fn GetTickCount
pop ecx
sub eax, ecx
print str$(eax)," ms FASTPROC",13,10
; --------------------------------
mov esi, 100000000
fn GetTickCount
push eax
lbl2:
mov eax, OFFSET item
lost
; print str$(eax),13,10
sub esi, 1
jnz lbl2
fn GetTickCount
pop ecx
sub eax, ecx
print str$(eax)," ms INLINE CODE",13,10
; --------------------------------
pop edi
pop esi
pop ebx
ret
main endp
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
sln proc
mov ecx, eax
sub eax, 1
lbl:
add eax, 1
cmp BYTE PTR [eax], 0
jne lbl
sub eax, ecx
ret
sln endp
OPTION PROLOGUE:PrologueDef
OPTION EPILOGUE:EpilogueDef
; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
end start
Using a structure is a tidy and convenient technique but its still memory operands which are slower than registers. On a longer procedure its fine but on very short procedures you are just adding extra memory operands which slow it down.
There is yet another technique from the Win3 16 bit days when you had very little stack space. Allocate a set of GLOBAL variables of the right size and pass values in the globals. Again it can only be used safely with leaf procedures but it lives somewhere between the speed of inlined code and a no stack frame procedure.
Quote from: hutch-- on January 09, 2016, 04:06:18 AMpass values in the globals. Again it can only be used safely with leaf procedures
Why unsafe?
I use a hybrid: SetGlobals (http://www.webalice.it/jj2006/MasmBasicQuickReference.htm#Mb1015) uses the LOCAL somevar:DWORD syntax, but mov eax, somevar is mov eax, [ebx+n] under the hood, where n is -128...+128 (and more). Speed-wise as fast as global variables, but shorter encoding.
You make your heap manager
:biggrin:
Well, there is safe and there is SAFE, try a recursive quick sort that iterated hundreds of thousands of calls deep and you will understand why fixed globals are not the solution. You can have many more fixed globals than registers and they are slightly slower than true FASTCALL but not by much.
I am OK with you Hutch. It is like trying to program a recursive application in FORTRAN.