packages feed

llvm-pretty 0.14.0.0 → 0.15.0.0

raw patch · 13 files changed

+1366/−55 lines, 13 filesdep +filepathdep +microlens-platformdep ~microlensPVP ok

version bump matches the API change (PVP)

Dependencies added: filepath, microlens-platform

Dependency ranges changed: microlens

API changes (from Hackage documentation)

- Text.LLVM.PP: angles :: Fmt Doc
- Text.LLVM.PP: commas :: Fmt [Doc]
- Text.LLVM.PP: integral :: Integral i => Fmt i
- Text.LLVM.PP: mcommas :: Fmt [Maybe Doc]
- Text.LLVM.PP: opt :: Bool -> Fmt Doc
- Text.LLVM.PP: ppDbgRecLabel' :: Fmt lab -> Fmt (DbgRecLabel' lab)
- Text.LLVM.PP: ppOptColonInt :: Fmt (Maybe Int)
- Text.LLVM.PP: structBraces :: Fmt Doc
- Text.LLVM.PP: validIdentifier :: String -> Bool
- Text.LLVM.PP: when' :: Monoid a => Bool -> a -> a
+ Text.LLVM: instance GHC.Base.Monoid Text.LLVM.ModuleBuilder
+ Text.LLVM: instance GHC.Base.Semigroup Text.LLVM.ModuleBuilder
+ Text.LLVM.AST: BFloat :: FloatType
+ Text.LLVM.AST: DIFixedPointType :: DwarfTag -> Maybe String -> Maybe (ValMd' lab) -> Word64 -> DwarfAttrEncoding -> DIFlags -> DIFixedPointKind' lab -> DIFixedPointType' lab
+ Text.LLVM.AST: DISubrangeType :: Maybe String -> Maybe (ValMd' lab) -> Word32 -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Word64 -> DIFlags -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> DISubrangeType' lab
+ Text.LLVM.AST: DebugInfoFixedPointType :: DIFixedPointType' lab -> DebugInfo' lab
+ Text.LLVM.AST: DebugInfoSubrangeType :: DISubrangeType' lab -> DebugInfo' lab
+ Text.LLVM.AST: FP128_LongDouble :: Word64 -> Word64 -> FP128Value
+ Text.LLVM.AST: FP128_PPC_DoubleDouble :: Double -> Double -> FP128_PPCValue
+ Text.LLVM.AST: FPBFloat :: Word16 -> FPBFloatValue
+ Text.LLVM.AST: FPHalf :: Word16 -> FPHalfValue
+ Text.LLVM.AST: FixedPointBinary :: Integer -> DIFixedPointKind' lab
+ Text.LLVM.AST: FixedPointDecimal :: Integer -> DIFixedPointKind' lab
+ Text.LLVM.AST: FixedPointRational :: Integer -> Integer -> DIFixedPointKind' lab
+ Text.LLVM.AST: UnnamedMdIdx :: Int -> UnnamedMdIdx
+ Text.LLVM.AST: ValBFloat :: FPBFloatValue -> Value' lab
+ Text.LLVM.AST: ValFP128 :: FP128Value -> Value' lab
+ Text.LLVM.AST: ValFP128_PPC :: FP128_PPCValue -> Value' lab
+ Text.LLVM.AST: ValHalf :: FPHalfValue -> Value' lab
+ Text.LLVM.AST: [dibtDataSize] :: DIBasicType' lab -> Word32
+ Text.LLVM.AST: [dicuSourceLanguageVersion] :: DICompileUnit' lab -> Word32
+ Text.LLVM.AST: [difptAlign] :: DIFixedPointType' lab -> Word64
+ Text.LLVM.AST: [difptEncoding] :: DIFixedPointType' lab -> DwarfAttrEncoding
+ Text.LLVM.AST: [difptFlags] :: DIFixedPointType' lab -> DIFlags
+ Text.LLVM.AST: [difptKind] :: DIFixedPointType' lab -> DIFixedPointKind' lab
+ Text.LLVM.AST: [difptName] :: DIFixedPointType' lab -> Maybe String
+ Text.LLVM.AST: [difptSize] :: DIFixedPointType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [difptTag] :: DIFixedPointType' lab -> DwarfTag
+ Text.LLVM.AST: [disrtAlign] :: DISubrangeType' lab -> Word64
+ Text.LLVM.AST: [disrtBaseType] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [disrtBias] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [disrtFile] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [disrtFlags] :: DISubrangeType' lab -> DIFlags
+ Text.LLVM.AST: [disrtLine] :: DISubrangeType' lab -> Word32
+ Text.LLVM.AST: [disrtLowerBound] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [disrtName] :: DISubrangeType' lab -> Maybe String
+ Text.LLVM.AST: [disrtScope] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [disrtSize] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [disrtStride] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [disrtUpperBound] :: DISubrangeType' lab -> Maybe (ValMd' lab)
+ Text.LLVM.AST: [unnamedMdIdx] :: UnnamedMdIdx -> Int
+ Text.LLVM.AST: data DIFixedPointKind' lab
+ Text.LLVM.AST: data DIFixedPointType' lab
+ Text.LLVM.AST: data DISubrangeType' lab
+ Text.LLVM.AST: data FP128Value
+ Text.LLVM.AST: data FP128_PPCValue
+ Text.LLVM.AST: data FPBFloatValue
+ Text.LLVM.AST: data FPHalfValue
+ Text.LLVM.AST: instance Data.Data.Data Text.LLVM.AST.FP128Value
+ Text.LLVM.AST: instance Data.Data.Data Text.LLVM.AST.FP128_PPCValue
+ Text.LLVM.AST: instance Data.Data.Data Text.LLVM.AST.FPBFloatValue
+ Text.LLVM.AST: instance Data.Data.Data Text.LLVM.AST.FPHalfValue
+ Text.LLVM.AST: instance Data.Data.Data Text.LLVM.AST.UnnamedMdIdx
+ Text.LLVM.AST: instance Data.Data.Data lab => Data.Data.Data (Text.LLVM.AST.DIFixedPointKind' lab)
+ Text.LLVM.AST: instance Data.Data.Data lab => Data.Data.Data (Text.LLVM.AST.DIFixedPointType' lab)
+ Text.LLVM.AST: instance Data.Data.Data lab => Data.Data.Data (Text.LLVM.AST.DISubrangeType' lab)
+ Text.LLVM.AST: instance GHC.Base.Functor Text.LLVM.AST.DIFixedPointKind'
+ Text.LLVM.AST: instance GHC.Base.Functor Text.LLVM.AST.DIFixedPointType'
+ Text.LLVM.AST: instance GHC.Base.Functor Text.LLVM.AST.DISubrangeType'
+ Text.LLVM.AST: instance GHC.Classes.Eq (Text.LLVM.AST.DIFixedPointKind' lab)
+ Text.LLVM.AST: instance GHC.Classes.Eq Text.LLVM.AST.FP128Value
+ Text.LLVM.AST: instance GHC.Classes.Eq Text.LLVM.AST.FP128_PPCValue
+ Text.LLVM.AST: instance GHC.Classes.Eq Text.LLVM.AST.FPBFloatValue
+ Text.LLVM.AST: instance GHC.Classes.Eq Text.LLVM.AST.FPHalfValue
+ Text.LLVM.AST: instance GHC.Classes.Eq Text.LLVM.AST.UnnamedMdIdx
+ Text.LLVM.AST: instance GHC.Classes.Eq lab => GHC.Classes.Eq (Text.LLVM.AST.DIFixedPointType' lab)
+ Text.LLVM.AST: instance GHC.Classes.Eq lab => GHC.Classes.Eq (Text.LLVM.AST.DISubrangeType' lab)
+ Text.LLVM.AST: instance GHC.Classes.Ord (Text.LLVM.AST.DIFixedPointKind' lab)
+ Text.LLVM.AST: instance GHC.Classes.Ord Text.LLVM.AST.FP128Value
+ Text.LLVM.AST: instance GHC.Classes.Ord Text.LLVM.AST.FP128_PPCValue
+ Text.LLVM.AST: instance GHC.Classes.Ord Text.LLVM.AST.FPBFloatValue
+ Text.LLVM.AST: instance GHC.Classes.Ord Text.LLVM.AST.FPHalfValue
+ Text.LLVM.AST: instance GHC.Classes.Ord Text.LLVM.AST.UnnamedMdIdx
+ Text.LLVM.AST: instance GHC.Classes.Ord lab => GHC.Classes.Ord (Text.LLVM.AST.DIFixedPointType' lab)
+ Text.LLVM.AST: instance GHC.Classes.Ord lab => GHC.Classes.Ord (Text.LLVM.AST.DISubrangeType' lab)
+ Text.LLVM.AST: instance GHC.Enum.Enum Text.LLVM.AST.UnnamedMdIdx
+ Text.LLVM.AST: instance GHC.Generics.Generic (Text.LLVM.AST.DIFixedPointKind' lab)
+ Text.LLVM.AST: instance GHC.Generics.Generic (Text.LLVM.AST.DIFixedPointType' lab)
+ Text.LLVM.AST: instance GHC.Generics.Generic (Text.LLVM.AST.DISubrangeType' lab)
+ Text.LLVM.AST: instance GHC.Generics.Generic Text.LLVM.AST.FP128Value
+ Text.LLVM.AST: instance GHC.Generics.Generic Text.LLVM.AST.FP128_PPCValue
+ Text.LLVM.AST: instance GHC.Generics.Generic Text.LLVM.AST.FPBFloatValue
+ Text.LLVM.AST: instance GHC.Generics.Generic Text.LLVM.AST.FPHalfValue
+ Text.LLVM.AST: instance GHC.Generics.Generic Text.LLVM.AST.UnnamedMdIdx
+ Text.LLVM.AST: instance GHC.Num.Num Text.LLVM.AST.UnnamedMdIdx
+ Text.LLVM.AST: instance GHC.Show.Show (Text.LLVM.AST.DIFixedPointKind' lab)
+ Text.LLVM.AST: instance GHC.Show.Show Text.LLVM.AST.FP128Value
+ Text.LLVM.AST: instance GHC.Show.Show Text.LLVM.AST.FP128_PPCValue
+ Text.LLVM.AST: instance GHC.Show.Show Text.LLVM.AST.FPBFloatValue
+ Text.LLVM.AST: instance GHC.Show.Show Text.LLVM.AST.FPHalfValue
+ Text.LLVM.AST: instance GHC.Show.Show Text.LLVM.AST.UnnamedMdIdx
+ Text.LLVM.AST: instance GHC.Show.Show lab => GHC.Show.Show (Text.LLVM.AST.DIFixedPointType' lab)
+ Text.LLVM.AST: instance GHC.Show.Show lab => GHC.Show.Show (Text.LLVM.AST.DISubrangeType' lab)
+ Text.LLVM.AST: newtype UnnamedMdIdx
+ Text.LLVM.AST: nextUnnamedMdIdx :: UnnamedMdIdx -> UnnamedMdIdx
+ Text.LLVM.AST: nonNullUnnamedMdIdx :: UnnamedMdIdx -> Maybe UnnamedMdIdx
+ Text.LLVM.AST: type DIFixedPointKind = DIFixedPointKind' BlockLabel
+ Text.LLVM.AST: type DIFixedPointType = DIFixedPointType' BlockLabel
+ Text.LLVM.AST: type DISubrangeType = DISubrangeType' BlockLabel
+ Text.LLVM.Combine: llvmModuleCombine :: Module -> Module -> Module
+ Text.LLVM.DebugUtils: ContiguousStmt :: BlockRel
+ Text.LLVM.DebugUtils: FirstBlock :: Bool -> DefineRel
+ Text.LLVM.DebugUtils: FirstBlockStmt :: BlockRel
+ Text.LLVM.DebugUtils: FirstLineStmt :: BlockRel
+ Text.LLVM.DebugUtils: OtherBlock :: DefineRel
+ Text.LLVM.DebugUtils: atBlockStart :: AtFileLines a b => b -> DefineRel -> BasicBlock -> a -> a
+ Text.LLVM.DebugUtils: atDefine :: AtFileLines a b => b -> Define -> a -> a
+ Text.LLVM.DebugUtils: atFileLines :: AtFileLines a b => b -> a -> FilePath -> Integer -> Module -> a
+ Text.LLVM.DebugUtils: atGlobal :: AtFileLines a b => b -> Global -> a -> a
+ Text.LLVM.DebugUtils: atStmt :: AtFileLines a b => b -> DefineRel -> BlockRel -> Stmt -> a -> a
+ Text.LLVM.DebugUtils: class AtFileLines a b
+ Text.LLVM.DebugUtils: data BlockRel
+ Text.LLVM.DebugUtils: data DefineRel
+ Text.LLVM.DebugUtils: instance GHC.Classes.Eq Text.LLVM.DebugUtils.BlockRel
+ Text.LLVM.DebugUtils: instance GHC.Classes.Eq Text.LLVM.DebugUtils.DefineRel
+ Text.LLVM.Labels: instance Text.LLVM.Labels.HasLabel Text.LLVM.AST.DIFixedPointKind'
+ Text.LLVM.Labels: instance Text.LLVM.Labels.HasLabel Text.LLVM.AST.DIFixedPointType'
+ Text.LLVM.Labels: instance Text.LLVM.Labels.HasLabel Text.LLVM.AST.DISubrangeType'
+ Text.LLVM.Lens: dibtDataSizeLens :: forall lab f. Functor f => (Word32 -> f Word32) -> DIBasicType' lab -> f (DIBasicType' lab)
+ Text.LLVM.Lens: dicuSourceLanguageVersionLens :: forall lab f. Functor f => (Word32 -> f Word32) -> DICompileUnit' lab -> f (DICompileUnit' lab)
+ Text.LLVM.Lens: difptAlignLens :: forall lab f. Functor f => (Word64 -> f Word64) -> DIFixedPointType' lab -> f (DIFixedPointType' lab)
+ Text.LLVM.Lens: difptEncodingLens :: forall lab f. Functor f => (DwarfAttrEncoding -> f DwarfAttrEncoding) -> DIFixedPointType' lab -> f (DIFixedPointType' lab)
+ Text.LLVM.Lens: difptFlagsLens :: forall lab f. Functor f => (DIFlags -> f DIFlags) -> DIFixedPointType' lab -> f (DIFixedPointType' lab)
+ Text.LLVM.Lens: difptKindLens :: forall lab f. Functor f => (DIFixedPointKind' lab -> f (DIFixedPointKind' lab)) -> DIFixedPointType' lab -> f (DIFixedPointType' lab)
+ Text.LLVM.Lens: difptNameLens :: forall lab f. Functor f => (Maybe String -> f (Maybe String)) -> DIFixedPointType' lab -> f (DIFixedPointType' lab)
+ Text.LLVM.Lens: difptSizeLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DIFixedPointType' lab -> f (DIFixedPointType' lab)
+ Text.LLVM.Lens: difptTagLens :: forall lab f. Functor f => (DwarfTag -> f DwarfTag) -> DIFixedPointType' lab -> f (DIFixedPointType' lab)
+ Text.LLVM.Lens: disrtAlignLens :: forall lab f. Functor f => (Word64 -> f Word64) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtBaseTypeLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtBiasLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtFileLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtFlagsLens :: forall lab f. Functor f => (DIFlags -> f DIFlags) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtLineLens :: forall lab f. Functor f => (Word32 -> f Word32) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtLowerBoundLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtNameLens :: forall lab f. Functor f => (Maybe String -> f (Maybe String)) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtScopeLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtSizeLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtStrideLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.Lens: disrtUpperBoundLens :: forall lab f. Functor f => (Maybe (ValMd' lab) -> f (Maybe (ValMd' lab))) -> DISubrangeType' lab -> f (DISubrangeType' lab)
+ Text.LLVM.PP: class PrettyLabel lab
+ Text.LLVM.PP: instance Text.LLVM.DebugUtils.AtFileLines Text.LLVM.PP.DocBld Text.LLVM.PP.AddDocAtLine
+ Text.LLVM.PP: instance Text.LLVM.PP.PrettyLabel Text.LLVM.AST.BlockLabel
+ Text.LLVM.PP: ppDIFixedPointType :: Fmt DIFixedPointType
+ Text.LLVM.PP: ppDIFixedPointType' :: Fmt i -> Fmt (DIFixedPointType' i)
+ Text.LLVM.PP: ppDISubrangeType :: Fmt DISubrangeType
+ Text.LLVM.PP: ppDISubrangeType' :: Fmt i -> Fmt (DISubrangeType' i)
+ Text.LLVM.PP: ppDefineSig :: Fmt Define
+ Text.LLVM.PP: ppLabel' :: PrettyLabel lab => Fmt lab
+ Text.LLVM.PP: ppModuleAtLine :: (?config :: Config) => String -> Integer -> Fmt Module
- Text.LLVM.AST: DIBasicType :: DwarfTag -> String -> Maybe (ValMd' lab) -> Word64 -> DwarfAttrEncoding -> Maybe DIFlags -> Word64 -> DIBasicType' lab
+ Text.LLVM.AST: DIBasicType :: DwarfTag -> String -> Maybe (ValMd' lab) -> Word64 -> DwarfAttrEncoding -> Maybe DIFlags -> Word64 -> Word32 -> DIBasicType' lab
- Text.LLVM.AST: DICompileUnit :: DwarfLang -> Maybe (ValMd' lab) -> Maybe String -> Bool -> Maybe String -> Word16 -> Maybe FilePath -> DIEmissionKind -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Word64 -> Bool -> Bool -> Word64 -> Bool -> Maybe String -> Maybe String -> DICompileUnit' lab
+ Text.LLVM.AST: DICompileUnit :: DwarfLang -> Maybe (ValMd' lab) -> Maybe String -> Bool -> Maybe String -> Word16 -> Maybe FilePath -> DIEmissionKind -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Maybe (ValMd' lab) -> Word64 -> Bool -> Bool -> Word64 -> Bool -> Maybe String -> Maybe String -> Word32 -> DICompileUnit' lab
- Text.LLVM.AST: NamedMd :: String -> [Int] -> NamedMd
+ Text.LLVM.AST: NamedMd :: String -> [UnnamedMdIdx] -> NamedMd
- Text.LLVM.AST: UnnamedMd :: !Int -> ValMd -> Bool -> UnnamedMd
+ Text.LLVM.AST: UnnamedMd :: !UnnamedMdIdx -> ValMd -> Bool -> UnnamedMd
- Text.LLVM.AST: ValMdRef :: Int -> ValMd' lab
+ Text.LLVM.AST: ValMdRef :: UnnamedMdIdx -> ValMd' lab
- Text.LLVM.AST: [nmValues] :: NamedMd -> [Int]
+ Text.LLVM.AST: [nmValues] :: NamedMd -> [UnnamedMdIdx]
- Text.LLVM.AST: [umIndex] :: UnnamedMd -> !Int
+ Text.LLVM.AST: [umIndex] :: UnnamedMd -> !UnnamedMdIdx
- Text.LLVM.Lens: nmValuesLens :: Lens' NamedMd [Int]
+ Text.LLVM.Lens: nmValuesLens :: Lens' NamedMd [UnnamedMdIdx]
- Text.LLVM.Lens: umIndexLens :: Lens' UnnamedMd Int
+ Text.LLVM.Lens: umIndexLens :: Lens' UnnamedMd UnnamedMdIdx

Files

CHANGELOG.md view
@@ -1,6 +1,48 @@ # Revision history for llvm-pretty -## 0.14.0.0 -- 2026-01-22+## 0.15.0.0 -- 2026-08-27++* Add `LLVM.Combine` module with `llvmModuleCombine` function.  This is the+  proper way to combine two LLVM `Module` definitions and maintain integrity+  (e.g. roughly equivalent to `llvm-link`).  The `Module` Semigroup instance is+  unsafe and is deprecated (along with the Monoid instance) and scheduled for+  removal.  Note that `llvmModuleCombine` does not do significant error detection+  and it's up to the caller to determine that the modules should be combined.+  See the documentation for `llvmModuleCombine` for more details.++* Support LLVM 22:+  * `DICompileUnit'` now has an additional `dicuSourceLanguageVersion :: Word64`+    field.+  * `DIBasicType'` now has an additional `dibtDataSize :: Word32` field.++* Support LLVM 21:+  * Added support for the `DISubrangeType` metadata.+  * Added support for the `DIFixedPointType` metadata.++* Corrected the printing of non-normal single-precision floating point+  constants.++* Added missing `FloatType` case `BFloat` for 16-bit "Brain" floats.++* Added missing `Value'` cases for floating point types:+  * `ValHalf` containing an `FPHalfValue` (a wrapper around `Word16`)+  * `ValBFloat` containing an `FPBFloatValue` (a wrapper around `Word16`)+  * `ValFP128` containing an `FP128Value` (a wrapper around two `Word64`)+  * `ValFP128_PPC` containing an `FP128_PPCValue`+    (a wrapper around two `Double`s)++* Added the `atFileLines` function to `DebugUtils.hs` which retrieves the+  statements associated with a specific source file and line number for user+  processing.++* Added the `ppModuleAtLine` which can be used to pretty-print only the portion+  of the bitcode that is associated with a specific source file and line number+  (this uses the new `atFileLines` function internally).++* Breaking change: Unnamed metadata indexes are in an `UnnamedMdIdx` newtype+  wrapper now instead of being an undecorated `Int`.++## 0.14.0.0 -- 2026-01-23  * Changes to support LLVM 19 (some of these changes are not backward-compatible):   * Changes to `LayoutSpec` for DataLayout:
README.md view
@@ -7,7 +7,12 @@  ## LLVM language feature support -Currently, `llvm-pretty` supports LLVM versions up through 17. As a result of+<!--+If you update the latest LLVM version mentioned below, make sure to also update+the definition of `llvmVlatest` in `Text.LLVM.PP`.+-->++Currently, `llvm-pretty` supports LLVM versions up through 22. As a result of the broad version coverage, the `llvm-pretty` AST is a superset of all versions of the LLVM AST. This means that the manner in which certain information is presented in the `llvm-pretty` AST (e.g., during pretty printing) will be
llvm-pretty.cabal view
@@ -1,6 +1,7 @@ Cabal-version:       2.2 Name:                llvm-pretty-Version:             0.14.0.0+Version:             0.15.0.0+                     -- TODO: needs to be 0.15 due to UnnamedMdIdx newtype wrapper License:             BSD-3-Clause License-file:        LICENSE Author:              Trevor Elliott@@ -13,7 +14,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==9.12.3, GHC==9.10.1, GHC==9.8.4+tested-with:         GHC==9.12.2, GHC==9.10.1, GHC==9.8.4 extra-doc-files:     CHANGELOG.md, README.md  @@ -38,6 +39,7 @@                        Text.LLVM.Lens                        Text.LLVM.Parser                        Text.LLVM.PP+                       Text.LLVM.Combine                        Text.LLVM.DebugUtils                        Text.LLVM.Triple                        Text.LLVM.Triple.AST@@ -49,11 +51,14 @@    Build-depends:       base             >= 4.11 && < 5,                        containers       >= 0.4,+                       filepath         >= 1.4,                        parsec           >= 3,                        pretty           >= 1.0.1,                        monadLib         >= 3.6.1,                        microlens        >= 0.4,                        microlens-th     >= 0.4,+                       microlens-platform >= 0.4,+                       -- microlens-platform provides the IxValue instance for IntMap                        syb              >= 0.7,                        template-haskell >= 2.7,                        th-abstraction   >= 0.3.1 && <0.8@@ -63,6 +68,7 @@   Type: exitcode-stdio-1.0   Main-is: Main.hs   Other-modules:+    CombineTests     DataLayout     Metadata     Output@@ -74,6 +80,7 @@   Build-depends:     llvm-pretty,     base,+    microlens,     pretty,     tasty,     tasty-hunit,
src/Text/LLVM.hs view
@@ -141,9 +141,41 @@ -- LLVM Monad ------------------------------------------------------------------  newtype LLVM a = LLVM-  { unLLVM :: WriterT Module (StateT Names Id) a+  { unLLVM :: WriterT ModuleBuilder (StateT Names Id) a   } deriving (Functor,Applicative,Monad,MonadFix) ++-- | This is an internal object used to provide the Monoid/Semigroup building+-- context for the WriterT.  There is no Semigroup instance for Module itself,+-- because combining modules is not a trivial operation and it can fail+-- (e.g. duplicate symbols/definitions); see the 'LLVM.Combine' module for a+-- proper link-like combining function.  However, the functionality here is not+-- really combining two modules, but instead is constructing a single module from+-- discrete operations and thus we can use the ModuleBuilder newtype wrapper to+-- allow Monoid/Semigroup functionality under this LLVM monad.++newtype ModuleBuilder = ModuleBuilder { getModule :: Module }++instance Semigroup ModuleBuilder where+  (ModuleBuilder m1) <> (ModuleBuilder m2) = ModuleBuilder $ Module+    { modSourceName = modSourceName m1 `mplus` modSourceName m2+    , modTriple = modTriple m1 <> modTriple m2+    , modDataLayout = modDataLayout m1 <> modDataLayout m2+    , modTypes = modTypes m1 <> modTypes m2+    , modUnnamedMd = modUnnamedMd m1 <> modUnnamedMd m2+    , modNamedMd = modNamedMd m1 <> modNamedMd m2+    , modGlobals = modGlobals m1 <> modGlobals m2+    , modDeclares = modDeclares m1 <> modDeclares m2+    , modDefines = modDefines m1 <> modDefines m2+    , modInlineAsm = modInlineAsm m1 <> modInlineAsm m2+    , modAliases = modAliases m1 <> modAliases m2+    , modComdat = modComdat m1 <> modComdat m2+    }++instance Monoid ModuleBuilder where+  mempty = ModuleBuilder emptyModule++ freshNameLLVM :: String -> LLVM String freshNameLLVM pfx = LLVM $ do   ns <- get@@ -152,24 +184,24 @@   return n  runLLVM :: LLVM a -> (a,Module)-runLLVM  = fst . runId . runStateT Map.empty . runWriterT . unLLVM+runLLVM  = fmap getModule . fst . runId . runStateT Map.empty . runWriterT . unLLVM  emitTypeDecl :: TypeDecl -> LLVM ()-emitTypeDecl td = LLVM (put emptyModule { modTypes = [td] })+emitTypeDecl td = LLVM (put $ ModuleBuilder $ emptyModule { modTypes = [td] })  emitGlobal :: Global -> LLVM (Typed Value) emitGlobal g =-  do LLVM (put emptyModule { modGlobals = [g] })+  do LLVM (put $ ModuleBuilder $ emptyModule { modGlobals = [g] })      return (ptrT (globalType g) -: globalSym g)  emitDefine :: Define -> LLVM (Typed Value) emitDefine d =-  do LLVM (put emptyModule { modDefines = [d] })+  do LLVM (put $ ModuleBuilder $ emptyModule { modDefines = [d] })      return (defFunType d -: defName d)  emitDeclare :: Declare -> LLVM (Typed Value) emitDeclare d =-  do LLVM (put emptyModule { modDeclares = [d] })+  do LLVM (put $ ModuleBuilder $ emptyModule { modDeclares = [d] })      return (decFunType d -: decName d)  alias :: Ident -> Type -> LLVM ()
src/Text/LLVM/AST.hs view
@@ -10,6 +10,8 @@ not yet represented here. -} +{-# LANGUAGE CPP #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveGeneric #-}@@ -25,7 +27,9 @@     -- * Named Metadata   , NamedMd(..)     -- * Unnamed Metadata-  , UnnamedMd(..)+  , UnnamedMd(..), UnnamedMdIdx(UnnamedMdIdx, unnamedMdIdx)+  , nonNullUnnamedMdIdx+  , nextUnnamedMdIdx     -- * Aliases   , GlobalAlias(..)     -- * Data Layout@@ -125,7 +129,11 @@   , FCmpOp(..)     -- * Values   , Value'(..), Value+  , FPHalfValue(..)+  , FPBFloatValue(..)   , FP80Value(..)+  , FP128Value(..)+  , FP128_PPCValue(..)   , ValMd'(..), ValMd   , KindMd   , FnMdAttachments@@ -163,6 +171,8 @@   , DICompileUnit'(..), DICompileUnit   , DICompositeType'(..), DICompositeType   , DIDerivedType'(..), DIDerivedType+  , DIFixedPointType'(..), DIFixedPointType+  , DIFixedPointKind'(..), DIFixedPointKind   , DIExpression(..)   , DIFile(..)   , DIGlobalVariable'(..), DIGlobalVariable@@ -172,6 +182,7 @@   , DILocalVariable'(..), DILocalVariable   , DISubprogram'(..), DISubprogram   , DISubrange'(..), DISubrange+  , DISubrangeType'(..), DISubrangeType   , DISubroutineType'(..), DISubroutineType   , DIArgList'(..), DIArgList   , dwarf_DW_APPLE_ENUM_KIND_invalid@@ -233,7 +244,12 @@   } deriving (Data, Eq, Ord, Generic, Show)  -- | Combines fields pointwise.-instance Sem.Semigroup Module where+instance+#if __GLASGOW_HASKELL__ >= 910+  -- Deprecation of instances was added in GHC 9.10+ {-# DEPRECATED "Unsafe! Scheduled for removal: use llvmModuleCombine instead" #-}+#endif+  Sem.Semigroup Module where   m1 <> m2 = Module     { modSourceName = modSourceName m1 `mplus`   modSourceName m2     , modTriple     = modTriple m1     <> modTriple     m2@@ -249,9 +265,13 @@     , modComdat     = modComdat     m1 <> modComdat     m2     } -instance Monoid Module where+instance+#if __GLASGOW_HASKELL__ >= 910+  -- Deprecation of instances was added in GHC 9.10+  {-# DEPRECATED "Scheduled for removal: use emptyModule instead" #-}+#endif+  Monoid Module where   mempty = emptyModule-  mappend = (<>)  emptyModule :: Module emptyModule  = Module@@ -274,14 +294,43 @@  data NamedMd = NamedMd   { nmName   :: String-  , nmValues :: [Int]+  , nmValues :: [UnnamedMdIdx]   } deriving (Data, Eq, Generic, Ord, Show)   -- Unnamed Metadata ------------------------------------------------------------ +-- | This is the type used to represent an unnamed metadata index.  A newtype+-- wrapper is used to distinguish the specific use of this value as this+-- particular type of index.+--+-- The Ord instance is provided to allow these indices to be used as Map keys.+-- Although Num and Enum instances are provided to enable manipulation, care+-- should be taken that these are all very carefully used only where needed and+-- appropriate.  In general, the `nextUnnamedMdIdx` function is preferred.+newtype UnnamedMdIdx = UnnamedMdIdx { unnamedMdIdx :: Int }+  deriving (Data, Eq, Generic, Ord, Enum, Num, Show)++-- | This is used when constructing an AST and a new unnamed metadata element is+-- to be added.  It should be passed the current maximum known index and will+-- return the new, unused index that should be used.+nextUnnamedMdIdx :: UnnamedMdIdx -> UnnamedMdIdx+nextUnnamedMdIdx (UnnamedMdIdx i) = UnnamedMdIdx $ i + 1++-- | In the bitcode, an "optional" unnamed metadata index is indicated by 0 (not+-- present) or the actual index + 1.  The parsing should treat these optional as+-- a different type than an UnnamedMdIdx, but this is not presently detected at+-- the parsing level, so this function is used to convert a parsed UnnamedMdIdx+-- to the option of the correct index.+--+-- Note that it is NOT valid to call this twice (or not at all in the event you+-- are starting with an optional form).+nonNullUnnamedMdIdx :: UnnamedMdIdx -> Maybe UnnamedMdIdx+nonNullUnnamedMdIdx (UnnamedMdIdx i) =+  if i == 0 then Nothing else Just $ UnnamedMdIdx $ i - 1+ data UnnamedMd = UnnamedMd-  { umIndex    :: !Int+  { umIndex    :: !UnnamedMdIdx   , umValues   :: ValMd   , umDistinct :: Bool   } deriving (Data, Eq, Generic, Ord, Show)@@ -507,6 +556,7 @@  data FloatType   = Half+  | BFloat -- ^ Introduced in LLVM 11   | Float   | Double   | Fp128@@ -713,10 +763,13 @@ primTypeNull _              = ValZeroInit  floatTypeNull :: FloatType -> Value' lab+floatTypeNull Half     = ValHalf $ FPHalf 0+floatTypeNull BFloat   = ValBFloat $ FPBFloat 0 floatTypeNull Float    = ValFloat 0-floatTypeNull Double   = ValDouble 0 -- XXX not sure about this+floatTypeNull Double   = ValDouble 0+floatTypeNull Fp128    = ValFP128 $ FP128_LongDouble 0 0 floatTypeNull X86_fp80 = ValFP80 $ FP80_LongDouble 0 0-floatTypeNull _        = error "must be a float type"+floatTypeNull PPC_fp128 = ValFP128_PPC $ FP128_PPC_DoubleDouble 0 0  typeNull :: Type -> NullResult lab typeNull (PrimType pt) = HasNull (primTypeNull pt)@@ -910,22 +963,47 @@  -- Attributes ------------------------------------------------------------------ --- | Symbol Linkage+-- | Symbol 'Linkage' provides information on how the symbol should be handled+-- during linking operations.  See https://llvm.org/docs/LangRef.html for more+-- details on the meanings of these flags. data Linkage   = Private+    -- ^ Only accessible by objects in the current module.  May be renamed during+    -- linking to avoid collisions. Not visible in the object file's symbol table.   | LinkerPrivate   | LinkerPrivateWeak   | LinkerPrivateWeakDefAuto   | Internal+    -- ^ Similar to private but shows up as a local symbol (e.g. C @static@)   | AvailableExternally+    -- ^ External declaration, never defined in the object file. Allows inlining+    -- and other optimizations knowing the symbol exists externally.  May be+    -- discarded at will.  Only allowed on 'Declare', not on 'Define'.   | Linkonce+    -- ^ Merged with globals of the same name during linkage.  Useful for common+    -- inlines, templates, or generated code from translation units that may be+    -- overridden with a more definitive definition later.  May be discarded if+    -- unreferenced.   | Weak+    -- ^ Same as Linkonce but may not be discarded (e.g. C @weak@).   | Common+    -- ^ Similar to "weak", but must have a zero initializer and may not be+    -- marked "constant". Not valid for functions and aliases.   | Appending+    -- ^ Only valid for global variables of "pointer to array" type.  Similar to+    -- section concatenation during linking.  No correspondence to an object file+    -- feature.   | ExternWeak+    -- ^ Semantics follows ELF: object is weak until linked.  If not linked, it+    -- becomes null instead of being undefined.   | LinkonceODR+    -- ^ Like Linkonce, with C++ "one definition rule", meaning it can be inlined and+    -- constants can be folded.   | WeakODR+    -- ^ Like Weak, with C++ "one definition rule", meaning it can be inlined and+    -- constants can be folded.   | External+    -- ^ If none of the others applies, this is externally visible.   | DLLImport   | DLLExport     deriving (Data, Eq, Enum, Generic, Ord, Show)@@ -1538,9 +1616,13 @@ data Value' lab   = ValInteger Integer   | ValBool Bool+  | ValHalf FPHalfValue+  | ValBFloat FPBFloatValue   | ValFloat Float   | ValDouble Double   | ValFP80 FP80Value+  | ValFP128 FP128Value+  | ValFP128_PPC FP128_PPCValue   | ValIdent Ident   | ValSymbol Symbol   | ValNull@@ -1560,13 +1642,36 @@  type Value = Value' BlockLabel +-- | 16-bit half-precision floating point value (IEEE half)+data FPHalfValue = FPHalf Word16+    deriving (Data, Eq, Ord, Generic, Show)++-- | Different 16-bit half-precision floating point value+--   ("Brain" or "bfloat16")+data FPBFloatValue = FPBFloat Word16+    deriving (Data, Eq, Ord, Generic, Show)++-- | x86 80-bit long double floating point value+--   (note that there's also an m86k 80-bit float that's almost but+--   not quite the same) data FP80Value = FP80_LongDouble Word16 Word64-               deriving (Data, Eq, Ord, Generic, Show)+    deriving (Data, Eq, Ord, Generic, Show) +-- | IEEE quad-precision long-double floating point value+data FP128Value = FP128_LongDouble Word64 Word64+    deriving (Data, Eq, Ord, Generic, Show)++-- | PowerPC pair-of-doubles floating point value+--   (The value represented is the sum of the two doubles, which+--   normally but not necessarily have exponents chosen so this makes+--   sense.)+data FP128_PPCValue = FP128_PPC_DoubleDouble Double Double+    deriving (Data, Eq, Ord, Generic, Show)+ data ValMd' lab   = ValMdString String   | ValMdValue (Typed (Value' lab))-  | ValMdRef Int+  | ValMdRef UnnamedMdIdx   | ValMdNode [Maybe (ValMd' lab)]   | ValMdLoc (DebugLoc' lab)   | ValMdDebugInfo (DebugInfo' lab)@@ -1593,9 +1698,13 @@ isConst :: Value' lab -> Bool isConst ValInteger{}   = True isConst ValBool{}      = True+isConst ValBFloat{}    = True+isConst ValHalf{}      = True isConst ValFloat{}     = True isConst ValDouble{}    = True isConst ValFP80{}      = True+isConst ValFP128{}     = True+isConst ValFP128_PPC{} = True isConst ValConstExpr{} = True isConst ValZeroInit    = True isConst ValNull        = True@@ -1764,6 +1873,8 @@   | DebugInfoLabel (DILabel' lab)   | DebugInfoArgList (DIArgList' lab)   | DebugInfoAssignID -- ^ Introduced in LLVM 17.+  | DebugInfoSubrangeType (DISubrangeType' lab)+  | DebugInfoFixedPointType (DIFixedPointType' lab)     deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show)  type DebugInfo = DebugInfo' BlockLabel@@ -1843,10 +1954,28 @@   , dibtEncoding :: DwarfAttrEncoding   , dibtFlags    :: Maybe DIFlags   , dibtNumExtraInhabitants :: Word64 -- ^ added in LLVM 20.+  , dibtDataSize :: Word32 -- ^ added in LLVM 22.   } deriving (Data, Eq, Functor, Generic, Ord, Show)  type DIBasicType = DIBasicType' BlockLabel +data DISubrangeType' lab = DISubrangeType -- Added in LLVM 21+  { disrtName       :: Maybe String+  , disrtFile       :: Maybe (ValMd' lab)+  , disrtLine       :: Word32+  , disrtScope      :: Maybe (ValMd' lab)+  , disrtBaseType   :: Maybe (ValMd' lab) -- ^ a type+  , disrtSize       :: Maybe (ValMd' lab) -- ^ in bits. signed constant, DIVariable, DIGlobalVariable, or DIExpression+  , disrtAlign      :: Word64 -- ^ in bits+  , disrtFlags      :: DIFlags+  , disrtLowerBound :: Maybe (ValMd' lab) -- ^ signed constant, DIVariable, DIGlobalVariable, or DIExpression+  , disrtUpperBound :: Maybe (ValMd' lab) -- ^ signed constant, DIVariable, DIGlobalVariable, or DIExpression+  , disrtStride     :: Maybe (ValMd' lab) -- ^ signed constant, DIVariable, DIGlobalVariable, or DIExpression+  , disrtBias       :: Maybe (ValMd' lab) -- ^ signed constant, DIVariable, DIGlobalVariable, or DIExpression+  } deriving (Data, Eq, Functor, Generic, Ord, Show)++type DISubrangeType = DISubrangeType' BlockLabel+ data DICompileUnit' lab = DICompileUnit   { dicuLanguage           :: DwarfLang   , dicuFile               :: Maybe (ValMd' lab)@@ -1870,6 +1999,8 @@   , dicuRangesBaseAddress  :: Bool   , dicuSysRoot            :: Maybe String   , dicuSDK                :: Maybe String+  , dicuSourceLanguageVersion :: Word32+    -- ^ added in LLVM 22   } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show)  type DICompileUnit = DICompileUnit' BlockLabel@@ -1946,6 +2077,36 @@   } deriving (Data, Eq, Functor, Generic, Generic1, Ord, Show)  type DIDerivedType = DIDerivedType' BlockLabel++-- | The DIFixedPointType represents fixed-point types as an integer with a scale+-- factor.  It's a derivation of the DIBaseType, although only two encodings are+-- permitted: DW_ATE_signed_fixed and DW_ATE_unsigned_fixed.+data DIFixedPointType' lab = DIFixedPointType -- Added in LLVM 21+  { difptTag      :: DwarfTag+  , difptName     :: Maybe String+  , difptSize     :: Maybe (ValMd' lab) -- ^ in bits. signed constant, DIVariable, DIGlobalVariable, or DIExpression+  , difptAlign    :: Word64 -- ^ in bits+  , difptEncoding :: DwarfAttrEncoding -- ^ only DW_ATE_signed_fixed or DW_ATE_unsigned_fixed+  , difptFlags    :: DIFlags+  -- n.b. in the bitcode representation, kind, factor, numerator, and denominator+  -- are all present, and kind controls which are actually used.+  , difptKind     :: DIFixedPointKind' lab+  } deriving (Data, Eq, Functor, Generic, Ord, Show)++data DIFixedPointKind' lab = FixedPointBinary Integer+                             -- ^ A binary fixed point type where the (signed)+                             -- scale factor is a power of 2.+                           | FixedPointDecimal Integer+                             -- ^ A decimal fixed point type where the (signed)+                             -- scale factor is a power of 10.+                           | FixedPointRational Integer Integer+                             -- ^ The scale factor is an arbitrary rational+                             -- number, specified by these numerator and+                             -- denominator values.+  deriving (Data, Eq, Functor, Generic, Ord, Show)++type DIFixedPointType = DIFixedPointType' BlockLabel+type DIFixedPointKind = DIFixedPointKind' BlockLabel  data DIExpression = DIExpression   { dieElements :: [Word64]
+ src/Text/LLVM/Combine.hs view
@@ -0,0 +1,217 @@+{-# LANGUAGE LambdaCase #-}++{- |+Module      : Text.LLVM.Combine+Description : Combine LLVM Modules+License     : BSD3+Maintainer  : Kevin Quick <kquick@galois.com>+Stability   : provisional++This module provides the ability to smash together LLVM 'Module' specifications+to provide the ability to load separate LLVM 'Module's (e.g. bitcode files) and+analyze them as if they had been linked together as a single program.++-}++module Text.LLVM.Combine+  (+    llvmModuleCombine+  )+where++import Data.Bool ( bool )+import Data.Generics.Schemes ( everywhere )+import Data.Generics.Aliases ( mkT )+import Lens.Micro+import Lens.Micro.Extras+import Data.Function ( on )+import Data.List ( find )+import Data.Maybe ( fromMaybe )+import Data.String ( fromString )+import Text.LLVM.AST+import Text.LLVM.Lens+++-- | Combines LLVM 'Module's into a single, composite 'Module'.  This is akin to+-- linking, but just from the perspective of what is needed for program analysis.+--+-- This differs from `llvm-link` in the following known ways:+--+-- 1. The `llvm-link` tool uses structural typing resolution: if two modules+--    each have a type with the same structure, the resulting module will only+--    have one type; the name from one of the modules is chosen and all+--    references to the typename in the other module will be rewritten to the+--    first module.+--+--    The `llvmModuleCombine` function takes a slightly different approach: types+--    are not structurally coalesced, but this means that type names are+--    deconflicted by adding a numbered suffix.  This still requires modifying+--    the type name throughout that module, but (a) there are probably fewer type+--    name conflicts than structural equivalences, and (b) the original name is+--    still part of the new name which maintains origin information.+--+-- 2. The `llvm-link` tool will occasionally rewrite calls to llvm intrinsics to+--    explicitly add the default personality specification.  For example,+--    `llvm.stacksave` may be rewritten to `llvm.stacksave.p0`.  Because these+--    are intrinsics, this should not have any significant impact on the result,+--    but `llvmModuleCombine` does not perform this naming update.+--+-- 3. External declaration resolution is type independent and only name+--    sensitive.  If 'Module' A has an external declaration `declare @f(i32 x)`+--    and 'Module' B has a definition `define @f(float x)`, then this+--    `llvmModuleCombine` operation will use the latter to satisfy the former (by+--    removing the former) even though the types do not match.+--+llvmModuleCombine :: Module -> Module -> Module+llvmModuleCombine a addModule =+  let defs = a ^. modDefinesLens+      decls = a ^. modDeclaresLens+      newDefs = b ^. modDefinesLens+      newDecls = b ^. modDeclaresLens+      rmvDefined = flip (foldr removeDefined)+      newDeclsLessOldDefs = rmvDefined defs newDecls+      oldDeclsLessNewDefs = rmvDefined newDefs decls+      joinedName n = Just $ fromMaybe "..." n <> "+" <> fromMaybe "..." (modSourceName b)+      newUmdBase = let umIdxs = umIndex <$> modUnnamedMd a+                   in bool (succ $ maximum umIdxs) (UnnamedMdIdx 0) $ null umIdxs+      -- unnamed metadata is referenced almost everywhere, so update that globally+      -- first:+      b = updateUmd newUmdBase (deConflictTypes addModule (a ^. modTypesLens))+  in a+     & modSourceNameLens %~ joinedName+     & modDeclaresLens .~ (oldDeclsLessNewDefs <> newDeclsLessOldDefs)+     & modDefinesLens %~ deConflict (b ^. modDefinesLens)+     & modTypesLens <>~ b ^. modTypesLens+     & modUnnamedMdLens <>~ b ^. modUnnamedMdLens+     & modNamedMdLens <>~ b ^. modNamedMdLens+     & modComdatLens <>~ b ^. modComdatLens+     & modGlobalsLens <>~ b ^. modGlobalsLens+     & modInlineAsmLens <>~ b ^. modInlineAsmLens+     & modAliasesLens <>~ b ^. modAliasesLens+  -- TODO Globals any should override Linkage external for the same name+  -- TODO verify modTriple and modDataLayout are the same?+++-- | Rewrites type references in the input module to ensure uniqueness against+-- all types mentioned in the second module.+deConflictTypes :: Module -> [TypeDecl] -> Module+deConflictTypes inpMod existingTypes =+  let resolveTypeConflict m t =+        if any (((==) `on` typeName) t) existingTypes+        then renameType m t (let Ident n = typeName t in n <> "___") (0 :: Int)+        else m+      renameType m t b n =+        let newName = Ident (b <> show n)+        in if any ((newName ==) . typeName) existingTypes+           then if n > 100000+                then error $ "Unable to generate unique type name for " <> b+                else renameType m t b $ succ n+           else everywhere (mkT (chngType (typeName t) newName)) m+      chngType oldName newName n = bool n newName $ n == oldName+  in foldl resolveTypeConflict inpMod (inpMod ^. modTypesLens)+++-- | A 'Define' takes precedence over a 'Declare'.  When combining modules,+-- module A may 'Declare' a function that is handled by a 'Define' in module B,+-- so get rid of the 'Declare' when putting A and B together.++removeDefined :: Define -> [Declare] -> [Declare]+removeDefined def = filter ((def ^. defNameLens /=) . view decNameLens)+++-- | 'Module' A and 'Module' B may have a Define with the same name ('Symbol').+-- This is normal when linking multiple modules together, and is resolved by+-- linkers as guided by the 'Linkage' information for the two 'Definition's,+-- usually by either renaming or merging.++deConflict :: [Define] -> [Define] -> [Define]+deConflict new curr = uncurry (<>) $ foldl deConflictDef (curr, new) new+  where+    deConflictDef (ads, bds) bd =+      case find (((==) `on` defName) bd) ads of+        Nothing -> (ads, bds)+        Just ad -> handle ads bds ad bd+    handle ads bds ad bd =+      case bd ^. defLinkageLens of+        Just Private -> (ads, renameDef bd (view defNameLens <$> ads) bds)+        Just LinkerPrivate -> (ads, renameDef bd (view defNameLens <$> ads) bds)+        Just LinkerPrivateWeak ->+          (ads, renameDef bd (view defNameLens <$> ads) bds) -- ??+        Just LinkerPrivateWeakDefAuto ->+          (ads, renameDef bd (view defNameLens <$> ads) bds) -- ??+        Just Internal -> (ads, renameDef bd (view defNameLens <$> ads) bds)+        Just AvailableExternally ->+          -- Never happen: not allowed on defines.  Ignore+          (ads, bds)+        Just Linkonce -> (mergeDef ad bd ads, removeDef bd bds)+        Just Weak -> (mergeDef ad bd ads, removeDef bd bds)+        Just Common -> (mergeDef ad bd ads, removeDef bd bds)+        Just ExternWeak -> (mergeDef ad bd ads, removeDef bd bds)+        Just LinkonceODR -> (mergeDef ad bd ads, removeDef bd bds)+        Just WeakODR -> (mergeDef ad bd ads, removeDef bd bds)+        Just Appending -> (appendDef ad bd ads, removeDef bd bds)+        Just External ->+          -- This should never happen: it is truly a symbol conflict.  A+          -- linker would reject this, but here we will just preserve the+          -- original.+          (ads, removeDef bd bds)+        Just DLLImport -> (ads, removeDef bd bds) -- ??+        Just DLLExport -> (ads, removeDef bd bds) -- ??+        Nothing ->+          -- No linkage specified.  The default is 'External', with associated+          -- considerations as documented for that case above.+          (ads, removeDef bd bds)++-- Note: Used for Linkonce, Weak, Common, ExternWeak, LinkonceODR, WeakODR. LLVM+-- docs say "merged", but also indicates that maybe there is a replacement+-- instead?  For now, treat "merged" as appending.+mergeDef :: Define -> Define -> [Define] -> [Define]+mergeDef = appendDef++appendDef :: Define -> Define -> [Define] -> [Define]+appendDef d1 d2 =+  let appenD = d1 & defBodyLens <>~ d2 ^. defBodyLens+  in (appenD :) . filter (((/=) `on` defName) d1)++removeDef :: Define -> [Define] -> [Define]+removeDef d = filter (((/=) `on` defName) d)+++-- Renames the Defined symbol to a new name using a discriminator to avoid a+-- conflict.  Only valid for renaming Private/Internal Defines such that changing+-- any reference to the original Symbol to the new Symbol in the provided set of+-- Defines is sufficient to change all references.  Note therefore this excludes:+-- renaming of global variables, changing a GlobalAlias.++renameDef :: Define -> [Symbol] -> [Define] -> [Define]+renameDef toRename known inDefs =+  -- KWQ TODO: needs to change GlobalAlias aliasName?+  --+  let getNewName nm n =+        -- Note: adds a "discriminator" to the name in a way that is valid for+        -- both C functions and C++ mangled names (see+        -- https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-scope).+        let nn = if n < 10+                 then nm <> "_" <> show n+                 else nm <> "__" <> show n <> "_"+        in case find ((fromString nn ==) . defName) inDefs of+             Just _ -> getNewName nm $ succ n+             Nothing ->+               if fromString nn `elem` known+               then getNewName nm $ succ n+               else nn+      (Symbol oldname) = defName toRename+      newName = Symbol $ getNewName oldname (1 :: Integer)+  in changeSym (defName toRename) newName inDefs+++changeSym :: Symbol -> Symbol -> [Define] -> [Define]+changeSym old new = everywhere (mkT chngSym)+  where+    chngSym s = bool s new $ old == s++-- | Adjusts all unnamed metadata indices in the Module to begin at the specified+-- newBase, which allows this module to be combined without conflict with a+-- module whose metadata indices are all below the newBase.+updateUmd :: UnnamedMdIdx -> Module -> Module+updateUmd newBase = everywhere (mkT (\n -> n + newBase))
src/Text/LLVM/DebugUtils.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# Language TransformListComp, MonadComprehensions #-} {- | Module           : Text.LLVM.DebugUtils@@ -32,11 +34,16 @@   -- * Line numbers of definitions   , debugInfoGlobalLines   , debugInfoDefineLines+  , atFileLines+  , AtFileLines(atDefine, atBlockStart, atStmt, atGlobal)+  , DefineRel(..)+  , BlockRel(..)   ) where  import           Control.Applicative    ((<|>)) import           Control.Monad          ((<=<)) import           Data.Bits              (Bits(..))+import           Data.Bool              (bool) import           Data.IntMap            (IntMap) import qualified Data.IntMap as IntMap import           Data.List              (elemIndex, tails, stripPrefix)@@ -44,6 +51,9 @@ import qualified Data.Map    as Map import           Data.Maybe             (fromMaybe, listToMaybe, maybeToList, mapMaybe) import           Data.Word              (Word16, Word64)+import           Lens.Micro.Platform    ((^.), at, _Just, to)+import           System.FilePath        ( (</>), equalFilePath, normalise+                                        , hasTrailingPathSeparator ) import           Text.LLVM.AST  dbgKind :: String@@ -162,22 +172,50 @@  -- | Compute an 'IntMap' of the unnamed metadata in a module mkMdMap :: Module -> IntMap ValMd-mkMdMap m = IntMap.fromList [ (umIndex md, umValues md) | md <- modUnnamedMd m ]+mkMdMap m = IntMap.fromList [ (unnamedMdIdx $ umIndex md, umValues md)+                            | md <- modUnnamedMd m ]  ------------------------------------------------------------------------  getDebugInfo :: MdMap -> ValMd -> Maybe DebugInfo-getDebugInfo mdMap (ValMdRef i)    = getDebugInfo mdMap =<< IntMap.lookup i mdMap+getDebugInfo mdMap (ValMdRef (UnnamedMdIdx i)) =+  getDebugInfo mdMap =<< IntMap.lookup i mdMap getDebugInfo _ (ValMdDebugInfo di) = Just di getDebugInfo _ _                   = Nothing +getMDFile :: MdMap -> ValMd -> Maybe FilePath+getMDFile mdMap = \case+  ValMdDebugInfo (DebugInfoFile i) -> pure $ difDirectory i </> difFilename i+  --  ^^ found it! ^^ or else vvv keep looking (recursively) vvv+  ValMdLoc l -> getMDFile mdMap $ dlScope l+  ValMdRef i -> mdMap ^. at (unnamedMdIdx i) . _Just . to (getMDFile mdMap)+  ValMdDebugInfo (DebugInfoGlobalVariable gv) ->+    (getMDFile mdMap =<< digvFile gv) <|> (getMDFile mdMap =<< digvScope gv)+  ValMdDebugInfo (DebugInfoLocalVariable lv) ->+    (getMDFile mdMap =<< dilvFile lv) <|> (getMDFile mdMap =<< dilvScope lv)+  ValMdDebugInfo (DebugInfoSubprogram sp) ->+    (getMDFile mdMap =<< dispFile sp) <|> (getMDFile mdMap =<< dispScope sp)+  ValMdDebugInfo (DebugInfoLexicalBlock lb) ->+    (getMDFile mdMap =<< dilbFile lb) <|> (getMDFile mdMap =<< dilbScope lb)+  ValMdDebugInfo (DebugInfoLexicalBlockFile lf) ->+    (getMDFile mdMap =<< dilbfFile lf) <|> (getMDFile mdMap $ dilbfScope lf)+  ValMdDebugInfo (DebugInfoDerivedType dt) ->+    (getMDFile mdMap =<< didtFile dt) <|> (getMDFile mdMap =<< didtScope dt)+  ValMdDebugInfo (DebugInfoCompositeType ct) ->+    (getMDFile mdMap =<< dictFile ct) <|> (getMDFile mdMap =<< dictScope ct)+  ValMdDebugInfo (DebugInfoCompileUnit cu) -> getMDFile mdMap =<< dicuFile cu+  ValMdDebugInfo (DebugInfoNameSpace ns) -> getMDFile mdMap $ dinsFile ns+  ValMdDebugInfo (DebugInfoLabel bl) ->+    (getMDFile mdMap =<< dilFile bl) <|> (getMDFile mdMap =<< dilScope bl)+  _ -> Nothing+ getInteger :: MdMap -> ValMd -> Maybe Integer-getInteger mdMap (ValMdRef i)                          = getInteger mdMap =<< IntMap.lookup i mdMap+getInteger mdMap (ValMdRef (UnnamedMdIdx i))           = getInteger mdMap =<< IntMap.lookup i mdMap getInteger _     (ValMdValue (Typed _ (ValInteger i))) = Just i getInteger _     _                                     = Nothing  getList :: MdMap -> ValMd -> Maybe [Maybe ValMd]-getList mdMap (ValMdRef i) = getList mdMap =<< IntMap.lookup i mdMap+getList mdMap (ValMdRef (UnnamedMdIdx i)) = getList mdMap =<< IntMap.lookup i mdMap getList _ (ValMdNode di)   = Just di getList _ _                = Nothing @@ -461,7 +499,7 @@     Just (ValMdRef s) -> scopeArgs s     _ -> IntMap.empty   where-    scopeArgs :: Int -> IntMap String+    scopeArgs :: UnnamedMdIdx -> IntMap String     scopeArgs s = IntMap.fromList . mapMaybe go $ modUnnamedMd m       where         go :: UnnamedMd -> Maybe (Int, String)@@ -514,3 +552,96 @@            )          }) = Just (n, (fromIntegral l))     go _ = Nothing+++-- | Given a file and line number and a handler, call the appropriate handler+-- method on every Define, Block, and Stmt that is associated with the line+-- number.+atFileLines :: AtFileLines a b+            => b -> a -> FilePath -> Integer -> Module -> a+atFileLines handle seed file line mdule =+  let mdMap = mkMdMap mdule+      matchesFile x =+        let fn = normalise file+            fl = length fn+            xl = length x+            (p,r) = splitAt (xl - fl) x+        in and [ fl <= xl+               , fn `equalFilePath` r+               , null p || hasTrailingPathSeparator p+               ]+      locMatch di =+        let getMDLine = \case+              ValMdLoc x@(DebugLoc {}) -> dlLine x+              ValMdDebugInfo (DebugInfoSubprogram x) -> dispLine x+              ValMdDebugInfo (DebugInfoLocalVariable x) -> dilvLine x+              ValMdDebugInfo (DebugInfoLexicalBlock x) -> dilbLine x+              ValMdDebugInfo (DebugInfoGlobalVariable x) -> digvLine x+              ValMdDebugInfo (DebugInfoDerivedType x) -> didtLine x+              ValMdDebugInfo (DebugInfoCompositeType x) -> dictLine x+              ValMdDebugInfo (DebugInfoNameSpace x) -> dinsLine x+              ValMdDebugInfo (DebugInfoLabel x) -> dilLine x+              ValMdRef (UnnamedMdIdx i) -> maybe 0 getMDLine $ mdMap ^. at i+              _ -> 0+        in and [ maybe False matchesFile (getMDFile mdMap di)+               , line == (toInteger $ getMDLine di)+               ]+      onGlobal a g =+        bool a (atGlobal handle g a) $ any locMatch $ Map.elems $ globalMetadata g+      onDefs a d =+        let isMatch = any locMatch $ Map.elems $ defMetadata d+            onDecl = bool id (atDefine handle d) isMatch+        in snd $ foldl onBlock (FirstBlock isMatch, onDecl a) $ defBody d+      onBlock (dr, a) bb =+        let onBlockLabel = case bbStmts bb of+                             [] -> id+                             (s:_) -> bool id (atBlockStart handle dr bb)+                                      $ any (locMatch . snd) $ stmtMetadata s+            sseed = (dr, FirstBlockStmt, onBlockLabel a)+            (_, _, blkstmts) = foldl onStmt sseed $ bbStmts bb+        in (OtherBlock, blkstmts)+      onStmt (dr, br, a) s =+        bool+        (dr, FirstLineStmt, a)+        (dr, ContiguousStmt, atStmt handle dr br s a)+        $ or [ any (locMatch . snd) $ stmtMetadata s+             -- n.b. the DebugRecords describe associated data, but do not+             -- (at this time, circa LLVM 22) contain instruction location+             -- references, so they are not considered here.+             , dr == FirstBlock True && null (stmtMetadata s)+             ]+  in foldl onGlobal (foldl onDefs seed $ modDefines mdule) $ modGlobals mdule++-- | The handler passed to 'atFileLines' must be an instance of this class.+--+-- Here, @b@ is an object for which the following methods can be called with an+-- accumulator @a@ and the corresponding LLVM AST element that has the @lab@+-- label type.  The method will return an updated accumulator.+class AtFileLines a b where+  -- | The 'atDefine' method is called (before any enclosed 'BasicBlock' or+  --   'Stmt' elements) if the file and line number are associated with the+  --   'Define' signature line.+  atDefine :: b -> Define -> a -> a+  -- | The 'atBlockStart' method is called if the first 'Stmt' in the+  --   'BasicBlock' is associated with the file and line number, and before any+  --   'Stmt's in the block are passed to 'atStmt'.+  --   the first block in the 'Define'.+  atBlockStart :: b -> DefineRel -> BasicBlock -> a -> a+  -- | The 'atStmt' method is called for every 'Stmt' in the basic block that is+  --   associated with the file and line number.  The boolean value passed is+  --   true if the 'Stmt' immediately follows a previous 'Stmt' that was+  --   associated with the same line, or if this was the first 'Stmt' in the+  --   block.+  atStmt :: b -> DefineRel -> BlockRel -> Stmt -> a -> a+  -- | The 'atGlobal' method is called for evey 'Global' that is associated with+  -- the file and line number.+  atGlobal :: b -> Global -> a -> a++data DefineRel = FirstBlock Bool -- ^ first block of a 'Define', matched file & line?+               | OtherBlock      -- ^ other blocks of a 'Define'+  deriving Eq++data BlockRel = FirstBlockStmt -- ^ first statement in a 'BasicBlock'+              | ContiguousStmt -- ^ previous statement also matched the file & line+              | FirstLineStmt  -- ^ previous statement did not match the file & line+  deriving Eq
src/Text/LLVM/Labels.hs view
@@ -136,6 +136,7 @@ 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 DISubrangeType'             where relabel = $(generateRelabel 'relabel ''DISubrangeType') instance HasLabel DIDerivedType'              where relabel = $(generateRelabel 'relabel ''DIDerivedType') instance HasLabel DISubroutineType'           where relabel = $(generateRelabel 'relabel ''DISubroutineType') instance HasLabel DISubrange'                 where relabel = $(generateRelabel 'relabel ''DISubrange')@@ -144,6 +145,8 @@ instance HasLabel DILocalVariable'            where relabel = $(generateRelabel 'relabel ''DILocalVariable') instance HasLabel DISubprogram'               where relabel = $(generateRelabel 'relabel ''DISubprogram') instance HasLabel DICompositeType'            where relabel = $(generateRelabel 'relabel ''DICompositeType')+instance HasLabel DIFixedPointType'           where relabel = $(generateRelabel 'relabel ''DIFixedPointType')+instance HasLabel DIFixedPointKind'           where relabel = $(generateRelabel 'relabel ''DIFixedPointKind') instance HasLabel DILexicalBlock'             where relabel = $(generateRelabel 'relabel ''DILexicalBlock') instance HasLabel DICompileUnit'              where relabel = $(generateRelabel 'relabel ''DICompileUnit') instance HasLabel DILexicalBlockFile'         where relabel = $(generateRelabel 'relabel ''DILexicalBlockFile')
src/Text/LLVM/Lens.hs view
@@ -32,6 +32,8 @@     , ''DIFile     , ''DISubrange'     , ''DIBasicType'+    , ''DISubrangeType'+    , ''DIFixedPointType'     , ''DIExpression     , ''DISubprogram'     , ''DISubroutineType'
src/Text/LLVM/PP.hs view
@@ -1,8 +1,10 @@ {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE ImplicitParams #-} {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Rank2Types #-}+{-# LANGUAGE TypeApplications #-}  -- | -- Module      :  Text.LLVM.PP@@ -15,22 +17,176 @@ -- -- This is the pretty-printer for llvm assembly versions 3.6 and lower. ---module Text.LLVM.PP where+module Text.LLVM.PP+  (+    Config(Config, cfgVer), withConfig+  , Fmt+  , LLVMVer, llvmVer, llvmVerToString+  , llvmVlatest, llvmV3_5, llvmV3_6, llvmV3_7, llvmV3_8+  , ppLLVM, ppLLVM35, ppLLVM36, ppLLVM37, ppLLVM38+  , LLVMPretty(llvmPP)+  , ppModule+  , ppSourceName+  , ppNamedMd+  , ppUnnamedMd+  , ppGlobalAlias+  , ppTargetTriple+  , ppDataLayout+  , ppLayoutSpec+  , ppPointerSize+  , ppStorage+  , ppAlignment+  , ppFunctionPointerAlignType+  , ppMangling+  , ppInlineAsm+  , ppIdent+  , ppSymbol+  , ppPrimType+  , ppFloatType+  , ppType+  , ppTypeDecl+  , ppGlobal+  , ppGlobalMetadata+  , ppGlobalAttrs+  , ppDeclare+  , ppComdatName+  , ppComdat+  , ppSelectionKind+  , ppDefineSig+  , ppDefine+  , ppFunAttr+  , ppLabelDef+  , ppLabel+  , PrettyLabel(ppLabel')+  , ppBasicBlock+  , ppStmt+  , ppAttachedMetadata+  , ppLinkage+  , ppVisibility+  , ppGC+  , ppTyped+  , ppSignBits+  , ppExact+  , ppArithOp+  , ppUnaryArithOp+  , ppBitOp+  , ppConvOp+  , ppAtomicOrdering+  , ppAtomicOp+  , ppScope+  , ppInstr+  , ppLoad+  , ppStore+  , ppClauses+  , ppClause+  , ppTypedLabel+  , ppSwitchEntry+  , ppVectorIndex+  , ppAlign+  , ppAlloca+  , ppCall+  , ppCallBr+  , ppCallSym+  , ppGEP+  , ppInvoke+  , ppPhiArg+  , ppICmpOp+  , ppFCmpOp+  , ppValue'+  , ppValue+  , ppValMd'+  , ppValMd+  , ppDebugLoc'+  , ppDebugLoc+  , ppTypedValMd+  , ppMetadata+  , ppMetadataNode'+  , ppMetadataNode+  , ppStringLiteral+  , ppAsm+  , ppConstExpr'+  , ppConstExpr+  , ppGepFlags+  , ppDebugInfo'+  , ppDebugRecords+  , ppDebugRecord'+  , ppDbgRecValue'+  , ppDbgRecDeclare'+  , ppDbgRecAssign'+  , ppDbgRecValueSimple'+  , ppDebugInfo+  , ppDIImportedEntity'+  , ppDIImportedEntity+  , ppDILabel'+  , ppDILabel+  , ppDINameSpace'+  , ppDINameSpace+  , ppDITemplateTypeParameter'+  , ppDITemplateTypeParameter+  , ppDITemplateValueParameter'+  , ppDITemplateValueParameter+  , ppDIBasicType'+  , ppDISubrangeType'+  , ppDISubrangeType+  , ppDICompileUnit'+  , ppDICompileUnit+  , ppFlags+  , ppDICompositeType'+  , ppDICompositeType+  , ppDIDerivedType'+  , ppDIDerivedType+  , ppDIEnumerator+  , ppDIFixedPointType'+  , ppDIFixedPointType+  , ppDIExpression+  , ppDIFile+  , ppDIGlobalVariable'+  , ppDIGlobalVariable+  , ppDIGlobalVariableExpression'+  , ppDIGlobalVariableExpression+  , ppDILexicalBlock'+  , ppDILexicalBlock+  , ppDILexicalBlockFile'+  , ppDILexicalBlockFile+  , ppDILocalVariable'+  , ppDILocalVariable+  , ppDISubprogram'+  , ppDISubprogram+  , ppDISubrange'+  , ppDISubrange+  , ppDISubroutineType'+  , ppDISubroutineType+  , ppDIArgList'+  , ppDIArgList+  , ppModuleAtLine+  , ppArgList+  , ppBool+  , ppInt64ValMd'+  , ppSizeOrOffsetValMd'+  , ppMaybe+  , hex+  , onlyOnLLVM+  , droppedInLLVM+  )+where  import Text.LLVM.AST+import Text.LLVM.DebugUtils import Text.LLVM.Triple.AST (TargetTriple) import Text.LLVM.Triple.Print (printTriple)  import Control.Applicative ((<|>))-import Data.Bits ( shiftR, (.&.) )+import Data.Bits ( shiftL, shiftR, (.|.), (.&.) )+import Data.Bool ( bool ) import Data.Char (isAlphaNum,isAscii,isDigit,isPrint,ord,toUpper) import Data.List ( intersperse, nub ) import qualified Data.Map as Map import Data.Maybe (catMaybes,fromMaybe,isJust)-import GHC.Float (castDoubleToWord64, castFloatToWord32)+import GHC.Float (castDoubleToWord64, castWord32ToFloat, float2Double) import Numeric (showHex) import Text.PrettyPrint.HughesPJ import Data.Int+import Data.Word (Word16, Word32) import Prelude hiding ((<>))  @@ -73,8 +229,8 @@ -- this is used for defaulting and otherwise reporting the maximum LLVM version -- known to be supported. llvmVlatest :: LLVMVer-llvmVlatest = 19-+llvmVlatest = 22 -- If you update this, make sure to also update the latest LLVM+                 -- version mentioned in the README.  -- | The differences between various versions of the llvm textual AST. newtype Config = Config { cfgVer :: LLVMVer }@@ -159,11 +315,11 @@ ppNamedMd :: Fmt NamedMd ppNamedMd nm =   sep [ ppMetadata (text (nmName nm)) <+> char '='-      , ppMetadata (braces (commas (map (ppMetadata . int) (nmValues nm)))) ]+      , ppMetadata (braces (commas (map (ppMetadata . int . unnamedMdIdx) (nmValues nm)))) ]  ppUnnamedMd :: Fmt UnnamedMd ppUnnamedMd um =-  sep [ ppMetadata (int (umIndex um)) <+> char '='+  sep [ ppMetadata (int (unnamedMdIdx $ umIndex um)) <+> char '='       , distinct <+> ppValMd (umValues um) ]   where   distinct | umDistinct um = "distinct"@@ -310,6 +466,7 @@  ppFloatType :: Fmt FloatType ppFloatType Half      = "half"+ppFloatType BFloat    = "bfloat" ppFloatType Float     = "float" ppFloatType Double    = "double" ppFloatType Fp128     = "fp128"@@ -404,26 +561,29 @@       ComdatNoDuplicates    -> "noduplicates"       ComdatSameSize        -> "samesize" -ppDefine :: Fmt Define-ppDefine d = "define"-         <+> ppMaybe ppLinkage (defLinkage d)-         <+> ppMaybe ppVisibility (defVisibility d)-         <+> ppType (defRetType d)-         <+> ppSymbol (defName d)-          <> ppArgList (defVarArgs d) (map (ppTyped ppIdent) (defArgs d))-         <+> hsep (ppFunAttr <$> defAttrs d)-         <+> ppMaybe (\s  -> "section" <+> doubleQuotes (text s)) (defSection d)-         <+> ppMaybe (\gc -> "gc" <+> ppGC gc) (defGC d)-         <+> ppMds (defMetadata d)-         <+> char '{'-         $+$ vcat (map ppBasicBlock (defBody d))-         $+$ char '}'+ppDefineSig :: Fmt Define+ppDefineSig d = "define"+                <+> ppMaybe ppLinkage (defLinkage d)+                <+> ppMaybe ppVisibility (defVisibility d)+                <+> ppType (defRetType d)+                <+> ppSymbol (defName d)+                <> ppArgList (defVarArgs d) (map (ppTyped ppIdent) (defArgs d))+                <+> hsep (ppFunAttr <$> defAttrs d)+                <+> ppMaybe (\s  -> "section" <+> doubleQuotes (text s)) (defSection d)+                <+> ppMaybe (\gc -> "gc" <+> ppGC gc) (defGC d)+                <+> ppMds (defMetadata d)   where   ppMds mdm =     case Map.toList mdm of       [] -> empty       mds -> hsep [ "!" <> text k <+> ppValMd md | (k, md) <- mds ] +ppDefine :: Fmt Define+ppDefine d = ppDefineSig d+             <+> char '{'+             $+$ vcat (map ppBasicBlock (defBody d))+             $+$ char '}'+ -- FunAttr ---------------------------------------------------------------------  ppFunAttr :: Fmt FunAttr@@ -473,6 +633,39 @@               $+$ nest 2 (vcat (map ppStmt (bbStmts bb)))  +-- | Many of the pretty printing functions (based on 'Pretty') in this module are+-- written for the monomorphized `BlockLabel` version of the AST objects, but+-- some (those ending with a "tick" or single-quote) support the parameterized form.+--+-- When the parameterized label type is known to be 'BlockLabel', then 'ppLabel'+-- can be passed as this first argument to those pretty printing functions.+--+-- When the parameterized label type is not known (e.g. when implementing other+-- libraries that utilize @llvm-pretty@), the library may need to invoke the+-- pretty printer without passing an explicit label printer, and can instead use+-- the following class as a constraint for an instance that will be resolved+-- later.+--+-- For example:+--+-- > data Something lab = Something { ..., val :: Value' lab, ... }+-- >+-- > instance PrettyLabel lab => Pretty Something where+-- >   pretty s = .... <> ppValue' ppLabel' <>+--+-- Note that the `PrettyLabel` class is very similar to the `Pretty` class, but+-- unlike the latter's `pretty` method, the `PrettyLabel` returns the `Fmt`+-- object that allows the pretty-printing to be affected by the implicit `Config`+-- parameter; this aligns the `PrettyLabel` usage to the other pretty-printing+-- functions in this module.++class PrettyLabel lab where+  ppLabel' :: Fmt lab++instance PrettyLabel BlockLabel where+  ppLabel' = ppLabel++ -- Statements ------------------------------------------------------------------  ppStmt :: Fmt Stmt@@ -865,17 +1058,89 @@ ppFCmpOp Funo   = "uno" ppFCmpOp Ftrue  = "true" +-- | Pad a string by prepending '0'.+zerofill :: Int -> String -> String+zerofill width s =+  let len = length s+      padding = if len < width then width - len else 0+      zeros = take padding $ repeat '0'+  in+  zeros ++ s++-- | Check if a half-float is an infinite or NaN value.+halfBitsIsInfOrNaN :: Word16 -> Bool+halfBitsIsInfOrNaN x =+  -- Half floats have a 1-bit sign, 5-bit exponent, and 10-bit+  -- significand. If the exponent field is all ones, the value+  -- is either +/- Inf (if the significand is 0) or a Nan.+  (x .&. 0x7c00) == 0x7c00++-- | Convert the bit representation of a half-float to a single.+halfToSingleBits :: Word16 -> Word32+halfToSingleBits x =+  -- Half floats have a 1-bit sign, 5-bit exponent, and 10-bit+  -- significand.+  --+  -- 32-bit single floats have a 1-bit sign, 8-bit exponent, and+  -- 23-bit significand. Convert as follows:+  --    - mask off the sign bit, widen, shift into place+  --    - mask off the significand, widen, shift into place+  --      (at the top of the new significand; rest stays 0)+  --    - mask off the exponent+  --    - convert it to int; if that's 0, it stays 0+  --    - otherwise re-offset it, convert to Word32, and shift+  --+  let sign = shiftL (fromIntegral (x .&. 0x8000)) (31 - 15)+      signif = shiftL (fromIntegral (x .&. 0xfff)) (23 - 10)+      expBits = x .&. 0x7c00+      expo = case fromIntegral @Word16 @Int (shiftR expBits 10) of+        0 -> 0+        n -> shiftL (fromIntegral ((n - 15) + 127)) 23+  in+  sign .|. expo .|. signif++-- | Check if a bfloat is an infinite or NaN value.+bfloatBitsIsInfOrNaN :: Word16 -> Bool+bfloatBitsIsInfOrNaN x =+  -- BFloat half floats have a 1-bit sign, 8-bit exponent, and 7-bit+  -- significand. If the exponent field is all ones, the value+  -- is either +/- Inf (if the significand is 0) or a Nan.+  (x .&. 0x7f80) == 0x7f80++-- | Convert the bit representation of a bfloat to a single.+bfloatToSingleBits :: Word16 -> Word32+bfloatToSingleBits x =+  -- Since 32-bit floats are the same layout, just with 16 bits+  -- more precision, all we need to do is widen and shift left.+  shiftL (fromIntegral x) 16+ ppValue' :: Fmt i -> Fmt (Value' i) ppValue' pp val = case val of   ValInteger i       -> integer i   ValBool b          -> ppBool b   -- Note: for +Inf/-Inf/NaNs, we want to output the bit-correct sequence+  ValHalf (FPHalf x) ->+    -- Shown in hex as 0H<<4-hex-digits>>, per+    -- https://llvm.org/docs/LangRef.html#simple-constants+    if halfBitsIsInfOrNaN x+      then text "0xH" <> text (zerofill 4 $ showHex x "")+      else float $ castWord32ToFloat $ halfToSingleBits x+  ValBFloat (FPBFloat x) ->+    -- Shown in hex as 0R<<4-hex-digits>>, per+    -- https://llvm.org/docs/LangRef.html#simple-constants+    if bfloatBitsIsInfOrNaN x+      then text "0xR" <> text (zerofill 4 $ showHex x "")+      else float $ castWord32ToFloat $ bfloatToSingleBits x   ValFloat f         ->     if isInfinite f || isNaN f-      then text "0x" <> text (showHex (castFloatToWord32 f) "")+      -- shown as 0x<<16-hex-digits>>, per+      -- https://llvm.org/docs/LangRef.html#simple-constants+      then text "0x" <> text (showHex (castDoubleToWord64 $ float2Double f) "")       else float f   ValDouble d        ->     if isInfinite d || isNaN d+      -- shown as 0x<<16-hex-digits>>, per+      -- https://llvm.org/docs/LangRef.html#simple-constants       then text "0x" <> text (showHex (castDoubleToWord64 d) "")       else double d   ValFP80 (FP80_LongDouble e s) ->@@ -885,6 +1150,19 @@               | otherwise = showHex n         fld v i = pad ((v `shiftR` (i * 8)) .&. 0xff)     in "0xK" <> text (foldr (fld e) (foldr (fld s) "" $ reverse [0..7::Int]) [1, 0])+  ValFP128 (FP128_LongDouble a b) ->+    -- shown as 0xL<<32-hex-digits>>, per+    -- https://llvm.org/docs/LangRef.html#simple-constants+    let print64 k = zerofill 16 $ showHex k "" in+    "0xL" <> text (print64 a ++ print64 b)+  ValFP128_PPC (FP128_PPC_DoubleDouble a b) ->+    -- shown as 0xM<<32-hex-digits>>, per+    -- https://llvm.org/docs/LangRef.html#simple-constants+    let print64 k = zerofill 16 $ showHex k ""+        a' = print64 (castDoubleToWord64 a)+        b' = print64 (castDoubleToWord64 b)+    in+    "0xM" <> text (a' ++ b')   ValIdent i         -> ppIdent i   ValSymbol s        -> ppSymbol s   ValNull            -> "null"@@ -911,7 +1189,7 @@ ppValMd' pp m = case m of   ValMdString str   -> ppMetadata (ppStringLiteral str)   ValMdValue tv     -> ppTyped (ppValue' pp) tv-  ValMdRef i        -> ppMetadata (int i)+  ValMdRef i        -> ppMetadata (int $ unnamedMdIdx i)   ValMdNode vs      -> ppMetadataNode' pp vs   ValMdLoc l        -> ppDebugLoc' pp l   ValMdDebugInfo di -> ppDebugInfo' pp di@@ -1072,6 +1350,8 @@   DebugInfoLocalVariable lv     -> ppDILocalVariable' pp lv   DebugInfoSubprogram sp        -> ppDISubprogram' pp sp   DebugInfoSubrange sr          -> ppDISubrange' pp sr+  DebugInfoSubrangeType srt     -> ppDISubrangeType' pp srt+  DebugInfoFixedPointType fpt   -> ppDIFixedPointType' pp fpt   DebugInfoSubroutineType st    -> ppDISubroutineType' pp st   DebugInfoNameSpace ns         -> ppDINameSpace' pp ns   DebugInfoTemplateTypeParameter dttp  -> ppDITemplateTypeParameter' pp dttp@@ -1209,7 +1489,7 @@  ppDIBasicType' :: Fmt i -> Fmt (DIBasicType' i) ppDIBasicType' pp bt = "!DIBasicType"-  <> parens (mcommas+  <> parens (mcommas $        [ pure ("tag:"      <+> integral (dibtTag bt))        , pure ("name:"     <+> doubleQuotes (text (dibtName bt)))        ,     (("size:"     <+>) . ppSizeOrOffsetValMd' pp) <$> dibtSize bt@@ -1220,8 +1500,35 @@        , if dibtNumExtraInhabitants bt > 0          then pure ("numExtraInhabitants:" <+> integral (dibtNumExtraInhabitants bt))          else Nothing+       ]+       +++       when' (llvmVer >= 22)+       [ if dibtDataSize bt > 0+         then pure ("dataSize:" <+> integral (dibtDataSize bt))+         else Nothing+       ]+       )++ppDISubrangeType' :: Fmt i -> Fmt (DISubrangeType' i)+ppDISubrangeType' pp srt = "!DISubrangeType"+  <> parens (mcommas+       [     (("name:"     <+>) . doubleQuotes . text) <$> (disrtName srt)+       ,     (("file:"     <+>) . ppValMd' pp) <$> (disrtFile srt)+       , pure ("line:"     <+> integral (disrtLine srt))+       ,     (("scope:"    <+>) . ppValMd' pp) <$> (disrtScope srt)+       ,     (("size:"     <+>) . ppValMd' pp) <$> (disrtSize srt)+       , pure ("align:"    <+> integral (disrtAlign srt))+       , pure ("flags:"    <+> integral (disrtFlags srt))+       ,     (("baseType:" <+>) . ppValMd' pp) <$> (disrtBaseType srt)+       , (("lowerBound:"   <+>) . ppInt64ValMd' True pp) <$> disrtLowerBound srt+       , (("upperBound:"   <+>) . ppInt64ValMd' True pp) <$> disrtUpperBound srt+       , (("stride:"       <+>) . ppInt64ValMd' True pp) <$> disrtStride srt+       , (("bias:"         <+>) . ppInt64ValMd' True pp) <$> disrtBias srt        ]) +ppDISubrangeType :: Fmt DISubrangeType+ppDISubrangeType = ppDISubrangeType' ppLabel+ ppDICompileUnit' :: Fmt i -> Fmt (DICompileUnit' i) ppDICompileUnit' pp cu = "!DICompileUnit"   <> parens (mcommas $@@ -1254,6 +1561,12 @@        ,     (("sdk:"                   <+>) . doubleQuotes . text)              <$> (dicuSDK cu)        ]+       +++       when' (llvmVer >= 22)+       [ if dicuSourceLanguageVersion cu > 0+         then pure ("sourceLanguageVersion:" <+> integral (dicuSourceLanguageVersion cu))+         else Nothing+       ]        )  @@ -1325,6 +1638,35 @@                     , "isUnsigned:" <+> ppBool u                     ]) +ppDIFixedPointType' :: Fmt i -> Fmt (DIFixedPointType' i)+ppDIFixedPointType' pp t = "!DIFixedPointType"+  <> parens (mcommas $+       [ pure ("tag:"       <+> integral (difptTag t))+       ,     (("name:"     <+>) . doubleQuotes . text) <$> (difptName t)+       ,     (("size:"     <+>) . ppValMd' pp) <$> (difptSize t)+       , pure ("align:"    <+> integral (difptAlign t))+       , pure ("encoding:" <+> integral (difptEncoding t))+       , pure ("flags:"    <+> integral (difptFlags t))+       ]+       ++ case difptKind t of+            FixedPointBinary v ->+              [ pure "kind: Binary"+              , pure ("factor:" <+> integral v)+              ]+            FixedPointDecimal v ->+              [ pure "kind: Decimal"+              , pure ("factor:" <+> integral v)+              ]+            FixedPointRational n d ->+              [ pure "kind: Rational"+              , pure ("numerator:" <+> integral n)+              , pure ("denominator:" <+> integral d)+              ]+       )++ppDIFixedPointType :: Fmt DIFixedPointType+ppDIFixedPointType = ppDIFixedPointType' ppLabel+ ppDIExpression :: Fmt DIExpression ppDIExpression e = "!DIExpression"   <> parens (commas (map integral (dieElements e)))@@ -1480,6 +1822,66 @@ ppDIArgList :: Fmt DIArgList ppDIArgList = ppDIArgList' ppLabel ++-- -------------------------------------------------------------------+-- Auxiliary pretty-printing functions+--+-- These are alternative pretty-printing functions (instead of the pretty-printers+-- for the basic AST elements above). These functions can be used in+-- situations where additional or alternative pretty-printing functionality is+-- needed.++-- | This is an auxiliary pretty printer for showing just part of a module: the+-- part corresponding to a specific source file and line in the source file+-- (whereas ppModule or even ppDefine will show the *entire* module or+-- definition/function).  A range of lines can be displayed by iterative calls+-- over multiple lines.+--+-- > putStrLn $ ppLLVM llvmVlatest $ ppModuleAtLine "foo.c" 23 llvmModule+--+-- The above example shows all the lines in llvmModule that correspond to line 23+-- of the "foo.c" source file.+ppModuleAtLine :: (?config :: Config) => String -> Integer -> Fmt Module+ppModuleAtLine file line =+  toDoc . atFileLines (AddDocAtLine ?config) (Start empty) file line++-- internal helper for the AtFileLines instance below+data AddDocAtLine = AddDocAtLine Config++-- internal helper for the AtFileLines instance below+data DocBld = Start Doc -- ^ at the start: doc-so-far+            | DF DocBld Define Doc+              -- ^ atDefine: doc-so-far, the define, and the doc for the body of+              -- the AtFileLines+            | BS DocBld (Maybe BlockLabel) Doc+              -- ^ atBlockStart: doc-so-far, block label (if any), and doc for the+              -- block body++instance AtFileLines DocBld AddDocAtLine where+  atDefine _ d docbld = DF docbld d empty+  atBlockStart _ _dr bb docbld = BS docbld (bbLabel bb) empty+  atStmt (AddDocAtLine c) _dr br s =+    let isContig = case br of+          FirstBlockStmt -> True+          ContiguousStmt -> True+          FirstLineStmt -> False+    in withConfig c $ emit $ bool (text "..." $$) (empty $$) isContig $ ppStmt s+  atGlobal (AddDocAtLine c) g = withConfig c $ emit $ ppGlobal g++-- internal helper for the AtFileLines instance below+emit :: Doc -> DocBld -> DocBld+emit n = \case+  DF b s d -> DF b s (d $$ n)+  BS b l d -> BS b l (d $$ n)+  Start d -> Start (d $$ n)++-- internal helper for the AtFileLines instance below+toDoc :: Fmt DocBld+toDoc = \case+  DF b s d -> toDoc b $$ ppDefineSig s $$ nest 2 d+  BS b l d -> toDoc b $$ text "" $$ ppMaybe ppLabelDef l $$ d+  Start d -> d+ -- Utilities -------------------------------------------------------------------  ppBool :: Fmt Bool@@ -1512,7 +1914,7 @@           ValMdValue tv             | PrimType (Integer _) <- typedType tv             , ValInteger i <- typedValue tv-              -> integer i  -- 64 bits is the largest Int, so no conversion needed+              -> integer i  -- 64 bits is the largest Int, so no conversion needed.           o@(ValMdDebugInfo (DebugInfoGlobalVariable gv)) ->             case digvVariable gv of               Nothing -> when' canFallBack $ ppValMd' pp o
+ test/CombineTests.hs view
@@ -0,0 +1,231 @@+module CombineTests+  (+    tests+  )+where++import           Data.Function ( on )+import           Data.String ( fromString )+import           Lens.Micro++import qualified Test.Tasty as Tasty+import           Test.Tasty.HUnit ( assertBool, testCase, (@?=) )++import           Text.LLVM -- ( emptyModule )+import           Text.LLVM.Combine+import           Text.LLVM.Lens+++tests :: Tasty.TestTree+tests = Tasty.testGroup "LLVM combine"+  [+    testCase "empty equivalences"+    $ let llvm1 = emptyModule+          llvm2 = emptyModule+          llvm3 = emptyModule+          llvmAll = llvmModuleCombine (llvmModuleCombine llvm1 llvm2) llvm3+      in assertBool "combining empty is empty"+         $ and [ llvm1 == llvm1+               , ((==) `on` (modSourceNameLens .~ Nothing)) llvmAll llvm1+               , ((==) `on` (modSourceNameLens .~ Nothing)) llvmAll llvm2+               , ((==) `on` (modSourceNameLens .~ Nothing)) llvmAll llvm3+               ]++  , testCase "metadata updates"+    $ let llvm1 = emptyModule+                  & modUnnamedMdLens .~ [ UnnamedMd { umIndex = 1+                                                    , umValues = ValMdString "a"+                                                    , umDistinct = False+                                                    }+                                        ]+                  & modNamedMdLens .~ [ NamedMd { nmName = "frog"+                                                , nmValues = [1]+                                                }+                                      ]+          llvm2 = emptyModule+                  & modUnnamedMdLens .~ [ UnnamedMd { umIndex = 1+                                                    , umValues = ValMdString "B"+                                                    , umDistinct = False+                                                    }+                                        , UnnamedMd { umIndex = 2+                                                    , umValues = ValMdRef 1+                                                    , umDistinct = False+                                                    }+                                        ]+                  & modNamedMdLens .~ [ NamedMd { nmName = "pig"+                                                , nmValues = [2, 1]+                                                }+                                      ]+          llvmAll = llvmModuleCombine llvm1 llvm2+    in do llvmAll ^. modUnnamedMdLens @?=+            [ UnnamedMd { umIndex = 1+                        , umValues = ValMdString "a"+                        , umDistinct = False+                        }+            , UnnamedMd { umIndex = 3+                        , umValues = ValMdString "B"+                        , umDistinct = False+                        }+            , UnnamedMd { umIndex = 4+                        , umValues = ValMdRef 3+                        , umDistinct = False+                        }+            ]+          llvmAll ^. modNamedMdLens @?=+            [ NamedMd { nmName = "frog"+                      , nmValues = [1]+                      }+            , NamedMd { nmName = "pig"+                      , nmValues = [4, 3]+                      }+            ]++  , testCase "type name deconflicting"+    $ let llvm1 = emptyModule+            & modTypesLens .~ [ TypeDecl { typeName = fromString "type1"+                                         , typeValue = Opaque }+                              , TypeDecl { typeName = fromString "type1___0"+                                         , typeValue = Alias $ fromString "cow"+                                         }+                              ]+          llvm2 = emptyModule+            & modTypesLens .~ [ TypeDecl { typeName = fromString "type1"+                                         , typeValue = PrimType Void+                                         }+                              , TypeDecl { typeName = fromString "type1___0"+                                         , typeValue = Alias $ fromString "moo"+                                         }+                              , TypeDecl { typeName = fromString "type2"+                                         , typeValue = PtrOpaque+                                         }+                              ]+            & modDefinesLens .~+            [+              Define { defName = fromString "foo"+                     , defLinkage = Nothing+                     , defVisibility = Nothing+                     , defComdat = Nothing+                     , defMetadata = mempty+                     , defGC = Nothing+                     , defSection = Nothing+                     , defVarArgs = False+                     , defArgs =+                         [ Typed { typedType = Alias $ fromString "moo"+                                 , typedValue = fromString "type1___0"+                                 }+                         ]+                     , defRetType = PrimType Void+                     , defAttrs = mempty+                     , defBody = []+                     }+            ]+          llvmAll = llvmModuleCombine llvm1 llvm2+    in do llvmAll ^. modTypesLens @?=+            [ TypeDecl { typeName = fromString "type1"+                       , typeValue = Opaque }+            , TypeDecl { typeName = fromString "type1___0"+                       , typeValue = Alias $ fromString "cow"+                       }+            , TypeDecl { typeName = fromString "type1___1"+                      , typeValue = PrimType Void+                      }+            , TypeDecl { typeName = fromString "type1___0___0"+                       , typeValue = Alias $ fromString "moo"+                       }+            , TypeDecl { typeName = fromString "type2"+                       , typeValue = PtrOpaque+                       }+            ]+          llvmAll ^. modDefinesLens @?=+            [+              Define { defName = fromString "foo"+                     , defLinkage = Nothing+                     , defVisibility = Nothing+                     , defComdat = Nothing+                     , defMetadata = mempty+                     , defGC = Nothing+                     , defSection = Nothing+                     , defVarArgs = False+                     , defArgs =+                         [ Typed { typedType = Alias $ fromString "moo"+                                 , typedValue = fromString "type1___0___0"+                                 }+                         ]+                     , defRetType = PrimType Void+                     , defAttrs = mempty+                     , defBody = []+                     }+            ]+  , testCase "internal define name deconflicting"+    $ let d1 = Define { defName = fromString "foo"+                           , defLinkage = Just Internal+                           , defVisibility = Nothing+                           , defComdat = Nothing+                           , defMetadata = mempty+                           , defGC = Nothing+                           , defSection = Nothing+                           , defVarArgs = False+                           , defArgs =+                             [ Typed { typedType = Alias $ fromString "moo"+                                     , typedValue = fromString "type1"+                                     }+                             ]+                           , defRetType = PrimType $ Integer 8+                           , defAttrs = mempty+                           , defBody = []+                           }+          d2 = Define { defName = fromString "foo"+                      , defLinkage = Just Internal+                      , defVisibility = Nothing+                      , defComdat = Nothing+                      , defMetadata = mempty+                      , defGC = Nothing+                      , defSection = Nothing+                      , defVarArgs = False+                      , defArgs = []+                      , defRetType = PrimType Void+                      , defAttrs = mempty+                      , defBody = []+                           }+          llvm1 = emptyModule & modDefinesLens .~ [ d1 ]+          llvm2 = emptyModule & modDefinesLens .~ [ d2 ]+          llvmAll = llvmModuleCombine llvm1 llvm2+    in do llvmAll ^. modDefinesLens @?=+            [ d1+            , d2 & defNameLens .~ fromString "foo_1"+            ]++  , testCase "declare to define resolution"+    $ let d1 = Declare { decName = fromString "foo"+                       , decLinkage = Nothing+                       , decVisibility = Nothing+                       , decComdat = Nothing+                       , decVarArgs = False+                       , decArgs = [ Alias $ fromString "moo" ]+                       , decRetType = PrimType $ Integer 8+                       , decAttrs = mempty+                       }+          d2 = Define { defName = fromString "foo"+                      , defLinkage = Nothing+                      , defVisibility = Nothing+                      , defComdat = Nothing+                      , defMetadata = mempty+                      , defGC = Nothing+                      , defSection = Nothing+                      , defVarArgs = False+                      , defArgs =+                           [ Typed { typedType = Alias $ fromString "cow"+                                   , typedValue = fromString "type1"+                                   }+                           ]+                      , defRetType = PrimType $ Integer 8+                      , defAttrs = mempty+                      , defBody = []+                           }+          llvm1 = emptyModule & modDeclaresLens .~ [ d1 ]+          llvm2 = emptyModule & modDefinesLens .~ [ d2 ]+          llvmAll = llvmModuleCombine llvm1 llvm2+    in do llvmAll ^. modDefinesLens @?= [ d2 ]+          llvmAll ^. modDeclaresLens @?= []++  ]
test/Main.hs view
@@ -2,6 +2,7 @@  import qualified Test.Tasty as Tasty +import qualified CombineTests import qualified DataLayout import qualified Metadata import qualified Output@@ -14,4 +15,5 @@        , Metadata.tests        , Output.tests        , Triple.tests+       , CombineTests.tests        ]
test/Output.hs view
@@ -74,6 +74,7 @@                               , dicuRangesBaseAddress = True                               , dicuSysRoot = Just "the root"                               , dicuSDK = Just "SDK"+                              , dicuSourceLanguageVersion = 0                               }         dtt = ValMdDebugInfo               $ DebugInfoTemplateTypeParameter@@ -309,25 +310,85 @@       --------       |] +  , testCase "Zero (half float)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValHalf (FPHalf 0x0000)))+      "0.0"++  , testCase "One (half float)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValHalf (FPHalf 0x3c00)))+      "1.0"++  , testCase "Two (half float)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValHalf (FPHalf 0x4000)))+      "2.0"++  , testCase "Positive Infinity (half float)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValHalf (FPHalf 0x7c00)))+      "0xH7c00"++  , testCase "Negative Infinity (half float)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValHalf (FPHalf 0xfc00)))+      "0xHfc00"++  , testCase "NaN (half float)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValHalf (FPHalf 0x7c55)))+      "0xH7c55"++  , testCase "Zero (bfloat)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValBFloat (FPBFloat 0x0000)))+      "0.0"++  , testCase "One (bfloat)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValBFloat (FPBFloat 0x3f80)))+      "1.0"++  , testCase "Two (bfloat)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValBFloat (FPBFloat 0x4000)))+      "2.0"++  , testCase "Positive Infinity (bfloat)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValBFloat (FPBFloat 0x7f80)))+      "0xR7f80"++  , testCase "Negative Infinity (bfloat)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValBFloat (FPBFloat 0xff80)))+      "0xRff80"++  , testCase "NaN (bfloat)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValBFloat (FPBFloat 0x7f85)))+      "0xR7f85"+   , testCase "Positive Infinity (float)" $     assertEqLines       (ppToText $ ppLLVM37 ppValue (ValFloat (castWord32ToFloat 0x7F800000)))-      "0x7f800000"+      "0x7ff0000000000000"    , testCase "Negative Infinity (float)" $     assertEqLines       (ppToText $ ppLLVM37 ppValue (ValFloat (castWord32ToFloat 0xFF800000)))-      "0xff800000"+      "0xfff0000000000000"    , testCase "NaN 1 (float)" $     assertEqLines       (ppToText $ ppLLVM37 ppValue (ValFloat (castWord32ToFloat 0x7FC00000)))-      "0x7fc00000"+      "0x7ff8000000000000"    , testCase "NaN 2 (float)" $     assertEqLines       (ppToText $ ppLLVM37 ppValue (ValFloat (castWord32ToFloat 0x7FD00000)))-      "0x7fd00000"+      "0x7ffa000000000000"    , testCase "Positive Infinity (double)" $     assertEqLines@@ -348,6 +409,21 @@     assertEqLines       (ppToText $ ppLLVM37 ppValue (ValDouble (castWord64ToDouble 0x7FFD000000000000)))       "0x7ffd000000000000"++  , testCase "Zero (FP80)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValFP80 (FP80_LongDouble 0x0000 0x0000000000000000)))+      "0xK00000000000000000000"++  , testCase "Zero (FP128)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValFP128 (FP128_LongDouble 0x0000000000000000 0x0000000000000000)))+      "0xL00000000000000000000000000000000"++  , testCase "Zero (FP128_PPC)" $+    assertEqLines+      (ppToText $ ppLLVM37 ppValue (ValFP128_PPC (FP128_PPC_DoubleDouble 0.0 0.0)))+      "0xM00000000000000000000000000000000"    ]