Android/ARM codegen

Joakim via digitalmars-d-ldc digitalmars-d-ldc at puremagic.com
Thu Jul 16 04:41:18 PDT 2015


Alright, I've been stepping through some failing tests: one that 
seems to be bad codegen is that many calls to 
std.algorithm.iteration.map seem to fail, for example, when 
running the tests for std.zip.  One of the std.zip tests calls 
std.random.uniform, which then gets its second parameter stomped 
by map from rndGen().  I've tracked it down to this function in 
the llvm IR:

define weak_odr void 
@_D3std9algorithm9iteration47__T3mapS363std6random6rndGenFNcNdNfZ9__lambda4Z42__T3mapTS3std5range13__T6RepeatTiZ6RepeatZ3mapMFNaNbNiNfS3std5range13__T6RepeatTiZ6RepeatZS3std9algorithm9iteration87__T9MapResultS363std6random6rndGenFNcNdNfZ9__lambda4TS3std5range13__T6RepeatTiZ6RepeatZ9MapResult(%"std.random.rndGen.MapResult!(__lambda4, Repeat!int).MapResult"* noalias nocapture sret %.sret_arg, i8* %.nest_arg, %"std.range.Repeat!int.Repeat"* byval nocapture readonly %r_arg) #1
{

   %.structliteral = alloca 
%"std.random.rndGen.MapResult!(__lambda4, Repeat!int).MapResult", 
align 4 ; [#uses = 3 type = 
%"std.random.rndGen.MapResult!(__lambda4, Repeat!int).MapResult"*]

   %1 = getelementptr inbounds 
%"std.random.rndGen.MapResult!(__lambda4, Repeat!int).MapResult"* 
%.structliteral, i32 0, i32 0, i32 0 ; [#uses = 1 type = i32*]

   store i32 0, i32* %1, align 4

   %2 = getelementptr %"std.random.rndGen.MapResult!(__lambda4, 
Repeat!int).MapResult"* %.structliteral, i32 0, i32 1 ; [#uses = 
1 type = i8**]

   store i8* %.nest_arg, i8** %2, align 4

   %tmp = call %"std.random.rndGen.MapResult!(__lambda4, 
Repeat!int).MapResult"* 
@_D3std9algorithm9iteration87__T9MapResultS363std6random6rndGenFNcNdNfZ9__lambda4TS3std5range13__T6RepeatTiZ6RepeatZ9MapResult6__ctorMFNaNbNcNiNfS3std5range13__T6RepeatTiZ6RepeatZS3std9algorithm9iteration87__T9MapResultS363std6random6rndGenFNcNdNfZ9__lambda4TS3std5range13__T6RepeatTiZ6RepeatZ9MapResult(%"std.random.rndGen.MapResult!(__lambda4, Repeat!int).MapResult"* returned %.structliteral, %"std.range.Repeat!int.Repeat"* byval %r_arg) ; [#uses = 1 type = %"std.random.rndGen.MapResult!(__lambda4, Repeat!int).MapResult"*]

   %3 = bitcast %"std.random.rndGen.MapResult!(__lambda4, 
Repeat!int).MapResult"* %tmp to i64* ; [#uses = 1 type = i64*]

   %4 = bitcast %"std.random.rndGen.MapResult!(__lambda4, 
Repeat!int).MapResult"* %.sret_arg to i64* ; [#uses = 1 type = 
i64*]

   %5 = load i64* %3, align 1                      ; [#uses = 1 
type = i64]

   store i64 %5, i64* %4, align 4

   ret void
}

which gets translated to the following ARM assembly:

_D3std9algorithm9iteration47__T3mapS363std6random6rndGenFNcNdNfZ9__lambda4Z42__T3mapTS3std5range13__T6RepeatTiZ6RepeatZ3mapMFNaNbNiNfS3std5range13__T6RepeatTiZ6RepeatZS3std9algorithm9iteration87__T9MapResultS363std6random6rndGenFNcNdNfZ9__lambda4TS3std5range13__T6RepeatTiZ6RepeatZ9MapResult:
         .fnstart
.Leh_func_begin94:
         .pad    #8
         sub     sp, sp, #8
         .save   {r4, lr}
         push    {r4, lr}
         .pad    #8
         sub     sp, sp, #8
         mov     r4, r0
         mov     r0, #0
         str     r2, [sp, #20]
         stmib   sp, {r0, r1}
         add     r0, sp, #4
         ldr     r1, [sp, #20]
         bl      
_D3std9algorithm9iteration87__T9MapResultS363std6random6rndGenFNcNdNfZ9__lambda4TS3std5range13__T6RepeatTiZ6RepeatZ9MapResult6__ctorMFNaNbNcNiNfS3std5range13__T6RepeatTiZ6RepeatZS3std9algorithm9iteration87__T9MapResultS363std6random6rndGenFNcNdNfZ9__lambda4TS3std5range13__T6RepeatTiZ6RepeatZ9MapResult(PLT)
         ldmib   sp, {r0, r1}
         stm     r4, {r0, r1}
         add     sp, sp, #8
         pop     {r4, lr}
         add     sp, sp, #8
         bx      lr

The problem appears to be that even though r4 is saved at the 
beginning of the function, it is overwritten by r1 in the stmib 
instruction afterwards.  Obviously there's no point in pushing r4 
and popping it at the end of the function, if you've lost it by 
overwriting in between.  Specifically, "sub sp, sp, #8" advances 
the stack pointer by 8, then stmib increments it 4 _before_ 
storing r0 then r1, overwriting the contents of r4 saved at the 
beginning of the function.  Other calls to map also seem to fail 
in other instances of the same template function, but 
interestingly in different ways, ie no uses of stmib there.  I 
haven't tracked down exactly why those other instances fail.

I'm not sure how to reduce this further and if I need to file a 
bug for llvm: any pointers?


More information about the digitalmars-d-ldc mailing list