Issue with Machine Verifier and earlyclobber

Hello,

I’m getting a machine verifier error after introducing the earlyclobber constraint to some instructions where the src and dest regs can’t be the same. The offending instruction pattern is this one:

let canFoldAsLoad = 1,
isReMaterializable = 1,
Constraints = “@earlyclobber $dst” in
def LDDWRdPtrQ : Inst<(outs DREGS:$dst),
(ins memri:$src),
“lddw\t$dst, $src”,
[(set DREGS:$dst, (load addr:$src))]>;

This is just a load with displacement instruction of the form “load reg, [reg_addr+]”, where reg_addr and dest can’t be the same register.

This caused the following verifier error:

*** Bad machine code: No live range at def ***

  • function: f3
  • basic block: entry 0x9d68664 (BB#0) [0B;5056B)
  • instruction: 3688B %vreg96<earlyclobber,def> = LDDWRdPtrQ <fi#0>, 0; mem:LD2FixedStack0 DREGS:%vreg96
  • operand 0: %vreg96<earlyclobber,def>
    3688e is not live in [3688r,4480r:0) 0@3688r

*** Bad machine code: Early clobber def must be at an early-clobber slot ***

  • function: f3
    Valno #0 is defined at 3688r in [3688r,4480r:0) 0@3688r

I’ve noticed this only happens when loading from frame indexes like in this case, regular loads won’t error.

Does anybody know what is causing this sort of error or if I’m missing something obvious? I can provide any other debug info if requested.

Thanks in advance.

Spiller bug, should be fixed in r160219.

/jakob

Hello Jakob,

I’m still getting the error, I can give you any other debug info you need. I haven’t pasted the regalloc debug info here because it is quite huge, but if you tell me what specific details you need I will include them.

Thanks for your help!

2012/7/14 Jakob Stoklund Olesen <stoklund@2pi.dk>

Jakob, one more hint, I’ve placed some asserts around the code you added and noticed that the InlineSpiller::insertReload() function is not being called.

2012/7/14 Borja Ferrer <borja.ferav@gmail.com>

Sorry, I can’t debug this for you. I suggest you take a look at the code yourself.

/jakob

I think I’m getting a bit closer to the problem. I’ve found that the call to InlineSpiller::foldMemoryOperand() inside InlineSpiller::spillAroundUses() is causing the problems.
As a test, I removed that call and with your yesterday’s patch I’m not getting any errors at all, the code generated is the same one as with the call. This is happening when InlineSpiller::foldMemoryOperand() returns true, so a very wild guess is that maybe when calling LIS.ReplaceMachineInstrInMaps() the new SlotIndex created is not of type Slot_EarlyClobber since the MI being replaced is a COPY with no EC ops.

I’ve also found a way for you to reproduce this error in a simple way with the ARM backend with -march=thumb:
Just add “Constraints = “@earlyclobber $Rt” in” to the tLDRspi instruction in ARMInstrThumb.td (around line 620) and compile the following code with llc at -O3:

target datalayout = “e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:32:64-v128:32:128-a0:0:32-n32-S32”
target triple = “armv4t-generic-generic”
define float @f3(float %days) nounwind readnone {
entry:
%mul = fmul float %days, 0x3FEF8A6C60000000
%add = fadd float %mul, 0x40718776A0000000
%mul1 = fmul float %days, 0x3FEF8A09A0000000
%add2 = fadd float %mul1, 0x4076587740000000
%mul3 = fmul float %days, 0x3E81B35CC0000000
%sub = fsub float 0x3FFEA235C0000000, %mul3
%call = tail call float @dsin(float %add2) nounwind readnone
%mul4 = fmul float %sub, %call
%mul5 = fmul float %days, 0x3E27C04CA0000000
%sub6 = fsub float 0x3F94790B80000000, %mul5
%mul7 = fmul float %add2, 2.000000e+00
%call8 = tail call float @dsin(float %mul7) nounwind readnone
%mul9 = fmul float %sub6, %call8
%add10 = fadd float %mul4, %mul9
%add11 = fadd float %add, %add10
%mul12 = fmul float %days, 0x3E13C5B640000000
%sub13 = fsub float 0x3F911C1180000000, %mul12
%mul14 = fmul float %add, 2.000000e+00
%call15 = tail call float @dsin(float %mul14) nounwind readnone
%mul16 = fmul float %call15, 0x3FF1F736C0000000
%mul17 = fmul float %sub13, 2.000000e+00
%mul19 = fmul float %mul17, %call
%sub20 = fsub float %mul16, %mul19
%mul21 = fmul float %sub13, 4.000000e+00
%mul22 = fmul float %mul21, 0x3FF1F736C0000000
%mul24 = fmul float %mul22, %call
%call26 = tail call float @dcos(float %mul14) nounwind readnone
%mul27 = fmul float %mul24, %call26
%add28 = fadd float %sub20, %mul27
%call29 = tail call float @dsin(float %add11) nounwind readnone
%mul30 = fmul float %call29, 0x3FF0AB6960000000
%call31 = tail call float @dasin(float %mul30) nounwind readnone
%add32 = fadd float %call31, %add28
ret float %add32
}

declare float @dsin(float) nounwind readnone
declare float @dcos(float) nounwind readnone
declare float @dasin(float) nounwind readnone

You will get the following error:

*** Bad machine code: No live range at def ***

  • function: f3
  • basic block: entry 0x9e5d2bc (BB#0) [0B;3360B)
  • instruction: 2440e %vreg51<earlyclobber,def> = tLDRspi <fi#0>, 0, pred:14, pred:%noreg; mem:LD4[FixedStack0] tGPR:%vreg51
  • operand 0: %vreg51<earlyclobber,def>
    2440e is not live in [2440r,2976r:0) 0@2440r

*** Bad machine code: Early clobber def must be at an early-clobber slot ***

  • function: f3
    Valno #0 is defined at 2440r in [2440r,2976r:0) 0@2440r2440r
    LLVM ERROR: Found 2 machine code errors.

Hope this helps a bit.

Thanks!

OK, I see what is happening. We don't expect foldMemoryOperand to turn a normal def into an early-clobber and vice versa.

This is not easy to fix, could you file a PR, please?

As a workaround, you can use a pseudo-instruction in loadRegFromStackSlot() that doesn't have the early-clobber flag. Then replace it with the real instruction in expandPostRAPseudo().

/jakob

OK, I see what is happening. We don’t expect foldMemoryOperand to turn a normal def into an early-clobber and vice versa.

This is not easy to fix, could you file a PR, please?

Great that you found the cause.
Sure! here it is: http://llvm.org/bugs/show_bug.cgi?id=13375

As a workaround, you can use a pseudo-instruction in loadRegFromStackSlot() that doesn’t have the early-clobber flag. Then replace it with the real instruction in expandPostRAPseudo().

OK, no problems with that, easy to handle.

As always thanks for your help Jakob!