--------------------------------------------------------------------------------
-- | The LLVM abstract syntax.
--

module GHC.Llvm.Syntax where

import GHC.Prelude

import GHC.Llvm.MetaData
import GHC.Llvm.Types

import GHC.Types.Unique

-- | Block labels
type LlvmBlockId = Unique

-- | A block of LLVM code.
data LlvmBlock = LlvmBlock {
    -- | The code label for this block
    LlvmBlock -> LlvmBlockId
blockLabel :: LlvmBlockId,

    -- | A list of LlvmStatement's representing the code for this block.
    -- This list must end with a control flow statement.
    LlvmBlock -> [LlvmStatement]
blockStmts :: [LlvmStatement]
  }

type LlvmBlocks = [LlvmBlock]

-- | An LLVM Module. This is a top level container in LLVM.
data LlvmModule = LlvmModule  {
    -- | Comments to include at the start of the module.
    LlvmModule -> [LMString]
modComments  :: [LMString],

    -- | LLVM Alias type definitions.
    LlvmModule -> [LlvmAlias]
modAliases   :: [LlvmAlias],

    -- | LLVM meta data.
    LlvmModule -> [MetaDecl]
modMeta      :: [MetaDecl],

    -- | Global variables to include in the module.
    LlvmModule -> [LMGlobal]
modGlobals   :: [LMGlobal],

    -- | LLVM Functions used in this module but defined in other modules.
    LlvmModule -> LlvmFunctionDecls
modFwdDecls  :: LlvmFunctionDecls,

    -- | LLVM Functions defined in this module.
    LlvmModule -> LlvmFunctions
modFuncs     :: LlvmFunctions
  }

-- | An LLVM Function
data LlvmFunction = LlvmFunction {
    -- | The signature of this declared function.
    LlvmFunction -> LlvmFunctionDecl
funcDecl      :: LlvmFunctionDecl,

    -- | The functions arguments
    LlvmFunction -> [LMString]
funcArgs      :: [LMString],

    -- | The function attributes.
    LlvmFunction -> [LlvmFuncAttr]
funcAttrs     :: [LlvmFuncAttr],

    -- | The section to put the function into,
    LlvmFunction -> LMSection
funcSect      :: LMSection,

    -- | Prefix data
    LlvmFunction -> Maybe LlvmStatic
funcPrefix    :: Maybe LlvmStatic,

    -- | The body of the functions.
    LlvmFunction -> LlvmBlocks
funcBody      :: LlvmBlocks
  }

type LlvmFunctions = [LlvmFunction]

type SingleThreaded = Bool

-- | LLVM ordering types for synchronization purposes. (Introduced in LLVM
-- 3.0). Please see the LLVM documentation for a better description.
data LlvmSyncOrdering
  -- | Some partial order of operations exists.
  = SyncUnord
  -- | A single total order for operations at a single address exists.
  | SyncMonotonic
  -- | Acquire synchronization operation.
  | SyncAcquire
  -- | Release synchronization operation.
  | SyncRelease
  -- | Acquire + Release synchronization operation.
  | SyncAcqRel
  -- | Full sequential Consistency operation.
  | SyncSeqCst
  deriving (Int -> LlvmSyncOrdering -> ShowS
[LlvmSyncOrdering] -> ShowS
LlvmSyncOrdering -> String
(Int -> LlvmSyncOrdering -> ShowS)
-> (LlvmSyncOrdering -> String)
-> ([LlvmSyncOrdering] -> ShowS)
-> Show LlvmSyncOrdering
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LlvmSyncOrdering] -> ShowS
$cshowList :: [LlvmSyncOrdering] -> ShowS
show :: LlvmSyncOrdering -> String
$cshow :: LlvmSyncOrdering -> String
showsPrec :: Int -> LlvmSyncOrdering -> ShowS
$cshowsPrec :: Int -> LlvmSyncOrdering -> ShowS
Show, LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
(LlvmSyncOrdering -> LlvmSyncOrdering -> Bool)
-> (LlvmSyncOrdering -> LlvmSyncOrdering -> Bool)
-> Eq LlvmSyncOrdering
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
$c/= :: LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
== :: LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
$c== :: LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
Eq)

-- | LLVM atomic operations. Please see the @atomicrmw@ instruction in
-- the LLVM documentation for a complete description.
data LlvmAtomicOp
  = LAO_Xchg
  | LAO_Add
  | LAO_Sub
  | LAO_And
  | LAO_Nand
  | LAO_Or
  | LAO_Xor
  | LAO_Max
  | LAO_Min
  | LAO_Umax
  | LAO_Umin
  deriving (Int -> LlvmAtomicOp -> ShowS
[LlvmAtomicOp] -> ShowS
LlvmAtomicOp -> String
(Int -> LlvmAtomicOp -> ShowS)
-> (LlvmAtomicOp -> String)
-> ([LlvmAtomicOp] -> ShowS)
-> Show LlvmAtomicOp
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LlvmAtomicOp] -> ShowS
$cshowList :: [LlvmAtomicOp] -> ShowS
show :: LlvmAtomicOp -> String
$cshow :: LlvmAtomicOp -> String
showsPrec :: Int -> LlvmAtomicOp -> ShowS
$cshowsPrec :: Int -> LlvmAtomicOp -> ShowS
Show, LlvmAtomicOp -> LlvmAtomicOp -> Bool
(LlvmAtomicOp -> LlvmAtomicOp -> Bool)
-> (LlvmAtomicOp -> LlvmAtomicOp -> Bool) -> Eq LlvmAtomicOp
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmAtomicOp -> LlvmAtomicOp -> Bool
$c/= :: LlvmAtomicOp -> LlvmAtomicOp -> Bool
== :: LlvmAtomicOp -> LlvmAtomicOp -> Bool
$c== :: LlvmAtomicOp -> LlvmAtomicOp -> Bool
Eq)

-- | Llvm Statements
data LlvmStatement
  {- |
    Assign an expression to a variable:
      * dest:   Variable to assign to
      * source: Source expression
  -}
  = Assignment LlvmVar LlvmExpression

  {- |
    Memory fence operation
  -}
  | Fence Bool LlvmSyncOrdering

  {- |
    Always branch to the target label
  -}
  | Branch LlvmVar

  {- |
    Branch to label targetTrue if cond is true otherwise to label targetFalse
      * cond:        condition that will be tested, must be of type i1
      * targetTrue:  label to branch to if cond is true
      * targetFalse: label to branch to if cond is false
  -}
  | BranchIf LlvmVar LlvmVar LlvmVar

  {- |
    Comment
    Plain comment.
  -}
  | Comment [LMString]

  {- |
    Set a label on this position.
      * name: Identifier of this label, unique for this module
  -}
  | MkLabel LlvmBlockId

  {- |
    Store variable value in pointer ptr. If value is of type t then ptr must
    be of type t*.
      * value: Variable/Constant to store.
      * ptr:   Location to store the value in
  -}
  | Store LlvmVar LlvmVar

  {- |
    Multiway branch
      * scrutinee: Variable or constant which must be of integer type that is
                   determines which arm is chosen.
      * def:       The default label if there is no match in target.
      * target:    A list of (value,label) where the value is an integer
                   constant and label the corresponding label to jump to if the
                   scrutinee matches the value.
  -}
  | Switch LlvmVar LlvmVar [(LlvmVar, LlvmVar)]

  {- |
    Return a result.
      * result: The variable or constant to return
  -}
  | Return (Maybe LlvmVar)

  {- |
    An instruction for the optimizer that the code following is not reachable
  -}
  | Unreachable

  {- |
    Raise an expression to a statement (if don't want result or want to use
    Llvm unnamed values.
  -}
  | Expr LlvmExpression

  {- |
    A nop LLVM statement. Useful as its often more efficient to use this
    then to wrap LLvmStatement in a Just or [].
  -}
  | Nop

  {- |
    A LLVM statement with metadata attached to it.
  -}
  | MetaStmt [MetaAnnot] LlvmStatement

  deriving (LlvmStatement -> LlvmStatement -> Bool
(LlvmStatement -> LlvmStatement -> Bool)
-> (LlvmStatement -> LlvmStatement -> Bool) -> Eq LlvmStatement
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmStatement -> LlvmStatement -> Bool
$c/= :: LlvmStatement -> LlvmStatement -> Bool
== :: LlvmStatement -> LlvmStatement -> Bool
$c== :: LlvmStatement -> LlvmStatement -> Bool
External instance of the constraint type Eq MetaAnnot
External instance of the constraint type forall a b. (Eq a, Eq b) => Eq (a, b)
External instance of the constraint type Eq LMString
External instance of the constraint type Eq MetaAnnot
External instance of the constraint type forall a. Eq a => Eq (Maybe a)
External instance of the constraint type forall a b. (Eq a, Eq b) => Eq (a, b)
External instance of the constraint type Eq LlvmVar
External instance of the constraint type Eq LlvmBlockId
External instance of the constraint type Eq LMString
External instance of the constraint type forall a. Eq a => Eq [a]
External instance of the constraint type Eq Bool
Instance of class: Eq of the constraint type Eq LlvmExpression
External instance of the constraint type Eq LlvmVar
External instance of the constraint type Eq LlvmVar
Instance of class: Eq of the constraint type Eq LlvmSyncOrdering
Instance of class: Eq of the constraint type Eq LlvmExpression
Instance of class: Eq of the constraint type Eq LlvmStatement
Eq)


-- | Llvm Expressions
data LlvmExpression
  {- |
    Allocate amount * sizeof(tp) bytes on the stack
      * tp:     LlvmType to reserve room for
      * amount: The nr of tp's which must be allocated
  -}
  = Alloca LlvmType Int

  {- |
    Perform the machine operator op on the operands left and right
      * op:    operator
      * left:  left operand
      * right: right operand
  -}
  | LlvmOp LlvmMachOp LlvmVar LlvmVar

  {- |
    Perform a compare operation on the operands left and right
      * op:    operator
      * left:  left operand
      * right: right operand
  -}
  | Compare LlvmCmpOp LlvmVar LlvmVar

  {- |
    Extract a scalar element from a vector
      * val: The vector
      * idx: The index of the scalar within the vector
  -}
  | Extract LlvmVar LlvmVar

  {- |
    Extract a scalar element from a structure
      * val: The structure
      * idx: The index of the scalar within the structure
    Corresponds to "extractvalue" instruction.
  -}
  | ExtractV LlvmVar Int

  {- |
    Insert a scalar element into a vector
      * val:   The source vector
      * elt:   The scalar to insert
      * index: The index at which to insert the scalar
  -}
  | Insert LlvmVar LlvmVar LlvmVar

  {- |
    Allocate amount * sizeof(tp) bytes on the heap
      * tp:     LlvmType to reserve room for
      * amount: The nr of tp's which must be allocated
  -}
  | Malloc LlvmType Int

  {- |
    Load the value at location ptr
  -}
  | Load LlvmVar

  {- |
    Atomic load of the value at location ptr
  -}
  | ALoad LlvmSyncOrdering SingleThreaded LlvmVar

  {- |
    Navigate in a structure, selecting elements
      * inbound: Is the pointer inbounds? (computed pointer doesn't overflow)
      * ptr:     Location of the structure
      * indexes: A list of indexes to select the correct value.
  -}
  | GetElemPtr Bool LlvmVar [LlvmVar]

  {- |
    Cast the variable from to the to type. This is an abstraction of three
    cast operators in Llvm, inttoptr, ptrtoint and bitcast.
       * cast: Cast type
       * from: Variable to cast
       * to:   type to cast to
  -}
  | Cast LlvmCastOp LlvmVar LlvmType

  {- |
    Atomic read-modify-write operation
       * op:       Atomic operation
       * addr:     Address to modify
       * operand:  Operand to operation
       * ordering: Ordering requirement
  -}
  | AtomicRMW LlvmAtomicOp LlvmVar LlvmVar LlvmSyncOrdering

  {- |
    Compare-and-exchange operation
       * addr:     Address to modify
       * old:      Expected value
       * new:      New value
       * suc_ord:  Ordering required in success case
       * fail_ord: Ordering required in failure case, can be no stronger than
                   suc_ord

    Result is an @i1@, true if store was successful.
  -}
  | CmpXChg LlvmVar LlvmVar LlvmVar LlvmSyncOrdering LlvmSyncOrdering

  {- |
    Call a function. The result is the value of the expression.
      * tailJumps: CallType to signal if the function should be tail called
      * fnptrval:  An LLVM value containing a pointer to a function to be
                   invoked. Can be indirect. Should be LMFunction type.
      * args:      Concrete arguments for the parameters
      * attrs:     A list of function attributes for the call. Only NoReturn,
                   NoUnwind, ReadOnly and ReadNone are valid here.
  -}
  | Call LlvmCallType LlvmVar [LlvmVar] [LlvmFuncAttr]

  {- |
    Call a function as above but potentially taking metadata as arguments.
      * tailJumps: CallType to signal if the function should be tail called
      * fnptrval:  An LLVM value containing a pointer to a function to be
                   invoked. Can be indirect. Should be LMFunction type.
      * args:      Arguments that may include metadata.
      * attrs:     A list of function attributes for the call. Only NoReturn,
                   NoUnwind, ReadOnly and ReadNone are valid here.
  -}
  | CallM LlvmCallType LlvmVar [MetaExpr] [LlvmFuncAttr]

  {- |
    Merge variables from different basic blocks which are predecessors of this
    basic block in a new variable of type tp.
      * tp:         type of the merged variable, must match the types of the
                    predecessor variables.
      * predecessors: A list of variables and the basic block that they originate
                      from.
  -}
  | Phi LlvmType [(LlvmVar,LlvmVar)]

  {- |
    Inline assembly expression. Syntax is very similar to the style used by GCC.
      * assembly:    Actual inline assembly code.
      * constraints: Operand constraints.
      * return ty:   Return type of function.
      * vars:        Any variables involved in the assembly code.
      * sideeffect:  Does the expression have side effects not visible from the
                     constraints list.
      * alignstack:  Should the stack be conservatively aligned before this
                     expression is executed.
  -}
  | Asm LMString LMString LlvmType [LlvmVar] Bool Bool

  {- |
    A LLVM expression with metadata attached to it.
  -}
  | MExpr [MetaAnnot] LlvmExpression

  deriving (LlvmExpression -> LlvmExpression -> Bool
(LlvmExpression -> LlvmExpression -> Bool)
-> (LlvmExpression -> LlvmExpression -> Bool) -> Eq LlvmExpression
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LlvmExpression -> LlvmExpression -> Bool
$c/= :: LlvmExpression -> LlvmExpression -> Bool
== :: LlvmExpression -> LlvmExpression -> Bool
$c== :: LlvmExpression -> LlvmExpression -> Bool
External instance of the constraint type Eq MetaExpr
External instance of the constraint type Eq LlvmFuncAttr
External instance of the constraint type Eq MetaAnnot
External instance of the constraint type Eq LMString
External instance of the constraint type forall a b. (Eq a, Eq b) => Eq (a, b)
External instance of the constraint type Eq LlvmVar
External instance of the constraint type Eq MetaExpr
External instance of the constraint type Eq LlvmFuncAttr
External instance of the constraint type forall a. Eq a => Eq [a]
External instance of the constraint type Eq LlvmFuncAttr
External instance of the constraint type Eq LlvmCallType
External instance of the constraint type Eq LlvmCallType
External instance of the constraint type Eq LlvmCastOp
External instance of the constraint type forall a. Eq a => Eq [a]
External instance of the constraint type Eq LlvmVar
External instance of the constraint type Eq Bool
Instance of class: Eq of the constraint type Eq LlvmSyncOrdering
External instance of the constraint type Eq LlvmCmpOp
External instance of the constraint type Eq LlvmVar
External instance of the constraint type Eq LlvmMachOp
External instance of the constraint type Eq Int
External instance of the constraint type Eq Int
External instance of the constraint type Eq LlvmType
External instance of the constraint type Eq LlvmType
External instance of the constraint type Eq MetaAnnot
External instance of the constraint type forall a b. (Eq a, Eq b) => Eq (a, b)
External instance of the constraint type Eq LMString
External instance of the constraint type forall a. Eq a => Eq [a]
External instance of the constraint type Eq Bool
External instance of the constraint type Eq LlvmVar
Instance of class: Eq of the constraint type Eq LlvmSyncOrdering
Instance of class: Eq of the constraint type Eq LlvmAtomicOp
Instance of class: Eq of the constraint type Eq LlvmExpression
Eq)