Add a verifier test to check the access on both sides of COPY are the same

Authored by aditya_nandakumar on Sep 12 2017, 3:32 PM.



Only checks if there are no sub registers involved for now.
There are lots of failures currently which need to be fixed by various backends.

Splitting this off from

Diff Detail

Failed to build as a shared library -DBUILD_SHARED_LIBS=1

igorb added inline comments.Sep 13 2017, 1:17 AM

For X86 back-end this is not always correct.
I think in case a few register classes with different size are mapped to the same physical registers, it is impossible to identify when the COPY is illegal without some additional target specific info.

def FR32 : RegisterClass<"X86", [f32], 32, (sequence "XMM%u", 0, 15)>;
def VR128 : RegisterClass<"X86", [v4f32, v2f64, v16i8, v8i16, v4i32, v2i64], 128, (add FR32)>;

For example the test fail DAG/GISEL (with the patch)
./bin/llc -O0 -mtriple=x86_64-linux-gnu -verify-machineinstrs -stop-before=legalizer
./bin/llc -O0 -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs -stop-before=legalizer

define float @test_add_float(float %arg1, float %arg2) {
  %ret = fadd float %arg1, %arg2
  ret float %ret

for the correct MIR. (xmm size is 128)

%0(s32) = COPY %xmm0
%1(s32) = COPY %xmm1
%2(s32) = G_FADD %0, %1
%xmm0 = COPY %2(s32)


qcolombet added inline comments.Sep 13 2017, 9:36 AM

I'd argue that when generic types are on one side of a copy, i.e., this is a pre-isel copy, we want the size to exactly match.
Thus, if the target wants to do truncate and whatnot at this point, it needs to use G_TRUNC, G_ANYEXT, and so on.

That being said, the check is too broad. We need to check that only for pre-isel copy. Regular copies require indeed target knowledge (e.g., eflags = copy gpr is valid on x86).


I can update the check to do it only when there are generic types involved (ie one of src and dst has a generic virtual register).

qcolombet added inline comments.Sep 13 2017, 10:42 AM

That would be perfect.

Updated to check only if one of Src/Dst has generic virtual registers.

aditya_nandakumar marked an inline comment as done.
aditya_nandakumar edited the summary of this revision. (Show Details)

Updated to refactor getRegSizeInBits into TargetRegisterInfo. There are 57 failures in total.

qcolombet accepted this revision.Sep 15 2017, 2:28 PM

LGTM with one suggestion


Seeing this pattern being actually the implementation of RegisterBankInfo::getSizeInBits, I would suggest to move the whole RegisterBankInfo::getSizeInBits directly in TargetRegisterInfo.

This revision is now accepted and ready to land.Sep 15 2017, 2:28 PM

Also, there are various tests that need to be updated by the various backends, and I can only land once those are updated. I haven't had time to update all the backends.


I thought TargetRegisterInfo doesn't have LLT headers pulled in (but looks like it is getting transitively pulled in). I can pretty much move the implementation of RegisterBankInfo::getSizeInBits into TargetRegisterInfo.

moved getSizeInBits to TargetRegisterInfo as suggested by Quentin.

qcolombet accepted this revision.Sep 18 2017, 10:51 AM

Updated AArch64 tests.

Would it be possible for someone to update the ARM/X86 tests?

rovka added a comment.Oct 17 2017, 1:56 AM

Sorry, I just noticed this. I'll have a look at the ARM side of things.

rovka added a comment.Oct 19 2017, 4:13 AM

Hi, here's the patch for the ARM GlobalISel tests:
Let me know if there's anything else that needs addressing on ARM.

Thanks Diana.
@igorb would it be possible for you to look at X86 when you get a chance? If not, I can update it.

zvi added a subscriber: zvi.Oct 29 2017, 2:09 AM

Hi All,

I will try to cover for Igor in helping with the X86 part of this patch.

AFAIU, the challenge is in getting the call/return lowering working for the case where a function's argument/return-value is a f32 or a f64. Some subtargets will use the FP stack registers (which are 80-bit wide), and other will use XMM's (which are 128-bit wide).

define float @foo(float %arg1, float %arg2) {
  ret float %arg2

Existing state on ToT: llc -mtriple=x86_64-linux-gnu -mattr=+sse2 -global-isel -stop-after=irtranslator

body:             |
  bb.1 (%ir-block.0):
    liveins: %xmm0, %xmm1

    %0:_(s32) = COPY %xmm0
    %1:_(s32) = COPY %xmm1
    %xmm0 = COPY %1(s32)
    RET 0, implicit %xmm0

Here are some options for resolving this issue:

  1. Perform the full expansion in X86CallLowering using G_COPY/G_TRUNC and G_ANYEXT/G_COPY. Fix whatever needs fixing to make it work.
  2. X86CallLoweing will continue with generation of G_COPY's with incompatible src/dest bit-sizes, but will assign register classes to the virtual registers. This will technically work because the verification check is guarded by the condition 'SrcTy.isValid() || DstTy.isValid()', which will not be met if final register classes are assigned.
  3. Introduce an X86-specific COPY instruction which will be pattern-matched in Instruction-Selection. This instruction will be generated instead of G_COPY's.

I haven't tried implementing any of the above options, and given my limited knowledge in GlobalISel, would appreciate any feedback on this.

Thanks, Zvi

I would definitely prefer the sizes to be right coming out of the CallLowering - so option #1.

igorb added a subscriber: aivchenk.Dec 21 2017, 4:23 AM
igorb added a comment.Dec 21 2017, 4:27 AM

Hi Aditya ,
Unfortunately, I don't have time to work on this task


Hi Aditya,
I'm going to take this over from Igor; Will do that in Jan

rtereshin added inline comments.

What if neither of the registers has a class? That would mean, both registers have LLTs. Then, the check won't complain if those LLTs have the same size in bits, but don't exactly match, like v2s32 and v4s16, for instance.

Shouldn't LLTs match exactly if both are valid?


Good catch. I should be checking LLTs are equal here. I will update the patch.

aivchenk added a comment.EditedJan 19 2018, 2:26 AM
This comment has been deleted.

Here we rely on having operands in MI, while previously in MachineVerifier::visitMachineInstrBefore we could discover that there are not enough operands given. Should we guard that with foundErrors?

fails due to that reason

qcolombet requested changes to this revision.Jan 19 2018, 12:15 PM
qcolombet added inline comments.

Sounds sensible to me.


This function is not consistent with RegisterBankInfo::getSizeInBits in the priority it gives to the different size when several sources are available (RC, Type).

RBI goes Type if any then RC, this one does the opposite and I believe this is not what we want.

At the very least, RBI should use this implementation instead of duplicating the logic.

This revision now requires changes to proceed.Jan 19 2018, 12:15 PM

X86 currently had/has three kinds of fails after this patch:

  1. test/CodeGen/MIR/X86/machine-verifier.mir
    • should be fixed in this patch
  2. Proper G_COPY/G_TRUNC and G_ANYEXT/G_COPY for floating point arguments
    • D42287 fixes that. However, it relies on getRegSizeInBits from this patch. We can either decide to split this patch or to submit it first and D42287 as the next one. The second option is not really good, though
  3. The rest of the tests just needed small tweaks or reautogeneration. This is fixed and submitted in rL323209

Updated based on Quentin's/Roman's feedback.
With this patch, only X86 backend fails.

qcolombet accepted this revision.Feb 2 2018, 9:27 AM

LGTM, coordinate with the x86 changes and you should be good to go!

This revision is now accepted and ready to land.Feb 2 2018, 9:27 AM

I can push the getSizeInbits change in a NFC change all by itself, and then the verifier change can land separately once X86 finishes it?


Good catch. Will fix this.

Pushed the NFC change in r324125.

X86 part is submitted. All ready to go :)