X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Fcompiler%2Fghci%2FByteCodeFFI.lhs;h=06c1aa1b654276be87f4cab4e62f3bde38466573;hb=2724902344992a88cc142a892b353466146b348d;hp=569e4f6ce5dd5a6df7f1c6fc2daef01d342a7f95;hpb=200114ef252e71db86291af96fa9ad26ac0de4c5;p=ghc-hetmet.git diff --git a/ghc/compiler/ghci/ByteCodeFFI.lhs b/ghc/compiler/ghci/ByteCodeFFI.lhs index 569e4f6..06c1aa1 100644 --- a/ghc/compiler/ghci/ByteCodeFFI.lhs +++ b/ghc/compiler/ghci/ByteCodeFFI.lhs @@ -4,50 +4,27 @@ \section[ByteCodeGen]{Generate machine-code sequences for foreign import} \begin{code} -module ByteCodeFFI ( taggedSizeW, untaggedSizeW, mkMarshalCode, moan64 ) where +module ByteCodeFFI ( mkMarshalCode, moan64 ) where #include "HsVersions.h" import Outputable -import PrimRep ( PrimRep(..), getPrimRepSize, isFollowableRep ) +import SMRep ( CgRep(..), cgRepSizeW ) import ForeignCall ( CCallConv(..) ) +import Panic --- DON'T remove apparently unused imports here .. there is ifdeffery --- below -import Bits ( Bits(..), shiftR, shiftL ) +-- DON'T remove apparently unused imports here .. +-- there is ifdeffery below +import Control.Exception ( throwDyn ) +import DATA_BITS ( Bits(..), shiftR, shiftL ) import Foreign ( newArray ) +import Data.List ( mapAccumL ) -import Word ( Word8, Word32 ) -import Foreign ( Ptr, mallocBytes ) -import IOExts ( trace, unsafePerformIO ) +import DATA_WORD ( Word8, Word32 ) +import Foreign ( Ptr ) +import System.IO.Unsafe ( unsafePerformIO ) import IO ( hPutStrLn, stderr ) -\end{code} - -%************************************************************************ -%* * -\subsection{The sizes of things. These are platform-independent.} -%* * -%************************************************************************ - -\begin{code} - --- When I push one of these on the H stack, how much does Sp move by? -taggedSizeW :: PrimRep -> Int -taggedSizeW pr - | isFollowableRep pr = 1 {-it's a pointer, Jim-} - | otherwise = 1 {-the tag-} + getPrimRepSize pr - --- The plain size of something, without tag. -untaggedSizeW :: PrimRep -> Int -untaggedSizeW pr - | isFollowableRep pr = 1 - | otherwise = getPrimRepSize pr - --- How big is this thing's tag? -sizeOfTagW :: PrimRep -> Int -sizeOfTagW pr - | isFollowableRep pr = 0 - | otherwise = 1 +-- import Debug.Trace ( trace ) \end{code} %************************************************************************ @@ -92,7 +69,7 @@ itself expects only to be called using the ccall convention -- that is, we don't clear our own (single) arg off the C stack. -} mkMarshalCode :: CCallConv - -> (Int, PrimRep) -> Int -> [(Int, PrimRep)] + -> (Int, CgRep) -> Int -> [(Int, CgRep)] -> IO (Ptr Word8) mkMarshalCode cconv (r_offW, r_rep) addr_offW arg_offs_n_reps = let bytes = mkMarshalCode_wrk cconv (r_offW, r_rep) @@ -103,7 +80,7 @@ mkMarshalCode cconv (r_offW, r_rep) addr_offW arg_offs_n_reps mkMarshalCode_wrk :: CCallConv - -> (Int, PrimRep) -> Int -> [(Int, PrimRep)] + -> (Int, CgRep) -> Int -> [(Int, CgRep)] -> [Word8] mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps @@ -113,18 +90,10 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps = let -- Don't change this without first consulting Intel Corp :-) bytes_per_word = 4 - -- addr and result bits offsetsW - offset_of_addr_bitsW = addr_offW + sizeOfTagW AddrRep - offset_of_res_bitsW = r_offW + sizeOfTagW r_rep - offsets_to_pushW = concat - [ let -- where this arg's bits start - a_bits_offW = a_offW + sizeOfTagW a_rep - in - -- reversed because x86 is little-endian - reverse - [a_bits_offW .. a_bits_offW + untaggedSizeW a_rep - 1] + [ -- reversed because x86 is little-endian + reverse [a_offW .. a_offW + cgRepSizeW a_rep - 1] -- reversed because args are pushed L -> R onto C stack | (a_offW, a_rep) <- reverse arg_offs_n_reps @@ -220,10 +189,9 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps -} ++ movl_offespmem_esi 32 - {- For each arg in args_offs_n_reps, examine the associated PrimRep - to determine how many payload (non-tag) words there are, and - whether or not there is a tag. This gives a bunch of offsets on - the H stack to copy to the C stack: + {- For each arg in args_offs_n_reps, examine the associated + CgRep to determine how many words there are. This gives a + bunch of offsets on the H stack to copy to the C stack: movl off1(%esi), %ecx pushl %ecx @@ -238,7 +206,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps movl 4*(1 /*tag*/ +addr_offW)(%esi), %ecx call * %ecx -} - ++ movl_offesimem_ecx (bytes_per_word * offset_of_addr_bitsW) + ++ movl_offesimem_ecx (bytes_per_word * addr_offW) ++ call_star_ecx {- Nuke the args just pushed and re-establish %esi at the @@ -264,21 +232,17 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps or fstps 4(%esi) -} - ++ let i32 = movl_eax_offesimem 4 - i64 = movl_eax_offesimem 4 ++ movl_edx_offesimem 8 - f32 = fstps_offesimem 4 - f64 = fstpl_offesimem 4 + ++ let i32 = movl_eax_offesimem 0 + i64 = movl_eax_offesimem 0 ++ movl_edx_offesimem 4 + f32 = fstps_offesimem 0 + f64 = fstpl_offesimem 0 in case r_rep of - CharRep -> i32 - IntRep -> i32 - WordRep -> i32 - AddrRep -> i32 - DoubleRep -> f64 - FloatRep -> f32 - -- Word64Rep -> i64 - -- Int64Rep -> i64 - VoidRep -> [] + NonPtrArg -> i32 + DoubleArg -> f64 + FloatArg -> f32 + -- LongArg -> i64 + VoidArg -> [] other -> moan64 "ByteCodeFFI.mkMarshalCode_wrk(x86)" (ppr r_rep) @@ -311,16 +275,9 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps fromIntegral (0xFF .&. (w `shiftR` 8)), fromIntegral (0xFF .&. w)] - -- addr and result bits offsetsW - offset_of_addr_bitsW = addr_offW + sizeOfTagW AddrRep - offset_of_res_bitsW = r_offW + sizeOfTagW r_rep - offsets_to_pushW = concat - [ let -- where this arg's bits start - a_bits_offW = a_offW + sizeOfTagW a_rep - in - [a_bits_offW .. a_bits_offW + untaggedSizeW a_rep - 1] + [ [a_offW .. a_offW + cgRepSizeW a_rep - 1] | (a_offW, a_rep) <- arg_offs_n_reps ] @@ -426,11 +383,11 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps -} [mkSAVE sp (- ({-92-}112 + 4*argWs_on_stack_ROUNDED_UP)) sp] - {- For each arg in args_offs_n_reps, examine the associated PrimRep - to determine how many payload (non-tag) words there are, and - whether or not there is a tag. This gives a bunch of offsets on - the H stack. Move the first 6 words into %o0 .. %o5 and the - rest on the stack, starting at [%sp+92]. Use %g1 as a temp. + {- For each arg in args_offs_n_reps, examine the associated + CgRep to determine how many words there are. This gives a + bunch of offsets on the H stack. Move the first 6 words into + %o0 .. %o5 and the rest on the stack, starting at [%sp+92]. + Use %g1 as a temp. -} ++ let doArgW (offW, wordNo) | wordNo < 6 @@ -447,7 +404,7 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps ld [4*(1 /*tag*/ +addr_offW) + %i0], %g1 call %g1 -} - ++ [mkLD i0 (bytes_per_word * offset_of_addr_bitsW) g1, + ++ [mkLD i0 (bytes_per_word * addr_offW) g1, mkCALL g1, mkNOP] @@ -465,26 +422,23 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps st %f1, [%i0 + 8] -- or the other way round? -} - ++ let i32 = [mkST o0 i0 4] - i64 = [mkST o0 i0 4, mkST o1 i0 8] - f32 = [mkSTF f0 i0 4] - f64 = [mkSTF f0 i0 4, mkSTF f1 i0 8] + ++ let i32 = [mkST o0 i0 0] + i64 = [mkST o0 i0 0, mkST o1 i0 4] + f32 = [mkSTF f0 i0 0] + f64 = [mkSTF f0 i0 0, mkSTF f1 i0 4] in case r_rep of - CharRep -> i32 - IntRep -> i32 - WordRep -> i32 - AddrRep -> i32 - DoubleRep -> f64 - FloatRep -> f32 - VoidRep -> [] + NonPtrArg -> i32 + DoubleArg -> f64 + FloatArg -> f32 + VoidArg -> [] other -> moan64 "ByteCodeFFI.mkMarshalCode_wrk(sparc)" (ppr r_rep) ++ [mkRET, mkRESTORE_TRIVIAL] -- this is in the delay slot of the RET ) -#elif powerpc_TARGET_ARCH +#elif powerpc_TARGET_ARCH && darwin_TARGET_OS = let bytes_per_word = 4 @@ -498,14 +452,14 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps fromIntegral (0xFF .&. w)] -- addr and result bits offsetsW - a_off = (addr_offW + sizeOfTagW AddrRep) * bytes_per_word - result_off = (r_offW + sizeOfTagW r_rep) * bytes_per_word + a_off = addr_offW * bytes_per_word + result_off = r_offW * bytes_per_word linkageArea = 24 - parameterArea = sum [ untaggedSizeW a_rep * bytes_per_word + parameterArea = sum [ cgRepSizeW a_rep * bytes_per_word | (_, a_rep) <- arg_offs_n_reps ] savedRegisterArea = 4 - frameSize = padTo16 (linkageArea + min parameterArea 32 + savedRegisterArea) + frameSize = padTo16 (linkageArea + max parameterArea 32 + savedRegisterArea) padTo16 x = case x `mod` 16 of 0 -> x y -> x - y + 16 @@ -513,12 +467,11 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps pass_parameters [] _ _ = [] pass_parameters ((a_offW, a_rep):args) nextFPR offsetW = let - haskellArgOffset = (a_offW + sizeOfTagW a_rep) - * bytes_per_word - offsetW' = offsetW + untaggedSizeW a_rep + haskellArgOffset = a_offW * bytes_per_word + offsetW' = offsetW + cgRepSizeW a_rep pass_word w - | w < 8 = + | offsetW + w < 8 = [0x801f0000 -- lwz rX, src(r31) .|. (fromIntegral src .&. 0xFFFF) .|. (fromIntegral (offsetW+w+3) `shiftL` 21)] @@ -532,34 +485,34 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps dst = linkageArea + (offsetW+w) * bytes_per_word in case a_rep of - FloatRep | nextFPR < 14 -> + FloatArg | nextFPR < 14 -> (0xc01f0000 -- lfs fX, haskellArgOffset(r31) .|. (fromIntegral haskellArgOffset .&. 0xFFFF) .|. (fromIntegral nextFPR `shiftL` 21)) : pass_parameters args (nextFPR+1) offsetW' - DoubleRep | nextFPR < 14 -> + DoubleArg | nextFPR < 14 -> (0xc81f0000 -- lfd fX, haskellArgOffset(r31) .|. (fromIntegral haskellArgOffset .&. 0xFFFF) .|. (fromIntegral nextFPR `shiftL` 21)) : pass_parameters args (nextFPR+1) offsetW' _ -> - concatMap pass_word [0 .. untaggedSizeW a_rep - 1] + concatMap pass_word [0 .. cgRepSizeW a_rep - 1] ++ pass_parameters args nextFPR offsetW' gather_result = case r_rep of - VoidRep -> [] - FloatRep -> + VoidArg -> [] + FloatArg -> [0xd03f0000 .|. (fromIntegral result_off .&. 0xFFFF)] -- stfs f1, result_off(r31) - DoubleRep -> + DoubleArg -> [0xd83f0000 .|. (fromIntegral result_off .&. 0xFFFF)] - -- stfs f1, result_off(r31) - _ | untaggedSizeW r_rep == 2 -> + -- stfd f1, result_off(r31) + _ | cgRepSizeW r_rep == 2 -> [0x907f0000 .|. (fromIntegral result_off .&. 0xFFFF), 0x909f0000 .|. (fromIntegral (result_off+4) .&. 0xFFFF)] -- stw r3, result_off(r31) -- stw r4, result_off+4(r31) - _ | untaggedSizeW r_rep == 1 -> + _ | cgRepSizeW r_rep == 1 -> [0x907f0000 .|. (fromIntegral result_off .&. 0xFFFF)] -- stw r3, result_off(r31) in @@ -582,9 +535,111 @@ mkMarshalCode_wrk cconv (r_offW, r_rep) addr_offW arg_offs_n_reps 0x7c0803a6, -- mtlr r0 0x4e800020 -- blr ] + +#elif powerpc_TARGET_ARCH && linux_TARGET_OS + + -- All offsets here are measured in Words (not bytes). This includes + -- arguments to the load/store machine code generators, alignment numbers + -- and the final 'framesize' among others. + + = concatMap w32_to_w8s_bigEndian $ [ + 0x7c0802a6, -- mflr r0 + 0x93e1fffc, -- stw r31,-4(r1) + 0x90010008, -- stw r0,8(r1) + 0x94210000 .|. offset (-framesize), -- stwu r1, -frameSize(r1) + 0x7c7f1b78 -- mr r31, r3 + ] ++ pass_parameters ++ -- pass the parameters + loadWord 12 addr_offW ++ [ -- lwz r12, a_off(r31) + 0x7d8903a6, -- mtctr r12 + 0x4e800421 -- bctrl + ] ++ gather_result ++ [ -- save the return value + 0x80210000, -- lwz r1, 0(r1) + 0x83e1fffc, -- lwz r31, -4(r1) + 0x80010008, -- lwz r0, 8(r1) + 0x7c0803a6, -- mtlr r0 + 0x4e800020 -- blr + ] + + where + gather_result :: [Word32] + gather_result = case r_rep of + VoidArg -> [] + FloatArg -> storeFloat 1 r_offW + DoubleArg -> storeDouble 1 r_offW + LongArg -> storeLong 3 r_offW + _ -> storeWord 3 r_offW + + pass_parameters :: [Word32] + pass_parameters = concat params + + -- vector aligned (4 word = 16 bytes) with 8 extra words of buffer space + framesize = alignedTo 4 (argsize + 8) + + ((_,_,argsize), params) = mapAccumL loadparam (3,1,2) arg_offs_n_reps + + -- handle one argument, returning machine code and the updated state + loadparam :: (Int, Int, Int) -> (Int, CgRep) -> + ((Int, Int, Int), [Word32]) + + loadparam (gpr, fpr, stack) (ofs, rep) = case rep of + FloatArg | fpr <= 8 -> ( (gpr, fpr + 1, stack), loadFloat fpr ofs ) + FloatArg -> ( (gpr, fpr, stack + 1), stackWord stack ofs ) + + DoubleArg | fpr <= 8 -> ( (gpr, fpr + 1, stack), loadDouble fpr ofs ) + DoubleArg -> ( (gpr, fpr, astack + 2), stackLong astack ofs ) + + LongArg | even gpr -> loadparam (gpr + 1, fpr, stack) (ofs, rep) + LongArg | gpr <= 9 -> ( (gpr + 2, fpr, stack), loadLong gpr ofs ) + LongArg -> ( (gpr, fpr, astack + 2), stackLong astack ofs ) + + _ | gpr <= 10 -> ( (gpr + 1, fpr, stack), loadWord gpr ofs ) + _ -> ( (gpr, fpr, stack + 1), stackWord stack ofs ) + where astack = alignedTo 2 stack + + alignedTo :: Int -> Int -> Int + alignedTo alignment x = case x `mod` alignment of + 0 -> x + y -> x - y + alignment + + -- convenience macros to do multiple-instruction data moves + stackWord dst src = loadWord 0 src ++ storeWordC 0 dst + stackLong dst src = stackWord dst src ++ stackWord (dst + 1) (src + 1) + loadLong dst src = loadWord dst src ++ loadWord (dst + 1) (src + 1) + storeLong dst src = storeWord dst src ++ storeWord (dst + 1) (src + 1) + + -- load data from the Haskell stack (relative to r31) + loadFloat = loadstoreInstr 0xc01f0000 -- lfs fpr, ofs(r31) + loadDouble = loadstoreInstr 0xc81f0000 -- lfd fpr, ofs(r31) + loadWord = loadstoreInstr 0x801f0000 -- lwz gpr, ofs(r31) + + -- store data to the Haskell stack (relative to r31) + storeFloat = loadstoreInstr 0xd01f0000 -- stfs fpr, ofs(r31) + storeDouble = loadstoreInstr 0xd81f0000 -- stfd fpr, ofs(r31) + storeWord = loadstoreInstr 0x901f0000 -- stw gpr, ofs(r31) + + -- store data to the C stack (relative to r1) + storeWordC = loadstoreInstr 0x90010000 -- stw gpr, ofs(r1) + + -- machine code building blocks + loadstoreInstr :: Word32 -> Int -> Int -> [Word32] + loadstoreInstr code reg ofs = [ code .|. register reg .|. offset ofs ] + + register :: Int -> Word32 + register reg = fromIntegral reg `shiftL` 21 + + offset :: Int -> Word32 + offset ofs = fromIntegral (ofs * 4) .&. 0xFFFF + + -- speaks for itself + w32_to_w8s_bigEndian :: Word32 -> [Word8] + w32_to_w8s_bigEndian w = [fromIntegral (0xFF .&. (w `shiftR` 24)), + fromIntegral (0xFF .&. (w `shiftR` 16)), + fromIntegral (0xFF .&. (w `shiftR` 8)), + fromIntegral (0xFF .&. w)] + #else - = undefined + = throwDyn (InstallationError "foreign import is not implemented for GHCi on this platform.") #endif