module LlvmMangler ( llvmFixupAsm ) where
import GhcPrelude
import DynFlags ( DynFlags, targetPlatform )
import Platform ( platformArch, Arch(..) )
import ErrUtils ( withTiming )
import Outputable ( text )
import Control.Exception
import qualified Data.ByteString.Char8 as B
import System.IO
llvmFixupAsm :: DynFlags -> FilePath -> FilePath -> IO ()
llvmFixupAsm :: DynFlags -> FilePath -> FilePath -> IO ()
llvmFixupAsm dflags :: DynFlags
dflags f1 :: FilePath
f1 f2 :: FilePath
f2 = {-# SCC "llvm_mangler" #-}
IO DynFlags -> SDoc -> (() -> ()) -> IO () -> IO ()
forall (m :: * -> *) a.
MonadIO m =>
m DynFlags -> SDoc -> (a -> ()) -> m a -> m a
withTiming (DynFlags -> IO DynFlags
forall (f :: * -> *) a. Applicative f => a -> f a
pure DynFlags
dflags) (FilePath -> SDoc
text "LLVM Mangler") () -> ()
forall a. a -> a
id (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
FilePath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile FilePath
f1 IOMode
ReadMode ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \r :: Handle
r -> FilePath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile FilePath
f2 IOMode
WriteMode ((Handle -> IO ()) -> IO ()) -> (Handle -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \w :: Handle
w -> do
Handle -> Handle -> IO ()
go Handle
r Handle
w
Handle -> IO ()
hClose Handle
r
Handle -> IO ()
hClose Handle
w
() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
where
go :: Handle -> Handle -> IO ()
go :: Handle -> Handle -> IO ()
go r :: Handle
r w :: Handle
w = do
Either IOError ByteString
e_l <- IO ByteString -> IO (Either IOError ByteString)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO ByteString -> IO (Either IOError ByteString))
-> IO ByteString -> IO (Either IOError ByteString)
forall a b. (a -> b) -> a -> b
$ Handle -> IO ByteString
B.hGetLine Handle
r ::IO (Either IOError B.ByteString)
let writeline :: ByteString -> IO ()
writeline a :: ByteString
a = Handle -> ByteString -> IO ()
B.hPutStrLn Handle
w (DynFlags -> [Rewrite] -> ByteString -> ByteString
rewriteLine DynFlags
dflags [Rewrite]
rewrites ByteString
a) IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Handle -> Handle -> IO ()
go Handle
r Handle
w
case Either IOError ByteString
e_l of
Right l :: ByteString
l -> ByteString -> IO ()
writeline ByteString
l
Left _ -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
rewrites :: [Rewrite]
rewrites :: [Rewrite]
rewrites = [Rewrite
rewriteSymType, Rewrite
rewriteAVX]
type Rewrite = DynFlags -> B.ByteString -> Maybe B.ByteString
rewriteLine :: DynFlags -> [Rewrite] -> B.ByteString -> B.ByteString
rewriteLine :: DynFlags -> [Rewrite] -> ByteString -> ByteString
rewriteLine dflags :: DynFlags
dflags rewrites :: [Rewrite]
rewrites l :: ByteString
l
| ByteString -> Bool
isSubsectionsViaSymbols ByteString
l =
(FilePath -> ByteString
B.pack "## no .subsection_via_symbols for ghc. We need our info tables!")
| Bool
otherwise =
case [Maybe ByteString] -> Maybe ByteString
forall a. [Maybe a] -> Maybe a
firstJust ([Maybe ByteString] -> Maybe ByteString)
-> [Maybe ByteString] -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ (Rewrite -> Maybe ByteString) -> [Rewrite] -> [Maybe ByteString]
forall a b. (a -> b) -> [a] -> [b]
map (\rewrite :: Rewrite
rewrite -> Rewrite
rewrite DynFlags
dflags ByteString
rest) [Rewrite]
rewrites of
Nothing -> ByteString
l
Just rewritten :: ByteString
rewritten -> [ByteString] -> ByteString
B.concat ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ [ByteString
symbol, FilePath -> ByteString
B.pack "\t", ByteString
rewritten]
where
isSubsectionsViaSymbols :: ByteString -> Bool
isSubsectionsViaSymbols = ByteString -> ByteString -> Bool
B.isPrefixOf (FilePath -> ByteString
B.pack ".subsections_via_symbols")
(symbol :: ByteString
symbol, rest :: ByteString
rest) = ByteString -> (ByteString, ByteString)
splitLine ByteString
l
firstJust :: [Maybe a] -> Maybe a
firstJust :: [Maybe a] -> Maybe a
firstJust (Just x :: a
x:_) = a -> Maybe a
forall a. a -> Maybe a
Just a
x
firstJust [] = Maybe a
forall a. Maybe a
Nothing
firstJust (_:rest :: [Maybe a]
rest) = [Maybe a] -> Maybe a
forall a. [Maybe a] -> Maybe a
firstJust [Maybe a]
rest
rewriteSymType :: Rewrite
rewriteSymType :: Rewrite
rewriteSymType _ l :: ByteString
l
| ByteString -> Bool
isType ByteString
l = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ Char -> ByteString -> ByteString
rewrite '@' (ByteString -> ByteString) -> ByteString -> ByteString
forall a b. (a -> b) -> a -> b
$ Char -> ByteString -> ByteString
rewrite '%' ByteString
l
| Bool
otherwise = Maybe ByteString
forall a. Maybe a
Nothing
where
isType :: ByteString -> Bool
isType = ByteString -> ByteString -> Bool
B.isPrefixOf (FilePath -> ByteString
B.pack ".type")
rewrite :: Char -> B.ByteString -> B.ByteString
rewrite :: Char -> ByteString -> ByteString
rewrite prefix :: Char
prefix = ByteString -> ByteString -> ByteString -> ByteString
replaceOnce ByteString
funcType ByteString
objType
where
funcType :: ByteString
funcType = Char
prefix Char -> ByteString -> ByteString
`B.cons` FilePath -> ByteString
B.pack "function"
objType :: ByteString
objType = Char
prefix Char -> ByteString -> ByteString
`B.cons` FilePath -> ByteString
B.pack "object"
rewriteAVX :: Rewrite
rewriteAVX :: Rewrite
rewriteAVX dflags :: DynFlags
dflags s :: ByteString
s
| Bool -> Bool
not Bool
isX86_64 = Maybe ByteString
forall a. Maybe a
Nothing
| ByteString -> Bool
isVmovdqa ByteString
s = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString -> ByteString
replaceOnce (FilePath -> ByteString
B.pack "vmovdqa") (FilePath -> ByteString
B.pack "vmovdqu") ByteString
s
| ByteString -> Bool
isVmovap ByteString
s = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString) -> ByteString -> Maybe ByteString
forall a b. (a -> b) -> a -> b
$ ByteString -> ByteString -> ByteString -> ByteString
replaceOnce (FilePath -> ByteString
B.pack "vmovap") (FilePath -> ByteString
B.pack "vmovup") ByteString
s
| Bool
otherwise = Maybe ByteString
forall a. Maybe a
Nothing
where
isX86_64 :: Bool
isX86_64 = Platform -> Arch
platformArch (DynFlags -> Platform
targetPlatform DynFlags
dflags) Arch -> Arch -> Bool
forall a. Eq a => a -> a -> Bool
== Arch
ArchX86_64
isVmovdqa :: ByteString -> Bool
isVmovdqa = ByteString -> ByteString -> Bool
B.isPrefixOf (FilePath -> ByteString
B.pack "vmovdqa")
isVmovap :: ByteString -> Bool
isVmovap = ByteString -> ByteString -> Bool
B.isPrefixOf (FilePath -> ByteString
B.pack "vmovap")
replaceOnce :: B.ByteString -> B.ByteString -> B.ByteString -> B.ByteString
replaceOnce :: ByteString -> ByteString -> ByteString -> ByteString
replaceOnce matchBS :: ByteString
matchBS replaceOnceBS :: ByteString
replaceOnceBS = ByteString -> ByteString
loop
where
loop :: B.ByteString -> B.ByteString
loop :: ByteString -> ByteString
loop cts :: ByteString
cts =
case ByteString -> ByteString -> (ByteString, ByteString)
B.breakSubstring ByteString
matchBS ByteString
cts of
(hd :: ByteString
hd,tl :: ByteString
tl) | ByteString -> Bool
B.null ByteString
tl -> ByteString
hd
| Bool
otherwise -> ByteString
hd ByteString -> ByteString -> ByteString
`B.append` ByteString
replaceOnceBS ByteString -> ByteString -> ByteString
`B.append`
Int -> ByteString -> ByteString
B.drop (ByteString -> Int
B.length ByteString
matchBS) ByteString
tl
splitLine :: B.ByteString -> (B.ByteString, B.ByteString)
splitLine :: ByteString -> (ByteString, ByteString)
splitLine l :: ByteString
l = (ByteString
symbol, (Char -> Bool) -> ByteString -> ByteString
B.dropWhile Char -> Bool
isSpace ByteString
rest)
where
isSpace :: Char -> Bool
isSpace ' ' = Bool
True
isSpace '\t' = Bool
True
isSpace _ = Bool
False
(symbol :: ByteString
symbol, rest :: ByteString
rest) = (Char -> Bool) -> ByteString -> (ByteString, ByteString)
B.span (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) ByteString
l