packages feed

crucible-llvm-0.6: src/Lang/Crucible/LLVM/Arch/X86.hs

{-# Language GADTs #-}
{-# Language DataKinds #-}
{-# Language KindSignatures #-}
{-# Language TypeOperators #-}
{-# Language ExplicitNamespaces #-}
{-# Language TemplateHaskell #-}
{-# Language RankNTypes #-}
{-# Language ScopedTypeVariables #-}
{-# Language PatternGuards #-}
{-# Language MultiWayIf #-}
module Lang.Crucible.LLVM.Arch.X86 where

import qualified Data.BitVector.Sized as BV
import Data.Word(Word8)
import Data.Bits
import Data.Kind
import GHC.TypeNats (type (<=))

import Data.Parameterized.NatRepr(knownNat)
import Data.Parameterized.Classes(testEquality,compareF)
import Data.Parameterized.TraversableFC
import Data.Parameterized.TH.GADT as U

import           What4.Interface (SymBV)
import qualified What4.Interface as I

import Lang.Crucible.CFG.Extension
import Lang.Crucible.Types(CrucibleType,BVType,NatRepr,TypeRepr(..))
import Lang.Crucible.Simulator.RegValue(RegValue)
import Lang.Crucible.Panic(panic)

import Lang.Crucible.LLVM.Arch.Util((|->))

data AVXOp1 = VShiftL Word8     -- ^ Shift left by this many bytes
                                -- New bytes are 0.
            | VShufD Word8      -- ^ Shuffle 32-bit words of vector
                                -- according to pattern in the word8
              deriving (Eq,Ord)


data ExtX86 :: (CrucibleType -> Type) -> CrucibleType -> Type where

  {- | Unary operation on a vector.  Should have no side effects. -}
  VOp1 :: (1 <= n) =>
     !(NatRepr n)        -> {- width of input/result -}
     !AVXOp1             -> {- do this operation -}
     !(f (BVType n))     -> {- on this thing -}
     ExtX86 f (BVType n)



eval :: forall sym f tp.
        I.IsSymExprBuilder sym =>
        sym ->
        (forall subT. f subT -> IO (RegValue sym subT)) ->
        ExtX86 f tp ->
        IO (RegValue sym tp)
eval sym ev ext =
  case ext of
    VOp1 w op e ->
      case op of
        VShiftL amt -> vShiftL sym w amt =<< ev e
        VShufD ixes -> vShufD sym w ixes =<< ev e


-- | See @vpslldq@
vShiftL :: (I.IsSymExprBuilder sym, 1 <= w) =>
           sym -> NatRepr w -> Word8 -> SymBV sym w -> IO (SymBV sym w)
vShiftL sym w amt v =
  do i <- I.bvLit sym w (BV.mkBV w (8 * fromIntegral amt))
     I.bvShl sym v i


-- | See @vpshufd@
vShufD :: forall sym w.
          I.IsSymExprBuilder sym =>
          sym -> NatRepr w -> Word8 -> SymBV sym w -> IO (SymBV sym w)
vShufD sym w ixes v
  | Just I.Refl <- testEquality w n128 = mk128 v
  | Just I.Refl <- testEquality w n256 =
    do lower128 <- mk128 =<< I.bvSelect sym n0   n128 v
       upper128 <- mk128 =<< I.bvSelect sym n128 n128 v
       I.bvConcat sym upper128 lower128
  | otherwise = panic "Arch.X86.vShufD"
                        [ "*** Unexpected width: " ++ show (I.natValue w) ]

  where
  mk128 :: SymBV sym 128 -> IO (SymBV sym 128)
  mk128 src = do f0 <- getV src 0
                 f1 <- getV src 1
                 f2 <- getV src 2
                 f3 <- getV src 3
                 lower64 <- I.bvConcat sym f1 f0
                 upper64 <- I.bvConcat sym f3 f2
                 I.bvConcat sym upper64 lower64

  getV :: SymBV sym 128 -> Int -> IO (SymBV sym 32)
  getV src n = case getIx n of
                 0 -> I.bvSelect sym n0 n32 src
                 1 -> I.bvSelect sym n1 n32 src
                 2 -> I.bvSelect sym n2 n32 src
                 _ -> I.bvSelect sym n3 n32 src

  getIx :: Int -> Word8
  getIx n = (ixes `shiftR` (2 * n)) .&. 0x03 -- get 2 bit field




--------------------------------------------------------------------------------
n0 :: NatRepr 0
n0 = knownNat

n1 :: NatRepr 1
n1 = knownNat

n2 :: NatRepr 2
n2 = knownNat

n3 :: NatRepr 3
n3 = knownNat

n32 :: NatRepr 32
n32 = knownNat

n128 :: NatRepr 128
n128 = knownNat

n256 :: NatRepr 256
n256 = knownNat


--------------------------------------------------------------------------------

$([d| {- New TH Scope -} |])


-- This is going to go away
instance ShowFC ExtX86 where
  showFC _ _ = error "[ShowFC ExtX86] Not implmented."

instance TestEqualityFC ExtX86 where
  testEqualityFC testSubterm =
    $(U.structuralTypeEquality [t| ExtX86 |]
        [ U.ConType [t|NatRepr |] `U.TypeApp` U.AnyType |-> [|testEquality|]
        , U.DataArg 0             `U.TypeApp` U.AnyType |-> [|testSubterm|]
        ])

instance OrdFC ExtX86 where
  compareFC testSubterm =
    $(U.structuralTypeOrd [t| ExtX86 |]
        [ U.ConType [t|NatRepr |] `U.TypeApp` U.AnyType |-> [|compareF|]
        , U.DataArg 0             `U.TypeApp` U.AnyType |-> [|testSubterm|]
        ])

-- This is going away
instance HashableFC ExtX86 where
  hashWithSaltFC _hash _s _x = error "[HashableFC ExtX86] Not implmented."

instance FunctorFC ExtX86 where
  fmapFC = fmapFCDefault

instance FoldableFC ExtX86 where
  foldMapFC = foldMapFCDefault

instance TraversableFC ExtX86 where
  traverseFC = $(U.structuralTraversal [t|ExtX86|] [])

instance PrettyApp ExtX86 where
  ppApp _pp _x = error "[PrettyApp ExtX86] XXX"

instance TypeApp ExtX86 where
  appType x =
    case x of
      VOp1 w _ _ -> BVRepr w