SPARC NCG, how to debug load isn issue.

Karel Gardas karel.gardas at
Sat Jan 24 21:54:43 UTC 2015


from time to time I'm attempting to resurrect SPARC NCG. It looks like 
it's off by default since 7.4? release and I feel it's kind of pity. 
I've been able to hack it on 7.6.x and make it functional. I failed on 
7.8 and later. Double float load was broken there.

Now, I'm attempting on fairly recent GHC HEAD as of Jan 17 and I do have 
problem with illegal isn generated into the binary. This is caused by LD 
II64 ... Instr to be translated to SPARC ldd <addr>,g1 where g1 reg is 
not even, but odd and this fails as spec. says:

The load doubleword integer instructions (LDD, LDDA) move a doubleword
from memory into an r register pair. The more significant word at the
effective memory address is moved into the even r register. The less
significant word (at the effective memory address + 4) is moved into the 
odd r register. (Note that a load doubleword with rd = 0 modifies
only r[1].) The least significant bit of the rd field is unused and 
should be set
to zero by software. An attempt to execute a load doubleword instruction
that refers to a mis-aligned (odd) destination register number may cause an
illegal_instruction trap.

I've found out that the problematic source code is HeapStackCheck.cmm 
and the problematic piece is:

             if (Capability_context_switch(MyCapability()) != 0 :: CInt ||
                 Capability_interrupt(MyCapability())      != 0 :: CInt ||
                 (StgTSO_alloc_limit(CurrentTSO) `lt` (0::I64) &&
                  (TO_W_(StgTSO_flags(CurrentTSO)) & TSO_ALLOC_LIMIT) != 
0)) {
                 ret = ThreadYielding;
                 goto sched;

This "(0::I64)" causes it. So that's the problem description. Now I'm 
attempting to debug it a little bit to find out where the LD II64 Instr 
is generated and I'm not able to find single place which would looks 
familiar with asm I get here:

         ld      [%i1+812],%g1
         ldd     [%g1+64],%g1
         cmp     %g1,0
         bge     .Lcs
         b       .Lcr

more importantly when I look into sparc's version on mkLoadInstr, I 
don't see any way how it may generate LD II64:

sparc_mkLoadInstr dflags reg _ slot
   = let platform = targetPlatform dflags
         off      = spillSlotToOffset dflags slot
         off_w   = 1 + (off `div` 4)
         sz      = case targetClassOfReg platform reg of
                         RcInteger -> II32
                         RcFloat   -> FF32
                         RcDouble  -> FF64
                         _         -> panic "sparc_mkLoadInstr"

         in LD sz (fpRel (- off_w)) reg

In whole SPARC NCG I've found the only place which clearly uses LD II64 
and this is in Gen32.hs for loading literal float into reg:

getRegister (CmmLit (CmmFloat d W64)) = do
     lbl <- getNewLabelNat
     tmp <- getNewRegNat II32
     let code dst = toOL [
             LDATA ReadOnlyData $ Statics lbl
                          [CmmStaticLit (CmmFloat d W64)],
             SETHI (HI (ImmCLbl lbl)) tmp,
             LD II64 (AddrRegImm tmp (LO (ImmCLbl lbl))) dst]
     return (Any FF64 code)

It's interesting but also iselExpr64 which should be probably here for 
manipulating 64bit data on 32bit platform, so even this is using pairs 
of LD II32 Instrs instead of single LD II64....

So I'm kind of out of idea where the LD II64 gets in the flow and is 
later translated into ldd with problematic reg.

Do you have any idea how to debug this issue? Or do you have any idea 
where to read more about general structure of NCG, I've already seen 
-- but this is kind of dated...

Thanks for any idea how to proceed!

More information about the ghc-devs mailing list