Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for LLVM address spaces #148

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions src/Text/LLVM.hs
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ iT :: Word32 -> Type
iT = PrimType . Integer

ptrT :: Type -> Type
ptrT = PtrTo
ptrT = PtrTo (AddrSpace 0)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded 0 address space here and elsewhere is reasonable because every previous use was with 0 (nothing else existed) but additional helpers may be useful later.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you factor AddrSpace 0 out into its own definition? Something like this (with an appropriate Haddock comment):

defaultAddrSpace :: AddrSpace
defaultAddrSpace = Addr 0

And then use this in places where AddrSpace 0 is currently used. This would make it more obvious at a glance that AddrSpace 0 is a distinguished value, IMO.


voidT :: Type
voidT = PrimType Void
Expand Down Expand Up @@ -618,7 +618,7 @@ shuffleVector vec1 vec2 mask =
_ -> error "shuffleVector not given a vector"

alloca :: Type -> Maybe (Typed Value) -> Maybe Int -> BB (Typed Value)
alloca ty mb align = observe (PtrTo ty) (Alloca ty es align)
alloca ty mb align = observe (PtrTo (AddrSpace 0) ty) (Alloca ty (AddrSpace 0) es align)
where
es = fmap toValue `fmap` mb

Expand All @@ -628,7 +628,7 @@ load ty ptr ma = observe ty (Load ty (toValue `fmap` ptr) Nothing ma)
store :: (IsValue a, IsValue b) => a -> Typed b -> Maybe Align -> BB ()
store a ptr ma =
case typedType ptr of
PtrTo ty -> effect (Store (ty -: a) (toValue `fmap` ptr) Nothing ma)
PtrTo adr ty -> effect (Store (ty -: a) (toValue `fmap` ptr) Nothing ma)
_ -> error "store not given a pointer"

nullPtr :: Type -> Typed Value
Expand Down Expand Up @@ -700,8 +700,8 @@ getelementptr ty ptr ixs = observe ty (GEP False ty (toValue `fmap` ptr) ixs)
-- | Emit a call instruction, and generate a new variable for its result.
call :: IsValue a => Typed a -> [Typed Value] -> BB (Typed Value)
call sym vs = case typedType sym of
PtrTo ty@(FunTy rty _ _) -> observe rty (Call False ty (toValue sym) vs)
_ -> error "invalid function type given to call"
PtrTo adr ty@(FunTy rty _ _) -> observe rty (Call False ty (toValue sym) vs)
_ -> error "invalid function type given to call"

-- | Emit a call instruction, but don't generate a new variable for its result.
call_ :: IsValue a => Typed a -> [Typed Value] -> BB ()
Expand Down
115 changes: 92 additions & 23 deletions src/Text/LLVM/AST.hs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ module Text.LLVM.AST
-- * Attributes
, Linkage(..)
, Visibility(..)
, ThreadLocality(..)
, UnnamedAddr(..)
, AddrSpace(..)
, allocaAddrSpace
, programAddrSpace
, ptrAddrSpace
, GC(..)
-- * Typed Things
, Typed(..)
Expand Down Expand Up @@ -284,7 +290,7 @@ type DataLayout = [LayoutSpec]
data LayoutSpec
= BigEndian
| LittleEndian
| PointerSize !Int !Int !Int (Maybe Int) -- ^ address space, size, abi, pref
| PointerSize !Bool !Int !Int !Int (Maybe Int) (Maybe Int) -- ^ fat pointer?, address space, size, abi, pref, "size of index used in GEP for address calculation"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, the first Int here is intended to be an address space, but it is not using the AddrSpace type. I wonder if it should.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the Bool (fat pointer?) documented? I'm looking here in the LLVM Language Reference Manual, but I don't see anything about fat pointers in the p[n]:<size>:<abi>[:<pref>][:<idx>] documentation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"size of index used in GEP for address calculation"

I'm not sure what to make of the quotation marks here. Is this quoting documentation from somewhere? If so, we should escape these double quotes, since Haddock will try to render things between double quotes as Haskell module names, which likely isn't what you intended here.

| IntegerSize !Int !Int (Maybe Int) -- ^ size, abi, pref
| VectorSize !Int !Int (Maybe Int) -- ^ size, abi, pref
| FloatSize !Int !Int (Maybe Int) -- ^ size, abi, pref
Expand All @@ -293,6 +299,9 @@ data LayoutSpec
| NativeIntSize [Int]
| StackAlign !Int -- ^ size
| Mangling Mangling
| AllocaAddressSpace !AddrSpace
| DefaultGlobalVariableAddressSpace !AddrSpace
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should abbreviate this to GlobalVariableAddressSpace? It might just be my reading of it, but I think the "Default" part is implied, and it's already a pretty long name.

| ProgramAddressSpace !AddrSpace -- ^ program address space, in particular functions
deriving (Data, Eq, Generic, Ord, Show, Typeable)

data Mangling = ElfMangling
Expand All @@ -318,7 +327,7 @@ parseDataLayout str =
'E' -> return BigEndian
'e' -> return LittleEndian
'S' -> StackAlign <$> pInt
'p' -> PointerSize <$> pInt0 <*> pCInt <*> pCInt <*> pPref
'p' -> PointerSize <$> pFat <*> pInt0 <*> pCInt <*> pCInt <*> pPref <*> pPref
'i' -> IntegerSize <$> pInt <*> pCInt <*> pPref
'v' -> VectorSize <$> pInt <*> pCInt <*> pPref
'f' -> FloatSize <$> pInt <*> pCInt <*> pPref -- size of float, abi-align, pref-align
Expand All @@ -340,6 +349,9 @@ parseDataLayout str =
'a' -> AggregateSize <$> pInt <*> pCInt <*> pPref
'n' -> NativeIntSize <$> sepBy pInt (char ':')
'm' -> Mangling <$> (char ':' >> pMangling)
'A' -> AllocaAddressSpace . AddrSpace <$> pInt
'G' -> DefaultGlobalVariableAddressSpace . AddrSpace <$> pInt
'P' -> ProgramAddressSpace . AddrSpace <$> pInt
_ -> mzero

pMangling :: Parser Mangling
Expand All @@ -361,6 +373,9 @@ parseDataLayout str =
pCInt :: Parser Int
pCInt = char ':' >> pInt

pFat :: Parser Bool
pFat = (char 'f' *> return True) <|> return False

pPref :: Parser (Maybe Int)
pPref = optionMaybe pCInt

Expand All @@ -380,7 +395,18 @@ data SelectionKind = ComdatAny
-- Identifiers -----------------------------------------------------------------

newtype Ident = Ident String
deriving (Data, Eq, Generic, Ord, Show, Typeable, Lift)
deriving (Data, Eq, Generic, Show, Typeable, Lift)

-- this exists so that struct types will be printed in the same order llvm-dis prints them
instance Ord Ident where
compare (Ident l) (Ident r) = go l r where
go [] [] = EQ
go [] _ = GT
go _ [] = LT
go (ll:ls) (rr:rs) = case compare ll rr of
LT -> LT
GT -> GT
EQ -> go ls rs
Comment on lines +400 to +409
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, how did you figure out that this is the approach that llvm-dis used? If there is LLVM documentation (or even code) that we can cite as inspiration for this, that would be ideal.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be good to point out how this is different from the default Ord; I think it's that the GT/LT for an empty Ident array is inverted from the norm?


instance IsString Ident where
fromString = Ident
Expand Down Expand Up @@ -427,20 +453,20 @@ data Type' ident
| Alias ident
| Array Word64 (Type' ident)
| FunTy (Type' ident) [Type' ident] Bool
| PtrTo (Type' ident)
| PtrTo !AddrSpace (Type' ident)
-- ^ A pointer to a memory location of a particular type. See also
-- 'PtrOpaque', which represents a pointer without a pointee type.
--
-- LLVM pointers can also have an optional address space attribute, but this
-- is not currently represented in the @llvm-pretty@ AST.
| PtrOpaque
-- LLVM pointers also have an optional address space attribute defaulting
-- to 0.
| PtrOpaque !AddrSpace
-- ^ A pointer to a memory location. Unlike 'PtrTo', a 'PtrOpaque' does not
-- have a pointee type. Instead, instructions interacting through opaque
-- pointers specify the type of the underlying memory they are interacting
-- with.
--
-- LLVM pointers can also have an optional address space attribute, but this
-- is not currently represented in the @llvm-pretty@ AST.
-- LLVM pointers also have an optional address space attribute defaulting to
-- 0.
--
-- 'PtrOpaque' should not be confused with 'Opaque', which is a completely
-- separate type with a similar-sounding name.
Expand All @@ -463,8 +489,8 @@ updateAliasesA f = loop
loop ty = case ty of
Array len ety -> Array len <$> (loop ety)
FunTy res ps var -> FunTy <$> (loop res) <*> (traverse loop ps) <*> pure var
PtrTo pty -> PtrTo <$> (loop pty)
PtrOpaque -> pure PtrOpaque
PtrTo adr pty -> PtrTo adr <$> (loop pty)
PtrOpaque adr -> pure $ PtrOpaque adr
Struct fs -> Struct <$> (traverse loop fs)
PackedStruct fs -> PackedStruct <$> (traverse loop fs)
Vector len ety -> Vector <$> pure len <*> (loop ety)
Expand Down Expand Up @@ -510,8 +536,8 @@ isArray ty = case ty of
_ -> False

isPointer :: Type -> Bool
isPointer (PtrTo _) = True
isPointer PtrOpaque = True
isPointer (PtrTo _ _) = True
isPointer (PtrOpaque _) = True
isPointer _ = False


Expand Down Expand Up @@ -545,8 +571,8 @@ data TypeView' ident
-- | Convert a `Type'` value to a `TypeView'` value.
typeView :: Type' ident -> TypeView' ident
-- The two most important cases. Both forms of pointers are mapped to PtrView.
typeView (PtrTo _) = PtrView
typeView PtrOpaque = PtrView
typeView (PtrTo _ _) = PtrView
typeView (PtrOpaque _) = PtrView
-- All other cases are straightforward.
typeView (PrimType pt) = PrimTypeView pt
typeView (Alias lab) = AliasView lab
Expand Down Expand Up @@ -592,11 +618,11 @@ fixupOpaquePtrs m
= m
where
isOpaquePtr :: Type -> Bool
isOpaquePtr PtrOpaque = True
isOpaquePtr (PtrOpaque _) = True
isOpaquePtr _ = False

opaquifyPtr :: Type -> Type
opaquifyPtr (PtrTo _) = PtrOpaque
opaquifyPtr (PtrTo adr _) = PtrOpaque adr
opaquifyPtr t = t

-- Find the first occurrence of a @b@ value within the @a@ value that
Expand Down Expand Up @@ -627,7 +653,7 @@ floatTypeNull _ = error "must be a float type"
typeNull :: Type -> NullResult lab
typeNull (PrimType pt) = HasNull (primTypeNull pt)
typeNull PtrTo{} = HasNull ValNull
typeNull PtrOpaque = HasNull ValNull
typeNull PtrOpaque{} = HasNull ValNull
typeNull (Alias i) = ResolveNull i
typeNull _ = HasNull ValZeroInit

Expand All @@ -642,7 +668,7 @@ elimAlias (Alias i) = return i
elimAlias _ = mzero

elimPtrTo :: MonadPlus m => Type -> m Type
elimPtrTo (PtrTo ty) = return ty
elimPtrTo (PtrTo _ ty) = return ty
elimPtrTo _ = mzero

elimVector :: MonadPlus m => Type -> m (Word64,Type)
Expand All @@ -668,7 +694,7 @@ elimFloatType _ = mzero
elimSequentialType :: MonadPlus m => Type -> m Type
elimSequentialType ty = case ty of
Array _ elTy -> return elTy
PtrTo elTy -> return elTy
PtrTo _ elTy -> return elTy
Vector _ pty -> return pty
_ -> mzero

Expand Down Expand Up @@ -698,13 +724,18 @@ addGlobal g m = m { modGlobals = g : modGlobals m }
data GlobalAttrs = GlobalAttrs
{ gaLinkage :: Maybe Linkage
, gaVisibility :: Maybe Visibility
, gaThreadLocality :: Maybe ThreadLocality
, gaUnnamedAddr :: Maybe UnnamedAddr
, gaAddrSpace :: AddrSpace
, gaConstant :: Bool
} deriving (Data, Eq, Generic, Ord, Show, Typeable)

emptyGlobalAttrs :: GlobalAttrs
emptyGlobalAttrs = GlobalAttrs
{ gaLinkage = Nothing
, gaVisibility = Nothing
, gaUnnamedAddr = Nothing
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing gaThreadLocality = Nothing?

, gaAddrSpace = AddrSpace 0
, gaConstant = False
}

Expand All @@ -714,24 +745,27 @@ emptyGlobalAttrs = GlobalAttrs
data Declare = Declare
{ decLinkage :: Maybe Linkage
, decVisibility :: Maybe Visibility
, decUnnamedAddr :: Maybe UnnamedAddr
, decRetType :: Type
, decName :: Symbol
, decArgs :: [Type]
, decVarArgs :: Bool
, decAttrs :: [FunAttr]
, decComdat :: Maybe String
, decAddrSpace :: AddrSpace
} deriving (Data, Eq, Generic, Ord, Show, Typeable)

-- | The function type of this declaration
decFunType :: Declare -> Type
decFunType Declare { .. } = PtrTo (FunTy decRetType decArgs decVarArgs)
decFunType Declare { .. } = PtrTo decAddrSpace (FunTy decRetType decArgs decVarArgs)


-- Function Definitions --------------------------------------------------------

data Define = Define
{ defLinkage :: Maybe Linkage
, defVisibility :: Maybe Visibility
, defAddrSpace :: AddrSpace
, defRetType :: Type
, defName :: Symbol
, defArgs :: [Typed Ident]
Expand All @@ -746,7 +780,7 @@ data Define = Define

defFunType :: Define -> Type
defFunType Define { .. } =
PtrTo (FunTy defRetType (map typedType defArgs) defVarArgs)
PtrTo defAddrSpace (FunTy defRetType (map typedType defArgs) defVarArgs)

addDefine :: Define -> Module -> Module
addDefine d m = m { modDefines = d : modDefines m }
Expand Down Expand Up @@ -841,6 +875,22 @@ data Visibility = DefaultVisibility
| ProtectedVisibility
deriving (Data, Eq, Generic, Ord, Show, Typeable)

data ThreadLocality = NotThreadLocal
| ThreadLocal
| LocalDynamic
| InitialExec
| LocalExec
Comment on lines +878 to +882
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style nit pick: I'd prefer if NotThreadLocal was aligned with the other data constructors. Perhaps something like:

Suggested change
data ThreadLocality = NotThreadLocal
| ThreadLocal
| LocalDynamic
| InitialExec
| LocalExec
data ThreadLocality
= NotThreadLocal
| ThreadLocal
| LocalDynamic
| InitialExec
| LocalExec

deriving (Data, Eq, Generic, Ord, Show, Typeable)

-- ^ there is also None, use Nothing for it
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this comment referring to?

data UnnamedAddr = GlobalUnnamedAddr
| LocalUnnamedAddr
deriving (Data, Eq, Generic, Ord, Show, Typeable)

newtype AddrSpace = AddrSpace
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments in this part of the LLVM Language Reference Manual suggest that an address space's value must be less than 2^24. Is that worth putting in the Haddocks here?

{ getAddrSpace :: Int
} deriving (Data, Eq, Generic, Ord, Show, Typeable) -- , Bits, FiniteBits)
Comment on lines +890 to +892
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you be willing to derive a Num instance for this? It would be convenient to be able to write, say, 0 instead of AddrSpace 0.

Comment on lines +890 to +892
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the commented-out code here be removed, or is there a need to keep it around?


newtype GC = GC
{ getGC :: String
} deriving (Data, Eq, Generic, Ord, Show, Typeable)
Expand Down Expand Up @@ -1070,8 +1120,9 @@ data Instr' lab
* The result is as indicated by the provided type.
* Introduced in LLVM 9. -}

| Alloca Type (Maybe (Typed (Value' lab))) (Maybe Int)
| Alloca Type AddrSpace (Maybe (Typed (Value' lab))) (Maybe Int)
{- ^ * Allocated space on the stack:
address space;
type of elements;
how many elements (1 if 'Nothing');
required alignment.
Expand Down Expand Up @@ -1822,3 +1873,21 @@ resolveValueIndex ty is@(ix:ixs) = case ty of

_ -> Invalid
resolveValueIndex ty [] = HasType ty

allocaAddrSpace :: DataLayout -> AddrSpace
allocaAddrSpace [] = AddrSpace 0
allocaAddrSpace (AllocaAddressSpace as:_) = as
allocaAddrSpace (_:ds) = allocaAddrSpace ds

programAddrSpace :: DataLayout -> AddrSpace
programAddrSpace [] = AddrSpace 0
programAddrSpace (ProgramAddressSpace as:_) = as
programAddrSpace (_:ds) = programAddrSpace ds

ptrAddrSpace :: Typed a -> AddrSpace
ptrAddrSpace = go . typedType
where
go :: Type -> AddrSpace
go (PtrTo x _) = x
go (PtrOpaque x) = x
go _ = AddrSpace 0
Comment on lines +1887 to +1893
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be worth leaving a Haddock comment saying that this returns the default address space on all non-pointer types (and this includes alias types).

2 changes: 1 addition & 1 deletion src/Text/LLVM/Labels.hs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ instance HasLabel Instr' where
<*> traverse (traverse (relabel f)) as
<*> f Nothing u
<*> traverse (f Nothing) es
relabel f (Alloca t n a) = Alloca t
relabel f (Alloca t s n a) = Alloca t s
<$> traverse (traverse (relabel f)) n
<*> pure a
relabel f (Load t a mo ma) = Load t
Expand Down
Loading
Loading