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.
The sentence leaves me confused as to what is or isn't supported (can do basic and exoric types, so what's missing?)