This is an archive of the discontinued LLVM Phabricator instance.

[MLIR] Add readonly,writeonly,noalias to func arg attributes
Needs ReviewPublic

Authored by sjw36 on Dec 19 2022, 5:30 PM.

Details

Summary

Includes conversion to corresponding LLVM attributes

Diff Detail

Event Timeline

sjw36 created this revision.Dec 19 2022, 5:30 PM
Herald added a project: Restricted Project. · View Herald Transcript
sjw36 requested review of this revision.Dec 19 2022, 5:30 PM
ftynse requested changes to this revision.Dec 20 2022, 1:31 AM

Why can't we keep using the attributes defined in the LLVM dialect?

This revision now requires changes to proceed.Dec 20 2022, 1:31 AM
sjw36 updated this revision to Diff 502688.Mar 6 2023, 9:18 AM

Simplified after rebase, using translation tables.

sjw36 added a comment.Mar 6 2023, 9:21 AM

@ftynse these attributes are specific to func parameters, and not necessarily to LLVM backends (e.g. SPIRV). They are useful for dataflow analysis and would prefer not to have to include LLVMIR everywhere.

sjw36 updated this revision to Diff 503911.Mar 9 2023, 1:15 PM

[MLIR][Func] Add readonly,writeonly,noalias to func arg attributes

Includes conversion to corresponding LLVM attributes

Differential Revision: https://reviews.llvm.org/D140357

There isn't sufficient context to justify the change in the commit description, and the change itself doesn't seem to do anything else than lifting function argument attributes from LLVM IR to the Func dialect level. Yes, there is SPIR-V, but the change does not include the lowering to SPIR-V or even a description of how it can be done. Blindly copying LLVM IR is acceptable in the LLVM dialect, but not at the higher-level abstractions such as Func. It is unclear to me what these attributes would even mean in the full generality of what MLIR type system allows. For example, what is a writeonly tensor? How do two SPIR-V types noalias? How do even two memrefs noalias when the default conversion to LLVM produces two pointers that precisely do alias each other?

These are useful concepts to have at this level, but they should be modeled with the sufficient generality. We quite likely want to leverage, e.g., memref's multidimensional and structured nature to capture more fine-grained information than we can about two opaque pointers with noalias. Consider posting on Discourse to discuss how to model these properly.

In the meantime, I checked the implementation, and I don't see anything that would prevent one from using llvm.noalias and the likes as an argument attribute in a func.func and regardless of the type.

Understood. This is as you said just lifting these attributes, a future change would use them and I will post it as an RFC to discuss. This change can wait for that, just trying to flush some trivial parts from my backlog.

As an example to answer some of your questions, take:

func.func @conv_relu(%arg0 : tensor<*xf32>, %arg1 : tensor<*xf32>) -> tensor<*xf32> {
  ...
  return %result : tensor<*xf32>
}

Since tensors are PBV, we can tag the inputs as 'readonly' and the results as 'writeonly' as we know the function cannot read and will fully write the result.

func.func @conv_relu(%arg0 : tensor<*xf32> {func.readonly, func.noalias}, %arg1 : tensor<*xf32> {func.readonly, func.noalias}) -> tensor<*xf32> {func.writeonly, func.noalias} {
  ...
  return %result : tensor<*xf32>
}

Then bufferization will take care to keep the specified attributes when moving results to out params:

func.func @conv_relu(%arg0 : memref<*xf32> {func.readonly, func.noalias}, %arg1 : memref<*xf32> {func.readonly, func.noalias}, %arg2 : memref<*xf32> {func.writeonly, func.noalias}) {
  ...
  return
}

Then one can reason about how a function will interact with the memory references that are passed to it. Further, the func can be optimized more aggressively knowing that loads/stores are independent.

ftynse resigned from this revision.Jul 20 2023, 4:56 AM