Compiler version: 12.2017
MEMCPY and MEMSET were introduced in 2016 as new standard procedures to support block moves and block initializations in the same way as C does it. The arguments are the same as in their C counterparts. Because we have the ADDR function, too, which supports getting the address of every variable (and SIZEOF to get the size of every variable or type), MEMCPY and MEMSET are very easy to use. Of course, there are some security problems, when using these procedures, and they have to be used with care.
The initial versions of MEMCPY and MEMSET were implemented using the library call facility of Stanford Pascal, that is: the compiler generates calls to an external Pascal procedure which implements the standard function (in this case, the external procedure was located in PASLIBX.PAS). This was a bit costly, because the procedure prologue has to be executed on every MEMCPY and MEMSET call.
What made things worse: MEMCPY and MEMSET were implemented using Pascal loops, which in fact moved one character at a time. This was, of course, the easiest way to do it, and for a proof of concept it was sufficient, but not for production work.
This is the library function that implemented MEMCPY and MEMSET, BTW; at least the PTR2INT and PRTADD function calls are implemented by inline code (simple P-Code instuctions). If they were true function calls, performance would be a real nightmare.
|
It was clear to me from the start that I would have to find a better solution later.
With the 12.2017 compiler release, I introduced some new P-Code instructions to support inline translation of MEMCPY and MEMSET:
MCP - for MEMCPY, if length is variable (MOV is sufficient for MEMCPY, if length is fixed)
MSE - for MEMSET, if length is variable (MFI is sufficient
for MEMSET, if length is fixed;
MFI was introduced recently to support pre-formatting
of longer target strings, when assigning shorter strings)
MZE - special case for MEMSET, if length is fixed and
init pattern is zero
(some platforms have special
instructions for this case, for example XC on the
mainframe)
For a detailed description of the new P-Code instructions, you may look at the new P-Code documentain (2017 update):
P-Code Description - 2017 release
On the mainframe, the P-Code translator PASCAL2.PAS generates MVCs for P-Codes MOV and MFI, if the length is less or equal to 256, and MVCLs otherwise. For variable length transfers (like MSE and MCP), MVCL is generated. MZE generates XC, if the length is less or equal to 256.
Example: some lines of a test program containing MEMSET and MEMCPY (variable lengths); the numbers on the left are the line numbers of the source.
|
This is the P-Code that the compiler generated:
|
and here you can see the 370 instructions that PASCAL2 generates from this P-Code (Pseudo ASSEMBLER):
|
The P-Code interpreter PCINT also runs much better with the new P-Codes, of course. Without them, procedure calls MEMSET and MEMCPY had to be done by running (interpreting) the Pascal loops in PASLIBX.PAS (see above). Now the new P-Codes are interpreted directly by PCINT (that is, it uses C function calls memset and memcpy to interpret them, which are often implemented by block moves using native code instructions). This should make a big difference.