This is an archive of the discontinued LLVM Phabricator instance.

[mlir][emitc] Add a variable op
ClosedPublic

Authored by marbre on Feb 17 2022, 4:05 PM.

Details

Summary

This adds a variable op, emitted as C/C++ locale variable, which can be
used if the emitc.constant op is not sufficient.

As an example, the canonicalization pass would transform

mlir
%0 = "emitc.constant"() {value = 0 : i32} : () -> i32
%1 = "emitc.constant"() {value = 0 : i32} : () -> i32
%2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
%3 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr<i32>
emitc.call "write"(%2, %3) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()

into

mlir
%0 = "emitc.constant"() {value = 0 : i32} : () -> i32
%1 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
%2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
emitc.call "write"(%1, %2) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()

resulting in pointer aliasing, as %1 and %2 point to the same address.
In such a case, the emitc.variable operation can be used instead.

Diff Detail

Event Timeline

marbre created this revision.Feb 17 2022, 4:05 PM
marbre requested review of this revision.Feb 17 2022, 4:05 PM

As an example, the canonicalization pass would transform

func @myfunc() {
  %0 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %1 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  %3 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr<i32>
  emitc.call "write"(%2, %3) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
  return
}

into

func @myfunc() {
  %0 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %1 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  %2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  emitc.call "write"(%1, %2) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
  return
}

resulting in pointer aliasing. Here, the variable op would be helpful.

As an example, the canonicalization pass would transform

func @myfunc() {
  %0 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %1 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  %3 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr<i32>
  emitc.call "write"(%2, %3) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
  return
}

into

func @myfunc() {
  %0 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %1 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  %2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  emitc.call "write"(%1, %2) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
  return
}

resulting in pointer aliasing. Here, the variable op would be helpful.

Could you elevate this to be part of the commit description and expand on the pains? (I think you'd want to expand in the op descriptions too what variety to use and why).

mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
156

The sentence leaves me confused as to what is or isn't supported (can do basic and exoric types, so what's missing?)

160

I think here could be good to expand when one would use this via constant (and same constant side add comment that it shouldn't be assumed to be materialized, and then it seems we may also want to flag in the verifier if you want to take an address of a constant)

mlir/test/Dialect/EmitC/ops.mlir
27

This is using the generic syntax, so unclear what is being tested? (Printing and parsing generically tested elsewhere)

marbre edited the summary of this revision. (Show Details)Feb 23 2022, 6:47 AM
marbre updated this revision to Diff 410810.Feb 23 2022, 6:52 AM

Address review comments

As an example, the canonicalization pass would transform

func @myfunc() {
  %0 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %1 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  %3 = emitc.apply "&"(%1) : (i32) -> !emitc.ptr<i32>
  emitc.call "write"(%2, %3) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
  return
}

into

func @myfunc() {
  %0 = "emitc.constant"() {value = 0 : i32} : () -> i32
  %1 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  %2 = emitc.apply "&"(%0) : (i32) -> !emitc.ptr<i32>
  emitc.call "write"(%1, %2) : (!emitc.ptr<i32>, !emitc.ptr<i32>) -> ()
  return
}

resulting in pointer aliasing. Here, the variable op would be helpful.

Could you elevate this to be part of the commit description and expand on the pains? (I think you'd want to expand in the op descriptions too what variety to use and why).

Thanks for the review @jpienaar! I have updated the commit description and expanded the op description. Please let me know if these changes are sufficient form your point of view.

mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
156

The emitter currently supports integer, float, index and tuple types as well as a subset of tensor types (e.g. a static shape is needed). In addition the emitc types are of course supported. The sentence is mainly a take over from the emitc.constant operation, so I think it might be fine to leave as is?

160

I elaborated more on what kind of code this allows to write and that it is intended to be used with pointers. Refactoring the emitc.apply and emitc.constant operations (as you mentioned taking the address of a constant is not a good idea) will be addressed in a followup. I would prefer to refactor the downstream users first to not break things within an integration commit that ships all changes at once.

mlir/test/Dialect/EmitC/ops.mlir
27

I removed the test.

jpienaar accepted this revision.Feb 23 2022, 9:11 AM
jpienaar added inline comments.
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
160

SGTM (perhaps add a TODO for interim)

This revision is now accepted and ready to land.Feb 23 2022, 9:11 AM
This revision was automatically updated to reflect the committed changes.
marbre added inline comments.Feb 24 2022, 7:32 AM
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
160

Fair enough. Added TODOs to the apply and constant op.