[DragonEgg] Why Fortran's "call flush()" is converted to "call void bitcast (void (...)* @_gfortran_flush_i4 to void (i8*)*)(i8* null) nounwind" ?

Dear LLVM,

This is probably a question for Fortran/DragonEGG experts:

Why Fortran’s “call flush()” is converted to “call void bitcast (void (…)* @_gfortran_flush_i4 to void (i8*))(i8 null) nounwind” ? Why it needs bitcast?

I’m expecting something like “call void @_gfortran_flush_i4(i8* null)”. Otherwise, we will need to teach our call parsers to digg into bitcasts, which is an undesired extra complexity.

Below is a test case (dragonegg/llvm as of r156703):

cat flush.f90
program test

call flush()

end program test

kernelgen-dragonegg flush.f90 -o- | opt -O3 -S -o -
; ModuleID = ‘’
target datalayout = “e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64”
target triple = “x86_64-unknown-linux-gnu”

@options.0.1537 = internal constant [8 x i32] [i32 68, i32 511, i32 0, i32 0, i32 0, i32 1, i32 0, i32 1], align 32

declare void @_gfortran_flush_i4(…)

define i32 @main(i32 %argc, i8** %argv) nounwind uwtable {
entry:
tail call void @_gfortran_set_args(i32 %argc, i8** %argv) nounwind
tail call void @_gfortran_set_options(i32 8, i32* getelementptr inbounds ([8 x i32]* @options.0.1537, i64 0, i64 0)) nounwind
tail call void bitcast (void (…)* @_gfortran_flush_i4 to void (i8*))(i8 null) nounwind
ret i32 0
}

declare void @_gfortran_set_args(i32, i8**)

declare void @_gfortran_set_options(i32, i32*)

Dmitry,

This is probably a question for Fortran/DragonEGG experts:

Why Fortran's "call flush()" is converted to "call void bitcast (void (...)*
@_gfortran_flush_i4 to void (i8*)*)(i8* null) nounwind" ? Why it needs
bitcast?

Just a wild guess (basing from my llvm-gcc knwoledge though): there is
a bug with in gcc fortran frontend where it fails to create the
function TREEs with proper types. It might easily be possible that
e.g. call of function with type with no args is performed with some
amount of args, etc. It's pretty fine in gcc, but not in LLVM, the
latter is much more strict wrt this.

The only solution / workaround for this was to emit the function
definition as variadic and do bitcast at a call site (there are some
other fortran-specific stuff involved here, e.g dummy args)...

See 33097 – Function decl trees without proper argument list for more info.

Yes, this is the reason.

Ciao, Duncan.

Dear Anton and Duncan,

Thank you for your insight,
Do you think this is a system problem of gcc applicable to other functions too, or just a flush-specific bug?

Best,
- Dima.

Hi Dmitry,

Do you think this is a system problem of gcc applicable to other functions too, or just a flush-specific bug?

it has nothing to do with flush - for all I know flush is fine. Dragonegg
does this for all Fortran functions because the Fortran front-end is so buggy,
i.e. often produces wrong function types. I have another way of handling this
in mind, which would avoid this trick, but I didn't get round to implementing
it yet.

Ciao, Duncan.

Duncan,

Oh, right, now I remember: it’s a very old problem I knew 1.5 years ago. There were even some bugs on it, here is a common case:

cat test1.f90
program test

call test1()

end program test

kernelgen-dragonegg test1.f90 -o- | opt -O3 -S -o -
; ModuleID = ‘’
target datalayout = “e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64”
target triple = “x86_64-unknown-linux-gnu”

@options.0.1537 = internal constant [8 x i32] [i32 68, i32 511, i32 0, i32 0, i32 0, i32 1, i32 0, i32 1], align 32

declare void @test1_(…)

define i32 @main(i32 %argc, i8** %argv) nounwind uwtable {
entry:
tail call void @_gfortran_set_args(i32 %argc, i8** %argv) nounwind
tail call void @gfortran_set_options(i32 8, i32* getelementptr inbounds ([8 x i32]* @options.0.1537, i64 0, i64 0)) nounwind
tail call void bitcast (void (…)* @test1
to void ()*)() nounwind
ret i32 0
}

declare void @_gfortran_set_args(i32, i8**)

declare void @_gfortran_set_options(i32, i32*)

So every external function call, not only flush, in DragonEgg is declared varargs and called with a bitcast. This is really really big problem in our case, because:

  1. We need to convert calls to external functions to FFI invocation, i.e. catch all CallInsts-s, get function name, args’ values and types. I don’t know how to deal with CallInst-s that have bitcasts.
  2. We can’t have any varargs function defined in module, because it is operated by NVPTX, varargs are not allowed there.

How do you think what would be the best way to workaround this problem, if it seems to be not in focus for anybody for now?

Thanks,

  • D.

2012/7/17 Duncan Sands <baldrick@free.fr>

Oh, right, now I remember: it's a very old problem I knew 1.5 years ago.
There were even some bugs on it, here is a common case:

Yes, this is right, fortran frontend produces bogus trees for every
external call.
The problem seems to have roots from the fact that there is no
external function decl here, so frontend has no way even to infer the
type from.

How do you think what would be the best way to workaround this problem, if
it seems to be not in focus for anybody for now?

Keep in mind, this not LLVM problem, it's gfortran problem. Also, it's
of pretty low priority for gcc devs since they do almost no type
checking on TREEs, so the varargs decl seems to be only viable
llvm-side fix.

Hi Anton,

How do you think what would be the best way to workaround this problem, if
it seems to be not in focus for anybody for now?

Keep in mind, this not LLVM problem, it's gfortran problem. Also, it's
of pretty low priority for gcc devs since they do almost no type
checking on TREEs, so the varargs decl seems to be only viable
llvm-side fix.

actually there is a different fix, which is to not pay any attention to GCC
function types when generating calls (and function prototypes), and instead do
everything by querying GCC's CUMULATIVE_ARGS.

Ciao, Duncan.

actually there is a different fix, which is to not pay any attention to GCC
function types when generating calls (and function prototypes), and instead
do everything by querying GCC's CUMULATIVE_ARGS.

I tried to do this during llvm-gcc times and it turned out that there
might be different calls with different signatures in single module
e.g. function with N arguments is called in some cases with N - 1
first args and since the remaining one is unused everything is fine.
So, basically the function *is* varargs but it's not possible to
deduce this from the args...

I don't recall all the details now though...

Hi Anton,

OK, at our end the following workaround seems to be sufficient:

// Check if function is called (needs -instcombine pass).
Function* callee = call->getCalledFunction();
if (!callee)
{
// Could be also a function called inside a bitcast.
// So try to extract function from the underlying constant expression.
// Required to workaround GCC/DragonEGG issue:
// http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-July/051786.html
ConstantExpr* expr = dyn_cast(call->getCalledValue());
if (!expr) continue;
callee = dyn_cast(expr->getOperand(0));
}

Hopefully there will be no more gcc-generated special cases :slight_smile:

Thanks,

  • D.

2012/7/17 Duncan Sands <baldrick@free.fr>

Hi Dmitry, it would be neater to use stripPointerCasts.

Ciao, Duncan.

Thanks, Duncan, makes sense! I suppose you meant something like this:

Function* callee = dyn_cast(
call->getCalledValue()->stripPointerCasts());
if (!callee) continue;

  • D.

2012/7/17 Duncan Sands <baldrick@free.fr>

Thanks, Duncan, makes sense! I suppose you meant something like this:

                    Function* callee = dyn_cast<Function>(
                        call->getCalledValue()->stripPointerCasts());
                    if (!callee) continue;

Yes. Note that you'll receive varargs function here.