[LLVMbugs] [Bug 14992] New: Tablegen incorrectly converts ARM tLDMIA_UPD pseudo to tLDMIA

bugzilla-daemon at llvm.org bugzilla-daemon at llvm.org
Fri Jan 18 12:56:33 PST 2013


http://llvm.org/bugs/show_bug.cgi?id=14992

             Bug #: 14992
           Summary: Tablegen incorrectly converts ARM tLDMIA_UPD pseudo to
                    tLDMIA
           Product: tools
           Version: trunk
          Platform: PC
        OS/Version: Windows NT
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: TableGen
        AssignedTo: unassignedbugs at nondot.org
        ReportedBy: dpeixott at codeaurora.org
                CC: llvmbugs at cs.uiuc.edu
    Classification: Unclassified


I'm seeing a problem in the ARM backend with an incorrect conversion between
the tLDMIA_UPD psuedo instruction and the tLDMIA instruction. The conversion is
duplicating a register when it generates the tLDMIA instruction, and the
duplicate register causes an assembler error. The problem looks like it is in
the c++ code that tablegen generates to convert between the two instructions.

We can demonstrate the problem with a small c program:

$ cat bug.c

  void bar(int*);

  int foo(int *a) {
    int b = a[0];
    int c = a[1];
    bar(a+2);
    return b+c;
  }

$ clang -mcpu=cortex-a9  -mthumb -Os bug.c -S -o-

    foo:
        push    {r4, r5, r7, lr}
        ldm     r0!, {r4, r4, r5}
        add     r7, sp, #8
        bl      bar
        adds    r0, r5, r4
        pop     {r4, r5, r7, pc}


The ldm instruction incorrectly lists r4 twice. If we try to assemble the file
with the gnu assembler using -no-integrated-as we get a warning like this:

  /tmp/bug-8h7TgZ.s: Assembler messages:
  /tmp/bug-8h7TgZ.s:21: Warning: duplicated register (r4) in register list


I believe the problem is in the PseudoLoweringEmitter::emitLoweringEmitter
function when it copies over the variable_ops (i.e. the reglist). The
tLDMIA_UPD pseudo instruction is a bit different than the other pseudo
instructions because it has more arguments that the instruction that it maps to
(tLDMIA). The _UPD version has an extra argument for the base register to
represent the writeback.

When we go to do the convert, we have a situation like this:

  tLDMIA_UPD r0<def>, r0, pred, predreg, r4, r5
  tLDMIA              r0, pred, predreg, r4, r5

The conversion correctly copies the base register, predicate operands and the
r4 register. The problem is, when it goes to copy the remaining variable_ops
arguments, it starts copying at index 4 which is where the variable_ops for the
destination (tLDMIA) start, but the variable_ops of the source (tLDMIA_UPD)
start at index 5. This error causes the register r4 to be copied twice.

I think we can fix the problem by starting to copy the the variable_ops from
where they start in the source operand instead of where they start in the
destination operand. For most instructions it should not matter because they
have the same number of operands, but the tLDMIA_UPD is a special case.  I
think this fix would be correct even if the source instruction has fewer
operands than the destination instruction, but I haven't seen any instructions
defined this way to test it out.

I tried the fix for the ARM backend and it correctly generates the ldm
instruction. It would be great to have someone that knows tablegen try the fix
and see if it is reasonable.

-- 
Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.



More information about the llvm-bugs mailing list