packages feed

apple-0.3.0.0: src/Asm/X86/Sp.hs

module Asm.X86.Sp ( spill ) where

import           Asm.X86
import           Asm.X86.CF
import           Control.Monad.Extra        (concatMapM)
import           Control.Monad.State.Strict (State, runState, state)
import           Data.Functor               (void)
import           Data.Int                   (Int32, Int8)
import qualified Data.IntMap.Strict         as IM
import qualified Data.IntSet                as IS
import           Data.Maybe                 (catMaybes)

type SpM = State Int

next :: SpM Int
next = state (\i -> (i, i+1))

spill :: Int -- ^ Unique state
      -> Int
      -> IS.IntSet
      -> [X86 AbsReg FAbsReg X2Abs a]
      -> (Int, Int, [X86 AbsReg FAbsReg X2Abs ()])
spill u offs m isns =
    let (o', ᴍ) = spillM offs m isns
        (nisns, u') = runState ᴍ u
    in (u', o', nisns)

spillM :: Int -- ^ Offset (from already spilled)
       -> IS.IntSet
       -> [X86 AbsReg FAbsReg X2Abs a]
       -> (Int, SpM [X86 AbsReg FAbsReg X2Abs ()]) -- ^ offset, rewritten
spillM offs m isns = (foffs, concatMapM g isns)
    where g isn = do
            let is = [ toInt r | r <- fR pure isn, toInt r `IS.member` m ]
            newRs <- traverse (\_ -> IReg <$> next) is
            let f = thread (zipWith (\i rϵ r -> if toInt r == i then rϵ else r) is newRs)
                ma i = ao (at i); as = ma <$> is
                isn' = mapR f isn
            pure $
                   catMaybes (zipWith (\r a -> if toInt r `IS.member` uses isn' then Just (MovRA () r a) else Nothing) newRs as)
                ++ void isn'
                : catMaybes (zipWith (\a r -> if toInt r `IS.member` defs isn' then Just (MovAR () a r) else Nothing) as newRs)

          ass :: IS.IntSet -> IM.IntMap Int
          ass = IM.fromList . (\k -> zip k [offs,offs+8..]) . IS.toList

          assgn = ass m
          at k = IM.findWithDefault (error "Internal error.") k assgn

          foffs = offs + 8*IS.size m

          thread = foldr (.) id

ao o | Just i8 <- mi8 o = RC BP i8
     | Just i32 <- mi32 o = RC32 BP i32

mi8 :: Int -> Maybe Int8
mi8 i | i <= fromIntegral (maxBound :: Int8) && i >= fromIntegral (minBound :: Int8) = Just $ fromIntegral i
      | otherwise = Nothing

mi32 :: Int -> Maybe Int32
mi32 i | i <= fromIntegral (maxBound :: Int32) && i >= fromIntegral (minBound :: Int32) = Just $ fromIntegral i
       | otherwise = Nothing