Doerfert, Johannes via llvm-dev
2019-Apr-12 20:33 UTC
[llvm-dev] Generating C headers from LLVM
Hi Peter, I inlined some comments below but it might also interest you that we plan to have a GSoC student work on something quite related [1]. I hope in the process we'll develop the functionality you are looking for as part of what we want to do. I know other people looked into your problem before* but I haven't seen anybody that trying to upstream the functionality yet. * I could look for references. [1] http://llvm.org/OpenProjects.html#header-generation On 04/12, Michael Spencer via llvm-dev wrote:> On Fri, Apr 12, 2019 at 3:53 AM Peter Lammich via llvm-dev < > llvm-dev at lists.llvm.org> wrote: > > > Hi List, > > > > is there any way to generate proper C header files for functions that > > are defined in LLVM-IR. My current attempts fail when clang does some > > fancy transformations (to adhere to some ABIs ??), e.g., for returning > > a struct. > > > > For example the declaration > > > > typedef struct {int64_t a; int64_t b;int64_t c;} test; > > test create_test(void);yields the LLVM code > > > > %struct.test = type { i64, i64, i64 } > > declare void @create_test(%struct.test* sret) #1 > > > > However, the function is defined in LLVM-IR as > > {i64,i64,i64} @create_test() > > > > Where are you getting this definition from? Clang outputs what is required > by the target backend to generate the correct ABI. The mapping from C code > to llvm ir is always target dependent. > > - Michael SpencerI'm also confused about this part.> > Questions: > > 1) Is there any way to convince clang to generate the "correct" output, > > that fits the given definition in LLVM-IR?Could you elaborate what you would call "correct output", what "incorrect output" you currently see, and how you generate the latter?> > 2) What other surprises to expect? Is there a "safe fragment" where the > > obvious C code actually matches the obvious LLVM-IR?This is a though question. Probably, depending on the target, but Idk if it is written down. You can try to change the target architecture to extend this subset* but as Michael noted above, LLVM-IR is always target dependent. * Try adding '-target spir' or '-target spir-v' to the clang call if you want to use the IR only to generate C code again. It is however still not a target independent IR because of things like the datalayout (=> sizeof, offsetof, ...). See the constant 8 in the example below: ******* INPUT ****** struct S { int a; int b; }; int foo(struct S s) { return s.a + s.b + sizeof(long); } **** INPUT END ***** ****** SPIR IR ****** target triple = "spir" %struct.S = type { i32, i32 } ; Function Attrs: noinline nounwind optnone define dso_local spir_func i32 @foo(%struct.S* byval align 4 %s) #0 { entry: %a = getelementptr inbounds %struct.S, %struct.S* %s, i32 0, i32 0 %0 = load i32, i32* %a, align 4 %b = getelementptr inbounds %struct.S, %struct.S* %s, i32 0, i32 1 %1 = load i32, i32* %b, align 4 %add = add nsw i32 %0, %1 %add1 = add i32 %add, 8 ret i32 %add1 } **** SPIR IR END ****> > 3) If 1 does not exist, is there a way to generate "wrapper-functions" > > in LLVM-IR, that map the given functions to what clang expects?I'm not 100% sure I get your question but maybe it helps to remember that there is a (target dependent) N to 1 mapping between C (signatures) and LLVM-IR (types). That being said, it is probably possible to "remember" the original C type and map generated IR back, we'll hope to explore this during the GSoC. Cheers, Johannes> _______________________________________________ > LLVM Developers mailing list > llvm-dev at lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev-- Johannes Doerfert Researcher Argonne National Laboratory Lemont, IL 60439, USA jdoerfert at anl.gov -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 228 bytes Desc: not available URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190412/9733f00f/attachment.sig>
Peter Lammich via llvm-dev
2019-Apr-12 21:35 UTC
[llvm-dev] Generating C headers from LLVM
Thanks Michael and Johannes for the replies.> However, the function is defined in LLVM-IR as > > > {i64,i64,i64} @create_test() > > > > Where are you getting this definition from? Clang outputs what is > > required by the target backend to generate the correct >ABI. > > The mapping > > from C code to llvm ir is always target dependent. > - Michael Spencer> I'm also confused about this part.I generate LLVM-IR code from my own frontend language, and that happens to generate things like the "create_test()" from above. I always thought this is valid LLVM, and llc will translate it to valid code for (almost) whatever target I choose. In my case, I have x86_64 Linux. Now, I want to call the procedures that my own frontend generates (e.g. the create_test()) from a C program. I hoped to be able to use clang for that.> > > Questions: > > > 1) Is there any way to convince clang to generate the "correct" > > > output, > > > that fits the given definition in LLVM-IR? > Could you elaborate what you would call "correct output", what > "incorrect output" you currently see, and how you generate the > latter?Given the LLVM-IR definition (say in file test.ll) {i64,i64,i64} > @create_test() { ... } somehow generate a declaration in C for it. When I try (say in file invoke.c) typedef struct {int64_t a; int64_t b;int64_t c;} test; test create_test(void);yields the LLVM code int main([...]) { test x = create_test(); HERE: [...] } and compile with > clang test.ll invoke.c the generated binary just crashes, and at HERE:, x contains garbage. I believe this is due to different calling conventions being used. When I invoke clang -S -emit-llvm invoke.c then I see that clang has produced declare void @create_test(%struct.test* sret) which is "incorrect" for my purpose, as it doesn't match the definition of create_test() in test.ll. Note that I have successfully done this with 2-element structures, e.g., with {i64,i64} the above example just works. That's why I asked for "other surprises"> > > 2) What other surprises to expect? Is there a "safe fragment" > > > where the > > > obvious C code actually matches the obvious LLVM-IR? > This is a though question. Probably, depending on the target, but Idk > if > it is written down. You can try to change the target architecture to > extend this subset* but as Michael noted above, LLVM-IR is always > target > dependent.I have no problem with being target dependent, as long as I can match the LLVM-IR definition with a C declaration.> > > > > > 3) If 1 does not exist, is there a way to generate "wrapper- > > > functions" > > > in LLVM-IR, that map the given functions to what clang expects? > I'm not 100% sure I get your question but maybe it helps to remember > that there is a (target dependent) N to 1 mapping between C > (signatures) > and LLVM-IR (types). That being said, it is probably possible to > "remember" the original C type and map generated IR back, we'll hope > to > explore this during the GSoC.In my use-case, the "original" type comes from my own frontend/LLVM-IR, and I want to generate a compatible C type for it. I hoped to keep my frontend simple, and that's why it just generates functions that return structure types. However, I need to call these functions from clang, ideally without clobbering my frontend with target-specific calling-convention implementations (Conceptually, those things belong to the backend!). Note that it is irrelevant for me whether my functions adhere to some specific ABI, as long as I can call them from C code compiled with clang. Best, Peter
Cranmer, Joshua via llvm-dev
2019-Apr-15 13:58 UTC
[llvm-dev] Generating C headers from LLVM
> -----Original Message----- > From: llvm-dev [mailto:llvm-dev-bounces at lists.llvm.org] On Behalf Of Peter > Lammich via llvm-dev > Sent: Friday, April 12, 2019 17:35 > To: Doerfert, Johannes <jdoerfert at anl.gov>; Michael Spencer > <bigcheesegs at gmail.com> > Cc: llvm-dev <llvm-dev at lists.llvm.org> > Subject: Re: [llvm-dev] Generating C headers from LLVM > > Given the LLVM-IR definition (say in file test.ll) > {i64,i64,i64} @create_test() { ... }The LLVM IR ABI is not, in general, the same as the C ABI, since there's generally more trickery that gets involved. There have been suggestions in the past to build an ABI lowering library that's not so tightly integrated to Clang, but nothing has come of that yet. In particular, the ABI you get from passing structs around is completely different: a function returning a struct generally maps each element of the struct into a different register (i.e., returning a struct in LLVM IR is essentially declaring that a function returns multiple values--which C doesn't support), whereas the ABI for most targets is to have the caller allocate a struct on the stack and pass the address as the first argument (generally marked sret).> I hoped to keep my frontend simple, and that's why it just generates > functions that return structure types. However, I need to call these > functions from clang, ideally without clobbering my frontend with > target-specific calling-convention implementations (Conceptually, those > things belong to the backend!). Note that it is irrelevant for me > whether my functions adhere to some specific ABI, as long as I can call > them from C code compiled with clang.Returning a struct in LLVM IR is pretty much the one thing you can do to a function to make it completely uncallable from a C code no matter how many compiler-specific annotations you put on the C code.