Stream: cranelift

Topic: just getting started


view this post on Zulip Taylor Holliday (May 22 2023 at 07:10):

I'm quite new. Wondering what's wrong here:

function u0:0() system_v {
    ss0 = explicit_slot 4

block0:
    v0 = stack_addr.i32 ss0
    v1 = iconst.i32 1
    store v0, v1  ; v1 = 1
    v2 = iconst.i32 0
    return
}

view this post on Zulip Taylor Holliday (May 22 2023 at 07:15):

looks like I want stack_store instead

view this post on Zulip bjorn3 (May 22 2023 at 09:11):

On 64bit systems you need to use stack_addr.i64 instead. The type param of stack_addr is the pointer type.

view this post on Zulip bjorn3 (May 22 2023 at 09:12):

@Taylor Holliday

view this post on Zulip Taylor Holliday (May 22 2023 at 15:27):

thanks @bjorn3 ! What about the stack_store instruction? Looks like I want to call StackStore but not sure how (https://docs.rs/cranelift-codegen/latest/cranelift_codegen/ir/trait.InstBuilder.html#method.StackStore)

view this post on Zulip Afonso Bordado (May 22 2023 at 15:31):

You might want to use InstBuilder::stack_store instead, which is the more friendly version of that API

view this post on Zulip Afonso Bordado (May 22 2023 at 15:32):

There you don't need to specify a pointer type. And can just provide v1(from the example above) as a value and ss0 as the stack slot

view this post on Zulip Taylor Holliday (May 22 2023 at 15:37):

excellent, thanks @Afonso Bordado !

view this post on Zulip bjorn3 (May 22 2023 at 16:04):

The CamelCase methods on InstBuilder should only be used in very specific cases. Rather than building an instruction with a certain opcode, like the snake_case methods do, the CamelCase methods build instructions with specific instruction formats. A single instruction format may be used by multiple opcodes. For example the Binary instruction format is used by iadd, isub, umul, smul, udiv, sdiv, and so on. Instruction formats are an artifact of the way we internally encode instructions. You shouldn't have to worry about them unless you are writing an optimization pass.

view this post on Zulip Taylor Holliday (May 22 2023 at 16:31):

cool... thanks for the info! I'm not sure how I missed the stack_store function when searching around

view this post on Zulip Taylor Holliday (May 22 2023 at 16:32):

I'm also wondering how to represent a struct. In LLVM I could build up a struct type, but I guess cranelift IR doesn't have structs?

view this post on Zulip Chris Fallin (May 22 2023 at 16:54):

@Taylor Holliday we had a recent discussion on this here, but briefly, that's correct: we don't support structs, only primitive types and pointers, but with those you can build structs at a higher abstraction level (i.e. your compiler) and lower to CLIF

view this post on Zulip Taylor Holliday (May 22 2023 at 16:55):

cool... thanks @Chris Fallin ! I'm a graphics person attempting a compiler hah

view this post on Zulip Chris Fallin (May 22 2023 at 16:57):

you wouldn't be the first person taking that path! :-) Best of luck and feel free to ask more questions here

view this post on Zulip bjorn3 (May 22 2023 at 17:02):

A quick search suggests that you are the developer of Audulus. Do you want to use Cranelift as jit compiler for the audio graph?

view this post on Zulip Taylor Holliday (May 22 2023 at 20:32):

@bjorn3 yep! It's gonna be tricky though since Apple forbids JIT on iOS. I was thinking of using a wasm interpreter. I'm also working on a little language for writing DSP code inside the nodes in Audulus: https://github.com/audulus/lyte

A programming language for Audulus nodes. Contribute to audulus/lyte development by creating an account on GitHub.

view this post on Zulip bjorn3 (May 22 2023 at 20:35):

Yeah, apple forbidding jitting is a pain.

view this post on Zulip bjorn3 (May 22 2023 at 20:36):

By the way I noticed a typo in the readme: langauge -> language

view this post on Zulip Taylor Holliday (May 22 2023 at 20:37):

ah thanks!

view this post on Zulip bjorn3 (May 22 2023 at 20:37):

Is that language meant to be directly used by end users or will audulus have a fixed set of nodes written in that language that are then composed together using a gui?

view this post on Zulip Taylor Holliday (May 22 2023 at 20:37):

directly by end users

view this post on Zulip Taylor Holliday (May 22 2023 at 20:37):

currently there is a Lua DSP node in the app

view this post on Zulip Taylor Holliday (May 22 2023 at 20:37):

which works reasonably well with LuaJIT

view this post on Zulip Taylor Holliday (May 22 2023 at 20:39):

I just figured a statically typed language would be better, plus its an excuse for me to make one

view this post on Zulip bjorn3 (May 22 2023 at 20:40):

In that case you can't precompile all nodes at build time for the ios version. Precompiling nodes + interpreting the composition of nodes would likely be faster than interpreting the individual instructions of a node. If there are nodes written in that language maybe you could still precompile just those fixed nodes and interpret the rest.

view this post on Zulip Taylor Holliday (May 22 2023 at 20:40):

there's also an expression node (simple C math expressions) that would benefit from JITting

view this post on Zulip Taylor Holliday (May 22 2023 at 20:41):

so actually what I currently do, which is a little nuts, is I generate C for various subgraphs in the library of modules that come with the app. when the app detects such a configuration by checksumming generated C, it will use an AOT compiled function

view this post on Zulip Taylor Holliday (May 22 2023 at 20:43):

that was the best I could do to work around the JIT restriction so far

view this post on Zulip Taylor Holliday (May 22 2023 at 20:45):

anyway the app is also on macOS so I can use JITting there

view this post on Zulip Taylor Holliday (May 22 2023 at 20:45):

and I want to bring back my Linux and Windows versions at some point, but I digress :)

view this post on Zulip bjorn3 (May 22 2023 at 20:47):

I know WebkitView doesn't allow jitting, but does SafariView allow jitting? If so I guess you could from a technical perspective try to compile the graph to webassembly and inject it into the SafariView. But the docs say that it isn't allowed to be hidden, so it wouldn't pass the app store review.

view this post on Zulip Taylor Holliday (May 22 2023 at 20:48):

oh that's interesting... where's that in the docs?

view this post on Zulip bjorn3 (May 22 2023 at 20:49):

If you are asking about it not being allowed by the app store guidelines: https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller

In accordance with App Store Review Guidelines, this view controller must be used to visibly present information to users; the controller may not be hidden or obscured by other views or layers.

An object that provides a visible standard interface for browsing the web.

view this post on Zulip bjorn3 (May 22 2023 at 20:52):

For jit support in safariview I found this, but I'm not sure if that is the default or requires a special entitlement only given to browsers: https://infrequently.org/2021/08/webkit-ios-deep-dive/

Safari on iOS had JIT for many years, whereas competing browsers were prevented from approaching similar levels of performance. More recently, WebView browsers on iOS have been able to take advantage of WebKit's JIT-ing JavaScript engine, but are prevented from bringing their own.

A deep dive into the arguments offered by Apple and others to defend a lack of browser engine choice on iOS. Instead of raising the security floor, Apple has set a cap whilst breeding a monoculture that ensures all iOS browsers are vulnerable to identical attacks, no matter whose icon is on the home screen.

view this post on Zulip bjorn3 (May 22 2023 at 20:54):

And it seems that jit compilation is possible for sideloaded apps: https://9to5mac.com/2020/11/06/ios-14-2-brings-jit-compilation-support-which-enables-emulation-apps-at-full-performance/

You may know some unofficial iOS apps that offer some kind of emulation. These apps run based on hacks and...

view this post on Zulip bjorn3 (May 22 2023 at 20:56):

I don't think any of this is realistically usable for a regular app store app though unfortunately.

view this post on Zulip Taylor Holliday (May 22 2023 at 23:13):

yeah not much one can do about it really

view this post on Zulip Taylor Holliday (May 22 2023 at 23:13):

thanks for the links!

view this post on Zulip Taylor Holliday (May 22 2023 at 23:16):

the Infrequently Noted article seems like an excellent treatment of the topic

view this post on Zulip Taylor Holliday (May 23 2023 at 01:54):

can I generate code to get the address of a cranelift_frontend::Variable? Trying to do lvalues

view this post on Zulip Taylor Holliday (May 23 2023 at 01:59):

hehe GPT thought I could pass in a Variable instead of a StackSlot: self.builder.ins().stack_addr(I32, variable, 0)

view this post on Zulip Chris Fallin (May 23 2023 at 02:21):

A Variable doesn't exist in memory; you'll want to create a stackslot if you need a thing that has an address (and then generate loads and stores to it as appropriate)

view this post on Zulip Chris Fallin (May 23 2023 at 02:22):

(also just fwiw, I'm pretty annoyed with GPT/LLMs' tendency to hallucinate incorrect things, so I'm really not wild about helping to fix its incorrect output; as a policy I'd prefer to offer help to human intelligences only!)

view this post on Zulip Taylor Holliday (May 23 2023 at 05:29):

ah ok... think I figured it out. Not sure I'm doing it the right way (I'm not using stack slots at all). Instead I created a separate function for codegen on lvalues which returns a Variable. That may not be doable for more complex lvalue expressions like my_struct.my_array[3] or something. I assume at some point I'll need to generate an address from a stack slot

view this post on Zulip Taylor Holliday (May 23 2023 at 05:32):

I've been mainly working from the cranelift jit demo (https://github.com/bytecodealliance/cranelift-jit-demo), but the toy language only has ints, so assignment is very simple

JIT compiler and runtime for a toy language, using Cranelift - GitHub - bytecodealliance/cranelift-jit-demo: JIT compiler and runtime for a toy language, using Cranelift

view this post on Zulip Taylor Holliday (May 23 2023 at 17:18):

now I'm wondering where to look for an example of exposing a rust function to be called from the generated code

view this post on Zulip Taylor Holliday (May 23 2023 at 17:59):

hmm this panics:

    fn setup_library(&mut self) {

        let mut sig = self.module.make_signature();
        sig.params.push(AbiParam::new(types::I32));

        let func_id = self.module
        .declare_function("lyte_assert", Linkage::Import, &sig)
        .unwrap();


        self.module.define_function(
            func_id,
            &mut self.ctx,
        ).unwrap(); // <--- this panics with InvalidImportDefinition("lyte_assert")
    }

view this post on Zulip Taylor Holliday (May 23 2023 at 18:01):

anything obvious there? I can do a more complete repro if necessary

view this post on Zulip Chris Fallin (May 23 2023 at 18:03):

@bjorn3 would have a more definitive answer (I don't know cranelift-module well) but I think one is not supposed to define a function that is also an import

view this post on Zulip Taylor Holliday (May 23 2023 at 18:15):

ah ok

view this post on Zulip PROMETHIA (May 23 2023 at 18:15):

If you're only trying to JIT, then an easy way is to make the rust function extern "C", and then grab its function pointer as an i64. Then you can just load it using iconst() and use that as a value to call_indirect. Just have to make sure you use the system default calling convention too, or else they'll mismatch.

view this post on Zulip Taylor Holliday (May 23 2023 at 18:15):

dang that's pretty easy :)

view this post on Zulip Chris Fallin (May 23 2023 at 18:21):

that's also going to be approximately the most efficient option, because a call from JIT code to some other arbitrary code in the process will have to use a full 64-bit address anyway (not within the 2GB RIP-relative range of an ordinary call instruction); so it's not bad at all!

view this post on Zulip bjorn3 (May 23 2023 at 18:25):

You can also call .symbol("lyte_assert", the_lyte_assert_function as usize as *const u8) on the JITBuilder before you create the JITModule using it.

view this post on Zulip bjorn3 (May 23 2023 at 18:28):

.symbol() takes precedence over dlsym() for symbol lookup.

view this post on Zulip Taylor Holliday (May 31 2023 at 06:21):

I did something dumb, but should cranelift panic like this?

function u0:0() system_v {
block0:
    v0 = iconst.i32 1
    v1 = load.i32 v0  ; v0 = 1
    v2 = iconst.i32 0
    return
}

thread 'compiler::tests::basic2' panicked at 'internal error: entered unreachable code: no rule matched for term to_amode at src/isa/x64/inst.isle line 1076; should it be partial?', /Users/holliday/lyte/target/debug/build/cranelift-codegen-db8482b6e5c711c6/out/isle_x64.rs:2297:5

view this post on Zulip bjorn3 (May 31 2023 at 08:44):

If you run the verifier does it throw an error?

view this post on Zulip bjorn3 (May 31 2023 at 08:45):

Backends work under the assumption that the verifier passed.

view this post on Zulip bjorn3 (May 31 2023 at 08:47):

In your case the issue is that you are using a 32bit address on a 64bit arch. If the verifier doesn't catch this even when passing the TargetIsa to verify_function, this is an issue in the verifier.

view this post on Zulip Taylor Holliday (May 31 2023 at 16:29):

I was running verify_function

view this post on Zulip bjorn3 (May 31 2023 at 17:11):

The second argument to verify_function can be flags or it can be a TargetIsa. You are passing flags, but the pointer type check only works when you pass it the TargetIsa for which you are compiling.


Last updated: Oct 23 2024 at 20:03 UTC