Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct ABI Support for Linux and OS X #387

Closed
gingerBill opened this issue Jun 10, 2019 · 3 comments
Closed

Correct ABI Support for Linux and OS X #387

gingerBill opened this issue Jun 10, 2019 · 3 comments

Comments

@gingerBill
Copy link
Member

Correctly implement ABI for all supported platforms.

This may require a huge change to how the IR is generated as certain ABIs, such as System V, will separate a value across multiple registers and the current LLVM IR generation only supports to a single register/stack value per passed value.

Example:

Foo :: struct {x, y, z: f32}

Would be passed to LLVM IR as the following parameters:

(<2 x f32> %a, f32 %b)
@dimenus
Copy link

dimenus commented Jul 8, 2019

Just want to add a repro example to this issue. Right now it doesn't seem possible to interop with C when using any struct that is larger than 8 bytes.

foo.c

#include <stdint.h>
#include <stdio.h>

typedef struct CXString {
    void* data;
    uint32_t flags;
} CXString;


const char *hellostr() {
    return "hello world";
}

CXString get_cxstring() {
    return (CXString){
        .data = (void*)"foo bar baz",
        .flags = 0xDEADBEEF,
    };
}

const char* get_cstr_from_cxstring(const char *val, CXString c) {
    printf("val: %s\n", val);
    printf("C: %s\n", (const char*)c.data);
    return (const char*)c.data;
}

main.odin

package repro


foreign import "foo.so"

import "core:c";
import "core:fmt";

CXString :: struct {
    data: rawptr,
    flags: u32,
}

foreign foo {
    @(link_name = "hellostr") hellostr :: proc "c" () -> cstring ---;
    @(link_name = "get_cxstring") get_cxstring :: proc "c" () -> CXString ---;
    @(link_name = "get_cstr_from_cxstring") get_cstr :: proc "c" (test: cstring, cx: CXString) -> cstring ---;
}

main :: proc() {
    fmt.println(hellostr());
    cxstr := get_cxstring();
    fmt.println(cast(cstring)cxstr.data, get_cstr("i am a str", cxstr));
}

@travisdoor
Copy link

Hi, I have a same issue with my programming language using LLVM backend, my first idea to fix this was use LLVM's 'byval' attribute and pass all structures by pointers (inspiration to do so came from clang C generated IR with same expected functionality), but it still does not work. What about to use implicit wrapper function for this (change generation of external calls seems to be quite hard since it requires lot of changes to IR generation pass); idea is not to call externals with struct passed by value as an argument directly, but create IR function taking struct by value as normal, do the split into register-friendly representation inside this function and then call original external.

@gingerBill
Copy link
Member Author

This is now correctly supported on System V AMD64 ABI.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants