[llvm-dev] Instruction selection pattern for intrinsic returning llvm_any_ty

241 views
Skip to first unread message

Mikael Holmén

unread,
Mar 30, 2016, 3:34:32 AM3/30/16
to llvm...@lists.llvm.org
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
_______________________________________________
LLVM Developers mailing list
llvm...@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

Matt Arsenault via llvm-dev

unread,
Mar 30, 2016, 5:15:21 AM3/30/16
to Mikael Holmén, llvm...@lists.llvm.org

> On Mar 30, 2016, at 09:33, Mikael Holmén via llvm-dev <llvm...@lists.llvm.org> wrote:
>
> 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

Mikael Holmén

unread,
Mar 30, 2016, 5:36:16 AM3/30/16
to Matt Arsenault, llvm...@lists.llvm.org
Hi,

On 03/30/2016 11:15 AM, Matt Arsenault wrote:
>
>> On Mar 30, 2016, at 09:33, Mikael Holmén via llvm-dev <llvm...@lists.llvm.org> wrote:
>>
>> 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

Matt Arsenault via llvm-dev

unread,
Mar 30, 2016, 5:38:12 AM3/30/16
to Mikael Holmén, llvm...@lists.llvm.org

On Mar 30, 2016, at 11:35, Mikael Holmén <mikael...@ericsson.com> wrote:

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? 

Mikael Holmén

unread,
Mar 30, 2016, 5:43:27 AM3/30/16
to Matt Arsenault, llvm...@lists.llvm.org
Hi,

On 03/30/2016 11:38 AM, Matt Arsenault wrote:
>
>> On Mar 30, 2016, at 11:35, Mikael Holmén <mikael...@ericsson.com

>> <mailto:mikael...@ericsson.com>> wrote:
>>
>> 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

Matt Arsenault via llvm-dev

unread,
Mar 30, 2016, 5:51:34 AM3/30/16
to Mikael Holmén, llvm...@lists.llvm.org

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

Mikael Holmén

unread,
Mar 30, 2016, 5:58:42 AM3/30/16
to Matt Arsenault, llvm...@lists.llvm.org

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

Matt Arsenault via llvm-dev

unread,
Mar 30, 2016, 6:01:17 AM3/30/16
to Mikael Holmén, llvm...@lists.llvm.org
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

Mikael Holmén

unread,
Mar 30, 2016, 7:14:55 AM3/30/16
to Matt Arsenault, llvm...@lists.llvm.org
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


> Having multiple result types that
> expand into a struct would be more normal
>
>
>>
>> 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
>>
>>>
>>> -Matt
>

_______________________________________________

Reply all
Reply to author
Forward
0 new messages