Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

finding GHC assembly for a function

I'd like to identify what assembly GHC produces for a given function.

Here, for example, is some code which (should) rotate bits around in a word - it moves bit 0 to bit 12, bit 12 to 14, bit 14 back to 0 and similarly for the positions 1, 18, 13 and 6.

What's the best way to go about finding the assembly generated for rot0cw in the .S file produced by ghc -O2 -S ...?

I've read this answer, but I don't see any ..._rot0cw_closure in the assembly output.

import Data.Bits
import Data.Int (Int64)
import Text.Printf
import System.Environment

{-# INLINE maskbits #-}
-- set in word v the bits of b corresponding to the mask m
-- assume a bit in b is zero if not in the mask
maskbits v m b = (v .&. (complement m) .|. b)

{-# INLINE tb #-}
-- transfer bit i of word v to bit j of word m; assume bit j of m is 0
tb v i j m =  m .|. (rotate  (v .&. (bit i)) (j-i))

rot0cw :: Int64 -> Int64
rot0cw v = maskbits (maskbits v m1 b1) m2 b2
  where
    m1 = 0x0000005005
    b1 = tb v 0 2 . tb v 2 14 . tb v 14 12 . tb v 12 0 $ 0
    m2 = 0x0000002142
    b2 = tb v 1 8 . tb v 8 13 . tb v 13 6 . tb v 6 1 $ 0

showBits v = 
  let set = [ i | i <- [0..35], testBit v i ]
  in "bits set: " ++ (unwords $ map show set)

main = do
  (arg0:_) <- getArgs
  let v = read arg0 
  -- let v = 0x0000000005
  let v' = rot0cw v
  putStrLn $ printf "v  = 0x%010x = %12d %s" v v (showBits v)
  putStrLn $ printf "v' = 0x%010x = %12d %s" v' v' (showBits v')
like image 541
ErikR Avatar asked Jan 10 '23 06:01

ErikR


2 Answers

I've read this answer, but I don't see any ..._rot0cw_closure in the assembly output.

You need to name your module. e.g. add module Main where at the beginning* to get Main_rot0cw_closure in the generated assembly.

* Strictly speaking, your module needs to export the function.

like image 139
Zeta Avatar answered Jan 18 '23 17:01

Zeta


You will need to export the function rot0cw from your module, otherwise it's effectively dead code. So add something like this to the top of your module:

module Asm(rot0cw) where

The assembly it generates is rather large, if you dump the Cmm -ddump-cmm you can look at each of the proc blocks labeled with the name of the function you're interested in. The basic blocks GHC generates here roughly corresponds to a label in the resulting assembly. So for instance the entry code for rot0cw_closure maps to the following:

     cB2:
         if (Sp - 32 < SpLim) goto cB4;
         Hp = Hp + 16;
         if (Hp > HpLim) goto cB6;
         I64[Sp - 16] = stg_upd_frame_info;
         I64[Sp - 8] = R1;
         I64[Hp - 8] = S#_con_info;
         I64[Hp + 0] = 0;
         I64[Sp - 24] = Hp - 7;
         I64[Sp - 32] = stg_ap_p_info;
         R2 = $fNumInt64_closure;
         Sp = Sp - 32;
         jump fromInteger_info; // [R2]
     cB4: jump stg_gc_enter_1; // [R1]
     cB6:
         HpAlloc = 16;
         goto cB4;

Which generates out to:

_cB2:
    leaq -32(%rbp),%rax
    cmpq %r15,%rax
    jb _cB4
    addq $16,%r12
    cmpq 144(%r13),%r12
    ja _cB6
    movq $stg_upd_frame_info,-16(%rbp)
    movq %rbx,-8(%rbp)
    movq $S#_con_info,-8(%r12)
    movq $0,0(%r12)
    leaq -7(%r12),%rax
    movq %rax,-24(%rbp)
    movq $stg_ap_p_info,-32(%rbp)
    movl $$fNumInt64_closure,%r14d
    addq $-32,%rbp
    jmp fromInteger_info
_cB6:
    movq $16,192(%r13)
_cB4:
    jmp *-16(%r13)
    .size sat_info, .-sat_info

Invariably you'll get a lot of "noise" from all the the GC functions and various runtime calls, and opaque predefined closure objects. But if you really want to dig into the generated looking at the Cmm first is the way to go.

like image 21
Stephen Diehl Avatar answered Jan 18 '23 18:01

Stephen Diehl