edA-qa mort-ora-y via llvm-dev
2018-Apr-22 05:34 UTC
[llvm-dev] Difference between "byval" and actually passing by value?
There appears to be a difference between passing by value: call void @foo(%some_struct %v) And using the `byval` attribute on a pointer: call void @foo(%some_struct* byval %v) They are not compatible with each other yet logically do the same thing. The second form is the one that appears to work with the ABI on linux, and the first one not. What is the reason for the difference? -- edA-qa mort-ora-y http://mortoray.com/ Creator of the Leaf language http://leaflang.org/ Streaming algorithms, AI, and design on Twitch https://www.twitch.tv/mortoray Twitter edaqa
Tim Northover via llvm-dev
2018-Apr-22 12:46 UTC
[llvm-dev] Difference between "byval" and actually passing by value?
Hi, On 22 April 2018 at 06:34, edA-qa mort-ora-y via llvm-dev <llvm-dev at lists.llvm.org> wrote:> They are not compatible with each other yet logically do the same > thing. The second form is the one that appears to work with the ABI on > linux, and the first one not. > > What is the reason for the difference?If you pass a struct directly, the LLVM target will just see an exploded list of the basic types (e.g. i8, i8, i32, ...) and have to classsify them individually. This is usually too simplistic to model a real C ABI, so it's not used much. But LLVM does have to give it some meaning because it's still a legitimate IR function. The result is that you tend to get the arguments out again if everything is consistent, but where they actually get passed is a bit random. A byval parameter is usually used to model a struct that gets passed on the stack; the target sees the size & alignment constraints, but not each individual sub-type. This is often actually used in C ABIs for a couple of reasons. First, the extra alignment parameter lets you pass structs with above-natural alignment correctly. Second, because the type actually is in memory, you tend to get a cleaner mapping from IR to machine instructions if the IR is represented that way. Of course, peepholes could probably fix a lot of that if we really cared. For structs that get passed in registers, the front-ends tend to coerce them to some type with the same constraints (register type, size, alignment, ...) in a pretty ad-hoc manner when emitting IR. That's actually responsible for a lot of the difficulty in calling C code from LLVM. Cheers. Tim.
edA-qa mort-ora-y via llvm-dev
2018-Apr-22 14:29 UTC
[llvm-dev] Difference between "byval" and actually passing by value?
Super, that clarifies a lot what happens. And yes, it's been a challenge calling C APIs with by-value structures, but I think I've got it working now, at least on x86_64 Linux. If I understood correctly, when llvm sees a struct like `foo = { i8, i64, float }` and then a function like `bar( %foo )` it is the same as the function `bar( i8, i64, float )`? Is the call guaranteed to be byte compatible, or should I not rely on it (I don't of course). What is the reason that `byval` requires a pointer type, as opposed to being able to take a value type? It's forcing me to copy values into an alloca memory, which I presume will then just be copied again on to the stack -- looking at the optimized output the redundancy is not disappearing. On 22/04/18 14:46, Tim Northover wrote:> Hi, > > On 22 April 2018 at 06:34, edA-qa mort-ora-y via llvm-dev > <llvm-dev at lists.llvm.org> wrote: >> They are not compatible with each other yet logically do the same >> thing. The second form is the one that appears to work with the ABI on >> linux, and the first one not. >> >> What is the reason for the difference? > If you pass a struct directly, the LLVM target will just see an > exploded list of the basic types (e.g. i8, i8, i32, ...) and have to > classsify them individually. This is usually too simplistic to model a > real C ABI, so it's not used much. But LLVM does have to give it some > meaning because it's still a legitimate IR function. The result is > that you tend to get the arguments out again if everything is > consistent, but where they actually get passed is a bit random. > > A byval parameter is usually used to model a struct that gets passed > on the stack; the target sees the size & alignment constraints, but > not each individual sub-type. This is often actually used in C ABIs > for a couple of reasons. First, the extra alignment parameter lets you > pass structs with above-natural alignment correctly. Second, because > the type actually is in memory, you tend to get a cleaner mapping from > IR to machine instructions if the IR is represented that way. Of > course, peepholes could probably fix a lot of that if we really cared. > > For structs that get passed in registers, the front-ends tend to > coerce them to some type with the same constraints (register type, > size, alignment, ...) in a pretty ad-hoc manner when emitting IR. > That's actually responsible for a lot of the difficulty in calling C > code from LLVM. > > Cheers. > > Tim. >-- edA-qa mort-ora-y http://mortoray.com/ Creator of the Leaf language http://leaflang.org/ Streaming algorithms, AI, and design on Twitch https://www.twitch.tv/mortoray Twitter edaqa
Seemingly Similar Threads
- Difference between "byval" and actually passing by value?
- A struct {i8, i64} has size == 12, clang says size 16
- Difference between "byval" and actually passing by value?
- A struct {i8,i64} has size == 12, clang says size 16
- A struct {i8, i64} has size == 12, clang says size 16