Getting original types in dialect converter

Maybe this is just me not understanding the docs properly, but I find myself needing the original types when lowering our dialect to LLVM.

However, when we start rewriting instructions, we call the type converter, and the resulting types get propagated with op->replaceAllUsesWith(newOp), so when the next instruction is rewritten the op argument values is of the new operation type which means we have no idea what the original type was which is important in our case as we are trying to lower a complex struct like thing to something that is mostly type erased in LLVM land and interacted with through a runtime.

With exception of manually building up maps for how types are remapped during conversion, is there anyway to get the original type before type conversion in a conversion pass?

To get an idea of what we are trying to do exactly, we have a struct like type and some operations (load/store) that operate with index-sequences on the struct. In principle these would work like a combined gep and load/store operation. When entering LLVM land, the types must be generalised due to complex binary layouts that can only be computed at runtime (e.g. nested variable length arrays in the middle of the object), so the general type translation is to a struct: {i8*, i8*} containing a begin and end pointer.

So what our conversion passes then sees is then primarily the {i8*, i8*} type instead of our high level struct like type, which means that we have lost the original type of the operand value, this in turn makes it impossible to synthesise our runtime calls.

Maybe it is just me being confused about this though? :confused:

How do you implement the conversion? You should be using the dialect conversion infrastructure (and not calling replaceAllUsesWith in any place yourself). In that infrastructure, the original operation is preserved, together with its operands, until you apply the entire conversion. In each pattern, the matchAndRewrite function takes an operation that can be inspected to extract the original types, and a separate list of converted operands. Here’s an example of lowering std.load that inspects the original memref type of the load.

Indeed, I should have called rewriter.replaceOp() instead.