[llvm] r283838 - [RegAllocGreedy] Attempt to split unspillable live intervals

Quentin Colombet via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 1 14:03:29 PST 2017


Hi Mikael,

Nice catch!

> On Jan 31, 2017, at 11:33 PM, Mikael Holmén <mikael.holmen at ericsson.com> wrote:
> 
> Hi Dylan and Quentin,
> 
> I think I've stumbled upon a problem with this patch. See below.
> 
> On 10/11/2016 03:04 AM, Dylan McKay via llvm-commits wrote:
>> Author: dylanmckay
>> Date: Mon Oct 10 20:04:36 2016
>> New Revision: 283838
>> 
>> URL: http://llvm.org/viewvc/llvm-project?rev=283838&view=rev
>> Log:
>> [RegAllocGreedy] Attempt to split unspillable live intervals
>> 
>> Summary:
>> Previously, when allocating unspillable live ranges, we would never
>> attempt to split. We would always bail out and try last ditch graph
>> recoloring.
>> 
>> This patch changes this by attempting to split all live intervals before
>> performing recoloring.
>> 
>> This fixes LLVM bug PR14879.
>> 
>> I can't add test cases for any backends other than AVR because none of
>> them have small enough register classes to trigger the bug.
>> 
>> Reviewers: qcolombet
>> 
>> Subscribers: MatzeB
>> 
>> Differential Revision: https://reviews.llvm.org/D25070
>> 
>> Added:
>>    llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll
>> Modified:
>>    llvm/trunk/lib/CodeGen/LiveRangeEdit.cpp
>>    llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp
>> 
>> Modified: llvm/trunk/lib/CodeGen/LiveRangeEdit.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/LiveRangeEdit.cpp?rev=283838&r1=283837&r2=283838&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/CodeGen/LiveRangeEdit.cpp (original)
>> +++ llvm/trunk/lib/CodeGen/LiveRangeEdit.cpp Mon Oct 10 20:04:36 2016
>> @@ -438,6 +438,9 @@ LiveRangeEdit::MRI_NoteNewVirtualRegiste
>>   if (VRM)
>>     VRM->grow();
>> 
>> +  if (Parent && !Parent->isSpillable())
>> +    LIS.getInterval(VReg).markNotSpillable();
>> +
> 
> I have a case where the above code actually triggers, but unfortunately it leads to a failed assertion slightly after.
> 
> We have:
> 
> LiveInterval &LiveRangeEdit::createEmptyIntervalFrom(unsigned OldReg) {
>  unsigned VReg = MRI.createVirtualRegister(MRI.getRegClass(OldReg));
> 
> HEre MachineRegisterInfo::createVirtualRegister is called, in turn doing
> 
>   TheDelegate->MRI_NoteNewVirtualRegister(Reg);
> 
> which triggers the code added in the patch above.
> 
> The new VReg doesn't have an interval yet, so
> 
> LIS.getInterval(VReg)
> 
> will actually create one (and compute it)!

We don’t want that.

> 
> However, when we return to LiveRangeEdit::createEmptyIntervalFrom we continue and do
> 
>  if (VRM) {
>    VRM->setIsSplitFromReg(VReg, VRM->getOriginal(OldReg));
>  }
>  LiveInterval &LI = LIS.createEmptyInterval(VReg);
> 
> And here an assertion blows since VReg already has an interval, namely the one created just recently from MRI_NoteNewVirtualRegister.
> 
> Should we check if the new VReg already has an interval before creating it in createEmptyIntervalFrom or should we do something smarter in MRI_NoteNewVirtualRegister or what?

I would lean toward changing the create.*Form method in LRE to do the marking here. We shouldn’t mess up with the interval in MRI_NoteNewVirtualRegister. Though I'm not super happy with that solution either. (Slightly coupled solution.)

Patch attached for convenience.

Let me know if that works for you.

Cheers,
-Quentin

> 
> Found this on my out-of-tree target.
> 
> Regards,
> Mikael
> 
>>   NewRegs.push_back(VReg);
>> }
>> 
>> 
>> Modified: llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp?rev=283838&r1=283837&r2=283838&view=diff
>> ==============================================================================
>> --- llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp (original)
>> +++ llvm/trunk/lib/CodeGen/RegAllocGreedy.cpp Mon Oct 10 20:04:36 2016
>> @@ -2553,18 +2553,20 @@ unsigned RAGreedy::selectOrSplitImpl(Liv
>>     return 0;
>>   }
>> 
>> +  if (Stage < RS_Spill) {
>> +    // Try splitting VirtReg or interferences.
>> +    unsigned NewVRegSizeBefore = NewVRegs.size();
>> +    unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs);
>> +    if (PhysReg || (NewVRegs.size() - NewVRegSizeBefore))
>> +      return PhysReg;
>> +  }
>> +
>>   // If we couldn't allocate a register from spilling, there is probably some
>>   // invalid inline assembly. The base class wil report it.
>>   if (Stage >= RS_Done || !VirtReg.isSpillable())
>>     return tryLastChanceRecoloring(VirtReg, Order, NewVRegs, FixedRegisters,
>>                                    Depth);
>> 
>> -  // Try splitting VirtReg or interferences.
>> -  unsigned NewVRegSizeBefore = NewVRegs.size();
>> -  unsigned PhysReg = trySplit(VirtReg, Order, NewVRegs);
>> -  if (PhysReg || (NewVRegs.size() - NewVRegSizeBefore))
>> -    return PhysReg;
>> -
>>   // Finally spill VirtReg itself.
>>   if (EnableDeferredSpilling && getStage(VirtReg) < RS_Memory) {
>>     // TODO: This is experimental and in particular, we do not model
>> 
>> Added: llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll
>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll?rev=283838&view=auto
>> ==============================================================================
>> --- llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll (added)
>> +++ llvm/trunk/test/CodeGen/AVR/high-pressure-on-ptrregs.ll Mon Oct 10 20:04:36 2016
>> @@ -0,0 +1,78 @@
>> +; RUN: llc < %s -march=avr | FileCheck %s
>> +
>> +; This tests how LLVM handles IR which puts very high
>> +; presure on the PTRREGS class for the register allocator.
>> +;
>> +; This causes a problem because we only have one small register
>> +; class for loading and storing from pointers - 'PTRREGS'.
>> +; One of these registers is also used for the frame pointer, meaning
>> +; that we only ever have two registers available for these operations.
>> +;
>> +; There is an existing bug filed for this issue - PR14879.
>> +;
>> +; The specific failure:
>> +; LLVM ERROR: ran out of registers during register allocation
>> +;
>> +; It has been assembled from the following c code:
>> +;
>> +; struct ss
>> +; {
>> +;   int a;
>> +;   int b;
>> +;   int c;
>> +; };
>> +;
>> +; void loop(struct ss *x, struct ss **y, int z)
>> +; {
>> +;   int i;
>> +;   for (i=0; i<z; ++i)
>> +;   {
>> +;     x->c += y[i]->b;
>> +;   }
>> +; }
>> +
>> +%struct.ss = type { i16, i16, i16 }
>> +
>> +; CHECK-LABEL: loop
>> +define void @loop(%struct.ss* %x, %struct.ss** %y, i16 %z) #0 {
>> +entry:
>> +  %x.addr = alloca %struct.ss*, align 2
>> +  %y.addr = alloca %struct.ss**, align 2
>> +  %z.addr = alloca i16, align 2
>> +  %i = alloca i16, align 2
>> +  store %struct.ss* %x, %struct.ss** %x.addr, align 2
>> +  store %struct.ss** %y, %struct.ss*** %y.addr, align 2
>> +  store i16 %z, i16* %z.addr, align 2
>> +  store i16 0, i16* %i, align 2
>> +  br label %for.cond
>> +
>> +for.cond:                                         ; preds = %for.inc, %entry
>> +  %tmp = load i16, i16* %i, align 2
>> +  %tmp1 = load i16, i16* %z.addr, align 2
>> +  %cmp = icmp slt i16 %tmp, %tmp1
>> +  br i1 %cmp, label %for.body, label %for.end
>> +
>> +for.body:                                         ; preds = %for.cond
>> +  %tmp2 = load %struct.ss**, %struct.ss*** %y.addr, align 2
>> +  %tmp3 = load i16, i16* %i, align 2
>> +  %arrayidx = getelementptr inbounds %struct.ss*, %struct.ss** %tmp2, i16 %tmp3
>> +  %tmp4 = load %struct.ss*, %struct.ss** %arrayidx, align 2
>> +  %b = getelementptr inbounds %struct.ss, %struct.ss* %tmp4, i32 0, i32 1
>> +  %tmp5 = load i16, i16* %b, align 2
>> +  %tmp6 = load %struct.ss*, %struct.ss** %x.addr, align 2
>> +  %c = getelementptr inbounds %struct.ss, %struct.ss* %tmp6, i32 0, i32 2
>> +  %tmp7 = load i16, i16* %c, align 2
>> +  %add = add nsw i16 %tmp7, %tmp5
>> +  store i16 %add, i16* %c, align 2
>> +  br label %for.inc
>> +
>> +for.inc:                                          ; preds = %for.body
>> +  %tmp8 = load i16, i16* %i, align 2
>> +  %inc = add nsw i16 %tmp8, 1
>> +  store i16 %inc, i16* %i, align 2
>> +  br label %for.cond
>> +
>> +for.end:                                          ; preds = %for.cond
>> +  ret void
>> +}
>> +
>> 
>> 
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170201/efce41f1/attachment-0002.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: markNotSpillable.patch
Type: application/octet-stream
Size: 1465 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170201/efce41f1/attachment-0001.obj>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170201/efce41f1/attachment-0003.html>


More information about the llvm-commits mailing list