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.
You will have to be careful appealing to such dark spirits, Steve Jobs may answer you. :P
It is weird indeed. If you are mainly interested in the functionality - these two work:
% echo @CatStr(<xmm>, <numxmm>)
echo xmm&numxmm
speaking of ECHO....
i was wondering if @CatStr is really needed ?
%ECHO MAPDIB_WIDTH = @CatStr(%(MAPDIB_WIDTH))
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
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
;)
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.
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.
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
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.
Thanks qWord !! :t
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:
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.
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:
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 (http://www.masmforum.com/board/index.php?topic=12460.msg96506#msg96506) :P
i think a C-style "\n" is chr$(10) :P
ok - according to the wiki page, "ms dos/windows \n" is 13,10
but, for MessageBox, all you need is the 10 :t
\n means "newline". On different systems, even different progs on same system, it can mean different chars; sometimes both 13 and 10, sometimes just 10; could be something else if u weren't using ASCII. (Pretty sure) the official C def only specifies "newline". qWord, BTW, translates it to 10 and uses \R for 13. Messagebox, and various other places in Windows, just 10 is enuff for a newline, but I've seen it not work right (forget where) and require the 13 also.
Hey, if it was simple anyone could do it!
But the issue here is the macro behavior ... jj2007, thx for pointing it out, checked my prnt routine and I've got the same problem. If user equ's n (or t, etc) to ebx (or whatever) it doesn't work. Need to suppress the macro expansion for the print escape codes ... clumsy way to do it: remember what n is equ'd to, re-equ it to n, then put it back at the end of the print routine. But, doesn't work if the user goes n equ 3 (a number). Then it's a "permanent constant" and u get error if try to re-define it. And, what if he really wants n to stand for (say) t: wants it to mean tab?
Hmmm ... perhaps the right approach is to take a nice nap, then see what's on the tube ...
Seems no sensible way to suppress the macro expansion using SUBSTR. But FORC behaves as it should: gives one unexpanded character, u have to tell it to expand (with %).
Have a short story about this issue ... Microsoft "deprecates" FORC in the Programmer's Guide 6.1:
QuoteWith versions of MASM earlier than 6.0, FORC is often used for complex
parsing tasks. A long sentence can be examined character by character. Each
character is then either thrown away or pasted onto a token string, depending on
whether it is a separator character. The new predefined macro functions and
string processing directives discussed in the following section are usually more
efficient for these tasks.
The new functions, of course, are SUBSTR, INSTR etc. Now, when I was going thru MASM32 macros.asm a couple months ago, I found that cfm$ uses FORC (not sure, but I think it's written by MichaelW?). So (believing MS) I re-wrote it using SUBSTR. It's shorter, maybe more efficient, and definitely harder to understand (aka clever). Turns out it's no good: seems no way to eliminate this bug (n equ ebx). So, going back to the old cfm$ instead. Learning similar lessons going thru masm32/m32lib, which somehow I never noticed until couple days ago. I've re-invented many wheels, but often mine are square or hexagonal instead of round ;)
Two lessons to be learned from this:
"Never trust MicroSoft" - jj2007
"Computer software is like wine - the older the better." - iZ!
Quote from: rrr314159 on February 26, 2015, 07:22:34 AMclumsy way to do it: remember what n is equ'd to, re-equ it to n, then put it back at the end of the print routine.
Works like a charm for n. For reasons that only Bill Gates may know, it fails miserably for t :(
Re FORC, I swear I had tested that option, and it expanded just like SUBSTR. So I discarded it. Today I retested after reading your last post, and voilà it works! Will try again tomorrow - probably it works on Thursdays only. Mysteries of the 20th century :bgrin:
When people outside the Masm32 scene read this, they must surely think "dear oldies, why don't you go for a modern language?" ;-)
I don't think people outside the Masm scene read this, but the answer would be "my prog is smaller and faster than yours, that's why" ... let us know if u find another way to handle the problem, until then I'm assuming "older is better" and reverting to FORC
p.s. don't forget, C++ has its arcane mysteries also, some features work only when the moon is full
Quote from: rrr314159 on February 28, 2015, 11:50:48 AM
p.s. don't forget, C++ has its arcane mysteries also, some features work only when the moon is full
That's a bit exaggerated, I think. But you're right: C++ comes with a lot of overhead and is sometimes very tricky. An example: Try to establish an external assembly language procedure as a regular class member. That's real fun.
Gunther
that was the one part i actually understood :lol:
Dave,
Quote from: dedndave on March 03, 2015, 02:12:12 AM
that was the one part i actually understood :lol:
that's very interesting. How did you manage the different name mangling and decoration schemes for different compilers? The extern C declaration won't work in that case. Or is it a joke?
Gunther
i don't use any C compilers (well, not very often)
but, i read about registering assemblies while reading about COM
it didn't seem that bad
haven't really had a need to do it :P
Dave,
Quote from: dedndave on March 03, 2015, 03:43:55 AM
i don't use any C compilers (well, not very often)
I see it was a joke. rrr314159 did talk about C++. In this case the name mangling for the external assembly language routine is only
one big hurdle. In C is that not necessary.
Gunther
Quote from: Gunther on March 02, 2015, 07:17:56 PMBut you're right: C++ comes with a lot of overhead
What?
Quote from: Gunther on March 02, 2015, 07:17:56 PMAn example: Try to establish an external assembly language procedure as a regular class member. That's real fun.
bad example, because that has nothing to do with the programming language C++.
Hi qWord,
Quote from: qWord on March 03, 2015, 05:28:19 AM
Quote from: Gunther on March 02, 2015, 07:17:56 PMBut you're right: C++ comes with a lot of overhead
What?
Only 2 simple examples:
- If you like it or not: The constructor and the destructor will run in any case. But that's sometimes not necessary (overhead).
- You have to pay a price for your fance overloading features: The complicated name mangling and decoration schemes, which are not standardized and different from compiler to compiler.
Quote from: qWord on March 03, 2015, 05:28:19 AM
bad example, because that has nothing to do with the programming language C++.
It has to do with the language and the name mangling. What helps me a HLL with a bad assembly language interface? Should that be modern design? I think not and we're discussing inside an assembly language board.
By the way qWord, fine to see you again after a break and no offense.
Greatings
Gunther
Quote from: Gunther on March 03, 2015, 08:54:42 PMThe constructor and the destructor will run in any case. But that's sometimes not necessary (overhead).
This example is to abstract for me...
Quote from: Gunther on March 03, 2015, 08:54:42 PM
You have to pay a price for your fance overloading features: The complicated name mangling and decoration schemes, which are not standardized and different from compiler to compiler.
When programming with c++ you must not mangle names, so no overhead.
Quote from: Gunther on March 03, 2015, 08:54:42 PMWhat helps me a HLL with a bad assembly language interface?
obviously nothing much :biggrin:
BTW, I'm curios: why did extern "C" does not work for your task?
regards
@Gunther, sorry I hadn't noticed you were responding to my post. Perhaps I should clarify my opinion.
First, I don't really think C++ has anything to do with the full moon. That's an old joke about mysterious technology that does what you want it to do only sporadically. In the Navy the enlisted men referred to computers (e.g. Combat Control System) as PFM - "Pure Friggin' Magic": same idea. I don't think C++ depends on phases of the moon, but can't be sure, since the latest rev C++11 is tl;dr. For all I know it may mention eyes of newt and cauls of newborns in there somewhere.
Which brings me to my complaint about C++. When I refer to bloat or overhead, I don't mean the build, but the spec. Modern C++ has feature bloat. You'll never win an argument with a C++ maven. You can incur overhead in various ways, but there's always a way to avoid it. In fact, for any problem anyone ever ran into, they added a new feature to get around it. The fix causes new problems, necessitating another feature in the next spec. (I can discuss examples if anyone cares).
It has another problem which I could call "abstraction addiction" - but that's another, more conceptually difficult, story. Briefly, I will say there's only one discipline that really knows how to handle abstraction: mathematics; because that's what math is. Computer languages, and physics, and everybody else, should be very leary of it and stick to their core competency: coding, experimentation, governing, teaching, whatever. But, I digress.
C++ is still, no doubt, the best alternative for some tasks; but that can't last forever. Something like Python will overtake it at the higher level, and (I hope) assembler will render it irrelevant at the lower level. It started out alright; in the late '80's it was good, in fact; but feature bloat (and over-abstraction) is ruining it. BTW this is just my "humble opinion", and as such I don't expect it can really be meaningfully debated. I felt obligated to explain my statements; take it for what it's worth.
Hi qWord,
thank you for your reply and please excuse the long delay. But I'm overwhelmed with work.
Quote from: qWord on March 04, 2015, 06:09:54 AM
BTW, I'm curios: why did extern "C" does not work for your task?
It's not my task. But if your external assembly language procedure
must be a class member, the extern "C" won't work. You must go another way for that.
Gunther