This is an archive of the discontinued LLVM Phabricator instance.

[mlir] Add InlineAsmOp to standard
AbandonedPublic

Authored by nicolasvasilache on Nov 27 2020, 1:31 AM.

Details

Summary

This revision adds std.inline_asm which is a counterpart to llvm.inline_asm that operates on MLIR types.

This allows connecting MLIR to actual assembly.

Arguably this should not be another addition to standard.
The discussion on splitting standard is ongoing.
If people see a new dialect I should add this to I'd be happy to just create it if it helps distribute the burden: please make a suggestion if you want this op in a different dialect than std.

Diff Detail

Event Timeline

Herald added a project: Restricted Project. · View Herald Transcript
nicolasvasilache requested review of this revision.Nov 27 2020, 1:31 AM

I would prefer that we don't use the fact that there are discussions to split standard as a potential means to forgo the need to justify the addition/representation of a new operation. Each new op should have proper discussion around its representation and how it fits, irregardless of how the standard dialect discussion progresses.

mlir/include/mlir/Dialect/StandardOps/IR/Ops.td
2002

This looks extremely tied to LLVM and not something general enough for standard, even in its current state. Can you post an RFC with discussion on how you want to represent inline assembly? If this is something that intends to be outside of the LLVM dialect domain, I'd like to see proper discussion on its representation and not just cargocult the restricted LLVM form. I would prefer we are cautious not to just copy over LLVM representations to the non LLVM parts of MLIR, otherwise this just becomes a copy of the LLVM dialect with the MLIR type system.

2002

"Its current state" -> the current state of the standard dialect.

rriddle added inline comments.Nov 27 2020, 2:00 AM
mlir/include/mlir/Dialect/StandardOps/IR/Ops.td
2002

As a more concrete comment, I wouldn't expect a standard dialect operation to have a hard coded assumption about LLVM given that not all lowerings go to LLVM. There are also comments on the meaning of "assembly" in an MLIR context, the representation of side effects, and more.

To the extent that this is just a mirror of the LLVM dialect inline_asm, maybe we could consider an asm dialect that has inline and eventually func operations and that accepts both a subset of standard (scalars) and LLVM types.

mlir/include/mlir/Dialect/StandardOps/IR/Ops.td
2002

Re. "tied to LLVM" and "I wouldn't expect a standard dialect operation to have a hard coded assumption about LLVM given that not all lowerings go to LLVM", I think this is a more general issue for which I'd love a good agreed upon solution.

I started https://llvm.discourse.group/t/exposing-llvm-ops-to-the-mlir-type-system/2290 to discuss this.

Re. "There are also comments on the meaning of "assembly" in an MLIR context, the representation of side effects, and more."

Yes absolutely, another one that comes to mind is what happens with the data type lowering and how things will break in various ways when the assembly says "1 register" and the action at a distance of lowering the value + type through LLVM and LLC has no guarantees about that.

The answer is I don't know yet.
But we don't have to to solve all problems at the same time to make progress, which ties back to discussion in the link above.

rriddle added a comment.EditedNov 27 2020, 2:49 AM

(Accidental half post)

mlir/include/mlir/Dialect/StandardOps/IR/Ops.td
2002

Thanks for raising that RFC, I really appreciate it! I think this is a really important discussion to have to prevent stalling progress in other areas.

mehdi_amini requested changes to this revision.Nov 27 2020, 11:21 AM

Inline assembly is a huge can of worm, I'd like that we don't take this lightly. This is independent of the general question about how to expose LLVM intrinsics to MLIR.

A particular example is how inline assembly can access global variables for example which bypass the symbol resolution mechanism in MLIR.

This revision now requires changes to proceed.Nov 27 2020, 11:21 AM

Inline assembly is a huge can of worm, I'd like that we don't take this lightly. This is independent of the general question about how to expose LLVM intrinsics to MLIR.

A particular example is how inline assembly can access global variables for example which bypass the symbol resolution mechanism in MLIR.

Happy to restrict to not using or defining any symbol and global variables and that everything else is UB.
Would that be reasonable?
Can this be checked to emit warnings/errors?

The cases we are interested in supporting atm are the cases library folks write asm to do unimpeded ISel and RA without compiler interference.
We want to be able to interop with such existing key pieces of assembly.

I just quickly browsed the bug btu what is the level of footgun protection in say C + asm ?
I'd think it is a fundamental property of asm in general that you can hurt yourself unless you're an expert: nothing prevents hardcoding a jump to some address and doing whatever.

I just quickly browsed the bug btu what is the level of footgun protection in say C + asm ?

Nothing: it is just left to the user I think.

I'd think it is a fundamental property of asm in general that you can hurt yourself unless you're an expert: nothing prevents hardcoding a jump to some address and doing whatever.

Possibly, but I am not convinced we should just inherit the same messy situation in MLIR. Right now I don't even know why we should add inline assembly at all: what can't you do by having an external library and calling into it?

Possibly, but I am not convinced we should just inherit the same messy situation in MLIR. Right now I don't even know why we should add inline assembly at all: what can't you do by having an external library and calling into it?

Besides avoiding make it unnecessarily complex, isn't the point of inline assembly to connect without indirection?
I am not fully aware of all the use cases but I'd imagine some of the constraints in the constraints string behave differently across function boundaries?
Isn't having an external library (written in assembly) displacing the problem?

Also, please respond to this:

Happy to restrict to not using or defining any symbol and global variables and that everything else is UB.
Would that be reasonable?

Do you still foresee the problematic behaviors you mentioned with these restrictions ?

Also, please respond to this:

Happy to restrict to not using or defining any symbol and global variables and that everything else is UB.
Would that be reasonable?

Do you still foresee the problematic behaviors you mentioned with these restrictions ?

UB is always a problem: it "may works in practice sometimes and people will rely on it". I'd say that UB without a sanitizer is rarely a good idea. In general deterministic failure, compile-time if possible and runtime otherwise is preferable.

-1 from me too on having this in standard. Inline ASM (given our frontends) is in the "I didn't care enough to model this as an intrinsic or op/my machine scheduler modelling isn't good enough/I need an escape hatch to do things which are invalid but work for my case". I wouldn't want to encourage any of that in standard though.

To the extent that this is just a mirror of the LLVM dialect inline_asm, maybe we could consider an asm dialect that has inline and eventually func operations and that accepts both a subset of standard (scalars) and LLVM types.

Why not just have it in llvm dialect (pseudo_inline_asm) and have it behave as you would here and relax type constraints on it? Having ASM dialect that depends on LLVM dialect also seems weird, feels like this op is a to help lowering to llvm and there only, so put it there. It should always be lowered away once everything is in LLVM. I haven't read the other discussion so don't know if the option of having casts back and forth that just fold away during lowering was discussed already.

"I didn't care enough to model this as an intrinsic or op/my machine scheduler modelling isn't good enough/I need an escape hatch to do things which are invalid but work for my case".

I don't disagree with the rest and will happily use any solution we find reasonable to expose LLVM ops to MLIR types.

I'll comment on this particular part on the "machine schedule modeling" though: this is a decades-old problem: ISel + RA + scheduling is a hard problem; compiler use heuristics (a.k.a human-engineered features) and when you really care about perf, it can often "get it wrong".
For such key pieces of SW, the compiler ends up being an impediment that library writers have to work around (even with intrinsics).
It is a fact that code that runs in production, on virtually all HW, relies on inline asm, sometimes heavily.

Maybe there are very good solutions in the fullness of time but note that all these things happen in LLVM, at a pretty big distance from MLIR std.

silvas added a subscriber: silvas.Nov 30 2020, 1:41 PM

Also big -1 from me. Too big of a can of worms. I don't think there is anything useful in the "inline asm" design space we can do in MLIR in the near-term (or even medium term) other than just having an llvm dialect op that mirrors the LLVM IR inline asm construct (and maybe some minor sugar around it, but still just a convenience pseudo-op around the low-level one that mirrors the LLVM IR construct).

FWIW, I'm extremely sympathetic to the desire to write inline asm... compiler scheduling/RA is never enough for the tail of use cases. I just think that anything we realistically do here other than mirroring LLVM is going to be a step in the wrong direction / have major unexpected issues.

nicolasvasilache abandoned this revision.Dec 7 2020, 6:02 AM