{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Llvm.MetaData where

import GhcPrelude

import Llvm.Types
import Outputable

-- The LLVM Metadata System.
--
-- The LLVM metadata feature is poorly documented but roughly follows the
-- following design:
-- * Metadata can be constructed in a few different ways (See below).
-- * After which it can either be attached to LLVM statements to pass along
-- extra information to the optimizer and code generator OR specifically named
-- metadata has an affect on the whole module (i.e., linking behaviour).
--
--
-- # Constructing metadata
-- Metadata comes largely in three forms:
--
-- * Metadata expressions -- these are the raw metadata values that encode
--   information. They consist of metadata strings, metadata nodes, regular
--   LLVM values (both literals and references to global variables) and
--   metadata expressions (i.e., recursive data type). Some examples:
--     !{ !"hello", !0, i32 0 }
--     !{ !1, !{ i32 0 } }
--
-- * Metadata nodes -- global metadata variables that attach a metadata
--   expression to a number. For example:
--     !0 = !{ [<metadata expressions>] !}
--
-- * Named metadata -- global metadata variables that attach a metadata nodes
--   to a name. Used ONLY to communicated module level information to LLVM
--   through a meaningful name. For example:
--     !llvm.module.linkage = !{ !0, !1 }
--
--
-- # Using Metadata
-- Using metadata depends on the form it is in:
--
-- * Attach to instructions -- metadata can be attached to LLVM instructions
--   using a specific reference as follows:
--     %l = load i32* @glob, !nontemporal !10
--     %m = load i32* @glob, !nontemporal !{ i32 0, !{ i32 0 } }
--   Only metadata nodes or expressions can be attached, named metadata cannot.
--   Refer to LLVM documentation for which instructions take metadata and its
--   meaning.
--
-- * As arguments -- llvm functions can take metadata as arguments, for
--   example:
--     call void @llvm.dbg.value(metadata !{ i32 0 }, i64 0, metadata !1)
--   As with instructions, only metadata nodes or expressions can be attached.
--
-- * As a named metadata -- Here the metadata is simply declared in global
--   scope using a specific name to communicate module level information to LLVM.
--   For example:
--     !llvm.module.linkage = !{ !0, !1 }
--

-- | A reference to an un-named metadata node.
newtype MetaId = MetaId Int
               deriving (MetaId -> MetaId -> Bool
(MetaId -> MetaId -> Bool)
-> (MetaId -> MetaId -> Bool) -> Eq MetaId
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MetaId -> MetaId -> Bool
$c/= :: MetaId -> MetaId -> Bool
== :: MetaId -> MetaId -> Bool
$c== :: MetaId -> MetaId -> Bool
Eq, Eq MetaId
Eq MetaId =>
(MetaId -> MetaId -> Ordering)
-> (MetaId -> MetaId -> Bool)
-> (MetaId -> MetaId -> Bool)
-> (MetaId -> MetaId -> Bool)
-> (MetaId -> MetaId -> Bool)
-> (MetaId -> MetaId -> MetaId)
-> (MetaId -> MetaId -> MetaId)
-> Ord MetaId
MetaId -> MetaId -> Bool
MetaId -> MetaId -> Ordering
MetaId -> MetaId -> MetaId
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: MetaId -> MetaId -> MetaId
$cmin :: MetaId -> MetaId -> MetaId
max :: MetaId -> MetaId -> MetaId
$cmax :: MetaId -> MetaId -> MetaId
>= :: MetaId -> MetaId -> Bool
$c>= :: MetaId -> MetaId -> Bool
> :: MetaId -> MetaId -> Bool
$c> :: MetaId -> MetaId -> Bool
<= :: MetaId -> MetaId -> Bool
$c<= :: MetaId -> MetaId -> Bool
< :: MetaId -> MetaId -> Bool
$c< :: MetaId -> MetaId -> Bool
compare :: MetaId -> MetaId -> Ordering
$ccompare :: MetaId -> MetaId -> Ordering
$cp1Ord :: Eq MetaId
Ord, Int -> MetaId
MetaId -> Int
MetaId -> [MetaId]
MetaId -> MetaId
MetaId -> MetaId -> [MetaId]
MetaId -> MetaId -> MetaId -> [MetaId]
(MetaId -> MetaId)
-> (MetaId -> MetaId)
-> (Int -> MetaId)
-> (MetaId -> Int)
-> (MetaId -> [MetaId])
-> (MetaId -> MetaId -> [MetaId])
-> (MetaId -> MetaId -> [MetaId])
-> (MetaId -> MetaId -> MetaId -> [MetaId])
-> Enum MetaId
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
enumFromThenTo :: MetaId -> MetaId -> MetaId -> [MetaId]
$cenumFromThenTo :: MetaId -> MetaId -> MetaId -> [MetaId]
enumFromTo :: MetaId -> MetaId -> [MetaId]
$cenumFromTo :: MetaId -> MetaId -> [MetaId]
enumFromThen :: MetaId -> MetaId -> [MetaId]
$cenumFromThen :: MetaId -> MetaId -> [MetaId]
enumFrom :: MetaId -> [MetaId]
$cenumFrom :: MetaId -> [MetaId]
fromEnum :: MetaId -> Int
$cfromEnum :: MetaId -> Int
toEnum :: Int -> MetaId
$ctoEnum :: Int -> MetaId
pred :: MetaId -> MetaId
$cpred :: MetaId -> MetaId
succ :: MetaId -> MetaId
$csucc :: MetaId -> MetaId
Enum)

instance Outputable MetaId where
    ppr :: MetaId -> SDoc
ppr (MetaId n :: Int
n) = Char -> SDoc
char '!' SDoc -> SDoc -> SDoc
<> Int -> SDoc
int Int
n

-- | LLVM metadata expressions
data MetaExpr = MetaStr !LMString
              | MetaNode !MetaId
              | MetaVar !LlvmVar
              | MetaStruct [MetaExpr]
              deriving (MetaExpr -> MetaExpr -> Bool
(MetaExpr -> MetaExpr -> Bool)
-> (MetaExpr -> MetaExpr -> Bool) -> Eq MetaExpr
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MetaExpr -> MetaExpr -> Bool
$c/= :: MetaExpr -> MetaExpr -> Bool
== :: MetaExpr -> MetaExpr -> Bool
$c== :: MetaExpr -> MetaExpr -> Bool
Eq)

instance Outputable MetaExpr where
  ppr :: MetaExpr -> SDoc
ppr (MetaVar (LMLitVar (LMNullLit _))) = String -> SDoc
text "null"
  ppr (MetaStr    s :: LMString
s ) = Char -> SDoc
char '!' SDoc -> SDoc -> SDoc
<> SDoc -> SDoc
doubleQuotes (LMString -> SDoc
ftext LMString
s)
  ppr (MetaNode   n :: MetaId
n ) = MetaId -> SDoc
forall a. Outputable a => a -> SDoc
ppr MetaId
n
  ppr (MetaVar    v :: LlvmVar
v ) = LlvmVar -> SDoc
forall a. Outputable a => a -> SDoc
ppr LlvmVar
v
  ppr (MetaStruct es :: [MetaExpr]
es) = Char -> SDoc
char '!' SDoc -> SDoc -> SDoc
<> SDoc -> SDoc
braces ([MetaExpr] -> SDoc
forall a. Outputable a => [a] -> SDoc
ppCommaJoin [MetaExpr]
es)

-- | Associates some metadata with a specific label for attaching to an
-- instruction.
data MetaAnnot = MetaAnnot LMString MetaExpr
               deriving (MetaAnnot -> MetaAnnot -> Bool
(MetaAnnot -> MetaAnnot -> Bool)
-> (MetaAnnot -> MetaAnnot -> Bool) -> Eq MetaAnnot
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: MetaAnnot -> MetaAnnot -> Bool
$c/= :: MetaAnnot -> MetaAnnot -> Bool
== :: MetaAnnot -> MetaAnnot -> Bool
$c== :: MetaAnnot -> MetaAnnot -> Bool
Eq)

-- | Metadata declarations. Metadata can only be declared in global scope.
data MetaDecl
    -- | Named metadata. Only used for communicating module information to
    -- LLVM. ('!name = !{ [!<n>] }' form).
    = MetaNamed !LMString [MetaId]
    -- | Metadata node declaration.
    -- ('!0 = metadata !{ <metadata expression> }' form).
    | MetaUnnamed !MetaId !MetaExpr