News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Weird MACRO behavior...

Started by rrr314159, February 18, 2015, 04:00:13 PM

Previous topic - Next topic

rrr314159

This macro does what I want it to do: echo "xmm5".
include \masm32\include\masm32rt.inc
;*******************************
weird MACRO numxmm
;*******************************
LOCAL xmmtxt, thexmm;  , ts$    ; doesn't work if ts$ is local
    xmmtxt equ <xmm>             ; actually this could take other values like <ymm>
    ts$ textequ %numxmm           ; equ doesn't work here
%    thexmm equ xmmtxt&&ts$        ; textequ doesn't work here
%    echo thexmm
ENDM
;*******************************
.code
five = 5

start:

weird five                                  ; use macro with variable numeric symbol

ret
end start


I found two weird behaviors while getting it to work, both indicated in the comments. Note, this is for 32-bits but the same things happens with 64-bits, both ML and JWasm.

First, you must use textequ, not equ, in the indicated line; and vice versa on the next line. I had thought there was no difference, but since qWord always uses textequ in such situations, so do I. But this is the first time I actually noticed a difference. Not 2 important ...

Second - and this seems really weird - it doesn't work if ts$ is LOCAL?!? I can live with that, but it's annoying. Does anyone know why, and how to make it work with a LOCAL ts$?

Right now, if I decide it needs to be local, my plan is to sacrifice my black cat under the next full moon, while muttering: "macro, local, ts$, please Lord Gates" over and over ... ;)

[edit] Modified it a little to clarify why the macro is written as it is. If you know a better way to accomplish this I'd be interested, but my main q is not about the functionality but: what are the rules governing the use of local and equ vs. textequ? Both of these weird behaviors contradict the spec (AFAIK) and, also, common sense.
I am NaN ;)

hutch--

You will have to be careful appealing to such dark spirits, Steve Jobs may answer you.  :P

jj2007

It is weird indeed. If you are mainly interested in the functionality - these two work:

% echo @CatStr(<xmm>, <numxmm>)
    echo xmm&numxmm

dedndave

speaking of ECHO....

i was wondering if @CatStr is really needed ?

%ECHO MAPDIB_WIDTH = @CatStr(%(MAPDIB_WIDTH))

rrr314159

Well, this is a manufactured snippet to show the weird behavior. In fact xmmtxt needs to be a variable (sometimes it will be ymm) and, I need to assign the "xmm5" result to the symbol "thexmm", not just echo it. Still I didn't realize your second suggestion worked: I can use something similar to "thexmm equ xmm&numxmm" in other situations instead of the awkward ts$ formulation, so, thanks. But neither it nor @CatStr work with a variable - AFAIK - altho I bet there's a way to do it. The characteristic problem is that it echoes "??00001" (e.g.) instead of xmm5.

Apart from that, I've noticed weird things happen with "local" elsewhere and would really like to know what's going on with that.

Finally, I'd like to understand equ vs. textequ better. BTW in the line "thexmm equ xmmtxt&&ts$" u can't substitute textequ - so they're definitely different, but documentation seems to say they're the same (when used with text).

My cat's nervous - she hopes I'll get it straight b4 the next full moon!  :lol:

[edit] realized why I have to use ts$: want to say "weird five" also, where "five = 5". The simpler form then gives "xmmfive". So, my snippet was oversimplified. Anyway, the main point is, what's up with local and equ vs. textequ? If no one knows, no problem, it's not life-or-death - except for the cat
I am NaN ;)

jj2007

#5
Quote from: rrr314159 on February 18, 2015, 08:57:31 PMBut neither it nor @CatStr work with a variable - AFAIK - altho I bet there's a way to do it.

I doubt that you can have an assembly time decision which regxmm to use based on a run-time variable. In such cases, I use a jump table. Here is an example from my numbertotext algo:
lea eax, [MovXmmStr+4*edx-80]
lea edx, f2sTmp64
call eax
...

MovXmmStr:
movlps qword ptr [edx], xmm0 ; 4 bytes incl. ret
retn
movlps qword ptr [edx], xmm1
retn
movlps qword ptr [edx], xmm2
retn
movlps qword ptr [edx], xmm3
retn
movlps qword ptr [edx], xmm4
retn
movlps qword ptr [edx], xmm5
retn
movlps qword ptr [edx], xmm6
retn
movlps qword ptr [edx], xmm7
retn


Of course, I'd be glad if somebody finds a shorter solution :P

P.S.: If you really insist...
include \masm32\MasmBasic\MasmBasic.inc
include movlpsN.inc

.data?
MyDest REAL8 ?

  Init
  movlps xmm3, FP8(12345678.33333333)
  mov ecx, 3
  movlpsN MyDest, ecx
  Print Str$("MyDest=%Gf\n", MyDest)
  movlps xmm7, FP8(12345678.77777777)
  movlpsN MyDest, 7
  Print Str$("MyDest=%Gf\n", MyDest)
  Exit
end start


Output:
MyDest=12345678.33333333
MyDest=12345678.77777777

;)

rrr314159

Thanks for revealing the Dark Secrets of MASMBasic ;) Jump Table seems the best way to accomplish run-time determination of xmm register; doubt there's anything better; not quite sure what's going on with MyDest, looks worth studying.

But of course I'm not referring to a run-time variable, rather compile-time variable symbol. I edited the original example to clarify this, I hope. (This is THE problem with short posts, they get misunderstood)

If there's a better way to do what "weird" macro does, I'd like to know, but that's not the point really; it works, good enuff. What I want to know is the rules governing local and equ vs. textequ. In other words, if there were a good MASM spec for these behaviors (which evidently there isn't) what would it say?

BTW I realized the obvious, perhaps only, way to satisfy my curiosity: read JWasm source; all the answers are in there.
I am NaN ;)

jj2007

Quote from: rrr314159 on February 19, 2015, 02:37:01 AMThanks for revealing the Dark Secrets of MASMBasic ;) Jump Table seems the best way to accomplish run-time determination of xmm register; doubt there's anything better; not quite sure what's going on with MyDest, looks worth studying.

The movlpsN macro attached above pushes two instructions on the cache and executes them there. It works but...:
Intel(R) Core(TM) i5-2450M CPU @ 2.50GHz (SSE4)
153     cycles for 100 * movlps
194676  cycles for 100 * call esp
1588    cycles for 100 * jump table

162     cycles for 100 * movlps
191477  cycles for 100 * call esp
1594    cycles for 100 * jump table

154     cycles for 100 * movlps
200407  cycles for 100 * call esp
1686    cycles for 100 * jump table

47      bytes for movlps
131     bytes for call esp
91      bytes for jump table


It seems there is a massive caching problem. Source & exe attached, curious how it performs on AMD.

sinsi

Quote from: jj2007 on February 19, 2015, 06:37:29 AMcurious how it performs on AMD.
It doesn't

AMD A10-7850K APU with Radeon(TM) R7 Graphics   (SSE4)

398     cycles for 100 * movlps
385014  cycles for 100 * call esp
1808    cycles for 100 * jump table

402     cycles for 100 * movlps
379945  cycles for 100 * call esp
1897    cycles for 100 * jump table

413     cycles for 100 * movlps
381635  cycles for 100 * call esp
1836    cycles for 100 * jump table

🍺🍺🍺

qWord

future-proof ⇒ DEP aware
call esp ⇒ not DEP aware
:icon_confused:

Quote from: rrr314159 on February 18, 2015, 04:00:13 PMit doesn't work if ts$ is LOCAL?!?
Local symbols are replaced like macro arguments and thus "eat" some of the ampersands before the intended substitution takes place. Adding just one more Ampersand to the LOCAL-only variant should work.

MREAL macros - when you need floating point arithmetic while assembling!

rrr314159

I am NaN ;)

jj2007

Quote from: qWord on February 19, 2015, 11:22:50 AM
future-proof ⇒ DEP aware
call esp ⇒ not DEP aware
:icon_confused:

Of course. It was just a demo for self-modifying code on the stack. As demonstrated, it is incredibly slow.

@sinsi: thanks :icon14:

jj2007

I'll hijack this thread for another weird macro behaviour:

include \masm32\include\masm32rt.inc

bla$ MACRO arg:=<>
LOCAL c$, P$
  P$ equ <arg>
  forc c$, <arg>
% echo [c$] ; this should be a single character, right?
  ENDM
  exitm <>
endm

.code
start:
% echo bla$(noob)
o equ surprise
% echo bla$(noob)
exit
.err
end start


If there is an elegant way to suppress this 'feature', let me know please.

rrr314159

You want it to echo s, u, r ..., each letter of "surprise" individually, right? AFAIK the only way is to add an extra loop:
bla$ MACRO arg:=<>
LOCAL c$, P$
  P$ equ <%arg>
  forc c$, <arg>
%    forc d$, <c$>
% echo [d$] ; now it is a single character
    ENDM
  ENDM
  exitm <>
endm


... which I would hardly call "elegant". One expects just an extra % or & in the right place should do it; wait for qWord to respond, then we'll know if it can be done.

OTOH if you want to see the two o's and ignore the "surprise", just remove the % from the echo statement.

It's not such a bad idea to continue to post weird macro behavior in this thread, collect them all in one place. After a while it will be the longest thread on the forum ... after another while, the longest thread on the internet!  :biggrin:
I am NaN ;)

jj2007

Quote from: rrr314159 on February 26, 2015, 04:02:13 AM
You want it to echo s, u, r ..., each letter of "surprise" individually, right?

No, the issue is in a macro that translates Hi\nMasm into Hi, 13, 10, Masm - c-style escapes. Works fine unless somewhere before the letter n was defined as a variable, e.g. as [ebx]. So instead of "n" you get [ebx], which defeats the purpose. With c$ SUBSTR <arg>, pos, 1 you would expect one char, not some totally unrelated expanded string, right? Let's see if qWord comes up with a solution - after all, the cStyle$ macro is his baby :P