Low level representation

as far as I understand, Memref stands for a piece of memory which can be heap memory or stack memory.
Is there register-level representation in MLIR or known reference work?
register-level might includes:
mov instruction
register allocate

if there is no reference work,
could you please suggest how to represents register allocate, op, type by MLIR?

thank you for reviewing this issue and share your insight.

In the RFC for SME there was also talk about registers in MLIR.

You could define a new type RegisterBank. One for GPR and one for FPR. Then you can define mov instructions resp. operations.

1 Like

In general, values of most first-class types such as vectors, integers, and floats can be seen as registers.

Overall it’s not recommended to deal with register semantics in SSA (that includes mlir and llvm ir), and it’s better to leave it to the backend to handle during the register allocation step.

1 Like

To give you the next example, the MLIR Toy dialect defined a struct. The struct fields could be seen as registers and the struct could be seen as a register bank.

1 Like

what do you mean by FPR ?
do you mean SPR (special purpose register) ?

you are right, it should be role of backend.
my first idea is to make simular pipeline in backend to handle registers
bufferization for register
register allocation

do you think it is reasonable?

compared RegisterBank struct, which one is more suitable?
could you please give me some advices?

may I ask why do you suggest to use struct type ?

def RegBank : …
def MovOp:
ins RegBank : dst , RegBank : src

def MovImmOp:
ins RegBank : dst, IntegerType: src
imagine there are 20 GPRs, how to know which register is used or how register allocation works based on this definition?

by the way, my first idea is to define single register type.
similar with memref dialect, alloca op is defined to manage registers
how do you think about this?

In general, registers can be modeled as memory. The specific modeling will be architecture- and task-specific. It can be one indexable “register file” type as suggested above, with indices potentially being more complex than just numbers (e.g., one can have rax/rsp/r42 instead of numbers for x86). It can also be one type per specific register, especially when some operations/instructions can only work with very specific registers. And anything in between.

It is a good idea to introduce an interface for such types, something similar to what is defined in MemorySlotInterfaces.td.

I generally wouldn’t expect these operations to operate on SSA values, except maybe for immediates that may be modeled as constants. So a load from memory would look something like lowlevel_asm.load_vector : (!lowlevel_asm.rax) -> !lowlevel_asm.zmm where %rax contains the memory address and %zmm will contain the loaded values.