Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!decvax!ucbvax!YALE.ARPA!LEICHTER-JERRY From: LEICHTER-JERRY@YALE.ARPA.UUCP Newsgroups: mod.computers.vax Subject: Re: Null arguments in VMS Fortran Message-ID: <8701051538.AA09457@ucbvax.Berkeley.EDU> Date: Mon, 5-Jan-87 10:39:08 EST Article-I.D.: ucbvax.8701051538.AA09457 Posted: Mon Jan 5 10:39:08 1987 Date-Received: Mon, 5-Jan-87 19:15:31 EST Sender: daemon@ucbvax.BERKELEY.EDU Reply-To: Organization: The ARPA Internet Lines: 140 Approved: info-vax@sri-kl.arpa 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; -------