    --------------------------------------------------------------------------------
    -- | 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
    $cshowsPrec :: Int -> LlvmSyncOrdering -> ShowS
    showsPrec :: Int -> LlvmSyncOrdering -> ShowS
    $cshow :: LlvmSyncOrdering -> String
    show :: LlvmSyncOrdering -> String
    $cshowList :: [LlvmSyncOrdering] -> ShowS
    showList :: [LlvmSyncOrdering] -> ShowS
    Show, LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
    (LlvmSyncOrdering -> LlvmSyncOrdering -> Bool)
    -> (LlvmSyncOrdering -> LlvmSyncOrdering -> Bool)
    -> Eq LlvmSyncOrdering
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
    == :: LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
    $c/= :: LlvmSyncOrdering -> LlvmSyncOrdering -> Bool
    /= :: 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
    $cshowsPrec :: Int -> LlvmAtomicOp -> ShowS
    showsPrec :: Int -> LlvmAtomicOp -> ShowS
    $cshow :: LlvmAtomicOp -> String
    show :: LlvmAtomicOp -> String
    $cshowList :: [LlvmAtomicOp] -> ShowS
    showList :: [LlvmAtomicOp] -> ShowS
    Show, LlvmAtomicOp -> LlvmAtomicOp -> Bool
    (LlvmAtomicOp -> LlvmAtomicOp -> Bool)
    -> (LlvmAtomicOp -> LlvmAtomicOp -> Bool) -> Eq LlvmAtomicOp
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: LlvmAtomicOp -> LlvmAtomicOp -> Bool
    == :: LlvmAtomicOp -> LlvmAtomicOp -> Bool
    $c/= :: LlvmAtomicOp -> LlvmAtomicOp -> Bool
    /= :: 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 LMAlign [MetaAnnot]

      {- |
        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

      deriving (LlvmStatement -> LlvmStatement -> Bool
    (LlvmStatement -> LlvmStatement -> Bool)
    -> (LlvmStatement -> LlvmStatement -> Bool) -> Eq LlvmStatement
    forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
    $c== :: LlvmStatement -> LlvmStatement -> Bool
    == :: LlvmStatement -> LlvmStatement -> Bool
    $c/= :: LlvmStatement -> LlvmStatement -> Bool
    /= :: LlvmStatement -> LlvmStatement -> Bool
    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 LMAlign

      {- |
        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
    $c== :: LlvmExpression -> LlvmExpression -> Bool
    == :: LlvmExpression -> LlvmExpression -> Bool
    $c/= :: LlvmExpression -> LlvmExpression -> Bool
    /= :: LlvmExpression -> LlvmExpression -> Bool
    Eq)