Schauble@MIT-MULTICS.ARPA (Paul Schauble) (01/02/87)
I have some fortran programs taken from a VAX to convert. These make use of null arguments in CALL statements, for example, CALL SUBR (A,,B) I understand that this produces a word of zeros in the generated argument list. What I don't understand is what this feature is used for. As I recall, page 0 of the process address space does not exist, so that references to small addresses produce some variety of memory protection fault. This would seem to be the fate of a fortran subroutine that attempts to use a null argument. Is there a language extension that would let it tell? Am I correct then in assuming that this feature requires that the routine being called must be written in another language and must be expecting use of this convention? Paul <Schauble at MIT-Multics.arpa>
stew%lhasa@HUCSC.HARVARD.EDU.UUCP (01/02/87)
The subroutine with the null argument can check for that by comparing %ADDR(X) to zero. Generally, this form is only used in calling system services which take optional arguments. Needless to say, the %ADDR feature makes you VMS dependant. Stew
Schauble@MIT-MULTICS.ARPA.UUCP (01/05/87)
My previous question about null arguments produced two replies to the effect that, yes, the subroutine can be written in Fortran. They proposed something like CALL SUBB(X,,Y) subroutine subb(a,b,c) ... v = default if (%loc(b).ne.0) v = b Assume that this is the only reference to b in the subroutine. This looks good except for one small problem. Several compilers that I have dealt with that use a similar linkage convention will generate a preamble that will move read-only formal parameters into the subroutine's local data space. Further references can be done faster than the indirect reference usually needed for a parameter. I know that VMS Fortran has a very good optimizer. Does it really not do this optimization? And does the above really work? Thanks, Paul <Schauble at MIT-Multics>
LEICHTER-JERRY@YALE.ARPA.UUCP (01/05/87)
My previous question about null arguments produced two replies to the
effect that, yes, the subroutine can be written in Fortran. They
proposed something like
CALL SUBB(X,,Y)
subroutine subb(a,b,c)
...
v = default
if (%loc(b).ne.0) v = b
Assume that this is the only reference to b in the subroutine.
This looks good except for one small problem. Several compilers that I
have dealt with that use a similar linkage convention will generate a
preamble that will move read-only formal parameters into the
subroutine's local data space. Further references can be done faster
than the indirect reference usually needed for a parameter.
I know that VMS Fortran has a very good optimizer. Does it really not do
this optimization? And does the above really work?
The VAX has a flat address space, so the notion of "the subroutine's local
data space" makes little sense - stuff is equally accessible whereever in
memory it happens to be. The VAX addressing modes allow for a double
indirection (if you are not trying to do much else with the address at the
same time), so you would save a single memory access, rather than a whole
instruction - not often worth it.
What DOES make sense - and IS done by the compiler - is placing heavily-used
objects in registers. If b is used, and will itself fit in a register, it may
very well get loaded into one. If b is a large object - for example, and
array - it can't be loaded into a register, but its address (i.e., the address
of b(0)) can be.
Usually, there is no advantage to putting a quantity in a register before it
is used. In fact, that just ties up a register that could be used for some-
thing else. Also, %loc(b) is a reference to b's address, not to b, so cannot
use a register copy of b anyway. (It COULD use a register copy of b's address,
but it is safe to load that.)
In the example you give, it is highly unlikely that any optimizer would choose
to put b in a register (or even copy it) - with only a single reference to b
itself, it costs more to load up the register than can be saved by having b
available there. So you are PROBABLY safe. However, without specific
indications in the documentation indicating that this is, indeed, supported,
be aware that you are taking SOME risk; it just could break in a later version
of the compiler.
Personally, in most situations, if I really needed this feature I'd make sure
the current compiler accepted it, then go ahead and use it - recognizing that
I MIGHT get burned. (I use optional arguments in C code all the time, but
because C uses call by value rather than call by reference, the problems
discussed here can't arise.)
I don't think I've ever used embedded optional arguments, though - just
optional TRAILING arguments. Functions decide whether they are there by
checking how many arguments they were called with - a 3-line or so MACRO
program returns that information. (There is a related problem here with
functions ALL of whose arguments are optional - if you don't provide at least
one formal, or if you provide one but then never use it, the C compiler will
go ahead and use the AP as a work register. Since you need to AP to find the
arguments, this will cause problems! So its important to provide a formal and
keep it "live" until you have a chance to pick up and save AP - another tiny
MACRO program. I do this by writing such functions with a single formal, then
calling the MACRO program with the formal as an argument. The MACRO program
never looks at its arguments, but this keeps the optimizer at bay.)
-- Jerry
For the curious:
------------------------Extract from SUPPORT.MAR------------------------------
.TITLE SUPPORT - Simple support routines
.IDENT 'V01-000'
; EDITLEVEL=27
.PSECT SUPPORT_CODE,CON,EXE,GBL,PIC,SHR,RD,REL,NOWRT
.SUBTITLE Get number of arguments
;
; int
; nargs()
;
; Return to caller the number of arguments he was called with. Only correct
; when all the arguments are actually longwords (e.g., not C double's, or
; struct's by value).
.ENTRY nargs,^M<>
MOVZBL @8(FP),R0 ;R0 <- count
RET ;Easy enough
.SUBTITLE Get argument list
;
; ARGLIST *
; arglist()
;
; Return a pointer to the caller's argument list.
;
; Note that the VAX C compiler will use AP as a working register in a function
; that has no arguments. (It could presumably also do so after all declared
; arguments become dead.) Calling arglist() would then produce, at best,
; meaningless results. If no fixed parameters are needed, use arglist() as
; follows:
;
; f(dummy)
; int dummy; /* Type irrelevant */
; { ...
; alist = arglist(dummy);
; ...
; }
.ENTRY arglist,^M<>
MOVL 8(FP),R0 ;R0 <- Caller's AP
RET ;Easy enough
---------------------------Extract from VMS.H---------------------------------
/*
* Fundamental datatypes
*/
typedef int INT_32;
typedef short INT_16;
typedef char INT_8;
typedef char *ADDR;
typedef char BYTE;
typedef short WORD;
typedef int LONG;
typedef unsigned char UBYTE;
typedef unsigned short UWORD;
typedef unsigned int ULONG;
typedef BYTE QUADWORD[8];
typedef BYTE OCTAWORD[16];
typedef struct arglist /* Argument list */
{ UBYTE count;
BYTE mbz[3];
LONG args[];
} ARGLIST;
-------