PHI node to different register class vs TailDuplication

Hi,

We're having an issue with TailDuplication in our out-of-tree target and it's this PHI-node that seems to be the cause of the trouble:

  %vreg2<def> = PHI %vreg0, <BB#2>, %vreg1, <BB#3>; rN:%vreg2 aNlh_0_7:%vreg0 aNlh_rN:%vreg1

Note that the defined %vreg2 has register class "rN" while the read %vreg0 has register class "aNlh_0_7". "rN" and "aNlh_0_7" are disjoint.

Is such a PHI node ok?

If it is, then there is a bug in TailDuplication.

Before TailDuplication we have:

BB#2: derived from LLVM BB %bb2
     Predecessors according to CFG: BB#1
  %vreg12<def> = mv16Sym <ga:@a>; rN:%vreg12
  %vreg13<def> = mv_nimm6_ar16 0; aNlh_rN:%vreg13
  mv_ar16_r16_rmod1 %vreg13<kill>, %vreg12<kill>; aNlh_rN:%vreg13 rN:%vreg12
  brr_uncond <BB#4>;
     Successors according to CFG: BB#4(?%)

BB#4: derived from LLVM BB %bb4
     Predecessors according to CFG: BB#2 BB#3
  %vreg2<def> = PHI %vreg0, <BB#2>, %vreg1, <BB#3>; rN:%vreg2 aNlh_0_7:%vreg0 aNlh_rN:%vreg1
  mv_a32_r16_rmod1 %vreg3, %vreg2; aN32_0_7:%vreg3 rN:%vreg2
  brr_uncond <BB#6>;
     Successors according to CFG: BB#6(?%)

Then TailDuplication runs

Tail-duplicating into PredBB: BB#2: derived from LLVM BB %bb2
[...]
From Succ: BB#4: derived from LLVM BB %bb4

and we get:

BB#2: derived from LLVM BB %bb2
     Predecessors according to CFG: BB#1
  %vreg12<def> = mv16Sym <ga:@a>; rN:%vreg12
  %vreg13<def> = mv_nimm6_ar16 0; aNlh_rN:%vreg13
  mv_ar16_r16_rmod1 %vreg13<kill>, %vreg12<kill>; aNlh_rN:%vreg13 rN:%vreg12
  mv_a32_r16_rmod1 %vreg3, %vreg0; aN32_0_7:%vreg3 aNlh_0_7:%vreg0
  %vreg18<def> = COPY %vreg0; rN:%vreg18 aNlh_0_7:%vreg0
  brr_uncond <BB#6>;
     Successors according to CFG: BB#6(0x80000000 / 0x80000000 = 100.00%)

The problem here is the duplicated instruction

  mv_a32_r16_rmod1 %vreg3, %vreg0; aN32_0_7:%vreg3 aNlh_0_7:%vreg0

since %vreg0 has register class "aNlh_0_7" but the instruction expects a disjoint register class, "rN".

During duplication TailDuplication copied the instruction and then simply replaced %vreg2 with %vreg0 since they are connected through a PHI, but since the register classes differ, the resulting code is wrong.

I've managed to get around this by inserting a COPY in TailDuplication but I don't know what the proper fix is to this.

In TailDuplicatePass::ProcessPHI:

    const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
+ const TargetRegisterClass *SrcRC = MRI->getRegClass(SrcReg);

That doesn't seem to be well documented. The PHI nodes are described as "representing an assignment", but what the "assignment" could be is not clear. Even if there exists an instruction that could copy registers between register classes, if you cannot substitute the output operand with one of the input operands in any use of the output, the PHI would seem to be malformed. At least, that is my interpretation.

-Krzysztof

A PHI can be thought of - and will be lowered to - COPY instructions at the end of the respective predecessor blocks. So what you need in the example is that a COPY instruction from class "aNlh_0_7" to class "rN" is valid and that a COPY from class "aNlh_rN" to class "rN" is valid.

- Matthias

Hi,

A PHI can be thought of - and will be lowered to - COPY instructions at the end of the respective predecessor blocks. So what you need in the example is that a COPY instruction from class "aNlh_0_7" to class "rN" is valid and that a COPY from class "aNlh_rN" to class "rN" is valid.

Both those COPY:s are valid.

However, TailDuplication doesn't insert any COPY, but just replaces the PHI dst uses with PHI src, and thus messes up the register classes.

You consider this a bug in TailDuplication then?

As I said, if I do the following in TailDuplicatePass::ProcessPHI and insert a COPY myself, then it seems to work for me:

    const TargetRegisterClass *RC = MRI->getRegClass(DefReg);
+ const TargetRegisterClass *SrcRC = MRI->getRegClass(SrcReg);