Register usage and WASM compiler

332 Views Asked by At

I am using Ubuntu on x86_64. I first generate non-optimized WebAssembly code from clang. The WebAssembly code is compiled into machine code using wasmtime which uses cranelift as compiling backend.

I am doing a simple matrix multiplication:

int first[m][n], second[p][q], multiply[m][q];

Here is the machine code for the first loop out of the three loops

for ( int c = 0 ; c < m ; c++ ){}

generated by wasmtime. I found many necessary instructions, but I cannot find a calling convention from cranelift to necessitate these instructions.

Assembly code

  1. My questions are mainly around esi register, does the compiler has to use it for get c's value using esi. Must esi's value be preserved? Otherwise why not directly use it to do cmp. If yes, why in 1ad we use esi to store 0 which is from r14d which is from eax? Also, the 0 value is preserved in eax, is eax also a non-volatile register?

  2. In 1b0, if we directly cmp esi, r12d and set esi 0 or 1 according to results, there is no need to complicated steps 1ba-1c3 Right?

  3. If I generate optimized machine code from optimized WebAssembly using

     wasm32-wasi-clang -O2
    

    I dont think cranelift by itself provides an optimization flag though, I find the machine code much shorter but also hard to understand. Are there any ways to help me read optimized machine code? AND Also, if my machine code is from the non-optimized wasm. According to the analysis we just did on this for loop example, is it ok to say that I have found the flaws of wasm compiler, cranelift?

Thank you so much for your help! I know the code may not be enjoyable to read, you can zoom in the page to see the picture

  195: rex mov DWORD PTR [rbx+rdx*1+0xc],eax         ;int c = 0, eax preserves 0. 

  19a: rex mov edx,ecx                              ; edx = ecx = [rdi+0x60]  + 0xffffffc0  

  19d: rex mov esi,DWORD PTR [rbx+rdx*1+0xc]         ; esi = [0xc]  = c,  get c into register? 

  1a2: mov    r12d,DWORD PTR [rbx+rdx*1+0x38]       ; r12d = m 

  1a7: mov    r14d,eax               ;r14d = eax = 0         
  
  1aa: rex mov eax,esi               ;     eax = esi = [c] = c [[!!! abuse register, you can directly use esi for cmp, eax remains 0, instead of store eax value 0 in r14d, 
                                                        ;use eax for cmp, and at the end restore eax value 0 by esi (esi = r14d)]

  1ad: mov    esi,r14d               ; esi = r14d = 0;  

  1b0: cmp    eax,r12d               ; cmp if eax (c) < r12d (m), if yes, al = 1, otherwise al = 0; {can use esi?? cmp usage ?}

  1b3: setl   al               

  1b6: movzx  eax,al               ; eax = al = 1 (if <)   [movzx already uses zero-extension!!]

  1ba: and    eax,0x1              ; eax = 1 if (if <). [al is low 8 bits, set only supports one byte, Byte Set On Condition (setcc), why not directrly set r12d also has low 8 bit !!!! ]

  1bd: mov    r12d,eax             ; r12d = eax = 1 (if <)

  1c0: rex mov eax,esi                ;eax = esi =  r14d = 0;   [restore eax = 0, but why use esi rather than r14d, actually you dont even need to restore eax 
                                                        ;if choose to replace eax with another register in CMP   ]

  1c3: mov    esi,r12d             ; esi = r12d =  eax = 1 (if <) [!!if directly use esi for CMP, there is no need of mov 12d, eax then mov esi, r12d]

  1c6: rex test esi,esi ;if esi=0 jump

  1c9: je     2f0 <_wasm_function_3+0x227>
0

There are 0 best solutions below