[llvm-dev] COPYs between register classes

Jonas Paulsson via llvm-dev llvm-dev at lists.llvm.org
Mon Feb 24 14:45:34 PST 2020


On 2020-02-22 16:14, Craig Topper wrote:
> Could you emit a target specific ISD opcode where the CopyToReg is 
> created? Then you could isel that ISD opcode however you want.
>
That doesn't seem quite satisfactory to me, since a copy could 
potentially be created in many different places. Since reg copies are 
kept as a general COPY instruction all the way until after regalloc 
until the target is supposed to implement them, it seems reasonable to 
let the target provide a constrained regclass at some point if needed.

Adding a new TRI hook for this is one way, another one might be to view 
this as an isel finalization step and let the target also handle COPY 
instructions in FinalizeISel. It would simply be a matter then of 
constraining the register class.

It seems possible (but ugly) though to handle this with a backend hack, 
by using a target pseudo opcode that needs the constrained regclass and 
insert that as a user of the copyFromReg during instruction selection. 
That might be fine if there really is only this one single case of this 
problem, but that would surprise me.

To give some more context, here is one test case I am looking at:


define i32 @fun() {
   %val = call i32 asm "blah", "={a0}, {a1}" (i32 0)
   ret i32 %val
}

(llc -mtriple=s390x-linux-gnu -mcpu=z196 -O0)

# *** IR Dump After Finalize ISel and expand pseudo-instructions ***:
# Machine code for function fun: IsSSA, TracksLiveness

bb.0 (%ir-block.0):
   %0:grx32bit = LHIMux 0
   $a1 = COPY %0:grx32bit
   INLINEASM &blah [attdialect], $0:[regdef], implicit-def $a0, 
$1:[reguse], $a1
   %1:grx32bit = COPY $a0
   $r2l = COPY %1:grx32bit
   Return implicit $r2l

ISel here produces COPYs to/from the GRX32 registers (both low and high 
parts) where access registers a1/a0 are involved. This is then the 
problem since these COPYs can only be made with low-parts by the 
processor. This was the SelectionDAG:

SelectionDAG has 15 nodes:
   t0: ch = EntryToken
   t8: ch,glue = CopyToReg t0, Register:i32 $a1, Constant:i32<0>
     t11: i32,ch,glue = CopyFromReg t15, Register:i32 $a0, t15:1
   t13: ch,glue = CopyToReg t0, Register:i32 $r2l, t11
   t15: ch,glue = inlineasm t8, TargetExternalSymbol:i64'blah', 
MDNode:ch<null>, TargetConstant:i64<0>, TargetConstant:i32<10>, 
Register:i32 $a0, TargetConstant:i32<9>,\
  Register:i32 $a1, t8:1
   t14: ch = Return Register:i32 $r2l, t13, t13:1

I can't simply select t8 here into a SAR (Set Access Register), because 
that would not provide the specific destination reg ($a1). So I tried 
replacing t8 with a target pseudo machine instruction opcode (CopyToAR) 
that looks identical on the DAG:

=> patched =>

SelectionDAG has 15 nodes:
   t0: ch = EntryToken
   t8: ch,glue = CopyToAR Register:i32 $a1, Constant:i32<0>, t0
     t11: i32,ch,glue = CopyFromReg t15, Register:i32 $a0, t15:1
   t13: ch,glue = CopyToReg t0, Register:i32 $r2l, t11
   t15: ch,glue = inlineasm t8, TargetExternalSymbol:i64'blah', 
MDNode:ch<null>, TargetConstant:i64<0>, TargetConstant:i32<10>, 
Register:i32 $a0, TargetConstant:i32<9>,\
  Register:i32 $a1, t8:1
   t14: ch = Return Register:i32 $r2l, t13, t13:1

When instruction selection ends, the only difference between the DAGs is 
that the CopyToReg has changed opcode to the target pseudo instruction 
opcode CopyToAR. The idea was to then insert CopyToAR with a custom 
inserter. However, before that can happen InstrEmitter triggers an 
assert in EmitMachineNode in the "Scan the glue chain for any used 
physregs" clause. Here, the glue users are looped over and while a 
ISD::CopyToReg would simply be skipped, the target CopyToAR opcode is 
not. In this example, CopyToAR is glued to an inlineasm and therefore 
the call to F->getMachineOpcode() triggers the assert "Not a 
MachineInstr opcode!".

I did not yet try to do the same opcode replacement for ISD::CopyFromReg 
since at this point it was clear to me that these nodes have special 
handlings in InstrEmitter and it probably would be worrisome to have a 
target opcode that did *not* get the same treatment even if that would 
succeed.

My patch at https://reviews.llvm.org/D75014 now has two separate 
versions ("Diff 1" and "Diff 2") where the first one handles this in 
common code and the other one in the backend. Any comments and 
suggestions welcome!

/Jonas


> ~Craig
>
>
> On Sat, Feb 22, 2020 at 3:45 PM Jonas Paulsson via llvm-dev 
> <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
>
>     Hi,
>
>     On SystemZ there are a set of "access registers" that can be
>     copied in
>     and out of 32-bit GPRs with special instructions. These
>     instructions can
>     only perform the copy using low 32-bit parts of the 64-bit GPRs. As
>     reported and discussed at
>     https://bugs.llvm.org/show_bug.cgi?id=44254,
>     this is currently broken due to the fact that the default register
>     class
>     for 32-bit integers is GRX32, which also contains the high 32-bit
>     part
>     registers.
>
>     I have tried to find a simple way to constrain the register class of
>     such copies (also at -O0), but this turned out to not be quite
>     simple.
>     Just selecting a pseudo instruction with a custom inserter does
>     not seem
>     to work since CopyToReg/CopyFromReg have special handlings in
>     InstrEmitter.
>
>     I then tried in SystemZDAGToDAG.cpp to select a CopyToReg to
>     (CopyToReg
>     COPY_TO_REGCLASS), which worked fine. But I could not get the same
>     results with CopyFromReg. (COPY_TO_REGCLASS CopyFromReg) only
>     resulted
>     in a later COPY into GR32, but the COPY from the Access register was
>     still first made to GRX32.
>
>     One alternative might be to let InstrEmitter deduce the needed
>     register
>     class for a CopyFromReg if there is only one user which is a
>     COPY_TO_REGCLASS. I thought this seemed a bit messy, so I instead
>     tried
>     adding a new TargetRegisterInfo hook that is used in InstrEmitter
>     when
>     emitting CopyToReg/CopyFromReg nodes
>     (https://reviews.llvm.org/D75014).
>
>     Does this make sense, or is there a better way?
>
>     A related question is if the target is required to be able to
>     implement
>     *any* move between register classes?
>
>     Thanks,
>
>     Jonas
>
>
>     _______________________________________________
>     LLVM Developers mailing list
>     llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
>     https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20200224/d2035992/attachment.html>


More information about the llvm-dev mailing list