Exposing LLVM ops to the MLIR type system

Well, I actually discussed this exact point in the RFC on reimplementing LLVM dialect types. I am still of the opinion that trying to use builtin types in the LLVM dialect creates significantly more complexity than it removes. Here are some examples:

  • MLIR integers can be signed, unsigned and signless; LLVM IR integers are singless only. This is a strict superset and can be handled by the verifier. Well, op verifier because we don’t have type verifiers.
  • LLVM IR supports floating point types that MLIR does not - x86_fp80, ppc_fp128, etc. So we will end up having llvm.fadd %0, %1 : f32 and llvm.fadd %0, %1 : !llvm.x86_fp80 and needing to remember if we should use a builtin type or a dialect type for a specific bitwidth. This starts getting awkward.
  • MLIR has nD vectors but no scaling, LLVM IR has 1D vectors and scaling. We will have to mix LLVM dialect vectors and MLIR vectors + additional restrictions on the latter, unless somebody is willing to propose scalable vectors as a built-in type. This is getting worse.
  • LLVM types can contain other types. Now, we have !llvm.struct<(i32, float, x86_fp80)> and all the inner types are LLVM dialect types. If, instead, i32 was an builtin type, we would need extra logic in many places where container types are used, and in the types themselves, to differentiate whether a builtin or a dialect type is used. Types also don’t have verifiers, so almost any construction of a container type will need to be guarded against nullptr result (even if we could create a wrapper LLVMOrBuiltInIntegerType, signedness semantics is not encoded in the C++ type and LLVM container types would reject non-signless types by producing nulls).
  • The syntax for containers will explode, it currently uses the fact that nested types are implicitly !llvm.
  • The translation to LLVM IR will have to handle both kinds of types, and we explicitly wanted the translation to be simple. (We could have a big “legalization before export” pass that changes types to LLVM, but that would mean we also keep all LLVM types). This was actually the entire point of creating the LLVM dialect rather than translating Standard directly, if you want a historical perspective.

I am open to considering builtin type values in a dialect based on intrinsics, which mostly use simple types, as suggested above, but not to overhauling the type system.