[llvm-commits] [llvm] r80654 - in /llvm/trunk: lib/CodeGen/TwoAddressInstructionPass.cpp test/CodeGen/ARM/2009-08-31-TwoRegShuffle.ll
Bob Wilson
bob.wilson at apple.com
Tue Sep 1 10:50:36 PDT 2009
On Sep 1, 2009, at 12:37 AM, Evan Cheng wrote:
> Hi Bob,
>
> I am taking issues with this patch. The two-address pass is starting
> to get too complicated (my fault).
No arguments about the complexity. I made a few minor simplifications
yesterday, but I'm sure there are more substantial improvements that
could be made.
> I've been thinking about restructuring the code. This patch is
> making the code even harder to read.
I tried pretty hard to simplify it. This was the best I could come up
with. Maybe you understand more of the context and can suggest ways
to simplify it further.
> It also potentially calls removeVirtualRegisterKilled() multiple
> times for each source register.
I don't think that can happen. It calls removeVirtualRegisterKilled
when: KillMO is set and FirstKeptMO is false, i.e., the register is
killed in this instruction, and none of the uses are tied to other
destination registers. Under those circumstances, all the uses of the
register will be replaced. Subsequent iterations cannot call
removeVirtualRegisterKilled for the same register because all
references to that register will be gone.
> Each of the call ends up scanning the entire operand list. That
> seems inefficient to me.
See comments below.
> Also, what happens to the code the calls LV-
> >removeVirtualRegisterDead(regB, mi)?
Sorry, I should have removed that in a separate patch. We're
modifying register uses here. Uses have kill markers. Defs have
death markers. If we don't change the defs, why would we need to call
removeVirtualRegisterDead? Am I missing something here? I searched
back through the svn history to see if this was added to fix a problem
but it seems to go all the way back to the origins of this code. I
concluded that it is not needed, but I should have submitted this
change separately.
>
> if (KillMO) {
> if (!FirstKeptMO) {
> // All uses of regB are being replaced; move the kill to prevMI.
> if (LV && LV->removeVirtualRegisterKilled(regB, mi))
>
> When KillMO is not null, it shouldn't be necessary to call
> removeVirtualRegisterKilled, right?
KillMO is the machine operand that currently has a kill marker on it.
If all of the register uses are being replaced, we want to move the
kill to the preceding copy instruction. This is no different than the
previous code.
>
> Also notice we are scanning the operands twice:
>
> for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
> ...
> }
>
> // Replace uses of regB with regA.
> for (unsigned i = 0, e = mi->getNumOperands(); i != e; ++i) {
> ...
> }
>
> Please scan the operands just once. If it sees any other source
> operand of the same virtual register tied to another def, then it
> should not update the other operands of the same virtual register.
> The next iteration will deal with them.
The first scan collects information. The second modifies the
operands. I first tried to do it in one scan but I could not come up
with a reasonable way to make that work. Note that
removeVirtualRegisterKilled needs to be called before you update the
registers, and since I didn't want to leave the instruction with
incorrect kill information in between iterations, I needed to first
check whether all the uses of the register should be replaced.
> As for the kill marker, it should move it to the previous
> instruction the first time it is processed. All you have to ensure
> is the later iteration does not insert any instruction between the
> kill marker and the mi being processed. That should be pretty
> straight forward. Just add a iterator which is the instruction
> insertion location. The first time you insert a copy, it should then
> be moved to the copy instruction, etc. e.g.
>
> a, b = op c<kill>, c // insert pos
>
> =>
>
> a = c<kill> // insert pos
> a, b = op a, c
>
> =>
>
> b = c
> a = c<kill>
> a, b = op a, b
That seems unsafe to me. You're leaving the instruction in an
inconsistent state. After the first copy is inserted, you've moved
the kill marker but there is still a use of c after the point where it
is killed. There is a lot of code inside this loop that is looking at
register uses and kill markers. On the next iteration, it seems like
things may get confused. It may be safe but I'm not able to easily
convince myself of that, and even if it is safe now, it seems likely
to be fragile in the future.
This seems like the root of your objections. I am trying to keep the
kill information up to date in between iterations. Given that goal, I
don't see a better way to write the code. If you are certain that it
is OK to leave the kill information in an incorrect state, I can
change it as you suggest. I would rather be safe here.
>
> Since you are working on this code, could be please clean it up a
> bit. Can you factor this if statement:
> if (mi->getOperand(ti).isDead() &&
> isSafeToDelete(mi, regB, TII, Kills)) {
>
> to a separate function?
Like this (in the attached patch)?
Checking mi->getOperand(ti).isDead() is completely redundant with
isSafeToDelete() so I assume it is only there to guard against calling
a relatively expensive function in the common case. If we're going to
call a function anyway, maybe it would be better to just remove the
isDead() check altogether.
I'd leave it as-is but I don't mind changing it if you tell me your
preference.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: safeToDelete.patch
Type: application/octet-stream
Size: 1370 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20090901/a52560cf/attachment.obj>
More information about the llvm-commits
mailing list