JuliaHubOSS / llvm-cbe

resurrected LLVM "C Backend", with improvements
Other
826 stars 141 forks source link

Function typedef is not emitted when a function pointer is only used in a struct #101

Closed hikari-no-yume closed 3 years ago

hikari-no-yume commented 3 years ago

Consider the following C program:

#include <stdio.h>
void foo(void) { }
struct foo_ptr_struct
{
    void (*foo_ptr)(void);
};
int main(void)
{
    struct foo_ptr_struct foo_ptr_object;
    //foo_ptr_object.foo_ptr = foo;
    printf("%p\n", (void*)&foo_ptr_object);
}

It has a function pointer type used in a struct type, but it's never actually touched in a function. Clang will generate LLVM IR for it that looks something like this:

%struct.foo_ptr_struct = type { void ()* }

@.str = private unnamed_addr constant [4 x i8] c"%p\0A\00", align 1

; Function Attrs: noinline nounwind optnone ssp uwtable
define void @foo() #0 {
  ret void 
} 

; Function Attrs: noinline nounwind optnone ssp uwtable
define i32 @main() #0 {
  %1 = alloca %struct.foo_ptr_struct, align 8
  %2 = bitcast %struct.foo_ptr_struct* %1 to i8*
  %3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i64 0, i64 0), i8* %2)
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

If this LLVM IR is compiled with LLVM-CBE, this function pointer type gets mentioned in the resulting C code within the struct definition, but never actually gets defined:

/* Function definitions */

/* Types Definitions */
struct l_struct_struct_OC_foo_ptr_struct {
  l_fptr_1* field0;
};

(There should be some typedef void l_fptr_1(void); line under “Function definitions”, but there isn't.)

C compilers obviously don't like this very much.

The real-world case where I encountered this was when trying to compile a Rust “hello world” program (though it wasn't the only problem). This C program is a contrived reproducer. If you un-comment the statement foo_ptr_object.foo_ptr = foo;, the bug doesn't happen. This suggests that the bug is specific to function pointer types that aren't directly referenced within functions.

Some printf debugging suggests that this problem is occurring because printFunctionName (which assigns the ID to the function type) is being called after all the function types have been printed.

There's already some logic in printModuleTypes for handling function types that depend on other function types, so maybe this can be fixed by just doing the same for structs. If so, I will probably have a fix for this very soon. :)

vtjnash commented 3 years ago

Probably the same issue as https://github.com/JuliaComputing/llvm-cbe/issues/66

hikari-no-yume commented 3 years ago

Ah, indeed, it must be the same issue. Sorry, I should have remembered it.

vtjnash commented 3 years ago

No worries. I just cross-linked so both can be closed together.

And if you’re interested in being a collaborator here with commit rights, let me know and I’ll see if I can give you that access.

hikari-no-yume commented 3 years ago

Thank you for the kind offer. I would be interested. I expect I would still use pull requests for most things, but being able to merge small fixes myself would be useful.

vtjnash commented 3 years ago

Yep, that's exactly right. While I don't commit here, when I do, I would also typically use PRs. Currently it is mostly just myself doing reviews and merging things for others. And while I have been mostly able to keep on top of it, being able to expand that will be helpful. And someday we may even finish getting CI setup, making the PR process even more useful for everyone. It took a couple days to work out the details, so you may see the repository team name has changed now, as that turned out to be necessary to add you here. But also welcome!