[llvm-commits] [llvm] r47046 - in /llvm/trunk: include/llvm/CodeGen/LiveIntervalAnalysis.h lib/CodeGen/SimpleRegisterCoalescing.cpp lib/CodeGen/SimpleRegisterCoalescing.h

Evan Cheng evan.cheng at apple.com
Wed Feb 13 01:47:52 PST 2008


On Feb 12, 2008, at 9:56 PM, Chris Lattner wrote:

> On Feb 12, 2008, at 7:01 PM, Evan Cheng wrote:
>
>> Author: evancheng
>> Date: Tue Feb 12 21:01:43 2008
>> New Revision: 47046
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=47046&view=rev
>> Log:
>> Initial support for copy elimination by commuting its definition MI.
>
> Yay, thanks for tackling this Evan!
>
>>
>> This speeds up FreeBench/neural by 29%, Olden/bh by 12%, oopack_v1p8
>> by 53%.
>
> Very nice, does it also help shootout/fib?

bh speedup doesn't seem real. It doesn't help fib.

>
>> +  // Get the location that B is defined at.  Two options: either
>> this value has
>> +  // an unknown definition point or it is defined at CopyIdx.  If
>> unknown, we
>> +  // can't process it.
>> +  if (!BValNo->reg) return false;
>> +  assert(BValNo->def == CopyIdx && "Copy doesn't define the  
>> value?");
>> +
>> +  // AValNo is the value number in A that defines the copy, A3 in
>> the example.
>> +  LiveInterval::iterator ALR =
>> IntA.FindLiveRangeContaining(CopyIdx-1);
>> +  VNInfo *AValNo = ALR->valno;
>
> This idiom happens a lot in the preexisting code.  Please use:
>
> VNInfo *AValNo = IntA.FindLiveRangeContaining(CopyIdx-1)->valno;

ALR is also used below.

>
>
> Or better yet, add a new method that returns valno directly.
>
>
>
>> +  int Idx = -1;
>
> "Idx" is too generic of a name for a variable with this long of
> lifetime, please name it something more descriptive.  What type of idx
> is it?
>
>>
>> +  for (unsigned i = 0, e = DefMI->getNumOperands(); i != e; ++i) {
>
> This loop needs a comment. What are you trying to find with this
> loop?  Maybe it should be moved out to its own function which just
> returns idx?  This would force you to name it, which would describe
> what it does :)

There is a reason I said "initial" in the commit message. This is not  
done. I need a target hook to tell me what is the new destination  
register after commuting. Right now this is basically assuming x86  
commutable instructions: A = A + B

>
> Another random question unrelated to this code: now that we have
> efficient RAUW, can we eliminate the 'rep'  mapping stuff and just
> RAUW vregs as they are coallesced?

Well, actually it's related. I think it's required for correctness.  
See below.

>>
>> +  MachineBasicBlock *MBB = DefMI->getParent();
>> +  MachineInstr *NewMI = tii_->commuteInstruction(DefMI);
>> +  if (NewMI != DefMI) {
>> +    li_->ReplaceMachineInstrInMaps(DefMI, NewMI);
>> +    MBB->insert(DefMI, NewMI);
>> +    MBB->erase(DefMI);
>> +  }
>> +  unsigned OpIdx = NewMI->findRegisterUseOperandIdx(IntA.reg);
>> +  NewMI->getOperand(OpIdx).setIsKill();
>> +
>> +  // Update uses of IntA of the specific Val# with IntB.
>> +  bool BHasPHIKill = BValNo->hasPHIKill;
>> +  SmallVector<VNInfo*, 4> BDeadValNos;
>> +  SmallVector<unsigned, 4> BKills;
>> +  std::map<unsigned, unsigned> BExtend;
>> +  for (MachineRegisterInfo::use_iterator UI = mri_-
>>> use_begin(IntA.reg),
>> +         UE = mri_->use_end(); UI != UE;) {
>
> Yay for use_iterators :)

Except I don't think this is quite right. Iterating through uses of  
IntA.reg means we end up not updating other uses that have already  
been coalesced to it.

>
>
>>
>> +    MachineOperand &UseMO = UI.getOperand();
>> +    ++UI;
>> +    MachineInstr *UseMI = UseMO.getParent();
>
> It would be more clear to use (before the increment):
> MachineInstr *UseMI = *UI;
>
> Note that if an instruction uses a register multiple times,
> incrementing the iterator could point into another operand of the same
> instruction.  This is rare, but the code needs to handle it
> correctly.  I'm concerned about cases like:
>
>   r1 = or r2, r2
>
> (which is the copy operation on some targets).
>
> Where the use iterator could point to the first r2, and incrementing
> it could point to the next r2.  This could be avoided by not zapping
> instructions in this loop: move the copy zapping to a walk over a
> smallset or something.

Nothing is being zapped in the loop. Copies that would be zapped are  
put into a set JoinedCopies. In fact, all uses have to be updated to  
the new register.

>
>
>
>> +    unsigned UseIdx = li_->getInstructionIndex(UseMI);
>> +    LiveInterval::iterator ULR =
>> IntA.FindLiveRangeContaining(UseIdx);
>> +    if (ULR->valno != AValNo)
>> +      continue;
>> +    UseMO.setReg(NewReg);
>> +    if (UseMO.isKill())
>> +      BKills.push_back(li_->getUseIndex(UseIdx)+1);
>> +    if (UseMI != CopyMI) {
>
> if (UseMI == CopyMI) continue;
>
>>
>> +      unsigned SrcReg, DstReg;
>> +      if (!tii_->isMoveInstr(*UseMI, SrcReg, DstReg))
>> +        continue;
>
>
>> +      unsigned repDstReg = rep(DstReg);
>> +      if (repDstReg != IntB.reg) {
>> +        // Update dst register interval val# since its source
>> register has
>> +        // changed.
>> +        LiveInterval &DLI = li_->getInterval(repDstReg);
>> +        LiveInterval::iterator DLR =
>> +          DLI.FindLiveRangeContaining(li_->getDefIndex(UseIdx));
>> +        DLR->valno->reg = NewReg;
>> +        ChangedCopies.insert(UseMI);
>> +      } else {
>> +        // This copy will become a noop. If it's defining a new  
>> val#,
>> +        // remove that val# as well. However this live range is  
>> being
>> +        // extended to the end of the existing live range defined
>> by the copy.
>> +        unsigned DefIdx = li_->getDefIndex(UseIdx);
>> +        LiveInterval::iterator DLR =
>> IntB.FindLiveRangeContaining(DefIdx);
>> +        BHasPHIKill |= DLR->valno->hasPHIKill;
>> +        assert(DLR->valno->def == DefIdx);
>> +        BDeadValNos.push_back(DLR->valno);
>> +        BExtend[DLR->start] = DLR->end;
>> +        JoinedCopies.insert(UseMI);
>> +        // If this is a kill but it's going to be removed, the last
>> use
>> +        // of the same val# is the new kill.
>> +        if (UseMO.isKill()) {
>> +          BKills.pop_back();
>> +        }
>> +      }
>
> It isn't clear to me what this code is doing.  It looks like it is
> looking for the copy that has now becomes an identity copy.  Is there
> some way to factor this with other code that is coallescing copies
> away?  It seems duplicated from somewhere else.  It would be nicer to

Not really. A number of things are happening here. We are trying to  
determine which copies are now identity copies and make sure their  
valno# will be eliminated. We also need to transfer the live ranges  
defined by the (now dead) copies to the new val# defined by the  
commuted definition MI. It's also tracking kill information.

>
> just add all copies to a small vector and then zap them later or
> something, to keep the logic simple.

That's essentially what's happening. This has gone through a number of  
iterations already. Apart from some cosmetic changes, it's not going  
to get much simpler than this.

>
>
>> =
>> =
>> =
>> =
>> =
>> =
>> =
>> =
>> = 
>> =====================================================================
>> --- llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.h (original)
>> +++ llvm/trunk/lib/CodeGen/SimpleRegisterCoalescing.h Tue Feb 12
>> 21:01:43 2008
>> @@ -80,6 +80,7 @@
>>
>> +    /// ChangedCopies - Keep track of copies modified due to
>> commuting.
>> +    SmallPtrSet<MachineInstr*, 32> ChangedCopies;
>
> Does this need to be an ivar?  Can it just be passed by-ref between
> the methods that need it?

This will be cleaned up later as part of RAUW change.

Evan

>
>
> -Chris
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list