This is an archive of the discontinued LLVM Phabricator instance.

[IntrisicEmitter] Allow intrinsic types to be dependent on the data layout
AbandonedPublic

Authored by arichardson on Nov 23 2022, 4:28 AM.

Details

Summary

For certain intrinsics (e.g. stack/code related ones), the address space
always has to be the alloca address space defined in the DataLayout and
there will not be another version of that intrinsic using other address
spaces in the same module.
This change adds new llvm_{prog,alloca,global}_ptr_ty to Intrinsics.td.
It only adds the infrastructure, follow-up commits will use it for e.g.
va_start,va_copy,va_end,returnaddress, etc.

The motivating use case here are the downstream CHERI targets
that use address space 200 for alloca/program/globals. So far CHERI LLVM
overloaded all those intrinsics but this caused a lot of downstream merge
conflicts in test files, so this approach may be more maintainable.

The alternative would be to overload all the remaining intrinsics but that
causes a lot of test churn (especially for llvm.va_*/llvm.stack{save,restore}*)
and should not be necessary since those intrinsics don't really need to
be overloaded, the types just happen to depend on the data layout string.

Diff Detail

Event Timeline

arichardson created this revision.Nov 23 2022, 4:28 AM
Herald added a project: Restricted Project. · View Herald Transcript

try to fix mlir build

arichardson edited the summary of this revision. (Show Details)Nov 24 2022, 10:03 AM
arichardson added reviewers: arsenm, nikic, jrtc27, theraven.
arichardson edited the summary of this revision. (Show Details)Nov 24 2022, 10:09 AM
arichardson published this revision for review.Nov 24 2022, 10:11 AM
Herald added a reviewer: dcaballe. · View Herald Transcript
Herald added projects: Restricted Project, Restricted Project. · View Herald Transcript
arichardson added inline comments.Nov 25 2022, 1:24 AM
llvm/lib/IR/Function.cpp
1314

'G' and 'P' are the wrong way around.

fix inverted switch statement

I have mixed feelings about this patch. It feels useful to support the typed matchers, mostly in the context of fixing iPTR (really we should have a more generally parameterized iPTR if we can't fully get rid of it)

The alternative would be to overload all the remaining intrinsics but that
causes a lot of test churn (especially for llvm.va_*/llvm.stack{save,restore}*)
and should not be necessary since those intrinsics don't really need to
be overloaded, the types just happen to depend on the data layout string.

I think this is the correct solution; I think llvm_ptr_ty should be removed entirely and all intrinsics should be mangled on the pointer address space. It's not composable and we've just been migrating an intrinsic at a time as needed. We've already migrated some intrinsics for the stack use case (e.g. int_frameaddress and lifetime markers) and this switches strategies for a different set so it introduces inconsistency. This is a roadblock to fully supporting per-alloca address spaces, which has come up before as potentially useful. The datalayout address spaces are really for situations where some generic code needs to create a new value without any context, which is not the case with an intrinsic call site.

This is also going to make these intrinsics syntactically behave differently based on the datalayout. We tried something similar with program address spaces, such that the assembler currently interprets an undecorated function's address space differently based on the datalayout and I'm currently hating it. It's inconsistent and confusing and I'll likely post a patch to undo it, such that functions are always printed with an explicit addrspace(N) if it's non-0.

Assuming we do want to go with this approach, this is missing various assembler and verifier tests for all the impacted intrinsics.

llvm/include/llvm/IR/Intrinsics.td
189

Just AddrSpace sounds like it's expecting the raw number, like in LLVMQualPointerType

272–274

This part feels useful

llvm/utils/TableGen/IntrinsicEmitter.cpp
387

This is a separate diagnostic improvement that should be split out

I have mixed feelings about this patch. It feels useful to support the typed matchers, mostly in the context of fixing iPTR (really we should have a more generally parameterized iPTR if we can't fully get rid of it)

The alternative would be to overload all the remaining intrinsics but that
causes a lot of test churn (especially for llvm.va_*/llvm.stack{save,restore}*)
and should not be necessary since those intrinsics don't really need to
be overloaded, the types just happen to depend on the data layout string.

I think this is the correct solution; I think llvm_ptr_ty should be removed entirely and all intrinsics should be mangled on the pointer address space. It's not composable and we've just been migrating an intrinsic at a time as needed. We've already migrated some intrinsics for the stack use case (e.g. int_frameaddress and lifetime markers) and this switches strategies for a different set so it introduces inconsistency. This is a roadblock to fully supporting per-alloca address spaces, which has come up before as potentially useful. The datalayout address spaces are really for situations where some generic code needs to create a new value without any context, which is not the case with an intrinsic call site.

This is also going to make these intrinsics syntactically behave differently based on the datalayout. We tried something similar with program address spaces, such that the assembler currently interprets an undecorated function's address space differently based on the datalayout and I'm currently hating it. It's inconsistent and confusing and I'll likely post a patch to undo it, such that functions are always printed with an explicit addrspace(N) if it's non-0.

Assuming we do want to go with this approach, this is missing various assembler and verifier tests for all the impacted intrinsics.

I am also happy to go down the overload all intrinsics route, I just posted this as a possible approach that avoids output changes for the common "(almost) everything in AS0" targets.
If others also believe the overloading approach is better, I'll close this and post (large) patches to overload the other intrinsics that we overloaded for CHERI over the past 10 years and failed to upstream. I opened a test PR for CHERI LLVM to see how much this reduces the diff (https://github.com/CTSRD-CHERI/llvm-project/pull/663) and it shows that around 200 test files will have to be updated for overloaded llvm.va*+llvm.stacksave/stackrestore.

Regarding the address space of functions that is probably my fault, but I thought it was always printed? I believe the only thing that I allowed was to allow IR that has calls without an explicit address space to not error if the target global is a function in the program address space - but if you feed it into llvm-as | llvm-dis it should be printed again?
That being said it might also be that global function declarations are implicitly being parsed as being in the program address space, but I'd have to double-check. This is rather useful for some of the downstream CHERI tests, but it can also be fixed using sed for the handful of tests that are affected. IMO a nicer solution for this would be to allow symbolic constants in the textual IR such as addrspace(P), addrspace(G).

nikic added a comment.Dec 6 2022, 3:17 AM

I agree with @arsenm, it would be better to overload the relevant intrinsics. I don't think the churn is particularly problematic.

I generally prefer the approach here. Generality is good when necessary but a source of bugs when unnecessary. For things like stack save and stack restore, the only valid address space is the address space used for the stack. Allowing overloading adds more burden to the verifier (it must check that the address space matches) for no benefit that I can perceive.

I could see a benefit if we permitted allocas to exist in different address spaces, for architectures with more than one stack, but that would be a very invasive change to the IR and one that would require rethinking a lot of assumptions.

I'm less convinced on the {prog,global} versions, because we do currently permit globals and functions to exist in specific address spaces and I can imagine a system with multiple ROM banks with different addressing making use of that.

nikic added a comment.Dec 6 2022, 3:43 AM

FWIW, we already allow allocas to have an address space that differs from the default alloca address space. IIRC it was added for some wasm use case.

arichardson abandoned this revision.Dec 7 2022, 7:14 AM

FWIW, we already allow allocas to have an address space that differs from the default alloca address space. IIRC it was added for some wasm use case.

I did not realize that allocas were allowed in multiple address spaces. In that case the only intrinsics that benefit from this are the returnaddress ones and those could conceivable also be wanted with multiple address spaces (if there are functions in different address spaces).
Will upload reviews to overload the intrinisics instead.