[llvm-dev] Generating C headers from LLVM

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

[llvm-dev] Generating C headers from LLVM

Shawn Webb via llvm-dev
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()

Questions:
1) Is there any way to convince clang to generate the "correct" output,
that fits the given definition in LLVM-IR?

2) What other surprises to expect? Is there a "safe fragment" where the
 obvious C code actually matches the obvious LLVM-IR?

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?


Thanks in advance for any help,
  Peter


_______________________________________________
LLVM Developers mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|

Re: [llvm-dev] Generating C headers from LLVM

Shawn Webb via llvm-dev
On Fri, Apr 12, 2019 at 3:53 AM Peter Lammich via llvm-dev <[hidden email]> 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 Spencer
 

Questions:
1) Is there any way to convince clang to generate the "correct" output,
that fits the given definition in LLVM-IR?

2) What other surprises to expect? Is there a "safe fragment" where the
 obvious C code actually matches the obvious LLVM-IR?

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?


Thanks in advance for any help,
  Peter


_______________________________________________
LLVM Developers mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|

Re: [llvm-dev] Generating C headers from LLVM

Shawn Webb via llvm-dev
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 <
> [hidden email]> 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 Spencer
I'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
> [hidden email]
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


--

Johannes Doerfert
Researcher

Argonne National Laboratory
Lemont, IL 60439, USA

[hidden email]

_______________________________________________
LLVM Developers mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

signature.asc (235 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [llvm-dev] Generating C headers from LLVM

Shawn Webb via llvm-dev
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

_______________________________________________
LLVM Developers mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|

Re: [llvm-dev] Generating C headers from LLVM

Shawn Webb via llvm-dev
> -----Original Message-----
> From: llvm-dev [mailto:[hidden email]] On Behalf Of Peter
> Lammich via llvm-dev
> Sent: Friday, April 12, 2019 17:35
> To: Doerfert, Johannes <[hidden email]>; Michael Spencer
> <[hidden email]>
> Cc: llvm-dev <[hidden email]>
> 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.
_______________________________________________
LLVM Developers mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|

Re: [llvm-dev] Generating C headers from LLVM

Shawn Webb via llvm-dev
Thank you for the response.
I have already feared that it will be like this.

So I will end up to generate interface methods between the C style convention and the Llvm style one. And, when I understood this point right, ending up reinventing the abi lowering wheel, as there is no library support for this.

--
Peter


-------- Original Message --------
Subject: RE: [llvm-dev] Generating C headers from LLVM
From: "Cranmer, Joshua" <[hidden email]>
To: Peter Lammich <[hidden email]>,"Doerfert, Johannes " <[hidden email]>,Michael Spencer <[hidden email]>," [hidden email]" <[hidden email]>
CC:


> -----Original Message-----
> From: llvm-dev [mailto:[hidden email]] On Behalf Of Peter
> Lammich via llvm-dev
> Sent: Friday, April 12, 2019 17:35
> To: Doerfert, Johannes ; Michael Spencer
>
> Cc: llvm-dev
> 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.

_______________________________________________
LLVM Developers mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|

Re: [llvm-dev] Generating C headers from LLVM

Shawn Webb via llvm-dev
In reply to this post by Shawn Webb via llvm-dev
On 4/12/19 12:53 PM, Peter Lammich via llvm-dev 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()
>
> Questions:
> 1) Is there any way to convince clang to generate the "correct" output,
> that fits the given definition in LLVM-IR?
>
> 2) What other surprises to expect? Is there a "safe fragment" where the
>  obvious C code actually matches the obvious LLVM-IR?
>
> 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?
>
>
> Thanks in advance for any help,
>   Peter

Hello,

In DragonFFI [1], I use the debug information emitted by clang to "reconstruct" the C
function types. This could be used to potentially emit proper C headers that define these
functions.

Regards,

[1] https://github.com/aguinet/dragonffi
_______________________________________________
LLVM Developers mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev