[project @ 2002-09-13 15:02:25 by simonpj]
[ghc-hetmet.git] / ghc / compiler / nativeGen / PprMach.lhs
index 13b1759..564a799 100644 (file)
@@ -22,10 +22,18 @@ import Stix         ( CodeSegment(..) )
 import Unique          ( pprUnique )
 import Panic           ( panic )
 import Pretty
+import FastString
 import qualified Outputable
 
-import ST
+#if __GLASGOW_HASKELL__ >= 504
+import Data.Array.ST
+import Data.Word       ( Word8 )
+#else
 import MutableArray
+#endif
+
+import MONAD_ST
+
 import Char            ( chr, ord )
 import Maybe           ( isJust )
 
@@ -387,13 +395,13 @@ pprInstr :: Instr -> Doc
 
 --pprInstr (COMMENT s) = empty -- nuke 'em
 pprInstr (COMMENT s)
-   =  IF_ARCH_alpha( ((<>) (ptext SLIT("\t# ")) (ptext s))
-     ,IF_ARCH_sparc( ((<>) (ptext SLIT("! "))   (ptext s))
-     ,IF_ARCH_i386( ((<>) (ptext SLIT("# "))   (ptext s))
+   =  IF_ARCH_alpha( ((<>) (ptext SLIT("\t# ")) (ftext s))
+     ,IF_ARCH_sparc( ((<>) (ptext SLIT("! "))   (ftext s))
+     ,IF_ARCH_i386( ((<>) (ptext SLIT("# "))   (ftext s))
      ,)))
 
 pprInstr (DELTA d)
-   = pprInstr (COMMENT (_PK_ ("\tdelta = " ++ show d)))
+   = pprInstr (COMMENT (mkFastString ("\tdelta = " ++ show d)))
 
 pprInstr (SEGMENT TextSegment)
     =  IF_ARCH_alpha(ptext SLIT("\t.text\n\t.align 3") {-word boundary-}
@@ -477,38 +485,6 @@ pprInstr (DATA s xs)
              in  map (\b -> ptext SLIT("\t.byte\t") <> pprImm (ImmInt b)) bs
 #endif
 
-        -- floatToBytes and doubleToBytes convert to the host's byte
-        -- order.  Providing that we're not cross-compiling for a 
-        -- target with the opposite endianness, this should work ok
-        -- on all targets.
-        floatToBytes :: Float -> [Int]
-        floatToBytes f
-           = runST (do
-                arr <- newFloatArray ((0::Int),3)
-                writeFloatArray arr 0 f
-                i0 <- readCharArray arr 0
-                i1 <- readCharArray arr 1
-                i2 <- readCharArray arr 2
-                i3 <- readCharArray arr 3
-                return (map ord [i0,i1,i2,i3])
-             )
-
-        doubleToBytes :: Double -> [Int]
-        doubleToBytes d
-           = runST (do
-                arr <- newDoubleArray ((0::Int),7)
-                writeDoubleArray arr 0 d
-                i0 <- readCharArray arr 0
-                i1 <- readCharArray arr 1
-                i2 <- readCharArray arr 2
-                i3 <- readCharArray arr 3
-                i4 <- readCharArray arr 4
-                i5 <- readCharArray arr 5
-                i6 <- readCharArray arr 6
-                i7 <- readCharArray arr 7
-                return (map ord [i0,i1,i2,i3,i4,i5,i6,i7])
-             )
-
 -- fall through to rest of (machine-specific) pprInstr...
 \end{code}
 
@@ -868,8 +844,7 @@ pprRI :: RI -> Doc
 pprRI (RIReg r) = pprReg r
 pprRI (RIImm r) = pprImm r
 
-pprRegRIReg :: FAST_STRING -> Reg -> RI -> Reg -> Doc
-
+pprRegRIReg :: LitString -> Reg -> RI -> Reg -> Doc
 pprRegRIReg name reg1 ri reg2
   = hcat [
        char '\t',
@@ -882,8 +857,7 @@ pprRegRIReg name reg1 ri reg2
        pprReg reg2
     ]
 
-pprSizeRegRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Reg -> Doc
-
+pprSizeRegRegReg :: LitString -> Size -> Reg -> Reg -> Reg -> Doc
 pprSizeRegRegReg name size reg1 reg2 reg3
   = hcat [
        char '\t',
@@ -971,8 +945,8 @@ pprInstr (POP size op) = pprSizeOp SLIT("pop") size op
 pprInstr PUSHA = ptext SLIT("\tpushal")
 pprInstr POPA = ptext SLIT("\tpopal")
 
-pprInstr (NOP) = ptext SLIT("\tnop")
-pprInstr (CLTD) = ptext SLIT("\tcltd")
+pprInstr NOP = ptext SLIT("\tnop")
+pprInstr CLTD = ptext SLIT("\tcltd")
 
 pprInstr (SETCC cond op) = pprCondInstr SLIT("set") cond (pprOperand B op)
 
@@ -980,7 +954,8 @@ pprInstr (JXX cond lab) = pprCondInstr SLIT("j") cond (pprCLabel_asm lab)
 
 pprInstr (JMP dsts (OpImm imm)) = (<>) (ptext SLIT("\tjmp ")) (pprImm imm)
 pprInstr (JMP dsts op)          = (<>) (ptext SLIT("\tjmp *")) (pprOperand L op)
-pprInstr (CALL imm)             = (<>) (ptext SLIT("\tcall ")) (pprImm imm)
+pprInstr (CALL (Left imm))      = (<>) (ptext SLIT("\tcall ")) (pprImm imm)
+pprInstr (CALL (Right reg))     = (<>) (ptext SLIT("\tcall *")) (pprReg L reg)
 
 -- First bool indicates signedness; second whether quot or rem
 pprInstr (IQUOT sz src dst) = pprInstr_quotRem True True sz src dst
@@ -1030,11 +1005,74 @@ pprInstr g@(GITOD src dst)
                    text " ; ffree %st(7); fildl (%esp) ; ",
                    gpop dst 1, text " ; addl $4,%esp"])
 
-pprInstr g@(GCMP sz src1 src2) 
-   = pprG g (hcat [gtab, text "pushl %eax ; ",gpush src1 0]
-             $$
-             hcat [gtab, text "fcomp ", greg src2 1, 
-                   text "; fstsw %ax ; sahf ; popl %eax"])
+{- Gruesome swamp follows.  If you're unfortunate enough to have ventured
+   this far into the jungle AND you give a Rat's Ass (tm) what's going
+   on, here's the deal.  Generate code to do a floating point comparison
+   of src1 and src2, of kind cond, and set the Zero flag if true.
+
+   The complications are to do with handling NaNs correctly.  We want the
+   property that if either argument is NaN, then the result of the
+   comparison is False ... except if we're comparing for inequality,
+   in which case the answer is True.
+
+   Here's how the general (non-inequality) case works.  As an
+   example, consider generating the an equality test:
+
+     pushl %eax                -- we need to mess with this
+     <get src1 to top of FPU stack>
+     fcomp <src2 location in FPU stack> and pop pushed src1
+               -- Result of comparison is in FPU Status Register bits
+               -- C3 C2 and C0
+     fstsw %ax -- Move FPU Status Reg to %ax
+     sahf      -- move C3 C2 C0 from %ax to integer flag reg
+     -- now the serious magic begins
+     setpo %ah    -- %ah = if comparable(neither arg was NaN) then 1 else 0
+     sete  %al     -- %al = if arg1 == arg2 then 1 else 0
+     andb %ah,%al  -- %al &= %ah
+                   -- so %al == 1 iff (comparable && same); else it holds 0
+     decb %al     -- %al == 0, ZeroFlag=1  iff (comparable && same); 
+                      else %al == 0xFF, ZeroFlag=0
+     -- the zero flag is now set as we desire.
+     popl %eax
+
+   The special case of inequality differs thusly:
+
+     setpe %ah     -- %ah = if incomparable(either arg was NaN) then 1 else 0
+     setne %al     -- %al = if arg1 /= arg2 then 1 else 0
+     orb %ah,%al   -- %al = if (incomparable || different) then 1 else 0
+     decb %al      -- if (incomparable || different) then (%al == 0, ZF=1)
+                                                     else (%al == 0xFF, ZF=0)
+-}
+pprInstr g@(GCMP cond src1 src2) 
+   | case cond of { NE -> True; other -> False }
+   = pprG g (vcat [
+        hcat [gtab, text "pushl %eax ; ",gpush src1 0],
+        hcat [gtab, text "fcomp ", greg src2 1, 
+                    text "; fstsw %ax ; sahf ;  setpe %ah"],
+        hcat [gtab, text "setne %al ;  ",
+              text "orb %ah,%al ;  decb %al ;  popl %eax"]
+    ])
+   | otherwise
+   = pprG g (vcat [
+        hcat [gtab, text "pushl %eax ; ",gpush src1 0],
+        hcat [gtab, text "fcomp ", greg src2 1, 
+                    text "; fstsw %ax ; sahf ;  setpo %ah"],
+        hcat [gtab, text "set", pprCond (fix_FP_cond cond), text " %al ;  ",
+              text "andb %ah,%al ;  decb %al ;  popl %eax"]
+    ])
+    where
+        {- On the 486, the flags set by FP compare are the unsigned ones!
+           (This looks like a HACK to me.  WDP 96/03)
+        -}
+        fix_FP_cond :: Cond -> Cond
+        fix_FP_cond GE   = GEU
+        fix_FP_cond GTT  = GU
+        fix_FP_cond LTT  = LU
+        fix_FP_cond LE   = LEU
+        fix_FP_cond EQQ  = EQQ
+        fix_FP_cond NE   = NE
+        -- there should be no others
+
 
 pprInstr g@(GABS sz src dst)
    = pprG g (hcat [gtab, gpush src 0, text " ; fabs ; ", gpop dst 1])
@@ -1204,7 +1242,7 @@ pprGInstr (GDTOI src dst) = pprSizeSizeRegReg SLIT("gdtoi") DF L src dst
 pprGInstr (GITOF src dst) = pprSizeSizeRegReg SLIT("gitof") L F  src dst
 pprGInstr (GITOD src dst) = pprSizeSizeRegReg SLIT("gitod") L DF src dst
 
-pprGInstr (GCMP sz src dst) = pprSizeRegReg SLIT("gcmp") sz src dst
+pprGInstr (GCMP co src dst) = pprCondRegReg SLIT("gcmp_") DF co src dst
 pprGInstr (GABS sz src dst) = pprSizeRegReg SLIT("gabs") sz src dst
 pprGInstr (GNEG sz src dst) = pprSizeRegReg SLIT("gneg") sz src dst
 pprGInstr (GSQRT sz src dst) = pprSizeRegReg SLIT("gsqrt") sz src dst
@@ -1229,7 +1267,7 @@ pprOperand s (OpReg r)   = pprReg s r
 pprOperand s (OpImm i)   = pprDollImm i
 pprOperand s (OpAddr ea) = pprAddr ea
 
-pprSizeImmOp :: FAST_STRING -> Size -> Imm -> Operand -> Doc
+pprSizeImmOp :: LitString -> Size -> Imm -> Operand -> Doc
 pprSizeImmOp name size imm op1
   = hcat [
         char '\t',
@@ -1242,7 +1280,7 @@ pprSizeImmOp name size imm op1
        pprOperand size op1
     ]
        
-pprSizeOp :: FAST_STRING -> Size -> Operand -> Doc
+pprSizeOp :: LitString -> Size -> Operand -> Doc
 pprSizeOp name size op1
   = hcat [
        char '\t',
@@ -1252,7 +1290,7 @@ pprSizeOp name size op1
        pprOperand size op1
     ]
 
-pprSizeOpOp :: FAST_STRING -> Size -> Operand -> Operand -> Doc
+pprSizeOpOp :: LitString -> Size -> Operand -> Operand -> Doc
 pprSizeOpOp name size op1 op2
   = hcat [
        char '\t',
@@ -1264,7 +1302,7 @@ pprSizeOpOp name size op1 op2
        pprOperand size op2
     ]
 
-pprSizeByteOpOp :: FAST_STRING -> Size -> Operand -> Operand -> Doc
+pprSizeByteOpOp :: LitString -> Size -> Operand -> Operand -> Doc
 pprSizeByteOpOp name size op1 op2
   = hcat [
        char '\t',
@@ -1276,7 +1314,7 @@ pprSizeByteOpOp name size op1 op2
        pprOperand size op2
     ]
 
-pprSizeOpReg :: FAST_STRING -> Size -> Operand -> Reg -> Doc
+pprSizeOpReg :: LitString -> Size -> Operand -> Reg -> Doc
 pprSizeOpReg name size op1 reg
   = hcat [
        char '\t',
@@ -1288,7 +1326,7 @@ pprSizeOpReg name size op1 reg
        pprReg size reg
     ]
 
-pprSizeReg :: FAST_STRING -> Size -> Reg -> Doc
+pprSizeReg :: LitString -> Size -> Reg -> Doc
 pprSizeReg name size reg1
   = hcat [
        char '\t',
@@ -1298,7 +1336,7 @@ pprSizeReg name size reg1
        pprReg size reg1
     ]
 
-pprSizeRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Doc
+pprSizeRegReg :: LitString -> Size -> Reg -> Reg -> Doc
 pprSizeRegReg name size reg1 reg2
   = hcat [
        char '\t',
@@ -1310,7 +1348,19 @@ pprSizeRegReg name size reg1 reg2
         pprReg size reg2
     ]
 
-pprSizeSizeRegReg :: FAST_STRING -> Size -> Size -> Reg -> Reg -> Doc
+pprCondRegReg :: LitString -> Size -> Cond -> Reg -> Reg -> Doc
+pprCondRegReg name size cond reg1 reg2
+  = hcat [
+       char '\t',
+       ptext name,
+       pprCond cond,
+       space,
+       pprReg size reg1,
+        comma,
+        pprReg size reg2
+    ]
+
+pprSizeSizeRegReg :: LitString -> Size -> Size -> Reg -> Reg -> Doc
 pprSizeSizeRegReg name size1 size2 reg1 reg2
   = hcat [
        char '\t',
@@ -1319,11 +1369,12 @@ pprSizeSizeRegReg name size1 size2 reg1 reg2
         pprSize size2,
        space,
        pprReg size1 reg1,
+
         comma,
         pprReg size2 reg2
     ]
 
-pprSizeRegRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Reg -> Doc
+pprSizeRegRegReg :: LitString -> Size -> Reg -> Reg -> Reg -> Doc
 pprSizeRegRegReg name size reg1 reg2 reg3
   = hcat [
        char '\t',
@@ -1337,7 +1388,7 @@ pprSizeRegRegReg name size reg1 reg2 reg3
         pprReg size reg3
     ]
 
-pprSizeAddr :: FAST_STRING -> Size -> MachRegsAddr -> Doc
+pprSizeAddr :: LitString -> Size -> MachRegsAddr -> Doc
 pprSizeAddr name size op
   = hcat [
        char '\t',
@@ -1347,7 +1398,7 @@ pprSizeAddr name size op
        pprAddr op
     ]
 
-pprSizeAddrReg :: FAST_STRING -> Size -> MachRegsAddr -> Reg -> Doc
+pprSizeAddrReg :: LitString -> Size -> MachRegsAddr -> Reg -> Doc
 pprSizeAddrReg name size op dst
   = hcat [
        char '\t',
@@ -1359,7 +1410,7 @@ pprSizeAddrReg name size op dst
        pprReg size dst
     ]
 
-pprSizeRegAddr :: FAST_STRING -> Size -> Reg -> MachRegsAddr -> Doc
+pprSizeRegAddr :: LitString -> Size -> Reg -> MachRegsAddr -> Doc
 pprSizeRegAddr name size src op
   = hcat [
        char '\t',
@@ -1371,7 +1422,7 @@ pprSizeRegAddr name size src op
        pprAddr op
     ]
 
-pprOpOp :: FAST_STRING -> Size -> Operand -> Operand -> Doc
+pprOpOp :: LitString -> Size -> Operand -> Operand -> Doc
 pprOpOp name size op1 op2
   = hcat [
        char '\t',
@@ -1381,7 +1432,7 @@ pprOpOp name size op1 op2
        pprOperand size op2
     ]
 
-pprSizeOpOpCoerce :: FAST_STRING -> Size -> Size -> Operand -> Operand -> Doc
+pprSizeOpOpCoerce :: LitString -> Size -> Size -> Operand -> Operand -> Doc
 pprSizeOpOpCoerce name size1 size2 op1 op2
   = hcat [ char '\t', ptext name, pprSize size1, pprSize size2, space,
        pprOperand size1 op1,
@@ -1389,7 +1440,7 @@ pprSizeOpOpCoerce name size1 size2 op1 op2
        pprOperand size2 op2
     ]
 
-pprCondInstr :: FAST_STRING -> Cond -> Doc -> Doc
+pprCondInstr :: LitString -> Cond -> Doc -> Doc
 pprCondInstr name cond arg
   = hcat [ char '\t', ptext name, pprCond cond, space, arg]
 
@@ -1611,8 +1662,10 @@ pprInstr (BF cond b lab)
 
 pprInstr (JMP dsts addr) = (<>) (ptext SLIT("\tjmp\t")) (pprAddr addr)
 
-pprInstr (CALL imm n _)
+pprInstr (CALL (Left imm) n _)
   = hcat [ ptext SLIT("\tcall\t"), pprImm imm, comma, int n ]
+pprInstr (CALL (Right reg) n _)
+  = hcat [ ptext SLIT("\tcall\t"), pprReg reg, comma, int n ]
 \end{code}
 
 Continue with SPARC-only printing bits and bobs:
@@ -1621,7 +1674,7 @@ pprRI :: RI -> Doc
 pprRI (RIReg r) = pprReg r
 pprRI (RIImm r) = pprImm r
 
-pprSizeRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Doc
+pprSizeRegReg :: LitString -> Size -> Reg -> Reg -> Doc
 pprSizeRegReg name size reg1 reg2
   = hcat [
        char '\t',
@@ -1634,7 +1687,7 @@ pprSizeRegReg name size reg1 reg2
        pprReg reg2
     ]
 
-pprSizeRegRegReg :: FAST_STRING -> Size -> Reg -> Reg -> Reg -> Doc
+pprSizeRegRegReg :: LitString -> Size -> Reg -> Reg -> Reg -> Doc
 pprSizeRegRegReg name size reg1 reg2 reg3
   = hcat [
        char '\t',
@@ -1649,7 +1702,7 @@ pprSizeRegRegReg name size reg1 reg2 reg3
        pprReg reg3
     ]
 
-pprRegRIReg :: FAST_STRING -> Bool -> Reg -> RI -> Reg -> Doc
+pprRegRIReg :: LitString -> Bool -> Reg -> RI -> Reg -> Doc
 pprRegRIReg name b reg1 ri reg2
   = hcat [
        char '\t',
@@ -1662,7 +1715,7 @@ pprRegRIReg name b reg1 ri reg2
        pprReg reg2
     ]
 
-pprRIReg :: FAST_STRING -> Bool -> RI -> Reg -> Doc
+pprRIReg :: LitString -> Bool -> RI -> Reg -> Doc
 pprRIReg name b ri reg1
   = hcat [
        char '\t',
@@ -1680,3 +1733,77 @@ pp_comma_a         = text ",a"
 
 #endif {-sparc_TARGET_ARCH-}
 \end{code}
+
+\begin{code}
+#if __GLASGOW_HASKELL__ >= 504
+newFloatArray :: (Int,Int) -> ST s (STUArray s Int Float)
+newFloatArray = newArray_
+
+newDoubleArray :: (Int,Int) -> ST s (STUArray s Int Double)
+newDoubleArray = newArray_
+
+castFloatToCharArray :: STUArray s Int Float -> ST s (STUArray s Int Word8)
+castFloatToCharArray = castSTUArray
+
+castDoubleToCharArray :: STUArray s Int Double -> ST s (STUArray s Int Word8)
+castDoubleToCharArray = castSTUArray
+
+writeFloatArray :: STUArray s Int Float -> Int -> Float -> ST s ()
+writeFloatArray = writeArray
+
+writeDoubleArray :: STUArray s Int Double -> Int -> Double -> ST s ()
+writeDoubleArray = writeArray
+
+readCharArray :: STUArray s Int Word8 -> Int -> ST s Char
+readCharArray arr i = do 
+  w <- readArray arr i
+  return $! (chr (fromIntegral w))
+
+#else
+
+castFloatToCharArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
+castFloatToCharArray = return
+
+castDoubleToCharArray :: MutableByteArray s t -> ST s (MutableByteArray s t)
+castDoubleToCharArray = return
+
+#endif
+
+-- floatToBytes and doubleToBytes convert to the host's byte
+-- order.  Providing that we're not cross-compiling for a 
+-- target with the opposite endianness, this should work ok
+-- on all targets.
+
+-- ToDo: this stuff is very similar to the shenanigans in PprAbs,
+-- could they be merged?
+
+floatToBytes :: Float -> [Int]
+floatToBytes f
+   = runST (do
+        arr <- newFloatArray ((0::Int),3)
+        writeFloatArray arr 0 f
+       arr <- castFloatToCharArray arr
+        i0 <- readCharArray arr 0
+        i1 <- readCharArray arr 1
+        i2 <- readCharArray arr 2
+        i3 <- readCharArray arr 3
+        return (map ord [i0,i1,i2,i3])
+     )
+
+doubleToBytes :: Double -> [Int]
+doubleToBytes d
+   = runST (do
+        arr <- newDoubleArray ((0::Int),7)
+        writeDoubleArray arr 0 d
+       arr <- castDoubleToCharArray arr
+        i0 <- readCharArray arr 0
+        i1 <- readCharArray arr 1
+        i2 <- readCharArray arr 2
+        i3 <- readCharArray arr 3
+        i4 <- readCharArray arr 4
+        i5 <- readCharArray arr 5
+        i6 <- readCharArray arr 6
+        i7 <- readCharArray arr 7
+        return (map ord [i0,i1,i2,i3,i4,i5,i6,i7])
+     )
+\end{code}