Matching Against Two Patterns with the Same Operand Types

Hello everyone,

I am working on a target in which all addresses are held in separate address registers. I have implemented a calling convention that assigns pointers to these registers. But at the time of instruction selection, the matching is happening via the operand type which is i32 for both addresses and non addresses rather than the input Register Class which is what I assumed it would match against. How do I distinguish between addresses and non addresses in this situation?

Here is some more concrete context to my problem. The following is an instruction definition

multiclass ST<string opcodestr> {
  def 32ai
  : XInst<(outs), (ins AddrReg:$aZ32, MEMri:$addr),
            "st32", "$aZ32, $addr",
            [(store AddrReg:$aZ32, Addr:$addr)]>;

  def 32ri
  : XInst<(outs), (ins Int32Reg:$rZ32, MEMri:$addr),
            "st32", "$rZ32, $addr",
            [(store Int32Reg:$rZ32, Addr:$addr)]>;

For the following IR

define void @foo(i16* %a, i32 %b) {
  %a.addr = alloca i16*, align 4
  %b.addr = alloca i32, align 4
  store i16* %a, i16** %a.addr, align 4
  store i32 %b, i32* %b.addr, align 4
  %0 = load i16*, i16** %a.addr, align 4
  %1 = load i32, i32* %b.addr, align 4
  ret void

the corresponding machine code is

0B  bb.0.entry:
    liveins: $a4, $d0
16B   %1:int32reg = COPY killed $d0
32B   %0:addrreg = COPY killed $a4
48B   %2:addrreg = COPY killed %1:int32reg
64B   ST32ai killed %2:addrreg, %stack.1.b.addr, 0 :: (store 4 into %ir.b.addr)
80B   ST32ai killed %0:addrreg, %stack.0.a.addr, 0 :: (store 4 into %ir.a.addr)
96B   RET

In the machine code, there is an implicit copy from int32reg to addrreg to match the first store instruction which has the operand type i32.

It would be really helpful to get some pointers on what I could do to get my expected outcome. TIA!

The register class selection is informed by the types in your pattern, not the other way around.

In SelectionDAG there’s no good way to do what you want. In GlobalISel, pointer types are preserved through selection so you could directly select based on whether the value is a pointer.

Assuming you can copy between AddrReg and Int32Reg, you could just always select to the integer version. You could then have an optimization pass looking for copies from AddrReg and swapping out the use instruction.

1 Like

Thank you for the reply. This was very helpful.