Stream: t-compiler/help

Topic: Getting the symbol name of an intrinsic?


Edd Barrett (Jun 19 2020 at 11:01, on Zulip):

Hi everyone,

I need to find the symbol name for a call to an intrinsic inside from inside rustc_codegen_llvm.

For example, in a little debug build of a program I wrote, wrapping_add for u32 codegens to a call to the symbol:

core::num::_<impl u32>::wrapping_add::h0d270c55aeefd2ff

I have the Instance and argument types of the intrinsic to hand.

Unfortunately, tcx.symbol_name doesn't seem to work on intrinsics.

Is there way to do this in the compiler? If not, is there an LLVM API call I could use to get it from the raw LLVM pointer for the intrinsic?

Thanks!

Matthew Jasper (Jun 19 2020 at 11:04, on Zulip):

Intrinsics don't have symbols, that's what makes them instrinsics. core::num::_<impl u32>::wrapping_add::h0d270c55aeefd2ff is the symbol for the u32::wrapping_add wrapper.

bjorn3 (Jun 19 2020 at 11:04, on Zulip):

Intrinsics don't have symbol names. They are never codegened. Any mir calls to intrinsics are translated by the codegen backend to specific instruction sequences. For example wrapping_add turns into a LLVM add instruction.

Edd Barrett (Jun 19 2020 at 11:05, on Zulip):

Is it possible to get the symbol name of the wrapper?

Matthew Jasper (Jun 19 2020 at 11:06, on Zulip):

Only if you know what the wrapper is.

bjorn3 (Jun 19 2020 at 11:06, on Zulip):

An intrinsics can be wrapped by multiple function.

Edd Barrett (Jun 19 2020 at 11:08, on Zulip):

I'm in codegen_intrinsic_call() in librustc_codegen_llvm/intrinsic.rs. I'm not sure if I have sufficient information to find the wrapper. In fact, it looks to me like it builds a call directly to the intrinsic?

bjorn3 (Jun 19 2020 at 11:09, on Zulip):

That function matches on the intrinsic and then depending on the intrinsic codegens different code.

Edd Barrett (Jun 19 2020 at 11:10, on Zulip):

Yes, but I don't see any mention of wrappers. It looks to me like it just emits an LLVM intrinsic call to llvm.x.y.

bjorn3 (Jun 19 2020 at 11:11, on Zulip):

Some rust intrinsics are lowered to LLVM intrinsics, while others are lowered to regular LLVM instructions.

oli (Jun 19 2020 at 11:11, on Zulip):

yea, but llvm codegens that in "arbitrary" ways, usually just to raw asm instructions, not to function calls

oli (Jun 19 2020 at 11:11, on Zulip):

oh you're inside codegen_llvm

oli (Jun 19 2020 at 11:11, on Zulip):

nevermind me

oli (Jun 19 2020 at 11:12, on Zulip):

what do you need the symbol name of the wrapper for?

bjorn3 (Jun 19 2020 at 11:13, on Zulip):

Edd Barrett Is working on an alternative codegen backend that is a tracing jit. He probably wants to avoid having to implement all intrinsics by hand for now by calling functions instead.

Edd Barrett (Jun 19 2020 at 11:13, on Zulip):

To add a little context, we are writing a tracing JIT for Rust. We've JITted a call to wrapping_add, which gets turned into a call to a symbol in our IR.

I'm starting to wonder if we need to implement our own intrinsics in the JIT.

And what @bjorn3 said :)

oli (Jun 19 2020 at 11:15, on Zulip):

not all intrinsics even have wrappers. transmute is directly invoked, there's no wrapper

oli (Jun 19 2020 at 11:15, on Zulip):

ok, but all non-transmute intrinsics have wrappers

oli (Jun 19 2020 at 11:15, on Zulip):

you can make the wrappers lang items, but that's a lot of lang items :confused:

oli (Jun 19 2020 at 11:16, on Zulip):

a hacky way would be to use paths to get the DefId of the wrappers and then compute the symbol name

oli (Jun 19 2020 at 11:18, on Zulip):

https://github.com/rust-lang/rust-clippy/blob/742706511c9f33c6a0d4380392e513e5249057e3/clippy_lints/src/utils/mod.rs#L252

oli (Jun 19 2020 at 11:18, on Zulip):

not great, but should allow you to progress immediately without having to do much groundwork

bjorn3 (Jun 19 2020 at 11:18, on Zulip):

Maybe creating an Instance with InstanceDef::ReifyShim pointing to the intrinsic will work? You would need to extend the mono item collector to generate appropriate InstanceDef::ReifyShim for all intrinsics when used though.

bjorn3 (Jun 19 2020 at 11:19, on Zulip):

You should then skip SIR generation for those intrinsic ReifyShim's and use the ReifyShim symbol_name when generating SIR for intrinsic calls.

bjorn3 (Jun 19 2020 at 11:21, on Zulip):

(For those not familiar with the tracing JIT of Edd Barrett, SIR is the IR produced by the codegen backend and consumed by the JIT itself)

Edd Barrett (Jun 19 2020 at 11:21, on Zulip):

OK, I understood @oli's suggestion.

@bjorn3 Can you expand upon:

You would need to extend the mono item collector to generate appropriate InstanceDef::ReifyShim for all intrinsics when used though.

Thanks

oli (Jun 19 2020 at 11:22, on Zulip):

yea I think the reifyshim solution (if it works) is the better one

oli (Jun 19 2020 at 11:22, on Zulip):

if it doesn't work, it's likely not hard to make it work

bjorn3 (Jun 19 2020 at 11:22, on Zulip):

In rustc_mir::monomorphize::collector all mono items that need to be codegened are collected. You would need to extend it to create a ReifyShim mono item for every intrinsic call.

bjorn3 (Jun 19 2020 at 11:24, on Zulip):

You should add a line like https://github.com/rust-lang/rust/blob/a39c7787ba246353178e099373b9240be0d9e603/src/librustc_mir/monomorphize/collector.rs#L743 at https://github.com/rust-lang/rust/blob/a39c7787ba246353178e099373b9240be0d9e603/src/librustc_mir/monomorphize/collector.rs#L726 for InstanceDef::Intrinsic. Take care to change the instance to be a ReifyShim instead of an Intrinsic though.

Edd Barrett (Jun 19 2020 at 11:24, on Zulip):

I see.

Thanks everyone. This has been very useful.

I need to weigh up @bjorn3's solution, vs. implementing our own intrinsics. In the long run we probably want the latter, as we want as few calls in our trace as possible. But, as you say, that's a lot of intrinsics!

Edd Barrett (Jun 19 2020 at 14:29, on Zulip):

If I understand correctly, this is the modification we need is something like:

    match instance.def {
        ty::InstanceDef::Intrinsic(_) => {
            output.push(create_fn_mono_item(
                Instance {
                    def: InstanceDef::ReifyShim(instance.def_id()),
                    substs: instance.substs,
                }
            ))
        },
        ty::InstanceDef::Virtual(..) => {
            if !is_direct_call {
                bug!("{:?} being reified", instance);
            }
        }
...

But this will give crashes as the compiler builds itself:

symbol `add_with_overflow` is already defined

Also tried monomorphising the instance first:

    match instance.def {
        ty::InstanceDef::Intrinsic(_) => {
            let callee_ty = instance.monomorphic_ty(tcx);
            if let ty::FnDef(def_id, substs) = callee_ty.kind {
                output.push(create_fn_mono_item(
                    Instance {
                        def: InstanceDef::ReifyShim(def_id),
                        substs,
                    }
                ))
            } else {
                bug!("xxx");
            }
        },

Same outcome.

Is there any hope?

nagisa (Jun 21 2020 at 02:42, on Zulip):

oli said:

ok, but all non-transmute intrinsics have wrappers

The wrapers aren't necessarily direct calls to intrinsics either, however, and the intrinsics can be called directly. So there may be cases where a call of an intrinsic cannot map to any wrapper.

nagisa (Jun 21 2020 at 02:43, on Zulip):

/me says before reading the rest of the thread

bjorn3 (Jun 21 2020 at 08:41, on Zulip):

Edd Barrett and I have talked about this in PM.

Last update: Sep 27 2020 at 14:30UTC