[LLVMdev] Predicated Vector Operations

Arnold Schwaighofer aschwaighofer at apple.com
Thu May 9 14:15:23 PDT 2013


On May 9, 2013, at 3:05 PM, Jeff Bush <jeffbush001 at gmail.com> wrote:

> On Thu, May 9, 2013 at 8:10 AM,  <dag at cray.com> wrote:
>> Jeff Bush <jeffbush001 at gmail.com> writes:
>> 
>>> %tx = select %mask, %x, <0.0, 0.0, 0.0 ...>
>>> %ty = select %mask, %y, <0.0, 0.0, 0.0 ...>
>>> %sum = fadd %tx, %ty
>>> %newvalue = select %mask, %sum, %oldvalue
>>> 
>>> I believe the generated instructions depend on whether %oldvalue is
>>> still live after the last instruction. If it is, you need to generate
>>> two instructions: a copy into a new physical register then predicated
>>> write to it.  If it is not used, then it is just a predicated write to
>>> the same register.
>>> 
>>>  move r1, r0
>>>  fadd r1{m0}, r2, r3
>>> 
>>> (r0 is now %oldvalue and r1 is %newvalue)
>>> 
>>> vs.
>>> 
>>>  fadd r0{m0}, r2, r3
>>> 
>>> (r0 was %oldvalue and is now %newvalue)
>> 
>> I'm assuming some parts of %oldvalue are still used.  The masked fadd
>> could preserve them for false values of the mask, depending on how
>> masking was defined.  Therefore, there's no need for a register copy.
>> If the masked operation does not preserve the old values in r0, then we
>> do need a register copy.
>> 
>> Preserving old values does complicate things for SSA, as you note.
>> 
>>>> The bottom line is that it is probably easier to set this up before LLVM
>>>> IR goes into SSA form.
>>> 
>>> That makes sense, but it's unclear to me how you would preserve that
>>> information after going into SSA form.
>> 
>> I should think the semantics of select would handle that.  After a
>> select all vector elements of the result are defined.  There is no
>> preservation of old values.  There cannot be, by definition of SSA.
>> 
>>> It seems to me that these are not really LLVM issues as much as the
>>> fact that SSA doesn't cleanly map to predicated instructions.
>> 
>> It entirely depends on how the predication is defined to work.
> 
> Good point.  I was thinking of it narrowly as preserving the old value
> in the register.  I guess I'd amend my previous statement to say that
> it actually does map just fine to SSA, but instruction selection
> becomes more complex.
> 
> It sounds like the current LLVM instruction selection algorithm can't
> really handle the use case I described cleanly (generating predicated
> arithmetic instructions that preserve the old register value).  Is
> that a fair statement?


I don’t think this is a fair statement. Tied register operands should handle this use case just fine. This problem is similar to that of two-address constraints. Two address instructions work as follows. When we match an instruction we “tie” input and output registers.

Say you had an LLVM-IR add:

x = add i32 y, z

for x86 we generate the following machine ir instruction during ISel:

vr0<def, tied1> = ADD32rr vr1<use, tied0>, vr2<use>

Once we go out of SSA during CodeGen we have to replace the two address constraint by copies:

vr0 = vr1
vr0 = ADD32rr vr0, vr2

Coalescing and allocation will then take care of removing unnecessary copies. I think that predicate instructions would be handled similar (for the sake of making the example shorted I replaced your sequence of IR instruction by one “virtual” IR instruction):

x = predicated_add %mask, %x, %y, %oldvalue

This (actually, your sequence of selects, and add) would be matched during ISel to:

vr0<def, tied1> = PRED_ADD mask_vr, vr1<use>, vr2<use>, vr3<use, tied0>

>From here on the machinery is the same, the two-address pass would translate such instructions to:

vr0 = vr3
vr0 = PRED_ADD mask_vr, vr1, vr2, vr0

If vr3 is not live after PRED_ADD coalescing will coalesce vr0 and vr3. I don’t think there is a fundamental difficulty handling predictated instructions this way - at least wrt. to register constraints.



More information about the llvm-dev mailing list