Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.pascal.misc > #2652

Live register analysis

From Robert Prins <robert@nospicedham.prino.org>
Newsgroups comp.lang.asm.x86, comp.lang.pascal.misc
Subject Live register analysis
Date 2020-06-02 14:10 +0000
Organization A noiseless patient Spider
Message-ID <rb5fk5$fsl$1@dont-email.me> (permalink)

Cross-posted to 2 groups.

Show all headers | View raw


Hi all,

I've got a few "Pasembler" programs to process my hitchhike data. They 
originated way back in the late 1980'ies (although the oldest saved set dates 
back to "only" 3 June 1994) and were originally written in Turbo Pascal 3.01a. 
In 1996 (at version 55) they started using and external file with 386 code, and 
eventually, on 5 August 1996, version 59 became the last version using TP 3.01a, 
with not just the external code, but even going as far as using the built-in 
option to embed assembler code (as bytes, ouch), even jumping back-and-forth 
across Pascal parts.

Needlessly to say, the first TP 6.00 version (dated 2 September 1996) did not 
like the TP 3.01a code, and I had to revert to pure Pascal again, but in the 
years that followed, more and more inline assembler "crept" in, this time using 
the built-in assembler(*), making life rather a lot easier. I also kept a 
separate pure Pascal version!

Which was pretty useful, when, in 2008, I had to abandon TP 6.00 (BP 7.01 would 
have allowed me to continue using, using DPMI, Borland tools) due to the volume 
of data exceeding the memory limitations of plain DOS, even having added a unit 
to extend the TP heap into the UMBs.

I had two options at that moment, FreePascal, or Virtual Pascal, and when the 
former refused to compile the pure Pascal sources (and now 12 years later it 
***still does not honour one particular Borland feature***), I went for Virtual 
Pascal. The first pure Pascal version compiled with only very minor changes, and 
even most of the in-line assembler didn't actually require too much effort to 
convert it to 386-ese, and right now most of the code has been converted to full 
in-line assembler, with some of it harking back to TP 3.01a times, i.e. coding 
post-Pentium (the final CPU supported by VPs built-in assembler), all the way 
AVX instructions as "db $xx,$yy,$zz..." sequences, generated by 
<https://defuse.ca/online-x86-assembler.htm>. In essence, nowadays I only use 
the compiler to generate an initial assembler listing, and then start playing 
with it, and in most cases the end result no longer bears much resemblance to 
the original code... (VP generates code that's not much better than what TP6/BP7 
generated or, for that matter, what FPC generates)

Initially I would follow the VP documentation, i,e, save EBX, ESI, and EDI, 
where the compiler saved them, but eventually I realized that this wasn't 
required in a lot of cases (certainly not for most, if not all, procedures 
called from the top level) and so most/all of those now freely use these three 
registers and in at least one case I can think of, I'm not passing "ebx" as a 
parameter to another lower-level procedure, but just using it in that one.

However, going to deeper levels, what to save? Eventually, this weekend, I 
wrote, more-or-less on-the-fly, but almost working at the first attempt, two 
little REXX execs to give give me some more insight into what's happening. The 
execs are free for the asking, but they rely a little bit on my directory 
structure and coding style, I close every Pascal procedure and function with an 
"end; {name-of-proc/func}" statement. (Having used PL/I for 35 years, where 
there's now an option to actually flag procedures that aren't terminated by a 
"end procedure-name;" statement)

The first (just short of 300 lines, including comments and blank lines) REXX 
exec reads all the source files (currently 115 files, just short of 80,000 
lines), goes through all procedures, and produces a neat listing that tells me 
which registers are saved upon entry to each (via a VP "{&uses ...}" directive), 
and which are actually used, which for many level-1 procedures results in "none" 
and "ebx,esi,edi,eax,ecx,edx" ;) (And no, I'm not (yet) scanning for partial 
(xH/L) registers, separating R/O from WRITE, or looking at MMX, FPU or AVX 
registers!) (It does all this in about three seconds...)

The other REXX exec (nearly 400 lines of code, whitespace and comments) adds a 
bit of code (easily removable via "SED") to the existing code to give me a 
calling tree, and actually, in a separate directory, compiles and runs 
everything to give me a count of the usage of all procedures. (Here all REXX 
processing, including compiling and running the programs takes sadly a bit 
longer, a total of about six seconds..)

A manual recompile with a define of "lvl" will produce a full call-tree (> 50Mb 
in the current format, 2.7 million lines), which shows that the procedures are 
nested up to 9 levels below the main program. Combining this file with the 
use-of-registers data (and aligning the latter vertically) would blow it up to 
about something I don't really want to think of (150+ Mb), which leads me to the 
actual question,

Is there any better way of doing a such a use-of-register analysis like this?

Thanks,

Robert

(*) I even had my own versions of TP 6/BP 7 with a modified assembler opcode 
hash-table that allowed me to directly include a selected number of post-286 
instructions. ;)
-- 
Robert AH Prins
robert(a)prino(d)org
The hitchhiking grandfather - https://prino.neocities.org/indez.html
Some REXX code for use on z/OS - https://prino.neocities.org/zOS/zOS-Tools.html

Back to comp.lang.pascal.misc | Previous | Next | Find similar


Thread

Live register analysis Robert Prins <robert@nospicedham.prino.org> - 2020-06-02 14:10 +0000

csiph-web