llvm-pretty 0.12.1.0 → 0.14.0.0
raw patch · 13 files changed
Files
- CHANGELOG.md +72/−0
- llvm-pretty.cabal +6/−3
- src/Text/LLVM.hs +44/−14
- src/Text/LLVM/AST.hs +507/−132
- src/Text/LLVM/DebugUtils.hs +21/−9
- src/Text/LLVM/Labels.hs +9/−1
- src/Text/LLVM/Lens.hs +1/−1
- src/Text/LLVM/PP.hs +258/−64
- src/Text/LLVM/Triple/AST.hs +7/−8
- test/DataLayout.hs +31/−0
- test/Main.hs +6/−2
- test/Metadata.hs +34/−0
- test/Output.hs +72/−7
CHANGELOG.md view
@@ -1,5 +1,77 @@ # Revision history for llvm-pretty +## 0.14.0.0 -- 2026-01-22++* Changes to support LLVM 19 (some of these changes are not backward-compatible):+ * Changes to `LayoutSpec` for DataLayout:+ * Size specification fields use a common sub-structure `Storage` which itself+ contains an `Alignment` common sub-structure: `IntegerSize`, `VectorSize`,+ `FloatSize`, and `StackObjSize`.+ * The pointer size specification field uses a `PointerSize` sub-structure+ that itself contains a `Storage` sub-structure.+ * Updated `AggregateSize` to make first field optional (it was dropped in+ LLVM 4) and the remaining fields are now provided via the `Alignment`+ sub-structure.+ * Added `ProgramAddrSpace`, `GlobalAddrSpace`, and `AllocaAddrSpace`+ constructors, each defined via an `AddressSpace` sub-structure.+ * Added `NonIntegralPointerSpaces` to record address spaces with an+ unspecified bitwise representation.+ * Added `GoffMangling`, `WindowsX86CoffMangling`, and `XCoffMangling` forms+ of Mangling.+ * Added `GEPAttr` flags for `GEP` instruction and constant expression, with+ `RangeSpec` for the latter.+ * Added `numExtraInhabitants` to `DIBasicType`.+ * Added support for `DebugRecord` parsing, specifically for:++ * `FUNC_CODE_DEBUG_RECORD_VALUE`+ * `FUNC_CODE_DEBUG_RECORD_DECLARE`+ * `FUNC_CODE_DEBUG_RECORD_ASSIGN`+ * `FUNC_CODE_DEBUG_RECORD_VALUE_SIMPLE`+ * `FUNC_CODE_DEBUG_RECORD_LABEL`++ This adds a new field to both the `Result` and `Effect` constructors of the `Stmt` type.+ * Pretty-printing with an LLVM version >= 19 now generates an error for `icmp`,+ `fcmp`, and `shl` constant expressions that are no longer supported as of+ LLVM 19.+* Changes to cast-related instructions:+ * Add a `Bool` field to `ZExt` which, if `True`, indicates that the+ argument must be non-negative. This is used by LLVM 18 and up.+ * Add a `Bool` field to `UiToFp` which, if `True`, indicates that the+ argument must be non-negative. This is used by LLVM 19 and up.+ * Add `Bool` fields to `Trunc` to check if the truncation would cause+ unsigned or signed overflow. These are used by LLVM 20 and up.+* Add a `Bool` field to `ICmp`, which indicates that the arguments must have+ the same sign. This is used by LLVM 20 and up.+* Add `dlAtomGroup` and `dlAtomRank` fields to `DebugLoc'`, which were+ introduced in LLVM 21.+* Add `dilColumn`, `dilIsArtificial`, and `dilCoroSuspendIdx` fields to+ `DILabel'`, which were introduced in LLVM 21.+* The following debug-related fields have had their types changed from `Word64`+ to `Maybe (ValMd' lab)`:++ * `DIBasicType'`: `dibtSize`+ * `DICompositeType'`: `dictSize` and `dictOffset`+ * `DIDerivedType'`: `didtSize` and `didtOffset`++ This allows them to encode non-constant sizes and offsets (a capability used+ by Ada, for instance) in LLVM 21 or later.+* Added the `bbStmtModifier` which can be used to modify individual statements as+ they are emitted from the top-level instruction generator functions (e.g to add+ Debug Metadata to each statement).+* Fix a bug that would cause `indirectbr` statements to be pretty-printed+ incorrectly.++## 0.13.1.0 (October 2025)++* Add a `FunctionPointerAlign` constructor to `LayoutSpec`.++## 0.13.0.0 (March 2025)++* Changed some of the signatures of helper functions in the AST to make them more+ flexible by using `Type' ident` rather than `Type` in their signatures (the+ latter fixes `ident` to be `Ident`). Changed functions: `isAlias`,+ `isPrimTypeOf`, `isVector`, `isVectorOf`, `isArray`, and `isPointer`.+ ## 0.12.1.0 (August 2024) * Fix for printing NaN and infinite floating point values.
llvm-pretty.cabal view
@@ -1,6 +1,6 @@ Cabal-version: 2.2 Name: llvm-pretty-Version: 0.12.1.0+Version: 0.14.0.0 License: BSD-3-Clause License-file: LICENSE Author: Trevor Elliott@@ -13,7 +13,7 @@ Augustsson. The library provides a monadic interface to a pretty printer, that allows functions to be defined and called, generating the corresponding LLVM assembly when run.-tested-with: GHC==8.4.3, GHC==8.2.2, GHC==8.0.2+tested-with: GHC==9.12.3, GHC==9.10.1, GHC==9.8.4 extra-doc-files: CHANGELOG.md, README.md @@ -25,6 +25,7 @@ Default-language: Haskell2010 Ghc-options: -Wall+ -fhide-source-paths Library Import: common@@ -55,13 +56,15 @@ microlens-th >= 0.4, syb >= 0.7, template-haskell >= 2.7,- th-abstraction >= 0.3.1 && <0.7+ th-abstraction >= 0.3.1 && <0.8 Test-suite llvm-pretty-test Import: common Type: exitcode-stdio-1.0 Main-is: Main.hs Other-modules:+ DataLayout+ Metadata Output Triple TQQDefs
src/Text/LLVM.hs view
@@ -40,6 +40,8 @@ -- * Basic Blocks , BB()+ , runBB+ , bbStmtModifier , freshLabel , label , comment@@ -313,9 +315,36 @@ -- Basic Block Monad ----------------------------------------------------------- newtype BB a = BB- { unBB :: WriterT [BasicBlock] (StateT RW Id) a+ { unBB :: ReaderT (Stmt -> Stmt) (WriterT [BasicBlock] (StateT RW Id)) a } deriving (Functor,Applicative,Monad,MonadFix) ++-- | The 'bbStmtModifier' function can be used to register a function that can+-- modify the subsequent statements generated into this block.+--+-- For example, the following 'BB' monad code segment will emit a couple of LLVM+-- statements:+--+-- > v <- load (iT 8) globalVar Nothing+-- > call fooFunc [v]+-- > jump end+--+-- But these statements will be \"plain\" in the resulting 'BasicBlock'. If the+-- caller wishes to add debug Metadata for location, they could instead write:+--+-- > bbStmtModifier (extendMetadata ("dbg", ValMdRef i))+-- > v <- load (iT 8) globalVar Nothing+-- > bbStmtModifier (extendMetadata ("dbg", ValMdRef j))+-- > call fooFunc [v]+-- > jump end+--+-- Where @i@ and @j@ are the metadata index values of the 'DebugLoc' entries+-- describing the source location of the \"load\" and \"call\"+\"jump\" statements,+-- respectively.++bbStmtModifier :: (Stmt -> Stmt) -> BB a -> BB a+bbStmtModifier stmtModifier = BB . local stmtModifier . unBB+ avoidName :: String -> BB () avoidName name = BB $ do rw <- get@@ -332,7 +361,7 @@ runBB :: BB a -> (a,[BasicBlock]) runBB m =- case runId (runStateT emptyRW (runWriterT (unBB body))) of+ case runId (runStateT emptyRW (runWriterT (runReaderT id (unBB body)))) of ((a,bbs),_rw) -> (a,bbs) where -- make sure that the last block is terminated@@ -366,17 +395,18 @@ emitStmt stmt = do BB $ do rw <- get- set $! rw { rwStmts = rwStmts rw Seq.|> stmt }+ smod <- ask+ set $! rw { rwStmts = rwStmts rw Seq.|> smod stmt } when (isTerminator (stmtInstr stmt)) terminateBasicBlock effect :: Instr -> BB ()-effect i = emitStmt (Effect i [])+effect i = emitStmt (Effect i mempty []) observe :: Type -> Instr -> BB (Typed Value) observe ty i = do name <- freshNameBB "r" let res = Ident name- emitStmt (Result res i [])+ emitStmt (Result res i mempty []) return (Typed ty (ValIdent res)) @@ -507,8 +537,8 @@ rw <- BB get case Seq.viewr (rwStmts rw) of - stmts Seq.:> Result _ i m ->- do BB (set rw { rwStmts = stmts Seq.|> Result r i m })+ stmts Seq.:> Result _ i d m ->+ do BB (set rw { rwStmts = stmts Seq.|> Result r i d m }) return (const (ValIdent r) `fmap` tv) _ -> error "assign: invalid argument"@@ -639,10 +669,10 @@ convop k a ty = observe ty (k (toValue `fmap` a) ty) trunc :: IsValue a => Typed a -> Type -> BB (Typed Value)-trunc = convop (Conv Trunc)+trunc = convop (Conv (Trunc False False)) zext :: IsValue a => Typed a -> Type -> BB (Typed Value)-zext = convop (Conv ZExt)+zext = convop (Conv (ZExt False)) sext :: IsValue a => Typed a -> Type -> BB (Typed Value) sext = convop (Conv SExt)@@ -660,7 +690,7 @@ fptosi = convop (Conv FpToSi) uitofp :: IsValue a => Typed a -> Type -> BB (Typed Value)-uitofp = convop (Conv UiToFp)+uitofp = convop (Conv (UiToFp False)) sitofp :: IsValue a => Typed a -> Type -> BB (Typed Value) sitofp = convop (Conv SiToFp)@@ -675,7 +705,7 @@ bitcast = convop (Conv BitCast) icmp :: (IsValue a, IsValue b) => ICmpOp -> Typed a -> b -> BB (Typed Value)-icmp op l r = observe (iT 1) (ICmp op (toValue `fmap` l) (toValue r))+icmp op l r = observe (iT 1) (ICmp False op (toValue `fmap` l) (toValue r)) fcmp :: (IsValue a, IsValue b) => FCmpOp -> Typed a -> b -> BB (Typed Value) fcmp op l r = observe (iT 1) (FCmp op (toValue `fmap` l) (toValue r))@@ -695,13 +725,13 @@ getelementptr :: IsValue a => Type -> Typed a -> [Typed Value] -> BB (Typed Value)-getelementptr ty ptr ixs = observe ty (GEP False ty (toValue `fmap` ptr) ixs)+getelementptr ty ptr ixs = observe ty (GEP [] 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- ty@(PtrTo (FunTy rty _ _)) -> observe rty (Call False ty (toValue sym) vs)- _ -> error "invalid function type given to call"+ PtrTo 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 ()
src/Text/LLVM/AST.hs view
@@ -9,12 +9,15 @@ incomplete: there are some values that new LLVM versions would accept but are not yet represented here. -}++{-# LANGUAGE LambdaCase #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric #-} {-# LANGUAGE PatternGuards #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE DeriveLift #-}+ module Text.LLVM.AST ( -- * Modules Module(..)@@ -28,6 +31,12 @@ -- * Data Layout , DataLayout , LayoutSpec(..)+ , Alignment(..)+ , FunctionPointerAlignType(..)+ , Storage(..)+ , PointerSize(..)+ , AddressSpace+ , NumBits , Mangling(..) , parseDataLayout -- * Inline Assembly@@ -131,8 +140,12 @@ , stmtInstr , stmtMetadata , extendMetadata+ , addDebugRecord -- * Constant Expressions , ConstExpr'(..), ConstExpr+ , GEPAttr(..)+ , orderedGEPAttrs+ , RangeSpec(RangeIndex, Range) -- * DWARF Debug Info , DebugInfo'(..), DebugInfo , DILabel, DILabel'(..)@@ -146,7 +159,7 @@ , DwarfVirtuality , DIFlags , DIEmissionKind- , DIBasicType(..)+ , DIBasicType'(..), DIBasicType , DICompileUnit'(..), DICompileUnit , DICompositeType'(..), DICompositeType , DIDerivedType'(..), DIDerivedType@@ -161,6 +174,13 @@ , DISubrange'(..), DISubrange , DISubroutineType'(..), DISubroutineType , DIArgList'(..), DIArgList+ , dwarf_DW_APPLE_ENUM_KIND_invalid+ , DebugRecord, DebugRecord'(..)+ , DbgRecAssign, DbgRecAssign'(..)+ , DbgRecDeclare, DbgRecDeclare'(..)+ , DbgRecLabel, DbgRecLabel'(..)+ , DbgRecValueSimple, DbgRecValueSimple'(..)+ , DbgRecValue, DbgRecValue'(..) -- * Aggregate Utilities , IndexResult(..) , isInvalid@@ -172,18 +192,19 @@ , resolveValueIndex ) where -import Data.Functor.Identity (Identity(..))+import Control.Monad (MonadPlus(mzero,mplus),(<=<),guard)+import Data.Bits ( complement ) import Data.Coerce (coerce) import Data.Data (Data)-import Data.Typeable (Typeable)-import Control.Monad (MonadPlus(mzero,mplus),(<=<),guard)-import Data.Int (Int32,Int64)+import Data.Functor.Identity (Identity(..)) import Data.Generics (everywhere, extQ, mkT, something)+import Data.Int (Int32,Int64) import Data.List (genericIndex,genericLength) import qualified Data.Map as Map import Data.Maybe (isJust) import Data.Semigroup as Sem import Data.String (IsString(fromString))+import Data.Typeable (Typeable) import Data.Word (Word8,Word16,Word32,Word64) import GHC.Generics (Generic, Generic1) import Language.Haskell.TH.Syntax (Lift)@@ -209,7 +230,7 @@ , modDefines :: [Define] -- ^ internal function declarations (with definitions) , modInlineAsm :: InlineAsm , modAliases :: [GlobalAlias]- } deriving (Data, Eq, Ord, Generic, Show, Typeable)+ } deriving (Data, Eq, Ord, Generic, Show) -- | Combines fields pointwise. instance Sem.Semigroup Module where@@ -254,7 +275,7 @@ data NamedMd = NamedMd { nmName :: String , nmValues :: [Int]- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) -- Unnamed Metadata ------------------------------------------------------------@@ -263,7 +284,7 @@ { umIndex :: !Int , umValues :: ValMd , umDistinct :: Bool- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) -- Aliases ---------------------------------------------------------------------@@ -274,38 +295,79 @@ , aliasName :: Symbol , aliasType :: Type , aliasTarget :: Value- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) -- Data Layout -----------------------------------------------------------------+-- https://releases.llvm.org/19.1.0/docs/LangRef.html#data-layout type DataLayout = [LayoutSpec] data LayoutSpec = BigEndian | LittleEndian- | PointerSize !Int !Int !Int (Maybe Int) -- ^ address space, size, abi, pref- | IntegerSize !Int !Int (Maybe Int) -- ^ size, abi, pref- | VectorSize !Int !Int (Maybe Int) -- ^ size, abi, pref- | FloatSize !Int !Int (Maybe Int) -- ^ size, abi, pref- | StackObjSize !Int !Int (Maybe Int) -- ^ size, abi, pref- | AggregateSize !Int !Int (Maybe Int) -- ^ size, abi, pref- | NativeIntSize [Int]- | StackAlign !Int -- ^ size+ | PointerSize PointerSize+ | IntegerSize Storage+ | VectorSize Storage+ | FloatSize Storage+ | StackObjSize Storage+ | AggregateSize (Maybe Int) !Alignment -- n.b. first Int present pre-LLVM4+ | NativeIntSize [NumBits]+ | StackAlign !NumBits -- ^ size+ | ProgramAddrSpace !AddressSpace+ | GlobalAddrSpace !AddressSpace+ | AllocaAddrSpace !AddressSpace+ | FunctionPointerAlign !FunctionPointerAlignType !NumBits -- ^ type, abi | Mangling Mangling- deriving (Data, Eq, Generic, Ord, Show, Typeable)+ | NonIntegralPointerSpaces [AddressSpace]+ deriving (Data, Eq, Generic, Ord, Show) +data Alignment = Alignment+ { alignABI :: !NumBits+ , alignPreferred :: Maybe NumBits -- ^ default = alignABI+ }+ deriving (Data, Eq, Generic, Ord, Show)++-- | How should a function pointer be aligned?+data FunctionPointerAlignType+ = IndependentOfFunctionAlign+ -- ^ The alignment of function pointers is independent of the alignment of+ -- functions.+ | MultipleOfFunctionAlign+ -- ^ The alignment of function pointers is a multiple of the explicit+ -- alignment specified on the function.+ deriving (Data, Eq, Enum, Generic, Ord, Show)++data Storage = Storage+ { storageSize :: !NumBits -- ^ valid range [1,2^24)+ , storageAlignment :: Alignment+ }+ deriving (Data, Eq, Generic, Ord, Show)++data PointerSize = PtrSize+ { ptrAddrSpace :: !AddressSpace+ , ptrStorage :: Storage+ , ptrAddrIndexSize :: Maybe NumBits -- ^ m.b. <= ptrSize, default = ptrSize+ }+ deriving (Data, Eq, Generic, Ord, Show)++type AddressSpace = Int+type NumBits = Int+ data Mangling = ElfMangling+ | GoffMangling | MipsMangling | MachOMangling | WindowsCoffMangling- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ | WindowsX86CoffMangling+ | XCoffMangling+ deriving (Data, Eq, Enum, Generic, Ord, Show) -- | Parse the data layout string. parseDataLayout :: MonadPlus m => String -> m DataLayout parseDataLayout str = case parse (pDataLayout <* eof) "<internal>" str of- Left _err -> mzero+ Left _err -> {- debugging: trace (show err) -} mzero Right specs -> return specs where pDataLayout :: Parser DataLayout@@ -317,11 +379,17 @@ case c of 'E' -> return BigEndian 'e' -> return LittleEndian- 'S' -> StackAlign <$> pInt- 'p' -> PointerSize <$> pInt0 <*> pCInt <*> pCInt <*> pPref- 'i' -> IntegerSize <$> pInt <*> pCInt <*> pPref- 'v' -> VectorSize <$> pInt <*> pCInt <*> pPref- 'f' -> FloatSize <$> pInt <*> pCInt <*> pPref -- size of float, abi-align, pref-align+ 'S' -> StackAlign <$> pInt+ 'P' -> ProgramAddrSpace <$> pInt -- Added in LLVM7+ 'G' -> GlobalAddrSpace <$> pInt -- Added in LLVM11+ 'A' -> AllocaAddrSpace <$> pInt -- Added in LLVM11+ 'p' -> do as <- pInt <|> return 0+ st <- char ':' >> pStorage+ idx <- pCOInt -- Added in LLVM7+ return $ PointerSize $ PtrSize as st idx+ 'i' -> IntegerSize <$> pStorage+ 'v' -> VectorSize <$> pStorage+ 'f' -> FloatSize <$> pStorage -- Note that the data layout specified in the LLVM -- BC/IR file is not a directive to the backend, but -- is instead an indication of what the particular@@ -336,33 +404,59 @@ -- (for example) references to LongDoubleWidth and -- LongDoubleFormat in -- https://github.com/llvm/llvm-project/blob/release_60/clang/lib/Basic/Targets/X86.h- 's' -> StackObjSize <$> pInt <*> pCInt <*> pPref- 'a' -> AggregateSize <$> pInt <*> pCInt <*> pPref- 'n' -> NativeIntSize <$> sepBy pInt (char ':')- 'm' -> Mangling <$> (char ':' >> pMangling)+ 's' -> StackObjSize <$> pStorage -- Obsoleted in LLVM4+ 'a' -> alphaNum >>= \case+ ':' -> AggregateSize Nothing <$> pAlignment+ d -> AggregateSize <$> (Just <$> pIntWithFirstDigit d)+ <* char ':' <*> pAlignment+ 'F' -> FunctionPointerAlign <$> pFunctionPointerAlignType <*> pInt -- Added in LLVM9+ 'm' -> Mangling <$ char ':' <*> pMangling+ 'n' -> alphaNum >>= \case+ 'i' -> char ':'+ >> (NonIntegralPointerSpaces <$> sepBy pInt (char ':'))+ d -> do fs <- pIntWithFirstDigit d+ ss <- char ':' *> sepBy pInt (char ':')+ return $ NativeIntSize $ fs : ss _ -> mzero + pFunctionPointerAlignType :: Parser FunctionPointerAlignType+ pFunctionPointerAlignType =+ do c <- letter+ case c of+ 'i' -> return IndependentOfFunctionAlign+ 'n' -> return MultipleOfFunctionAlign+ _ -> mzero+ pMangling :: Parser Mangling pMangling = do c <- letter case c of 'e' -> return ElfMangling+ 'l' -> return GoffMangling 'm' -> return MipsMangling 'o' -> return MachOMangling 'w' -> return WindowsCoffMangling+ 'x' -> return WindowsX86CoffMangling+ 'a' -> return XCoffMangling _ -> mzero + pAlignment :: Parser Alignment+ pAlignment = Alignment <$> pInt <*> pCOInt++ pStorage :: Parser Storage+ pStorage = Storage <$> pInt <* char ':' <*> pAlignment+ pInt :: Parser Int pInt = read <$> many1 digit - pInt0 :: Parser Int- pInt0 = pInt <|> return 0+ pIntWithFirstDigit :: Char -> Parser Int+ pIntWithFirstDigit d0 = read . (d0:) <$> many digit pCInt :: Parser Int pCInt = char ':' >> pInt - pPref :: Parser (Maybe Int)- pPref = optionMaybe pCInt+ pCOInt :: Parser (Maybe Int)+ pCOInt = optionMaybe pCInt -- Inline Assembly ------------------------------------------------------------- @@ -375,12 +469,12 @@ | ComdatLargest | ComdatNoDuplicates | ComdatSameSize- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Enum, Generic, Ord, Show) -- Identifiers ----------------------------------------------------------------- newtype Ident = Ident String- deriving (Data, Eq, Generic, Ord, Show, Typeable, Lift)+ deriving (Data, Eq, Generic, Ord, Show, Lift) instance IsString Ident where fromString = Ident@@ -388,7 +482,7 @@ -- Symbols --------------------------------------------------------------------- newtype Symbol = Symbol String- deriving (Data, Eq, Generic, Ord, Show, Typeable, Lift)+ deriving (Data, Eq, Generic, Ord, Show, Lift) instance Sem.Semigroup Symbol where Symbol a <> Symbol b = Symbol (a <> b)@@ -409,7 +503,7 @@ | FloatType FloatType | X86mmx | Metadata- deriving (Data, Eq, Generic, Ord, Show, Typeable, Lift)+ deriving (Data, Eq, Generic, Ord, Show, Lift) data FloatType = Half@@ -418,7 +512,7 @@ | Fp128 | X86_fp80 | PPC_fp128- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable, Lift)+ deriving (Data, Eq, Enum, Generic, Ord, Show, Lift) type Type = Type' Ident @@ -454,7 +548,7 @@ -- -- 'Opaque' should not be confused with 'PtrOpaque', which is a completely -- separate type with a similar-sounding name.- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) -- | Applicatively traverse a type, updating or removing aliases. updateAliasesA :: (Applicative f) => (a -> f (Type' b)) -> Type' a -> f (Type' b)@@ -480,11 +574,11 @@ isFloatingPoint (FloatType _) = True isFloatingPoint _ = False -isAlias :: Type -> Bool+isAlias :: Type' ident -> Bool isAlias Alias{} = True isAlias _ = False -isPrimTypeOf :: (PrimType -> Bool) -> Type -> Bool+isPrimTypeOf :: (PrimType -> Bool) -> Type' ident -> Bool isPrimTypeOf p (PrimType pt) = p pt isPrimTypeOf _ _ = False @@ -496,20 +590,20 @@ isInteger Integer{} = True isInteger _ = False -isVector :: Type -> Bool+isVector :: Type' ident -> Bool isVector Vector{} = True isVector _ = False -isVectorOf :: (Type -> Bool) -> Type -> Bool+isVectorOf :: (Type' ident -> Bool) -> Type' ident -> Bool isVectorOf p (Vector _ e) = p e isVectorOf _ _ = False -isArray :: Type -> Bool+isArray :: Type' ident -> Bool isArray ty = case ty of Array _ _ -> True _ -> False -isPointer :: Type -> Bool+isPointer :: Type' ident -> Bool isPointer (PtrTo _) = True isPointer PtrOpaque = True isPointer _ = False@@ -610,7 +704,7 @@ data NullResult lab = HasNull (Value' lab) | ResolveNull Ident- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) primTypeNull :: PrimType -> Value' lab primTypeNull (Integer 1) = ValBool False@@ -678,7 +772,7 @@ data TypeDecl = TypeDecl { typeName :: Ident , typeValue :: Type- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) -- Globals ---------------------------------------------------------------------@@ -690,7 +784,7 @@ , globalValue :: Maybe Value , globalAlign :: Maybe Align , globalMetadata :: GlobalMdAttachments- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) addGlobal :: Global -> Module -> Module addGlobal g m = m { modGlobals = g : modGlobals m }@@ -699,7 +793,7 @@ { gaLinkage :: Maybe Linkage , gaVisibility :: Maybe Visibility , gaConstant :: Bool- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) emptyGlobalAttrs :: GlobalAttrs emptyGlobalAttrs = GlobalAttrs@@ -720,7 +814,7 @@ , decVarArgs :: Bool , decAttrs :: [FunAttr] , decComdat :: Maybe String- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) -- | The function type of this declaration decFunType :: Declare -> Type@@ -742,7 +836,7 @@ , defBody :: [BasicBlock] , defMetadata :: FnMdAttachments , defComdat :: Maybe String- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) defFunType :: Define -> Type defFunType Define { .. } =@@ -783,14 +877,14 @@ | SSPreq | SSPstrong | UWTable- deriving (Data, Eq, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Generic, Ord, Show) -- Basic Block Labels ---------------------------------------------------------- data BlockLabel = Named Ident | Anon Int- deriving (Data, Eq, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Generic, Ord, Show) instance IsString BlockLabel where fromString str = Named (fromString str)@@ -800,7 +894,7 @@ data BasicBlock' lab = BasicBlock { bbLabel :: Maybe lab , bbStmts :: [Stmt' lab]- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type BasicBlock = BasicBlock' BlockLabel @@ -834,23 +928,23 @@ | External | DLLImport | DLLExport- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Enum, Generic, Ord, Show) data Visibility = DefaultVisibility | HiddenVisibility | ProtectedVisibility- deriving (Data, Eq, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Generic, Ord, Show) newtype GC = GC { getGC :: String- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) -- Typed Things ---------------------------------------------------------------- data Typed a = Typed { typedType :: Type , typedValue :: a- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) instance Foldable Typed where foldMap f t = f (typedValue t)@@ -920,7 +1014,7 @@ -- ^ * Floating point reminder resulting from floating point division. -- * The reminder has the same sign as the divident (first parameter). - deriving (Data, Eq, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Generic, Ord, Show) isIArith :: ArithOp -> Bool isIArith Add{} = True@@ -938,7 +1032,7 @@ data UnaryArithOp = FNeg -- ^ Floating point negation.- deriving (Data, Eq, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Generic, Ord, Show) -- | Binary bitwise operators. data BitOp@@ -975,23 +1069,55 @@ | And | Or | Xor- deriving (Data, Eq, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Generic, Ord, Show) -- | Conversions from one type to another. data ConvOp- = Trunc- | ZExt+ = Trunc Bool Bool+ -- ^ Truncate an integer value to a smaller integer type.+ --+ -- The 'Bool' fields (added in in LLVM 20) encode whether to perform+ -- overflow-related checks:+ --+ -- * First 'Bool': check for unsigned overflow.+ -- * Second 'Bool': check for signed overflow.+ --+ -- If the checks fail, then the result is poisoned.+ --+ -- These fields can only ever 'True' in 'Conv' instructions in LLVM 20 or+ -- later. These fields are always 'False' in 'ConstConv' constant+ -- expressions or if the LLVM version is older than 20.+ | ZExt Bool+ -- ^ Zero extension.+ --+ -- The 'Bool' field (added in LLVM 18) encodes whether to enforce that the+ -- argument is non-negative. If the 'Bool' is 'True' and the argument is+ -- negative, then the result is poisoned.+ --+ -- This field can only ever 'True' in 'Conv' instructions in LLVM 18 or+ -- later. This field is always 'False' in 'ConstConv' constant expressions+ -- or if the LLVM version is older than 18. | SExt | FpTrunc | FpExt | FpToUi | FpToSi- | UiToFp+ | UiToFp Bool+ -- ^ Convert the argument from an unsigned integer to a floating-point+ -- value.+ --+ -- The 'Bool' field (added in LLVM 19) encodes whether to enforce that the+ -- argument is non-negative. If the 'Bool' is 'True' and the argument is+ -- negative, then the result is poisoned.+ --+ -- This field can only ever 'True' in 'Conv' instructions in LLVM 19 or+ -- later. This field is always 'False' in 'ConstConv' constant expressions+ -- or if the LLVM version is older than 19. | SiToFp | PtrToInt | IntToPtr | BitCast- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Generic, Ord, Show) data AtomicRWOp = AtomicXchg@@ -1011,7 +1137,7 @@ | AtomicFMin -- ^ Introduced in LLVM 15 | AtomicUIncWrap -- ^ Introduced in LLVM 16 | AtomicUDecWrap -- ^ Introduced in LLVM 16- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Enum, Generic, Ord, Show) data AtomicOrdering = Unordered@@ -1020,7 +1146,7 @@ | Release | AcqRel | SeqCst- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Enum, Generic, Ord, Show) type Align = Int @@ -1129,10 +1255,14 @@ * Middle of basic block. * Effect. -} - | ICmp ICmpOp (Typed (Value' lab)) (Value' lab)+ | ICmp Bool ICmpOp (Typed (Value' lab)) (Value' lab) {- ^ * Compare two integral values. * Middle of basic block.- * Returns a boolean value. -}+ * Returns a boolean value.+ * The 'Bool' field (added in LLVM 20) encodes whether to enforce that+ the arguments have the same sign. If the 'Bool' is 'True' and the+ arguments have mismatched signs, then the result is poisoned. This+ field is always 'False' if the LLVM version is older than 20. -} | FCmp FCmpOp (Typed (Value' lab)) (Value' lab) {- ^ * Compare two floating point values.@@ -1145,16 +1275,19 @@ * Middle of basic block. * Returns a value of the specified type. -} - | GEP Bool Type (Typed (Value' lab)) [Typed (Value' lab)]+ | GEP [GEPAttr] Type (Typed (Value' lab)) [Typed (Value' lab)] {- ^ * "Get element pointer", compute the address of a field in a structure:- inbounds check (value poisoned if this fails);+ inbounds check attr (value poisoned if this fails); type to use as a basis for calculations; pointer to parent structure; path to a sub-component of a structure. * Middle of basic block. * Returns the address of the requested member. + It's recommended that the GEPAttr list should be normalized (i.e. only one of+ each entry).+ The types in path are the types of the index, not the fields. The indexes are in units of fields (i.e., the first element in@@ -1196,7 +1329,16 @@ | ShuffleVector (Typed (Value' lab)) (Value' lab) (Typed (Value' lab))-+ {- ^ * Constructs a fixed permutation of two input vectors: the first+ and second arguments are input vectors, and the third argument+ is the mask.+ * Middle of basic block.+ * Returns the permuted vector. For each element, the mask selects+ an element from one of the input vectors to copy to the result:+ * non-negative mask values represent an index into the concatenated+ pair of input vectors, and+ * -1 mask value indicates that the output element is poison.+ -} | Jump lab {- ^ * Jump to the given basic block.@@ -1208,6 +1350,16 @@ * Ends basic block. -} | Invoke Type (Value' lab) [Typed (Value' lab)] lab lab+ {- ^ * Calls the specified target function, then branches to the success+ label. If an exception occurs during the call, the exception unwind+ handling branches to the second label.+ * Arguments:+ 1. The function's return type+ 2. The function target itself (to be called)+ 3. arguments to the function+ 4. successful return target label+ 5. on-exception unwind target label+ * Ends basic block. -} | Comment String -- ^ Comment@@ -1217,31 +1369,58 @@ | Unwind | VaArg (Typed (Value' lab)) Type+ -- ^ Accesses arguments passed through \"varargs\" areas of a function call.+ -- The argument is a @va_list*@; this instruction returns the value of the+ -- specified type located at the target and increments the pointer.+ | IndirectBr (Typed (Value' lab)) [lab]+ -- ^ Branch via pointer indirection. The argument is the address of the+ -- label to jump to. (All) Possible destination targets are provided. | Switch (Typed (Value' lab)) lab [(Integer,lab)]- {- ^ * Multi-way branch: the first value determines the direction- of the branch, the label is a default direction, if the value- does not appear in the jump table, the last argument is the- jump table.+ {- ^ * Multi-way branch: the first value determines the target index+ for the jump, which is looked up in the third argument table+ (key values are unique). The second argument is the default+ destination if the target is not found in the table. * Ends basic block. -} | LandingPad Type (Maybe (Typed (Value' lab))) Bool [Clause' lab]+ {- ^ Target of an exception (from the 'Invoke' instruction).+ * Arguments:+ 1. The result type (the values set by the personality function+ on re-entry to the function).+ 2. The second argument may be the personality function, which defines+ values on re-entry. This is used in older LLVM versions and is+ not supplied for recent LLVM versions.+ 3. True if this block is a "cleanup".+ 4. The list of clauses to handle the exception; the clauses are+ used to match the exception thrown.+ * If no clause matches and cleanup not set, continue unwinding up+ the stack (see 'Resume').+ * If cleanup is false, there must be at least one clause+ -} | Resume (Typed (Value' lab))+ {- ^ Resumes propagation of an in-flight exception whose unwinding was+ interrupted by a 'LandingPad' instruction.+ * Argument: the value of the exception to propagate.+ -} | Freeze (Typed (Value' lab)) {- ^ * Used to stop propagation of @undef@ and @poison@ values.+ * If the argument is @undef@ or @poison@, returns an arbitrary+ (but fixed) value of that type instead, otherwise a no-op and+ returns its argument. * Middle of basic block. -} - deriving (Data, Eq, Functor, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Functor, Generic, Ord, Show) type Instr = Instr' BlockLabel data Clause' lab = Catch (Typed (Value' lab)) | Filter (Typed (Value' lab))- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type Clause = Clause' BlockLabel @@ -1271,15 +1450,89 @@ -- | Integer comparison operators. data ICmpOp = Ieq | Ine | Iugt | Iuge | Iult | Iule | Isgt | Isge | Islt | Isle- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Enum, Generic, Ord, Show) -- | Floating-point comparison operators. data FCmpOp = Ffalse | Foeq | Fogt | Foge | Folt | Fole | Fone | Ford | Fueq | Fugt | Fuge | Fult | Fule | Fune | Funo | Ftrue- deriving (Data, Eq, Enum, Generic, Ord, Show, Typeable)+ deriving (Data, Eq, Enum, Generic, Ord, Show) +-- Debug Instructions ----------------------------------------------------------++-- | Debug Instructions+--+-- In LLVM 19, debug instructions were added as a replacement for the intrinsic+-- functions previously used. This addition is described in+-- llvm-project/llvm/docs/RemoveDIsDebugInfo.md in the LLVM repository.+data DebugRecord' lab+ = DebugRecordValue (DbgRecValue' lab)+ | DebugRecordDeclare (DbgRecDeclare' lab)+ | DebugRecordAssign (DbgRecAssign' lab)+ | DebugRecordValueSimple (DbgRecValueSimple' lab)+ | DebugRecordLabel (DbgRecLabel' lab)+ deriving (Data, Eq, Functor, Generic, Ord, Show)++type DebugRecord = DebugRecord' BlockLabel++data DbgRecValue' lab = DbgRecValue+ {+ drvLocation :: ValMd' lab -- ^ Expected to be a DILocation+ , drvLocalVariable :: ValMd' lab -- ^ Expected to be a DILocalVariable+ , drvExpression :: ValMd' lab -- ^ Expected to be a DIExpression+ , drvValAsMetadata :: ValMd' lab+ }+ deriving (Data, Eq, Functor, Generic, Ord, Show)++type DbgRecValue = DbgRecValue' BlockLabel++data DbgRecValueSimple' lab = DbgRecValueSimple+ {+ drvsLocation :: ValMd' lab -- ^ Expected to be a DILocation+ , drvsLocalVariable :: ValMd' lab -- ^ Expected to be a DILocalVariable+ , drvsExpression :: ValMd' lab -- ^ Expected to be a DIExpression+ , drvsValue :: Typed (Value' lab)+ }+ deriving (Data, Eq, Functor, Generic, Ord, Show)++type DbgRecValueSimple = DbgRecValueSimple' BlockLabel++data DbgRecDeclare' lab = DbgRecDeclare+ {+ drdLocation :: ValMd' lab -- ^ Expected to be a DILocation+ , drdLocalVariable :: ValMd' lab -- ^ Expected to be a DILocalVariable+ , drdExpression :: ValMd' lab -- ^ Expected to be a DIExpression+ , drdValAsMetadata :: ValMd' lab+ }+ deriving (Data, Eq, Functor, Generic, Ord, Show)++type DbgRecDeclare = DbgRecDeclare' BlockLabel++data DbgRecAssign' lab = DbgRecAssign+ {+ draLocation :: ValMd' lab -- ^ Expected to be a DILocation+ , draLocalVariable :: ValMd' lab -- ^ Expected to be a DILocalVariable+ , draExpression :: ValMd' lab -- ^ Expected to be a DIExpression+ , draValAsMetadata :: ValMd' lab+ , draAssignID :: ValMd' lab -- ^ Expected to be a DIAssignID+ , draExpressionAddr :: ValMd' lab -- ^ Expected to be a DIExpression+ , draValAsMetadataAddr :: ValMd' lab+ }+ deriving (Data, Eq, Functor, Generic, Ord, Show)++type DbgRecAssign = DbgRecAssign' BlockLabel++data DbgRecLabel' lab = DbgRecLabel+ {+ drlLocation :: ValMd' lab -- ^ Expected to be a DILocation+ , drlLabel :: ValMd' lab -- ^ Expected to be a DILabel+ }+ deriving (Data, Eq, Functor, Generic, Ord, Show)++type DbgRecLabel = DbgRecLabel' BlockLabel++ -- Values ---------------------------------------------------------------------- data Value' lab@@ -1303,12 +1556,12 @@ | ValAsm Bool Bool String String | ValMd (ValMd' lab) | ValPoison- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type Value = Value' BlockLabel data FP80Value = FP80_LongDouble Word16 Word64- deriving (Data, Eq, Ord, Generic, Show, Typeable)+ deriving (Data, Eq, Ord, Generic, Show) data ValMd' lab = ValMdString String@@ -1317,7 +1570,7 @@ | ValMdNode [Maybe (ValMd' lab)] | ValMdLoc (DebugLoc' lab) | ValMdDebugInfo (DebugInfo' lab)- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type ValMd = ValMd' BlockLabel @@ -1331,7 +1584,9 @@ , dlScope :: ValMd' lab , dlIA :: Maybe (ValMd' lab) , dlImplicit :: Bool- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ , dlAtomGroup :: Word64 -- ^ Introduced in LLVM 21+ , dlAtomRank :: Word64 -- ^ Introduced in LLVM 21+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DebugLoc = DebugLoc' BlockLabel @@ -1358,36 +1613,66 @@ -- Statements ------------------------------------------------------------------ +-- | Each statement, which can return a value (`Result`) referenced by the+-- `Ident` or else it has no return value (`Effect`). The statement has a single+-- Instruction, followed by any Debug Records or associated metadata.+--+-- See llvm-project/llvm/docs/RemoveDIsDebugInfo.md for discussion on the+-- [DebugRecord] fields. Note that DebugRecords and debug intrinsics may not be+-- mixed in a module; the former is new and preferred over the latter.+--+-- Technically, DebugRecords are attached to Instructions, but since there's a+-- 1:1 correspondence between Stmt and Instr, it is cleaner to attach the+-- DebugRecords to the Stmt to keep the Instrs from getting additional+-- complications.+--+-- Each statement may have both Debug Records (2nd-to-last field) and a list of+-- metadata attributes (last field). As noted above, bitcode file should not mix+-- Debug Records and intrinsics; if Debug Records are used, the metadata+-- attribute list should not contain intrinsics (although it may contain other+-- metadata associated with this statement).+ data Stmt' lab- = Result Ident (Instr' lab) [(String,ValMd' lab)]- | Effect (Instr' lab) [(String,ValMd' lab)]- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ = Result Ident (Instr' lab) [DebugRecord' lab] [(String, ValMd' lab)]+ | Effect (Instr' lab) [DebugRecord' lab] [(String, ValMd' lab)]+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type Stmt = Stmt' BlockLabel -stmtInstr :: Stmt' lab -> Instr' lab-stmtInstr (Result _ i _) = i-stmtInstr (Effect i _) = i+stmtMetadata :: Stmt' lab -> [(String, ValMd' lab)]+stmtMetadata = \case+ Result _ _ _ mds -> mds+ Effect _ _ mds -> mds -stmtMetadata :: Stmt' lab -> [(String,ValMd' lab)]-stmtMetadata stmt = case stmt of- Result _ _ mds -> mds- Effect _ mds -> mds+stmtInstr :: Stmt' lab -> Instr' lab+stmtInstr (Result _ i _ _) = i+stmtInstr (Effect i _ _) = i -extendMetadata :: (String,ValMd' lab) -> Stmt' lab -> Stmt' lab+extendMetadata :: Show lab => (String, ValMd' lab) -> Stmt' lab -> Stmt' lab extendMetadata md stmt = case stmt of- Result r i mds -> Result r i (md:mds)- Effect i mds -> Effect i (md:mds)+ Result r i [] mds -> Result r i [] (md:mds)+ Result _ _ _ _ -> error $ "Adding MD " <> show md <> " after DebugRecord"+ Effect i drs mds -> Effect i drs (md:mds) +addDebugRecord :: DebugRecord' lab -> Stmt' lab -> Stmt' lab+addDebugRecord dr = \case+ Result r i drs mds -> Result r i (snoc dr drs) mds+ Effect i drs mds -> Effect i (snoc dr drs) mds+ where+ snoc e ls = ls <> [e] -- Constant Expressions -------------------------------------------------------- data ConstExpr' lab- = ConstGEP Bool (Maybe Word64) Type (Typed (Value' lab)) [Typed (Value' lab)]+ = ConstGEP [GEPAttr] (Maybe RangeSpec) Type (Typed (Value' lab)) [Typed (Value' lab)] -- ^ Since LLVM 3.7, constant @getelementptr@ expressions include an explicit -- type to use as a basis for calculations. For older versions of LLVM, this -- type can be reconstructed by inspecting the pointee type of the parent -- pointer value.+ --+ -- Since LLVM 19, the bool "inbounds" is now [GEPAttr] and range is via+ -- RangeSpec instead of just Word64. It's recommended that the GEPAttr list+ -- should be normalized (i.e. only one of each entry). | ConstConv ConvOp (Typed (Value' lab)) Type | ConstSelect (Typed (Value' lab)) (Typed (Value' lab)) (Typed (Value' lab)) | ConstBlockAddr (Typed (Value' lab)) lab@@ -1396,14 +1681,67 @@ | ConstArith ArithOp (Typed (Value' lab)) (Value' lab) | ConstUnaryArith UnaryArithOp (Typed (Value' lab)) | ConstBit BitOp (Typed (Value' lab)) (Value' lab)- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type ConstExpr = ConstExpr' BlockLabel +-- | Attributes imposing rules on the GEP; violating any rule results in a poison+-- value. If the base is a vector of pointers, the attributes apply to each+-- computation element-wise. See+-- https://llvm.org/docs/LangRef.html#getelementptr-instruction for more+-- information.+data GEPAttr+ = GEP_Inbounds+ -- ^ Rules:+ -- * Base pointer has an inbounds (but not necessarily live) address of the+ -- allocated object it is based on (i.e. points into that allocation or to+ -- its end. Size for a growable allocated object is the max size, not the+ -- current size.+ -- * Pointer must remain inbounds at all times when adding the offsets+ -- * Implies 'GEP_NUSW'+ | GEP_NUSW+ -- ^ No unsigned signed wrap.+ -- Rules:+ -- * If type of index is larger than ptr index type, truncation preserves+ -- the signed value.+ -- * Multiplication of an index by the type size does not wrap in a+ -- signed sense.+ -- * Offset additions (excluding base address) does not wrap in a+ -- signed sense+ -- * Addition of the current address (as unsigned, truncated to ptr+ -- index type) and each offset (as signed) does not wrap the ptr+ -- index type.+ | GEP_NUW+ -- ^ No unsigned wrap+ -- Rules:+ -- * If type of index is larger than ptr index type, truncation preserves+ -- the unsigned value.+ -- * Multiplication of an index by the type size does not wrap in an+ -- unsigned sense.+ -- * Offset additions (excluding base address) does not wrap in an+ -- unsigned sense+ -- * Addition of the current address (as unsigned, truncated to ptr+ -- index type) and each offset (as unsigned) does not wrap the ptr+ -- index type.+ deriving (Data, Eq, Generic, Ord, Show)++orderedGEPAttrs :: [GEPAttr]+orderedGEPAttrs = [GEP_Inbounds, GEP_NUSW, GEP_NUW] -- bit0, bit1, ...++data RangeSpec+ = RangeIndex Word64+ -- ^ index of valid range as used in pre-LLVM19 for when "inbounds" as a+ -- boolean was True. Deprecated.+ | Range Int Integer Integer+ -- ^ width of arbitrary-precision integer (in bits) and lower and upper+ -- arbitrary-precision integer bounds of that size as [lower, upper).+ deriving (Data, Eq, Generic, Ord, Show)++ -- DWARF Debug Info ------------------------------------------------------------ data DebugInfo' lab- = DebugInfoBasicType DIBasicType+ = DebugInfoBasicType (DIBasicType' lab) | DebugInfoCompileUnit (DICompileUnit' lab) | DebugInfoCompositeType (DICompositeType' lab) | DebugInfoDerivedType (DIDerivedType' lab)@@ -1425,9 +1763,8 @@ | DebugInfoImportedEntity (DIImportedEntity' lab) | DebugInfoLabel (DILabel' lab) | DebugInfoArgList (DIArgList' lab)- | DebugInfoAssignID- -- ^ Introduced in LLVM 17.- deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ | DebugInfoAssignID -- ^ Introduced in LLVM 17.+ deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DebugInfo = DebugInfo' BlockLabel @@ -1437,7 +1774,10 @@ , dilName :: String , dilFile :: Maybe (ValMd' lab) , dilLine :: Word32- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ , dilColumn :: Word32 -- ^ Introduced in LLVM 21.+ , dilIsArtificial :: Bool -- ^ Introduced in LLVM 21.+ , dilCoroSuspendIdx :: Maybe Word32 -- ^ Introduced in LLVM 21.+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DIImportedEntity = DIImportedEntity' BlockLabel data DIImportedEntity' lab = DIImportedEntity@@ -1447,14 +1787,14 @@ , diieFile :: Maybe (ValMd' lab) , diieLine :: Word32 , diieName :: Maybe String- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DITemplateTypeParameter = DITemplateTypeParameter' BlockLabel data DITemplateTypeParameter' lab = DITemplateTypeParameter { dittpName :: Maybe String , dittpType :: Maybe (ValMd' lab) , dittpIsDefault :: Maybe Bool -- since LLVM 11- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DITemplateValueParameter = DITemplateValueParameter' BlockLabel data DITemplateValueParameter' lab = DITemplateValueParameter@@ -1463,7 +1803,7 @@ , ditvpType :: Maybe (ValMd' lab) , ditvpIsDefault :: Maybe Bool -- since LLVM 11 , ditvpValue :: ValMd' lab- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DINameSpace = DINameSpace' BlockLabel data DINameSpace' lab = DINameSpace@@ -1471,7 +1811,7 @@ , dinsScope :: ValMd' lab , dinsFile :: ValMd' lab , dinsLine :: Word32- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) -- TODO: Turn these into sum types -- See https://github.com/llvm-mirror/llvm/blob/release_38/include/llvm/Support/Dwarf.def@@ -1486,15 +1826,27 @@ -- it stabilizes. type DIEmissionKind = Word8 -data DIBasicType = DIBasicType+-- See https://github.com/llvm/llvm-project/commit/eb8901bda11fd55deeecd067fc4c9dcc0fb89984+dwarf_DW_APPLE_ENUM_KIND_invalid :: Word32+dwarf_DW_APPLE_ENUM_KIND_invalid = complement (0 :: Word32) -- ~ LLVM 19++data DIBasicType' lab = DIBasicType { dibtTag :: DwarfTag , dibtName :: String- , dibtSize :: Word64+ , dibtSize :: Maybe (ValMd' lab)+ -- ^ If using LLVM 20 or older, this will always be @Just@ an 'ValMdValue',+ -- where the underlying value is a 64-bit 'ValInteger'. If using LLVM 21 or+ -- later, this can also be a null reference (i.e., 'Nothing'), a variable+ -- (i.e., @Just@ a 'DIGlobalVariable' or 'DILocalVariable'), or an+ -- expression (i.e., @Just@ a 'DIExpression'). , dibtAlign :: Word64 , dibtEncoding :: DwarfAttrEncoding , dibtFlags :: Maybe DIFlags- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ , dibtNumExtraInhabitants :: Word64 -- ^ added in LLVM 20.+ } deriving (Data, Eq, Functor, Generic, Ord, Show) +type DIBasicType = DIBasicType' BlockLabel+ data DICompileUnit' lab = DICompileUnit { dicuLanguage :: DwarfLang , dicuFile :: Maybe (ValMd' lab)@@ -1518,7 +1870,7 @@ , dicuRangesBaseAddress :: Bool , dicuSysRoot :: Maybe String , dicuSDK :: Maybe String- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DICompileUnit = DICompileUnit' BlockLabel @@ -1529,9 +1881,19 @@ , dictLine :: Word32 , dictScope :: Maybe (ValMd' lab) , dictBaseType :: Maybe (ValMd' lab)- , dictSize :: Word64+ , dictSize :: Maybe (ValMd' lab)+ -- ^ If using LLVM 20 or older, this will always be @Just@ an 'ValMdValue',+ -- where the underlying value is a 64-bit 'ValInteger'. If using LLVM 21 or+ -- later, this can also be a null reference (i.e., 'Nothing'), a variable+ -- (i.e., @Just@ a 'DIGlobalVariable' or 'DILocalVariable'), or an+ -- expression (i.e., @Just@ a 'DIExpression'). , dictAlign :: Word64- , dictOffset :: Word64+ , dictOffset :: Maybe (ValMd' lab)+ -- ^ If using LLVM 20 or older, this will always be @Just@ an 'ValMdValue',+ -- where the underlying value is a 64-bit 'ValInteger'. If using LLVM 21 or+ -- later, this can also be a null reference (i.e., 'Nothing'), a variable+ -- (i.e., @Just@ a 'DIGlobalVariable' or 'DILocalVariable'), or an+ -- expression (i.e., @Just@ a 'DIExpression'). , dictFlags :: DIFlags , dictElements :: Maybe (ValMd' lab) , dictRuntimeLang :: DwarfLang@@ -1543,9 +1905,12 @@ , dictAssociated :: Maybe (ValMd' lab) , dictAllocated :: Maybe (ValMd' lab) , dictRank :: Maybe (ValMd' lab)- , dictAnnotations :: Maybe (ValMd' lab)- -- ^ Introduced in LLVM 14.- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ , dictAnnotations :: Maybe (ValMd' lab) -- ^ Introduced in LLVM 14.+ , dictNumExtraInhabitants :: Word64 -- ^ added in LLVM 20.+ , dictSpecification :: Maybe (ValMd' lab) -- ^ added in LLVM 20.+ , dictEnumKind :: Maybe Word32 -- ^ added in LLVM 20.+ , dictBitStride :: Maybe (ValMd' lab) -- ^ added in LLVM 20.+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DICompositeType = DICompositeType' BlockLabel @@ -1556,9 +1921,19 @@ , didtLine :: Word32 , didtScope :: Maybe (ValMd' lab) , didtBaseType :: Maybe (ValMd' lab)- , didtSize :: Word64+ , didtSize :: Maybe (ValMd' lab)+ -- ^ If using LLVM 20 or older, this will always be @Just@ an 'ValMdValue',+ -- where the underlying value is a 64-bit 'ValInteger'. If using LLVM 21 or+ -- later, this can also be a null reference (i.e., 'Nothing'), a variable+ -- (i.e., @Just@ a 'DIGlobalVariable' or 'DILocalVariable'), or an+ -- expression (i.e., @Just@ a 'DIExpression'). , didtAlign :: Word64- , didtOffset :: Word64+ , didtOffset :: Maybe (ValMd' lab)+ -- ^ If using LLVM 20 or older, this will always be @Just@ an 'ValMdValue',+ -- where the underlying value is a 64-bit 'ValInteger'. If using LLVM 21 or+ -- later, this can also be a null reference (i.e., 'Nothing'), a variable+ -- (i.e., @Just@ a 'DIGlobalVariable' or 'DILocalVariable'), or an+ -- expression (i.e., @Just@ a 'DIExpression'). , didtFlags :: DIFlags , didtExtraData :: Maybe (ValMd' lab) , didtDwarfAddressSpace :: Maybe Word32@@ -1568,18 +1943,18 @@ -- space (in LLVM, the sentinel value @0@ is used for this). , didtAnnotations :: Maybe (ValMd' lab) -- ^ Introduced in LLVM 14- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DIDerivedType = DIDerivedType' BlockLabel data DIExpression = DIExpression { dieElements :: [Word64]- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) data DIFile = DIFile { difFilename :: FilePath , difDirectory :: FilePath- } deriving (Data, Eq, Generic, Ord, Show, Typeable)+ } deriving (Data, Eq, Generic, Ord, Show) data DIGlobalVariable' lab = DIGlobalVariable { digvScope :: Maybe (ValMd' lab)@@ -1595,14 +1970,14 @@ , digvAlignment :: Maybe Word32 , digvAnnotations :: Maybe (ValMd' lab) -- ^ Introduced in LLVM 14.- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DIGlobalVariable = DIGlobalVariable' BlockLabel data DIGlobalVariableExpression' lab = DIGlobalVariableExpression { digveVariable :: Maybe (ValMd' lab) , digveExpression :: Maybe (ValMd' lab)- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DIGlobalVariableExpression = DIGlobalVariableExpression' BlockLabel @@ -1611,7 +1986,7 @@ , dilbFile :: Maybe (ValMd' lab) , dilbLine :: Word32 , dilbColumn :: Word16- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DILexicalBlock = DILexicalBlock' BlockLabel @@ -1619,7 +1994,7 @@ { dilbfScope :: ValMd' lab , dilbfFile :: Maybe (ValMd' lab) , dilbfDiscriminator :: Word32- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DILexicalBlockFile = DILexicalBlockFile' BlockLabel @@ -1635,7 +2010,7 @@ -- ^ Introduced in LLVM 4. , dilvAnnotations :: Maybe (ValMd' lab) -- ^ Introduced in LLVM 14.- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DILocalVariable = DILocalVariable' BlockLabel @@ -1662,7 +2037,7 @@ , dispThrownTypes :: Maybe (ValMd' lab) , dispAnnotations :: Maybe (ValMd' lab) -- ^ Introduced in LLVM 14.- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DISubprogram = DISubprogram' BlockLabel @@ -1694,21 +2069,21 @@ , disrLowerBound :: Maybe (ValMd' lab) , disrUpperBound :: Maybe (ValMd' lab) , disrStride :: Maybe (ValMd' lab)- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DISubrange = DISubrange' BlockLabel data DISubroutineType' lab = DISubroutineType { distFlags :: DIFlags , distTypeArray :: Maybe (ValMd' lab)- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DISubroutineType = DISubroutineType' BlockLabel -- | See <https://releases.llvm.org/13.0.0/docs/LangRef.html#diarglist>. newtype DIArgList' lab = DIArgList { dialArgs :: [ValMd' lab]- } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show, Typeable)+ } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show) type DIArgList = DIArgList' BlockLabel @@ -1718,7 +2093,7 @@ = Invalid -- ^ An invalid use of GEP | HasType Type -- ^ A resolved type | Resolve Ident (Type -> IndexResult) -- ^ Continue, after resolving an alias- deriving (Generic, Typeable)+ deriving (Generic) isInvalid :: IndexResult -> Bool isInvalid ir = case ir of
src/Text/LLVM/DebugUtils.hs view
@@ -230,16 +230,28 @@ let bitfield | testBit (didtFlags dt) 19 , Just extraData <- didtExtraData dt , Just bitfieldOffset <- getInteger mdMap extraData- = Just $ BitfieldInfo { biFieldSize = didtSize dt- , biBitfieldOffset = fromInteger bitfieldOffset- }+ = do size <- getSizeOrOffset (didtSize dt)+ Just $ BitfieldInfo { biFieldSize = size+ , biBitfieldOffset = fromInteger bitfieldOffset+ } | otherwise = Nothing+ offset <- getSizeOrOffset (didtOffset dt) Just (StructFieldInfo { sfiName = fieldName- , sfiOffset = didtOffset dt+ , sfiOffset = offset , sfiBitfield = bitfield , sfiInfo = valMdToInfo' mdMap (didtBaseType dt) })+ where+ -- TODO: Currently, this only recognizes bare integer (i.e., 'ValInteger')+ -- sizes and offsets. This is likely good enough for Clang-derived LLVM, but+ -- Ada-derived LLVM may contain more complex metadata values that this+ -- currently doesn't handle.+ getSizeOrOffset :: Maybe ValMd -> Maybe Word64+ getSizeOrOffset (Just (ValMdValue tv))+ | ValInteger i <- typedValue tv+ = Just (fromInteger i)+ getSizeOrOffset _ = Nothing getUnionFields :: MdMap -> DICompositeType -> Maybe [UnionFieldInfo]@@ -365,10 +377,10 @@ where aux :: [Stmt] -> Map Ident Ident -> Map Ident Ident- aux ( Effect (Store src dst _ _) _- : Effect (Call _ _ (ValSymbol (Symbol what)) [var,md,_]) _+ aux ( Effect (Store src dst _ _) _ _+ : Effect (Call _ _ (ValSymbol (Symbol what)) [var,md,_]) _ _ : _) sofar- | what == "llvm.dbg.declare"+ | what == "llvm.dbg.declare" -- pre-LLVM19: intrinsic declaration match , Just dstIdent <- extractIdent dst , Just srcIdent <- extractIdent src , Just varIdent <- extractIdent var@@ -376,9 +388,9 @@ , Just name <- extractLvName md = Map.insert name srcIdent sofar - aux ( Effect (Call _ _ (ValSymbol (Symbol what)) [var,_,md,_]) _+ aux ( Effect (Call _ _ (ValSymbol (Symbol what)) [var,_,md,_]) _ _ : _) sofar- | what == "llvm.dbg.value"+ | what == "llvm.dbg.value" -- pre-LLVM19: intrinsic declaration match , Just key <- extractIdent var , Just name <- extractLvName md = Map.insert name key sofar
src/Text/LLVM/Labels.hs view
@@ -60,7 +60,8 @@ <*> traverse (relabel f) a <*> pure s <*> pure o- relabel f (ICmp op l r) = ICmp op+ relabel f (ICmp samesign op l r)+ = ICmp samesign op <$> traverse (relabel f) l <*> relabel f r relabel f (FCmp op l r) = FCmp op@@ -125,9 +126,16 @@ instance HasLabel Clause' where relabel = $(generateRelabel 'relabel ''Clause') instance HasLabel Value' where relabel = $(generateRelabel 'relabel ''Value') instance HasLabel ValMd' where relabel = $(generateRelabel 'relabel ''ValMd')+instance HasLabel DebugRecord' where relabel = $(generateRelabel 'relabel ''DebugRecord')+instance HasLabel DbgRecAssign' where relabel = $(generateRelabel 'relabel ''DbgRecAssign')+instance HasLabel DbgRecDeclare' where relabel = $(generateRelabel 'relabel ''DbgRecDeclare')+instance HasLabel DbgRecLabel' where relabel = $(generateRelabel 'relabel ''DbgRecLabel')+instance HasLabel DbgRecValueSimple' where relabel = $(generateRelabel 'relabel ''DbgRecValueSimple')+instance HasLabel DbgRecValue' where relabel = $(generateRelabel 'relabel ''DbgRecValue') instance HasLabel DILabel' where relabel = $(generateRelabel 'relabel ''DILabel') instance HasLabel DebugLoc' where relabel = $(generateRelabel 'relabel ''DebugLoc') instance HasLabel DebugInfo' where relabel = $(generateRelabel 'relabel ''DebugInfo')+instance HasLabel DIBasicType' where relabel = $(generateRelabel 'relabel ''DIBasicType') instance HasLabel DIDerivedType' where relabel = $(generateRelabel 'relabel ''DIDerivedType') instance HasLabel DISubroutineType' where relabel = $(generateRelabel 'relabel ''DISubroutineType') instance HasLabel DISubrange' where relabel = $(generateRelabel 'relabel ''DISubrange')
src/Text/LLVM/Lens.hs view
@@ -31,7 +31,7 @@ , ''DebugInfo' , ''DIFile , ''DISubrange'- , ''DIBasicType+ , ''DIBasicType' , ''DIExpression , ''DISubprogram' , ''DISubroutineType'
src/Text/LLVM/PP.hs view
@@ -24,7 +24,7 @@ import Control.Applicative ((<|>)) import Data.Bits ( shiftR, (.&.) ) import Data.Char (isAlphaNum,isAscii,isDigit,isPrint,ord,toUpper)-import Data.List (intersperse)+import Data.List ( intersperse, nub ) import qualified Data.Map as Map import Data.Maybe (catMaybes,fromMaybe,isJust) import GHC.Float (castDoubleToWord64, castFloatToWord32)@@ -73,7 +73,7 @@ -- this is used for defaulting and otherwise reporting the maximum LLVM version -- known to be supported. llvmVlatest :: LLVMVer-llvmVlatest = 17+llvmVlatest = 19 -- | The differences between various versions of the llvm textual AST.@@ -206,32 +206,59 @@ case ls of BigEndian -> char 'E' LittleEndian -> char 'e'- PointerSize 0 sz abi pref -> char 'p' <> char ':' <> ppLayoutBody sz abi pref- PointerSize n sz abi pref -> char 'p' <> int n <> char ':'- <> ppLayoutBody sz abi pref- IntegerSize sz abi pref -> char 'i' <> ppLayoutBody sz abi pref- VectorSize sz abi pref -> char 'v' <> ppLayoutBody sz abi pref- FloatSize sz abi pref -> char 'f' <> ppLayoutBody sz abi pref- StackObjSize sz abi pref -> char 's' <> ppLayoutBody sz abi pref- AggregateSize sz abi pref -> char 'a' <> ppLayoutBody sz abi pref+ PointerSize ps -> char 'p' <> ppPointerSize ps+ IntegerSize sz -> char 'i' <> ppStorage sz+ VectorSize sz -> char 'v' <> ppStorage sz+ FloatSize sz -> char 'f' <> ppStorage sz+ StackObjSize sz -> char 's' <> ppStorage sz+ AggregateSize Nothing a -> char 'a' <> char ':' <> ppAlignment a+ AggregateSize (Just s) a -> char 'a' <> int s <> char ':' <> ppAlignment a NativeIntSize szs -> char 'n' <> hcat (punctuate (char ':') (map int szs)) StackAlign a -> char 'S' <> int a+ ProgramAddrSpace as -> char 'P' <> int as+ GlobalAddrSpace as -> char 'G' <> int as+ AllocaAddrSpace as -> char 'A' <> int as+ FunctionPointerAlign ty abi ->+ char 'F' <> ppFunctionPointerAlignType ty <> int abi Mangling m -> char 'm' <> char ':' <> ppMangling m+ NonIntegralPointerSpaces asl ->+ "ni:" <> hcat (punctuate (char ':') (map int asl)) --- | Pretty-print the common case for data layout specifications.-ppLayoutBody :: Int -> Int -> Fmt (Maybe Int)-ppLayoutBody size abi mb = int size <> char ':' <> int abi <> pref- where- pref = case mb of- Nothing -> empty- Just p -> char ':' <> int p+ppPointerSize :: Fmt PointerSize+ppPointerSize ps =+ if ptrAddrSpace ps == 0+ then char ':' <> ppStorage (ptrStorage ps)+ <> ppOptColonInt (ptrAddrIndexSize ps)+ else int (ptrAddrSpace ps) <> char ':' <> ppStorage (ptrStorage ps)+ <> ppOptColonInt (ptrAddrIndexSize ps) +ppStorage :: Fmt Storage+ppStorage s = int (storageSize s) <> char ':'+ <> ppAlignment (storageAlignment s)++ppAlignment :: Fmt Alignment+ppAlignment a = int (alignABI a) <> ppOptColonInt (alignPreferred a)++ppOptColonInt :: Fmt (Maybe Int)+ppOptColonInt = \case+ Nothing -> empty+ Just i -> char ':' <> int i++ppFunctionPointerAlignType :: Fmt FunctionPointerAlignType+ppFunctionPointerAlignType ty =+ case ty of+ IndependentOfFunctionAlign -> char 'i'+ MultipleOfFunctionAlign -> char 'n'+ ppMangling :: Fmt Mangling ppMangling ElfMangling = char 'e'+ppMangling GoffMangling = char 'l' ppMangling MipsMangling = char 'm' ppMangling MachOMangling = char 'o' ppMangling WindowsCoffMangling = char 'w'+ppMangling WindowsX86CoffMangling = char 'x'+ppMangling XCoffMangling = char 'a' -- Inline Assembly -------------------------------------------------------------@@ -313,8 +340,15 @@ <+> ppGlobalAttrs (isJust $ globalValue g) (globalAttrs g) <+> ppType (globalType g) <+> ppMaybe ppValue (globalValue g) <> ppAlign (globalAlign g)- <> ppAttachedMetadata (Map.toList (globalMetadata g))+ <> ppGlobalMetadata (Map.toList (globalMetadata g)) +ppGlobalMetadata :: Fmt [(String, ValMd' BlockLabel)]+ppGlobalMetadata mds+ | null mds = empty+ | otherwise = comma <+> commas (map step mds)+ where+ step (l,md) = ppMetadata (text l) <+> ppValMd md+ -- | Pretty-print Global Attributes (usually associated with a global variable -- declaration). The first argument to ppGlobalAttrs indicates whether there is a -- value associated with this global declaration: a global declaration with a@@ -443,9 +477,11 @@ ppStmt :: Fmt Stmt ppStmt stmt = case stmt of- Result var i mds -> ppIdent var <+> char '=' <+> ppInstr i- <> ppAttachedMetadata mds- Effect i mds -> ppInstr i <> ppAttachedMetadata mds+ Result var i drs mds -> ppDebugRecords drs (ppIdent var <+> char '='+ <+> ppInstr i+ <> ppAttachedMetadata mds)+ Effect i drs mds -> ppDebugRecords drs (ppInstr i+ <> ppAttachedMetadata mds) ppAttachedMetadata :: Fmt [(String,ValMd)] ppAttachedMetadata mds@@ -523,14 +559,14 @@ ppBitOp Xor = "xor" ppConvOp :: Fmt ConvOp-ppConvOp Trunc = "trunc"-ppConvOp ZExt = "zext"+ppConvOp (Trunc nuw nsw) = "trunc" <+> ppSignBits nuw nsw+ppConvOp (ZExt nneg) = "zext" <+> opt nneg "nneg" ppConvOp SExt = "sext" ppConvOp FpTrunc = "fptrunc" ppConvOp FpExt = "fpext" ppConvOp FpToUi = "fptoui" ppConvOp FpToSi = "fptosi"-ppConvOp UiToFp = "uitofp"+ppConvOp (UiToFp nneg) = "uitofp" <+> opt nneg "nneg" ppConvOp SiToFp = "sitofp" ppConvOp PtrToInt = "ptrtoint" ppConvOp IntToPtr = "inttoptr"@@ -599,7 +635,7 @@ <> comma <+> ppTyped ppValue a <+> ppScope s <+> ppAtomicOrdering o- ICmp op l r -> "icmp" <+> ppICmpOp op+ ICmp samesign op l r -> "icmp" <+> opt samesign "samesign" <+> ppICmpOp op <+> ppTyped ppValue l <> comma <+> ppValue r FCmp op l r -> "fcmp" <+> ppFCmpOp op <+> ppTyped ppValue l <> comma <+> ppValue r@@ -616,7 +652,7 @@ ShuffleVector a b m -> "shufflevector" <+> ppTyped ppValue a <> comma <+> ppTyped ppValue (b <$ a) <> comma <+> ppTyped ppValue m- GEP ib ty ptr ixs -> ppGEP ib ty ptr ixs+ GEP gf ty ptr ixs -> ppGEP gf ty ptr ixs Comment str -> char ';' <+> text str Jump i -> "br" <+> ppTypedLabel i@@ -639,7 +675,10 @@ <> comma <+> ppVectorIndex i IndirectBr d ls -> "indirectbr" <+> ppTyped ppValue d- <> comma <+> commas (map ppTypedLabel ls)+ <> comma+ <+> char '['+ <+> commas (map ppTypedLabel ls)+ <+> char ']' Switch c d ls -> "switch" <+> ppTyped ppValue c <> comma <+> ppTypedLabel d@@ -771,19 +810,20 @@ -> ppType res _ -> ppType ty -ppGEP :: Bool -> Type -> Typed Value -> Fmt [Typed Value]-ppGEP ib ty ptr ixs =- "getelementptr" <+> inbounds+ppGEP :: [GEPAttr] -> Type -> Typed Value -> Fmt [Typed Value]+ppGEP gf ty ptr ixs =+ "getelementptr"+ <+> (if inlineIsBool+ then (if GEP_Inbounds `elem` gf then "inbounds" else empty)+ else ppGepFlags gf) <+> (if isExplicit then explicit else empty) <+> commas (map (ppTyped ppValue) (ptr:ixs)) where isExplicit = llvmVer >= llvmV3_7+ inlineIsBool = llvmVer < 19 explicit = ppType ty <> comma - inbounds | ib = "inbounds"- | otherwise = empty- ppInvoke :: Type -> Value -> [Typed Value] -> BlockLabel -> Fmt BlockLabel ppInvoke ty f args to uw = body where@@ -885,13 +925,20 @@ <> parens (commas [ "line:" <+> integral (dlLine dl) , "column:" <+> integral (dlCol dl) , "scope:" <+> ppValMd' pp (dlScope dl)- ] <> mbIA <> mbImplicit)+ ] <> mbIA <> mbImplicit <>+ when' (llvmVer >= 21) (mbAtomGroup <> mbAtomRank)) where mbIA = case dlIA dl of Just md -> comma <+> "inlinedAt:" <+> ppValMd' pp md Nothing -> empty mbImplicit = if dlImplicit dl then comma <+> "implicit" else empty+ mbAtomGroup = if dlAtomGroup dl > 0+ then comma <+> "atomGroup:" <+> integral (dlAtomGroup dl)+ else empty+ mbAtomRank = if dlAtomRank dl > 0+ then comma <+> "atomRank:" <+> integral (dlAtomRank dl)+ else empty ppDebugLoc :: Fmt DebugLoc ppDebugLoc = ppDebugLoc' ppLabel@@ -934,24 +981,76 @@ ppConstExpr' :: Fmt i -> Fmt (ConstExpr' i) ppConstExpr' pp expr = case expr of- ConstGEP inb _mix ty ptr ixs ->+ ConstGEP optflgs mrng ty ptr ixs -> "getelementptr"- <+> opt inb "inbounds"- <+> parens (commas (ppType ty : map ppTyp' (ptr:ixs)))- ConstConv op tv t -> ppConvOp op <+> parens (ppTyp' tv <+> "to" <+> ppType t)+ <+> ppGepFlags optflgs+ <+> ppRange mrng+ <+> parens (commas (+ let argIndices = 0 : [0..] -- rval, ptr, then ixs indices+ in reverse -- ppTyp's pushes entries to the listg head+ $ foldl (ppTyp's mrng) [ppType ty]+ $ zip argIndices (ptr:ixs)))+ ConstConv op tv t ->+ let droppedIn18 = case op of+ -- https://github.com/llvm/llvm-project commit e4a4122 dropped ZExt and SExt+ ZExt _ -> True+ SExt -> True+ -- https://github.com/llvm/llvm-project commit 17764d2 dropped FpTrunc through SiToFP+ FpTrunc -> True+ FpExt -> True+ FpToUi -> True+ FpToSi -> True+ UiToFp _ -> True+ SiToFp -> True+ _ -> False+ ppConstConv = ppConvOp op <+> parens (ppTyp' tv <+> "to" <+> ppType t)+ in if droppedIn18+ then droppedInLLVM 18 "fptrunc/fpext/fptoui/fptosi/uitofp/sitofp constexprs" ppConstConv+ else ppConstConv ConstSelect c l r ->- "select" <+> parens (commas [ ppTyp' c, ppTyp' l , ppTyp' r])+ droppedInLLVM 17 "select constexpr" -- https://github.com/llvm/llvm-project commit bbfb13a++ $ "select" <+> parens (commas [ ppTyp' c, ppTyp' l , ppTyp' r]) ConstBlockAddr t l -> "blockaddress" <+> parens (ppVal' (typedValue t) <> comma <+> pp l)- ConstFCmp op a b -> "fcmp" <+> ppFCmpOp op <+> ppTupleT a b- ConstICmp op a b -> "icmp" <+> ppICmpOp op <+> ppTupleT a b+ ConstFCmp op a b -> droppedInLLVM 19 "fcmp constexprs"+ $ "fcmp" <+> ppFCmpOp op <+> ppTupleT a b+ ConstICmp op a b -> droppedInLLVM 19 "icmp constexprs"+ $ "icmp" <+> ppICmpOp op <+> ppTupleT a b ConstArith op a b -> ppArithOp op <+> ppTuple a b ConstUnaryArith op a -> ppUnaryArithOp op <+> ppTyp' a- ConstBit op a b -> ppBitOp op <+> ppTuple a b+ ConstBit op@(Shl _ _) a b -> droppedInLLVM 19 "shl constexprs"+ $ ppBitOp op <+> ppTuple a b+ ConstBit Xor a b -> ppBitOp Xor <+> ppTuple a b+ ConstBit op a b -> droppedInLLVM 18 "and/or/lshr/ashr constexprs"+ $ ppBitOp op <+> ppTuple a b where ppTuple a b = parens $ ppTyped ppVal' a <> comma <+> ppVal' b ppTupleT a b = parens $ ppTyped ppVal' a <> comma <+> ppTyp' b ppVal' = ppValue' pp ppTyp' = ppTyped ppVal'+ ppTyp's mrng a (i,t) =+ let inrangeMark = if Just (RangeIndex i) == mrng then "inrange" else empty+ in (inrangeMark <+> ppTyp' t) : a+ ppRange =+ let ppR = \case+ RangeIndex _i -> empty -- handled in ppTyp's+ Range _ l u ->+ "inrange(" <> integral l <> ", " <> integral u <> ")"+ in maybe empty ppR +ppGepFlags :: Fmt [GEPAttr]+ppGepFlags s =+ let fltr = if GEP_Inbounds `elem` s+ then+ -- inbounds implies nusw, but LLVM stipulates that if+ -- inbounds is present, nusw is not also printed.+ filter (/= GEP_NUSW)+ else id+ ppF = \case+ GEP_Inbounds -> "inbounds"+ GEP_NUSW -> "nusw"+ GEP_NUW -> "nuw"+ in foldl (\o f -> o <+> ppF f) empty $ fltr $ nub s+ ppConstExpr :: Fmt ConstExpr ppConstExpr = ppConstExpr' ppLabel @@ -959,7 +1058,7 @@ ppDebugInfo' :: Fmt i -> Fmt (DebugInfo' i) ppDebugInfo' pp di = case di of- DebugInfoBasicType bt -> ppDIBasicType bt+ DebugInfoBasicType bt -> ppDIBasicType' pp bt DebugInfoCompileUnit cu -> ppDICompileUnit' pp cu DebugInfoCompositeType ct -> ppDICompositeType' pp ct DebugInfoDerivedType dt -> ppDIDerivedType' pp dt@@ -981,7 +1080,69 @@ DebugInfoLabel dil -> ppDILabel' pp dil DebugInfoArgList args -> ppDIArgList' pp args DebugInfoAssignID -> "!DIAssignID()"+ -- DebugRecordDeclare drd -> ppDbgRecDeclare' pp drd +-- Prints DebugRecords (introduced in LLVM 19) which replace debug intrinsics and+-- unlike the intrinsics that follow the instruction, the debug records *precede*+-- the Instruction they affect.+ppDebugRecords :: [DebugRecord' BlockLabel] -> Fmt Doc+ppDebugRecords [] = id+ppDebugRecords drs = ((nest 2 $ vcat (ppDebugRecord' ppLabel <$> drs)) $$)++ppDebugRecord' :: Fmt lab -> Fmt (DebugRecord' lab)+ppDebugRecord' pl = \case+ DebugRecordValue drv -> ppDbgRecValue' pl drv+ DebugRecordDeclare drd -> ppDbgRecDeclare' pl drd+ DebugRecordAssign dra -> ppDbgRecAssign' pl dra+ DebugRecordValueSimple dvs -> ppDbgRecValueSimple' pl dvs+ DebugRecordLabel drl -> ppDbgRecLabel' pl drl++ppDbgRecValue' :: Fmt lab -> Fmt (DbgRecValue' lab)+ppDbgRecValue' pl dr =+ "#dbg_value"+ <> parens (commas [ ppValMd' pl $ drvValAsMetadata dr+ , ppValMd' pl $ drvLocalVariable dr+ , ppValMd' pl $ drvExpression dr+ , ppValMd' pl $ drvLocation dr+ ])++ppDbgRecDeclare' :: Fmt lab -> Fmt (DbgRecDeclare' lab)+ppDbgRecDeclare' pl dr =+ "#dbg_declare"+ <> parens (commas [ ppValMd' pl $ drdValAsMetadata dr+ , ppValMd' pl $ drdLocalVariable dr+ , ppValMd' pl $ drdExpression dr+ , ppValMd' pl $ drdLocation dr+ ])++ppDbgRecAssign' :: Fmt lab -> Fmt (DbgRecAssign' lab)+ppDbgRecAssign' pl dr =+ "#dbg_assign"+ <> parens (commas [ ppValMd' pl $ draValAsMetadata dr+ , ppValMd' pl $ draLocalVariable dr+ , ppValMd' pl $ draExpression dr+ , ppValMd' pl $ draAssignID dr+ , ppValMd' pl $ draValAsMetadataAddr dr+ , ppValMd' pl $ draExpressionAddr dr+ , ppValMd' pl $ draLocation dr+ ])++ppDbgRecValueSimple' :: Fmt lab -> Fmt (DbgRecValueSimple' lab)+ppDbgRecValueSimple' pl dr =+ "#dbg_value"+ <> parens (commas [ ppTyped (ppValue' pl) $ drvsValue dr+ , ppValMd' pl $ drvsLocalVariable dr+ , ppValMd' pl $ drvsExpression dr+ , ppValMd' pl $ drvsLocation dr+ ])++ppDbgRecLabel' :: Fmt lab -> Fmt (DbgRecLabel' lab)+ppDbgRecLabel' pl dr =+ "#dbg_label"+ <> parens (commas [ ppValMd' pl $ drlLabel dr+ , ppValMd' pl $ drlLocation dr+ ])+ ppDebugInfo :: Fmt DebugInfo ppDebugInfo = ppDebugInfo' ppLabel @@ -1000,11 +1161,17 @@ ppDILabel' :: Fmt i -> Fmt (DILabel' i) ppDILabel' pp ie = "!DILabel"- <> parens (mcommas [ (("scope:" <+>) . ppValMd' pp) <$> dilScope ie- , pure ("name:" <+> ppStringLiteral (dilName ie))- , (("file:" <+>) . ppValMd' pp) <$> dilFile ie- , pure ("line:" <+> integral (dilLine ie))- ])+ <> parens (mcommas $+ [ (("scope:" <+>) . ppValMd' pp) <$> dilScope ie+ , pure ("name:" <+> ppStringLiteral (dilName ie))+ , (("file:" <+>) . ppValMd' pp) <$> dilFile ie+ , pure ("line:" <+> integral (dilLine ie))+ ] +++ when' (llvmVer >= 21)+ [ pure ("column:" <+> integral (dilColumn ie))+ , pure ("isArtificial:" <+> ppBool (dilIsArtificial ie))+ , (("coroSuspendIdx:" <+>) . integral) <$> dilCoroSuspendIdx ie+ ]) ppDILabel :: Fmt DILabel ppDILabel = ppDILabel' ppLabel@@ -1040,18 +1207,20 @@ ppDITemplateValueParameter :: Fmt DITemplateValueParameter ppDITemplateValueParameter = ppDITemplateValueParameter' ppLabel -ppDIBasicType :: Fmt DIBasicType-ppDIBasicType bt = "!DIBasicType"- <> parens (commas [ "tag:" <+> integral (dibtTag bt)- , "name:" <+> doubleQuotes (text (dibtName bt))- , "size:" <+> integral (dibtSize bt)- , "align:" <+> integral (dibtAlign bt)- , "encoding:" <+> integral (dibtEncoding bt)- ] <> mbFlags)- where- mbFlags = case dibtFlags bt of- Just flags -> comma <+> "flags:" <+> integral flags- Nothing -> empty+ppDIBasicType' :: Fmt i -> Fmt (DIBasicType' i)+ppDIBasicType' pp bt = "!DIBasicType"+ <> parens (mcommas+ [ pure ("tag:" <+> integral (dibtTag bt))+ , pure ("name:" <+> doubleQuotes (text (dibtName bt)))+ , (("size:" <+>) . ppSizeOrOffsetValMd' pp) <$> dibtSize bt+ , pure ("align:" <+> integral (dibtAlign bt))+ , pure ("encoding:" <+> integral (dibtEncoding bt))+ , (("flags:" <+>) . integral)+ <$> dibtFlags bt+ , if dibtNumExtraInhabitants bt > 0+ then pure ("numExtraInhabitants:" <+> integral (dibtNumExtraInhabitants bt))+ else Nothing+ ]) ppDICompileUnit' :: Fmt i -> Fmt (DICompileUnit' i) ppDICompileUnit' pp cu = "!DICompileUnit"@@ -1102,9 +1271,9 @@ , (("file:" <+>) . ppValMd' pp) <$> (dictFile ct) , pure ("line:" <+> integral (dictLine ct)) , (("baseType:" <+>) . ppValMd' pp) <$> (dictBaseType ct)- , pure ("size:" <+> integral (dictSize ct))+ , (("size:" <+>) . ppSizeOrOffsetValMd' pp) <$> dictSize ct , pure ("align:" <+> integral (dictAlign ct))- , pure ("offset:" <+> integral (dictOffset ct))+ , (("offset:" <+>) . ppSizeOrOffsetValMd' pp) <$> dictOffset ct , pure ("flags:" <+> integral (dictFlags ct)) , (("elements:" <+>) . ppValMd' pp) <$> (dictElements ct) , pure ("runtimeLang:" <+> integral (dictRuntimeLang ct))@@ -1117,6 +1286,12 @@ , (("allocated:" <+>) . ppValMd' pp) <$> (dictAllocated ct) , (("rank:" <+>) . ppValMd' pp) <$> (dictRank ct) , (("annotations:" <+>) . ppValMd' pp) <$> (dictAnnotations ct)+ , if dictNumExtraInhabitants ct > 0+ then pure ("numExtraInhabitants:" <+> integral (dictNumExtraInhabitants ct))+ else Nothing+ , (("specification:" <+>) . ppValMd' pp) <$> (dictSpecification ct)+ , (("enumKind:" <+>) . integral) <$> (dictEnumKind ct)+ , (("bitStride:" <+>) . ppValMd' pp) <$> (dictBitStride ct) ]) ppDICompositeType :: Fmt DICompositeType@@ -1131,9 +1306,9 @@ , pure ("line:" <+> integral (didtLine dt)) , (("scope:" <+>) . ppValMd' pp) <$> (didtScope dt) , ("baseType:" <+>) <$> (ppValMd' pp <$> didtBaseType dt <|> Just "null")- , pure ("size:" <+> integral (didtSize dt))+ , (("size:" <+>) . ppSizeOrOffsetValMd' pp) <$> didtSize dt , pure ("align:" <+> integral (didtAlign dt))- , pure ("offset:" <+> integral (didtOffset dt))+ , (("offset:" <+>) . ppSizeOrOffsetValMd' pp) <$> didtOffset dt , pure ("flags:" <+> integral (didtFlags dt)) , (("extraData:" <+>) . ppValMd' pp) <$> (didtExtraData dt) , (("dwarfAddressSpace:" <+>) . integral) <$> didtDwarfAddressSpace dt@@ -1351,7 +1526,18 @@ -- ValMdRef _idx -> mempty -- no table here to look this up... o -> when' canFallBack $ ppValMd' pp o +-- | Print the size or offset of a type-related metadata node. This value can+-- either be an integer literal (in which case the bare literal is printed), or+-- in LLVM 21 or later, it can be a more complicated metadata expression (in+-- which case the metadata is pretty-printed).+ppSizeOrOffsetValMd' :: Fmt i -> Fmt (ValMd' i)+ppSizeOrOffsetValMd' pp = \case+ ValMdValue tv+ | ValInteger i <- typedValue tv+ -> integer i+ o -> when' (llvmVer >= 21) $ ppValMd' pp o + commas :: Fmt [Doc] commas = fsep . punctuate comma @@ -1376,3 +1562,11 @@ | llvmVer >= fromVer = id | otherwise = error $ name ++ " is supported only on LLVM >= " ++ llvmVerToString fromVer++-- | Throw an error if the @?config@ version is older than the given version. The+-- String indicates which constructor is unavailable in the error message.+droppedInLLVM :: (?config :: Config) => LLVMVer -> String -> a -> a+droppedInLLVM fromVer name+ | llvmVer >= fromVer = error $ name ++ " is supported only up to LLVM >= "+ ++ llvmVerToString fromVer+ | otherwise = id
src/Text/LLVM/Triple/AST.hs view
@@ -21,7 +21,6 @@ ) where import Data.Data (Data)-import Data.Typeable (Typeable) import GHC.Generics (Generic) -- | The constructors of this type exactly mirror the LLVM @enum ArchType@,@@ -150,7 +149,7 @@ | RenderScript64 -- | NEC SX-Aurora Vector Engine | VE- deriving (Bounded, Data, Eq, Enum, Generic, Ord, Read, Show, Typeable)+ deriving (Bounded, Data, Eq, Enum, Generic, Ord, Read, Show) -- | A 'First'-like semigroup instance that simply drops the RHS, unless the LHS -- is 'UnknownArch'.@@ -216,7 +215,7 @@ | SPIRVSubArch_v13 | SPIRVSubArch_v14 | SPIRVSubArch_v15- deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)+ deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show) -- | A 'First'-like semigroup instance that simply drops the RHS, unless the LHS -- is 'NoSubArch'.@@ -250,7 +249,7 @@ | Mesa | SUSE | OpenEmbedded- deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)+ deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show) -- | A 'First'-like semigroup instance that simply drops the RHS, unless the LHS -- is 'UnknownVendor'.@@ -323,7 +322,7 @@ | Emscripten -- | DirectX ShaderModel | ShaderModel- deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)+ deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show) -- | A 'First'-like semigroup instance that simply drops the RHS, unless the LHS -- is 'UnknownOS'.@@ -386,7 +385,7 @@ | Callable | Mesh | Amplification- deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)+ deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show) -- | A 'First'-like semigroup instance that simply drops the RHS, unless the LHS -- is 'UnknownEnvironment'.@@ -414,7 +413,7 @@ | SPIRV | Wasm | XCOFF- deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show, Typeable)+ deriving (Bounded, Data, Enum, Eq, Generic, Ord, Read, Show) -- | A 'First'-like semigroup instance that simply drops the RHS, unless the LHS -- is 'UnknownObjectFormat'.@@ -440,7 +439,7 @@ , ttEnv :: Environment , ttObjFmt :: ObjectFormat }- deriving (Bounded, Data, Eq, Generic, Ord, Read, Show, Typeable)+ deriving (Bounded, Data, Eq, Generic, Ord, Read, Show) -- | Combines fields pointwise. instance Semigroup TargetTriple where
+ test/DataLayout.hs view
@@ -0,0 +1,31 @@+module DataLayout ( tests ) where++import Text.LLVM.AST+import Text.LLVM.PP++import Test.Tasty+import Test.Tasty.HUnit++tests :: TestTree+tests =+ let rspDL s = Just $ "target datalayout = \"" <> s <> "\""+ ppDL = show . ppLLVM llvmVlatest ppDataLayout+ in testGroup "Test DataLayout"+ [ testCase "datalayout 0" $ ppDL <$> parseDataLayout "" @?= Just ""+ , testCase "datalayout 1"+ $ let dl = "e" in ppDL <$> parseDataLayout dl @?= rspDL dl+ , testCase "datalayout 2"+ $ let dl = "e-m:e" in ppDL <$> parseDataLayout dl @?= rspDL dl+ , testCase "datalayout 3"+ $ let dl = "e-m:e-p270:32:32"+ in ppDL <$> parseDataLayout dl @?= rspDL dl+ , testCase "datalayout 4"+ $ let dl = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-S128"+ in ppDL <$> parseDataLayout dl @?= rspDL dl+ , testCase "datalayout 5"+ $ let dl = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"+ in ppDL <$> parseDataLayout dl @?= rspDL dl+ , testCase "datalayout 6"+ $ let dl = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-ni:3:4-S128"+ in ppDL <$> parseDataLayout dl @?= rspDL dl+ ]
test/Main.hs view
@@ -2,12 +2,16 @@ import qualified Test.Tasty as Tasty -import qualified Triple+import qualified DataLayout+import qualified Metadata import qualified Output+import qualified Triple main :: IO () main = Tasty.defaultMain $ Tasty.testGroup "LLVM tests" [- Output.tests+ DataLayout.tests+ , Metadata.tests+ , Output.tests , Triple.tests ]
+ test/Metadata.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE TypeApplications #-}++-- | This module provides some testing of the metadata that can be attached to+-- Statements.++module Metadata ( tests ) where++import qualified Test.Tasty as Tasty+import Test.Tasty.HUnit++import Text.LLVM.AST+++tests :: Tasty.TestTree+tests = Tasty.testGroup "LLVM metadata tests" $+ let s1 = Effect (Load PtrOpaque (Typed Opaque ValNull) Nothing Nothing)+ mempty md1+ s2 = Result (Ident "r1")+ (Load PtrOpaque (Typed Opaque ValNull) Nothing Nothing)+ mempty md1+ md1 = [ ("foo", ValMdLoc $ DebugLoc { dlLine = 12+ , dlCol = 34+ , dlScope = ValMdRef 5+ , dlIA = Nothing+ , dlImplicit = True+ , dlAtomGroup = 0+ , dlAtomRank = 0 })+ , ("moo", ValMdString @Value "cow")+ ]+ in+ [+ testCase "stmtMetadata Effect" $ stmtMetadata s1 @?= md1+ , testCase "stmtMetadata Result" $ stmtMetadata s2 @?= md1+ ]
test/Output.hs view
@@ -32,15 +32,23 @@ -- output are seen. s1, s2 :: Stmt s1 = Effect- (GEP True (Alias (Ident "hi")) (Typed Opaque dcu) [])- []+ (GEP [GEP_Inbounds] (Alias (Ident "hi")) (Typed Opaque dcu) [])+ mempty [] s2 = Effect (Load PtrOpaque (Typed Opaque ValNull) Nothing Nothing)+ mempty [ ("location", ValMdLoc $ DebugLoc { dlLine = 12 , dlCol = 34 , dlScope = ValMdRef 5 , dlIA = Nothing- , dlImplicit = True })+ , dlImplicit = True+ , dlAtomGroup = 0+ , dlAtomRank = 0 }) ]+ s3 = Effect+ (IndirectBr+ (Typed PtrOpaque (ValIdent "addr"))+ [Named "hello", Named "world"])+ [] [] dcu :: Value dcu = ValMd $ ValMdDebugInfo@@ -75,10 +83,10 @@ } blk1 = BasicBlock { bbLabel = Just $ Named $ Ident "blk1" , bbStmts =- [ Result (Ident "r1") (Comment "insanity follows...") []- , Effect (Jump $ Named $ Ident "blk1") []- , Result (Ident "oh no") RetVoid []- , Effect (Br (Typed (PrimType Metadata) ValZeroInit) (Anon 3) (Named "oh no")) []+ [ Result (Ident "r1") (Comment "insanity follows...") mempty []+ , Effect (Jump $ Named $ Ident "blk1") mempty []+ , Result (Ident "oh no") RetVoid mempty []+ , Effect (Br (Typed (PrimType Metadata) ValZeroInit) (Anon 3) (Named "oh no")) mempty [] ] } blk2 = BasicBlock { bbLabel = Just $ Anon 123@@ -167,6 +175,51 @@ ---- |] + , testCase "Stmt 1, LLVM 18" $+ assertEqLines (ppToText $ ppLLVM 18 $ ppStmt s1) [sq|+ Significant changes occur in LLVM 19; ensure that the output is as+ expected just prior to those changes to properly capture the+ inflection point.+ ----+ getelementptr inbounds %hi, opaque !DICompileUnit(language: 12,+ producer: "llvm-pretty-test",+ isOptimized: true,+ flags: "some flags",+ runtimeVersion: 3,+ emissionKind: 1,+ enums: !DITemplateTypeParameter(name: ttp),+ dwoId: 2,+ splitDebugInlining: false,+ debugInfoForProfiling: true,+ nameTableKind: 4,+ rangesBaseAddress: true,+ sysroot: "the root",+ sdk: "SDK")+ ----+ |]++ , testCase "Stmt 1, LLVM 19" $+ assertEqLines (ppToText $ ppLLVM 19 $ ppStmt s1) [sq|+ In LLVM 19, the GEP instruction "inbounds" is no longer a boolean+ but a flag with multiple possible values (only one is checked here).+ ----+ getelementptr inbounds %hi, opaque !DICompileUnit(language: 12,+ producer: "llvm-pretty-test",+ isOptimized: true,+ flags: "some flags",+ runtimeVersion: 3,+ emissionKind: 1,+ enums: !DITemplateTypeParameter(name: ttp),+ dwoId: 2,+ splitDebugInlining: false,+ debugInfoForProfiling: true,+ nameTableKind: 4,+ rangesBaseAddress: true,+ sysroot: "the root",+ sdk: "SDK")+ ----+ |]+ ------------------------------------------------------------ , testCase "Stmt 2, LLVM 3.5" $@@ -201,6 +254,18 @@ ---- |] (ppToText $ ppLLVM 10 $ ppStmt s2)++ ------------------------------------------------------------++ , testCase "Stmt 3" $+ assertEqLines [sq|+ `indirectbr` pretty-printing works as expected (#174)+ ----+ indirectbr ptr %addr, [ label %hello,+ label %world ]+ ----+ |]+ (ppToText $ ppLLVM llvmVlatest $ ppStmt s3) ------------------------------------------------------------ -- Verify named labels and label targets are emitted correctly