Do I need to add an intrinsic for what I want to do?

I’m working on a research project and have come to the conclusion that to achieve what I want with LLVM I need to use a custom intrinsic function. The very top of the documentation page for extending LLVM however encourages me to ensure this is the correct course of action, so I want to outline my problem here, and the various solutions I’ve considered, to get people’s opinion.

I’m looking into emitting a new load opcode based on compiler analysis. For specific code patterns, I want to inform the backend to replace regular load instructions with these new load instruction opcodes, which carry out the same function but carry contextual information for out of order speculation.

So far I’ve tried to attach metadata to the source pointers of the load instructions, like the GEP instructions. Then, from a backend machine function pass, I find the IR level memory operand of each load instruction, and walk the def chain to see if the pointers have this metadata attached. However, by default metadata is stripped from IR when it’s lowered to machine specific representation, and so my only two choices there are to hack each individual pass that strips this metadata to make my new metadata count as known metadata (infeasible) or classify my new metadata as alias analysis metadata, which isn’t fitting for what it is and also hacky.

Another idea I was given was to set the address spaces of the pointers to differentiate loads on them as candidates for this new opcode, but pointers in different address spaces are not allowed to alias, which is not a guarantee I am making at all with my analysis so this would be unsound.

Lastly I’m considering using an intrinsic function that takes as arguments the relevant pointers, and then the machine function pass can scan the IR function and compare the intrinsic’s arguments against a given load’s IR memory operands. This seems like the most natural option by this point, but before pursuing this I wanted to ensure I was correct. Please let me know if there are better ways to do this.

According to who? They definitely are, and do in current use cases. Otherwise addrspacecast wouldn’t make sense as an instruction.

Oh, I read it here: https://groups.google.com/g/llvm-dev/c/0ZbzzN6t05o/m/6A15x3fCDAAJ

but is this wrong? If so different address spaces might be viable, but then I also need to figure out the optimisations implications of moving a pointer out of address space 0, as I don’t want to colour results.

Read the reply to that email immediately below it, it states exactly what I did.

Ah! My bad, thanks for pointing that out. So do you know about any other implications I should be aware of with setting a pointer to an arbitrary, unused address space for my purposes? I have already seen machine specific passes in my architecture (aarch64) return early if the given pointer isn’t address space 0, so presumably to keep things consistent I’d have to add support for my new one there, but is there anything else, particularly at the IR level?

I often have the same question as the title of the topic. I have not the same case as you, but I feel the question here might be rephrased as “How can I pass information obtained at IR level to machine function passes?”. I had the same strugles with metadata as you described, and to use intrinsics to indicate a certain situation (or even let those carry information in their operands) seemed to be the most natural approach. But I am not sure if that is the way it should be done.