packages feed

fortran-vars-0.1.0: src/Language/Fortran/Vars/CPValue.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.Fortran.Vars.CPValue
  ( CPValue(..)
  , meet
  , unaryOper
  , binaryOper
  , isTop
  , isBot
  , isConstInt
  )
where

import           Language.Fortran.Vars.Types
                                                ( ExpVal(..) )
import           Language.Fortran.Vars.Operation
                                                ( unaryOp
                                                , binaryOp
                                                )

import           Language.Fortran.AST           ( UnaryOp(..)
                                                , BinaryOp(..)
                                                )

import           Data.Data                      ( Data )
import           Data.Typeable                  ( Typeable )
import           GHC.Generics                   ( Generic )
import           Control.DeepSeq                ( NFData )

-- | CPValue (Constant Propagation Value) represnts the value of an expression
-- determined by constant propagation analysis.
-- The value can be uninitialized, a constant, or unknown due to conflict.
-- The data type is represented with 'ExpVal' together with two special values:
-- Top represents uninitialized value and is the least upper bound
-- Bot represents unknown and is the greatest lower bound
-- Top, Const, and Bot forms a lattice strucutre with meet operation defined below
data CPValue
  = Top           -- ^ represents uninitialized value
  | Const ExpVal  -- ^ represents a constant value
  | Bot           -- ^ short for bottom, represents unknown value
  deriving (Eq, Ord, Show, Data, Typeable, Generic, NFData)


-- | meet operation for CPValue lattice with user defined function to handle
-- two Const values
meetWith :: (ExpVal -> ExpVal -> CPValue) -> CPValue -> CPValue -> CPValue
meetWith f v1 v2 = case (v1, v2) of
  (Bot     , _       ) -> Bot
  (_       , Bot     ) -> Bot
  (Top     , v       ) -> v
  (v       , Top     ) -> v
  (Const c1, Const c2) -> f c1 c2

-- | meet operation for CPValue lattice.
-- meet of two different constant value indicates conflict, therefore yields Bot.
meet :: CPValue -> CPValue -> CPValue
meet = meetWith (\c1 c2 -> if c1 == c2 then Const c1 else Bot)


unaryOper :: UnaryOp -> CPValue -> CPValue
unaryOper op v = case v of
  Top          -> Top
  Bot          -> Bot
  Const expVal -> Const (unaryOp op expVal)

binaryOper :: BinaryOp -> CPValue -> CPValue -> CPValue
binaryOper op v1 v2 = case (op, v1, v2) of
  (Multiplication, Const (Int 0), _) -> Const (Int 0)
  (Multiplication, _, Const (Int 0)) -> Const (Int 0)
  (Multiplication, Const (Real 0.0), _) -> Const (Real 0.0)
  (Multiplication, _, Const (Real 0.0)) -> Const (Real 0.0)
  (Exponentiation, Const (Real 1.0), _) -> Const (Real 1.0)
  (Exponentiation, Const (Int 1), _) -> Const (Real 1.0)
  (Exponentiation, _, Const (Real 0.0)) -> Const (Real 1.0)
  (Exponentiation, _, Const (Int 0)) -> Const (Real 1.0)
  (And, Const (Logical False), _) -> Const (Logical False)
  (And, _, Const (Logical False)) -> Const (Logical False)
  (Or, Const (Logical True), _) -> Const (Logical True)
  (Or, _, Const (Logical True)) -> Const (Logical True)
  (_, Bot, _) -> Bot
  (_, _, Bot) -> Bot
  (_, Top, _) -> Top
  (_, _, Top) -> Top
  (_, Const x, Const y) -> Const (binaryOp op x y)


isTop :: CPValue -> Bool
isTop Top = True
isTop _   = False

isBot :: CPValue -> Bool
isBot Bot = True
isBot _   = False

isConstInt :: CPValue -> Bool
isConstInt (Const Int{}) = True
isConstInt _             = False