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

How do you have multiple functions in the same JIT compilation or do you have to compile them individually? #74

Open
salmmanfred opened this issue Mar 6, 2023 · 22 comments

Comments

@salmmanfred
Copy link

as the title says. Do you have to compile them individually and then use indirect call? or is there some other way of doing it?

@bjorn3
Copy link

bjorn3 commented Mar 6, 2023

For each function you have to call define_function once with the return value of declare_function for the function you want to compile. If you want to call another function you would do declare_function for this function name to get a FuncId, then declare_func_in_func with this FuncId and the Function you are currently building and finally add a call instruction with the FuncRef returned by declare_func_in_func. This works even if the function you want to call isn't compiled yet. You just need to make sure it is compiled by the time you call it.

@salmmanfred
Copy link
Author

Do I make a seperate function builder for all of them?

@bjorn3
Copy link

bjorn3 commented Mar 6, 2023

Yes. You can reuse the FunctionBuilderContext for slightly better performance, but each FunctionBuilder only works for a single function.

@salmmanfred
Copy link
Author

when I use the FuncRef using a builder.ins().call() I get a index out of bounds

@bjorn3
Copy link

bjorn3 commented Mar 9, 2023

The return value of declare_func_in_func can only be used in the Function which you passed to declare_func_in_func. I did recommend calling it right before inserting a call instruction instead of keeping it around to prevent accidentally using it with the wrong Function.

@salmmanfred
Copy link
Author

I got 2 functions to work however now my print function spits out completely wrong data again (except when you send in 0).

Also how do i get a value from the return data of call()?

@salmmanfred
Copy link
Author

correction: The data gets completely mangled the print function prints the correct data but the data itself is inherently worng

its suppose to give me
y1 = x+1
y2 = x+2
y3 = y1+y2
when I send in 0 I get the correct value back (3)

however when I send anything above zero it sends me 251892446413572

@bjorn3
Copy link

bjorn3 commented Mar 9, 2023

Also how do i get a value from the return data of call()?

You can use func.dfg.inst_results(call_inst) where call_inst is the return value of creating the call instruction.

however when I send anything above zero it sends me 251892446413572

Can you show the clif ir you are using? You can print the Function right after building it using eg println!("{}", func);.

@salmmanfred
Copy link
Author

function u1:1(i64, i64) -> i64 windows_fastcall {
    sig0 = (i64, i64) system_v

block0(v0: i64, v1: i64):
    v2 = iconst.i64 0x7ff6_63df_d750
    v3 = iadd_imm v0, 1
    call_indirect sig0, v2(v3, v0)  ; v2 = 0x7ff6_63df_d750
    return v3
}

function u0:0(i64) -> i64 windows_fastcall {
    sig0 = (i64, i64) -> i64 windows_fastcall
    sig1 = (i64, i64) system_v
    fn0 = colocated u0:0 sig0

block0(v0: i64):
    v1 = iconst.i64 0x7ff6_63df_d6a0
    v2 = iadd_imm v0, 1
    v3 = iadd_imm v0, 2
    v4 = iadd v2, v3
    call_indirect sig1, v1(v4, v0)  ; v1 = 0x7ff6_63df_d6a0
    v5 = call fn0(v4, v3)
    return v4
}

@bjorn3
Copy link

bjorn3 commented Mar 9, 2023

How do you call the function from native code? Do you cast it to a function pointer of type extern "C" fn(u64) -> u64 before calling it? And are you on Windows? (I assume you are given that you use the windows calling convention. If you are not on Windows, you will have to use the system_v calling convention.)

@salmmanfred
Copy link
Author

salmmanfred commented Mar 9, 2023

im using extern "sysv64" fn(i64) -> i64. but I dont think that is the issue.

@bjorn3
Copy link

bjorn3 commented Mar 9, 2023

If you use extern "sysv64" you have to define the function as having the system_v calling convention, not the windows_fastcall calling convention. Never mix calling conventions. It breaks in all kinds of ways.

@salmmanfred
Copy link
Author

Its working now.

The so for the dfg.inst_result() you have to append two results with dfg.append_result()?

I noticed only the second returned the updated data

@bjorn3
Copy link

bjorn3 commented Mar 9, 2023

You shouldn't ever need to use append_results as regular cranelift user. It is meant for in place modification of clif ir, like during optimizations. What exactly is the problem you have with inst_results?

@salmmanfred
Copy link
Author

Well inst results just returns an empty array.

Is the the Function of the current Function or the Function being called?

@bjorn3
Copy link

bjorn3 commented Mar 9, 2023

You should call inst_results on the same Function as which you added the call instruction to. (The current function)

@salmmanfred
Copy link
Author

The issue with that is that the current Function is borrowed to the function builder

@bjorn3
Copy link

bjorn3 commented Mar 9, 2023

You can use the func field of the function builder.

@salmmanfred
Copy link
Author

How do I allocate a chunk of memory?

@bjorn3
Copy link

bjorn3 commented Mar 25, 2023

You did call a function to do so like malloc. Basically the same way you did do in C.

@salmmanfred
Copy link
Author

Is there a builtin function for malloc in cranelift IR or do I need to make like a function myself and implement it? I saw there were built in address functions that use u32 instead of i64 how do I recast them or can I just do as u32?

@bjorn3
Copy link

bjorn3 commented Mar 26, 2023

Is there a builtin function for malloc in cranelift IR or do I need to make like a function myself and implement it?

You can directly import the malloc from libc. If you don't define a function yourself, cranelift-jit will try to look it up using dlsym as fallback.

I saw there were built in address functions that use u32 instead of i64 how do I recast them or can I just do as u32?

You can use the pointer_type() function to get the right pointer type:

let pointer = self.module.target_config().pointer_type();
You shouldn't do any casts as that will lose information.

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

No branches or pull requests

2 participants