Instruction selection pattern for intrinsic returning llvm_any_ty

Hi,

On my out-of-tree target I have an intrinsic

def int_phx_divm_u16 : Intrinsic<[llvm_any_ty],
                                  [llvm_i16_ty, llvm_i16_ty],
                                  [IntrNoMem]>;

that I want to translate to the following instruction during instruction selection:

def divm16_pseudo : MyPseudoInst<
     (outs aNh_0_7:$dst, aNh_0_7:$dst2),
     (ins aNh_0_7:$src1, aNh_0_7:$src2)>;

So I've done a pattern the same way I've done for numerous other intrinsics (that returns simple types like i16/i32 etc):

def : Pat<(int_phx_divm_u16 i16:$src1, i16:$src2),
           (divm16_pseudo $src1, $src2)>;

But this doesn't work for me:

anonymous_1373(src1, src2): (divm16_pseudo:i16:i16:i16 ?:i16:$src1, ?:i16:$src2)

error: In anonymous_1373: Type inference contradiction found, merging 'i16' into 'Any'
def : Pat<(int_phx_divm_u16 i16:$src1, i16:$src2),
^

So is there a way I can get around this?

Before ISel the call to my intrisic looks like

   %_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

and %rec6 is

   %rec6 = type { i16, i16 }

Then at ISel, before selection the call is lowered to

   t6: i16,i16 = llvm.phx.divm.u16 TargetConstant:i16<3778>, t2, t4

which fits nicely to my divm16_pseudo that I want to select.

Is there any way I can select this with a tablegen pattern, and not having to do selection "manually" in my target's MytargetDAGToDAGISel::Select function?

I'm having a bunch of intrisics looking like this and I'd prefer selecting them with patterns rather than doing much more verbose stuff in C++.

I've tried to look in in-tree targets for something similar but I've failed to find anything.

Thanks,
Mikael

Hi,

On my out-of-tree target I have an intrinsic

def int_phx_divm_u16 : Intrinsic<[llvm_any_ty],
                                [llvm_i16_ty, llvm_i16_ty],
                                [IntrNoMem]>;

that I want to translate to the following instruction during instruction selection:

def divm16_pseudo : MyPseudoInst<
   (outs aNh_0_7:$dst, aNh_0_7:$dst2),
   (ins aNh_0_7:$src1, aNh_0_7:$src2)>;

So I've done a pattern the same way I've done for numerous other intrinsics (that returns simple types like i16/i32 etc):

def : Pat<(int_phx_divm_u16 i16:$src1, i16:$src2),
         (divm16_pseudo $src1, $src2)>;

It isn’t able to infer the type of the divm16_pseudo instruction, which would be necessary depending on whether the result’s register class for divm16_pseudo includes other types. I would expect you would need to add an explicit i16 around the instruction (e.g. (i16 (divm16_pseudo …)), tlahough the error message does look like it’s having trouble with the operands. You can try inserting the explicit i16:$src1 there if that still doesn’t work

Hi,

Hi,

On my out-of-tree target I have an intrinsic

def int_phx_divm_u16 : Intrinsic<[llvm_any_ty],
                                 [llvm_i16_ty, llvm_i16_ty],
                                 [IntrNoMem]>;

that I want to translate to the following instruction during instruction selection:

def divm16_pseudo : MyPseudoInst<
    (outs aNh_0_7:$dst, aNh_0_7:$dst2),
    (ins aNh_0_7:$src1, aNh_0_7:$src2)>;

So I've done a pattern the same way I've done for numerous other intrinsics (that returns simple types like i16/i32 etc):

def : Pat<(int_phx_divm_u16 i16:$src1, i16:$src2),
          (divm16_pseudo $src1, $src2)>;

It isn’t able to infer the type of the divm16_pseudo instruction, which would be necessary depending on whether the result’s register class for divm16_pseudo includes other types. I would expect you would need to add an explicit i16 around the instruction (e.g. (i16 (divm16_pseudo …)), tlahough the error message does look like it’s having trouble with the operands. You can try inserting the explicit i16:$src1 there if that still doesn’t work

Thanks!

Adding i16 on the arguments to my instruction

def : Pat<(int_phx_divm_u16 i16:$src1, i16:$src2),
           (divm16_pseudo i16:$src1, i16:$src2)>;

now gives me

anonymous_1654: (divm16_pseudo:i16:i16:i16 i16:i16:$src1, i16:i16:$src2)

error: In anonymous_1654: Type inference contradiction found, merging 'i16' into 'Any'
def : Pat<(int_phx_divm_u16 i16:$src1, i16:$src2),
^

So at least it doesn't say "?" on the arguments anymore, but then I still get the same error about merging i16 and Any.

Since the divm16_pseudo instruction (and the lowered call to the intrinsic) defines two i16 values, what would be the syntax for the

(i16 (divm16_pseudo …)

stuff?

I've tried
(i16, i16 (divm16_pseudo i16:$src1, i16:$src2)
and
((i16, i16) (divm16_pseudo i16:$src1, i16:$src2)
and a few other variants without managing to get it through.

Thanks again,
Mikael

Are you trying to return multiple values?

Hi,

i16 (divm16_pseudo …)

stuff?

I've tried
(i16, i16 (divm16_pseudo i16:$src1, i16:$src2)
and
((i16, i16) (divm16_pseudo i16:$src1, i16:$src2)
and a few other variants without managing to get it through.

Thanks again,
Mikael

Are you trying to return multiple values?

Yes, the intrisic returns a record

   %rec6 = type { i16, i16 }

so at instructions selection the original call

   %_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

has been lowered to

   t6: i16,i16 = llvm.phx.divm.u16 TargetConstant:i16<3778>, t2, t4

and the instruction I want to select also returns two values

def divm16_pseudo : MyPseudoInst<
     (outs aNh_0_7:$dst, aNh_0_7:$dst2),
     (ins aNh_0_7:$src1, aNh_0_7:$src2)>;

Both outs are i16.

/Mikael

The intrinsic itself should define multiple IR outputs rather than using any ty. I’m also not sure if tablegen currently supports patterns with multiple results

-Matt

Hi,

i16 (divm16_pseudo …)

stuff?

I've tried
(i16, i16 (divm16_pseudo i16:$src1, i16:$src2)
and
((i16, i16) (divm16_pseudo i16:$src1, i16:$src2)
and a few other variants without managing to get it through.

Thanks again,
Mikael

Are you trying to return multiple values?

Yes, the intrisic returns a record

  %rec6 = type { i16, i16 }

so at instructions selection the original call

  %_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

has been lowered to

  t6: i16,i16 = llvm.phx.divm.u16 TargetConstant:i16<3778>, t2, t4

and the instruction I want to select also returns two values

def divm16_pseudo : MyPseudoInst<
    (outs aNh_0_7:$dst, aNh_0_7:$dst2),
    (ins aNh_0_7:$src1, aNh_0_7:$src2)>;

Both outs are i16.

/Mikael

The intrinsic itself should define multiple IR outputs rather than using any ty.

But the intrinsic returns a record so in the input ll-file it is one result

%_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

and then the return value struct is lowered to two i16:s by

SelectionDAGISel::SelectBasicBlock:

   // Lower the instructions. If a call is emitted as a tail call, cease emitting
   // nodes for this block.
   for (BasicBlock::const_iterator I = Begin; I != End && !SDB->HasTailCall; ++I)
     SDB->visit(*I);

just prior to the selection.

I’m also not sure if tablegen currently supports patterns with multiple results

Yes, me neither...

/Mikael

Hi,

i16 (divm16_pseudo …)

stuff?

I’ve tried
(i16, i16 (divm16_pseudo i16:$src1, i16:$src2)
and
((i16, i16) (divm16_pseudo i16:$src1, i16:$src2)
and a few other variants without managing to get it through.

Thanks again,
Mikael

Are you trying to return multiple values?

Yes, the intrisic returns a record

%rec6 = type { i16, i16 }

so at instructions selection the original call

%_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

has been lowered to

t6: i16,i16 = llvm.phx.divm.u16 TargetConstant:i16<3778>, t2, t4

and the instruction I want to select also returns two values

def divm16_pseudo : MyPseudoInst<
(outs aNh_0_7:$dst, aNh_0_7:$dst2),
(ins aNh_0_7:$src1, aNh_0_7:$src2)>;

Both outs are i16.

/Mikael

The intrinsic itself should define multiple IR outputs rather than using any ty.

But the intrinsic returns a record so in the input ll-file it is one result

%_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

and then the return value struct is lowered to two i16:s by

This seems like a strange way to do it. Do you need it to be an arbitrary struct type for some reason? Having multiple result types that expand into a struct would be more normal

Hi,

The intrinsic itself should define multiple IR outputs rather than
using any ty.

But the intrinsic returns a record so in the input ll-file it is one
result

%_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

and then the return value struct is lowered to two i16:s by

This seems like a strange way to do it. Do you need it to be an
arbitrary struct type for some reason?

Not really.
At the C level we have

typedef struct {
     __u16_t quotient;
     __u16_t remainder;
} __divm16_t;

__divm16_t __divm_u16(__u16_t, __u16_t);

and our frontend translates calls to this function to calls to our intrisic

%_tmp3 = call %rec6 @llvm.phx.divm.u16.rec6(i16 %_tmp1, i16 %_tmp2)

and then we translate it tou our hardware instruction divm (which produces two i16 values).

We could probably change our frontend so the intrinsic produces two values rather than the struct, but if tablegen will not accept a pattern with multiple results (which I've no idea if it does or not, but at least I don't know what the syntax would be for it) we won't gain anything from this anyway.

The code we have works, only that we need to handle all instrisics like this "manually" in ISelDAGToDAG and I would prefer to write patterns for the selection instead, but it seems it's not very straight forward, if even possible.

Thanks for your help,
Mikael