packages feed

llvm-pretty 0.12.1.0 → 0.14.0.0

raw patch · 13 files changed

Files

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