[LLVMdev] Incorrect codegen of getelementptr for ARM with JIT

Martins Mozeiko 49640f8a at gmail.com
Wed Feb 17 10:42:06 PST 2010


Thanks for answer, Renato.
But I still thing that there is some issue with ARM codegen.
When I tried running your code you modified I got exactly same LLVM IR result (verified it by comparing output from llvm-dis) - and program on runtime still produces wrong result.

With some help from another developer we managed to reduce issue to following C code that is simpler:

#include <stdio.h>
void init(int* value, int val) {
    *value = val;
    printf("Values: %08x\n", *value);
}
int main() {
    static struct {
        int a;
        int b;
    } value;

    init(&value.b, 11);
    init(&value.a, 10);

    printf("%i\n", value.a);
    printf("%i\n", value.b);
}

Correct result would be following output (I am getting this when I'm running ARM+Interpreter, or Windows+JIT):
Values: 0000000b
Values: 0000000a
10
11

But 2.6 LLVM + JIT on ARM, when compiled with llvm-gcc -O3, produces this:
Values: 0000000b
Values: 0000000a
10
10

Here is LLVM IR of main function:

define i32 @main() nounwind {
entry:
  store i32 11, i32* getelementptr inbounds (%struct..0._6* @_ZZ4mainE5value, i32 0, i32 1), align 4
  %0 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0), i32 11) nounwind ; <i32> [#uses=0]
  store i32 10, i32* getelementptr inbounds (%struct..0._6* @_ZZ4mainE5value, i32 0, i32 0), align 8
  %1 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([14 x i8]* @.str, i32 0, i32 0), i32 10) nounwind ; <i32> [#uses=0]
  %2 = load i32* getelementptr inbounds (%struct..0._6* @_ZZ4mainE5value, i32 0, i32 0), align 8 ; <i32> [#uses=1]
  %3 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([4 x i8]* @.str1, i32 0, i32 0), i32 %2) ; <i32> [#uses=0]
  %4 = load i32* getelementptr inbounds (%struct..0._6* @_ZZ4mainE5value, i32 0, i32 1), align 4 ; <i32> [#uses=1]
  %5 = tail call i32 (i8*, ...)* @printf(i8* noalias getelementptr inbounds ([4 x i8]* @.str1, i32 0, i32 0), i32 %4) ; <i32> [#uses=0]
  ret i32 0
}

It looks like the JIT compiler doesn't handle the following bitcode instructions correctly:
  store i32 11, i32* getelementptr inbounds (%struct..0._6* @_ZZ4mainE5value, i32 0, i32 1), align 4
and
  %4 = load i32* getelementptr inbounds (%struct..0._6* @_ZZ4mainE5value, i32 0, i32 1), align 4 ; <i32> [#uses=1]
It ignores the "i32 1" offset in the getelementptr bitcode instruction.

Here is produced ARM assembly of main function displayed from GDB:

(gdb) x/30i FPtr
0x40029010:    sub    sp, sp, #16    ; 0x10
0x40029014:    str    lr, [sp, #12]
0x40029018:    str    r11, [sp, #8]
0x4002901c:    str    r5, [sp, #4]
0x40029020:    str    r4, [sp]

Allocate four entries on the stack, and save the return address, r11, r5, and r4.

0x40029024:    ldr    r4, [pc, #88]    ; 0x40029084

Address of the value variable in r4.

0x40029028:    mov    r1, #11    ; 0xb
0x4002902c:    str    r1, [r4]
0x40029030:    ldr    r5, [pc, #80]    ; 0x40029088
0x40029034:    mov    r0, r5
0x40029038:    bl    0x40009008

Inline the init function: store 11 at the address of the "value" variable, call printf with the string from r5. This is a bug, should have stored at an offset of four (str r1, [r4,4]).

0x4002903c:    mov    r1, #10    ; 0xa
0x40029040:    str    r1, [r4]
0x40029044:    mov    r0, r5
0x40029048:    bl    0x40009008

Inline the init function: store 10 at the address of the "value" variable, call printf with the string from r5. This looks OK.

0x4002904c:    ldr    r1, [r4]
0x40029050:    ldr    r5, [pc, #52]    ; 0x4002908c
0x40029054:    mov    r0, r5
0x40029058:    bl    0x40009008

Load first number from the structure and print its value.

0x4002905c:    ldr    r1, [r4]
0x40029060:    mov    r0, r5
0x40029064:    bl    0x40009008

Load first number from the structure and print its value. This is bug also, should have been "ldr r1, [r4,4]".

0x40029068:    mov    r0, #0    ; 0x0
0x4002906c:    ldr    r4, [sp]
0x40029070:    ldr    r5, [sp, #4]
0x40029074:    ldr    r11, [sp, #8]
0x40029078:    ldr    lr, [sp, #12]
0x4002907c:    add    sp, sp, #16    ; 0x10
0x40029080:    bx    lr

And at the end restore registers from the stack and return. 

Can somebody confirm that this is a bug? Or am I missing something else here?

--
Martins Mozeiko


On Feb 17, 2010, at 12:23 , Renato Golin wrote:

> On 15 February 2010 14:49, Martins Mozeiko <49640f8a at gmail.com> wrote:
>> #include <stdio.h>
>> struct Global {
>>  typedef unsigned char ArrayType[4];
>>  ArrayType value;
>>  Global(const ArrayType& arg) {
>>    for (int i = 0; i < 4; i++) this->value[i] = arg[i];
>>  }
>> };
>> static const unsigned char arr[] = { 1, 2, 3, 4 };
>> static const Global Constant(arr);
>> int main() {
>>  for (int i=0; i<4; i++) printf("%i", Constant.value[i]);
>> }
> 
> Compiling with clang I got lots of errors, but boils down to two problems:
> 
>> typedef unsigned char ArrayType[4];
> 
> const_array.cpp:3:2: error: type name does not allow storage class to
> be specified
> typedef unsigned char ArrayType[4];
> ^
> 
> Which, as far as I can tell, it's confusing ArrayType[4] by a
> declaration of an unsigned char[4] type.
> 
> I've changed your code slightly to make it compile with clang, but I
> haven't been able to make it print 4444, not even with your own code,
> not even at -O3. There seems to be nothing wrong with the LLVM IR
> generated by your code, too, even at -O3.
> 
> #include <stdio.h>
> typedef unsigned char ArrayType;
> struct Global {
> ArrayType value[4];
> Global(const ArrayType* arg) {
>   for (int i = 0; i < 4; i++) this->value[i] = arg[i];
> }
> };
> static const unsigned char arr[] = { 1, 2, 3, 4 };
> static const struct Global Constant(arr);
> int main() {
> for (int i=0; i<4; i++) printf("%i", Constant.value[i]);
> }
> 
> See if that helps. I think it has nothing to do with code generation, though.
> 
> cheers,
> --renato
> 
> http://systemcall.org/
> 
> Reclaim your digital rights, eliminate DRM, learn more at
> http://www.defectivebydesign.org/what_is_drm

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20100217/7c14056c/attachment.html>


More information about the llvm-dev mailing list