gfortran calling convention

The NIST F77 test suite doesn't seem to be compatible with gfortran at
all, so I had to work from my own sample codes, and generate test
cases from them.

Here's what works now, and I have a separate test case for each of these:

statement functions
intrinsic functions (print, cos, etc)
loops, goto statments
scalarized array operations
function calls with *no arguments*
simple common blocks

Function calls with more than one argument don't work. Specifically:

..../gfortran funccall-1arg.f -o funccall-1arg.exe
..../llvm/lib/VMCore/Instructions.cpp:209: failed assertion
`(Params.size() == FTy->getNumParams() || (FTy->isVarArg() &&
Params.size() > FTy->getNumParams())) && "Calling a function with bad
signature!"'
funccall-1arg.f: In function 'MAIN__':
funccall-1arg.f:5: internal compiler error: Abort trap
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://llvm.org/bugs&gt; for instructions.
make: *** [funccall-1arg.exe] Error 1

While I didn't entirely understand the cause from the backtraces and
inspection in the debugger, I did notice that there is not yet a
calling convention in CallingConv.h for Fortran, and llvm-convert only
tests for CallingConv:C and CSRet, so I suspect that the different CCs
is a problem here.

It looks like I will have to implement a complement to the
FunctionCallArgumentConversion class in llvm-convert.c for the Fortran
CC, but I'm not clear on the role of the CallingConv ID enum. Does a
Fortran CC belong in there, or is that only for the back end?

Thanks,
-mike

Here's what works now, and I have a separate test case for each of these:

statement functions
intrinsic functions (print, cos, etc)
loops, goto statments
scalarized array operations
function calls with *no arguments*
simple common blocks

Great!

Function calls with more than one argument don't work. Specifically:

..../gfortran funccall-1arg.f -o funccall-1arg.exe
..../llvm/lib/VMCore/Instructions.cpp:209: failed assertion
`(Params.size() == FTy->getNumParams() || (FTy->isVarArg() &&
Params.size() > FTy->getNumParams())) && "Calling a function with bad
signature!"'
funccall-1arg.f: In function 'MAIN__':
funccall-1arg.f:5: internal compiler error: Abort trap
Please submit a full bug report,
with preprocessed source if appropriate.
See <URL:http://llvm.org/bugs&gt; for instructions.
make: *** [funccall-1arg.exe] Error 1

Okay, this is probably due to the fact that the prototype for the function isn't beeing matched up with the number of formals in the trees. At the point of the assertion, what does "FTy->dump()" print to, and what do each of the params in the Params array print to?

While I didn't entirely understand the cause from the backtraces and
inspection in the debugger, I did notice that there is not yet a
calling convention in CallingConv.h for Fortran, and llvm-convert only
tests for CallingConv:C and CSRet, so I suspect that the different CCs
is a problem here.

I don't think that that would be necessary, gfortran (IIUC) uses C calling conventions for easy interop.

It looks like I will have to implement a complement to the
FunctionCallArgumentConversion class in llvm-convert.c for the Fortran
CC, but I'm not clear on the role of the CallingConv ID enum. Does a
Fortran CC belong in there, or is that only for the back end?

I don't *think* you'll need to do that, the first thing to find out is why the prototype for the function doesn't match up with the arguments. There are two likely answers:

1. We're handling a formal argument incorrectly.
2. We're building the prototype incorrectly.

Figuring out which of the two is happening is important. If it's #2, getting the output of "debug_tree(x)" on the function type "tree" node would be useful. If it's #1, getting the output of debug_tree(x) on the argument node that isn't getting converted correctly would be useful.

-Chris

Hi,
I commented out the assertion in TreeConstantToLLVM::Convert that I
mentioned in an earlier message, so I could keep looking at the
function call issue.

[snip]

> Function calls with more than one argument don't work. Specifically:
>
> ..../gfortran funccall-1arg.f -o funccall-1arg.exe
> ..../llvm/lib/VMCore/Instructions.cpp:209: failed assertion
> `(Params.size() == FTy->getNumParams() || (FTy->isVarArg() &&
> Params.size() > FTy->getNumParams())) && "Calling a function with bad
> signature!"'
> funccall-1arg.f: In function 'MAIN__':
> funccall-1arg.f:5: internal compiler error: Abort trap
> Please submit a full bug report,
> with preprocessed source if appropriate.
> See <URL:http://llvm.org/bugs&gt; for instructions.
> make: *** [funccall-1arg.exe] Error 1

Okay, this is probably due to the fact that the prototype for the function
isn't beeing matched up with the number of formals in the trees. At the
point of the assertion, what does "FTy->dump()" print to, and what do each
of the params in the Params array print to?

At the point of the assertion, llvm-convert.c:1851 ,
FTy->dump() is invalid, giving me an invalid memory location:

(gdb) print FTy->dump()
Cannot access memory at address 0x10

I get CallOperands.size() = 0
and FTy->getNumParams() = 146542211

"print *FTy" gives me this:

(gdb) print *FTy
$2 = {
  <DerivedType> = {
    <Type> = {
      <AbstractTypeUser> = {
        _vptr$AbstractTypeUser = 0x0
      },
      members of Type:
      ID = 69,
      Abstract = true,
      RefCount = 0,
      ForwardType = 0x39800000,
      ContainedTys = {
        <_Vector_base<llvm::PATypeHandle,std::allocator<llvm::PATypeHandle>

= {

          _M_impl = {
            <allocator<llvm::PATypeHandle>> = {
              <new_allocator<llvm::PATypeHandle>> = {<No data

}, <No data fields>},

            members of _Vector_impl:
            _M_start = 0x0,
            _M_finish = 0x45e07420,
            _M_end_of_storage = 0x0
          }
        }, <No data fields>},
      AbstractTypeUsers = {
        <_Vector_base<llvm::AbstractTypeUser*,std::allocator<llvm::AbstractTypeUser*>

= {

          _M_impl = {
            <allocator<llvm::AbstractTypeUser*>> = {
              <new_allocator<llvm::AbstractTypeUser*>> = {<No data

}, <No data fields>},

            members of _Vector_impl:
            _M_start = 0x0,
            _M_finish = 0x45e2abd0,
            _M_end_of_storage = 0x45e2b780
          }
        }, <No data fields>},
      static VoidTy = 0x40a6cd60,
      static BoolTy = 0x40a6cd38,
      static SByteTy = 0x40a6cd10,
      static UByteTy = 0x40a6cce8,
      static ShortTy = 0x40a6ccc0,
      static UShortTy = 0x40a6cc98,
      static IntTy = 0x40a6cc70,
      static UIntTy = 0x40a6cc48,
      static LongTy = 0x40a6cc20,
      static ULongTy = 0x40a6cbf8,
      static FloatTy = 0x40a6cbd0,
      static DoubleTy = 0x40a6cba8,
      static LabelTy = 0x40a6cb80
    }, <No data fields>},
  members of FunctionType:
  isVarArgs = false
}

> While I didn't entirely understand the cause from the backtraces and
> inspection in the debugger, I did notice that there is not yet a
> calling convention in CallingConv.h for Fortran, and llvm-convert only
> tests for CallingConv:C and CSRet, so I suspect that the different CCs
> is a problem here.

I don't think that that would be necessary, gfortran (IIUC) uses C calling
conventions for easy interop.

OK, I wasn't sure about that - I saw some code in gfortran to use
'f2c-style' calling convention, but I couldn't tell right away how
that changed things.

> It looks like I will have to implement a complement to the
> FunctionCallArgumentConversion class in llvm-convert.c for the Fortran
> CC, but I'm not clear on the role of the CallingConv ID enum. Does a
> Fortran CC belong in there, or is that only for the back end?

I don't *think* you'll need to do that, the first thing to find out is why
the prototype for the function doesn't match up with the arguments.
There are two likely answers:

1. We're handling a formal argument incorrectly.
2. We're building the prototype incorrectly.

Figuring out which of the two is happening is important. If it's #2,
getting the output of "debug_tree(x)" on the function type "tree" node
would be useful. If it's #1, getting the output of debug_tree(x) on the
argument node that isn't getting converted correctly would be useful.

At this point, it is looking like #2 to me...

Here is the debug_tree(exp) output with the program stopped at
llvm-convert.cpp:1786

<call_expr 0x45e2ac00
    type <real_type 0x45e0ae00 real4 SF
        size <integer_cst 0x45e05600 constant invariant 32>
        unit size <integer_cst 0x45e05120 constant invariant 4>
        align 32 symtab 1084672976 alias set -1 precision 32
        pointer_to_this <pointer_type 0x45e0af80>>
    side-effects
    arg 0 <addr_expr 0x45e2abd0
        type <pointer_type 0x45e2e080 type <function_type 0x45e2cf80>
            unsigned SI size <integer_cst 0x45e05600 32> unit size
<integer_cst 0x45e05120 4>
            align 32 symtab 1183916800 alias set -1>
        constant invariant
        arg 0 <function_decl 0x45e2e000 print_one_num type
<function_type 0x45e2cf80>
            addressable used public external asm-frame-size 0 SI file
funccall-1.f line 5
            LLVM: float ()* %print_one_num_ chain <function_decl
0x45e2cd00 MAIN__>>>
    arg 1 <tree_list 0x45e2b780
        value <addr_expr 0x45e2aba0 type <pointer_type 0x45e12100>
            invariant arg 0 <const_decl 0x45e2cf00 C.264>>>
    funccall-1.f:5>

Here is the whole program I'm trying to compile:

  program derivatives

  real x, dx, diff1, diff2

  diff1 = print_one_num(1) <-- Line 5, tree seen above.

  end

  function print_one_num(x)

  print * ,'Function print_one_num ', x
  print_one_num = 0.0
  return

  end

-mike