Tie output operand to subregister of input operand

Hi,

I have an instruction that takes a 64-bit register as input and uses the lower 32-bit subregister as output. I am struggling to define the constraint in TableGen to make this work however.

Originally I had the following constraint:

let Constraint = "$dst = $src" in
def Foo : Instruction<..., (out GPR32:$dst), (ins GPR64:$src), ...>;

This however causes the following code to be produced:

%1:GPR32 = COPY %0:GPR64
%1:GPR32 = Foo %1:GPR32(tied-def 0)

Which causes an error, because the input to Foo must be a GPR64, not a GPR32.

I stumbled across complex operands, i.e. operands with suboperands:

def subregpair : Operand<i64> {
let MIOperandInfo = (ops GPR32:$lo, GPR32:$hi);
}

let Constraint = "$dst = $src.lo" in
def Foo : Instruction<..., (out GPR32:$dst), (ins subregpair:$src), ...>;

However I'm not sure whether I'm using this correctly and if this is even the intended use-case for it, because I now get an error that Foo expects 2 operands, not 1.

Is this even doable in TableGen or will I need to manually fix up the registers somehow?

Cheers,

Dominik

Hi Dominik,

Hi,

I have an instruction that takes a 64-bit register as input and uses the lower 32-bit subregister as output. I am struggling to define the constraint in TableGen to make this work however.

Originally I had the following constraint:

let Constraint = "$dst = $src" in
def Foo : Instruction<..., (out GPR32:$dst), (ins GPR64:$src), ...>;

This however causes the following code to be produced:

%1:GPR32 = COPY %0:GPR64
%1:GPR32 = Foo %1:GPR32(tied-def 0)

Which causes an error, because the input to Foo must be a GPR64, not a GPR32.

I stumbled across complex operands, i.e. operands with suboperands:

def subregpair : Operand<i64> {
  let MIOperandInfo = (ops GPR32:$lo, GPR32:$hi);
}

let Constraint = "$dst = $src.lo" in
def Foo : Instruction<..., (out GPR32:$dst), (ins subregpair:$src), ...>;

However I'm not sure whether I'm using this correctly and if this is even the intended use-case for it, because I now get an error that Foo expects 2 operands, not 1.

I don’t think this is the intended use-case, but what you see is expected. IIRC the complex operands are just a convenient way to setup several operands that are logically connected, but they are still different operands. This is what is used for X86 addressing mode for instance. At the td level, this is just one complex operand (X86Mem) but when the instruction is built, every individual operand needs to be set (see addFullAddress).

Is this even doable in TableGen or will I need to manually fix up the registers somehow?

I don’t think this is doable in TableGen, but take it with a grain of salt, I am no TableGen expert!

If you're okay with losing the upper part of the register (for register allocation purposes), you could model that as a regular 64-bit tied operand followed by an extract_subreg.

Cheers,
-Quentin

Hi Quentin,

thanks for the response. Your suggested work-around is exactly what we're using for the moment. It's a shame that we "lose" the upper bits this way, but guess it's the best we can do for now. Would be nice if this is supported at some point in the future :slight_smile:

Cheers,

Dominik