accelerate-llvm-1.4.0.0: src/LLVM/AST/Type/Name.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RoleAnnotations #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS_HADDOCK hide #-}
-- |
-- Module : LLVM.AST.Type.Name
-- Copyright : [2015..2020] The Accelerate Team
-- License : BSD3
--
-- Maintainer : Trevor L. McDonell <trevor.mcdonell@gmail.com>
-- Stability : experimental
-- Portability : non-portable (GHC extensions)
--
module LLVM.AST.Type.Name
where
import Data.ByteString.Short ( ShortByteString )
import qualified Data.ByteString.Short as SBS
import qualified Data.ByteString.Short.Char8 as SBS8
import Data.Data
import Data.Semigroup
import Data.Hashable
import Data.String
import Data.Word
import Prelude
import qualified Data.Array.Accelerate.LLVM.Internal.LLVMPretty as LLVM
-- | Objects of various sorts in LLVM IR are identified by address in the LLVM
-- C++ API, and may be given a string name. When printed to (resp. read from)
-- human-readable LLVM assembly, objects without string names are numbered
-- sequentially (resp. must be numbered sequentially). String names may be
-- quoted, and are quoted when printed if they would otherwise be misread - e.g.
-- when containing special characters.
--
-- > 7
--
-- means the seventh unnamed object, while
--
-- > "7"
--
-- means the object named with the string "7".
--
-- This libraries handling of 'UnName's during translation of the AST down into
-- C++ IR is somewhat more forgiving than the LLVM assembly parser: it does not
-- require that unnamed values be numbered sequentially; however, the numbers of
-- 'UnName's passed into C++ cannot be preserved in the C++ objects. If the C++
-- IR is printed as assembly or translated into a Haskell AST, unnamed nodes
-- will be renumbered sequentially. Thus unnamed node numbers should be thought
-- of as having any scope limited to the 'LLVM.AST.Module' in which they
-- are used.
--
type role Name representational
data Name a
= Name {-# UNPACK #-} !ShortByteString -- ^ a string name
| UnName {-# UNPACK #-} !Word -- ^ a number for a nameless thing
deriving (Eq, Ord, Read, Show, Typeable, Data)
instance IsString (Name a) where
fromString = Name . fromString
-- TLM: 'Name' is used a lot over the place, to refer to things like variables
-- as well as basic block labels. In the first case the type makes sense,
-- but what about the latter? Should basic blocks have type '()', or 'IO
-- ()', or the type of the thing that they "return" (although, from memory
-- BBs don't really return anything, they just compute a bunch of stuff
-- which is now in scope. Hmm... the only types that we can truly know are
-- the inputs to the basic block bound via phi nodes, but this is
-- unsatisfactory... )
--
data Label = Label {-# UNPACK #-} !ShortByteString
deriving (Eq, Ord, Read, Show, Typeable, Data)
instance IsString Label where
fromString = Label . fromString
instance Semigroup Label where
Label x <> Label y = Label (x <> y)
instance Monoid Label where
mempty = Label mempty
instance Hashable Label where
hashWithSalt salt (Label sbs) = hashWithSalt salt sbs
-- | Some names are not external function references but instead references to
-- definitions that we provide inline in the module to be compiled by LLVM. See
-- 'Data.Array.Accelerate.LLVM.CodeGen.Base.call' for more details. This
-- function checks whether the given label is one of those inline-provided
-- functions.
labelIsAccPrelude :: Label -> Bool
labelIsAccPrelude (Label x) = SBS.take (SBS.length prefix) x == prefix
where Label prefix = makeAccPreludeLabel SBS.empty
-- | Create a reference to an inline-provided function. See
-- 'labelIsAccPrelude'.
makeAccPreludeLabel :: ShortByteString -> Label
makeAccPreludeLabel s = Label (SBS8.pack "accprelude_" <> s)
-- | Convert to llvm-pretty
--
-- We only explicit conversion functions for symbols and identifiers separately.
--
nameToPrettyS :: Name a -> LLVM.Symbol
nameToPrettyS (Name s) = LLVM.Symbol (SBS8.unpack s)
nameToPrettyS (UnName n) = LLVM.Symbol ("tollpr_s_" ++ show n)
nameToPrettyI :: Name a -> LLVM.Ident
nameToPrettyI (Name s) = LLVM.Ident (SBS8.unpack s)
nameToPrettyI (UnName n) = LLVM.Ident ("tollpr_i_" ++ show n)
labelToPrettyS :: Label -> LLVM.Symbol
labelToPrettyS (Label s) = LLVM.Symbol (SBS8.unpack s)
labelToPrettyI :: Label -> LLVM.Ident
labelToPrettyI (Label s) = LLVM.Ident (SBS8.unpack s)
labelToPrettyBL :: Label -> LLVM.BlockLabel
labelToPrettyBL (Label s) = LLVM.Named (LLVM.Ident (SBS8.unpack s))