Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29248 Discussions

Using undefineable constant in called function...

pchidamb
Beginner
946 Views
Hi

Please look at this sample snippet:

PROGRAM TEST
real *4 A,B,C
call newsub1(10,20,c)
write (*,'(3e12.5)') A,B,C
stop
end

subroutine newsub1(a,b,c)
real*8 a,b,c
intent(in) :: a,b
intent(out) :: c
c = a+b
return
end

I did the followingexercise to understand the behavior of undefineable constant in the subroutine.
Infact, this program will give compile error with /gen-interface option. I suppressed this to check the
behavior of the constants inside the subroutine. Nothing gets copied in temporary storage and hence
the value of 'c' is garbage. Also the behavior is not altered by the keyword INTENT.
Please throw some light!

Thanks
Praba

0 Kudos
6 Replies
Steven_L_Intel1
Employee
946 Views
So you have a VERY incorrect program and wonder why the results are not understandable?

Here's what happens.

The main program passes the addresses of two integer constants and a REAL*4 variable. The subroutine thinks that the integer constants are REAL*8 and fetches the 8 bytes at the locations of the constants, treating the found bytes as REAL*8. This yields some very different and not necessarily predictable REAL*8 value. Not predictable because you don't know what follows the integer value in memory.

These garbage values are then added and stored in C. But in the subroutine, C is REAL*8 so the value stored is 8 bytes, overwriting C and whatever followed it. This value is not valid as a REAL*4 because of the different exponent width.

INTENT has nothing to do with this, and I don't see what "undefinable constants" has to do with it either as you don't store to the constants. If you did, you'd probably get an asccess violation. There is an option, /assume:noprotect_constants, that will cause a writable copy of the constants to be passed.
0 Kudos
mecej4
Honored Contributor III
946 Views
Unless you have considerable experience with the compiler used, it is improper to rely upon (in your case, unfounded) expectations of what the compiler will produce when given incorrect code. Furthermore, what the compiler does can often be explained only at the machine instruction level.

> Nothing gets copied in temporary storage and hence the value of 'c' is garbage.

The first part of this sentence, be it correct or not, does not lead to the second part.

Produce the assembly listing using the /Fa compiler option to see what the compiler does. Note that other compiler options can affect the behavior of buggy code, so you should not presume that the same kind of errors in code will always produce the same buggy behavior in the EXE.
0 Kudos
pchidamb
Beginner
946 Views
Thanks Steve!
I am able to see the contents copied into the subroutine args for newsub1 & newsub2.
I followed the old style in newsub3 which does not work. Please explain!

PROGRAM TEST

REAL*8 c8

REAL*4 c4

integer *4 ic

call newsub1(10,20,ic)

call newsub2(10.0,20.0,c4)

call newsub3(10.0d0,20.0d0,c8)

stop

end

c

subroutine newsub1(ia,ib,ic)

integer*4 ia, ib, ic

ic = ia+ib

return

end

subroutine newsub2(a,b,c)

real*4 a,b,c

c = a+b

return

end

subroutine newsub3(a,b,c)

real*8 a,b,c

c = a+b

return

end

0 Kudos
Steven_L_Intel1
Employee
946 Views
What "doesn't work" and how do you know? What does this program have to do with "undefinable constant"?

I compiled this without optimization (otherwise the whole program would have been evaporated) and looked at the assembly code. The code that calls each of the routines operates exactly the same way.

[plain].B1.2:                          ; Preds .B1.9
        add       esp, -12                                      ;9.6
        mov       DWORD PTR [esp], OFFSET FLAT: __NLITPACK_1    ;9.6
        mov       DWORD PTR [4+esp], OFFSET FLAT: __NLITPACK_2  ;9.6
        lea       eax, DWORD PTR [-16+ebp]                      ;9.6
        mov       DWORD PTR [8+esp], eax                        ;9.6
        call      _NEWSUB1                                      ;9.6
                                ; LOE
.B1.10:                         ; Preds .B1.2
        add       esp, 12                                       ;9.6
                                ; LOE
.B1.3:                          ; Preds .B1.10
        add       esp, -12                                      ;11.6
        mov       DWORD PTR [esp], OFFSET FLAT: __NLITPACK_3    ;11.6
        mov       DWORD PTR [4+esp], OFFSET FLAT: __NLITPACK_4  ;11.6
        lea       eax, DWORD PTR [-12+ebp]                      ;11.6
        mov       DWORD PTR [8+esp], eax                        ;11.6
        call      _NEWSUB2                                      ;11.6
                                ; LOE
.B1.11:                         ; Preds .B1.3
        add       esp, 12                                       ;11.6
                                ; LOE
.B1.4:                          ; Preds .B1.11
        add       esp, -12                                      ;13.6
        mov       DWORD PTR [esp], OFFSET FLAT: __NLITPACK_5    ;13.6
        mov       DWORD PTR [4+esp], OFFSET FLAT: __NLITPACK_6  ;13.6
        lea       eax, DWORD PTR [-8+ebp]                       ;13.6
        mov       DWORD PTR [8+esp], eax                        ;13.6
        call      _NEWSUB3                                      ;13.6[/plain]
Each one creates space on the stack for the argument list of addresses, moves the addresses of the arguments to the respective locations, and calls the routines. In the case of the constants, the addresses are of "materialized literals" in static memory locations.

What is it that concerns you? What are you trying to show?

Lastly, if you want to paste code, please use the code insertion tool (yellow pencil icon) to preserve formatting.
0 Kudos
mecej4
Honored Contributor III
946 Views
> I followed the old style in newsub3 which does not work. Please explain!

What do you mean by "old style"? What do you mean by "does not work"? Your program does not do any output. Therefore, you need to do some explaining first. What is it that you expect, in the context of which "does not work" makes some sense?

You need to report the compiler version and options used to compile.

Add this before the STOP statement:

write(*,*)ic,c4,c8

Compile, link and run the program again and see what you get.
0 Kudos
pchidamb
Beginner
946 Views
[bash]Here is the little background about my problem....

I was porting some legacy code. The results are different with intel compiler and pgf77 in Linux.
When I trace back, I realize that the arguments (some are constants) are being treated differently in pg compiler.
Hence I am doing memory debug to see the argument transfer with intel debugger. I created the above sample program for discussion.

I am able to see 
(1) integer values 10 & 20  in Memory debugger for newsub1.
(2) real*4 values (10.0 & 20.0) are communicated for a & b in debugger.
(3) real*8 values (0.0 & 0.0) are communicated for a & b in debugger.

Legacy code writers use DEXP(), DSQRT(), 1.0d0 etc for double precision.
Hence I used 
"call newsub3(10.0d0,20.0d0,c8)".
But inside the function newsub3, the debugger shows the values for 'a' & 'b' as '0.0' & '0.0'.
If I use variables as arguments, I can ensure the type consistency between the caller and called function.
If I have constants (though I do not redefine them inside the function), I did not get the correct data type
in the called function.

I looked into my compile option...
/nologo /debug:full /Od /fpp /I"C:Program FilesIntelCompiler11.0�72fortranmklinclude" 
/I"C:Program FilesVNIimslfnl600IA32includeDLL" 
/I"C:Program FilesVNIimslfnl600IA32includeSTATIC" 
/double_size:128 /module:"Debug\" /object:"Debug\" 
/traceback /check:bounds /check:arg_temp_created /libs:static /threads /dbglibs /c

After removing  "/double_size:128", I am able to get proper data type transfer ...
It is my bad!
Thanks for your time!

  [/bash]
0 Kudos
Reply